diff --git a/proxy/http/config.go b/proxy/http/config.go index 8ee51533..c6d70d99 100644 --- a/proxy/http/config.go +++ b/proxy/http/config.go @@ -1,42 +1,7 @@ package http -import "crypto/tls" - -// CertificateConfig is the config for TLS certificates used in HTTP proxy. -type CertificateConfig struct { - Domain string - Certificate tls.Certificate -} - -// TlsConfig is the config for TLS connections. -type TLSConfig struct { - Enabled bool - Certs []*CertificateConfig -} - -// GetConfig returns corresponding tls.Config. -func (this *TLSConfig) GetConfig() *tls.Config { - if !this.Enabled { - return nil - } - - config := &tls.Config{ - InsecureSkipVerify: false, - } - - config.Certificates = make([]tls.Certificate, len(this.Certs)) - for index, cert := range this.Certs { - config.Certificates[index] = cert.Certificate - } - - config.BuildNameToCertificate() - - return config -} - // Config for HTTP proxy server. type Config struct { - TLSConfig *TLSConfig } // ClientConfig for HTTP proxy client. diff --git a/proxy/http/config_json.go b/proxy/http/config_json.go index 7730d86e..5071ae38 100644 --- a/proxy/http/config_json.go +++ b/proxy/http/config_json.go @@ -3,62 +3,21 @@ package http import ( - "crypto/tls" "encoding/json" "errors" "github.com/v2ray/v2ray-core/proxy/internal" ) -// UnmarshalJSON implements json.Unmarshaler -func (this *CertificateConfig) UnmarshalJSON(data []byte) error { - type JsonConfig struct { - Domain string `json:"domain"` - CertFile string `json:"cert"` - KeyFile string `json:"key"` - } - jsonConfig := new(JsonConfig) - if err := json.Unmarshal(data, jsonConfig); err != nil { - return errors.New("HTTP: Failed to parse certificate config: " + err.Error()) - } - - cert, err := tls.LoadX509KeyPair(jsonConfig.CertFile, jsonConfig.KeyFile) - if err != nil { - return err - } - this.Domain = jsonConfig.Domain - this.Certificate = cert - return nil -} - -// UnmarshalJSON implements json.Unmarshaler -func (this *TLSConfig) UnmarshalJSON(data []byte) error { - type JsonConfig struct { - Enabled bool `json:"enable"` - Certs []*CertificateConfig `json:"certs"` - } - jsonConfig := new(JsonConfig) - if err := json.Unmarshal(data, jsonConfig); err != nil { - return errors.New("HTTP: Failed to parse TLS config: " + err.Error()) - } - - this.Enabled = jsonConfig.Enabled - this.Certs = jsonConfig.Certs - return nil -} - // UnmarshalJSON implements json.Unmarshaler func (this *Config) UnmarshalJSON(data []byte) error { type JsonConfig struct { - Tls *TLSConfig `json:"tls"` } jsonConfig := new(JsonConfig) if err := json.Unmarshal(data, jsonConfig); err != nil { return errors.New("HTTP: Failed to parse config: " + err.Error()) } - this.TLSConfig = jsonConfig.Tls - return nil } diff --git a/transport/internet/connection.go b/transport/internet/connection.go index c34e9a06..58ae2144 100644 --- a/transport/internet/connection.go +++ b/transport/internet/connection.go @@ -1,6 +1,7 @@ package internet import ( + "crypto/tls" "net" ) @@ -13,14 +14,38 @@ type Reusable interface { type StreamConnectionType int -var ( +const ( StreamConnectionTypeRawTCP StreamConnectionType = 1 StreamConnectionTypeTCP StreamConnectionType = 2 StreamConnectionTypeKCP StreamConnectionType = 4 ) +type StreamSecurityType int + +const ( + StreamSecurityTypeNone StreamSecurityType = 0 + StreamSecurityTypeTLS StreamSecurityType = 1 +) + +type TLSSettings struct { + Certs []tls.Certificate +} + +func (this *TLSSettings) GetTLSConfig() *tls.Config { + config := &tls.Config{ + InsecureSkipVerify: true, + } + + config.Certificates = this.Certs + config.BuildNameToCertificate() + + return config +} + type StreamSettings struct { - Type StreamConnectionType + Type StreamConnectionType + Security StreamSecurityType + TLSSettings *TLSSettings } func (this *StreamSettings) IsCapableOf(streamType StreamConnectionType) bool { diff --git a/transport/internet/connection_json.go b/transport/internet/connection_json.go index a4ad8c5a..6b96ad8b 100644 --- a/transport/internet/connection_json.go +++ b/transport/internet/connection_json.go @@ -3,14 +3,42 @@ package internet import ( + "crypto/tls" "encoding/json" + "errors" + "strings" v2net "github.com/v2ray/v2ray-core/common/net" ) +func (this *TLSSettings) UnmarshalJSON(data []byte) error { + type JSONCertConfig struct { + CertFile string `json:"certFile"` + KeyFile string `json:"keyFile"` + } + type JSONConfig struct { + Certs []*JSONCertConfig `json:"certs"` + } + jsonConfig := new(JSONConfig) + if err := json.Unmarshal(data, jsonConfig); err != nil { + return err + } + this.Certs = make([]tls.Certificate, len(jsonConfig.Certs)) + for idx, certConf := range jsonConfig.Certs { + cert, err := tls.LoadX509KeyPair(certConf.CertFile, certConf.KeyFile) + if err != nil { + return errors.New("Internet|TLS: Failed to load certificate file: " + err.Error()) + } + this.Certs[idx] = cert + } + return nil +} + func (this *StreamSettings) UnmarshalJSON(data []byte) error { type JSONConfig struct { - Network v2net.NetworkList `json:"network"` + Network v2net.NetworkList `json:"network"` + Security string `json:"security"` + TLSSettings *TLSSettings `json:"tlsSettings"` } this.Type = StreamConnectionTypeRawTCP jsonConfig := new(JSONConfig) @@ -23,5 +51,12 @@ func (this *StreamSettings) UnmarshalJSON(data []byte) error { if jsonConfig.Network.HasNetwork(v2net.TCPNetwork) { this.Type |= StreamConnectionTypeTCP } + this.Security = StreamSecurityTypeNone + if strings.ToLower(jsonConfig.Security) == "tls" { + this.Security = StreamSecurityTypeTLS + } + if jsonConfig.TLSSettings != nil { + this.TLSSettings = jsonConfig.TLSSettings + } return nil } diff --git a/transport/internet/dialer.go b/transport/internet/dialer.go index 04858faf..ff270e0f 100644 --- a/transport/internet/dialer.go +++ b/transport/internet/dialer.go @@ -1,11 +1,13 @@ package internet import ( + "crypto/tls" "errors" "net" "time" v2net "github.com/v2ray/v2ray-core/common/net" + v2tls "github.com/v2ray/v2ray-core/transport/internet/tls" ) var ( @@ -22,16 +24,32 @@ var ( ) func Dial(src v2net.Address, dest v2net.Destination, settings *StreamSettings) (Connection, error) { + var connection Connection + var err error if dest.IsTCP() { switch { case settings.IsCapableOf(StreamConnectionTypeTCP): - return TCPDialer(src, dest) + connection, err = TCPDialer(src, dest) case settings.IsCapableOf(StreamConnectionTypeKCP): - return KCPDialer(src, dest) + connection, err = KCPDialer(src, dest) case settings.IsCapableOf(StreamConnectionTypeRawTCP): - return RawTCPDialer(src, dest) + connection, err = RawTCPDialer(src, dest) + default: + return nil, ErrUnsupportedStreamType } - return nil, ErrUnsupportedStreamType + if err != nil { + return nil, err + } + if settings.Security == StreamSecurityTypeNone { + return connection, nil + } + + config := settings.TLSSettings.GetTLSConfig() + if dest.Address().IsDomain() { + config.ServerName = dest.Address().Domain() + } + tlsConn := tls.Client(connection, config) + return v2tls.NewConnection(tlsConn), nil } return UDPDialer(src, dest) diff --git a/transport/internet/tcp_hub.go b/transport/internet/tcp_hub.go index 328b1473..d0642de7 100644 --- a/transport/internet/tcp_hub.go +++ b/transport/internet/tcp_hub.go @@ -1,12 +1,14 @@ package internet import ( + "crypto/tls" "errors" "net" "sync" "github.com/v2ray/v2ray-core/common/log" v2net "github.com/v2ray/v2ray-core/common/net" + v2tls "github.com/v2ray/v2ray-core/transport/internet/tls" ) var ( @@ -29,6 +31,7 @@ type TCPHub struct { listener Listener connCallback ConnectionHandler accepting bool + tlsConfig *tls.Config } func ListenTCP(address v2net.Address, port v2net.Port, callback ConnectionHandler, settings *StreamSettings) (*TCPHub, error) { @@ -51,9 +54,15 @@ func ListenTCP(address v2net.Address, port v2net.Port, callback ConnectionHandle return nil, err } + var tlsConfig *tls.Config + if settings.Security == StreamSecurityTypeTLS { + tlsConfig = settings.TLSSettings.GetTLSConfig() + } + hub := &TCPHub{ listener: listener, connCallback: callback, + tlsConfig: tlsConfig, } go hub.start() @@ -76,6 +85,10 @@ func (this *TCPHub) start() { } continue } + if this.tlsConfig != nil { + tlsConn := tls.Server(conn, this.tlsConfig) + conn = v2tls.NewConnection(tlsConn) + } go this.connCallback(conn) } } diff --git a/transport/internet/tls/connection.go b/transport/internet/tls/connection.go new file mode 100644 index 00000000..f4624914 --- /dev/null +++ b/transport/internet/tls/connection.go @@ -0,0 +1,21 @@ +package tls + +import ( + "crypto/tls" +) + +type Connection struct { + *tls.Conn +} + +func (this *Connection) Reusable() bool { + return false +} + +func (this *Connection) SetReusable(bool) {} + +func NewConnection(conn *tls.Conn) *Connection { + return &Connection{ + Conn: conn, + } +}