goproxy/core/cs/client/client.go
2018-09-14 16:12:56 +08:00

136 lines
3.9 KiB
Go

package client
import (
"crypto/tls"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"net"
"strconv"
"strings"
"time"
"github.com/snail007/goproxy/core/dst"
"github.com/snail007/goproxy/core/lib/kcpcfg"
compressconn "github.com/snail007/goproxy/core/lib/transport"
encryptconn "github.com/snail007/goproxy/core/lib/transport/encrypt"
kcp "github.com/xtaci/kcp-go"
)
func TlsConnectHost(host string, timeout int, certBytes, keyBytes, caCertBytes []byte) (conn tls.Conn, err error) {
h := strings.Split(host, ":")
port, _ := strconv.Atoi(h[1])
return TlsConnect(h[0], port, timeout, certBytes, keyBytes, caCertBytes)
}
func TlsConnect(host string, port, timeout int, certBytes, keyBytes, caCertBytes []byte) (conn tls.Conn, err error) {
conf, err := getRequestTlsConfig(certBytes, keyBytes, caCertBytes)
if err != nil {
return
}
_conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", host, port), time.Duration(timeout)*time.Millisecond)
if err != nil {
return
}
return *tls.Client(_conn, conf), err
}
func TlsConfig(certBytes, keyBytes, caCertBytes []byte) (conf *tls.Config, err error) {
return getRequestTlsConfig(certBytes, keyBytes, caCertBytes)
}
func getRequestTlsConfig(certBytes, keyBytes, caCertBytes []byte) (conf *tls.Config, err error) {
var cert tls.Certificate
cert, err = tls.X509KeyPair(certBytes, keyBytes)
if err != nil {
return
}
serverCertPool := x509.NewCertPool()
caBytes := certBytes
if caCertBytes != nil {
caBytes = caCertBytes
}
ok := serverCertPool.AppendCertsFromPEM(caBytes)
if !ok {
err = errors.New("failed to parse root certificate")
}
block, _ := pem.Decode(caBytes)
if block == nil {
panic("failed to parse certificate PEM")
}
x509Cert, _ := x509.ParseCertificate(block.Bytes)
if x509Cert == nil {
panic("failed to parse block")
}
conf = &tls.Config{
RootCAs: serverCertPool,
Certificates: []tls.Certificate{cert},
InsecureSkipVerify: true,
ServerName: x509Cert.Subject.CommonName,
VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
opts := x509.VerifyOptions{
Roots: serverCertPool,
}
for _, rawCert := range rawCerts {
cert, _ := x509.ParseCertificate(rawCert)
_, err := cert.Verify(opts)
if err != nil {
return err
}
}
return nil
},
}
return
}
func TCPConnectHost(hostAndPort string, timeout int) (conn net.Conn, err error) {
conn, err = net.DialTimeout("tcp", hostAndPort, time.Duration(timeout)*time.Millisecond)
return
}
func TCPSConnectHost(hostAndPort string, method, password string, compress bool, timeout int) (conn net.Conn, err error) {
conn, err = net.DialTimeout("tcp", hostAndPort, time.Duration(timeout)*time.Millisecond)
if err != nil {
return
}
if compress {
conn = compressconn.NewCompConn(conn)
}
conn, err = encryptconn.NewConn(conn, method, password)
return
}
func TOUConnectHost(hostAndPort string, method, password string, compress bool, timeout int) (conn net.Conn, err error) {
udpConn, err := net.ListenUDP("udp", &net.UDPAddr{})
if err != nil {
panic(err)
}
// Create a DST mux around the packet connection with the default max
// packet size.
mux := dst.NewMux(udpConn, 0)
conn, err = mux.Dial("dst", hostAndPort)
if compress {
conn = compressconn.NewCompConn(conn)
}
conn, err = encryptconn.NewConn(conn, method, password)
return
}
func KCPConnectHost(hostAndPort string, config kcpcfg.KCPConfigArgs) (conn net.Conn, err error) {
kcpconn, err := kcp.DialWithOptions(hostAndPort, config.Block, *config.DataShard, *config.ParityShard)
if err != nil {
return
}
kcpconn.SetStreamMode(true)
kcpconn.SetWriteDelay(true)
kcpconn.SetNoDelay(*config.NoDelay, *config.Interval, *config.Resend, *config.NoCongestion)
kcpconn.SetMtu(*config.MTU)
kcpconn.SetWindowSize(*config.SndWnd, *config.RcvWnd)
kcpconn.SetACKNoDelay(*config.AckNodelay)
if *config.NoComp {
return kcpconn, err
}
return compressconn.NewCompStream(kcpconn), err
}