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

     1  package mixed
     2  
     3  import (
     4  	"net"
     5  
     6  	"github.com/yaling888/clash/common/cache"
     7  	N "github.com/yaling888/clash/common/net"
     8  	"github.com/yaling888/clash/component/auth"
     9  	C "github.com/yaling888/clash/constant"
    10  	"github.com/yaling888/clash/listener/http"
    11  	"github.com/yaling888/clash/listener/socks"
    12  	"github.com/yaling888/clash/transport/socks4"
    13  	"github.com/yaling888/clash/transport/socks5"
    14  )
    15  
    16  type Listener struct {
    17  	listener net.Listener
    18  	addr     string
    19  	cache    *cache.LruCache[string, bool]
    20  	auth     auth.Authenticator
    21  	closed   bool
    22  }
    23  
    24  // RawAddress implements C.Listener
    25  func (l *Listener) RawAddress() string {
    26  	return l.addr
    27  }
    28  
    29  // Address implements C.Listener
    30  func (l *Listener) Address() string {
    31  	return l.listener.Addr().String()
    32  }
    33  
    34  // Close implements C.Listener
    35  func (l *Listener) Close() error {
    36  	l.closed = true
    37  	return l.listener.Close()
    38  }
    39  
    40  // SetAuthenticator implements C.AuthenticatorListener
    41  func (l *Listener) SetAuthenticator(users []auth.AuthUser) {
    42  	l.auth = auth.NewAuthenticator(users)
    43  }
    44  
    45  func New(addr string, in chan<- C.ConnContext) (C.Listener, error) {
    46  	l, err := net.Listen("tcp", addr)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	ml := &Listener{
    52  		listener: l,
    53  		addr:     addr,
    54  		cache:    cache.New[string, bool](cache.WithAge[string, bool](30)),
    55  	}
    56  	go func() {
    57  		for {
    58  			c, err := ml.listener.Accept()
    59  			if err != nil {
    60  				if ml.closed {
    61  					break
    62  				}
    63  				continue
    64  			}
    65  			go handleConn(c, in, ml.cache, ml.auth)
    66  		}
    67  	}()
    68  
    69  	return ml, nil
    70  }
    71  
    72  func handleConn(conn net.Conn, in chan<- C.ConnContext, cache *cache.LruCache[string, bool], auth auth.Authenticator) {
    73  	_ = conn.(*net.TCPConn).SetKeepAlive(true)
    74  
    75  	bufConn := N.NewBufferedConn(conn)
    76  	head, err := bufConn.Peek(1)
    77  	if err != nil {
    78  		return
    79  	}
    80  
    81  	switch head[0] {
    82  	case socks4.Version:
    83  		socks.HandleSocks4(bufConn, in, auth)
    84  	case socks5.Version:
    85  		socks.HandleSocks5(bufConn, in, auth)
    86  	default:
    87  		http.HandleConn(bufConn, in, cache, auth)
    88  	}
    89  }