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

     1  package socks
     2  
     3  import (
     4  	"io"
     5  	"net"
     6  
     7  	"github.com/metacubex/mihomo/adapter/inbound"
     8  	N "github.com/metacubex/mihomo/common/net"
     9  	C "github.com/metacubex/mihomo/constant"
    10  	authStore "github.com/metacubex/mihomo/listener/auth"
    11  	"github.com/metacubex/mihomo/transport/socks4"
    12  	"github.com/metacubex/mihomo/transport/socks5"
    13  )
    14  
    15  type Listener struct {
    16  	listener net.Listener
    17  	addr     string
    18  	closed   bool
    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 New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) {
    38  	isDefault := false
    39  	if len(additions) == 0 {
    40  		isDefault = true
    41  		additions = []inbound.Addition{
    42  			inbound.WithInName("DEFAULT-SOCKS"),
    43  			inbound.WithSpecialRules(""),
    44  		}
    45  	}
    46  	l, err := inbound.Listen("tcp", addr)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	sl := &Listener{
    52  		listener: l,
    53  		addr:     addr,
    54  	}
    55  	go func() {
    56  		for {
    57  			c, err := l.Accept()
    58  			if err != nil {
    59  				if sl.closed {
    60  					break
    61  				}
    62  				continue
    63  			}
    64  			if isDefault { // only apply on default listener
    65  				if !inbound.IsRemoteAddrDisAllowed(c.RemoteAddr()) {
    66  					_ = c.Close()
    67  					continue
    68  				}
    69  			}
    70  			go handleSocks(c, tunnel, additions...)
    71  		}
    72  	}()
    73  
    74  	return sl, nil
    75  }
    76  
    77  func handleSocks(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) {
    78  	N.TCPKeepAlive(conn)
    79  	bufConn := N.NewBufferedConn(conn)
    80  	head, err := bufConn.Peek(1)
    81  	if err != nil {
    82  		conn.Close()
    83  		return
    84  	}
    85  
    86  	switch head[0] {
    87  	case socks4.Version:
    88  		HandleSocks4(bufConn, tunnel, additions...)
    89  	case socks5.Version:
    90  		HandleSocks5(bufConn, tunnel, additions...)
    91  	default:
    92  		conn.Close()
    93  	}
    94  }
    95  
    96  func HandleSocks4(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) {
    97  	authenticator := authStore.Authenticator()
    98  	if inbound.SkipAuthRemoteAddr(conn.RemoteAddr()) {
    99  		authenticator = nil
   100  	}
   101  	addr, _, user, err := socks4.ServerHandshake(conn, authenticator)
   102  	if err != nil {
   103  		conn.Close()
   104  		return
   105  	}
   106  	additions = append(additions, inbound.WithInUser(user))
   107  	tunnel.HandleTCPConn(inbound.NewSocket(socks5.ParseAddr(addr), conn, C.SOCKS4, additions...))
   108  }
   109  
   110  func HandleSocks5(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) {
   111  	authenticator := authStore.Authenticator()
   112  	if inbound.SkipAuthRemoteAddr(conn.RemoteAddr()) {
   113  		authenticator = nil
   114  	}
   115  	target, command, user, err := socks5.ServerHandshake(conn, authenticator)
   116  	if err != nil {
   117  		conn.Close()
   118  		return
   119  	}
   120  	if command == socks5.CmdUDPAssociate {
   121  		defer conn.Close()
   122  		io.Copy(io.Discard, conn)
   123  		return
   124  	}
   125  	additions = append(additions, inbound.WithInUser(user))
   126  	tunnel.HandleTCPConn(inbound.NewSocket(target, conn, C.SOCKS5, additions...))
   127  }