func (this *VMessOutboundHandler) Dispatch(firstPacket v2net.Packet, ray ray.OutboundRay) error { vNextAddress, vNextUser := this.receiverManager.PickReceiver() command := protocol.CmdTCP if firstPacket.Destination().IsUDP() { command = protocol.CmdUDP } request := &protocol.VMessRequest{ Version: protocol.Version, User: vNextUser, Command: command, Address: firstPacket.Destination().Address(), Port: firstPacket.Destination().Port(), } if command == protocol.CmdUDP { request.Option |= protocol.OptionChunk } buffer := alloc.NewSmallBuffer() defer buffer.Release() // Buffer is released after communication finishes. io.ReadFull(rand.Reader, buffer.Value[:33]) // 16 + 16 + 1 request.RequestIV = buffer.Value[:16] request.RequestKey = buffer.Value[16:32] request.ResponseHeader = buffer.Value[32] return this.startCommunicate(request, vNextAddress, ray, firstPacket) }
func (this *OutboundConnectionHandler) Dispatch(packet v2net.Packet, ray ray.OutboundRay) error { input := ray.OutboundInput() output := ray.OutboundOutput() this.Destination = packet.Destination() if packet.Chunk() != nil { this.ConnOutput.Write(packet.Chunk().Value) packet.Chunk().Release() } if packet.MoreChunks() { writeFinish := &sync.Mutex{} writeFinish.Lock() go func() { v2io.ChanToRawWriter(this.ConnOutput, input) writeFinish.Unlock() }() writeFinish.Lock() } v2io.RawReaderToChan(output, this.ConnInput) close(output) return nil }
func (this *UDPServer) locateExistingAndDispatch(dest string, packet v2net.Packet) bool { this.RLock() defer this.RUnlock() if entry, found := this.conns[dest]; found { entry.inboundRay.InboundInput() <- packet.Chunk() return true } return false }
func (this *BlackHole) Dispatch(firstPacket v2net.Packet, ray ray.OutboundRay) error { if chunk := firstPacket.Chunk(); chunk != nil { chunk.Release() } close(ray.OutboundOutput()) if firstPacket.MoreChunks() { v2net.ChanToWriter(ioutil.Discard, ray.OutboundInput()) } return nil }
func (this *VMessOutboundHandler) handleRequest(conn net.Conn, request *protocol.VMessRequest, firstPacket v2net.Packet, input <-chan *alloc.Buffer, finish *sync.Mutex) { defer finish.Unlock() aesStream, err := v2crypto.NewAesEncryptionStream(request.RequestKey[:], request.RequestIV[:]) if err != nil { log.Error("VMessOut: Failed to create AES encryption stream: ", err) return } encryptRequestWriter := v2crypto.NewCryptionWriter(aesStream, conn) buffer := alloc.NewBuffer().Clear() defer buffer.Release() buffer, err = request.ToBytes(protocol.NewRandomTimestampGenerator(protocol.Timestamp(time.Now().Unix()), 30), buffer) if err != nil { log.Error("VMessOut: Failed to serialize VMess request: ", err) return } // Send first packet of payload together with request, in favor of small requests. firstChunk := firstPacket.Chunk() moreChunks := firstPacket.MoreChunks() for firstChunk == nil && moreChunks { firstChunk, moreChunks = <-input } if firstChunk == nil && !moreChunks { log.Warning("VMessOut: Nothing to send. Existing...") return } if request.IsChunkStream() { vmessio.Authenticate(firstChunk) } aesStream.XORKeyStream(firstChunk.Value, firstChunk.Value) buffer.Append(firstChunk.Value) firstChunk.Release() _, err = conn.Write(buffer.Value) if err != nil { log.Error("VMessOut: Failed to write VMess request: ", err) return } if moreChunks { var streamWriter v2io.Writer streamWriter = v2io.NewAdaptiveWriter(encryptRequestWriter) if request.IsChunkStream() { streamWriter = vmessio.NewAuthChunkWriter(streamWriter) } v2io.ChanToWriter(streamWriter, input) } return }
func (this *UDPServer) Dispatch(source v2net.Destination, packet v2net.Packet, callback UDPResponseCallback) { destString := source.String() + "-" + packet.Destination().String() if this.locateExistingAndDispatch(destString, packet) { return } this.Lock() inboundRay := this.packetDispatcher.DispatchToOutbound(v2net.NewPacket(packet.Destination(), packet.Chunk(), true)) this.conns[destString] = &connEntry{ inboundRay: inboundRay, callback: callback, } this.Unlock() go this.handleConnection(destString, inboundRay, source, callback) }
// Dispatches a Packet to an OutboundConnection. // The packet will be passed through the router (if configured), and then sent to an outbound // connection with matching tag. func (this *Point) DispatchToOutbound(context app.Context, packet v2net.Packet) ray.InboundRay { direct := ray.NewRay() dest := packet.Destination() dispatcher := this.och if this.router != nil { if tag, err := this.router.TakeDetour(dest); err == nil { if handler, found := this.odh[tag]; found { dispatcher = handler } } } go this.FilterPacketAndDispatch(packet, direct, dispatcher) return direct }
func handleRequest(conn net.Conn, request *protocol.VMessRequest, firstPacket v2net.Packet, input <-chan *alloc.Buffer, finish *sync.Mutex) { defer finish.Unlock() aesStream, err := v2crypto.NewAesEncryptionStream(request.RequestKey[:], request.RequestIV[:]) if err != nil { log.Error("VMessOut: Failed to create AES encryption stream: %v", err) return } encryptRequestWriter := v2crypto.NewCryptionWriter(aesStream, conn) buffer := alloc.NewBuffer().Clear() defer buffer.Release() buffer, err = request.ToBytes(user.NewTimeHash(user.HMACHash{}), user.GenerateRandomInt64InRange, buffer) if err != nil { log.Error("VMessOut: Failed to serialize VMess request: %v", err) return } // Send first packet of payload together with request, in favor of small requests. firstChunk := firstPacket.Chunk() moreChunks := firstPacket.MoreChunks() for firstChunk == nil && moreChunks { firstChunk, moreChunks = <-input } if firstChunk == nil && !moreChunks { log.Warning("VMessOut: Nothing to send. Existing...") return } aesStream.XORKeyStream(firstChunk.Value, firstChunk.Value) buffer.Append(firstChunk.Value) firstChunk.Release() _, err = conn.Write(buffer.Value) if err != nil { log.Error("VMessOut: Failed to write VMess request: %v", err) return } if moreChunks { v2net.ChanToWriter(encryptRequestWriter, input) } return }
func (this *Point) DispatchToOutbound(packet v2net.Packet) ray.InboundRay { direct := ray.NewRay() dest := packet.Destination() if this.router != nil { tag, err := this.router.TakeDetour(dest) if err == nil { handler, found := this.odh[tag] if found { go handler.Dispatch(packet, direct) return direct } } } go this.och.Dispatch(packet, direct) return direct }
func handleRequest(conn net.Conn, request *protocol.VMessRequest, firstPacket v2net.Packet, input <-chan *alloc.Buffer, finish *sync.Mutex) { defer finish.Unlock() encryptRequestWriter, err := v2io.NewAesEncryptWriter(request.RequestKey[:], request.RequestIV[:], conn) if err != nil { log.Error("VMessOut: Failed to create encrypt writer: %v", err) return } buffer := alloc.NewBuffer() buffer.Clear() requestBytes, err := request.ToBytes(user.NewTimeHash(user.HMACHash{}), user.GenerateRandomInt64InRange, buffer.Value) if err != nil { log.Error("VMessOut: Failed to serialize VMess request: %v", err) return } // Send first packet of payload together with request, in favor of small requests. firstChunk := firstPacket.Chunk() moreChunks := firstPacket.MoreChunks() if firstChunk == nil && moreChunks { firstChunk, moreChunks = <-input } if firstChunk != nil { encryptRequestWriter.Crypt(firstChunk.Value) requestBytes = append(requestBytes, firstChunk.Value...) firstChunk.Release() _, err = conn.Write(requestBytes) buffer.Release() if err != nil { log.Error("VMessOut: Failed to write VMess request: %v", err) return } } if moreChunks { v2net.ChanToWriter(encryptRequestWriter, input) } return }
// Dispatches a Packet to an OutboundConnection. // The packet will be passed through the router (if configured), and then sent to an outbound // connection with matching tag. func (this *Point) DispatchToOutbound(context app.Context, packet v2net.Packet) ray.InboundRay { direct := ray.NewRay() dest := packet.Destination() dispatcher := this.och if this.router != nil { if tag, err := this.router.TakeDetour(dest); err == nil { if handler, found := this.odh[tag]; found { log.Info("Point: Taking detour [", tag, "] for [", dest, "]", tag, dest) dispatcher = handler } else { log.Warning("Point: Unable to find routing destination: ", tag) } } } go this.FilterPacketAndDispatch(packet, direct, dispatcher) return direct }
func (this *VMessOutboundHandler) Dispatch(firstPacket v2net.Packet, ray ray.OutboundRay) error { vNextAddress, vNextUser := this.receiverManager.PickReceiver() command := proto.RequestCommandTCP if firstPacket.Destination().IsUDP() { command = proto.RequestCommandUDP } request := &proto.RequestHeader{ Version: raw.Version, User: vNextUser, Command: command, Address: firstPacket.Destination().Address(), Port: firstPacket.Destination().Port(), } if command == proto.RequestCommandUDP { request.Option |= proto.RequestOptionChunkStream } return this.startCommunicate(request, vNextAddress, ray, firstPacket) }
func (handler *VMessOutboundHandler) Dispatch(firstPacket v2net.Packet, ray ray.OutboundRay) error { vNextList := handler.vNextList if firstPacket.Destination().IsUDP() { vNextList = handler.vNextListUDP } vNextAddress, vNextUser := pickVNext(vNextList) command := protocol.CmdTCP if firstPacket.Destination().IsUDP() { command = protocol.CmdUDP } request := &protocol.VMessRequest{ Version: protocol.Version, User: vNextUser, Command: command, Address: firstPacket.Destination().Address(), } buffer := alloc.NewSmallBuffer() defer buffer.Release() v2net.ReadAllBytes(rand.Reader, buffer.Value[:36]) // 16 + 16 + 4 request.RequestIV = buffer.Value[:16] request.RequestKey = buffer.Value[16:32] request.ResponseHeader = buffer.Value[32:36] return startCommunicate(request, vNextAddress, ray, firstPacket) }
func (handler *OutboundConnectionHandler) Dispatch(packet v2net.Packet, ray core.OutboundRay) error { input := ray.OutboundInput() output := ray.OutboundOutput() handler.Destination = packet.Destination() if packet.Chunk() != nil { handler.Data2Send.Write(packet.Chunk().Value) } go func() { for { data, open := <-input if !open { break } handler.Data2Send.Write(data.Value) data.Release() } response := alloc.NewBuffer() response.Clear() response.Append(handler.Data2Return) output <- response close(output) }() return nil }
func (handler *VMessOutboundHandler) Dispatch(firstPacket v2net.Packet, ray core.OutboundRay) error { vNextList := handler.vNextList if firstPacket.Destination().IsUDP() { vNextList = handler.vNextListUDP } vNextAddress, vNextUser := pickVNext(vNextList) command := protocol.CmdTCP if firstPacket.Destination().IsUDP() { command = protocol.CmdUDP } request := &protocol.VMessRequest{ Version: protocol.Version, UserId: vNextUser.Id, Command: command, Address: firstPacket.Destination().Address(), } buffer := make([]byte, 36) // 16 + 16 + 4 rand.Read(buffer) request.RequestIV = buffer[:16] request.RequestKey = buffer[16:32] request.ResponseHeader = buffer[32:] go startCommunicate(request, vNextAddress, ray, firstPacket) return nil }
func (handler *OutboundConnectionHandler) Dispatch(packet v2net.Packet, ray core.OutboundRay) error { input := ray.OutboundInput() output := ray.OutboundOutput() handler.Destination = packet.Destination() if packet.Chunk() != nil { handler.Data2Send.Write(packet.Chunk()) } go func() { for { data, open := <-input if !open { break } handler.Data2Send.Write(data) } dataCopy := make([]byte, len(handler.Data2Return)) copy(dataCopy, handler.Data2Return) output <- dataCopy close(output) }() return nil }
func (this *VMessOutboundHandler) handleRequest(session *raw.ClientSession, conn net.Conn, request *proto.RequestHeader, firstPacket v2net.Packet, input <-chan *alloc.Buffer, finish *sync.Mutex) { defer finish.Unlock() writer := v2io.NewBufferedWriter(conn) session.EncodeRequestHeader(request, writer) // Send first packet of payload together with request, in favor of small requests. firstChunk := firstPacket.Chunk() moreChunks := firstPacket.MoreChunks() for firstChunk == nil && moreChunks { firstChunk, moreChunks = <-input } if firstChunk == nil && !moreChunks { log.Warning("VMessOut: Nothing to send. Existing...") return } if request.Option.IsChunkStream() { vmessio.Authenticate(firstChunk) } bodyWriter := session.EncodeRequestBody(writer) bodyWriter.Write(firstChunk.Value) firstChunk.Release() writer.SetCached(false) if moreChunks { var streamWriter v2io.ReleasableWriter = v2io.NewAdaptiveWriter(bodyWriter) if request.Option.IsChunkStream() { streamWriter = vmessio.NewAuthChunkWriter(streamWriter) } v2io.ChanToWriter(streamWriter, input) streamWriter.Release() } return }
func (handler *OutboundConnectionHandler) Create(point *core.Point, packet v2net.Packet) (core.OutboundConnectionHandler, error) { handler.Destination = packet.Destination() if packet.Chunk() != nil { handler.Data2Send.Write(packet.Chunk()) } return handler, nil }
func startCommunicate(request *protocol.VMessRequest, dest v2net.Destination, ray core.OutboundRay, firstPacket v2net.Packet) error { conn, err := net.DialTCP(dest.Network(), nil, &net.TCPAddr{dest.Address().IP(), int(dest.Address().Port()), ""}) if err != nil { log.Error("Failed to open tcp (%s): %v", dest.String(), err) if ray != nil { close(ray.OutboundOutput()) } return err } log.Info("VMessOut: Tunneling request for %s", request.Address.String()) defer conn.Close() if chunk := firstPacket.Chunk(); chunk != nil { conn.Write(chunk) } if !firstPacket.MoreChunks() { if ray != nil { close(ray.OutboundOutput()) } return nil } input := ray.OutboundInput() output := ray.OutboundOutput() var requestFinish, responseFinish sync.Mutex requestFinish.Lock() responseFinish.Lock() go handleRequest(conn, request, input, &requestFinish) go handleResponse(conn, request, output, &responseFinish) requestFinish.Lock() conn.CloseWrite() responseFinish.Lock() return nil }
func (this *Point) FilterPacketAndDispatch(packet v2net.Packet, link ray.OutboundRay, dispatcher proxy.OutboundConnectionHandler) { // Filter empty packets chunk := packet.Chunk() moreChunks := packet.MoreChunks() changed := false for chunk == nil && moreChunks { changed = true chunk, moreChunks = <-link.OutboundInput() } if chunk == nil && !moreChunks { close(link.OutboundOutput()) return } if changed { packet = v2net.NewPacket(packet.Destination(), chunk, moreChunks) } dispatcher.Dispatch(packet, link) }
func (this *FreedomConnection) Dispatch(firstPacket v2net.Packet, ray ray.OutboundRay) error { conn, err := net.Dial(firstPacket.Destination().Network(), firstPacket.Destination().Address().String()) log.Info("Freedom: Opening connection to %s", firstPacket.Destination().String()) if err != nil { close(ray.OutboundOutput()) log.Error("Freedom: Failed to open connection: %s : %v", firstPacket.Destination().String(), err) return err } input := ray.OutboundInput() output := ray.OutboundOutput() var readMutex, writeMutex sync.Mutex readMutex.Lock() writeMutex.Lock() if chunk := firstPacket.Chunk(); chunk != nil { conn.Write(chunk.Value) chunk.Release() } if !firstPacket.MoreChunks() { writeMutex.Unlock() } else { go func() { v2net.ChanToWriter(conn, input) writeMutex.Unlock() }() } go func() { defer readMutex.Unlock() defer close(output) response, err := v2net.ReadFrom(conn, nil) log.Info("Freedom receives %d bytes from %s", response.Len(), conn.RemoteAddr().String()) if response.Len() > 0 { output <- response } else { response.Release() } if err != nil { return } if firstPacket.Destination().IsUDP() { return } v2net.ReaderToChan(output, conn) }() writeMutex.Lock() if tcpConn, ok := conn.(*net.TCPConn); ok { tcpConn.CloseWrite() } readMutex.Lock() conn.Close() return nil }
func (this *FreedomConnection) Dispatch(firstPacket v2net.Packet, ray ray.OutboundRay) error { log.Info("Freedom: Opening connection to ", firstPacket.Destination()) var conn net.Conn err := retry.Timed(5, 100).On(func() error { rawConn, err := dialer.Dial(firstPacket.Destination()) if err != nil { return err } conn = rawConn return nil }) if err != nil { close(ray.OutboundOutput()) log.Error("Freedom: Failed to open connection to ", firstPacket.Destination(), ": ", err) return err } defer conn.Close() input := ray.OutboundInput() output := ray.OutboundOutput() var readMutex, writeMutex sync.Mutex readMutex.Lock() writeMutex.Lock() if chunk := firstPacket.Chunk(); chunk != nil { conn.Write(chunk.Value) chunk.Release() } if !firstPacket.MoreChunks() { writeMutex.Unlock() } else { go func() { v2net.ChanToWriter(conn, input) writeMutex.Unlock() }() } go func() { defer readMutex.Unlock() defer close(output) response, err := v2net.ReadFrom(conn, nil) log.Info("Freedom receives ", response.Len(), " bytes from ", conn.RemoteAddr()) if response.Len() > 0 { output <- response } else { response.Release() } if err != nil { return } if firstPacket.Destination().IsUDP() { return } v2net.ReaderToChan(output, conn) }() if this.space.HasDnsCache() { if firstPacket.Destination().Address().IsDomain() { domain := firstPacket.Destination().Address().Domain() addr := conn.RemoteAddr() switch typedAddr := addr.(type) { case *net.TCPAddr: this.space.DnsCache().Add(domain, typedAddr.IP) case *net.UDPAddr: this.space.DnsCache().Add(domain, typedAddr.IP) } } } writeMutex.Lock() if tcpConn, ok := conn.(*net.TCPConn); ok { tcpConn.CloseWrite() } readMutex.Lock() return nil }
func (handler *OutboundConnectionHandler) Create(point *core.Point, config []byte, packet v2net.Packet) (core.OutboundConnectionHandler, error) { handler.Destination = packet.Destination() return handler, nil }
func (this *FreedomConnection) Dispatch(firstPacket v2net.Packet, ray ray.OutboundRay) error { log.Info("Freedom: Opening connection to ", firstPacket.Destination()) var conn net.Conn err := retry.Timed(5, 100).On(func() error { rawConn, err := dialer.Dial(firstPacket.Destination()) if err != nil { return err } conn = rawConn return nil }) if err != nil { close(ray.OutboundOutput()) log.Error("Freedom: Failed to open connection to ", firstPacket.Destination(), ": ", err) return err } defer conn.Close() input := ray.OutboundInput() output := ray.OutboundOutput() var readMutex, writeMutex sync.Mutex readMutex.Lock() writeMutex.Lock() if chunk := firstPacket.Chunk(); chunk != nil { conn.Write(chunk.Value) chunk.Release() } if !firstPacket.MoreChunks() { writeMutex.Unlock() } else { go func() { v2io.ChanToRawWriter(conn, input) writeMutex.Unlock() }() } go func() { defer readMutex.Unlock() defer close(output) var reader io.Reader reader = conn if firstPacket.Destination().IsUDP() { reader = v2net.NewTimeOutReader(16 /* seconds */, conn) } v2io.RawReaderToChan(output, reader) }() writeMutex.Lock() if tcpConn, ok := conn.(*net.TCPConn); ok { tcpConn.CloseWrite() } readMutex.Lock() return nil }
func (vconn *FreedomConnection) Dispatch(firstPacket v2net.Packet, ray core.OutboundRay) error { conn, err := net.Dial(firstPacket.Destination().Network(), firstPacket.Destination().Address().String()) log.Info("Freedom: Opening connection to %s", firstPacket.Destination().String()) if err != nil { if ray != nil { close(ray.OutboundOutput()) } return log.Error("Freedom: Failed to open connection: %s : %v", firstPacket.Destination().String(), err) } input := ray.OutboundInput() output := ray.OutboundOutput() var readMutex, writeMutex sync.Mutex readMutex.Lock() writeMutex.Lock() if chunk := firstPacket.Chunk(); chunk != nil { conn.Write(chunk) } if !firstPacket.MoreChunks() { writeMutex.Unlock() } else { go dumpInput(conn, input, &writeMutex) } go dumpOutput(conn, output, &readMutex, firstPacket.Destination().IsUDP()) go func() { writeMutex.Lock() if tcpConn, ok := conn.(*net.TCPConn); ok { tcpConn.CloseWrite() } readMutex.Lock() conn.Close() }() return nil }