mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2026-02-26 16:57:08 +00:00
feat: support kcptun plugin for ss client/server
This commit is contained in:
8
listener/config/kcptun.go
Normal file
8
listener/config/kcptun.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package config
|
||||
|
||||
import "github.com/metacubex/mihomo/transport/kcptun"
|
||||
|
||||
type KcpTun struct {
|
||||
Enable bool `json:"enable"`
|
||||
kcptun.Config `json:",inline"`
|
||||
}
|
||||
@@ -14,6 +14,7 @@ type ShadowsocksServer struct {
|
||||
Udp bool
|
||||
MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"`
|
||||
ShadowTLS ShadowTLS `yaml:"shadow-tls" json:"shadow-tls,omitempty"`
|
||||
KcpTun KcpTun `yaml:"kcp-tun" json:"kcp-tun,omitempty"`
|
||||
}
|
||||
|
||||
func (t ShadowsocksServer) String() string {
|
||||
|
||||
64
listener/inbound/kcptun.go
Normal file
64
listener/inbound/kcptun.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package inbound
|
||||
|
||||
import (
|
||||
LC "github.com/metacubex/mihomo/listener/config"
|
||||
"github.com/metacubex/mihomo/transport/kcptun"
|
||||
)
|
||||
|
||||
type KcpTun struct {
|
||||
Enable bool `inbound:"enable"`
|
||||
Key string `inbound:"key,omitempty"`
|
||||
Crypt string `inbound:"crypt,omitempty"`
|
||||
Mode string `inbound:"mode,omitempty"`
|
||||
Conn int `inbound:"conn,omitempty"`
|
||||
AutoExpire int `inbound:"autoexpire,omitempty"`
|
||||
ScavengeTTL int `inbound:"scavengettl,omitempty"`
|
||||
MTU int `inbound:"mtu,omitempty"`
|
||||
SndWnd int `inbound:"sndwnd,omitempty"`
|
||||
RcvWnd int `inbound:"rcvwnd,omitempty"`
|
||||
DataShard int `inbound:"datashard,omitempty"`
|
||||
ParityShard int `inbound:"parityshard,omitempty"`
|
||||
DSCP int `inbound:"dscp,omitempty"`
|
||||
NoComp bool `inbound:"nocomp,omitempty"`
|
||||
AckNodelay bool `inbound:"acknodelay,omitempty"`
|
||||
NoDelay int `inbound:"nodelay,omitempty"`
|
||||
Interval int `inbound:"interval,omitempty"`
|
||||
Resend int `inbound:"resend,omitempty"`
|
||||
NoCongestion int `inbound:"nc,omitempty"`
|
||||
SockBuf int `inbound:"sockbuf,omitempty"`
|
||||
SmuxVer int `inbound:"smuxver,omitempty"`
|
||||
SmuxBuf int `inbound:"smuxbuf,omitempty"`
|
||||
StreamBuf int `inbound:"streambuf,omitempty"`
|
||||
KeepAlive int `inbound:"keepalive,omitempty"`
|
||||
}
|
||||
|
||||
func (c KcpTun) Build() LC.KcpTun {
|
||||
return LC.KcpTun{
|
||||
Enable: c.Enable,
|
||||
Config: kcptun.Config{
|
||||
Key: c.Key,
|
||||
Crypt: c.Crypt,
|
||||
Mode: c.Mode,
|
||||
Conn: c.Conn,
|
||||
AutoExpire: c.AutoExpire,
|
||||
ScavengeTTL: c.ScavengeTTL,
|
||||
MTU: c.MTU,
|
||||
SndWnd: c.SndWnd,
|
||||
RcvWnd: c.RcvWnd,
|
||||
DataShard: c.DataShard,
|
||||
ParityShard: c.ParityShard,
|
||||
DSCP: c.DSCP,
|
||||
NoComp: c.NoComp,
|
||||
AckNodelay: c.AckNodelay,
|
||||
NoDelay: c.NoDelay,
|
||||
Interval: c.Interval,
|
||||
Resend: c.Resend,
|
||||
NoCongestion: c.NoCongestion,
|
||||
SockBuf: c.SockBuf,
|
||||
SmuxVer: c.SmuxVer,
|
||||
SmuxBuf: c.SmuxBuf,
|
||||
StreamBuf: c.StreamBuf,
|
||||
KeepAlive: c.KeepAlive,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ type ShadowSocksOption struct {
|
||||
UDP bool `inbound:"udp,omitempty"`
|
||||
MuxOption MuxOption `inbound:"mux-option,omitempty"`
|
||||
ShadowTLS ShadowTLS `inbound:"shadow-tls,omitempty"`
|
||||
KcpTun KcpTun `inbound:"kcp-tun,omitempty"`
|
||||
}
|
||||
|
||||
func (o ShadowSocksOption) Equal(config C.InboundConfig) bool {
|
||||
@@ -45,6 +46,7 @@ func NewShadowSocks(options *ShadowSocksOption) (*ShadowSocks, error) {
|
||||
Udp: options.UDP,
|
||||
MuxOption: options.MuxOption.Build(),
|
||||
ShadowTLS: options.ShadowTLS.Build(),
|
||||
KcpTun: options.KcpTun.Build(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/metacubex/mihomo/adapter/outbound"
|
||||
"github.com/metacubex/mihomo/listener/inbound"
|
||||
"github.com/metacubex/mihomo/transport/kcptun"
|
||||
shadowtls "github.com/metacubex/mihomo/transport/sing-shadowtls"
|
||||
|
||||
shadowsocks "github.com/metacubex/sing-shadowsocks"
|
||||
@@ -21,7 +22,7 @@ import (
|
||||
|
||||
var noneList = []string{shadowsocks.MethodNone}
|
||||
var shadowsocksCipherLists = [][]string{noneList, shadowaead.List, shadowaead_2022.List, shadowstream.List}
|
||||
var shadowsocksCipherShortLists = [][]string{noneList, shadowaead.List[:5]} // for test shadowTLS
|
||||
var shadowsocksCipherShortLists = [][]string{noneList, shadowaead.List[:5]} // for test shadowTLS and kcptun
|
||||
var shadowsocksPassword32 string
|
||||
var shadowsocksPassword16 string
|
||||
|
||||
@@ -32,11 +33,11 @@ func init() {
|
||||
shadowsocksPassword16 = base64.StdEncoding.EncodeToString(passwordBytes[:16])
|
||||
}
|
||||
|
||||
func testInboundShadowSocks(t *testing.T, inboundOptions inbound.ShadowSocksOption, outboundOptions outbound.ShadowSocksOption, cipherLists [][]string) {
|
||||
func testInboundShadowSocks(t *testing.T, inboundOptions inbound.ShadowSocksOption, outboundOptions outbound.ShadowSocksOption, cipherLists [][]string, enableSingMux bool) {
|
||||
t.Parallel()
|
||||
for _, cipherList := range cipherLists {
|
||||
for i, cipher := range cipherList {
|
||||
enableSingMux := i == 0
|
||||
enableSingMux := enableSingMux && i == 0
|
||||
cipher := cipher
|
||||
t.Run(cipher, func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := inboundOptions, outboundOptions // don't modify outside options value
|
||||
@@ -100,19 +101,19 @@ func testInboundShadowSocks0(t *testing.T, inboundOptions inbound.ShadowSocksOpt
|
||||
func TestInboundShadowSocks_Basic(t *testing.T) {
|
||||
inboundOptions := inbound.ShadowSocksOption{}
|
||||
outboundOptions := outbound.ShadowSocksOption{}
|
||||
testInboundShadowSocks(t, inboundOptions, outboundOptions, shadowsocksCipherLists)
|
||||
testInboundShadowSocks(t, inboundOptions, outboundOptions, shadowsocksCipherLists, true)
|
||||
}
|
||||
|
||||
func testInboundShadowSocksShadowTls(t *testing.T, inboundOptions inbound.ShadowSocksOption, outboundOptions outbound.ShadowSocksOption) {
|
||||
t.Parallel()
|
||||
t.Run("Conn", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := inboundOptions, outboundOptions // don't modify outside options value
|
||||
testInboundShadowSocks(t, inboundOptions, outboundOptions, shadowsocksCipherShortLists)
|
||||
testInboundShadowSocks(t, inboundOptions, outboundOptions, shadowsocksCipherShortLists, true)
|
||||
})
|
||||
t.Run("UConn", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := inboundOptions, outboundOptions // don't modify outside options value
|
||||
outboundOptions.ClientFingerprint = "chrome"
|
||||
testInboundShadowSocks(t, inboundOptions, outboundOptions, shadowsocksCipherShortLists)
|
||||
testInboundShadowSocks(t, inboundOptions, outboundOptions, shadowsocksCipherShortLists, true)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -163,3 +164,17 @@ func TestInboundShadowSocks_ShadowTlsv3(t *testing.T) {
|
||||
}
|
||||
testInboundShadowSocksShadowTls(t, inboundOptions, outboundOptions)
|
||||
}
|
||||
|
||||
func TestInboundShadowSocks_KcpTun(t *testing.T) {
|
||||
inboundOptions := inbound.ShadowSocksOption{
|
||||
KcpTun: inbound.KcpTun{
|
||||
Enable: true,
|
||||
Key: shadowsocksPassword16,
|
||||
},
|
||||
}
|
||||
outboundOptions := outbound.ShadowSocksOption{
|
||||
Plugin: kcptun.Mode,
|
||||
PluginOpts: map[string]any{"key": shadowsocksPassword16},
|
||||
}
|
||||
testInboundShadowSocks(t, inboundOptions, outboundOptions, shadowsocksCipherShortLists, false)
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/metacubex/mihomo/listener/sing"
|
||||
"github.com/metacubex/mihomo/log"
|
||||
"github.com/metacubex/mihomo/ntp"
|
||||
"github.com/metacubex/mihomo/transport/kcptun"
|
||||
|
||||
shadowsocks "github.com/metacubex/sing-shadowsocks"
|
||||
"github.com/metacubex/sing-shadowsocks/shadowaead"
|
||||
@@ -138,6 +139,12 @@ func New(config LC.ShadowsocksServer, tunnel C.Tunnel, additions ...inbound.Addi
|
||||
}
|
||||
}
|
||||
|
||||
var kcptunServer *kcptun.Server
|
||||
if config.KcpTun.Enable {
|
||||
kcptunServer = kcptun.NewServer(config.KcpTun.Config)
|
||||
config.Udp = true
|
||||
}
|
||||
|
||||
for _, addr := range strings.Split(config.Listen, ",") {
|
||||
addr := addr
|
||||
|
||||
@@ -154,6 +161,14 @@ func New(config LC.ShadowsocksServer, tunnel C.Tunnel, additions ...inbound.Addi
|
||||
|
||||
sl.udpListeners = append(sl.udpListeners, ul)
|
||||
|
||||
if kcptunServer != nil {
|
||||
go kcptunServer.Serve(ul, func(c net.Conn) {
|
||||
sl.HandleConn(c, tunnel)
|
||||
})
|
||||
|
||||
continue // skip tcp listener
|
||||
}
|
||||
|
||||
go func() {
|
||||
conn := bufio.NewPacketConn(ul)
|
||||
rwOptions := network.NewReadWaitOptions(conn, sl.service)
|
||||
|
||||
Reference in New Issue
Block a user