mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2025-12-19 08:20:05 +08:00
chore: cleanup sudoku internal code
This commit is contained in:
parent
25041b599e
commit
c33d9ad857
@ -6,23 +6,16 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"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"
|
N "github.com/metacubex/mihomo/common/net"
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
"github.com/metacubex/mihomo/log"
|
|
||||||
"github.com/metacubex/mihomo/transport/sudoku"
|
"github.com/metacubex/mihomo/transport/sudoku"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Sudoku struct {
|
type Sudoku struct {
|
||||||
*Base
|
*Base
|
||||||
option *SudokuOption
|
option *SudokuOption
|
||||||
table *sudokuobfs.Table
|
baseConf sudoku.ProtocolConfig
|
||||||
baseConf apis.ProtocolConfig
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type SudokuOption struct {
|
type SudokuOption struct {
|
||||||
@ -60,11 +53,21 @@ func (s *Sudoku) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Con
|
|||||||
defer done(&err)
|
defer done(&err)
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err = s.streamConn(c, cfg)
|
c, err = sudoku.ClientHandshake(c, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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
|
return NewConn(c, s), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +96,7 @@ func (s *Sudoku) ListenPacketContext(ctx context.Context, metadata *C.Metadata)
|
|||||||
defer done(&err)
|
defer done(&err)
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err = s.handshakeConn(c, cfg)
|
c, err = sudoku.ClientHandshake(c, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -118,7 +121,7 @@ func (s *Sudoku) ProxyInfo() C.ProxyInfo {
|
|||||||
return info
|
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() {
|
if metadata == nil || metadata.DstPort == 0 || !metadata.Valid() {
|
||||||
return nil, fmt.Errorf("invalid metadata for sudoku outbound")
|
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
|
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) {
|
func NewSudoku(option SudokuOption) (*Sudoku, error) {
|
||||||
if option.Server == "" {
|
if option.Server == "" {
|
||||||
return nil, fmt.Errorf("server is required")
|
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")
|
return nil, fmt.Errorf("table-type must be prefer_ascii or prefer_entropy")
|
||||||
}
|
}
|
||||||
|
|
||||||
seed := option.Key
|
defaultConf := sudoku.DefaultConfig()
|
||||||
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()
|
|
||||||
paddingMin := defaultConf.PaddingMin
|
paddingMin := defaultConf.PaddingMin
|
||||||
paddingMax := defaultConf.PaddingMax
|
paddingMax := defaultConf.PaddingMax
|
||||||
if option.PaddingMin != nil {
|
if option.PaddingMin != nil {
|
||||||
@ -203,11 +174,11 @@ func NewSudoku(option SudokuOption) (*Sudoku, error) {
|
|||||||
enablePureDownlink = *option.EnablePureDownlink
|
enablePureDownlink = *option.EnablePureDownlink
|
||||||
}
|
}
|
||||||
|
|
||||||
baseConf := apis.ProtocolConfig{
|
baseConf := sudoku.ProtocolConfig{
|
||||||
ServerAddress: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
|
ServerAddress: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
|
||||||
Key: option.Key,
|
Key: option.Key,
|
||||||
AEADMethod: defaultConf.AEADMethod,
|
AEADMethod: defaultConf.AEADMethod,
|
||||||
Table: table,
|
Table: sudoku.NewTable(sudoku.ClientAEADSeed(option.Key), tableType),
|
||||||
PaddingMin: paddingMin,
|
PaddingMin: paddingMin,
|
||||||
PaddingMax: paddingMax,
|
PaddingMax: paddingMax,
|
||||||
EnablePureDownlink: enablePureDownlink,
|
EnablePureDownlink: enablePureDownlink,
|
||||||
@ -232,7 +203,6 @@ func NewSudoku(option SudokuOption) (*Sudoku, error) {
|
|||||||
prefer: option.IPVersion,
|
prefer: option.IPVersion,
|
||||||
},
|
},
|
||||||
option: &option,
|
option: &option,
|
||||||
table: table,
|
|
||||||
baseConf: baseConf,
|
baseConf: baseConf,
|
||||||
}
|
}
|
||||||
outbound.dialer = option.NewDialer(outbound.DialOptions())
|
outbound.dialer = option.NewDialer(outbound.DialOptions())
|
||||||
|
|||||||
@ -5,8 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/metacubex/mihomo/component/ech"
|
"github.com/metacubex/mihomo/component/ech"
|
||||||
|
"github.com/metacubex/mihomo/transport/sudoku"
|
||||||
"github.com/metacubex/mihomo/transport/vless/encryption"
|
"github.com/metacubex/mihomo/transport/vless/encryption"
|
||||||
"github.com/saba-futai/sudoku/pkg/crypto"
|
|
||||||
|
|
||||||
"github.com/gofrs/uuid/v5"
|
"github.com/gofrs/uuid/v5"
|
||||||
)
|
)
|
||||||
@ -71,18 +71,12 @@ func Main(args []string) {
|
|||||||
fmt.Println("Password: " + passwordBase64)
|
fmt.Println("Password: " + passwordBase64)
|
||||||
fmt.Println("Hash32: " + hash32Base64)
|
fmt.Println("Hash32: " + hash32Base64)
|
||||||
case "sudoku-keypair":
|
case "sudoku-keypair":
|
||||||
// Generate Master Key
|
privateKey, publicKey, err := sudoku.GenKeyPair()
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
// Output: Available Private Key for client, Master Public Key for server
|
// Output: Available Private Key for client, Master Public Key for server
|
||||||
fmt.Println("PrivateKey: " + availablePrivateKey)
|
fmt.Println("PrivateKey: " + privateKey)
|
||||||
fmt.Println("PublicKey: " + crypto.EncodePoint(pair.Public))
|
fmt.Println("PublicKey: " + publicKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,11 +5,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/saba-futai/sudoku/apis"
|
|
||||||
|
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
LC "github.com/metacubex/mihomo/listener/config"
|
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"
|
"github.com/metacubex/mihomo/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -31,7 +29,7 @@ func (o SudokuOption) Equal(config C.InboundConfig) bool {
|
|||||||
type Sudoku struct {
|
type Sudoku struct {
|
||||||
*Base
|
*Base
|
||||||
config *SudokuOption
|
config *SudokuOption
|
||||||
listeners []*sudokuListener.Listener
|
listeners []*sudoku.Listener
|
||||||
serverConf LC.SudokuServer
|
serverConf LC.SudokuServer
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,24 +42,16 @@ func NewSudoku(options *SudokuOption) (*Sudoku, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConf := apis.DefaultConfig()
|
|
||||||
|
|
||||||
serverConf := LC.SudokuServer{
|
serverConf := LC.SudokuServer{
|
||||||
Enable: true,
|
Enable: true,
|
||||||
Listen: base.RawAddress(),
|
Listen: base.RawAddress(),
|
||||||
Key: options.Key,
|
Key: options.Key,
|
||||||
AEADMethod: options.AEADMethod,
|
AEADMethod: options.AEADMethod,
|
||||||
PaddingMin: options.PaddingMin,
|
PaddingMin: options.PaddingMin,
|
||||||
PaddingMax: options.PaddingMax,
|
PaddingMax: options.PaddingMax,
|
||||||
TableType: options.TableType,
|
TableType: options.TableType,
|
||||||
EnablePureDownlink: options.EnablePureDownlink,
|
HandshakeTimeoutSecond: options.HandshakeTimeoutSecond,
|
||||||
}
|
EnablePureDownlink: options.EnablePureDownlink,
|
||||||
if options.HandshakeTimeoutSecond != nil {
|
|
||||||
serverConf.HandshakeTimeoutSecond = options.HandshakeTimeoutSecond
|
|
||||||
} else {
|
|
||||||
// Use Sudoku default if not specified.
|
|
||||||
v := defaultConf.HandshakeTimeoutSeconds
|
|
||||||
serverConf.HandshakeTimeoutSecond = &v
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Sudoku{
|
return &Sudoku{
|
||||||
@ -96,7 +86,7 @@ func (s *Sudoku) Listen(tunnel C.Tunnel) error {
|
|||||||
conf := s.serverConf
|
conf := s.serverConf
|
||||||
conf.Listen = addr
|
conf.Listen = addr
|
||||||
|
|
||||||
l, err := sudokuListener.New(conf, tunnel, s.Additions()...)
|
l, err := sudoku.New(conf, tunnel, s.Additions()...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
continue
|
continue
|
||||||
|
|||||||
@ -6,9 +6,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/saba-futai/sudoku/apis"
|
|
||||||
sudokuobfs "github.com/saba-futai/sudoku/pkg/obfs/sudoku"
|
|
||||||
|
|
||||||
"github.com/metacubex/mihomo/adapter/inbound"
|
"github.com/metacubex/mihomo/adapter/inbound"
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
LC "github.com/metacubex/mihomo/listener/config"
|
LC "github.com/metacubex/mihomo/listener/config"
|
||||||
@ -21,7 +18,7 @@ type Listener struct {
|
|||||||
listener net.Listener
|
listener net.Listener
|
||||||
addr string
|
addr string
|
||||||
closed bool
|
closed bool
|
||||||
protoConf apis.ProtocolConfig
|
protoConf sudoku.ProtocolConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// RawAddress implements C.Listener
|
// RawAddress implements C.Listener
|
||||||
@ -135,9 +132,7 @@ func New(config LC.SudokuServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
|||||||
tableType = "prefer_ascii"
|
tableType = "prefer_ascii"
|
||||||
}
|
}
|
||||||
|
|
||||||
table := sudokuobfs.NewTable(config.Key, tableType)
|
defaultConf := sudoku.DefaultConfig()
|
||||||
|
|
||||||
defaultConf := apis.DefaultConfig()
|
|
||||||
paddingMin := defaultConf.PaddingMin
|
paddingMin := defaultConf.PaddingMin
|
||||||
paddingMax := defaultConf.PaddingMax
|
paddingMax := defaultConf.PaddingMax
|
||||||
if config.PaddingMin != nil {
|
if config.PaddingMin != nil {
|
||||||
@ -162,10 +157,10 @@ func New(config LC.SudokuServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
|||||||
handshakeTimeout = *config.HandshakeTimeoutSecond
|
handshakeTimeout = *config.HandshakeTimeoutSecond
|
||||||
}
|
}
|
||||||
|
|
||||||
protoConf := apis.ProtocolConfig{
|
protoConf := sudoku.ProtocolConfig{
|
||||||
Key: config.Key,
|
Key: config.Key,
|
||||||
AEADMethod: defaultConf.AEADMethod,
|
AEADMethod: defaultConf.AEADMethod,
|
||||||
Table: table,
|
Table: sudoku.NewTable(config.Key, tableType),
|
||||||
PaddingMin: paddingMin,
|
PaddingMin: paddingMin,
|
||||||
PaddingMax: paddingMax,
|
PaddingMax: paddingMax,
|
||||||
EnablePureDownlink: enablePureDownlink,
|
EnablePureDownlink: enablePureDownlink,
|
||||||
|
|||||||
@ -17,6 +17,10 @@ import (
|
|||||||
"github.com/metacubex/mihomo/log"
|
"github.com/metacubex/mihomo/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ProtocolConfig = apis.ProtocolConfig
|
||||||
|
|
||||||
|
func DefaultConfig() *ProtocolConfig { return apis.DefaultConfig() }
|
||||||
|
|
||||||
type SessionType int
|
type SessionType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -106,13 +110,6 @@ func downlinkMode(cfg *apis.ProtocolConfig) byte {
|
|||||||
return downlinkModePacked
|
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 {
|
func buildClientObfsConn(raw net.Conn, cfg *apis.ProtocolConfig) net.Conn {
|
||||||
base := sudoku.NewConn(raw, cfg.Table, cfg.PaddingMin, cfg.PaddingMax, false)
|
base := sudoku.NewConn(raw, cfg.Table, cfg.PaddingMin, cfg.PaddingMax, false)
|
||||||
if cfg.EnablePureDownlink {
|
if cfg.EnablePureDownlink {
|
||||||
@ -148,6 +145,20 @@ func buildHandshakePayload(key string) [16]byte {
|
|||||||
return payload
|
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).
|
// ClientHandshake performs the client-side Sudoku handshake (without sending target address).
|
||||||
func ClientHandshake(rawConn net.Conn, cfg *apis.ProtocolConfig) (net.Conn, error) {
|
func ClientHandshake(rawConn net.Conn, cfg *apis.ProtocolConfig) (net.Conn, error) {
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
@ -164,7 +175,7 @@ func ClientHandshake(rawConn net.Conn, cfg *apis.ProtocolConfig) (net.Conn, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
obfsConn := buildClientObfsConn(rawConn, cfg)
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("setup crypto failed: %w", err)
|
return nil, fmt.Errorf("setup crypto failed: %w", err)
|
||||||
}
|
}
|
||||||
@ -275,3 +286,19 @@ func ServerHandshake(rawConn net.Conn, cfg *apis.ProtocolConfig) (*ServerSession
|
|||||||
Target: target,
|
Target: target,
|
||||||
}, nil
|
}, 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