func (v *Server) transport(ctx context.Context, reader io.Reader, writer io.Writer) error { ray := v.packetDispatcher.DispatchToOutbound(ctx) input := ray.InboundInput() output := ray.InboundOutput() requestDone := signal.ExecuteAsync(func() error { defer input.Close() v2reader := buf.NewReader(reader) if err := buf.PipeUntilEOF(v2reader, input); err != nil { log.Info("Socks|Server: Failed to transport all TCP request: ", err) return err } return nil }) responseDone := signal.ExecuteAsync(func() error { v2writer := buf.NewWriter(writer) if err := buf.PipeUntilEOF(output, v2writer); err != nil { log.Info("Socks|Server: Failed to transport all TCP response: ", err) return err } return nil }) if err := signal.ErrorOrFinish2(requestDone, responseDone); err != nil { log.Info("Socks|Server: Connection ends with ", err) input.CloseError() output.CloseError() return err } return nil }
func (v *Server) transport(reader io.Reader, writer io.Writer, session *proxy.SessionInfo) { ray := v.packetDispatcher.DispatchToOutbound(session) input := ray.InboundInput() output := ray.InboundOutput() defer input.Close() defer output.Release() go func() { v2reader := buf.NewReader(reader) defer v2reader.Release() if err := buf.PipeUntilEOF(v2reader, input); err != nil { log.Info("Socks|Server: Failed to transport all TCP request: ", err) } input.Close() }() v2writer := buf.NewWriter(writer) defer v2writer.Release() if err := buf.PipeUntilEOF(output, v2writer); err != nil { log.Info("Socks|Server: Failed to transport all TCP response: ", err) } output.Release() }
func (v *DefaultDispatcher) DispatchToOutbound(session *proxy.SessionInfo) ray.InboundRay { direct := ray.NewRay() dispatcher := v.ohm.GetDefaultHandler() destination := session.Destination if v.router != nil { if tag, err := v.router.TakeDetour(session); err == nil { if handler := v.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 session.Inbound != nil && session.Inbound.AllowPassiveConnection { go dispatcher.Dispatch(destination, buf.NewLocal(32), direct) } else { go v.FilterPacketAndDispatch(destination, direct, dispatcher) } return direct }
func (this *Router) takeDetourWithoutCache(session *proxy.SessionInfo) (string, error) { for _, rule := range this.rules { if rule.Apply(session) { return rule.Tag, nil } } dest := session.Destination if this.domainStrategy == Config_IpIfNonMatch && dest.Address.Family().IsDomain() { log.Info("Router: Looking up IP for ", dest) ipDests := this.ResolveIP(dest) if ipDests != nil { for _, ipDest := range ipDests { log.Info("Router: Trying IP ", ipDest) for _, rule := range this.rules { if rule.Apply(&proxy.SessionInfo{ Source: session.Source, Destination: ipDest, User: session.User, }) { return rule.Tag, nil } } } } } return "", ErrNoRuleApplicable }
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 (v *Server) transport(input io.Reader, output io.Writer, ray ray.InboundRay) { var wg sync.WaitGroup wg.Add(2) defer wg.Wait() go func() { v2reader := buf.NewReader(input) defer v2reader.Release() if err := buf.PipeUntilEOF(v2reader, ray.InboundInput()); err != nil { log.Info("HTTP: Failed to transport all TCP request: ", err) } ray.InboundInput().Close() wg.Done() }() go func() { v2writer := buf.NewWriter(output) defer v2writer.Release() if err := buf.PipeUntilEOF(ray.InboundOutput(), v2writer); err != nil { log.Info("HTTP: Failed to transport all TCP response: ", err) } ray.InboundOutput().Release() wg.Done() }() }
func (v *DokodemoDoor) HandleTCPConnection(conn internet.Connection) { defer conn.Close() var dest v2net.Destination if v.config.FollowRedirect { originalDest := GetOriginalDestination(conn) if originalDest.Network != v2net.Network_Unknown { log.Info("Dokodemo: Following redirect to: ", originalDest) dest = originalDest } } if dest.Network == v2net.Network_Unknown && v.address != nil && v.port > v2net.Port(0) { dest = v2net.TCPDestination(v.address, v.port) } if dest.Network == v2net.Network_Unknown { log.Info("Dokodemo: Unknown destination, stop forwarding...") return } log.Info("Dokodemo: Handling request to ", dest) ray := v.packetDispatcher.DispatchToOutbound(&proxy.SessionInfo{ Source: v2net.DestinationFromAddr(conn.RemoteAddr()), Destination: dest, Inbound: v.meta, }) defer ray.InboundOutput().Release() var wg sync.WaitGroup reader := v2net.NewTimeOutReader(v.config.Timeout, conn) defer reader.Release() wg.Add(1) go func() { v2reader := buf.NewReader(reader) defer v2reader.Release() if err := buf.PipeUntilEOF(v2reader, ray.InboundInput()); err != nil { log.Info("Dokodemo: Failed to transport all TCP request: ", err) } wg.Done() ray.InboundInput().Close() }() wg.Add(1) go func() { v2writer := buf.NewWriter(conn) defer v2writer.Release() if err := buf.PipeUntilEOF(ray.InboundOutput(), v2writer); err != nil { log.Info("Dokodemo: Failed to transport all TCP response: ", err) } wg.Done() }() wg.Wait() }
func CloseAllServers() { log.Info("Closing all servers.") for _, server := range runningServers { server.Process.Signal(os.Interrupt) server.Process.Wait() } runningServers = make([]*exec.Cmd, 0, 10) log.Info("All server closed.") }
func (this *DokodemoDoor) HandleTCPConnection(conn internet.Connection) { defer conn.Close() var dest v2net.Destination if this.config.FollowRedirect { originalDest := GetOriginalDestination(conn) if originalDest.Network != v2net.Network_Unknown { log.Info("Dokodemo: Following redirect to: ", originalDest) dest = originalDest } } if dest.Network == v2net.Network_Unknown && this.address != nil && this.port > v2net.Port(0) { dest = v2net.TCPDestination(this.address, this.port) } if dest.Network == v2net.Network_Unknown { log.Info("Dokodemo: Unknown destination, stop forwarding...") return } log.Info("Dokodemo: Handling request to ", dest) ray := this.packetDispatcher.DispatchToOutbound(&proxy.SessionInfo{ Source: v2net.DestinationFromAddr(conn.RemoteAddr()), Destination: dest, Inbound: this.meta, }) defer ray.InboundOutput().Release() var wg sync.WaitGroup reader := v2net.NewTimeOutReader(this.config.Timeout, conn) defer reader.Release() wg.Add(1) go func() { v2reader := v2io.NewAdaptiveReader(reader) defer v2reader.Release() v2io.Pipe(v2reader, ray.InboundInput()) wg.Done() ray.InboundInput().Close() }() wg.Add(1) go func() { v2writer := v2io.NewAdaptiveWriter(conn) defer v2writer.Release() v2io.Pipe(ray.InboundOutput(), v2writer) wg.Done() }() wg.Wait() }
func (v *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection) error { source := proxy.SourceFromContext(ctx) reader := buf.NewReader(conn) for { payload, err := reader.Read() if err != nil { break } request, data, err := DecodeUDPPacket(v.user, payload) if err != nil { log.Info("Shadowsocks|Server: Skipping invalid UDP packet from: ", source, ": ", err) log.Access(source, "", log.AccessRejected, err) payload.Release() continue } if request.Option.Has(RequestOptionOneTimeAuth) && v.account.OneTimeAuth == Account_Disabled { log.Info("Shadowsocks|Server: Client payload enables OTA but server doesn't allow it.") payload.Release() continue } if !request.Option.Has(RequestOptionOneTimeAuth) && v.account.OneTimeAuth == Account_Enabled { log.Info("Shadowsocks|Server: Client payload disables OTA but server forces it.") payload.Release() continue } dest := request.Destination() log.Access(source, dest, log.AccessAccepted, "") log.Info("Shadowsocks|Server: Tunnelling request to ", dest) ctx = protocol.ContextWithUser(ctx, request.User) v.udpServer.Dispatch(ctx, dest, data, func(payload *buf.Buffer) { defer payload.Release() data, err := EncodeUDPPacket(request, payload) if err != nil { log.Warning("Shadowsocks|Server: Failed to encode UDP packet: ", err) return } defer data.Release() conn.Write(data.Bytes()) }) } return nil }
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 *UDPHub) start() { this.cancel.WaitThread() defer this.cancel.FinishThread() oobBytes := make([]byte, 256) for this.Running() { buffer := this.pool.Allocate() nBytes, noob, _, addr, err := ReadUDPMsg(this.conn, buffer.Value, oobBytes) if err != nil { log.Info("UDP|Hub: Failed to read UDP msg: ", err) buffer.Release() continue } buffer.Slice(0, nBytes) session := new(proxy.SessionInfo) session.Source = v2net.UDPDestination(v2net.IPAddress(addr.IP), v2net.Port(addr.Port)) if this.option.ReceiveOriginalDest && noob > 0 { session.Destination = RetrieveOriginalDest(oobBytes[:noob]) } this.queue.Enqueue(UDPPayload{ payload: buffer, session: session, }) } }
func (v *VMessInboundHandler) generateCommand(ctx context.Context, request *protocol.RequestHeader) protocol.ResponseCommand { if v.detours != nil { tag := v.detours.To if v.inboundHandlerManager != nil { handler, err := v.inboundHandlerManager.GetHandler(ctx, tag) if err != nil { log.Warning("VMess|Inbound: Failed to get detour handler: ", tag, err) return nil } proxyHandler, port, availableMin := handler.GetRandomInboundProxy() inboundHandler, ok := proxyHandler.(*VMessInboundHandler) if ok { if availableMin > 255 { availableMin = 255 } log.Info("VMessIn: Pick detour handler for port ", port, " for ", availableMin, " minutes.") user := inboundHandler.GetUser(request.User.Email) if user == nil { return nil } account, _ := user.GetTypedAccount() return &protocol.CommandSwitchAccount{ Port: port, ID: account.(*vmess.InternalAccount).ID.UUID(), AlterIds: uint16(len(account.(*vmess.InternalAccount).AlterIDs)), Level: user.Level, ValidMin: byte(availableMin), } } } } return nil }
func (h *Handler) Dial(ctx context.Context, dest v2net.Destination) (internet.Connection, error) { if h.senderSettings != nil { if h.senderSettings.ProxySettings.HasTag() { tag := h.senderSettings.ProxySettings.Tag handler := h.outboundManager.GetHandler(tag) if handler != nil { log.Info("Proxyman|OutboundHandler: Proxying to ", tag) ctx = proxy.ContextWithDestination(ctx, dest) stream := ray.NewRay(ctx) go handler.Dispatch(ctx, stream) return NewConnection(stream), nil } log.Warning("Proxyman|OutboundHandler: Failed to get outbound handler with tag: ", tag) } if h.senderSettings.Via != nil { ctx = internet.ContextWithDialerSource(ctx, h.senderSettings.Via.AsAddress()) } if h.senderSettings != nil { ctx = internet.ContextWithStreamSettings(ctx, h.senderSettings.StreamSettings) } } return internet.Dial(ctx, dest) }
// NewConnection create a new KCP connection between local and remote. func NewConnection(conv uint16, writerCloser io.WriteCloser, local *net.UDPAddr, remote *net.UDPAddr, block internet.Authenticator) *Connection { log.Info("KCP|Connection: creating connection ", conv) conn := new(Connection) conn.local = local conn.remote = remote conn.block = block conn.writer = writerCloser conn.since = nowMillisec() conn.dataInputCond = sync.NewCond(new(sync.Mutex)) conn.dataOutputCond = sync.NewCond(new(sync.Mutex)) authWriter := &AuthenticationWriter{ Authenticator: block, Writer: writerCloser, } conn.conv = conv conn.output = NewSegmentWriter(authWriter) conn.mss = authWriter.Mtu() - DataSegmentOverhead conn.roundTrip = &RoundTripInfo{ rto: 100, minRtt: effectiveConfig.Tti, } conn.interval = effectiveConfig.Tti conn.receivingWorker = NewReceivingWorker(conn) conn.fastresend = 2 conn.congestionControl = effectiveConfig.Congestion conn.sendingWorker = NewSendingWorker(conn) go conn.updateTask() return conn }
func (v *VMessOutboundHandler) handleRequest(session *encoding.ClientSession, conn internet.Connection, request *protocol.RequestHeader, payload *buf.Buffer, input buf.Reader, finish *sync.Mutex) { defer finish.Unlock() writer := bufio.NewWriter(conn) defer writer.Release() session.EncodeRequestHeader(request, writer) bodyWriter := session.EncodeRequestBody(request, writer) defer bodyWriter.Release() if !payload.IsEmpty() { if err := bodyWriter.Write(payload); err != nil { log.Info("VMess|Outbound: Failed to write payload. Disabling connection reuse.", err) conn.SetReusable(false) } payload.Release() } writer.SetCached(false) if err := buf.PipeUntilEOF(input, bodyWriter); err != nil { conn.SetReusable(false) } if request.Option.Has(protocol.RequestOptionChunkStream) { err := bodyWriter.Write(buf.NewLocal(8)) if err != nil { conn.SetReusable(false) } } return }
func wsDial(src v2net.Address, dest v2net.Destination) (*wsconn, error) { commonDial := func(network, addr string) (net.Conn, error) { return internet.DialToDest(src, dest) } tlsconf := &tls.Config{ServerName: dest.Address().Domain(), InsecureSkipVerify: effectiveConfig.DeveloperInsecureSkipVerify} dialer := websocket.Dialer{NetDial: commonDial, ReadBufferSize: 65536, WriteBufferSize: 65536, TLSClientConfig: tlsconf} effpto := calcPto(dest) uri := func(dst v2net.Destination, pto string, path string) string { return fmt.Sprintf("%v://%v/%v", pto, dst.NetAddr(), path) }(dest, effpto, effectiveConfig.Path) conn, resp, err := dialer.Dial(uri, nil) if err != nil { if resp != nil { reason, reasonerr := ioutil.ReadAll(resp.Body) log.Info(string(reason), reasonerr) } return nil, err } return func() internet.Connection { connv2ray := &wsconn{wsc: conn, connClosing: false} connv2ray.setup() return connv2ray }().(*wsconn), nil }
func Dial(src v2net.Address, dest v2net.Destination, options internet.DialerOptions) (internet.Connection, error) { log.Info("WebSocket|Dailer: Creating connection to ", dest) if src == nil { src = v2net.AnyIP } networkSettings, err := options.Stream.GetEffectiveNetworkSettings() if err != nil { return nil, err } wsSettings := networkSettings.(*Config) id := src.String() + "-" + dest.NetAddr() var conn *wsconn if dest.Network == v2net.Network_TCP && wsSettings.ConnectionReuse.IsEnabled() { connt := globalCache.Get(id) if connt != nil { conn = connt.(*wsconn) } } if conn == nil { var err error conn, err = wsDial(src, dest, options) if err != nil { log.Warning("WebSocket|Dialer: Dial failed: ", err) return nil, err } } return NewConnection(id, conn, globalCache, wsSettings), nil }
func (v *VMessInboundHandler) generateCommand(request *protocol.RequestHeader) protocol.ResponseCommand { if v.detours != nil { tag := v.detours.To if v.inboundHandlerManager != nil { handler, availableMin := v.inboundHandlerManager.GetHandler(tag) inboundHandler, ok := handler.(*VMessInboundHandler) if ok { if availableMin > 255 { availableMin = 255 } log.Info("VMessIn: Pick detour handler for port ", inboundHandler.Port(), " for ", availableMin, " minutes.") user := inboundHandler.GetUser(request.User.Email) if user == nil { return nil } account, _ := user.GetTypedAccount() return &protocol.CommandSwitchAccount{ Port: inboundHandler.Port(), ID: account.(*vmess.InternalAccount).ID.UUID(), AlterIds: uint16(len(account.(*vmess.InternalAccount).AlterIDs)), Level: user.Level, ValidMin: byte(availableMin), } } } } return nil }
func ListenUDP(address v2net.Address, port v2net.Port, option ListenOption) (*Hub, error) { if option.Concurrency < 1 { option.Concurrency = 1 } udpConn, err := net.ListenUDP("udp", &net.UDPAddr{ IP: address.IP(), Port: int(port), }) if err != nil { return nil, err } log.Info("UDP|Hub: Listening on ", address, ":", port) if option.ReceiveOriginalDest { fd, err := internal.GetSysFd(udpConn) if err != nil { log.Warning("UDP|Listener: Failed to get fd: ", err) return nil, err } err = SetOriginalDestOptions(fd) if err != nil { log.Warning("UDP|Listener: Failed to set socket options: ", err) return nil, err } } hub := &Hub{ conn: udpConn, queue: NewPayloadQueue(option), option: option, cancel: signal.NewCloseSignal(), } go hub.start() return hub, nil }
func Dial(src v2net.Address, dest v2net.Destination, options DialerOptions) (Connection, error) { if options.Proxy.HasTag() && ProxyDialer != nil { log.Info("Internet: Proxying outbound connection through: ", options.Proxy.Tag) return ProxyDialer(src, dest, options) } var connection Connection var err error if dest.Network == v2net.Network_TCP { switch options.Stream.Network { case v2net.Network_TCP: connection, err = TCPDialer(src, dest, options) case v2net.Network_KCP: connection, err = KCPDialer(src, dest, options) case v2net.Network_WebSocket: connection, err = WSDialer(src, dest, options) // This check has to be the last one. case v2net.Network_RawTCP: connection, err = RawTCPDialer(src, dest, options) default: return nil, ErrUnsupportedStreamType } if err != nil { return nil, err } return connection, nil } return UDPDialer(src, dest, options) }
func (v *UDPHub) start() { v.cancel.WaitThread() defer v.cancel.FinishThread() oobBytes := make([]byte, 256) for v.Running() { buffer := buf.NewSmall() var noob int var addr *net.UDPAddr err := buffer.AppendSupplier(func(b []byte) (int, error) { n, nb, _, a, e := ReadUDPMsg(v.conn, b, oobBytes) noob = nb addr = a return n, e }) if err != nil { log.Info("UDP|Hub: Failed to read UDP msg: ", err) buffer.Release() continue } session := new(proxy.SessionInfo) session.Source = v2net.UDPDestination(v2net.IPAddress(addr.IP), v2net.Port(addr.Port)) if v.option.ReceiveOriginalDest && noob > 0 { session.Destination = RetrieveOriginalDest(oobBytes[:noob]) } v.queue.Enqueue(UDPPayload{ payload: buffer, session: session, }) } }
// Close closes the connection. func (v *Connection) Close() error { if v == nil { return ErrClosedConnection } v.OnDataInput() v.OnDataOutput() state := v.State() if state.Is(StateReadyToClose, StateTerminating, StateTerminated) { return ErrClosedConnection } log.Info("KCP|Connection: Closing connection to ", v.conn.RemoteAddr()) if state == StateActive { v.SetState(StateReadyToClose) } if state == StatePeerClosed { v.SetState(StateTerminating) } if state == StatePeerTerminating { v.SetState(StateTerminated) } return nil }
func (s *Server) Process(ctx context.Context, network v2net.Network, conn internet.Connection) error { conn.SetReusable(false) timedReader := v2net.NewTimeOutReader(s.config.Timeout, conn) reader := bufio.OriginalReaderSize(timedReader, 2048) request, err := http.ReadRequest(reader) if err != nil { if errors.Cause(err) != io.EOF { log.Warning("HTTP: Failed to read http request: ", err) } return err } log.Info("HTTP: Request to Method [", request.Method, "] Host [", request.Host, "] with URL [", request.URL, "]") defaultPort := v2net.Port(80) if strings.ToLower(request.URL.Scheme) == "https" { defaultPort = v2net.Port(443) } host := request.Host if len(host) == 0 { host = request.URL.Host } dest, err := parseHost(host, defaultPort) if err != nil { log.Warning("HTTP: Malformed proxy host (", host, "): ", err) return err } log.Access(conn.RemoteAddr(), request.URL, log.AccessAccepted, "") ctx = proxy.ContextWithDestination(ctx, dest) if strings.ToUpper(request.Method) == "CONNECT" { return s.handleConnect(ctx, request, reader, conn) } else { return s.handlePlainHTTP(ctx, request, reader, conn) } }
// Close closes the connection. func (this *Connection) Close() error { if this == nil { return ErrClosedConnection } this.dataInputCond.Broadcast() this.dataOutputCond.Broadcast() state := this.State() if state.Is(StateReadyToClose, StateTerminating, StateTerminated) { return ErrClosedConnection } log.Info("KCP|Connection: Closing connection to ", this.remote) if state == StateActive { this.SetState(StateReadyToClose) } if state == StatePeerClosed { this.SetState(StateTerminating) } if state == StatePeerTerminating { this.SetState(StateTerminated) } 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(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 == Config_USE_IP && destination.Address.Family().IsDomain() { destination = this.ResolveIP(destination) } err := retry.ExponentialBackoff(5, 100).On(func() error { rawConn, err := internet.Dial(this.meta.Address, destination, this.meta.GetDialerOptions()) 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() if !payload.IsEmpty() { conn.Write(payload.Value) } go func() { v2writer := v2io.NewAdaptiveWriter(conn) defer v2writer.Release() v2io.Pipe(input, v2writer) if tcpConn, ok := conn.(*tcp.RawConnection); ok { tcpConn.CloseWrite() } }() var reader io.Reader = conn timeout := this.timeout if destination.Network == v2net.Network_UDP { timeout = 16 } if timeout > 0 { reader = v2net.NewTimeOutReader(timeout /* seconds */, conn) } v2reader := v2io.NewAdaptiveReader(reader) v2io.Pipe(v2reader, output) v2reader.Release() ray.OutboundOutput().Close() return nil }
func wsDial(src v2net.Address, dest v2net.Destination, options internet.DialerOptions) (*wsconn, error) { networkSettings, err := options.Stream.GetEffectiveNetworkSettings() if err != nil { return nil, err } wsSettings := networkSettings.(*Config) commonDial := func(network, addr string) (net.Conn, error) { return internet.DialToDest(src, dest) } dialer := websocket.Dialer{ NetDial: commonDial, ReadBufferSize: 65536, WriteBufferSize: 65536, } protocol := "ws" if options.Stream != nil && options.Stream.HasSecuritySettings() { protocol = "wss" securitySettings, err := options.Stream.GetEffectiveSecuritySettings() if err != nil { log.Error("WebSocket: Failed to create security settings: ", err) return nil, err } tlsConfig, ok := securitySettings.(*v2tls.Config) if ok { dialer.TLSClientConfig = tlsConfig.GetTLSConfig() if dest.Address.Family().IsDomain() { dialer.TLSClientConfig.ServerName = dest.Address.Domain() } } } uri := func(dst v2net.Destination, pto string, path string) string { return fmt.Sprintf("%v://%v/%v", pto, dst.NetAddr(), path) }(dest, protocol, wsSettings.Path) conn, resp, err := dialer.Dial(uri, nil) if err != nil { if resp != nil { reason, reasonerr := ioutil.ReadAll(resp.Body) log.Info(string(reason), reasonerr) } return nil, err } return func() internet.Connection { connv2ray := &wsconn{ wsc: conn, connClosing: false, config: wsSettings, } connv2ray.setup() return connv2ray }().(*wsconn), nil }
func (v *DefaultDispatcher) waitAndDispatch(ctx context.Context, wait func() error, link ray.OutboundRay, dispatcher proxyman.OutboundHandler) { if err := wait(); err != nil { log.Info("DefaultDispatcher: Failed precondition: ", err) link.OutboundInput().CloseError() link.OutboundOutput().CloseError() return } dispatcher.Dispatch(ctx, link) }
func (this *DokodemoDoor) handleUDPPackets(payload *alloc.Buffer, session *proxy.SessionInfo) { if session.Destination == nil && this.address != nil && this.port > 0 { session.Destination = v2net.UDPDestination(this.address, this.port) } if session.Destination == nil { log.Info("Dokodemo: Unknown destination, stop forwarding...") return } this.udpServer.Dispatch(session, payload, this.handleUDPResponse) }