From be10ca7e093e7eba8b387ae4ec44378599de01c0 Mon Sep 17 00:00:00 2001 From: v2ray Date: Fri, 29 Jan 2016 21:55:42 +0100 Subject: [PATCH] fix shadowsocks udp ota --- proxy/shadowsocks/protocol.go | 42 ++++++++++++++++++++++-------- proxy/shadowsocks/protocol_test.go | 38 +++++++++++++++++++++++++-- proxy/shadowsocks/shadowsocks.go | 10 +++---- 3 files changed, 71 insertions(+), 19 deletions(-) diff --git a/proxy/shadowsocks/protocol.go b/proxy/shadowsocks/protocol.go index 626075806..a8391b0ae 100644 --- a/proxy/shadowsocks/protocol.go +++ b/proxy/shadowsocks/protocol.go @@ -17,12 +17,13 @@ const ( ) type Request struct { - Address v2net.Address - Port v2net.Port - OTA bool + Address v2net.Address + Port v2net.Port + OTA bool + UDPPayload *alloc.Buffer } -func ReadRequest(reader io.Reader, auth *Authenticator) (*Request, error) { +func ReadRequest(reader io.Reader, auth *Authenticator, udp bool) (*Request, error) { buffer := alloc.NewSmallBuffer() defer buffer.Release() @@ -85,14 +86,33 @@ func ReadRequest(reader io.Reader, auth *Authenticator) (*Request, error) { request.Port = v2net.PortFromBytes(buffer.Value[lenBuffer : lenBuffer+2]) lenBuffer += 2 - if request.OTA { - authBytes := buffer.Value[lenBuffer : lenBuffer+AuthSize] - _, err = io.ReadFull(reader, authBytes) - if err != nil { - log.Error("Shadowsocks: Failed to read OTA: ", err) - return nil, transport.CorruptedPacket - } + var authBytes []byte + if udp { + nBytes, err := reader.Read(buffer.Value[lenBuffer:]) + if err != nil { + log.Error("Shadowsocks: Failed to read UDP payload: ", err) + } + buffer.Slice(0, lenBuffer+nBytes) + if request.OTA { + authBytes = buffer.Value[lenBuffer+nBytes-AuthSize:] + request.UDPPayload = alloc.NewSmallBuffer().Clear().Append(buffer.Value[lenBuffer : lenBuffer+nBytes-AuthSize]) + lenBuffer = lenBuffer + nBytes - AuthSize + } else { + request.UDPPayload = alloc.NewSmallBuffer().Clear().Append(buffer.Value[lenBuffer:]) + } + } else { + if request.OTA { + authBytes = buffer.Value[lenBuffer : lenBuffer+AuthSize] + _, err = io.ReadFull(reader, authBytes) + if err != nil { + log.Error("Shadowsocks: Failed to read OTA: ", err) + return nil, transport.CorruptedPacket + } + } + } + + if request.OTA { actualAuth := auth.Authenticate(nil, buffer.Value[0:lenBuffer]) if !serial.BytesLiteral(actualAuth).Equals(serial.BytesLiteral(authBytes)) { log.Error("Shadowsocks: Invalid OTA: ", actualAuth) diff --git a/proxy/shadowsocks/protocol_test.go b/proxy/shadowsocks/protocol_test.go index 2b5658d2a..e7023a6a9 100644 --- a/proxy/shadowsocks/protocol_test.go +++ b/proxy/shadowsocks/protocol_test.go @@ -17,7 +17,7 @@ func TestNormalRequestParsing(t *testing.T) { buffer := alloc.NewSmallBuffer().Clear() buffer.AppendBytes(1, 127, 0, 0, 1, 0, 80) - request, err := ReadRequest(buffer, nil) + request, err := ReadRequest(buffer, nil, false) assert.Error(err).IsNil() netassert.Address(request.Address).Equals(v2net.IPAddress([]byte{127, 0, 0, 1})) netassert.Port(request.Port).Equals(v2net.Port(80)) @@ -33,8 +33,42 @@ func TestOTARequest(t *testing.T) { auth := NewAuthenticator(HeaderKeyGenerator( []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5}, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5})) - request, err := ReadRequest(buffer, auth) + request, err := ReadRequest(buffer, auth, false) assert.Error(err).IsNil() netassert.Address(request.Address).Equals(v2net.DomainAddress("www.v2ray.com")) assert.Bool(request.OTA).IsTrue() } + +func TestUDPRequestParsing(t *testing.T) { + v2testing.Current(t) + + buffer := alloc.NewSmallBuffer().Clear() + buffer.AppendBytes(1, 127, 0, 0, 1, 0, 80, 1, 2, 3, 4, 5, 6) + + request, err := ReadRequest(buffer, nil, true) + assert.Error(err).IsNil() + netassert.Address(request.Address).Equals(v2net.IPAddress([]byte{127, 0, 0, 1})) + netassert.Port(request.Port).Equals(v2net.Port(80)) + assert.Bool(request.OTA).IsFalse() + assert.Bytes(request.UDPPayload.Value).Equals([]byte{1, 2, 3, 4, 5, 6}) +} + +func TestUDPRequestWithOTA(t *testing.T) { + v2testing.Current(t) + + buffer := alloc.NewSmallBuffer().Clear() + buffer.AppendBytes( + 0x13, 13, 119, 119, 119, 46, 118, 50, 114, 97, 121, 46, 99, 111, 109, 0, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 58, 32, 223, 30, 57, 199, 50, 139, 143, 101) + + auth := NewAuthenticator(HeaderKeyGenerator( + []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5}, + []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5})) + request, err := ReadRequest(buffer, auth, true) + assert.Error(err).IsNil() + netassert.Address(request.Address).Equals(v2net.DomainAddress("www.v2ray.com")) + assert.Bool(request.OTA).IsTrue() + assert.Bytes(request.UDPPayload.Value).Equals([]byte{ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0}) +} diff --git a/proxy/shadowsocks/shadowsocks.go b/proxy/shadowsocks/shadowsocks.go index 19d074182..bad56d2a9 100644 --- a/proxy/shadowsocks/shadowsocks.go +++ b/proxy/shadowsocks/shadowsocks.go @@ -85,14 +85,12 @@ func (this *Shadowsocks) handlerUDPPayload(payload *alloc.Buffer, dest v2net.Des return } - request, err := ReadRequest(reader, NewAuthenticator(HeaderKeyGenerator(key, iv))) + request, err := ReadRequest(reader, NewAuthenticator(HeaderKeyGenerator(key, iv)), true) if err != nil { return } - buffer, _ := v2io.ReadFrom(reader, nil) - - packet := v2net.NewPacket(v2net.TCPDestination(request.Address, request.Port), buffer, false) + packet := v2net.NewPacket(v2net.TCPDestination(request.Address, request.Port), request.UDPPayload, false) ray := this.space.PacketDispatcher().DispatchToOutbound(packet) close(ray.InboundInput()) @@ -126,7 +124,7 @@ func (this *Shadowsocks) handlerUDPPayload(payload *alloc.Buffer, dest v2net.Des if request.OTA { respAuth := NewAuthenticator(HeaderKeyGenerator(key, respIv)) - respAuth.Authenticate(buffer.Value, buffer.Value[this.config.Cipher.IVSize():]) + respAuth.Authenticate(response.Value, response.Value[this.config.Cipher.IVSize():]) } this.udpHub.WriteTo(response.Value, dest) @@ -155,7 +153,7 @@ func (this *Shadowsocks) handleConnection(conn *hub.TCPConn) { return } - request, err := ReadRequest(reader, NewAuthenticator(HeaderKeyGenerator(iv, key))) + request, err := ReadRequest(reader, NewAuthenticator(HeaderKeyGenerator(iv, key)), false) if err != nil { return }