diff --git a/listener/config/hysteria2.go b/listener/config/hysteria2.go index 5520babc..898204c6 100644 --- a/listener/config/hysteria2.go +++ b/listener/config/hysteria2.go @@ -1,6 +1,10 @@ package config -import "encoding/json" +import ( + "github.com/metacubex/mihomo/listener/sing" + + "encoding/json" +) type Hysteria2Server struct { Enable bool `yaml:"enable" json:"enable"` @@ -17,6 +21,7 @@ type Hysteria2Server struct { IgnoreClientBandwidth bool `yaml:"ignore-client-bandwidth" json:"ignore-client-bandwidth,omitempty"` Masquerade string `yaml:"masquerade" json:"masquerade,omitempty"` CWND int `yaml:"cwnd" json:"cwnd,omitempty"` + MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"` } func (h Hysteria2Server) String() string { diff --git a/listener/config/shadowsocks.go b/listener/config/shadowsocks.go index 60540bbd..c5c60f10 100644 --- a/listener/config/shadowsocks.go +++ b/listener/config/shadowsocks.go @@ -1,15 +1,18 @@ package config import ( + "github.com/metacubex/mihomo/listener/sing" + "encoding/json" ) type ShadowsocksServer struct { - Enable bool - Listen string - Password string - Cipher string - Udp bool + Enable bool + Listen string + Password string + Cipher string + Udp bool + MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"` } func (t ShadowsocksServer) String() string { diff --git a/listener/config/tuic.go b/listener/config/tuic.go index 191cb59c..14a46809 100644 --- a/listener/config/tuic.go +++ b/listener/config/tuic.go @@ -1,6 +1,8 @@ package config import ( + "github.com/metacubex/mihomo/listener/sing" + "encoding/json" ) @@ -18,6 +20,7 @@ type TuicServer struct { MaxUdpRelayPacketSize int `yaml:"max-udp-relay-packet-size" json:"max-udp-relay-packet-size,omitempty"` MaxDatagramFrameSize int `yaml:"max-datagram-frame-size" json:"max-datagram-frame-size,omitempty"` CWND int `yaml:"cwnd" json:"cwnd,omitempty"` + MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"` } func (t TuicServer) String() string { diff --git a/listener/config/vmess.go b/listener/config/vmess.go index 1cf2d46c..810d6bc1 100644 --- a/listener/config/vmess.go +++ b/listener/config/vmess.go @@ -1,6 +1,8 @@ package config import ( + "github.com/metacubex/mihomo/listener/sing" + "encoding/json" ) @@ -17,6 +19,7 @@ type VmessServer struct { WsPath string Certificate string PrivateKey string + MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"` } func (t VmessServer) String() string { diff --git a/listener/inbound/hysteria2.go b/listener/inbound/hysteria2.go index 112d03f8..acd5f9a8 100644 --- a/listener/inbound/hysteria2.go +++ b/listener/inbound/hysteria2.go @@ -21,6 +21,7 @@ type Hysteria2Option struct { IgnoreClientBandwidth bool `inbound:"ignore-client-bandwidth,omitempty"` Masquerade string `inbound:"masquerade,omitempty"` CWND int `inbound:"cwnd,omitempty"` + MuxOption MuxOption `inbound:"mux-option,omitempty"` } func (o Hysteria2Option) Equal(config C.InboundConfig) bool { @@ -57,6 +58,7 @@ func NewHysteria2(options *Hysteria2Option) (*Hysteria2, error) { IgnoreClientBandwidth: options.IgnoreClientBandwidth, Masquerade: options.Masquerade, CWND: options.CWND, + MuxOption: options.MuxOption.Build(), }, }, nil } diff --git a/listener/inbound/mux.go b/listener/inbound/mux.go new file mode 100644 index 00000000..c4068e10 --- /dev/null +++ b/listener/inbound/mux.go @@ -0,0 +1,25 @@ +package inbound + +import "github.com/metacubex/mihomo/listener/sing" + +type MuxOption struct { + Padding bool `inbound:"padding,omitempty"` + Brutal BrutalOptions `inbound:"brutal,omitempty"` +} + +type BrutalOptions struct { + Enabled bool `inbound:"enabled,omitempty"` + Up string `inbound:"up,omitempty"` + Down string `inbound:"down,omitempty"` +} + +func (m MuxOption) Build() sing.MuxOption { + return sing.MuxOption{ + Padding: m.Padding, + Brutal: sing.BrutalOptions{ + Enabled: m.Brutal.Enabled, + Up: m.Brutal.Up, + Down: m.Brutal.Down, + }, + } +} diff --git a/listener/inbound/shadowsocks.go b/listener/inbound/shadowsocks.go index cb32dcfb..240e6419 100644 --- a/listener/inbound/shadowsocks.go +++ b/listener/inbound/shadowsocks.go @@ -9,9 +9,10 @@ import ( type ShadowSocksOption struct { BaseOption - Password string `inbound:"password"` - Cipher string `inbound:"cipher"` - UDP bool `inbound:"udp,omitempty"` + Password string `inbound:"password"` + Cipher string `inbound:"cipher"` + UDP bool `inbound:"udp,omitempty"` + MuxOption MuxOption `inbound:"mux-option,omitempty"` } func (o ShadowSocksOption) Equal(config C.InboundConfig) bool { @@ -34,11 +35,12 @@ func NewShadowSocks(options *ShadowSocksOption) (*ShadowSocks, error) { Base: base, config: options, ss: LC.ShadowsocksServer{ - Enable: true, - Listen: base.RawAddress(), - Password: options.Password, - Cipher: options.Cipher, - Udp: options.UDP, + Enable: true, + Listen: base.RawAddress(), + Password: options.Password, + Cipher: options.Cipher, + Udp: options.UDP, + MuxOption: options.MuxOption.Build(), }, }, nil } diff --git a/listener/inbound/tuic.go b/listener/inbound/tuic.go index c2a73b84..562228ee 100644 --- a/listener/inbound/tuic.go +++ b/listener/inbound/tuic.go @@ -19,6 +19,7 @@ type TuicOption struct { ALPN []string `inbound:"alpn,omitempty"` MaxUdpRelayPacketSize int `inbound:"max-udp-relay-packet-size,omitempty"` CWND int `inbound:"cwnd,omitempty"` + MuxOption MuxOption `inbound:"mux-option,omitempty"` } func (o TuicOption) Equal(config C.InboundConfig) bool { @@ -53,6 +54,7 @@ func NewTuic(options *TuicOption) (*Tuic, error) { ALPN: options.ALPN, MaxUdpRelayPacketSize: options.MaxUdpRelayPacketSize, CWND: options.CWND, + MuxOption: options.MuxOption.Build(), }, }, nil } diff --git a/listener/inbound/vmess.go b/listener/inbound/vmess.go index 3508aa3c..226a54d5 100644 --- a/listener/inbound/vmess.go +++ b/listener/inbound/vmess.go @@ -13,6 +13,7 @@ type VmessOption struct { WsPath string `inbound:"ws-path,omitempty"` Certificate string `inbound:"certificate,omitempty"` PrivateKey string `inbound:"private-key,omitempty"` + MuxOption MuxOption `inbound:"mux-option,omitempty"` } type VmessUser struct { @@ -55,6 +56,7 @@ func NewVmess(options *VmessOption) (*Vmess, error) { WsPath: options.WsPath, Certificate: options.Certificate, PrivateKey: options.PrivateKey, + MuxOption: options.MuxOption.Build(), }, }, nil } diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 990bbb14..65c42b6a 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -9,6 +9,7 @@ import ( "time" "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/adapter/outbound" N "github.com/metacubex/mihomo/common/net" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" @@ -26,11 +27,27 @@ import ( const UDPTimeout = 5 * time.Minute -type ListenerHandler struct { +type ListenerConfig struct { Tunnel C.Tunnel Type C.Type Additions []inbound.Addition UDPTimeout time.Duration + MuxOption MuxOption +} + +type MuxOption struct { + Padding bool `yaml:"padding" json:"padding,omitempty"` + Brutal BrutalOptions `yaml:"brutal" json:"brutal,omitempty"` +} + +type BrutalOptions struct { + Enabled bool `yaml:"enabled" json:"enabled"` + Up string `yaml:"up" json:"up,omitempty"` + Down string `yaml:"down" json:"down,omitempty"` +} + +type ListenerHandler struct { + ListenerConfig muxService *mux.Service } @@ -49,15 +66,19 @@ func ConvertMetadata(metadata *C.Metadata) M.Metadata { } } -func (h *ListenerHandler) Initialize() (err error) { +func NewListenerHandler(lc ListenerConfig) (h *ListenerHandler, err error) { + h = &ListenerHandler{ListenerConfig: lc} h.muxService, err = mux.NewService(mux.ServiceOptions{ NewStreamContext: func(ctx context.Context, conn net.Conn) context.Context { return ctx }, Logger: log.SingLogger, Handler: h, - Brutal: mux.BrutalOptions{ - // TODO: sing-mux tcp brutal inbound + Padding: lc.MuxOption.Padding, + Brutal: mux.BrutalOptions{ + Enabled: lc.MuxOption.Brutal.Enabled, + SendBPS: outbound.StringToBps(lc.MuxOption.Brutal.Up), + ReceiveBPS: outbound.StringToBps(lc.MuxOption.Brutal.Down), }, }) return diff --git a/listener/sing_hysteria2/server.go b/listener/sing_hysteria2/server.go index f6c646a8..de4c95f5 100644 --- a/listener/sing_hysteria2/server.go +++ b/listener/sing_hysteria2/server.go @@ -42,12 +42,12 @@ func New(config LC.Hysteria2Server, tunnel C.Tunnel, additions ...inbound.Additi } } - h := &sing.ListenerHandler{ + h, err := sing.NewListenerHandler(sing.ListenerConfig{ Tunnel: tunnel, Type: C.HYSTERIA2, Additions: additions, - } - err = h.Initialize() + MuxOption: config.MuxOption, + }) if err != nil { return nil, err } diff --git a/listener/sing_shadowsocks/server.go b/listener/sing_shadowsocks/server.go index af122775..1760e43c 100644 --- a/listener/sing_shadowsocks/server.go +++ b/listener/sing_shadowsocks/server.go @@ -50,12 +50,12 @@ func New(config LC.ShadowsocksServer, tunnel C.Tunnel, additions ...inbound.Addi udpTimeout := int64(sing.UDPTimeout.Seconds()) - h := &sing.ListenerHandler{ + h, err := sing.NewListenerHandler(sing.ListenerConfig{ Tunnel: tunnel, Type: C.SHADOWSOCKS, Additions: additions, - } - err = h.Initialize() + MuxOption: config.MuxOption, + }) if err != nil { return nil, err } diff --git a/listener/sing_tun/dns.go b/listener/sing_tun/dns.go index 62a15c6c..122f5a32 100644 --- a/listener/sing_tun/dns.go +++ b/listener/sing_tun/dns.go @@ -26,7 +26,7 @@ const DefaultDnsReadTimeout = time.Second * 10 const DefaultDnsRelayTimeout = time.Second * 5 type ListenerHandler struct { - sing.ListenerHandler + *sing.ListenerHandler DnsAdds []netip.AddrPort } diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 5b28da04..2017e922 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -8,7 +8,6 @@ import ( "runtime" "strconv" "strings" - "time" "github.com/metacubex/mihomo/adapter/inbound" "github.com/metacubex/mihomo/component/dialer" @@ -150,19 +149,19 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis dnsAdds = append(dnsAdds, addrPort) } - handler := &ListenerHandler{ - ListenerHandler: sing.ListenerHandler{ - Tunnel: tunnel, - Type: C.TUN, - Additions: additions, - UDPTimeout: time.Second * time.Duration(udpTimeout), - }, - DnsAdds: dnsAdds, - } - err = handler.Initialize() + h, err := sing.NewListenerHandler(sing.ListenerConfig{ + Tunnel: tunnel, + Type: C.TUN, + Additions: additions, + }) if err != nil { return nil, err } + + handler := &ListenerHandler{ + ListenerHandler: h, + DnsAdds: dnsAdds, + } l = &Listener{ closed: false, options: options, diff --git a/listener/sing_vmess/server.go b/listener/sing_vmess/server.go index d444a53e..ce422b16 100644 --- a/listener/sing_vmess/server.go +++ b/listener/sing_vmess/server.go @@ -40,12 +40,12 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) _listener = sl }() } - h := &sing.ListenerHandler{ + h, err := sing.NewListenerHandler(sing.ListenerConfig{ Tunnel: tunnel, Type: C.VMESS, Additions: additions, - } - err = h.Initialize() + MuxOption: config.MuxOption, + }) if err != nil { return nil, err } diff --git a/listener/tuic/server.go b/listener/tuic/server.go index 36d86e7f..5d807cbc 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -38,12 +38,12 @@ func New(config LC.TuicServer, tunnel C.Tunnel, additions ...inbound.Addition) ( inbound.WithSpecialRules(""), } } - h := &sing.ListenerHandler{ + h, err := sing.NewListenerHandler(sing.ListenerConfig{ Tunnel: tunnel, Type: C.TUIC, Additions: additions, - } - err := h.Initialize() + MuxOption: config.MuxOption, + }) if err != nil { return nil, err }