func (this *DnsCache) Add(context app.Context, domain string, ip net.IP) { callerTag := context.CallerTag() if !this.config.IsTrustedSource(serial.StringLiteral(callerTag)) { return } this.cache.Set(serial.StringLiteral(domain), newEntry(domain, ip)) }
func (this *VMessInboundHandler) HandleConnection(connection *net.TCPConn) error { defer connection.Close() connReader := v2net.NewTimeOutReader(16, connection) requestReader := protocol.NewVMessRequestReader(this.clients) request, err := requestReader.Read(connReader) if err != nil { log.Access(connection.RemoteAddr(), serial.StringLiteral(""), log.AccessRejected, serial.StringLiteral(err.Error())) log.Warning("VMessIn: Invalid request from ", connection.RemoteAddr(), ": ", err) return err } log.Access(connection.RemoteAddr(), request.Address, log.AccessAccepted, serial.StringLiteral("")) log.Debug("VMessIn: Received request for ", request.Address) ray := this.space.PacketDispatcher().DispatchToOutbound(v2net.NewPacket(request.Destination(), nil, true)) input := ray.InboundInput() output := ray.InboundOutput() var readFinish, writeFinish sync.Mutex readFinish.Lock() writeFinish.Lock() userSettings := vmess.GetUserSettings(request.User.Level) connReader.SetTimeOut(userSettings.PayloadReadTimeout) go handleInput(request, connReader, input, &readFinish) responseKey := md5.Sum(request.RequestKey) responseIV := md5.Sum(request.RequestIV) aesStream, err := v2crypto.NewAesEncryptionStream(responseKey[:], responseIV[:]) if err != nil { log.Error("VMessIn: Failed to create AES decryption stream: ", err) close(input) return err } responseWriter := v2crypto.NewCryptionWriter(aesStream, connection) // Optimize for small response packet buffer := alloc.NewLargeBuffer().Clear() defer buffer.Release() buffer.AppendBytes(request.ResponseHeader[0] ^ request.ResponseHeader[1]) buffer.AppendBytes(request.ResponseHeader[2] ^ request.ResponseHeader[3]) buffer.AppendBytes(byte(0), byte(0)) if data, open := <-output; open { buffer.Append(data.Value) data.Release() responseWriter.Write(buffer.Value) go handleOutput(request, responseWriter, output, &writeFinish) writeFinish.Lock() } connection.CloseWrite() readFinish.Lock() return nil }
func (this *RegexpDomainMatcher) Apply(dest v2net.Destination) bool { if !dest.Address().IsDomain() { return false } domain := serial.StringLiteral(dest.Address().Domain()) return this.pattern.MatchString(domain.ToLower().String()) }
func (this *PlainDomainMatcher) Apply(dest v2net.Destination) bool { if !dest.Address().IsDomain() { return false } domain := serial.StringLiteral(dest.Address().Domain()) return domain.Contains(this.pattern) }
func TestAccessLog(t *testing.T) { v2testing.Current(t) filename := "/tmp/test_access_log.log" InitAccessLogger(filename) _, err := os.Stat(filename) assert.Error(err).IsNil() Access("test_from", "test_to", AccessAccepted, "test_reason") <-time.After(2 * time.Second) accessLoggerInstance.(*fileLogWriter).close() accessLoggerInstance = &noOpLogWriter{} content, err := ioutil.ReadFile(filename) assert.Error(err).IsNil() contentStr := serial.StringLiteral(content) assert.String(contentStr).Contains(serial.StringLiteral("test_from")) assert.String(contentStr).Contains(serial.StringLiteral("test_to")) assert.String(contentStr).Contains(serial.StringLiteral("test_reason")) assert.String(contentStr).Contains(serial.StringLiteral("accepted")) }
func TestStreamLogger(t *testing.T) { v2testing.Current(t) buffer := bytes.NewBuffer(make([]byte, 0, 1024)) infoLogger = &stdOutLogWriter{ logger: log.New(buffer, "", 0), } Info("Test ", "Stream Logger", " Format") assert.StringLiteral(string(buffer.Bytes())).Equals("[Info]Test Stream Logger Format" + platform.LineSeparator()) buffer.Reset() errorLogger = infoLogger Error("Test ", serial.StringLiteral("literal"), " Format") assert.StringLiteral(string(buffer.Bytes())).Equals("[Error]Test literal Format" + platform.LineSeparator()) }
func TestDnsAdd(t *testing.T) { v2testing.Current(t) domain := "v2ray.com" cache := dns.NewCache(&dns.CacheConfig{ TrustedTags: map[serial.StringLiteral]bool{ serial.StringLiteral("testtag"): true, }, }) ip := cache.Get(&apptesting.Context{}, domain) netassert.IP(ip).IsNil() cache.Add(&apptesting.Context{CallerTagValue: "notvalidtag"}, domain, []byte{1, 2, 3, 4}) ip = cache.Get(&apptesting.Context{}, domain) netassert.IP(ip).IsNil() cache.Add(&apptesting.Context{CallerTagValue: "testtag"}, domain, []byte{1, 2, 3, 4}) ip = cache.Get(&apptesting.Context{}, domain) netassert.IP(ip).Equals(net.IP([]byte{1, 2, 3, 4})) }
func (subject *StringSubject) NotEquals(expectation string) { if subject.value.String() == expectation { subject.Fail(subject.DisplayString(), "is not equal to ", serial.StringLiteral(expectation)) } }
func (subject *PortSubject) IsValid() { if subject.value == 0 { subject.Fail(subject.DisplayString(), "is", serial.StringLiteral("a valid port")) } }
func (this *DnsCache) Get(context app.Context, domain string) net.IP { if value := this.cache.Get(serial.StringLiteral(domain)); value != nil { return value.(*entry).ip } return nil }
func (this *Shadowsocks) handleConnection(conn *hub.TCPConn) { defer conn.Close() buffer := alloc.NewSmallBuffer() defer buffer.Release() _, err := io.ReadFull(conn, buffer.Value[:this.config.Cipher.IVSize()]) if err != nil { log.Access(conn.RemoteAddr(), serial.StringLiteral(""), log.AccessRejected, serial.StringLiteral(err.Error())) 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, NewAuthenticator(HeaderKeyGenerator(iv, key)), false) if err != nil { log.Access(conn.RemoteAddr(), serial.StringLiteral(""), log.AccessRejected, serial.StringLiteral(err.Error())) log.Warning("Shadowsocks: Invalid request from ", conn.RemoteAddr(), ": ", err) return } dest := v2net.TCPDestination(request.Address, request.Port) log.Access(conn.RemoteAddr(), dest, log.AccessAccepted, serial.StringLiteral("")) log.Info("Shadowsocks: Tunnelling request to ", dest) packet := v2net.NewPacket(dest, nil, true) ray := this.packetDispatcher.DispatchToOutbound(packet) var writeFinish sync.Mutex writeFinish.Lock() go func() { if payload, ok := <-ray.InboundOutput(); ok { payload.SliceBack(16) rand.Read(payload.Value[:16]) writer, err := this.config.Cipher.NewEncodingStream(key, payload.Value[:16], conn) if err != nil { log.Error("Shadowsocks: Failed to create encoding stream: ", err) return } writer.Write(payload.Value) payload.Release() v2io.ChanToRawWriter(writer, ray.InboundOutput()) } writeFinish.Unlock() }() var payloadReader v2io.Reader if request.OTA { payloadAuth := NewAuthenticator(ChunkKeyGenerator(iv)) payloadReader = NewChunkReader(reader, payloadAuth) } else { payloadReader = v2io.NewAdaptiveReader(reader) } v2io.ReaderToChan(ray.InboundInput(), payloadReader) close(ray.InboundInput()) writeFinish.Lock() }
func (this *Shadowsocks) handlerUDPPayload(payload *alloc.Buffer, source v2net.Destination) { defer payload.Release() iv := payload.Value[:this.config.Cipher.IVSize()] key := this.config.Key payload.SliceFrom(this.config.Cipher.IVSize()) reader, err := this.config.Cipher.NewDecodingStream(key, iv, payload) if err != nil { log.Error("Shadowsocks: Failed to create decoding stream: ", err) return } request, err := ReadRequest(reader, NewAuthenticator(HeaderKeyGenerator(key, iv)), true) if err != nil { log.Access(source, serial.StringLiteral(""), log.AccessRejected, serial.StringLiteral(err.Error())) log.Warning("Shadowsocks: Invalid request from ", source, ": ", err) return } dest := v2net.UDPDestination(request.Address, request.Port) log.Access(source, dest, log.AccessAccepted, serial.StringLiteral("")) log.Info("Shadowsocks: Tunnelling request to ", dest) packet := v2net.NewPacket(dest, request.UDPPayload, false) this.udpServer.Dispatch(source, packet, func(packet v2net.Packet) { defer packet.Chunk().Release() response := alloc.NewBuffer().Slice(0, this.config.Cipher.IVSize()) defer response.Release() rand.Read(response.Value) respIv := response.Value writer, err := this.config.Cipher.NewEncodingStream(key, respIv, response) if err != nil { log.Error("Shadowsocks: Failed to create encoding stream: ", err) return } switch { case request.Address.IsIPv4(): writer.Write([]byte{AddrTypeIPv4}) writer.Write(request.Address.IP()) case request.Address.IsIPv6(): writer.Write([]byte{AddrTypeIPv6}) writer.Write(request.Address.IP()) case request.Address.IsDomain(): writer.Write([]byte{AddrTypeDomain, byte(len(request.Address.Domain()))}) writer.Write([]byte(request.Address.Domain())) } writer.Write(request.Port.Bytes()) writer.Write(packet.Chunk().Value) if request.OTA { respAuth := NewAuthenticator(HeaderKeyGenerator(key, respIv)) respAuth.Authenticate(response.Value, response.Value[this.config.Cipher.IVSize():]) } this.udpHub.WriteTo(response.Value, source) }) }
func (subject *AddressSubject) IsNotIPv6() { if subject.value.IsIPv6() { subject.Fail(subject.DisplayString(), "is not", serial.StringLiteral("an IPv6 address")) } }
func (subject *AddressSubject) IsNotDomain() { if subject.value.IsDomain() { subject.Fail(subject.DisplayString(), "is not", serial.StringLiteral("a domain address")) } }
func (this *DestinationSubject) IsTCP() { if !this.value.IsTCP() { this.Fail(this.DisplayString(), "is", serial.StringLiteral("a TCP destination")) } }
func (subject *AddressSubject) IsIPv4() { if !subject.value.IsIPv4() { subject.Fail(subject.DisplayString(), "is", serial.StringLiteral("an IPv4 address")) } }
func StringLiteral(value string) *StringSubject { return String(serial.StringLiteral((value))) }
func NewPlainDomainMatcher(pattern string) *PlainDomainMatcher { return &PlainDomainMatcher{ pattern: serial.StringLiteral(pattern), } }
func (subject *IPSubject) IsNil() { if subject.value != nil { subject.Fail(subject.DisplayString(), "is", serial.StringLiteral("nil")) } }
func (this *VMessInboundHandler) HandleConnection(connection *hub.TCPConn) { defer connection.Close() connReader := v2net.NewTimeOutReader(16, connection) reader := v2io.NewBufferedReader(connReader) session := raw.NewServerSession(this.clients) request, err := session.DecodeRequestHeader(reader) if err != nil { log.Access(connection.RemoteAddr(), serial.StringLiteral(""), log.AccessRejected, serial.StringLiteral(err.Error())) log.Warning("VMessIn: Invalid request from ", connection.RemoteAddr(), ": ", err) return } log.Access(connection.RemoteAddr(), request.Destination(), log.AccessAccepted, serial.StringLiteral("")) log.Debug("VMessIn: Received request for ", request.Destination()) ray := this.packetDispatcher.DispatchToOutbound(v2net.NewPacket(request.Destination(), nil, true)) input := ray.InboundInput() output := ray.InboundOutput() var readFinish, writeFinish sync.Mutex readFinish.Lock() writeFinish.Lock() userSettings := proto.GetUserSettings(request.User.Level) connReader.SetTimeOut(userSettings.PayloadReadTimeout) reader.SetCached(false) go func() { defer close(input) defer readFinish.Unlock() bodyReader := session.DecodeRequestBody(reader) var requestReader v2io.Reader if request.Option.IsChunkStream() { requestReader = vmessio.NewAuthChunkReader(bodyReader) } else { requestReader = v2io.NewAdaptiveReader(bodyReader) } v2io.ReaderToChan(input, requestReader) }() writer := v2io.NewBufferedWriter(connection) response := &proto.ResponseHeader{ Command: this.generateCommand(request), } session.EncodeResponseHeader(response, writer) bodyWriter := session.EncodeResponseBody(writer) // Optimize for small response packet if data, open := <-output; open { if request.Option.IsChunkStream() { vmessio.Authenticate(data) } bodyWriter.Write(data.Value) data.Release() writer.SetCached(false) go func(finish *sync.Mutex) { var writer v2io.Writer = v2io.NewAdaptiveWriter(bodyWriter) if request.Option.IsChunkStream() { writer = vmessio.NewAuthChunkWriter(writer) } v2io.ChanToWriter(writer, output) finish.Unlock() }(&writeFinish) writeFinish.Lock() } connection.CloseWrite() readFinish.Lock() }
func (this *DestinationSubject) IsNotUDP() { if this.value.IsUDP() { this.Fail(this.DisplayString(), "is not", serial.StringLiteral("a UDP destination")) } }