chore: cleanup sudoku internal code

This commit is contained in:
wwqgtxx 2025-12-05 08:53:18 +08:00
parent 25041b599e
commit c33d9ad857
5 changed files with 72 additions and 96 deletions

View File

@ -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())

View File

@ -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)
}
}

View File

@ -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

View File

@ -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,

View File

@ -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
}