mihomo/transport/anytls/client.go
wwqgtxx f90d0b954c
Some checks are pending
Test / test (1.20, macos-13) (push) Waiting to run
Test / test (1.20, macos-latest) (push) Waiting to run
Test / test (1.20, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.20, ubuntu-latest) (push) Waiting to run
Test / test (1.20, windows-latest) (push) Waiting to run
Test / test (1.21, macos-13) (push) Waiting to run
Test / test (1.21, macos-latest) (push) Waiting to run
Test / test (1.21, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.21, ubuntu-latest) (push) Waiting to run
Test / test (1.21, windows-latest) (push) Waiting to run
Test / test (1.22, macos-13) (push) Waiting to run
Test / test (1.22, macos-latest) (push) Waiting to run
Test / test (1.22, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.22, ubuntu-latest) (push) Waiting to run
Test / test (1.22, windows-latest) (push) Waiting to run
Test / test (1.23, macos-13) (push) Waiting to run
Test / test (1.23, macos-latest) (push) Waiting to run
Test / test (1.23, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.23, ubuntu-latest) (push) Waiting to run
Test / test (1.23, windows-latest) (push) Waiting to run
Test / test (1.24, macos-13) (push) Waiting to run
Test / test (1.24, macos-latest) (push) Waiting to run
Test / test (1.24, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.24, ubuntu-latest) (push) Waiting to run
Test / test (1.24, windows-latest) (push) Waiting to run
Test / test (1.25, macos-13) (push) Waiting to run
Test / test (1.25, macos-latest) (push) Waiting to run
Test / test (1.25, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.25, ubuntu-latest) (push) Waiting to run
Test / test (1.25, windows-latest) (push) Waiting to run
Trigger CMFA Update / trigger-CMFA-update (push) Waiting to run
chore: using atomic.Pointer in anytls
2025-08-14 00:51:55 +08:00

102 lines
2.5 KiB
Go

package anytls
import (
"context"
"crypto/sha256"
"encoding/binary"
"net"
"sync/atomic"
"time"
"github.com/metacubex/mihomo/common/buf"
"github.com/metacubex/mihomo/transport/anytls/padding"
"github.com/metacubex/mihomo/transport/anytls/session"
"github.com/metacubex/mihomo/transport/vmess"
M "github.com/metacubex/sing/common/metadata"
N "github.com/metacubex/sing/common/network"
)
type ClientConfig struct {
Password string
IdleSessionCheckInterval time.Duration
IdleSessionTimeout time.Duration
MinIdleSession int
Server M.Socksaddr
Dialer N.Dialer
TLSConfig *vmess.TLSConfig
}
type Client struct {
passwordSha256 []byte
tlsConfig *vmess.TLSConfig
dialer N.Dialer
server M.Socksaddr
sessionClient *session.Client
padding atomic.Pointer[padding.PaddingFactory]
}
func NewClient(ctx context.Context, config ClientConfig) *Client {
pw := sha256.Sum256([]byte(config.Password))
c := &Client{
passwordSha256: pw[:],
tlsConfig: config.TLSConfig,
dialer: config.Dialer,
server: config.Server,
}
// Initialize the padding state of this client
padding.UpdatePaddingScheme(padding.DefaultPaddingScheme, &c.padding)
c.sessionClient = session.NewClient(ctx, c.CreateOutboundTLSConnection, &c.padding, config.IdleSessionCheckInterval, config.IdleSessionTimeout, config.MinIdleSession)
return c
}
func (c *Client) CreateProxy(ctx context.Context, destination M.Socksaddr) (net.Conn, error) {
conn, err := c.sessionClient.CreateStream(ctx)
if err != nil {
return nil, err
}
err = M.SocksaddrSerializer.WriteAddrPort(conn, destination)
if err != nil {
conn.Close()
return nil, err
}
return conn, nil
}
func (c *Client) CreateOutboundTLSConnection(ctx context.Context) (net.Conn, error) {
conn, err := c.dialer.DialContext(ctx, N.NetworkTCP, c.server)
if err != nil {
return nil, err
}
b := buf.NewPacket()
defer b.Release()
b.Write(c.passwordSha256)
var paddingLen int
if pad := c.padding.Load().GenerateRecordPayloadSizes(0); len(pad) > 0 {
paddingLen = pad[0]
}
binary.BigEndian.PutUint16(b.Extend(2), uint16(paddingLen))
if paddingLen > 0 {
b.WriteZeroN(paddingLen)
}
tlsConn, err := vmess.StreamTLSConn(ctx, conn, c.tlsConfig)
if err != nil {
conn.Close()
return nil, err
}
_, err = b.WriteTo(tlsConn)
if err != nil {
tlsConn.Close()
return nil, err
}
return tlsConn, nil
}
func (h *Client) Close() error {
return h.sessionClient.Close()
}