func TestNormalChunkWriting(t *testing.T) { assert := assert.On(t) buffer := alloc.NewLocalBuffer(512).Clear() writer := NewChunkWriter(buffer, NewAuthenticator(ChunkKeyGenerator( []byte{21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36}))) err := writer.Write(alloc.NewLocalBuffer(256).Clear().Append([]byte{11, 12, 13, 14, 15, 16, 17, 18})) assert.Error(err).IsNil() assert.Bytes(buffer.Value).Equals([]byte{0, 8, 39, 228, 69, 96, 133, 39, 254, 26, 201, 70, 11, 12, 13, 14, 15, 16, 17, 18}) }
func TestUDPEncoding(t *testing.T) { assert := assert.On(t) request := &protocol.RequestHeader{ Version: Version, Command: protocol.RequestCommandUDP, Address: v2net.LocalHostIP, Port: 1234, User: &protocol.User{ Email: "*****@*****.**", Account: loader.NewTypedSettings(&Account{ Password: "******", CipherType: CipherType_AES_128_CFB, Ota: Account_Disabled, }), }, } data := alloc.NewLocalBuffer(256).Clear().AppendString("test string") encodedData, err := EncodeUDPPacket(request, data) assert.Error(err).IsNil() decodedRequest, decodedData, err := DecodeUDPPacket(request.User, encodedData) assert.Error(err).IsNil() assert.Bytes(decodedData.Value).Equals(data.Value) assert.Address(decodedRequest.Address).Equals(request.Address) assert.Port(decodedRequest.Port).Equals(request.Port) }
func TestResponseWrite(t *testing.T) { assert := assert.On(t) response := Socks5Response{ socksVersion, ErrorSuccess, AddrTypeIPv4, [4]byte{0x72, 0x72, 0x72, 0x72}, "", [16]byte{}, v2net.Port(53), } buffer := alloc.NewLocalBuffer(2048).Clear() defer buffer.Release() response.Write(buffer) expectedBytes := []byte{ socksVersion, ErrorSuccess, byte(0x00), AddrTypeIPv4, 0x72, 0x72, 0x72, 0x72, byte(0x00), byte(0x035), } assert.Bytes(buffer.Value).Equals(expectedBytes) }
func TestTCPRequest(t *testing.T) { assert := assert.On(t) request := &protocol.RequestHeader{ Version: Version, Command: protocol.RequestCommandTCP, Address: v2net.LocalHostIP, Option: RequestOptionOneTimeAuth, Port: 1234, User: &protocol.User{ Email: "*****@*****.**", Account: loader.NewTypedSettings(&Account{ Password: "******", CipherType: CipherType_CHACHA20, }), }, } data := alloc.NewLocalBuffer(256).Clear().AppendString("test string") cache := alloc.NewBuffer().Clear() writer, err := WriteTCPRequest(request, cache) assert.Error(err).IsNil() writer.Write(data) decodedRequest, reader, err := ReadTCPSession(request.User, cache) assert.Error(err).IsNil() assert.Address(decodedRequest.Address).Equals(request.Address) assert.Port(decodedRequest.Port).Equals(request.Port) decodedData, err := reader.Read() assert.Error(err).IsNil() assert.Bytes(decodedData.Value).Equals([]byte("test string")) }
func (this *VMessOutboundHandler) handleRequest(session *encoding.ClientSession, conn internet.Connection, request *protocol.RequestHeader, payload *alloc.Buffer, input v2io.Reader, finish *sync.Mutex) { defer finish.Unlock() writer := v2io.NewBufferedWriter(conn) defer writer.Release() session.EncodeRequestHeader(request, writer) bodyWriter := session.EncodeRequestBody(writer) var streamWriter v2io.Writer = v2io.NewAdaptiveWriter(bodyWriter) if request.Option.Has(protocol.RequestOptionChunkStream) { streamWriter = vmessio.NewAuthChunkWriter(streamWriter) } if !payload.IsEmpty() { if err := streamWriter.Write(payload); err != nil { conn.SetReusable(false) } } writer.SetCached(false) err := v2io.Pipe(input, streamWriter) if err != io.EOF { conn.SetReusable(false) } if request.Option.Has(protocol.RequestOptionChunkStream) { err := streamWriter.Write(alloc.NewLocalBuffer(32).Clear()) if err != nil { conn.SetReusable(false) } } streamWriter.Release() return }
func ReadUserPassRequest(reader io.Reader) (request Socks5UserPassRequest, err error) { buffer := alloc.NewLocalBuffer(512) defer buffer.Release() _, err = reader.Read(buffer.Value[0:2]) if err != nil { return } request.version = buffer.Value[0] nUsername := buffer.Value[1] nBytes, err := reader.Read(buffer.Value[:nUsername]) if err != nil { return } request.username = string(buffer.Value[:nBytes]) _, err = reader.Read(buffer.Value[0:1]) if err != nil { return } nPassword := buffer.Value[0] nBytes, err = reader.Read(buffer.Value[:nPassword]) if err != nil { return } request.password = string(buffer.Value[:nBytes]) return }
func (this *ChunkReader) Read() (*alloc.Buffer, error) { buffer := alloc.NewBuffer() if _, err := io.ReadFull(this.reader, buffer.Value[:2]); err != nil { buffer.Release() return nil, err } // There is a potential buffer overflow here. Large buffer is 64K bytes, // while uin16 + 10 will be more than that length := serial.BytesToUint16(buffer.Value[:2]) + AuthSize if length > alloc.BufferSize { // Theoretically the size of a chunk is 64K, but most Shadowsocks implementations used <4K buffer. buffer.Release() buffer = alloc.NewLocalBuffer(int(length) + 128) } if _, err := io.ReadFull(this.reader, buffer.Value[:length]); err != nil { buffer.Release() return nil, err } buffer.Slice(0, int(length)) authBytes := buffer.Value[:AuthSize] payload := buffer.Value[AuthSize:] actualAuthBytes := this.auth.Authenticate(nil, payload) if !bytes.Equal(authBytes, actualAuthBytes) { buffer.Release() return nil, errors.New("Shadowsocks|AuthenticationReader: Invalid auth.") } buffer.SliceFrom(AuthSize) return buffer, nil }
func MarshalCommand(command interface{}, writer io.Writer) error { if command == nil { return ErrUnknownCommand } var cmdId byte var factory CommandFactory switch command.(type) { case *protocol.CommandSwitchAccount: factory = new(CommandSwitchAccountFactory) cmdId = 1 default: return ErrUnknownCommand } buffer := alloc.NewLocalBuffer(512).Clear() defer buffer.Release() err := factory.Marshal(command, buffer) if err != nil { return err } auth := Authenticate(buffer.Value) len := buffer.Len() + 4 if len > 255 { return ErrCommandTooLarge } writer.Write([]byte{cmdId, byte(len), byte(auth >> 24), byte(auth >> 16), byte(auth >> 8), byte(auth)}) writer.Write(buffer.Value) return nil }
func (this *DefaultDispatcher) DispatchToOutbound(meta *proxy.InboundHandlerMeta, session *proxy.SessionInfo) ray.InboundRay { direct := ray.NewRay() dispatcher := this.ohm.GetDefaultHandler() destination := session.Destination if this.router != nil { if tag, err := this.router.TakeDetour(destination); err == nil { if handler := this.ohm.GetHandler(tag); handler != nil { log.Info("DefaultDispatcher: Taking detour [", tag, "] for [", destination, "].") dispatcher = handler } else { log.Warning("DefaultDispatcher: Nonexisting tag: ", tag) } } else { log.Info("DefaultDispatcher: Default route for ", destination) } } if meta.AllowPassiveConnection { go dispatcher.Dispatch(destination, alloc.NewLocalBuffer(32).Clear(), direct) } else { go this.FilterPacketAndDispatch(destination, direct, dispatcher) } return direct }
func TestSocks4AuthenticationResponseToBytes(t *testing.T) { assert := assert.On(t) response := NewSocks4AuthenticationResponse(byte(0x10), 443, []byte{1, 2, 3, 4}) buffer := alloc.NewLocalBuffer(2048).Clear() defer buffer.Release() response.Write(buffer) assert.Bytes(buffer.Value).Equals([]byte{0x00, 0x10, 0x01, 0xBB, 0x01, 0x02, 0x03, 0x04}) }
func TestSRTPOpenSeal(t *testing.T) { assert := assert.On(t) content := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g'} payload := alloc.NewLocalBuffer(2048).Clear().Append(content) srtp := SRTP{} srtp.Seal(payload) assert.Int(payload.Len()).GreaterThan(len(content)) assert.Bool(srtp.Open(payload)).IsTrue() assert.Bytes(content).Equals(payload.Bytes()) }
func TestSetIPv6(t *testing.T) { assert := assert.On(t) response := NewSocks5Response() response.SetIPv6([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}) buffer := alloc.NewLocalBuffer(2048).Clear() defer buffer.Release() response.Write(buffer) assert.Bytes(buffer.Value).Equals([]byte{ socksVersion, 0, 0, AddrTypeIPv6, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0}) }
func TestSetDomain(t *testing.T) { assert := assert.On(t) response := NewSocks5Response() response.SetDomain("v2ray.com") buffer := alloc.NewLocalBuffer(2048).Clear() defer buffer.Release() response.Write(buffer) assert.Bytes(buffer.Value).Equals([]byte{ socksVersion, 0, 0, AddrTypeDomain, 9, 118, 50, 114, 97, 121, 46, 99, 111, 109, 0, 0}) }
func TestSimpleAuthenticator2(t *testing.T) { assert := assert.On(t) buffer := alloc.NewLocalBuffer(512).Clear() buffer.AppendBytes('1', '2') auth := NewSimpleAuthenticator() auth.Seal(buffer) assert.Bool(auth.Open(buffer)).IsTrue() assert.Bytes(buffer.Value).Equals([]byte{'1', '2'}) }
func BenchmarkSimpleAuthenticator(b *testing.B) { buffer := alloc.NewLocalBuffer(2048).Clear() buffer.Slice(0, 1024) rand.Read(buffer.Value) auth := NewSimpleAuthenticator() b.SetBytes(int64(buffer.Len())) b.ResetTimer() for i := 0; i < b.N; i++ { auth.Seal(buffer) auth.Open(buffer) } }
func TestReaderWriter(t *testing.T) { assert := assert.On(t) cache := alloc.NewBuffer() writer := NewHeaderWriter(alloc.NewLocalBuffer(256).Clear().AppendString("abcd" + ENDING)) writer.Write(cache) cache.Write([]byte{'e', 'f', 'g'}) reader := &HeaderReader{} buffer, err := reader.Read(cache) assert.Error(err).IsNil() assert.Bytes(buffer.Value).Equals([]byte{'e', 'f', 'g'}) }
func ReadRequest(reader io.Reader) (request *Socks5Request, err error) { buffer := alloc.NewLocalBuffer(512) defer buffer.Release() _, err = io.ReadFull(reader, buffer.Value[:4]) if err != nil { return } request = &Socks5Request{ Version: buffer.Value[0], Command: buffer.Value[1], // buffer[2] is a reserved field AddrType: buffer.Value[3], } switch request.AddrType { case AddrTypeIPv4: _, err = io.ReadFull(reader, request.IPv4[:]) if err != nil { return } case AddrTypeDomain: _, err = io.ReadFull(reader, buffer.Value[0:1]) if err != nil { return } domainLength := buffer.Value[0] _, err = io.ReadFull(reader, buffer.Value[:domainLength]) if err != nil { return } request.Domain = string(append([]byte(nil), buffer.Value[:domainLength]...)) case AddrTypeIPv6: _, err = io.ReadFull(reader, request.IPv6[:]) if err != nil { return } default: err = fmt.Errorf("Socks: Unexpected address type %d", request.AddrType) return } _, err = io.ReadFull(reader, buffer.Value[:2]) if err != nil { return } request.Port = v2net.PortFromBytes(buffer.Value[:2]) return }
func (this HttpAuthenticator) GetClientWriter() *HeaderWriter { header := alloc.NewLocalBuffer(2048).Clear() config := this.config.Request header.AppendString(config.Method.GetValue()).AppendString(" ").AppendString(config.PickUri()).AppendString(" ").AppendString(config.GetFullVersion()).AppendString(CRLF) headers := config.PickHeaders() for _, h := range headers { header.AppendString(h).AppendString(CRLF) } header.AppendString(CRLF) return &HeaderWriter{ header: header, } }
func (this *Server) handleUDPPayload(payload *alloc.Buffer, session *proxy.SessionInfo) { source := session.Source log.Info("Socks: Client UDP connection from ", source) request, err := protocol.ReadUDPRequest(payload.Value) payload.Release() if err != nil { log.Error("Socks: Failed to parse UDP request: ", err) return } if request.Data.Len() == 0 { request.Data.Release() return } if request.Fragment != 0 { log.Warning("Socks: Dropping fragmented UDP packets.") // TODO handle fragments request.Data.Release() return } log.Info("Socks: Send packet to ", request.Destination(), " with ", request.Data.Len(), " bytes") log.Access(source, request.Destination, log.AccessAccepted, "") this.udpServer.Dispatch(&proxy.SessionInfo{Source: source, Destination: request.Destination()}, request.Data, func(destination v2net.Destination, payload *alloc.Buffer) { response := &protocol.Socks5UDPRequest{ Fragment: 0, Address: request.Destination().Address(), Port: request.Destination().Port(), Data: payload, } log.Info("Socks: Writing back UDP response with ", payload.Len(), " bytes to ", destination) udpMessage := alloc.NewLocalBuffer(2048).Clear() response.Write(udpMessage) this.udpMutex.RLock() if !this.accepting { this.udpMutex.RUnlock() return } nBytes, err := this.udpHub.WriteTo(udpMessage.Value, destination) this.udpMutex.RUnlock() udpMessage.Release() response.Data.Release() if err != nil { log.Error("Socks: failed to write UDP message (", nBytes, " bytes) to ", destination, ": ", err) } }) }
func (this *UDPReader) Read() (*alloc.Buffer, error) { buffer := alloc.NewLocalBuffer(2048) nBytes, err := this.Reader.Read(buffer.Value) if err != nil { buffer.Release() return nil, err } buffer.Slice(0, nBytes) _, payload, err := DecodeUDPPacket(this.User, buffer) if err != nil { buffer.Release() return nil, err } return payload, nil }
func (this *BufferedSegmentWriter) Write(seg Segment) { this.Lock() defer this.Unlock() nBytes := seg.ByteSize() if uint32(this.buffer.Len()+nBytes) > this.mtu { this.FlushWithoutLock() } if this.buffer == nil { this.buffer = alloc.NewLocalBuffer(2048).Clear() } this.buffer.Value = seg.Bytes(this.buffer.Value) }
func EncodeUDPPacket(request *protocol.RequestHeader, payload *alloc.Buffer) (*alloc.Buffer, error) { user := request.User rawAccount, err := user.GetTypedAccount() if err != nil { return nil, errors.New("Shadowsocks|UDP: Failed to parse account: " + err.Error()) } account := rawAccount.(*ShadowsocksAccount) buffer := alloc.NewLocalBuffer(2048) ivLen := account.Cipher.IVSize() buffer.Slice(0, ivLen) rand.Read(buffer.Value) iv := buffer.Value switch request.Address.Family() { case v2net.AddressFamilyIPv4: buffer.AppendBytes(AddrTypeIPv4) buffer.Append([]byte(request.Address.IP())) case v2net.AddressFamilyIPv6: buffer.AppendBytes(AddrTypeIPv6) buffer.Append([]byte(request.Address.IP())) case v2net.AddressFamilyDomain: buffer.AppendBytes(AddrTypeDomain, byte(len(request.Address.Domain()))) buffer.Append([]byte(request.Address.Domain())) default: return nil, errors.New("Shadowsocks|UDP: Unsupported address type. ") } buffer.AppendUint16(uint16(request.Port)) buffer.Append(payload.Value) if request.Option.Has(RequestOptionOneTimeAuth) { authenticator := NewAuthenticator(HeaderKeyGenerator(account.Key, iv)) buffer.Value[ivLen] |= 0x10 buffer.Value = authenticator.Authenticate(buffer.Value, buffer.Value[ivLen:]) } stream, err := account.Cipher.NewEncodingStream(account.Key, iv) if err != nil { return nil, errors.New("Shadowsocks|TCP: Failed to create encoding stream: " + err.Error()) } stream.XORKeyStream(buffer.Value[ivLen:], buffer.Value[ivLen:]) return buffer, nil }
func (this HttpAuthenticator) GetServerWriter() *HeaderWriter { header := alloc.NewLocalBuffer(2048).Clear() config := this.config.Response header.AppendString(config.GetFullVersion()).AppendString(" ").AppendString(config.Status.GetCode()).AppendString(" ").AppendString(config.Status.GetReason()).AppendString(CRLF) headers := config.PickHeaders() for _, h := range headers { header.AppendString(h).AppendString(CRLF) } if !config.HasHeader("Date") { header.AppendString("Date: ").AppendString(time.Now().Format(http.TimeFormat)).AppendString(CRLF) } header.AppendString(CRLF) return &HeaderWriter{ header: header, } }
func (this *Connection) FetchInputFrom(conn io.Reader) { go func() { payload := alloc.NewLocalBuffer(2048) defer payload.Release() for this.State() != StateTerminated { payload.Reset() nBytes, err := conn.Read(payload.Value) if err != nil { return } payload.Slice(0, nBytes) if this.block.Open(payload) { this.Input(payload.Value) } } }() }
func TestUnreachableDestination(t *testing.T) { assert := assert.On(t) freedom := NewFreedomConnection( &Config{}, app.NewSpace(), &proxy.OutboundHandlerMeta{ Address: v2net.AnyIP, StreamSettings: &internet.StreamConfig{ Network: v2net.Network_RawTCP, }, }) traffic := ray.NewRay() data2Send := "Data to be sent to remote" payload := alloc.NewLocalBuffer(2048).Clear().Append([]byte(data2Send)) err := freedom.Dispatch(v2net.TCPDestination(v2net.IPAddress([]byte{127, 0, 0, 1}), 128), payload, traffic) assert.Error(err).IsNotNil() }
func (*HeaderReader) Read(reader io.Reader) (*alloc.Buffer, error) { buffer := alloc.NewLocalBuffer(2048) for { _, err := buffer.FillFrom(reader) if err != nil { return nil, err } if n := bytes.Index(buffer.Value, []byte(ENDING)); n != -1 { buffer.SliceFrom(n + len(ENDING)) break } if buffer.Len() >= len(ENDING) { copy(buffer.Value, buffer.Value[buffer.Len()-len(ENDING):]) buffer.Slice(0, len(ENDING)) } } if buffer.IsEmpty() { buffer.Release() return nil, nil } return buffer, nil }
func TestSinglePacket(t *testing.T) { assert := assert.On(t) tcpServer := &tcp.Server{ MsgProcessor: func(data []byte) []byte { buffer := make([]byte, 0, 2048) buffer = append(buffer, []byte("Processed: ")...) buffer = append(buffer, data...) return buffer }, } _, err := tcpServer.Start() assert.Error(err).IsNil() space := app.NewSpace() freedom := NewFreedomConnection( &Config{}, space, &proxy.OutboundHandlerMeta{ Address: v2net.AnyIP, StreamSettings: &internet.StreamConfig{ Network: v2net.Network_RawTCP, }, }) space.Initialize() traffic := ray.NewRay() data2Send := "Data to be sent to remote" payload := alloc.NewLocalBuffer(2048).Clear().Append([]byte(data2Send)) go freedom.Dispatch(v2net.TCPDestination(v2net.LocalHostIP, tcpServer.Port), payload, traffic) traffic.InboundInput().Close() respPayload, err := traffic.InboundOutput().Read() assert.Error(err).IsNil() assert.Bytes(respPayload.Value).Equals([]byte("Processed: Data to be sent to remote")) tcpServer.Close() }
func TestDataSegment(t *testing.T) { assert := assert.On(t) seg := &DataSegment{ Conv: 1, Timestamp: 3, Number: 4, SendingNext: 5, Data: alloc.NewLocalBuffer(512).Clear().Append([]byte{'a', 'b', 'c', 'd'}), } nBytes := seg.ByteSize() bytes := seg.Bytes(nil) assert.Int(len(bytes)).Equals(nBytes) iseg, _ := ReadSegment(bytes) seg2 := iseg.(*DataSegment) assert.Uint16(seg2.Conv).Equals(seg.Conv) assert.Uint32(seg2.Timestamp).Equals(seg.Timestamp) assert.Uint32(seg2.SendingNext).Equals(seg.SendingNext) assert.Uint32(seg2.Number).Equals(seg.Number) assert.Bytes(seg2.Data.Value).Equals(seg.Data.Value) }
func (this *HTTPResponse) WriteTo(writer v2io.Writer) { writer.Write(alloc.NewLocalBuffer(512).Clear().AppendString(http403response)) }
func (this *VMessInboundHandler) HandleConnection(connection internet.Connection) { defer connection.Close() if !this.accepting { return } connReader := v2net.NewTimeOutReader(8, connection) defer connReader.Release() reader := v2io.NewBufferedReader(connReader) defer reader.Release() this.RLock() if !this.accepting { this.RUnlock() return } session := encoding.NewServerSession(this.clients) defer session.Release() request, err := session.DecodeRequestHeader(reader) this.RUnlock() if err != nil { if err != io.EOF { log.Access(connection.RemoteAddr(), "", log.AccessRejected, err) log.Warning("VMessIn: Invalid request from ", connection.RemoteAddr(), ": ", err) } connection.SetReusable(false) return } log.Access(connection.RemoteAddr(), request.Destination(), log.AccessAccepted, "") log.Info("VMessIn: Received request for ", request.Destination()) connection.SetReusable(request.Option.Has(protocol.RequestOptionConnectionReuse)) ray := this.packetDispatcher.DispatchToOutbound(this.meta, &proxy.SessionInfo{ Source: v2net.DestinationFromAddr(connection.RemoteAddr()), Destination: request.Destination(), }) input := ray.InboundInput() output := ray.InboundOutput() defer input.Close() defer output.Release() var readFinish sync.Mutex readFinish.Lock() userSettings := protocol.GetUserSettings(request.User.Level) connReader.SetTimeOut(userSettings.PayloadReadTimeout) reader.SetCached(false) go func() { bodyReader := session.DecodeRequestBody(reader) var requestReader v2io.Reader if request.Option.Has(protocol.RequestOptionChunkStream) { requestReader = vmessio.NewAuthChunkReader(bodyReader) } else { requestReader = v2io.NewAdaptiveReader(bodyReader) } err := v2io.Pipe(requestReader, input) if err != io.EOF { connection.SetReusable(false) } requestReader.Release() input.Close() readFinish.Unlock() }() writer := v2io.NewBufferedWriter(connection) defer writer.Release() response := &protocol.ResponseHeader{ Command: this.generateCommand(request), } if connection.Reusable() { response.Option.Set(protocol.ResponseOptionConnectionReuse) } session.EncodeResponseHeader(response, writer) bodyWriter := session.EncodeResponseBody(writer) var v2writer v2io.Writer = v2io.NewAdaptiveWriter(bodyWriter) if request.Option.Has(protocol.RequestOptionChunkStream) { v2writer = vmessio.NewAuthChunkWriter(v2writer) } // Optimize for small response packet if data, err := output.Read(); err == nil { if err := v2writer.Write(data); err != nil { connection.SetReusable(false) } writer.SetCached(false) err = v2io.Pipe(output, v2writer) if err != io.EOF { connection.SetReusable(false) } } output.Release() if request.Option.Has(protocol.RequestOptionChunkStream) { if err := v2writer.Write(alloc.NewLocalBuffer(32).Clear()); err != nil { connection.SetReusable(false) } } writer.Flush() v2writer.Release() readFinish.Lock() }