package anytls import ( "context" "crypto/sha256" "crypto/tls" "encoding/binary" "errors" "net" "strings" "github.com/metacubex/mihomo/adapter/inbound" "github.com/metacubex/mihomo/common/atomic" "github.com/metacubex/mihomo/common/buf" N "github.com/metacubex/mihomo/common/net" C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/sing" "github.com/metacubex/mihomo/transport/anytls/padding" "github.com/metacubex/mihomo/transport/anytls/session" "github.com/sagernet/sing/common/auth" "github.com/sagernet/sing/common/bufio" M "github.com/sagernet/sing/common/metadata" ) type Listener struct { closed bool config LC.AnyTLSServer listeners []net.Listener tlsConfig *tls.Config userMap map[[32]byte]string padding atomic.TypedValue[*padding.PaddingFactory] } func New(config LC.AnyTLSServer, tunnel C.Tunnel, additions ...inbound.Addition) (sl *Listener, err error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-ANYTLS"), inbound.WithSpecialRules(""), } } tlsConfig := &tls.Config{} if config.Certificate != "" && config.PrivateKey != "" { cert, err := N.ParseCert(config.Certificate, config.PrivateKey, C.Path) if err != nil { return nil, err } tlsConfig.Certificates = []tls.Certificate{cert} } sl = &Listener{ config: config, tlsConfig: tlsConfig, userMap: make(map[[32]byte]string), } for user, password := range config.Users { sl.userMap[sha256.Sum256([]byte(password))] = user } if len(config.PaddingScheme) > 0 { if !padding.UpdatePaddingScheme([]byte(config.PaddingScheme), &sl.padding) { return nil, errors.New("incorrect padding scheme format") } } else { padding.UpdatePaddingScheme(padding.DefaultPaddingScheme, &sl.padding) } // Using sing handler can automatically handle UoT h, err := sing.NewListenerHandler(sing.ListenerConfig{ Tunnel: tunnel, Type: C.ANYTLS, Additions: additions, }) if err != nil { return nil, err } for _, addr := range strings.Split(config.Listen, ",") { addr := addr //TCP l, err := inbound.Listen("tcp", addr) if err != nil { return nil, err } sl.listeners = append(sl.listeners, l) go func() { for { c, err := l.Accept() if err != nil { if sl.closed { break } continue } go sl.HandleConn(c, h) } }() } return sl, nil } func (l *Listener) Close() error { l.closed = true var retErr error for _, lis := range l.listeners { err := lis.Close() if err != nil { retErr = err } } return retErr } func (l *Listener) Config() string { return l.config.String() } func (l *Listener) AddrList() (addrList []net.Addr) { for _, lis := range l.listeners { addrList = append(addrList, lis.Addr()) } return } func (l *Listener) HandleConn(conn net.Conn, h *sing.ListenerHandler) { ctx := context.TODO() conn = tls.Server(conn, l.tlsConfig) defer conn.Close() b := buf.NewPacket() _, err := b.ReadOnceFrom(conn) if err != nil { return } conn = bufio.NewCachedConn(conn, b) by, err := b.ReadBytes(32) if err != nil { return } var passwordSha256 [32]byte copy(passwordSha256[:], by) if user, ok := l.userMap[passwordSha256]; ok { ctx = auth.ContextWithUser(ctx, user) } else { return } by, err = b.ReadBytes(2) if err != nil { return } paddingLen := binary.BigEndian.Uint16(by) if paddingLen > 0 { _, err = b.ReadBytes(int(paddingLen)) if err != nil { return } } session := session.NewServerSession(conn, func(stream *session.Stream) { defer stream.Close() destination, err := M.SocksaddrSerializer.ReadAddrPort(stream) if err != nil { return } h.NewConnection(ctx, stream, M.Metadata{ Source: M.SocksaddrFromNet(conn.RemoteAddr()), Destination: destination, }) }, &l.padding) session.Run(true) session.Close() }