Add Snell protocol. Refactor MASQUE HTTP/2, Fair Queue. Update XHTTP, OpenVPN, Sudoku, Fallback. Fixes

This commit is contained in:
Shtorm
2026-06-26 01:25:57 +03:00
parent d174962a04
commit edf38d33d6
107 changed files with 5346 additions and 708 deletions

View File

@@ -18,7 +18,8 @@ type URLTestOutboundOptions struct {
}
type FallbackOutboundOptions struct {
Outbounds []string `json:"outbounds"`
Outbounds []string `json:"outbounds"`
BlacklistTimeout badoption.Duration `json:"blacklist_timeout,omitempty"`
}
type GroupCommonOption struct {

View File

@@ -69,3 +69,8 @@ type RateLimiterUser struct {
Count uint32 `json:"count"`
Interval badoption.Duration `json:"interval"`
}
type FairQueueOutboundOptions struct {
FlowKeys []string `json:"flow_keys,omitempty"`
Outbound string `json:"outbound"`
}

View File

@@ -18,6 +18,8 @@ type MASQUEOutboundOptions struct {
UDPKeepalivePeriod badoption.Duration `json:"udp_keepalive_period,omitempty"`
UDPInitialPacketSize uint16 `json:"udp_initial_packet_size,omitempty"`
ReconnectDelay badoption.Duration `json:"reconnect_delay,omitempty"`
CongestionController string `json:"congestion_controller,omitempty"`
CWND int `json:"cwnd,omitempty"`
MASQUEOutboundTLSOptionsContainer
}

View File

@@ -25,6 +25,7 @@ type OpenVPNOutboundOptions struct {
KeyDirection int `json:"key_direction,omitempty"`
ReconnectDelay badoption.Duration `json:"reconnect_delay,omitempty"`
PingInterval badoption.Duration `json:"ping_interval,omitempty"`
PingRestart badoption.Duration `json:"ping_restart,omitempty"`
OpenVPNOutboundTLSOptionsContainer
}

24
option/snell.go Normal file
View File

@@ -0,0 +1,24 @@
package option
type SnellOutboundOptions struct {
DialerOptions
ServerOptions
PSK string `json:"psk"`
Version int `json:"version,omitempty"`
Reuse bool `json:"reuse,omitempty"`
Network NetworkList `json:"network,omitempty"`
Obfs *SnellObfsOptions `json:"obfs,omitempty"`
}
type SnellInboundOptions struct {
ListenOptions
PSK string `json:"psk"`
Version int `json:"version,omitempty"`
Network NetworkList `json:"network,omitempty"`
Obfs *SnellObfsOptions `json:"obfs,omitempty"`
}
type SnellObfsOptions struct {
Mode string `json:"mode,omitempty"`
Host string `json:"host,omitempty"`
}

View File

@@ -6,7 +6,6 @@ type TrustTunnelInboundOptions struct {
Users []TrustTunnelUser `json:"users,omitempty"`
Network NetworkList `json:"network,omitempty"`
CongestionController string `json:"congestion_controller,omitempty"`
BBRProfile string `json:"bbr_profile,omitempty"`
CWND int `json:"cwnd,omitempty"`
}
@@ -32,7 +31,6 @@ type TrustTunnelOutboundOptions struct {
HealthCheck bool `json:"health_check,omitempty"`
QUIC bool `json:"quic,omitempty"`
CongestionController string `json:"congestion_controller,omitempty"`
BBRProfile string `json:"bbr_profile,omitempty"`
CWND int `json:"cwnd,omitempty"`
Multiplex *TrustTunnelMultiplexOptions `json:"multiplex,omitempty"`
}

View File

@@ -4,7 +4,6 @@ import (
"net/http"
"strings"
Xbadoption "github.com/sagernet/sing-box/common/xray/json/badoption"
"github.com/sagernet/sing-box/common/xray/utils"
C "github.com/sagernet/sing-box/constant"
E "github.com/sagernet/sing/common/exceptions"
@@ -119,13 +118,13 @@ type V2RayXHTTPBaseOptions struct {
Path string `json:"path,omitempty"`
Headers map[string]string `json:"headers,omitempty"`
DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"`
XPaddingBytes Xbadoption.Range `json:"x_padding_bytes"`
XPaddingBytes badoption.Range[int] `json:"x_padding_bytes"`
NoGRPCHeader bool `json:"no_grpc_header,omitempty"`
NoSSEHeader bool `json:"no_sse_header,omitempty"`
ScMaxEachPostBytes *Xbadoption.Range `json:"sc_max_each_post_bytes"`
ScMinPostsIntervalMs *Xbadoption.Range `json:"sc_min_posts_interval_ms"`
ScMaxEachPostBytes *badoption.Range[int] `json:"sc_max_each_post_bytes"`
ScMinPostsIntervalMs *badoption.Range[int] `json:"sc_min_posts_interval_ms"`
ScMaxBufferedPosts int64 `json:"sc_max_buffered_posts,omitempty"`
ScStreamUpServerSecs *Xbadoption.Range `json:"sc_stream_up_server_secs"`
ScStreamUpServerSecs *badoption.Range[int] `json:"sc_stream_up_server_secs"`
ServerMaxHeaderBytes int `json:"server_max_header_bytes"`
TrustedXForwardedFor badoption.Listable[string] `json:"trusted_x_forwarded_for,omitempty"`
Xmux *V2RayXHTTPXmuxOptions `json:"xmux"`
@@ -141,7 +140,11 @@ type V2RayXHTTPBaseOptions struct {
SeqKey string `json:"seq_key,omitempty"`
UplinkDataPlacement string `json:"uplink_data_placement,omitempty"`
UplinkDataKey string `json:"uplink_data_key,omitempty"`
UplinkChunkSize *Xbadoption.Range `json:"uplink_chunk_size,omitempty"`
UplinkChunkSize *badoption.Range[int] `json:"uplink_chunk_size,omitempty"`
SessionIDTable string `json:"session_id_table,omitempty"`
SessionIDLength badoption.Range[int] `json:"session_id_length,omitempty"`
CongestionController string `json:"congestion_controller,omitempty"`
CWND int `json:"cwnd,omitempty"`
}
type _V2RayXHTTPOptions struct {
@@ -302,6 +305,10 @@ func checkV2RayXHTTPBaseOptions(mode string, options *V2RayXHTTPBaseOptions) err
return E.New("invalid negative value of maxHeaderBytes")
}
if mode != "stream-one" && mode != "stream-up" && options.GetNormalizedScMaxEachPostBytes().From <= 0 {
return E.New("`scMaxEachPostBytes` should be bigger than 0")
}
if options.Xmux == nil {
options.Xmux = &V2RayXHTTPXmuxOptions{}
options.Xmux.MaxConcurrency.From = 1
@@ -346,9 +353,9 @@ func (c *V2RayXHTTPBaseOptions) GetRequestHeader() http.Header {
return header
}
func (c *V2RayXHTTPBaseOptions) GetNormalizedXPaddingBytes() Xbadoption.Range {
func (c *V2RayXHTTPBaseOptions) GetNormalizedXPaddingBytes() badoption.Range[int] {
if c.XPaddingBytes.To == 0 {
return Xbadoption.Range{
return badoption.Range[int]{
From: 100,
To: 1000,
}
@@ -363,9 +370,9 @@ func (c *V2RayXHTTPBaseOptions) GetNormalizedUplinkHTTPMethod() string {
return c.UplinkHTTPMethod
}
func (c *V2RayXHTTPBaseOptions) GetNormalizedScMaxEachPostBytes() Xbadoption.Range {
func (c *V2RayXHTTPBaseOptions) GetNormalizedScMaxEachPostBytes() badoption.Range[int] {
if c.ScMaxEachPostBytes == nil {
return Xbadoption.Range{
return badoption.Range[int]{
From: 1000000,
To: 1000000,
}
@@ -373,9 +380,9 @@ func (c *V2RayXHTTPBaseOptions) GetNormalizedScMaxEachPostBytes() Xbadoption.Ran
return *c.ScMaxEachPostBytes
}
func (c *V2RayXHTTPBaseOptions) GetNormalizedScMinPostsIntervalMs() Xbadoption.Range {
func (c *V2RayXHTTPBaseOptions) GetNormalizedScMinPostsIntervalMs() badoption.Range[int] {
if c.ScMinPostsIntervalMs == nil {
return Xbadoption.Range{
return badoption.Range[int]{
From: 30,
To: 30,
}
@@ -391,9 +398,9 @@ func (c *V2RayXHTTPBaseOptions) GetNormalizedScMaxBufferedPosts() int {
return int(c.ScMaxBufferedPosts)
}
func (c *V2RayXHTTPBaseOptions) GetNormalizedScStreamUpServerSecs() Xbadoption.Range {
func (c *V2RayXHTTPBaseOptions) GetNormalizedScStreamUpServerSecs() badoption.Range[int] {
if c.ScStreamUpServerSecs == nil {
return Xbadoption.Range{
return badoption.Range[int]{
From: 20,
To: 80,
}
@@ -401,16 +408,16 @@ func (c *V2RayXHTTPBaseOptions) GetNormalizedScStreamUpServerSecs() Xbadoption.R
return *c.ScStreamUpServerSecs
}
func (c *V2RayXHTTPBaseOptions) GetNormalizedUplinkChunkSize() Xbadoption.Range {
func (c *V2RayXHTTPBaseOptions) GetNormalizedUplinkChunkSize() badoption.Range[int] {
if c.UplinkChunkSize == nil || c.UplinkChunkSize.To == 0 {
switch c.UplinkDataPlacement {
case PlacementCookie:
return Xbadoption.Range{
return badoption.Range[int]{
From: 2 * 1024, // 2 KiB
To: 3 * 1024, // 3 KiB
}
case PlacementHeader:
return Xbadoption.Range{
return badoption.Range[int]{
From: 3 * 1000, // 3 KB
To: 4 * 1000, // 4 KB
}
@@ -418,7 +425,7 @@ func (c *V2RayXHTTPBaseOptions) GetNormalizedUplinkChunkSize() Xbadoption.Range
return c.GetNormalizedScMaxEachPostBytes()
}
} else if c.UplinkChunkSize.From < 64 {
return Xbadoption.Range{
return badoption.Range[int]{
From: 64,
To: max(64, c.UplinkChunkSize.To),
}
@@ -485,31 +492,31 @@ func (c *V2RayXHTTPBaseOptions) GetNormalizedSeqKey() string {
}
type V2RayXHTTPXmuxOptions struct {
MaxConcurrency Xbadoption.Range `json:"max_concurrency"`
MaxConnections Xbadoption.Range `json:"max_connections"`
CMaxReuseTimes Xbadoption.Range `json:"c_max_reuse_times"`
HMaxRequestTimes Xbadoption.Range `json:"h_max_request_times"`
HMaxReusableSecs Xbadoption.Range `json:"h_max_reusable_secs"`
HKeepAlivePeriod int64 `json:"h_keep_alive_period"`
MaxConcurrency badoption.Range[int] `json:"max_concurrency"`
MaxConnections badoption.Range[int] `json:"max_connections"`
CMaxReuseTimes badoption.Range[int] `json:"c_max_reuse_times"`
HMaxRequestTimes badoption.Range[int] `json:"h_max_request_times"`
HMaxReusableSecs badoption.Range[int] `json:"h_max_reusable_secs"`
HKeepAlivePeriod int64 `json:"h_keep_alive_period"`
}
func (m *V2RayXHTTPXmuxOptions) GetNormalizedMaxConcurrency() Xbadoption.Range {
func (m *V2RayXHTTPXmuxOptions) GetNormalizedMaxConcurrency() badoption.Range[int] {
return m.MaxConcurrency
}
func (m *V2RayXHTTPXmuxOptions) GetNormalizedMaxConnections() Xbadoption.Range {
func (m *V2RayXHTTPXmuxOptions) GetNormalizedMaxConnections() badoption.Range[int] {
return m.MaxConnections
}
func (m *V2RayXHTTPXmuxOptions) GetNormalizedCMaxReuseTimes() Xbadoption.Range {
func (m *V2RayXHTTPXmuxOptions) GetNormalizedCMaxReuseTimes() badoption.Range[int] {
return m.CMaxReuseTimes
}
func (m *V2RayXHTTPXmuxOptions) GetNormalizedHMaxRequestTimes() Xbadoption.Range {
func (m *V2RayXHTTPXmuxOptions) GetNormalizedHMaxRequestTimes() badoption.Range[int] {
return m.HMaxRequestTimes
}
func (m *V2RayXHTTPXmuxOptions) GetNormalizedHMaxReusableSecs() Xbadoption.Range {
func (m *V2RayXHTTPXmuxOptions) GetNormalizedHMaxReusableSecs() badoption.Range[int] {
return m.HMaxReusableSecs
}

View File

@@ -3,7 +3,6 @@ package option
import (
"net/netip"
Xbadoption "github.com/sagernet/sing-box/common/xray/json/badoption"
"github.com/sagernet/sing/common/json/badoption"
)
@@ -40,10 +39,10 @@ type WireGuardAmnezia struct {
S2 int `json:"s2,omitempty"`
S3 int `json:"s3,omitempty"`
S4 int `json:"s4,omitempty"`
H1 *Xbadoption.Range `json:"h1,omitempty"`
H2 *Xbadoption.Range `json:"h2,omitempty"`
H3 *Xbadoption.Range `json:"h3,omitempty"`
H4 *Xbadoption.Range `json:"h4,omitempty"`
H1 *badoption.Range[uint32] `json:"h1,omitempty"`
H2 *badoption.Range[uint32] `json:"h2,omitempty"`
H3 *badoption.Range[uint32] `json:"h3,omitempty"`
H4 *badoption.Range[uint32] `json:"h4,omitempty"`
I1 string `json:"i1,omitempty"`
I2 string `json:"i2,omitempty"`
I3 string `json:"i3,omitempty"`