hysteria2: Add gecko obfs

This commit is contained in:
世界
2026-05-25 13:11:59 +08:00
parent c3e63b0f01
commit 824ccb8b3a
8 changed files with 146 additions and 13 deletions
+5
View File
@@ -1,5 +1,10 @@
package constant
const (
Hysteria2ObfsTypeSalamander = "salamander"
Hysteria2ObfsTypeGecko = "gecko"
)
const (
Hysterai2MasqueradeTypeFile = "file"
Hysterai2MasqueradeTypeProxy = "proxy"
+19 -2
View File
@@ -5,7 +5,8 @@ icon: material/alert-decagram
!!! quote "Changes in sing-box 1.14.0"
:material-plus: [bbr_profile](#bbr_profile)
:material-plus: [realm](#realm)
:material-plus: [realm](#realm)
:material-alert: [obfs](#obfstype)
!!! quote "Changes in sing-box 1.11.0"
@@ -75,7 +76,7 @@ Conflict with `ignore_client_bandwidth`.
#### obfs.type
QUIC traffic obfuscator type, only available with `salamander`.
QUIC traffic obfuscator type, one of `salamander` `gecko`.
Disabled if empty.
@@ -83,6 +84,22 @@ Disabled if empty.
QUIC traffic obfuscator password.
#### obfs.min_packet_size
!!! question "Since sing-box 1.14.0"
Minimum on-wire packet size in bytes. Gecko only.
`512` is used by default.
#### obfs.max_packet_size
!!! question "Since sing-box 1.14.0"
Maximum on-wire packet size in bytes. Gecko only.
`1200` is used by default.
#### users
Hysteria2 users
+20 -3
View File
@@ -5,7 +5,8 @@ icon: material/alert-decagram
!!! quote "sing-box 1.14.0 中的更改"
:material-plus: [bbr_profile](#bbr_profile)
:material-plus: [realm](#realm)
:material-plus: [realm](#realm)
:material-alert: [obfs](#obfstype)
!!! quote "sing-box 1.11.0 中的更改"
@@ -72,13 +73,29 @@ icon: material/alert-decagram
#### obfs.type
QUIC 流量混淆器类型,仅可设为 `salamander`
QUIC 流量混淆器类型,可选 `salamander` `gecko`
如果为空则禁用。
#### obfs.password
QUIC 流量混淆器密码.
QUIC 流量混淆器密码
#### obfs.min_packet_size
!!! question "自 sing-box 1.14.0 起"
最小线上数据包大小(字节)。仅限 Gecko。
默认使用 `512`
#### obfs.max_packet_size
!!! question "自 sing-box 1.14.0 起"
最大线上数据包大小(字节)。仅限 Gecko。
默认使用 `1200`
#### users
+19 -2
View File
@@ -2,7 +2,8 @@
:material-plus: [hop_interval_max](#hop_interval_max)
:material-plus: [bbr_profile](#bbr_profile)
:material-plus: [realm](#realm)
:material-plus: [realm](#realm)
:material-alert: [obfs](#obfstype)
!!! quote "Changes in sing-box 1.11.0"
@@ -113,7 +114,7 @@ If empty, the BBR congestion control algorithm will be used instead of Hysteria
#### obfs.type
QUIC traffic obfuscator type, only available with `salamander`.
QUIC traffic obfuscator type, one of `salamander` `gecko`.
Disabled if empty.
@@ -121,6 +122,22 @@ Disabled if empty.
QUIC traffic obfuscator password.
#### obfs.min_packet_size
!!! question "Since sing-box 1.14.0"
Minimum on-wire packet size in bytes. Gecko only.
`512` is used by default.
#### obfs.max_packet_size
!!! question "Since sing-box 1.14.0"
Maximum on-wire packet size in bytes. Gecko only.
`1200` is used by default.
#### password
Authentication password.
+20 -3
View File
@@ -2,7 +2,8 @@
:material-plus: [hop_interval_max](#hop_interval_max)
:material-plus: [bbr_profile](#bbr_profile)
:material-plus: [realm](#realm)
:material-plus: [realm](#realm)
:material-alert: [obfs](#obfstype)
!!! quote "sing-box 1.11.0 中的更改"
@@ -111,13 +112,29 @@
#### obfs.type
QUIC 流量混淆器类型,仅可设为 `salamander`
QUIC 流量混淆器类型,可选 `salamander` `gecko`
如果为空则禁用。
#### obfs.password
QUIC 流量混淆器密码.
QUIC 流量混淆器密码
#### obfs.min_packet_size
!!! question "自 sing-box 1.14.0 起"
最小线上数据包大小(字节)。仅限 Gecko。
默认使用 `512`
#### obfs.max_packet_size
!!! question "自 sing-box 1.14.0 起"
最大线上数据包大小(字节)。仅限 Gecko。
默认使用 `1200`
#### password
+45 -3
View File
@@ -38,9 +38,51 @@ type Hysteria2InboundRealm struct {
STUNDomainResolver *DomainResolveOptions `json:"stun_domain_resolver,omitempty"`
}
type Hysteria2Obfs struct {
Type string `json:"type,omitempty"`
Password string `json:"password,omitempty"`
type Hysteria2ObfsGecko struct {
MinPacketSize int `json:"min_packet_size,omitempty"`
MaxPacketSize int `json:"max_packet_size,omitempty"`
}
type _Hysteria2Obfs struct {
Type string `json:"type,omitempty"`
Password string `json:"password,omitempty"`
GeckoOptions Hysteria2ObfsGecko `json:"-"`
}
type Hysteria2Obfs _Hysteria2Obfs
func (o Hysteria2Obfs) MarshalJSON() ([]byte, error) {
var v any
switch o.Type {
case C.Hysteria2ObfsTypeSalamander:
case C.Hysteria2ObfsTypeGecko:
v = o.GeckoOptions
default:
return nil, E.New("unknown obfs type: ", o.Type)
}
if v == nil {
return json.Marshal((_Hysteria2Obfs)(o))
}
return badjson.MarshallObjects((_Hysteria2Obfs)(o), v)
}
func (o *Hysteria2Obfs) UnmarshalJSON(bytes []byte) error {
err := json.Unmarshal(bytes, (*_Hysteria2Obfs)(o))
if err != nil {
return err
}
var v any
switch o.Type {
case C.Hysteria2ObfsTypeSalamander:
case C.Hysteria2ObfsTypeGecko:
v = &o.GeckoOptions
default:
return E.New("unknown obfs type: ", o.Type)
}
if v == nil {
return nil
}
return badjson.UnmarshallExcluded(bytes, (*_Hysteria2Obfs)(o), v)
}
type Hysteria2User struct {
+9
View File
@@ -52,6 +52,8 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
return nil, err
}
var salamanderPassword string
var geckoPassword string
var geckoMinPacketSize, geckoMaxPacketSize int
if options.Obfs != nil {
if options.Obfs.Password == "" {
return nil, E.New("missing obfs password")
@@ -59,6 +61,10 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
switch options.Obfs.Type {
case hysteria2.ObfsTypeSalamander:
salamanderPassword = options.Obfs.Password
case hysteria2.ObfsTypeGecko:
geckoPassword = options.Obfs.Password
geckoMinPacketSize = options.Obfs.GeckoOptions.MinPacketSize
geckoMaxPacketSize = options.Obfs.GeckoOptions.MaxPacketSize
default:
return nil, E.New("unknown obfs type: ", options.Obfs.Type)
}
@@ -154,6 +160,9 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
SendBPS: uint64(options.UpMbps * hysteria.MbpsToBps),
ReceiveBPS: uint64(options.DownMbps * hysteria.MbpsToBps),
SalamanderPassword: salamanderPassword,
GeckoPassword: geckoPassword,
GeckoMinPacketSize: geckoMinPacketSize,
GeckoMaxPacketSize: geckoMaxPacketSize,
TLSConfig: tlsConfig,
QUICOptions: qtls.QUICOptions{
IdleTimeout: options.IdleTimeout.Build(),
+9
View File
@@ -59,6 +59,8 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
return nil, err
}
var salamanderPassword string
var geckoPassword string
var geckoMinPacketSize, geckoMaxPacketSize int
if options.Obfs != nil {
if options.Obfs.Password == "" {
return nil, E.New("missing obfs password")
@@ -66,6 +68,10 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
switch options.Obfs.Type {
case hysteria2.ObfsTypeSalamander:
salamanderPassword = options.Obfs.Password
case hysteria2.ObfsTypeGecko:
geckoPassword = options.Obfs.Password
geckoMinPacketSize = options.Obfs.GeckoOptions.MinPacketSize
geckoMaxPacketSize = options.Obfs.GeckoOptions.MaxPacketSize
default:
return nil, E.New("unknown obfs type: ", options.Obfs.Type)
}
@@ -121,6 +127,9 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
SendBPS: uint64(options.UpMbps * hysteria.MbpsToBps),
ReceiveBPS: uint64(options.DownMbps * hysteria.MbpsToBps),
SalamanderPassword: salamanderPassword,
GeckoPassword: geckoPassword,
GeckoMinPacketSize: geckoMinPacketSize,
GeckoMaxPacketSize: geckoMaxPacketSize,
Password: options.Password,
TLSConfig: tlsConfig,
QUICOptions: qtls.QUICOptions{