Procházet zdrojové kódy

tcp handler for shadowsocks

v2ray před 9 roky
rodič
revize
095905a460

+ 22 - 3
proxy/shadowsocks/config.go

@@ -1,6 +1,7 @@
 package shadowsocks
 
 import (
+	"crypto/md5"
 	"io"
 
 	"github.com/v2ray/v2ray-core/common/crypto"
@@ -44,7 +45,25 @@ func (this *AesCfb) NewDecodingStream(key []byte, iv []byte, reader io.Reader) (
 }
 
 type Config struct {
-	Cipher   Cipher
-	Password string
-	UDP      bool
+	Cipher Cipher
+	Key    []byte
+	UDP    bool
+}
+
+func PasswordToCipherKey(password string, keySize int) []byte {
+	pwdBytes := []byte(password)
+	key := make([]byte, 0, keySize)
+
+	md5Sum := md5.Sum(pwdBytes)
+	key = append(key, md5Sum[:]...)
+
+	for len(key) < keySize {
+		md5Hash := md5.New()
+		md5Hash.Write(md5Sum[:])
+		md5Hash.Write(pwdBytes)
+		md5Hash.Sum(md5Sum[:0])
+
+		key = append(key, md5Sum[:]...)
+	}
+	return key
 }

+ 18 - 10
proxy/shadowsocks/config_json.go

@@ -8,6 +8,7 @@ import (
 	"github.com/v2ray/v2ray-core/common/log"
 	"github.com/v2ray/v2ray-core/common/serial"
 	"github.com/v2ray/v2ray-core/proxy/internal"
+	"github.com/v2ray/v2ray-core/proxy/internal/config"
 )
 
 func (this *Config) UnmarshalJSON(data []byte) error {
@@ -20,16 +21,8 @@ func (this *Config) UnmarshalJSON(data []byte) error {
 	if err := json.Unmarshal(data, jsonConfig); err != nil {
 		return err
 	}
-	if len(jsonConfig.Password) == 0 {
-		log.Error("Shadowsocks: Password is not specified.")
-		return internal.ErrorBadConfiguration
-	}
+
 	this.UDP = jsonConfig.UDP
-	this.Password = jsonConfig.Password.String()
-	if this.Cipher == nil {
-		log.Error("Shadowsocks: Cipher method is not specified.")
-		return internal.ErrorBadConfiguration
-	}
 	jsonConfig.Cipher = jsonConfig.Cipher.ToLower()
 	switch jsonConfig.Cipher.String() {
 	case "aes-256-cfb":
@@ -38,11 +31,26 @@ func (this *Config) UnmarshalJSON(data []byte) error {
 		}
 	case "aes-128-cfb":
 		this.Cipher = &AesCfb{
-			KeyBytes: 32,
+			KeyBytes: 16,
 		}
 	default:
 		log.Error("Shadowsocks: Unknown cipher method: ", jsonConfig.Cipher)
 		return internal.ErrorBadConfiguration
 	}
+
+	if len(jsonConfig.Password) == 0 {
+		log.Error("Shadowsocks: Password is not specified.")
+		return internal.ErrorBadConfiguration
+	}
+	this.Key = PasswordToCipherKey(jsonConfig.Password.String(), this.Cipher.KeySize())
+
 	return nil
 }
+
+func init() {
+	config.RegisterInboundConfig("shadowsocks", func(data []byte) (interface{}, error) {
+		rawConfig := new(Config)
+		err := json.Unmarshal(data, rawConfig)
+		return rawConfig, err
+	})
+}

+ 77 - 0
proxy/shadowsocks/protocol.go

@@ -0,0 +1,77 @@
+package shadowsocks
+
+import (
+	"io"
+
+	"github.com/v2ray/v2ray-core/common/alloc"
+	"github.com/v2ray/v2ray-core/common/log"
+	v2net "github.com/v2ray/v2ray-core/common/net"
+	"github.com/v2ray/v2ray-core/transport"
+)
+
+const (
+	AddrTypeIPv4   = 1
+	AddrTypeIPv6   = 4
+	AddrTypeDomain = 3
+)
+
+type Request struct {
+	Address v2net.Address
+	Port    v2net.Port
+}
+
+func ReadRequest(reader io.Reader) (*Request, error) {
+	buffer := alloc.NewSmallBuffer()
+	defer buffer.Release()
+
+	_, err := v2net.ReadAllBytes(reader, buffer.Value[:1])
+	if err != nil {
+		log.Error("Shadowsocks: Failed to read address type: ", err)
+		return nil, transport.CorruptedPacket
+	}
+
+	request := new(Request)
+
+	addrType := buffer.Value[0]
+	switch addrType {
+	case AddrTypeIPv4:
+		_, err := v2net.ReadAllBytes(reader, buffer.Value[:4])
+		if err != nil {
+			log.Error("Shadowsocks: Failed to read IPv4 address: ", err)
+			return nil, transport.CorruptedPacket
+		}
+		request.Address = v2net.IPAddress(buffer.Value[:4])
+	case AddrTypeIPv6:
+		_, err := v2net.ReadAllBytes(reader, buffer.Value[:16])
+		if err != nil {
+			log.Error("Shadowsocks: Failed to read IPv6 address: ", err)
+			return nil, transport.CorruptedPacket
+		}
+		request.Address = v2net.IPAddress(buffer.Value[:16])
+	case AddrTypeDomain:
+		_, err := v2net.ReadAllBytes(reader, buffer.Value[:1])
+		if err != nil {
+			log.Error("Shadowsocks: Failed to read domain lenth: ", err)
+			return nil, transport.CorruptedPacket
+		}
+		domainLength := int(buffer.Value[0])
+		_, err = v2net.ReadAllBytes(reader, buffer.Value[:domainLength])
+		if err != nil {
+			log.Error("Shadowsocks: Failed to read domain: ", err)
+			return nil, transport.CorruptedPacket
+		}
+		request.Address = v2net.DomainAddress(string(buffer.Value[:domainLength]))
+	default:
+		log.Error("Shadowsocks: Unknown address type: ", addrType)
+		return nil, transport.CorruptedPacket
+	}
+
+	_, err = v2net.ReadAllBytes(reader, buffer.Value[:2])
+	if err != nil {
+		log.Error("Shadowsocks: Failed to read port: ", err)
+		return nil, transport.CorruptedPacket
+	}
+
+	request.Port = v2net.PortFromBytes(buffer.Value[:2])
+	return request, nil
+}

+ 60 - 0
proxy/shadowsocks/shadowsocks.go

@@ -3,13 +3,19 @@
 package shadowsocks
 
 import (
+	"sync"
+
+	"github.com/v2ray/v2ray-core/app"
+	"github.com/v2ray/v2ray-core/common/alloc"
 	"github.com/v2ray/v2ray-core/common/log"
 	v2net "github.com/v2ray/v2ray-core/common/net"
 	"github.com/v2ray/v2ray-core/proxy"
+	"github.com/v2ray/v2ray-core/proxy/internal"
 	"github.com/v2ray/v2ray-core/transport/listener"
 )
 
 type Shadowsocks struct {
+	space       app.Space
 	config      *Config
 	port        v2net.Port
 	accepting   bool
@@ -48,4 +54,58 @@ func (this *Shadowsocks) Listen(port v2net.Port) error {
 func (this *Shadowsocks) handleConnection(conn *listener.TCPConn) {
 	defer conn.Close()
 
+	buffer := alloc.NewSmallBuffer()
+	defer buffer.Release()
+
+	_, err := v2net.ReadAllBytes(conn, buffer.Value[:this.config.Cipher.IVSize()])
+	if err != nil {
+		log.Error("Shadowsocks: Failed to read IV: ", err)
+		return
+	}
+
+	iv := buffer.Value[:this.config.Cipher.IVSize()]
+	key := this.config.Key
+
+	reader, err := this.config.Cipher.NewDecodingStream(key, iv, conn)
+	if err != nil {
+		log.Error("Shadowsocks: Failed to create decoding stream: ", err)
+		return
+	}
+
+	request, err := ReadRequest(reader)
+	if err != nil {
+		return
+	}
+
+	packet := v2net.NewPacket(v2net.TCPDestination(request.Address, request.Port), nil, true)
+	ray := this.space.PacketDispatcher().DispatchToOutbound(packet)
+
+	writer, err := this.config.Cipher.NewEncodingStream(key, iv, conn)
+	if err != nil {
+		log.Error("Shadowsocks: Failed to create encoding stream: ", err)
+		return
+	}
+
+	var writeFinish sync.Mutex
+	writeFinish.Lock()
+	go func() {
+		v2net.ChanToWriter(writer, ray.InboundOutput())
+		writeFinish.Unlock()
+	}()
+
+	v2net.ReaderToChan(ray.InboundInput(), reader)
+	close(ray.InboundInput())
+
+	writeFinish.Lock()
+}
+
+func init() {
+	internal.MustRegisterInboundHandlerCreator("shadowsocks",
+		func(space app.Space, rawConfig interface{}) (proxy.InboundHandler, error) {
+			config := rawConfig.(*Config)
+			return &Shadowsocks{
+				space:  space,
+				config: config,
+			}, nil
+		})
 }