mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2025-12-19 00:10:06 +08:00
chore: cleanup sudoku internal code
This commit is contained in:
parent
25041b599e
commit
c33d9ad857
@ -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())
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user