diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 5d803106..81920221 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -18,9 +18,9 @@ import ( "github.com/Dreamacro/clash/config" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/dns" + P "github.com/Dreamacro/clash/listener" + authStore "github.com/Dreamacro/clash/listener/auth" "github.com/Dreamacro/clash/log" - P "github.com/Dreamacro/clash/proxy" - authStore "github.com/Dreamacro/clash/proxy/auth" "github.com/Dreamacro/clash/tunnel" ) @@ -187,23 +187,26 @@ func updateGeneral(general *config.General, force bool) { bindAddress := general.BindAddress P.SetBindAddress(bindAddress) - if err := P.ReCreateHTTP(general.Port); err != nil { + tcpIn := tunnel.TCPIn() + udpIn := tunnel.UDPIn() + + if err := P.ReCreateHTTP(general.Port, tcpIn); err != nil { log.Errorln("Start HTTP server error: %s", err.Error()) } - if err := P.ReCreateSocks(general.SocksPort); err != nil { + if err := P.ReCreateSocks(general.SocksPort, tcpIn, udpIn); err != nil { log.Errorln("Start SOCKS5 server error: %s", err.Error()) } - if err := P.ReCreateRedir(general.RedirPort); err != nil { + if err := P.ReCreateRedir(general.RedirPort, tcpIn, udpIn); err != nil { log.Errorln("Start Redir server error: %s", err.Error()) } - if err := P.ReCreateTProxy(general.TProxyPort); err != nil { + if err := P.ReCreateTProxy(general.TProxyPort, tcpIn, udpIn); err != nil { log.Errorln("Start TProxy server error: %s", err.Error()) } - if err := P.ReCreateMixed(general.MixedPort); err != nil { + if err := P.ReCreateMixed(general.MixedPort, tcpIn, udpIn); err != nil { log.Errorln("Start Mixed(http and socks5) server error: %s", err.Error()) } } diff --git a/hub/route/configs.go b/hub/route/configs.go index 84dd10a6..315180f7 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -7,8 +7,8 @@ import ( "github.com/Dreamacro/clash/component/resolver" "github.com/Dreamacro/clash/config" "github.com/Dreamacro/clash/hub/executor" + P "github.com/Dreamacro/clash/listener" "github.com/Dreamacro/clash/log" - P "github.com/Dreamacro/clash/proxy" "github.com/Dreamacro/clash/tunnel" "github.com/go-chi/chi/v5" @@ -66,11 +66,15 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) { } ports := P.GetPorts() - P.ReCreateHTTP(pointerOrDefault(general.Port, ports.Port)) - P.ReCreateSocks(pointerOrDefault(general.SocksPort, ports.SocksPort)) - P.ReCreateRedir(pointerOrDefault(general.RedirPort, ports.RedirPort)) - P.ReCreateTProxy(pointerOrDefault(general.TProxyPort, ports.TProxyPort)) - P.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort)) + + tcpIn := tunnel.TCPIn() + udpIn := tunnel.UDPIn() + + P.ReCreateHTTP(pointerOrDefault(general.Port, ports.Port), tcpIn) + P.ReCreateSocks(pointerOrDefault(general.SocksPort, ports.SocksPort), tcpIn, udpIn) + P.ReCreateRedir(pointerOrDefault(general.RedirPort, ports.RedirPort), tcpIn, udpIn) + P.ReCreateTProxy(pointerOrDefault(general.TProxyPort, ports.TProxyPort), tcpIn, udpIn) + P.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort), tcpIn, udpIn) if general.Mode != nil { tunnel.SetMode(*general.Mode) diff --git a/proxy/auth/auth.go b/listener/auth/auth.go similarity index 100% rename from proxy/auth/auth.go rename to listener/auth/auth.go diff --git a/proxy/http/server.go b/listener/http/server.go similarity index 79% rename from proxy/http/server.go rename to listener/http/server.go index 69117dbb..e52b84a9 100644 --- a/proxy/http/server.go +++ b/listener/http/server.go @@ -11,28 +11,25 @@ import ( "github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/common/cache" "github.com/Dreamacro/clash/component/auth" + C "github.com/Dreamacro/clash/constant" + authStore "github.com/Dreamacro/clash/listener/auth" "github.com/Dreamacro/clash/log" - authStore "github.com/Dreamacro/clash/proxy/auth" - "github.com/Dreamacro/clash/tunnel" ) -type HTTPListener struct { +type Listener struct { net.Listener address string closed bool cache *cache.Cache } -func NewHTTPProxy(addr string) (*HTTPListener, error) { +func New(addr string, in chan<- C.ConnContext) (*Listener, error) { l, err := net.Listen("tcp", addr) if err != nil { return nil, err } - hl := &HTTPListener{l, addr, false, cache.New(30 * time.Second)} - + hl := &Listener{l, addr, false, cache.New(30 * time.Second)} go func() { - log.Infoln("HTTP proxy listening at: %s", addr) - for { c, err := hl.Accept() if err != nil { @@ -41,19 +38,19 @@ func NewHTTPProxy(addr string) (*HTTPListener, error) { } continue } - go HandleConn(c, hl.cache) + go HandleConn(c, in, hl.cache) } }() return hl, nil } -func (l *HTTPListener) Close() { +func (l *Listener) Close() { l.closed = true l.Listener.Close() } -func (l *HTTPListener) Address() string { +func (l *Listener) Address() string { return l.address } @@ -70,7 +67,7 @@ func canActivate(loginStr string, authenticator auth.Authenticator, cache *cache return } -func HandleConn(conn net.Conn, cache *cache.Cache) { +func HandleConn(conn net.Conn, in chan<- C.ConnContext, cache *cache.Cache) { br := bufio.NewReader(conn) keepAlive: @@ -106,9 +103,9 @@ keepAlive: conn.Close() return } - tunnel.Add(inbound.NewHTTPS(request, conn)) + in <- inbound.NewHTTPS(request, conn) return } - tunnel.Add(inbound.NewHTTP(request, conn)) + in <- inbound.NewHTTP(request, conn) } diff --git a/proxy/listener.go b/listener/listener.go similarity index 71% rename from proxy/listener.go rename to listener/listener.go index ec9b69f9..cf0390e7 100644 --- a/proxy/listener.go +++ b/listener/listener.go @@ -6,26 +6,29 @@ import ( "strconv" "sync" + "github.com/Dreamacro/clash/adapter/inbound" + C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/listener/http" + "github.com/Dreamacro/clash/listener/mixed" + "github.com/Dreamacro/clash/listener/redir" + "github.com/Dreamacro/clash/listener/socks" + "github.com/Dreamacro/clash/listener/tproxy" "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/proxy/http" - "github.com/Dreamacro/clash/proxy/mixed" - "github.com/Dreamacro/clash/proxy/redir" - "github.com/Dreamacro/clash/proxy/socks" ) var ( allowLan = false bindAddress = "*" - socksListener *socks.SockListener - socksUDPListener *socks.SockUDPListener - httpListener *http.HTTPListener - redirListener *redir.RedirListener - redirUDPListener *redir.RedirUDPListener - tproxyListener *redir.TProxyListener - tproxyUDPListener *redir.RedirUDPListener - mixedListener *mixed.MixedListener - mixedUDPLister *socks.SockUDPListener + socksListener *socks.Listener + socksUDPListener *socks.UDPListener + httpListener *http.Listener + redirListener *redir.Listener + redirUDPListener *tproxy.UDPListener + tproxyListener *tproxy.Listener + tproxyUDPListener *tproxy.UDPListener + mixedListener *mixed.Listener + mixedUDPLister *socks.UDPListener // lock for recreate function socksMux sync.Mutex @@ -59,7 +62,7 @@ func SetBindAddress(host string) { bindAddress = host } -func ReCreateHTTP(port int) error { +func ReCreateHTTP(port int, tcpIn chan<- C.ConnContext) error { httpMux.Lock() defer httpMux.Unlock() @@ -78,15 +81,16 @@ func ReCreateHTTP(port int) error { } var err error - httpListener, err = http.NewHTTPProxy(addr) + httpListener, err = http.New(addr, tcpIn) if err != nil { return err } + log.Infoln("HTTP proxy listening at: %s", httpListener.Address()) return nil } -func ReCreateSocks(port int) error { +func ReCreateSocks(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) error { socksMux.Lock() defer socksMux.Unlock() @@ -121,12 +125,12 @@ func ReCreateSocks(port int) error { return nil } - tcpListener, err := socks.NewSocksProxy(addr) + tcpListener, err := socks.New(addr, tcpIn) if err != nil { return err } - udpListener, err := socks.NewSocksUDPProxy(addr) + udpListener, err := socks.NewUDP(addr, udpIn) if err != nil { tcpListener.Close() return err @@ -135,10 +139,11 @@ func ReCreateSocks(port int) error { socksListener = tcpListener socksUDPListener = udpListener + log.Infoln("SOCKS5 proxy listening at: %s", socksListener.Address()) return nil } -func ReCreateRedir(port int) error { +func ReCreateRedir(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) error { redirMux.Lock() defer redirMux.Unlock() @@ -165,20 +170,21 @@ func ReCreateRedir(port int) error { } var err error - redirListener, err = redir.NewRedirProxy(addr) + redirListener, err = redir.New(addr, tcpIn) if err != nil { return err } - redirUDPListener, err = redir.NewRedirUDPProxy(addr) + redirUDPListener, err = tproxy.NewUDP(addr, udpIn) if err != nil { log.Warnln("Failed to start Redir UDP Listener: %s", err) } + log.Infoln("Redirect proxy listening at: %s", redirListener.Address()) return nil } -func ReCreateTProxy(port int) error { +func ReCreateTProxy(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) error { tproxyMux.Lock() defer tproxyMux.Unlock() @@ -205,20 +211,21 @@ func ReCreateTProxy(port int) error { } var err error - tproxyListener, err = redir.NewTProxy(addr) + tproxyListener, err = tproxy.New(addr, tcpIn) if err != nil { return err } - tproxyUDPListener, err = redir.NewRedirUDPProxy(addr) + tproxyUDPListener, err = tproxy.NewUDP(addr, udpIn) if err != nil { log.Warnln("Failed to start TProxy UDP Listener: %s", err) } + log.Infoln("TProxy server listening at: %s", tproxyListener.Address()) return nil } -func ReCreateMixed(port int) error { +func ReCreateMixed(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) error { mixedMux.Lock() defer mixedMux.Unlock() @@ -253,17 +260,18 @@ func ReCreateMixed(port int) error { } var err error - mixedListener, err = mixed.NewMixedProxy(addr) + mixedListener, err = mixed.New(addr, tcpIn) if err != nil { return err } - mixedUDPLister, err = socks.NewSocksUDPProxy(addr) + mixedUDPLister, err = socks.NewUDP(addr, udpIn) if err != nil { mixedListener.Close() return err } + log.Infoln("Mixed(http+socks5) proxy listening at: %s", mixedListener.Address()) return nil } diff --git a/proxy/mixed/conn.go b/listener/mixed/conn.go similarity index 100% rename from proxy/mixed/conn.go rename to listener/mixed/conn.go diff --git a/proxy/mixed/mixed.go b/listener/mixed/mixed.go similarity index 52% rename from proxy/mixed/mixed.go rename to listener/mixed/mixed.go index b89748ee..b930d068 100644 --- a/proxy/mixed/mixed.go +++ b/listener/mixed/mixed.go @@ -5,29 +5,27 @@ import ( "time" "github.com/Dreamacro/clash/common/cache" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/proxy/http" - "github.com/Dreamacro/clash/proxy/socks" + C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/listener/http" + "github.com/Dreamacro/clash/listener/socks" "github.com/Dreamacro/clash/transport/socks5" ) -type MixedListener struct { +type Listener struct { net.Listener address string closed bool cache *cache.Cache } -func NewMixedProxy(addr string) (*MixedListener, error) { +func New(addr string, in chan<- C.ConnContext) (*Listener, error) { l, err := net.Listen("tcp", addr) if err != nil { return nil, err } - ml := &MixedListener{l, addr, false, cache.New(30 * time.Second)} + ml := &Listener{l, addr, false, cache.New(30 * time.Second)} go func() { - log.Infoln("Mixed(http+socks5) proxy listening at: %s", addr) - for { c, err := ml.Accept() if err != nil { @@ -36,23 +34,23 @@ func NewMixedProxy(addr string) (*MixedListener, error) { } continue } - go handleConn(c, ml.cache) + go handleConn(c, in, ml.cache) } }() return ml, nil } -func (l *MixedListener) Close() { +func (l *Listener) Close() { l.closed = true l.Listener.Close() } -func (l *MixedListener) Address() string { +func (l *Listener) Address() string { return l.address } -func handleConn(conn net.Conn, cache *cache.Cache) { +func handleConn(conn net.Conn, in chan<- C.ConnContext, cache *cache.Cache) { bufConn := NewBufferedConn(conn) head, err := bufConn.Peek(1) if err != nil { @@ -60,9 +58,9 @@ func handleConn(conn net.Conn, cache *cache.Cache) { } if head[0] == socks5.Version { - socks.HandleSocks(bufConn) + socks.HandleSocks(bufConn, in) return } - http.HandleConn(bufConn, cache) + http.HandleConn(bufConn, in, cache) } diff --git a/proxy/redir/tcp.go b/listener/redir/tcp.go similarity index 56% rename from proxy/redir/tcp.go rename to listener/redir/tcp.go index ef6718ec..a54bfff8 100644 --- a/proxy/redir/tcp.go +++ b/listener/redir/tcp.go @@ -5,25 +5,22 @@ import ( "github.com/Dreamacro/clash/adapter/inbound" C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/tunnel" ) -type RedirListener struct { +type Listener struct { net.Listener address string closed bool } -func NewRedirProxy(addr string) (*RedirListener, error) { +func New(addr string, in chan<- C.ConnContext) (*Listener, error) { l, err := net.Listen("tcp", addr) if err != nil { return nil, err } - rl := &RedirListener{l, addr, false} + rl := &Listener{l, addr, false} go func() { - log.Infoln("Redir proxy listening at: %s", addr) for { c, err := l.Accept() if err != nil { @@ -32,28 +29,28 @@ func NewRedirProxy(addr string) (*RedirListener, error) { } continue } - go handleRedir(c) + go handleRedir(c, in) } }() return rl, nil } -func (l *RedirListener) Close() { +func (l *Listener) Close() { l.closed = true l.Listener.Close() } -func (l *RedirListener) Address() string { +func (l *Listener) Address() string { return l.address } -func handleRedir(conn net.Conn) { +func handleRedir(conn net.Conn, in chan<- C.ConnContext) { target, err := parserPacket(conn) if err != nil { conn.Close() return } conn.(*net.TCPConn).SetKeepAlive(true) - tunnel.Add(inbound.NewSocket(target, conn, C.REDIR)) + in <- inbound.NewSocket(target, conn, C.REDIR) } diff --git a/proxy/redir/tcp_darwin.go b/listener/redir/tcp_darwin.go similarity index 100% rename from proxy/redir/tcp_darwin.go rename to listener/redir/tcp_darwin.go diff --git a/proxy/redir/tcp_freebsd.go b/listener/redir/tcp_freebsd.go similarity index 100% rename from proxy/redir/tcp_freebsd.go rename to listener/redir/tcp_freebsd.go diff --git a/proxy/redir/tcp_linux.go b/listener/redir/tcp_linux.go similarity index 100% rename from proxy/redir/tcp_linux.go rename to listener/redir/tcp_linux.go diff --git a/proxy/redir/tcp_linux_386.go b/listener/redir/tcp_linux_386.go similarity index 100% rename from proxy/redir/tcp_linux_386.go rename to listener/redir/tcp_linux_386.go diff --git a/proxy/redir/tcp_linux_other.go b/listener/redir/tcp_linux_other.go similarity index 100% rename from proxy/redir/tcp_linux_other.go rename to listener/redir/tcp_linux_other.go diff --git a/proxy/redir/tcp_other.go b/listener/redir/tcp_other.go similarity index 100% rename from proxy/redir/tcp_other.go rename to listener/redir/tcp_other.go diff --git a/proxy/socks/tcp.go b/listener/socks/tcp.go similarity index 63% rename from proxy/socks/tcp.go rename to listener/socks/tcp.go index a58d63d1..eca36f0f 100644 --- a/proxy/socks/tcp.go +++ b/listener/socks/tcp.go @@ -7,27 +7,24 @@ import ( "github.com/Dreamacro/clash/adapter/inbound" C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" - authStore "github.com/Dreamacro/clash/proxy/auth" + authStore "github.com/Dreamacro/clash/listener/auth" "github.com/Dreamacro/clash/transport/socks5" - "github.com/Dreamacro/clash/tunnel" ) -type SockListener struct { +type Listener struct { net.Listener address string closed bool } -func NewSocksProxy(addr string) (*SockListener, error) { +func New(addr string, in chan<- C.ConnContext) (*Listener, error) { l, err := net.Listen("tcp", addr) if err != nil { return nil, err } - sl := &SockListener{l, addr, false} + sl := &Listener{l, addr, false} go func() { - log.Infoln("SOCKS proxy listening at: %s", addr) for { c, err := l.Accept() if err != nil { @@ -36,23 +33,23 @@ func NewSocksProxy(addr string) (*SockListener, error) { } continue } - go HandleSocks(c) + go HandleSocks(c, in) } }() return sl, nil } -func (l *SockListener) Close() { +func (l *Listener) Close() { l.closed = true l.Listener.Close() } -func (l *SockListener) Address() string { +func (l *Listener) Address() string { return l.address } -func HandleSocks(conn net.Conn) { +func HandleSocks(conn net.Conn, in chan<- C.ConnContext) { target, command, err := socks5.ServerHandshake(conn, authStore.Authenticator()) if err != nil { conn.Close() @@ -66,5 +63,5 @@ func HandleSocks(conn net.Conn) { io.Copy(ioutil.Discard, conn) return } - tunnel.Add(inbound.NewSocket(target, conn, C.SOCKS)) + in <- inbound.NewSocket(target, conn, C.SOCKS) } diff --git a/proxy/socks/udp.go b/listener/socks/udp.go similarity index 66% rename from proxy/socks/udp.go rename to listener/socks/udp.go index b41e6f18..7ddeed20 100644 --- a/proxy/socks/udp.go +++ b/listener/socks/udp.go @@ -9,27 +9,25 @@ import ( C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/transport/socks5" - "github.com/Dreamacro/clash/tunnel" ) -type SockUDPListener struct { +type UDPListener struct { net.PacketConn address string closed bool } -func NewSocksUDPProxy(addr string) (*SockUDPListener, error) { +func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error) { l, err := net.ListenPacket("udp", addr) if err != nil { return nil, err } - err = sockopt.UDPReuseaddr(l.(*net.UDPConn)) - if err != nil { + if err := sockopt.UDPReuseaddr(l.(*net.UDPConn)); err != nil { log.Warnln("Failed to Reuse UDP Address: %s", err) } - sl := &SockUDPListener{l, addr, false} + sl := &UDPListener{l, addr, false} go func() { for { buf := pool.Get(pool.RelayBufferSize) @@ -41,23 +39,23 @@ func NewSocksUDPProxy(addr string) (*SockUDPListener, error) { } continue } - handleSocksUDP(l, buf[:n], remoteAddr) + handleSocksUDP(l, in, buf[:n], remoteAddr) } }() return sl, nil } -func (l *SockUDPListener) Close() error { +func (l *UDPListener) Close() error { l.closed = true return l.PacketConn.Close() } -func (l *SockUDPListener) Address() string { +func (l *UDPListener) Address() string { return l.address } -func handleSocksUDP(pc net.PacketConn, buf []byte, addr net.Addr) { +func handleSocksUDP(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []byte, addr net.Addr) { target, payload, err := socks5.DecodeUDPPacket(buf) if err != nil { // Unresolved UDP packet, return buffer to the pool @@ -70,5 +68,8 @@ func handleSocksUDP(pc net.PacketConn, buf []byte, addr net.Addr) { payload: payload, bufRef: buf, } - tunnel.AddPacket(inbound.NewPacket(target, packet, C.SOCKS)) + select { + case in <- inbound.NewPacket(target, packet, C.TPROXY): + default: + } } diff --git a/proxy/socks/utils.go b/listener/socks/utils.go similarity index 100% rename from proxy/socks/utils.go rename to listener/socks/utils.go diff --git a/proxy/redir/utils.go b/listener/tproxy/packet.go similarity index 97% rename from proxy/redir/utils.go rename to listener/tproxy/packet.go index 58e30b0c..8aa3e9bf 100644 --- a/proxy/redir/utils.go +++ b/listener/tproxy/packet.go @@ -1,4 +1,4 @@ -package redir +package tproxy import ( "net" diff --git a/proxy/redir/tproxy_linux.go b/listener/tproxy/setsockopt_linux.go similarity index 98% rename from proxy/redir/tproxy_linux.go rename to listener/tproxy/setsockopt_linux.go index 22f8b46b..a70223f7 100644 --- a/proxy/redir/tproxy_linux.go +++ b/listener/tproxy/setsockopt_linux.go @@ -1,6 +1,6 @@ // +build linux -package redir +package tproxy import ( "net" diff --git a/proxy/redir/tproxy_other.go b/listener/tproxy/setsockopt_other.go similarity index 91% rename from proxy/redir/tproxy_other.go rename to listener/tproxy/setsockopt_other.go index c20ea7d7..05947728 100644 --- a/proxy/redir/tproxy_other.go +++ b/listener/tproxy/setsockopt_other.go @@ -1,6 +1,6 @@ // +build !linux -package redir +package tproxy import ( "errors" diff --git a/proxy/redir/tproxy.go b/listener/tproxy/tproxy.go similarity index 62% rename from proxy/redir/tproxy.go rename to listener/tproxy/tproxy.go index 44682362..a787b359 100644 --- a/proxy/redir/tproxy.go +++ b/listener/tproxy/tproxy.go @@ -1,22 +1,20 @@ -package redir +package tproxy import ( "net" "github.com/Dreamacro/clash/adapter/inbound" C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/transport/socks5" - "github.com/Dreamacro/clash/tunnel" ) -type TProxyListener struct { +type Listener struct { net.Listener address string closed bool } -func NewTProxy(addr string) (*TProxyListener, error) { +func New(addr string, in chan<- C.ConnContext) (*Listener, error) { l, err := net.Listen("tcp", addr) if err != nil { return nil, err @@ -33,13 +31,12 @@ func NewTProxy(addr string) (*TProxyListener, error) { return nil, err } - rl := &TProxyListener{ + rl := &Listener{ Listener: l, address: addr, } go func() { - log.Infoln("TProxy server listening at: %s", addr) for { c, err := l.Accept() if err != nil { @@ -48,24 +45,24 @@ func NewTProxy(addr string) (*TProxyListener, error) { } continue } - go rl.handleTProxy(c) + go rl.handleTProxy(c, in) } }() return rl, nil } -func (l *TProxyListener) Close() { +func (l *Listener) Close() { l.closed = true l.Listener.Close() } -func (l *TProxyListener) Address() string { +func (l *Listener) Address() string { return l.address } -func (l *TProxyListener) handleTProxy(conn net.Conn) { +func (l *Listener) handleTProxy(conn net.Conn, in chan<- C.ConnContext) { target := socks5.ParseAddrToSocksAddr(conn.LocalAddr()) conn.(*net.TCPConn).SetKeepAlive(true) - tunnel.Add(inbound.NewSocket(target, conn, C.TPROXY)) + in <- inbound.NewSocket(target, conn, C.TPROXY) } diff --git a/proxy/redir/udp.go b/listener/tproxy/udp.go similarity index 66% rename from proxy/redir/udp.go rename to listener/tproxy/udp.go index e43af878..88125016 100644 --- a/proxy/redir/udp.go +++ b/listener/tproxy/udp.go @@ -1,4 +1,4 @@ -package redir +package tproxy import ( "net" @@ -7,22 +7,21 @@ import ( "github.com/Dreamacro/clash/common/pool" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/socks5" - "github.com/Dreamacro/clash/tunnel" ) -type RedirUDPListener struct { +type UDPListener struct { net.PacketConn address string closed bool } -func NewRedirUDPProxy(addr string) (*RedirUDPListener, error) { +func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error) { l, err := net.ListenPacket("udp", addr) if err != nil { return nil, err } - rl := &RedirUDPListener{l, addr, false} + rl := &UDPListener{l, addr, false} c := l.(*net.UDPConn) @@ -53,27 +52,30 @@ func NewRedirUDPProxy(addr string) (*RedirUDPListener, error) { if err != nil { continue } - handleRedirUDP(l, buf[:n], lAddr, rAddr) + handlePacketConn(l, in, buf[:n], lAddr, rAddr) } }() return rl, nil } -func (l *RedirUDPListener) Close() error { +func (l *UDPListener) Close() error { l.closed = true return l.PacketConn.Close() } -func (l *RedirUDPListener) Address() string { +func (l *UDPListener) Address() string { return l.address } -func handleRedirUDP(pc net.PacketConn, buf []byte, lAddr *net.UDPAddr, rAddr *net.UDPAddr) { +func handlePacketConn(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []byte, lAddr *net.UDPAddr, rAddr *net.UDPAddr) { target := socks5.ParseAddrToSocksAddr(rAddr) pkt := &packet{ lAddr: lAddr, buf: buf, } - tunnel.AddPacket(inbound.NewPacket(target, pkt, C.TPROXY)) + select { + case in <- inbound.NewPacket(target, pkt, C.TPROXY): + default: + } } diff --git a/proxy/redir/utils_linux.go b/listener/tproxy/udp_linux.go similarity index 71% rename from proxy/redir/utils_linux.go rename to listener/tproxy/udp_linux.go index 888601a4..40c177e7 100644 --- a/proxy/redir/utils_linux.go +++ b/listener/tproxy/udp_linux.go @@ -1,8 +1,10 @@ // +build linux -package redir +package tproxy import ( + "encoding/binary" + "errors" "fmt" "net" "os" @@ -10,6 +12,11 @@ import ( "syscall" ) +const ( + IPV6_TRANSPARENT = 0x4b + IPV6_RECVORIGDSTADDR = 0x4a +) + // dialUDP acts like net.DialUDP for transparent proxy. // It binds to a non-local address(`lAddr`). func dialUDP(network string, lAddr *net.UDPAddr, rAddr *net.UDPAddr) (*net.UDPConn, error) { @@ -94,3 +101,24 @@ func udpAddrFamily(net string, lAddr, rAddr *net.UDPAddr) int { } return syscall.AF_INET6 } + +func getOrigDst(oob []byte, oobn int) (*net.UDPAddr, error) { + msgs, err := syscall.ParseSocketControlMessage(oob[:oobn]) + if err != nil { + return nil, err + } + + for _, msg := range msgs { + if msg.Header.Level == syscall.SOL_IP && msg.Header.Type == syscall.IP_RECVORIGDSTADDR { + ip := net.IP(msg.Data[4:8]) + port := binary.BigEndian.Uint16(msg.Data[2:4]) + return &net.UDPAddr{IP: ip, Port: int(port)}, nil + } else if msg.Header.Level == syscall.SOL_IPV6 && msg.Header.Type == IPV6_RECVORIGDSTADDR { + ip := net.IP(msg.Data[8:24]) + port := binary.BigEndian.Uint16(msg.Data[2:4]) + return &net.UDPAddr{IP: ip, Port: int(port)}, nil + } + } + + return nil, errors.New("cannot find origDst") +} diff --git a/proxy/redir/utils_other.go b/listener/tproxy/udp_other.go similarity index 58% rename from proxy/redir/utils_other.go rename to listener/tproxy/udp_other.go index faec71e2..a4531b5d 100644 --- a/proxy/redir/utils_other.go +++ b/listener/tproxy/udp_other.go @@ -1,12 +1,16 @@ // +build !linux -package redir +package tproxy import ( "errors" "net" ) +func getOrigDst(oob []byte, oobn int) (*net.UDPAddr, error) { + return nil, errors.New("UDP redir not supported on current platform") +} + func dialUDP(network string, lAddr *net.UDPAddr, rAddr *net.UDPAddr) (*net.UDPConn, error) { return nil, errors.New("UDP redir not supported on current platform") } diff --git a/proxy/redir/udp_linux.go b/proxy/redir/udp_linux.go deleted file mode 100644 index e5a53e4d..00000000 --- a/proxy/redir/udp_linux.go +++ /dev/null @@ -1,36 +0,0 @@ -// +build linux - -package redir - -import ( - "encoding/binary" - "errors" - "net" - "syscall" -) - -const ( - IPV6_TRANSPARENT = 0x4b - IPV6_RECVORIGDSTADDR = 0x4a -) - -func getOrigDst(oob []byte, oobn int) (*net.UDPAddr, error) { - msgs, err := syscall.ParseSocketControlMessage(oob[:oobn]) - if err != nil { - return nil, err - } - - for _, msg := range msgs { - if msg.Header.Level == syscall.SOL_IP && msg.Header.Type == syscall.IP_RECVORIGDSTADDR { - ip := net.IP(msg.Data[4:8]) - port := binary.BigEndian.Uint16(msg.Data[2:4]) - return &net.UDPAddr{IP: ip, Port: int(port)}, nil - } else if msg.Header.Level == syscall.SOL_IPV6 && msg.Header.Type == IPV6_RECVORIGDSTADDR { - ip := net.IP(msg.Data[8:24]) - port := binary.BigEndian.Uint16(msg.Data[2:4]) - return &net.UDPAddr{IP: ip, Port: int(port)}, nil - } - } - - return nil, errors.New("cannot find origDst") -} diff --git a/proxy/redir/udp_other.go b/proxy/redir/udp_other.go deleted file mode 100644 index e50ec5b9..00000000 --- a/proxy/redir/udp_other.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build !linux - -package redir - -import ( - "errors" - "net" -) - -func getOrigDst(oob []byte, oobn int) (*net.UDPAddr, error) { - return nil, errors.New("UDP redir not supported on current platform") -} diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 18551ae8..a9ffb61f 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -37,17 +37,14 @@ func init() { go process() } -// Add request to queue -func Add(ctx C.ConnContext) { - tcpQueue <- ctx +// TCPIn return fan-in queue +func TCPIn() chan<- C.ConnContext { + return tcpQueue } -// AddPacket add udp Packet to queue -func AddPacket(packet *inbound.PacketAdapter) { - select { - case udpQueue <- packet: - default: - } +// UDPIn return fan-in udp queue +func UDPIn() chan<- *inbound.PacketAdapter { + return udpQueue } // Rules return all rules