From c33d9ad857fa8941644ba53c994e57eb2c6cd627 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 5 Dec 2025 08:53:18 +0800 Subject: [PATCH] chore: cleanup sudoku internal code --- adapter/outbound/sudoku.go | 64 ++++++++++------------------------- component/generator/cmd.go | 14 +++----- listener/inbound/sudoku.go | 34 +++++++------------ listener/sudoku/server.go | 13 +++---- transport/sudoku/handshake.go | 43 ++++++++++++++++++----- 5 files changed, 72 insertions(+), 96 deletions(-) diff --git a/adapter/outbound/sudoku.go b/adapter/outbound/sudoku.go index ef28f3ac..128dbc98 100644 --- a/adapter/outbound/sudoku.go +++ b/adapter/outbound/sudoku.go @@ -6,23 +6,16 @@ import ( "net" "strconv" "strings" - "time" - - "github.com/saba-futai/sudoku/apis" - "github.com/saba-futai/sudoku/pkg/crypto" - sudokuobfs "github.com/saba-futai/sudoku/pkg/obfs/sudoku" N "github.com/metacubex/mihomo/common/net" C "github.com/metacubex/mihomo/constant" - "github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/transport/sudoku" ) type Sudoku struct { *Base option *SudokuOption - table *sudokuobfs.Table - baseConf apis.ProtocolConfig + baseConf sudoku.ProtocolConfig } type SudokuOption struct { @@ -60,11 +53,21 @@ func (s *Sudoku) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Con defer done(&err) } - c, err = s.streamConn(c, cfg) + c, err = sudoku.ClientHandshake(c, cfg) if err != nil { return nil, err } + addrBuf, err := sudoku.EncodeAddress(cfg.TargetAddress) + if err != nil { + return nil, fmt.Errorf("encode target address failed: %w", err) + } + + if _, err = c.Write(addrBuf); err != nil { + _ = c.Close() + return nil, fmt.Errorf("send target address failed: %w", err) + } + return NewConn(c, s), nil } @@ -93,7 +96,7 @@ func (s *Sudoku) ListenPacketContext(ctx context.Context, metadata *C.Metadata) defer done(&err) } - c, err = s.handshakeConn(c, cfg) + c, err = sudoku.ClientHandshake(c, cfg) if err != nil { return nil, err } @@ -118,7 +121,7 @@ func (s *Sudoku) ProxyInfo() C.ProxyInfo { return info } -func (s *Sudoku) buildConfig(metadata *C.Metadata) (*apis.ProtocolConfig, error) { +func (s *Sudoku) buildConfig(metadata *C.Metadata) (*sudoku.ProtocolConfig, error) { if metadata == nil || metadata.DstPort == 0 || !metadata.Valid() { return nil, fmt.Errorf("invalid metadata for sudoku outbound") } @@ -132,29 +135,6 @@ func (s *Sudoku) buildConfig(metadata *C.Metadata) (*apis.ProtocolConfig, error) return &cfg, nil } -func (s *Sudoku) handshakeConn(rawConn net.Conn, cfg *apis.ProtocolConfig) (_ net.Conn, err error) { - return sudoku.ClientHandshake(rawConn, cfg) -} - -func (s *Sudoku) streamConn(rawConn net.Conn, cfg *apis.ProtocolConfig) (_ net.Conn, err error) { - cConn, err := s.handshakeConn(rawConn, cfg) - if err != nil { - return nil, err - } - - addrBuf, err := sudoku.EncodeAddress(cfg.TargetAddress) - if err != nil { - return nil, fmt.Errorf("encode target address failed: %w", err) - } - - if _, err = cConn.Write(addrBuf); err != nil { - cConn.Close() - return nil, fmt.Errorf("send target address failed: %w", err) - } - - return cConn, nil -} - func NewSudoku(option SudokuOption) (*Sudoku, error) { if option.Server == "" { return nil, fmt.Errorf("server is required") @@ -174,16 +154,7 @@ func NewSudoku(option SudokuOption) (*Sudoku, error) { return nil, fmt.Errorf("table-type must be prefer_ascii or prefer_entropy") } - seed := option.Key - if recoveredFromKey, err := crypto.RecoverPublicKey(option.Key); err == nil { - seed = crypto.EncodePoint(recoveredFromKey) - } - - start := time.Now() - table := sudokuobfs.NewTable(seed, tableType) - log.Infoln("[Sudoku] Tables initialized (%s) in %v", tableType, time.Since(start)) - - defaultConf := apis.DefaultConfig() + defaultConf := sudoku.DefaultConfig() paddingMin := defaultConf.PaddingMin paddingMax := defaultConf.PaddingMax if option.PaddingMin != nil { @@ -203,11 +174,11 @@ func NewSudoku(option SudokuOption) (*Sudoku, error) { enablePureDownlink = *option.EnablePureDownlink } - baseConf := apis.ProtocolConfig{ + baseConf := sudoku.ProtocolConfig{ ServerAddress: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)), Key: option.Key, AEADMethod: defaultConf.AEADMethod, - Table: table, + Table: sudoku.NewTable(sudoku.ClientAEADSeed(option.Key), tableType), PaddingMin: paddingMin, PaddingMax: paddingMax, EnablePureDownlink: enablePureDownlink, @@ -232,7 +203,6 @@ func NewSudoku(option SudokuOption) (*Sudoku, error) { prefer: option.IPVersion, }, option: &option, - table: table, baseConf: baseConf, } outbound.dialer = option.NewDialer(outbound.DialOptions()) diff --git a/component/generator/cmd.go b/component/generator/cmd.go index 39064c71..1feac0f1 100644 --- a/component/generator/cmd.go +++ b/component/generator/cmd.go @@ -5,8 +5,8 @@ import ( "fmt" "github.com/metacubex/mihomo/component/ech" + "github.com/metacubex/mihomo/transport/sudoku" "github.com/metacubex/mihomo/transport/vless/encryption" - "github.com/saba-futai/sudoku/pkg/crypto" "github.com/gofrs/uuid/v5" ) @@ -71,18 +71,12 @@ func Main(args []string) { fmt.Println("Password: " + passwordBase64) fmt.Println("Hash32: " + hash32Base64) case "sudoku-keypair": - // Generate Master Key - pair, err := crypto.GenerateMasterKey() - if err != nil { - panic(err) - } - // Split the master private key to get Available Private Key - availablePrivateKey, err := crypto.SplitPrivateKey(pair.Private) + privateKey, publicKey, err := sudoku.GenKeyPair() if err != nil { panic(err) } // Output: Available Private Key for client, Master Public Key for server - fmt.Println("PrivateKey: " + availablePrivateKey) - fmt.Println("PublicKey: " + crypto.EncodePoint(pair.Public)) + fmt.Println("PrivateKey: " + privateKey) + fmt.Println("PublicKey: " + publicKey) } } diff --git a/listener/inbound/sudoku.go b/listener/inbound/sudoku.go index dd7cce5b..e7cde308 100644 --- a/listener/inbound/sudoku.go +++ b/listener/inbound/sudoku.go @@ -5,11 +5,9 @@ import ( "fmt" "strings" - "github.com/saba-futai/sudoku/apis" - C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" - sudokuListener "github.com/metacubex/mihomo/listener/sudoku" + "github.com/metacubex/mihomo/listener/sudoku" "github.com/metacubex/mihomo/log" ) @@ -31,7 +29,7 @@ func (o SudokuOption) Equal(config C.InboundConfig) bool { type Sudoku struct { *Base config *SudokuOption - listeners []*sudokuListener.Listener + listeners []*sudoku.Listener serverConf LC.SudokuServer } @@ -44,24 +42,16 @@ func NewSudoku(options *SudokuOption) (*Sudoku, error) { return nil, err } - defaultConf := apis.DefaultConfig() - serverConf := LC.SudokuServer{ - Enable: true, - Listen: base.RawAddress(), - Key: options.Key, - AEADMethod: options.AEADMethod, - PaddingMin: options.PaddingMin, - PaddingMax: options.PaddingMax, - TableType: options.TableType, - EnablePureDownlink: options.EnablePureDownlink, - } - if options.HandshakeTimeoutSecond != nil { - serverConf.HandshakeTimeoutSecond = options.HandshakeTimeoutSecond - } else { - // Use Sudoku default if not specified. - v := defaultConf.HandshakeTimeoutSeconds - serverConf.HandshakeTimeoutSecond = &v + Enable: true, + Listen: base.RawAddress(), + Key: options.Key, + AEADMethod: options.AEADMethod, + PaddingMin: options.PaddingMin, + PaddingMax: options.PaddingMax, + TableType: options.TableType, + HandshakeTimeoutSecond: options.HandshakeTimeoutSecond, + EnablePureDownlink: options.EnablePureDownlink, } return &Sudoku{ @@ -96,7 +86,7 @@ func (s *Sudoku) Listen(tunnel C.Tunnel) error { conf := s.serverConf conf.Listen = addr - l, err := sudokuListener.New(conf, tunnel, s.Additions()...) + l, err := sudoku.New(conf, tunnel, s.Additions()...) if err != nil { errs = append(errs, err) continue diff --git a/listener/sudoku/server.go b/listener/sudoku/server.go index d8e7337c..a1aa9fd2 100644 --- a/listener/sudoku/server.go +++ b/listener/sudoku/server.go @@ -6,9 +6,6 @@ import ( "net" "strings" - "github.com/saba-futai/sudoku/apis" - sudokuobfs "github.com/saba-futai/sudoku/pkg/obfs/sudoku" - "github.com/metacubex/mihomo/adapter/inbound" C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" @@ -21,7 +18,7 @@ type Listener struct { listener net.Listener addr string closed bool - protoConf apis.ProtocolConfig + protoConf sudoku.ProtocolConfig } // RawAddress implements C.Listener @@ -135,9 +132,7 @@ func New(config LC.SudokuServer, tunnel C.Tunnel, additions ...inbound.Addition) tableType = "prefer_ascii" } - table := sudokuobfs.NewTable(config.Key, tableType) - - defaultConf := apis.DefaultConfig() + defaultConf := sudoku.DefaultConfig() paddingMin := defaultConf.PaddingMin paddingMax := defaultConf.PaddingMax if config.PaddingMin != nil { @@ -162,10 +157,10 @@ func New(config LC.SudokuServer, tunnel C.Tunnel, additions ...inbound.Addition) handshakeTimeout = *config.HandshakeTimeoutSecond } - protoConf := apis.ProtocolConfig{ + protoConf := sudoku.ProtocolConfig{ Key: config.Key, AEADMethod: defaultConf.AEADMethod, - Table: table, + Table: sudoku.NewTable(config.Key, tableType), PaddingMin: paddingMin, PaddingMax: paddingMax, EnablePureDownlink: enablePureDownlink, diff --git a/transport/sudoku/handshake.go b/transport/sudoku/handshake.go index 05abdf66..a4f85f29 100644 --- a/transport/sudoku/handshake.go +++ b/transport/sudoku/handshake.go @@ -17,6 +17,10 @@ import ( "github.com/metacubex/mihomo/log" ) +type ProtocolConfig = apis.ProtocolConfig + +func DefaultConfig() *ProtocolConfig { return apis.DefaultConfig() } + type SessionType int const ( @@ -106,13 +110,6 @@ func downlinkMode(cfg *apis.ProtocolConfig) byte { return downlinkModePacked } -func clientAEADSeed(key string) string { - if recovered, err := crypto.RecoverPublicKey(key); err == nil { - return crypto.EncodePoint(recovered) - } - return key -} - func buildClientObfsConn(raw net.Conn, cfg *apis.ProtocolConfig) net.Conn { base := sudoku.NewConn(raw, cfg.Table, cfg.PaddingMin, cfg.PaddingMax, false) if cfg.EnablePureDownlink { @@ -148,6 +145,20 @@ func buildHandshakePayload(key string) [16]byte { return payload } +func NewTable(key string, tableType string) *sudoku.Table { + start := time.Now() + table := sudoku.NewTable(key, tableType) + log.Infoln("[Sudoku] Tables initialized (%s) in %v", tableType, time.Since(start)) + return table +} + +func ClientAEADSeed(key string) string { + if recovered, err := crypto.RecoverPublicKey(key); err == nil { + return crypto.EncodePoint(recovered) + } + return key +} + // ClientHandshake performs the client-side Sudoku handshake (without sending target address). func ClientHandshake(rawConn net.Conn, cfg *apis.ProtocolConfig) (net.Conn, error) { if cfg == nil { @@ -164,7 +175,7 @@ func ClientHandshake(rawConn net.Conn, cfg *apis.ProtocolConfig) (net.Conn, erro } obfsConn := buildClientObfsConn(rawConn, cfg) - cConn, err := crypto.NewAEADConn(obfsConn, clientAEADSeed(cfg.Key), cfg.AEADMethod) + cConn, err := crypto.NewAEADConn(obfsConn, ClientAEADSeed(cfg.Key), cfg.AEADMethod) if err != nil { return nil, fmt.Errorf("setup crypto failed: %w", err) } @@ -275,3 +286,19 @@ func ServerHandshake(rawConn net.Conn, cfg *apis.ProtocolConfig) (*ServerSession Target: target, }, nil } + +func GenKeyPair() (privateKey, publicKey string, err error) { + // Generate Master Key + pair, err := crypto.GenerateMasterKey() + if err != nil { + return + } + // Split the master private key to get Available Private Key + availablePrivateKey, err := crypto.SplitPrivateKey(pair.Private) + if err != nil { + return + } + privateKey = availablePrivateKey // Available Private Key for client + publicKey = crypto.EncodePoint(pair.Public) // Master Public Key for server + return +}