func startCommunicate(request *protocol.VMessRequest, dest v2net.Destination, ray ray.OutboundRay, firstPacket v2net.Packet) error { conn, err := net.Dial(dest.Network(), dest.Address().String()) if err != nil { log.Error("Failed to open %s: %v", dest.String(), err) if ray != nil { close(ray.OutboundOutput()) } return err } log.Info("VMessOut: Tunneling request to %s via %s", request.Address.String(), dest.String()) defer conn.Close() input := ray.OutboundInput() output := ray.OutboundOutput() var requestFinish, responseFinish sync.Mutex requestFinish.Lock() responseFinish.Lock() go handleRequest(conn, request, firstPacket, input, &requestFinish) go handleResponse(conn, request, output, &responseFinish, dest.IsUDP()) requestFinish.Lock() if tcpConn, ok := conn.(*net.TCPConn); ok { tcpConn.CloseWrite() } responseFinish.Lock() 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() { v2io.ChanToRawWriter(conn, input) writeMutex.Unlock() }() } go func() { defer readMutex.Unlock() defer close(output) var reader io.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 (this *VMessOutboundHandler) Dispatch(target v2net.Destination, payload *alloc.Buffer, ray ray.OutboundRay) error { defer ray.OutboundInput().Release() defer ray.OutboundOutput().Close() var rec *protocol.ServerSpec var conn internet.Connection err := retry.Timed(5, 100).On(func() error { rec = this.serverPicker.PickServer() rawConn, err := internet.Dial(this.meta.Address, rec.Destination(), this.meta.StreamSettings) if err != nil { return err } conn = rawConn return nil }) if err != nil { log.Error("VMess|Outbound: Failed to find an available destination:", err) return err } log.Info("VMess|Outbound: Tunneling request to ", target, " via ", rec.Destination) command := protocol.RequestCommandTCP if target.IsUDP() { command = protocol.RequestCommandUDP } request := &protocol.RequestHeader{ Version: encoding.Version, User: rec.PickUser(), Command: command, Address: target.Address(), Port: target.Port(), Option: protocol.RequestOptionChunkStream, } defer conn.Close() conn.SetReusable(true) if conn.Reusable() { // Conn reuse may be disabled on transportation layer request.Option.Set(protocol.RequestOptionConnectionReuse) } input := ray.OutboundInput() output := ray.OutboundOutput() var requestFinish, responseFinish sync.Mutex requestFinish.Lock() responseFinish.Lock() session := encoding.NewClientSession(protocol.DefaultIDHash) go this.handleRequest(session, conn, request, payload, input, &requestFinish) go this.handleResponse(session, conn, request, rec.Destination(), output, &responseFinish) requestFinish.Lock() responseFinish.Lock() return nil }
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 }
// @Private func (this *DefaultDispatcher) FilterPacketAndDispatch(destination v2net.Destination, link ray.OutboundRay, dispatcher proxy.OutboundHandler) { payload, err := link.OutboundInput().Read() if err != nil { log.Info("DefaultDispatcher: No payload towards ", destination, ", stopping now.") link.OutboundInput().Release() link.OutboundOutput().Release() return } dispatcher.Dispatch(destination, payload, link) }
func (this *BlackHole) Dispatch(destination v2net.Destination, payload *alloc.Buffer, ray ray.OutboundRay) error { payload.Release() this.response.WriteTo(ray.OutboundOutput()) ray.OutboundOutput().Close() ray.OutboundInput().Release() return nil }
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 *OutboundConnectionHandler) Dispatch(destination v2net.Destination, payload *alloc.Buffer, ray ray.OutboundRay) error { input := ray.OutboundInput() output := ray.OutboundOutput() this.Destination = destination this.ConnOutput.Write(payload.Value) payload.Release() writeFinish := &sync.Mutex{} writeFinish.Lock() go func() { v2writer := v2io.NewAdaptiveWriter(this.ConnOutput) defer v2writer.Release() v2io.Pipe(input, v2writer) writeFinish.Unlock() input.Release() }() writeFinish.Lock() v2reader := v2io.NewAdaptiveReader(this.ConnInput) defer v2reader.Release() v2io.Pipe(v2reader, output) output.Close() return nil }
func (this *VMessOutboundHandler) startCommunicate(request *proto.RequestHeader, dest v2net.Destination, ray ray.OutboundRay, firstPacket v2net.Packet) error { var destIP net.IP if dest.Address().IsIPv4() || dest.Address().IsIPv6() { destIP = dest.Address().IP() } else { ips, err := net.LookupIP(dest.Address().Domain()) if err != nil { return err } destIP = ips[0] } conn, err := net.DialTCP("tcp", nil, &net.TCPAddr{ IP: destIP, Port: int(dest.Port()), }) if err != nil { log.Error("Failed to open ", dest, ": ", err) if ray != nil { close(ray.OutboundOutput()) } return err } log.Info("VMessOut: Tunneling request to ", request.Address, " via ", dest) defer conn.Close() input := ray.OutboundInput() output := ray.OutboundOutput() var requestFinish, responseFinish sync.Mutex requestFinish.Lock() responseFinish.Lock() session := raw.NewClientSession(proto.DefaultIDHash) go this.handleRequest(session, conn, request, firstPacket, input, &requestFinish) go this.handleResponse(session, conn, request, dest, output, &responseFinish) requestFinish.Lock() conn.CloseWrite() responseFinish.Lock() return nil }
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 *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 startCommunicate(request *protocol.VMessRequest, dest v2net.Destination, ray ray.OutboundRay, firstPacket v2net.Packet) error { var destIp net.IP if dest.Address().IsIPv4() || dest.Address().IsIPv6() { destIp = dest.Address().IP() } else { ips, err := net.LookupIP(dest.Address().Domain()) if err != nil { return err } destIp = ips[0] } conn, err := net.DialTCP("tcp", nil, &net.TCPAddr{ IP: destIp, Port: int(dest.Port()), }) if err != nil { log.Error("Failed to open ", dest, ": ", err) if ray != nil { close(ray.OutboundOutput()) } return err } log.Info("VMessOut: Tunneling request to ", request.Address, " via ", dest) defer conn.Close() input := ray.OutboundInput() output := ray.OutboundOutput() var requestFinish, responseFinish sync.Mutex requestFinish.Lock() responseFinish.Lock() go handleRequest(conn, request, firstPacket, input, &requestFinish) go handleResponse(conn, request, output, &responseFinish, (request.Command == protocol.CmdUDP)) requestFinish.Lock() conn.CloseWrite() responseFinish.Lock() return nil }
func (vconn *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 dumpInput(conn, input, &writeMutex) } go dumpOutput(conn, output, &readMutex, firstPacket.Destination().IsUDP()) 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 (this *FreedomConnection) Dispatch(destination v2net.Destination, payload *alloc.Buffer, ray ray.OutboundRay) error { log.Info("Freedom: Opening connection to ", destination) defer payload.Release() defer ray.OutboundInput().Release() defer ray.OutboundOutput().Close() var conn internet.Connection if this.domainStrategy == DomainStrategyUseIP && destination.Address().IsDomain() { destination = this.ResolveIP(destination) } err := retry.Timed(5, 100).On(func() error { rawConn, err := internet.Dial(this.meta.Address, destination, this.meta.StreamSettings) if err != nil { return err } conn = rawConn return nil }) if err != nil { log.Warning("Freedom: Failed to open connection to ", destination, ": ", err) return err } defer conn.Close() input := ray.OutboundInput() output := ray.OutboundOutput() var readMutex, writeMutex sync.Mutex readMutex.Lock() writeMutex.Lock() conn.Write(payload.Value) go func() { v2writer := v2io.NewAdaptiveWriter(conn) defer v2writer.Release() v2io.Pipe(input, v2writer) writeMutex.Unlock() }() go func() { defer readMutex.Unlock() var reader io.Reader = conn timeout := this.timeout if destination.IsUDP() { timeout = 16 } if timeout > 0 { reader = v2net.NewTimeOutReader(int(timeout) /* seconds */, conn) } v2reader := v2io.NewAdaptiveReader(reader) defer v2reader.Release() v2io.Pipe(v2reader, output) ray.OutboundOutput().Close() }() writeMutex.Lock() if tcpConn, ok := conn.(*tcp.RawConnection); ok { tcpConn.CloseWrite() } readMutex.Lock() return nil }