github.com/igoogolx/clash@v1.19.8/listener/tproxy/tcp.go (about)

     1  package tproxy
     2  
     3  import (
     4  	"net"
     5  
     6  	"github.com/igoogolx/clash/adapter/inbound"
     7  	C "github.com/igoogolx/clash/constant"
     8  	"github.com/igoogolx/clash/transport/socks5"
     9  )
    10  
    11  type Listener struct {
    12  	listener net.Listener
    13  	addr     string
    14  	closed   bool
    15  }
    16  
    17  // RawAddress implements C.Listener
    18  func (l *Listener) RawAddress() string {
    19  	return l.addr
    20  }
    21  
    22  // Address implements C.Listener
    23  func (l *Listener) Address() string {
    24  	return l.listener.Addr().String()
    25  }
    26  
    27  // Close implements C.Listener
    28  func (l *Listener) Close() error {
    29  	l.closed = true
    30  	return l.listener.Close()
    31  }
    32  
    33  func (l *Listener) handleTProxy(conn net.Conn, in chan<- C.ConnContext) {
    34  	target := socks5.ParseAddrToSocksAddr(conn.LocalAddr())
    35  	conn.(*net.TCPConn).SetKeepAlive(true)
    36  	in <- inbound.NewSocket(target, conn, C.TPROXY)
    37  }
    38  
    39  func New(addr string, in chan<- C.ConnContext) (C.Listener, error) {
    40  	l, err := net.Listen("tcp", addr)
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  
    45  	tl := l.(*net.TCPListener)
    46  	rc, err := tl.SyscallConn()
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	err = setsockopt(rc, addr)
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  
    56  	rl := &Listener{
    57  		listener: l,
    58  		addr:     addr,
    59  	}
    60  
    61  	go func() {
    62  		for {
    63  			c, err := l.Accept()
    64  			if err != nil {
    65  				if rl.closed {
    66  					break
    67  				}
    68  				continue
    69  			}
    70  			go rl.handleTProxy(c, in)
    71  		}
    72  	}()
    73  
    74  	return rl, nil
    75  }