github.com/chwjbn/xclash@v0.2.0/listener/socks/tcp.go (about)

     1  package socks
     2  
     3  import (
     4  	"io"
     5  	"net"
     6  
     7  	"github.com/chwjbn/xclash/adapter/inbound"
     8  	N "github.com/chwjbn/xclash/common/net"
     9  	C "github.com/chwjbn/xclash/constant"
    10  	authStore "github.com/chwjbn/xclash/listener/auth"
    11  	"github.com/chwjbn/xclash/transport/socks4"
    12  	"github.com/chwjbn/xclash/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, in chan<- C.ConnContext) (*Listener, error) {
    38  	l, err := net.Listen("tcp", addr)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  
    43  	sl := &Listener{
    44  		listener: l,
    45  		addr:     addr,
    46  	}
    47  	go func() {
    48  		for {
    49  			c, err := l.Accept()
    50  			if err != nil {
    51  				if sl.closed {
    52  					break
    53  				}
    54  				continue
    55  			}
    56  			go handleSocks(c, in)
    57  		}
    58  	}()
    59  
    60  	return sl, nil
    61  }
    62  
    63  func handleSocks(conn net.Conn, in chan<- C.ConnContext) {
    64  	bufConn := N.NewBufferedConn(conn)
    65  	head, err := bufConn.Peek(1)
    66  	if err != nil {
    67  		conn.Close()
    68  		return
    69  	}
    70  
    71  	switch head[0] {
    72  	case socks4.Version:
    73  		HandleSocks4(bufConn, in)
    74  	case socks5.Version:
    75  		HandleSocks5(bufConn, in)
    76  	default:
    77  		conn.Close()
    78  	}
    79  }
    80  
    81  func HandleSocks4(conn net.Conn, in chan<- C.ConnContext) {
    82  	addr, _, err := socks4.ServerHandshake(conn, authStore.Authenticator())
    83  	if err != nil {
    84  		conn.Close()
    85  		return
    86  	}
    87  	if c, ok := conn.(*net.TCPConn); ok {
    88  		c.SetKeepAlive(true)
    89  	}
    90  	in <- inbound.NewSocket(socks5.ParseAddr(addr), conn, C.SOCKS4)
    91  }
    92  
    93  func HandleSocks5(conn net.Conn, in chan<- C.ConnContext) {
    94  	authUser, target, command, err := socks5.ServerHandshake(conn, authStore.Authenticator())
    95  	if err != nil {
    96  		conn.Close()
    97  		return
    98  	}
    99  	if c, ok := conn.(*net.TCPConn); ok {
   100  		c.SetKeepAlive(true)
   101  	}
   102  	if command == socks5.CmdUDPAssociate {
   103  		defer conn.Close()
   104  		io.Copy(io.Discard, conn)
   105  		return
   106  	}
   107  	in <- inbound.NewSocketWithAuth(target, conn, C.SOCKS5, authUser)
   108  }