mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-06-15 15:52:02 +03:00
Add new admin panel, failover, dns fallback, providers, limiters. Update XHTTP
This commit is contained in:
@@ -2,12 +2,5 @@ package option
|
||||
|
||||
type AdminPanelServiceOptions struct {
|
||||
ListenOptions
|
||||
Manager string `json:"manager"`
|
||||
Database AdminPanelServiceDatabase `json:"database"`
|
||||
InboundTLSOptionsContainer
|
||||
}
|
||||
|
||||
type AdminPanelServiceDatabase struct {
|
||||
Driver string `json:"driver"`
|
||||
DSN string `json:"dsn"`
|
||||
}
|
||||
|
||||
@@ -332,10 +332,10 @@ func (o *DNSServerOptions) Upgrade(ctx context.Context) error {
|
||||
if !serverAddr.IsValid() {
|
||||
return E.New("invalid server address")
|
||||
}
|
||||
o.Options = &SDNSDNSServerOptions{
|
||||
RemoteDNSServerOptions: remoteOptions,
|
||||
Stamp: serverAddr.AddrString(),
|
||||
}
|
||||
o.Options = &SDNSDNSServerOptions{
|
||||
RemoteDNSServerOptions: remoteOptions,
|
||||
Stamp: serverAddr.AddrString(),
|
||||
}
|
||||
default:
|
||||
return E.New("unsupported DNS server scheme: ", serverType)
|
||||
}
|
||||
@@ -424,4 +424,9 @@ type DHCPDNSServerOptions struct {
|
||||
type SDNSDNSServerOptions struct {
|
||||
RemoteDNSServerOptions
|
||||
Stamp string `json:"stamp"`
|
||||
}
|
||||
}
|
||||
|
||||
type FallbackDNSServerOptions struct {
|
||||
Servers []string `json:"servers"`
|
||||
Strategy string `json:"strategy,omitempty"`
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
package option
|
||||
|
||||
import "github.com/sagernet/sing/common/json/badoption"
|
||||
|
||||
type FailoverInboundOptions struct {
|
||||
Inbounds []Inbound `json:"inbounds"`
|
||||
}
|
||||
|
||||
type FailoverOutboundOptions struct {
|
||||
Outbounds []Outbound `json:"outbounds"`
|
||||
Strategy string `json:"strategy,omitempty"`
|
||||
Delay badoption.Duration `json:"delay,omitempty"`
|
||||
Outbounds []Outbound `json:"outbounds"`
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ func (m Hysteria2Masquerade) MarshalJSON() ([]byte, error) {
|
||||
default:
|
||||
return nil, E.New("unknown masquerade type: ", m.Type)
|
||||
}
|
||||
return badjson.MarshallObjects((_Hysteria2Masquerade)(m), v)
|
||||
return badjson.MarshallObjects(_Hysteria2Masquerade(m), v)
|
||||
}
|
||||
|
||||
func (m *Hysteria2Masquerade) UnmarshalJSON(bytes []byte) error {
|
||||
|
||||
@@ -90,7 +90,7 @@ type ListenOptions struct {
|
||||
type UDPTimeoutCompat badoption.Duration
|
||||
|
||||
func (c UDPTimeoutCompat) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal((time.Duration)(c).String())
|
||||
return json.Marshal(time.Duration(c).String())
|
||||
}
|
||||
|
||||
func (c *UDPTimeoutCompat) UnmarshalJSON(data []byte) error {
|
||||
|
||||
@@ -2,12 +2,14 @@ package option
|
||||
|
||||
import (
|
||||
"github.com/sagernet/sing/common/byteformats"
|
||||
"github.com/sagernet/sing/common/json/badoption"
|
||||
)
|
||||
|
||||
type BandwidthLimiterOutboundOptions struct {
|
||||
Strategy string `json:"strategy"`
|
||||
Mode string `json:"mode"`
|
||||
ConnectionType string `json:"connection_type,omitempty"`
|
||||
Mode string `json:"mode"`
|
||||
FlowKeys []string `json:"flow_keys,omitempty"`
|
||||
Speed *byteformats.NetworkBytesCompat `json:"speed"`
|
||||
Users []BandwidthLimiterUser `json:"users,omitempty"`
|
||||
Route RouteOptions `json:"route"`
|
||||
@@ -16,11 +18,26 @@ type BandwidthLimiterOutboundOptions struct {
|
||||
type BandwidthLimiterUser struct {
|
||||
Name string `json:"name"`
|
||||
Strategy string `json:"strategy"`
|
||||
Mode string `json:"mode"`
|
||||
ConnectionType string `json:"connection_type,omitempty"`
|
||||
Mode string `json:"mode"`
|
||||
Speed *byteformats.NetworkBytesCompat `json:"speed"`
|
||||
}
|
||||
|
||||
type TrafficLimiterOutboundOptions struct {
|
||||
Strategy string `json:"strategy"`
|
||||
Mode string `json:"mode"`
|
||||
Total *byteformats.Bytes `json:"total"`
|
||||
Users []TrafficLimiterUser `json:"users,omitempty"`
|
||||
Route RouteOptions `json:"route"`
|
||||
}
|
||||
|
||||
type TrafficLimiterUser struct {
|
||||
Name string `json:"name"`
|
||||
Strategy string `json:"strategy"`
|
||||
Mode string `json:"mode"`
|
||||
Total *byteformats.Bytes `json:"total"`
|
||||
}
|
||||
|
||||
type ConnectionLimiterOutboundOptions struct {
|
||||
Strategy string `json:"strategy"`
|
||||
ConnectionType string `json:"connection_type,omitempty"`
|
||||
@@ -35,3 +52,20 @@ type ConnectionLimiterUser struct {
|
||||
ConnectionType string `json:"connection_type,omitempty"`
|
||||
Count uint32 `json:"count"`
|
||||
}
|
||||
|
||||
type RateLimiterOutboundOptions struct {
|
||||
Strategy string `json:"strategy"`
|
||||
ConnectionType string `json:"connection_type,omitempty"`
|
||||
Count uint32 `json:"count"`
|
||||
Interval badoption.Duration `json:"interval"`
|
||||
Users []RateLimiterUser `json:"users,omitempty"`
|
||||
Route RouteOptions `json:"route"`
|
||||
}
|
||||
|
||||
type RateLimiterUser struct {
|
||||
Name string `json:"name"`
|
||||
Strategy string `json:"strategy"`
|
||||
ConnectionType string `json:"connection_type,omitempty"`
|
||||
Count uint32 `json:"count"`
|
||||
Interval badoption.Duration `json:"interval"`
|
||||
}
|
||||
|
||||
77
option/manager_api.go
Normal file
77
option/manager_api.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package option
|
||||
|
||||
import (
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/json"
|
||||
"github.com/sagernet/sing/common/json/badjson"
|
||||
)
|
||||
|
||||
type _ManagerAPIOptions struct {
|
||||
APIType string `json:"api_type"`
|
||||
ProtocolType string `json:"protocol_type"`
|
||||
ServerOptions ManagerAPIServerOptions `json:"-"`
|
||||
ClientOptions ManagerAPIClientOptions `json:"-"`
|
||||
}
|
||||
|
||||
type ManagerAPIOptions _ManagerAPIOptions
|
||||
|
||||
func (o ManagerAPIOptions) MarshalJSON() ([]byte, error) {
|
||||
var v any
|
||||
switch o.APIType {
|
||||
case C.ManagerAPIServer:
|
||||
v = o.ServerOptions
|
||||
case C.ManagerAPIClient:
|
||||
v = o.ClientOptions
|
||||
case "":
|
||||
return nil, E.New("missing api type")
|
||||
default:
|
||||
return nil, E.New("unknown api type: " + o.APIType)
|
||||
}
|
||||
return badjson.MarshallObjects(_ManagerAPIOptions(o), v)
|
||||
}
|
||||
|
||||
func (o *ManagerAPIOptions) UnmarshalJSON(bytes []byte) error {
|
||||
err := json.Unmarshal(bytes, (*_ManagerAPIOptions)(o))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var v any
|
||||
switch o.APIType {
|
||||
case C.ManagerAPIServer:
|
||||
v = &o.ServerOptions
|
||||
case C.ManagerAPIClient:
|
||||
v = &o.ClientOptions
|
||||
case "":
|
||||
return E.New("missing api type")
|
||||
default:
|
||||
return E.New("unknown api type: " + o.APIType)
|
||||
}
|
||||
|
||||
err = badjson.UnmarshallExcluded(bytes, (*_ManagerAPIOptions)(o), v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ManagerAPIServerOptions struct {
|
||||
ListenOptions
|
||||
InboundTLSOptionsContainer
|
||||
Manager string `json:"manager"`
|
||||
APIKey string `json:"api_key"`
|
||||
CORS *ManagerAPICORSOptions `json:"cors,omitempty"`
|
||||
}
|
||||
|
||||
type ManagerAPICORSOptions struct {
|
||||
AllowedOrigins []string `json:"allowed_origins,omitempty"`
|
||||
ExposedHeaders []string `json:"exposed_headers,omitempty"`
|
||||
MaxAge int `json:"max_age,omitempty"`
|
||||
}
|
||||
|
||||
type ManagerAPIClientOptions struct {
|
||||
DialerOptions
|
||||
ServerOptions
|
||||
OutboundTLSOptionsContainer
|
||||
APIKey string `json:"api_key"`
|
||||
}
|
||||
@@ -5,5 +5,7 @@ type NodeServiceOptions struct {
|
||||
Inbounds []string `json:"inbounds"`
|
||||
ConnectionLimiters []string `json:"connection_limiters"`
|
||||
BandwidthLimiters []string `json:"bandwidth_limiters"`
|
||||
TrafficLimiters []string `json:"traffic_limiters"`
|
||||
RateLimiters []string `json:"rate_limiters"`
|
||||
Manager string `json:"manager"`
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
package option
|
||||
|
||||
type NodeManagerServerServiceOptions struct {
|
||||
ListenOptions
|
||||
InboundTLSOptionsContainer
|
||||
Manager string `json:"manager"`
|
||||
}
|
||||
|
||||
type NodeManagerClientServiceOptions struct {
|
||||
DialerOptions
|
||||
ServerOptions
|
||||
OutboundTLSOptionsContainer
|
||||
}
|
||||
69
option/node_manager_api.go
Normal file
69
option/node_manager_api.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package option
|
||||
|
||||
import (
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/json"
|
||||
"github.com/sagernet/sing/common/json/badjson"
|
||||
)
|
||||
|
||||
type _NodeManagerAPIOptions struct {
|
||||
APIType string `json:"api_type"`
|
||||
ServerOptions NodeManagerAPIServerOptions `json:"-"`
|
||||
ClientOptions NodeManagerAPIClientOptions `json:"-"`
|
||||
}
|
||||
|
||||
type NodeManagerAPIOptions _NodeManagerAPIOptions
|
||||
|
||||
func (o NodeManagerAPIOptions) MarshalJSON() ([]byte, error) {
|
||||
var v any
|
||||
switch o.APIType {
|
||||
case C.NodeManagerAPIServer:
|
||||
v = o.ServerOptions
|
||||
case C.NodeManagerAPIClient:
|
||||
v = o.ClientOptions
|
||||
case "":
|
||||
return nil, E.New("missing api type")
|
||||
default:
|
||||
return nil, E.New("unknown api type: " + o.APIType)
|
||||
}
|
||||
return badjson.MarshallObjects(_NodeManagerAPIOptions(o), v)
|
||||
}
|
||||
|
||||
func (o *NodeManagerAPIOptions) UnmarshalJSON(bytes []byte) error {
|
||||
err := json.Unmarshal(bytes, (*_NodeManagerAPIOptions)(o))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var v any
|
||||
switch o.APIType {
|
||||
case C.NodeManagerAPIServer:
|
||||
v = &o.ServerOptions
|
||||
case C.NodeManagerAPIClient:
|
||||
v = &o.ClientOptions
|
||||
case "":
|
||||
return E.New("missing api type")
|
||||
default:
|
||||
return E.New("unknown api type: " + o.APIType)
|
||||
}
|
||||
|
||||
err = badjson.UnmarshallExcluded(bytes, (*_NodeManagerAPIOptions)(o), v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type NodeManagerAPIServerOptions struct {
|
||||
ListenOptions
|
||||
InboundTLSOptionsContainer
|
||||
Manager string `json:"manager"`
|
||||
APIKey string `json:"api_key"`
|
||||
}
|
||||
|
||||
type NodeManagerAPIClientOptions struct {
|
||||
DialerOptions
|
||||
ServerOptions
|
||||
OutboundTLSOptionsContainer
|
||||
APIKey string `json:"api_key"`
|
||||
}
|
||||
@@ -111,7 +111,7 @@ func (o DomainResolveOptions) MarshalJSON() ([]byte, error) {
|
||||
o.ClientSubnet == nil {
|
||||
return json.Marshal(o.Server)
|
||||
} else {
|
||||
return json.Marshal((_DomainResolveOptions)(o))
|
||||
return json.Marshal(_DomainResolveOptions(o))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
9
option/profiler.go
Normal file
9
option/profiler.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package option
|
||||
|
||||
import "github.com/sagernet/sing/common/json/badoption"
|
||||
|
||||
type ProfilerServiceOptions struct {
|
||||
Listen string `json:"listen,omitempty"`
|
||||
ReadTimeout badoption.Duration `json:"read_timeout,omitempty"`
|
||||
WriteTimeout badoption.Duration `json:"write_timeout,omitempty"`
|
||||
}
|
||||
@@ -16,7 +16,7 @@ type _ResolvedServiceOptions struct {
|
||||
type ResolvedServiceOptions _ResolvedServiceOptions
|
||||
|
||||
func (r ResolvedServiceOptions) MarshalJSONContext(ctx context.Context) ([]byte, error) {
|
||||
if r.Listen != nil && netip.Addr(*r.Listen) == (netip.AddrFrom4([4]byte{127, 0, 0, 53})) {
|
||||
if r.Listen != nil && netip.Addr(*r.Listen) == netip.AddrFrom4([4]byte{127, 0, 0, 53}) {
|
||||
r.Listen = nil
|
||||
}
|
||||
if r.ListenPort == 53 {
|
||||
|
||||
@@ -30,7 +30,7 @@ func (r Rule) MarshalJSON() ([]byte, error) {
|
||||
default:
|
||||
return nil, E.New("unknown rule type: " + r.Type)
|
||||
}
|
||||
return badjson.MarshallObjects((_Rule)(r), v)
|
||||
return badjson.MarshallObjects(_Rule(r), v)
|
||||
}
|
||||
|
||||
func (r *Rule) UnmarshalJSON(bytes []byte) error {
|
||||
|
||||
@@ -53,9 +53,9 @@ func (r RuleAction) MarshalJSON() ([]byte, error) {
|
||||
return nil, E.New("unknown rule action: " + r.Action)
|
||||
}
|
||||
if v == nil {
|
||||
return badjson.MarshallObjects((_RuleAction)(r))
|
||||
return badjson.MarshallObjects(_RuleAction(r))
|
||||
}
|
||||
return badjson.MarshallObjects((_RuleAction)(r), v)
|
||||
return badjson.MarshallObjects(_RuleAction(r), v)
|
||||
}
|
||||
|
||||
func (r *RuleAction) UnmarshalJSON(data []byte) error {
|
||||
@@ -124,7 +124,7 @@ func (r DNSRuleAction) MarshalJSON() ([]byte, error) {
|
||||
default:
|
||||
return nil, E.New("unknown DNS rule action: " + r.Action)
|
||||
}
|
||||
return badjson.MarshallObjects((_DNSRuleAction)(r), v)
|
||||
return badjson.MarshallObjects(_DNSRuleAction(r), v)
|
||||
}
|
||||
|
||||
func (r *DNSRuleAction) UnmarshalJSONContext(ctx context.Context, data []byte) error {
|
||||
@@ -281,7 +281,7 @@ func (r RejectActionOptions) MarshalJSON() ([]byte, error) {
|
||||
case C.RuleActionRejectMethodDefault:
|
||||
r.Method = ""
|
||||
}
|
||||
return json.Marshal((_RejectActionOptions)(r))
|
||||
return json.Marshal(_RejectActionOptions(r))
|
||||
}
|
||||
|
||||
func (r *RejectActionOptions) UnmarshalJSON(bytes []byte) error {
|
||||
|
||||
@@ -31,7 +31,7 @@ func (r DNSRule) MarshalJSON() ([]byte, error) {
|
||||
default:
|
||||
return nil, E.New("unknown rule type: " + r.Type)
|
||||
}
|
||||
return badjson.MarshallObjects((_DNSRule)(r), v)
|
||||
return badjson.MarshallObjects(_DNSRule(r), v)
|
||||
}
|
||||
|
||||
func (r *DNSRule) UnmarshalJSONContext(ctx context.Context, bytes []byte) error {
|
||||
|
||||
@@ -53,7 +53,7 @@ func (r RuleSet) MarshalJSON() ([]byte, error) {
|
||||
default:
|
||||
return nil, E.New("unknown rule-set type: " + r.Type)
|
||||
}
|
||||
return badjson.MarshallObjects((_RuleSet)(r), v)
|
||||
return badjson.MarshallObjects(_RuleSet(r), v)
|
||||
}
|
||||
|
||||
func (r *RuleSet) UnmarshalJSON(bytes []byte) error {
|
||||
@@ -145,7 +145,7 @@ func (r HeadlessRule) MarshalJSON() ([]byte, error) {
|
||||
default:
|
||||
return nil, E.New("unknown rule type: " + r.Type)
|
||||
}
|
||||
return badjson.MarshallObjects((_HeadlessRule)(r), v)
|
||||
return badjson.MarshallObjects(_HeadlessRule(r), v)
|
||||
}
|
||||
|
||||
func (r *HeadlessRule) UnmarshalJSON(bytes []byte) error {
|
||||
@@ -248,7 +248,7 @@ func (r PlainRuleSetCompat) MarshalJSON() ([]byte, error) {
|
||||
default:
|
||||
return nil, E.New("unknown rule-set version: ", r.Version)
|
||||
}
|
||||
return badjson.MarshallObjects((_PlainRuleSetCompat)(r), v)
|
||||
return badjson.MarshallObjects(_PlainRuleSetCompat(r), v)
|
||||
}
|
||||
|
||||
func (r *PlainRuleSetCompat) UnmarshalJSON(bytes []byte) error {
|
||||
|
||||
@@ -50,7 +50,7 @@ func (o ACMEDNS01ChallengeOptions) MarshalJSON() ([]byte, error) {
|
||||
default:
|
||||
return nil, E.New("unknown provider type: " + o.Provider)
|
||||
}
|
||||
return badjson.MarshallObjects((_ACMEDNS01ChallengeOptions)(o), v)
|
||||
return badjson.MarshallObjects(_ACMEDNS01ChallengeOptions(o), v)
|
||||
}
|
||||
|
||||
func (o *ACMEDNS01ChallengeOptions) UnmarshalJSON(bytes []byte) error {
|
||||
|
||||
@@ -48,7 +48,7 @@ func (o V2RayTransportOptions) MarshalJSON() ([]byte, error) {
|
||||
default:
|
||||
return nil, E.New("unknown transport type: " + o.Type)
|
||||
}
|
||||
return badjson.MarshallObjects((_V2RayTransportOptions)(o), v)
|
||||
return badjson.MarshallObjects(_V2RayTransportOptions(o), v)
|
||||
}
|
||||
|
||||
func (o *V2RayTransportOptions) UnmarshalJSON(bytes []byte) error {
|
||||
@@ -115,31 +115,33 @@ type V2RayHTTPUpgradeOptions struct {
|
||||
}
|
||||
|
||||
type V2RayXHTTPBaseOptions struct {
|
||||
Host string `json:"host,omitempty"`
|
||||
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"`
|
||||
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"`
|
||||
ScMaxBufferedPosts int64 `json:"sc_max_buffered_posts,omitempty"`
|
||||
ScStreamUpServerSecs Xbadoption.Range `json:"sc_stream_up_server_secs"`
|
||||
Xmux *V2RayXHTTPXmuxOptions `json:"xmux"`
|
||||
XPaddingObfsMode bool `json:"x_padding_obfs_mode,omitempty"`
|
||||
XPaddingKey string `json:"x_padding_key,omitempty"`
|
||||
XPaddingHeader string `json:"x_padding_header,omitempty"`
|
||||
XPaddingPlacement string `json:"x_padding_placement,omitempty"`
|
||||
XPaddingMethod string `json:"x_padding_method,omitempty"`
|
||||
UplinkHTTPMethod string `json:"uplink_http_method,omitempty"`
|
||||
SessionPlacement string `json:"session_placement,omitempty"`
|
||||
SessionKey string `json:"session_key,omitempty"`
|
||||
SeqPlacement string `json:"seq_placement,omitempty"`
|
||||
SeqKey string `json:"seq_key,omitempty"`
|
||||
UplinkDataPlacement string `json:"uplink_data_placement,omitempty"`
|
||||
UplinkDataKey string `json:"uplink_data_key,omitempty"`
|
||||
UplinkChunkSize uint32 `json:"uplink_chunk_size,omitempty"`
|
||||
Host string `json:"host,omitempty"`
|
||||
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"`
|
||||
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"`
|
||||
ScMaxBufferedPosts int64 `json:"sc_max_buffered_posts,omitempty"`
|
||||
ScStreamUpServerSecs *Xbadoption.Range `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"`
|
||||
XPaddingObfsMode bool `json:"x_padding_obfs_mode,omitempty"`
|
||||
XPaddingKey string `json:"x_padding_key,omitempty"`
|
||||
XPaddingHeader string `json:"x_padding_header,omitempty"`
|
||||
XPaddingPlacement string `json:"x_padding_placement,omitempty"`
|
||||
XPaddingMethod string `json:"x_padding_method,omitempty"`
|
||||
UplinkHTTPMethod string `json:"uplink_http_method,omitempty"`
|
||||
SessionPlacement string `json:"session_placement,omitempty"`
|
||||
SessionKey string `json:"session_key,omitempty"`
|
||||
SeqPlacement string `json:"seq_placement,omitempty"`
|
||||
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"`
|
||||
}
|
||||
|
||||
type _V2RayXHTTPOptions struct {
|
||||
@@ -164,6 +166,7 @@ const (
|
||||
PlacementQuery = "query"
|
||||
PlacementPath = "path"
|
||||
PlacementBody = "body"
|
||||
PlacementAuto = "auto"
|
||||
)
|
||||
|
||||
func (c V2RayXHTTPOptions) MarshalJSON() ([]byte, error) {
|
||||
@@ -202,15 +205,19 @@ func checkV2RayXHTTPBaseOptions(mode string, options *V2RayXHTTPBaseOptions) err
|
||||
return E.New(`"headers" can't contain "host"`)
|
||||
}
|
||||
}
|
||||
|
||||
if options.XPaddingBytes.From <= 0 || options.XPaddingBytes.To <= 0 {
|
||||
return E.New("x_padding_bytes cannot be disabled")
|
||||
}
|
||||
|
||||
if options.XPaddingKey == "" {
|
||||
options.XPaddingKey = "x_padding"
|
||||
}
|
||||
|
||||
if options.XPaddingHeader == "" {
|
||||
options.XPaddingHeader = "X-Padding"
|
||||
}
|
||||
|
||||
switch options.XPaddingPlacement {
|
||||
case "":
|
||||
options.XPaddingPlacement = "queryInHeader"
|
||||
@@ -218,6 +225,7 @@ func checkV2RayXHTTPBaseOptions(mode string, options *V2RayXHTTPBaseOptions) err
|
||||
default:
|
||||
return E.New("unsupported padding placement: " + options.XPaddingPlacement)
|
||||
}
|
||||
|
||||
switch options.XPaddingMethod {
|
||||
case "":
|
||||
options.XPaddingMethod = "repeat-x"
|
||||
@@ -225,24 +233,28 @@ func checkV2RayXHTTPBaseOptions(mode string, options *V2RayXHTTPBaseOptions) err
|
||||
default:
|
||||
return E.New("unsupported padding method: " + options.XPaddingMethod)
|
||||
}
|
||||
|
||||
switch options.UplinkDataPlacement {
|
||||
case "":
|
||||
options.UplinkDataPlacement = "body"
|
||||
case "body":
|
||||
case "cookie", "header":
|
||||
options.UplinkDataPlacement = PlacementAuto
|
||||
case PlacementAuto, PlacementBody:
|
||||
case PlacementCookie, PlacementHeader:
|
||||
if mode != "packet-up" {
|
||||
return E.New("uplink_data_placement can be " + options.UplinkDataPlacement + " only in packet-up mode")
|
||||
return E.New("UplinkDataPlacement can be " + options.UplinkDataPlacement + " only in packet-up mode")
|
||||
}
|
||||
default:
|
||||
return E.New("unsupported uplink data placement: " + options.UplinkDataPlacement)
|
||||
}
|
||||
|
||||
if options.UplinkHTTPMethod == "" {
|
||||
options.UplinkHTTPMethod = "POST"
|
||||
}
|
||||
options.UplinkHTTPMethod = strings.ToUpper(options.UplinkHTTPMethod)
|
||||
|
||||
if options.UplinkHTTPMethod == "GET" && mode != "packet-up" {
|
||||
return E.New("uplink_http_method can be GET only in packet-up mode")
|
||||
}
|
||||
|
||||
switch options.SessionPlacement {
|
||||
case "":
|
||||
options.SessionPlacement = "path"
|
||||
@@ -250,17 +262,15 @@ func checkV2RayXHTTPBaseOptions(mode string, options *V2RayXHTTPBaseOptions) err
|
||||
default:
|
||||
return E.New("unsupported session placement: " + options.SessionPlacement)
|
||||
}
|
||||
|
||||
switch options.SeqPlacement {
|
||||
case "":
|
||||
options.SeqPlacement = "path"
|
||||
case "path":
|
||||
case "cookie", "header", "query":
|
||||
if options.SessionPlacement == "path" {
|
||||
return E.New("seq_placement must be path when session_placement is path")
|
||||
}
|
||||
case "path", "cookie", "header", "query":
|
||||
default:
|
||||
return E.New("unsupported seq placement: " + options.SeqPlacement)
|
||||
}
|
||||
|
||||
if options.SessionPlacement != "path" && options.SessionKey == "" {
|
||||
switch options.SessionPlacement {
|
||||
case "cookie", "query":
|
||||
@@ -269,6 +279,7 @@ func checkV2RayXHTTPBaseOptions(mode string, options *V2RayXHTTPBaseOptions) err
|
||||
options.SessionKey = "X-Session"
|
||||
}
|
||||
}
|
||||
|
||||
if options.SeqPlacement != "path" && options.SeqKey == "" {
|
||||
switch options.SeqPlacement {
|
||||
case "cookie", "query":
|
||||
@@ -277,24 +288,20 @@ func checkV2RayXHTTPBaseOptions(mode string, options *V2RayXHTTPBaseOptions) err
|
||||
options.SeqKey = "X-Seq"
|
||||
}
|
||||
}
|
||||
if options.UplinkDataPlacement != "body" && options.UplinkDataKey == "" {
|
||||
|
||||
if options.UplinkDataPlacement != PlacementBody && options.UplinkDataKey == "" {
|
||||
switch options.UplinkDataPlacement {
|
||||
case "cookie":
|
||||
case PlacementCookie:
|
||||
options.UplinkDataKey = "x_data"
|
||||
case "header":
|
||||
case PlacementAuto, PlacementHeader:
|
||||
options.UplinkDataKey = "X-Data"
|
||||
}
|
||||
}
|
||||
if options.UplinkChunkSize == 0 {
|
||||
switch options.UplinkDataPlacement {
|
||||
case "cookie":
|
||||
options.UplinkChunkSize = 3 * 1024 // 3KB
|
||||
case "header":
|
||||
options.UplinkChunkSize = 4 * 1024 // 4KB
|
||||
}
|
||||
} else if options.UplinkChunkSize < 64 {
|
||||
options.UplinkChunkSize = 64
|
||||
|
||||
if options.ServerMaxHeaderBytes < 0 {
|
||||
return E.New("invalid negative value of maxHeaderBytes")
|
||||
}
|
||||
|
||||
if options.Xmux == nil {
|
||||
options.Xmux = &V2RayXHTTPXmuxOptions{}
|
||||
options.Xmux.MaxConcurrency.From = 1
|
||||
@@ -335,9 +342,7 @@ func (c *V2RayXHTTPBaseOptions) GetRequestHeader() http.Header {
|
||||
for k, v := range c.Headers {
|
||||
header.Add(k, v)
|
||||
}
|
||||
if header.Get("User-Agent") == "" {
|
||||
header.Set("User-Agent", utils.ChromeUA)
|
||||
}
|
||||
utils.TryDefaultHeadersWith(header, "fetch")
|
||||
return header
|
||||
}
|
||||
|
||||
@@ -359,23 +364,23 @@ func (c *V2RayXHTTPBaseOptions) GetNormalizedUplinkHTTPMethod() string {
|
||||
}
|
||||
|
||||
func (c *V2RayXHTTPBaseOptions) GetNormalizedScMaxEachPostBytes() Xbadoption.Range {
|
||||
if c.ScMaxEachPostBytes.To == 0 {
|
||||
if c.ScMaxEachPostBytes == nil {
|
||||
return Xbadoption.Range{
|
||||
From: 1000000,
|
||||
To: 1000000,
|
||||
}
|
||||
}
|
||||
return c.ScMaxEachPostBytes
|
||||
return *c.ScMaxEachPostBytes
|
||||
}
|
||||
|
||||
func (c *V2RayXHTTPBaseOptions) GetNormalizedScMinPostsIntervalMs() Xbadoption.Range {
|
||||
if c.ScMinPostsIntervalMs.To == 0 {
|
||||
if c.ScMinPostsIntervalMs == nil {
|
||||
return Xbadoption.Range{
|
||||
From: 30,
|
||||
To: 30,
|
||||
}
|
||||
}
|
||||
return c.ScMinPostsIntervalMs
|
||||
return *c.ScMinPostsIntervalMs
|
||||
}
|
||||
|
||||
func (c *V2RayXHTTPBaseOptions) GetNormalizedScMaxBufferedPosts() int {
|
||||
@@ -387,13 +392,47 @@ func (c *V2RayXHTTPBaseOptions) GetNormalizedScMaxBufferedPosts() int {
|
||||
}
|
||||
|
||||
func (c *V2RayXHTTPBaseOptions) GetNormalizedScStreamUpServerSecs() Xbadoption.Range {
|
||||
if c.ScStreamUpServerSecs.To == 0 {
|
||||
if c.ScStreamUpServerSecs == nil {
|
||||
return Xbadoption.Range{
|
||||
From: 20,
|
||||
To: 80,
|
||||
}
|
||||
}
|
||||
return c.ScStreamUpServerSecs
|
||||
return *c.ScStreamUpServerSecs
|
||||
}
|
||||
|
||||
func (c *V2RayXHTTPBaseOptions) GetNormalizedUplinkChunkSize() Xbadoption.Range {
|
||||
if c.UplinkChunkSize == nil || c.UplinkChunkSize.To == 0 {
|
||||
switch c.UplinkDataPlacement {
|
||||
case PlacementCookie:
|
||||
return Xbadoption.Range{
|
||||
From: 2 * 1024, // 2 KiB
|
||||
To: 3 * 1024, // 3 KiB
|
||||
}
|
||||
case PlacementHeader:
|
||||
return Xbadoption.Range{
|
||||
From: 3 * 1000, // 3 KB
|
||||
To: 4 * 1000, // 4 KB
|
||||
}
|
||||
default:
|
||||
return c.GetNormalizedScMaxEachPostBytes()
|
||||
}
|
||||
} else if c.UplinkChunkSize.From < 64 {
|
||||
return Xbadoption.Range{
|
||||
From: 64,
|
||||
To: max(64, c.UplinkChunkSize.To),
|
||||
}
|
||||
}
|
||||
|
||||
return *c.UplinkChunkSize
|
||||
}
|
||||
|
||||
func (c *V2RayXHTTPBaseOptions) GetNormalizedServerMaxHeaderBytes() int {
|
||||
if c.ServerMaxHeaderBytes <= 0 {
|
||||
return 8192
|
||||
} else {
|
||||
return c.ServerMaxHeaderBytes
|
||||
}
|
||||
}
|
||||
|
||||
func (c *V2RayXHTTPBaseOptions) GetNormalizedSessionPlacement() string {
|
||||
|
||||
Reference in New Issue
Block a user