github.com/metacubex/mihomo@v1.18.5/listener/tproxy/tproxy.go (about)

     1  package tproxy
     2  
     3  import (
     4  	"net"
     5  
     6  	"github.com/metacubex/mihomo/adapter/inbound"
     7  	N "github.com/metacubex/mihomo/common/net"
     8  	C "github.com/metacubex/mihomo/constant"
     9  	"github.com/metacubex/mihomo/transport/socks5"
    10  )
    11  
    12  type Listener struct {
    13  	listener net.Listener
    14  	addr     string
    15  	closed   bool
    16  }
    17  
    18  // RawAddress implements C.Listener
    19  func (l *Listener) RawAddress() string {
    20  	return l.addr
    21  }
    22  
    23  // Address implements C.Listener
    24  func (l *Listener) Address() string {
    25  	return l.listener.Addr().String()
    26  }
    27  
    28  // Close implements C.Listener
    29  func (l *Listener) Close() error {
    30  	l.closed = true
    31  	return l.listener.Close()
    32  }
    33  
    34  func (l *Listener) handleTProxy(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) {
    35  	target := socks5.ParseAddrToSocksAddr(conn.LocalAddr())
    36  	N.TCPKeepAlive(conn)
    37  	// TProxy's conn.LocalAddr() is target address, so we set from l.listener
    38  	additions = append([]inbound.Addition{inbound.WithInAddr(l.listener.Addr())}, additions...)
    39  	tunnel.HandleTCPConn(inbound.NewSocket(target, conn, C.TPROXY, additions...))
    40  }
    41  
    42  func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) {
    43  	if len(additions) == 0 {
    44  		additions = []inbound.Addition{
    45  			inbound.WithInName("DEFAULT-TPROXY"),
    46  			inbound.WithSpecialRules(""),
    47  		}
    48  	}
    49  	l, err := net.Listen("tcp", addr)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  
    54  	tl := l.(*net.TCPListener)
    55  	rc, err := tl.SyscallConn()
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  
    60  	err = setsockopt(rc, addr)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  
    65  	rl := &Listener{
    66  		listener: l,
    67  		addr:     addr,
    68  	}
    69  
    70  	go func() {
    71  		for {
    72  			c, err := l.Accept()
    73  			if err != nil {
    74  				if rl.closed {
    75  					break
    76  				}
    77  				continue
    78  			}
    79  			go rl.handleTProxy(c, tunnel, additions...)
    80  		}
    81  	}()
    82  
    83  	return rl, nil
    84  }