github.com/yaling888/clash@v1.53.0/listener/autoredir/tcp.go (about)

     1  package autoredir
     2  
     3  import (
     4  	"net"
     5  	"net/netip"
     6  
     7  	"github.com/phuslu/log"
     8  
     9  	"github.com/yaling888/clash/adapter/inbound"
    10  	C "github.com/yaling888/clash/constant"
    11  	"github.com/yaling888/clash/transport/socks5"
    12  )
    13  
    14  type Listener struct {
    15  	listener   net.Listener
    16  	addr       string
    17  	closed     bool
    18  	lookupFunc func(netip.AddrPort) (socks5.Addr, error)
    19  }
    20  
    21  // RawAddress implements C.Listener
    22  func (l *Listener) RawAddress() string {
    23  	return l.addr
    24  }
    25  
    26  // Address implements C.Listener
    27  func (l *Listener) Address() string {
    28  	return l.listener.Addr().String()
    29  }
    30  
    31  // Close implements C.Listener
    32  func (l *Listener) Close() error {
    33  	l.closed = true
    34  	return l.listener.Close()
    35  }
    36  
    37  func (l *Listener) TCPAddr() netip.AddrPort {
    38  	return l.listener.Addr().(*net.TCPAddr).AddrPort()
    39  }
    40  
    41  func (l *Listener) SetLookupFunc(lookupFunc func(netip.AddrPort) (socks5.Addr, error)) {
    42  	l.lookupFunc = lookupFunc
    43  }
    44  
    45  func (l *Listener) handleRedir(conn net.Conn, in chan<- C.ConnContext) {
    46  	if l.lookupFunc == nil {
    47  		log.Error().Msg("[Auto Redirect] lookup function is nil")
    48  		return
    49  	}
    50  
    51  	target, err := l.lookupFunc(conn.RemoteAddr().(*net.TCPAddr).AddrPort())
    52  	if err != nil {
    53  		log.Warn().Err(err).Msg("[Auto Redirect]")
    54  		_ = conn.Close()
    55  		return
    56  	}
    57  
    58  	_ = conn.(*net.TCPConn).SetKeepAlive(true)
    59  
    60  	in <- inbound.NewSocket(target, conn, C.REDIR)
    61  }
    62  
    63  func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
    64  	l, err := net.Listen("tcp", addr)
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  	al := &Listener{
    69  		listener: l,
    70  		addr:     addr,
    71  	}
    72  
    73  	go func() {
    74  		for {
    75  			c, err := l.Accept()
    76  			if err != nil {
    77  				if al.closed {
    78  					break
    79  				}
    80  				continue
    81  			}
    82  			go al.handleRedir(c, in)
    83  		}
    84  	}()
    85  
    86  	return al, nil
    87  }