diff --git a/intra/ipn/socks5.go b/intra/ipn/socks5.go index d5b8a281..f3608a7e 100644 --- a/intra/ipn/socks5.go +++ b/intra/ipn/socks5.go @@ -7,8 +7,10 @@ package ipn import ( + "net" "net/http" + "github.com/celzero/firestack/intra/core" "github.com/celzero/firestack/intra/dialers" "github.com/celzero/firestack/intra/log" "github.com/celzero/firestack/intra/protect" @@ -25,6 +27,41 @@ type socks5 struct { status int } +type socks5tcpconn struct { + *tx.Client +} + +type socks5udpconn struct { + *tx.Client +} + +var _ core.TCPConn = (*socks5tcpconn)(nil) +var _ core.UDPConn = (*socks5udpconn)(nil) + +func (c *socks5tcpconn) CloseRead() error { + return c.Close() +} + +func (c *socks5tcpconn) CloseWrite() error { + return c.Close() +} + +func (c *socks5udpconn) Ready() bool { + return c.Client != nil && c.Client.UDPConn != nil +} + +// WriteFrom writes b to TUN using addr as the source. +func (c *socks5udpconn) WriteFrom(b []byte, addr *net.UDPAddr) (int, error) { + // no-op; intra/udp.go does not require outbound udp to implement TUN specific methods + return 0, nil +} + +// ReceiveTo is incoming TUN packet b to be sent to addr. +func (c *socks5udpconn) ReceiveTo(b []byte, addr *net.UDPAddr) error { + // no-op; intra/udp.go does not require outbound udp to implement TUN specific methods + return nil +} + func NewSocks5Proxy(id string, ctl protect.Controller, po *settings.ProxyOptions) (Proxy, error) { var err error if po == nil { @@ -65,30 +102,31 @@ func (h *socks5) Dial(network, addr string) (c protect.Conn, err error) { return nil, errProxyStopped } + log.D("proxy: socks5: %d dial(%s) from %s -> %s", h.ID(), network, h.GetAddr(), addr) // tx.Client.Dial does not support dialing hostnames if c, err = dialers.ProxyDial(h.proxydialer, network, addr); err == nil { // in txthinking/socks5, an underlying-conn is actually a net.TCPConn // github.com/txthinking/socks5/blob/39268fae/client.go#L15 if uc, ok := c.(*tx.Client); ok { if uc.TCPConn != nil { - c = uc.TCPConn + c = &socks5tcpconn{uc} } else if uc.UDPConn != nil { - c = uc.UDPConn + c = &socks5udpconn{uc} } else { - log.W("proxy: socks5 conn not tcp nor udp %s -> %s", h.GetAddr(), addr) + log.W("proxy: socks5: %s conn not tcp nor udp %s -> %s", h.ID(), h.GetAddr(), addr) c = nil err = errNoProxyConn } } else { - log.W("proxy: socks5 conn not a tx.Client(%s) %s -> %s", network, h.GetAddr(), addr) + log.W("proxy: socks5: %s conn not a tx.Client(%s) %s -> %s", h.ID(), network, h.GetAddr(), addr) c = nil err = errNoProxyConn } } else { - log.W("proxy: socks5 dial(%s) failed %s -> %s: %v", network, h.GetAddr(), addr, err) + log.W("proxy: socks5: %s dial(%s) failed %s -> %s: %v", h.ID(), network, h.GetAddr(), addr, err) } if err == nil { - log.I("proxy: socks5: dial(%s) from %s -> %s", network, h.GetAddr(), addr) + log.I("proxy: socks5: %s dial(%s) from %s -> %s", h.ID(), network, h.GetAddr(), addr) h.status = TOK } else { h.status = TKO @@ -106,7 +144,7 @@ func (h *socks5) DNS() string { func (h *socks5) fetch(req *http.Request) (*http.Response, error) { stopped := h.status == END - log.V("proxy: socks5: %s; fetch(%s); ok? %t", h.id, req.URL, !stopped) + log.V("proxy: socks5: %s; fetch(%s); ended? %t", h.id, req.URL, stopped) if stopped { return nil, errProxyStopped }