mirror of
https://gitclone.com/github.com/MetaCubeX/Clash.Meta
synced 2025-04-25 04:38:04 +08:00
183 lines
3.9 KiB
Go
183 lines
3.9 KiB
Go
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()
|
|
}
|