mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-07-08 04:38:50 +00:00
311 lines
11 KiB
Go
311 lines
11 KiB
Go
package conf
|
|
|
|
import (
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/xtls/xray-core/common/errors"
|
|
"github.com/xtls/xray-core/common/serial"
|
|
"github.com/xtls/xray-core/transport/internet"
|
|
"github.com/xtls/xray-core/transport/internet/hysteria/congestion/bbr"
|
|
)
|
|
|
|
type TransportProtocol string
|
|
|
|
// Build implements Buildable.
|
|
func (p TransportProtocol) Build() (string, error) {
|
|
switch strings.ToLower(string(p)) {
|
|
case "raw", "tcp":
|
|
return "tcp", nil
|
|
case "xhttp", "splithttp":
|
|
return "splithttp", nil
|
|
case "kcp", "mkcp":
|
|
return "mkcp", nil
|
|
case "grpc":
|
|
errors.PrintNonRemovalDeprecatedFeatureWarning("gRPC transport (with unnecessary costs, etc.)", "XHTTP stream-up H2")
|
|
return "grpc", nil
|
|
case "ws", "websocket":
|
|
errors.PrintNonRemovalDeprecatedFeatureWarning("WebSocket transport (with ALPN http/1.1, etc.)", "XHTTP H2 & H3")
|
|
return "websocket", nil
|
|
case "httpupgrade":
|
|
errors.PrintNonRemovalDeprecatedFeatureWarning("HTTPUpgrade transport (with ALPN http/1.1, etc.)", "XHTTP H2 & H3")
|
|
return "httpupgrade", nil
|
|
case "h2", "h3", "http":
|
|
return "", errors.PrintRemovedFeatureError("HTTP transport (without header padding, etc.)", "XHTTP stream-one H2 & H3")
|
|
case "quic":
|
|
return "", errors.PrintRemovedFeatureError("QUIC transport (without web service, etc.)", "XHTTP stream-one H3")
|
|
case "hysteria":
|
|
return "hysteria", nil
|
|
default:
|
|
return "", errors.New("Config: unknown transport protocol: ", p)
|
|
}
|
|
}
|
|
|
|
type StreamConfig struct {
|
|
Address *Address `json:"address"`
|
|
Port uint16 `json:"port"`
|
|
Method *TransportProtocol `json:"method"`
|
|
Network *TransportProtocol `json:"network"`
|
|
Security string `json:"security"`
|
|
FinalMask *FinalMask `json:"finalmask"`
|
|
TLSSettings *TLSConfig `json:"tlsSettings"`
|
|
REALITYSettings *REALITYConfig `json:"realitySettings"`
|
|
RAWSettings *TCPConfig `json:"rawSettings"`
|
|
TCPSettings *TCPConfig `json:"tcpSettings"`
|
|
XHTTPSettings *SplitHTTPConfig `json:"xhttpSettings"`
|
|
SplitHTTPSettings *SplitHTTPConfig `json:"splithttpSettings"`
|
|
KCPSettings *KCPConfig `json:"kcpSettings"`
|
|
GRPCSettings *GRPCConfig `json:"grpcSettings"`
|
|
WSSettings *WebSocketConfig `json:"wsSettings"`
|
|
HTTPUPGRADESettings *HttpUpgradeConfig `json:"httpupgradeSettings"`
|
|
HysteriaSettings *HysteriaConfig `json:"hysteriaSettings"`
|
|
SocketSettings *SocketConfig `json:"sockopt"`
|
|
}
|
|
|
|
// Build implements Buildable.
|
|
func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
|
|
config := &internet.StreamConfig{
|
|
Port: uint32(c.Port),
|
|
ProtocolName: "tcp",
|
|
}
|
|
if c.Address != nil {
|
|
config.Address = c.Address.Build()
|
|
}
|
|
if c.Method != nil {
|
|
c.Network = c.Method
|
|
}
|
|
if c.Network != nil {
|
|
protocol, err := c.Network.Build()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
config.ProtocolName = protocol
|
|
}
|
|
|
|
switch strings.ToLower(c.Security) {
|
|
case "", "none":
|
|
case "tls":
|
|
tlsSettings := c.TLSSettings
|
|
if tlsSettings == nil {
|
|
tlsSettings = &TLSConfig{}
|
|
}
|
|
ts, err := tlsSettings.Build()
|
|
if err != nil {
|
|
return nil, errors.New("Failed to build TLS config.").Base(err)
|
|
}
|
|
tm := serial.ToTypedMessage(ts)
|
|
config.SecuritySettings = append(config.SecuritySettings, tm)
|
|
config.SecurityType = tm.Type
|
|
case "reality":
|
|
if config.ProtocolName != "tcp" && config.ProtocolName != "splithttp" && config.ProtocolName != "grpc" {
|
|
return nil, errors.New("REALITY only supports RAW, XHTTP and gRPC for now.")
|
|
}
|
|
if c.REALITYSettings == nil {
|
|
return nil, errors.New(`REALITY: Empty "realitySettings".`)
|
|
}
|
|
ts, err := c.REALITYSettings.Build()
|
|
if err != nil {
|
|
return nil, errors.New("Failed to build REALITY config.").Base(err)
|
|
}
|
|
tm := serial.ToTypedMessage(ts)
|
|
config.SecuritySettings = append(config.SecuritySettings, tm)
|
|
config.SecurityType = tm.Type
|
|
case "xtls":
|
|
return nil, errors.PrintRemovedFeatureError(`Legacy XTLS`, `xtls-rprx-vision with TLS or REALITY`)
|
|
default:
|
|
return nil, errors.New(`Unknown security "` + c.Security + `".`)
|
|
}
|
|
|
|
if c.RAWSettings != nil {
|
|
c.TCPSettings = c.RAWSettings
|
|
}
|
|
if c.TCPSettings != nil {
|
|
ts, err := c.TCPSettings.Build()
|
|
if err != nil {
|
|
return nil, errors.New("Failed to build RAW config.").Base(err)
|
|
}
|
|
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
|
|
ProtocolName: "tcp",
|
|
Settings: serial.ToTypedMessage(ts),
|
|
})
|
|
}
|
|
if c.XHTTPSettings != nil {
|
|
c.SplitHTTPSettings = c.XHTTPSettings
|
|
}
|
|
if c.SplitHTTPSettings != nil {
|
|
hs, err := c.SplitHTTPSettings.Build()
|
|
if err != nil {
|
|
return nil, errors.New("Failed to build XHTTP config.").Base(err)
|
|
}
|
|
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
|
|
ProtocolName: "splithttp",
|
|
Settings: serial.ToTypedMessage(hs),
|
|
})
|
|
}
|
|
if c.KCPSettings != nil {
|
|
ts, err := c.KCPSettings.Build()
|
|
if err != nil {
|
|
return nil, errors.New("Failed to build mKCP config.").Base(err)
|
|
}
|
|
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
|
|
ProtocolName: "mkcp",
|
|
Settings: serial.ToTypedMessage(ts),
|
|
})
|
|
}
|
|
if c.GRPCSettings != nil {
|
|
gs, err := c.GRPCSettings.Build()
|
|
if err != nil {
|
|
return nil, errors.New("Failed to build gRPC config.").Base(err)
|
|
}
|
|
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
|
|
ProtocolName: "grpc",
|
|
Settings: serial.ToTypedMessage(gs),
|
|
})
|
|
}
|
|
if c.WSSettings != nil {
|
|
ts, err := c.WSSettings.Build()
|
|
if err != nil {
|
|
return nil, errors.New("Failed to build WebSocket config.").Base(err)
|
|
}
|
|
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
|
|
ProtocolName: "websocket",
|
|
Settings: serial.ToTypedMessage(ts),
|
|
})
|
|
}
|
|
if c.HTTPUPGRADESettings != nil {
|
|
hs, err := c.HTTPUPGRADESettings.Build()
|
|
if err != nil {
|
|
return nil, errors.New("Failed to build HTTPUpgrade config.").Base(err)
|
|
}
|
|
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
|
|
ProtocolName: "httpupgrade",
|
|
Settings: serial.ToTypedMessage(hs),
|
|
})
|
|
}
|
|
if c.HysteriaSettings != nil {
|
|
hs, err := c.HysteriaSettings.Build()
|
|
if err != nil {
|
|
return nil, errors.New("Failed to build Hysteria config.").Base(err)
|
|
}
|
|
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
|
|
ProtocolName: "hysteria",
|
|
Settings: serial.ToTypedMessage(hs),
|
|
})
|
|
}
|
|
if c.SocketSettings != nil {
|
|
ss, err := c.SocketSettings.Build()
|
|
if err != nil {
|
|
return nil, errors.New("Failed to build sockopt.").Base(err)
|
|
}
|
|
config.SocketSettings = ss
|
|
}
|
|
|
|
if c.FinalMask != nil {
|
|
for _, mask := range c.FinalMask.Tcp {
|
|
u, err := mask.Build(true)
|
|
if err != nil {
|
|
return nil, errors.New("failed to build mask with type ", mask.Type).Base(err)
|
|
}
|
|
config.Tcpmasks = append(config.Tcpmasks, serial.ToTypedMessage(u))
|
|
}
|
|
for _, mask := range c.FinalMask.Udp {
|
|
u, err := mask.Build(false)
|
|
if err != nil {
|
|
return nil, errors.New("failed to build mask with type ", mask.Type).Base(err)
|
|
}
|
|
config.Udpmasks = append(config.Udpmasks, serial.ToTypedMessage(u))
|
|
}
|
|
if c.FinalMask.QuicParams != nil {
|
|
profile := strings.ToLower(c.FinalMask.QuicParams.BbrProfile)
|
|
switch profile {
|
|
case "", string(bbr.ProfileConservative), string(bbr.ProfileStandard), string(bbr.ProfileAggressive):
|
|
if profile == "" {
|
|
profile = string(bbr.ProfileStandard)
|
|
}
|
|
default:
|
|
return nil, errors.New("unknown bbr profile")
|
|
}
|
|
|
|
up, err := c.FinalMask.QuicParams.BrutalUp.Bps()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
down, err := c.FinalMask.QuicParams.BrutalDown.Bps()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if up > 0 && up < 65536 {
|
|
return nil, errors.New("BrutalUp must be at least 65536 bytes per second")
|
|
}
|
|
if down > 0 && down < 65536 {
|
|
return nil, errors.New("BrutalDown must be at least 65536 bytes per second")
|
|
}
|
|
|
|
c.FinalMask.QuicParams.Congestion = strings.ToLower(c.FinalMask.QuicParams.Congestion)
|
|
switch c.FinalMask.QuicParams.Congestion {
|
|
case "", "brutal", "reno", "bbr":
|
|
case "force-brutal":
|
|
if up == 0 {
|
|
return nil, errors.New("force-brutal requires up")
|
|
}
|
|
default:
|
|
return nil, errors.New("unknown congestion control: ", c.FinalMask.QuicParams.Congestion, ", valid values: reno, bbr, brutal, force-brutal")
|
|
}
|
|
|
|
if (c.FinalMask.QuicParams.UdpHop.Interval.From != 0 && c.FinalMask.QuicParams.UdpHop.Interval.From < 5) || (c.FinalMask.QuicParams.UdpHop.Interval.To != 0 && c.FinalMask.QuicParams.UdpHop.Interval.To < 5) {
|
|
return nil, errors.New("Interval must be at least 5")
|
|
}
|
|
|
|
if c.FinalMask.QuicParams.InitStreamReceiveWindow > 0 && c.FinalMask.QuicParams.InitStreamReceiveWindow < 16384 {
|
|
return nil, errors.New("InitStreamReceiveWindow must be at least 16384")
|
|
}
|
|
if c.FinalMask.QuicParams.MaxStreamReceiveWindow > 0 && c.FinalMask.QuicParams.MaxStreamReceiveWindow < 16384 {
|
|
return nil, errors.New("MaxStreamReceiveWindow must be at least 16384")
|
|
}
|
|
if c.FinalMask.QuicParams.InitConnectionReceiveWindow > 0 && c.FinalMask.QuicParams.InitConnectionReceiveWindow < 16384 {
|
|
return nil, errors.New("InitConnectionReceiveWindow must be at least 16384")
|
|
}
|
|
if c.FinalMask.QuicParams.MaxConnectionReceiveWindow > 0 && c.FinalMask.QuicParams.MaxConnectionReceiveWindow < 16384 {
|
|
return nil, errors.New("MaxConnectionReceiveWindow must be at least 16384")
|
|
}
|
|
if c.FinalMask.QuicParams.MaxIdleTimeout != 0 && (c.FinalMask.QuicParams.MaxIdleTimeout < 4 || c.FinalMask.QuicParams.MaxIdleTimeout > 120) {
|
|
return nil, errors.New("MaxIdleTimeout must be between 4 and 120")
|
|
}
|
|
if c.FinalMask.QuicParams.KeepAlivePeriod != 0 && (c.FinalMask.QuicParams.KeepAlivePeriod < 2 || c.FinalMask.QuicParams.KeepAlivePeriod > 60) {
|
|
return nil, errors.New("KeepAlivePeriod must be between 2 and 60")
|
|
}
|
|
if c.FinalMask.QuicParams.MaxIncomingStreams != 0 && c.FinalMask.QuicParams.MaxIncomingStreams < 8 {
|
|
return nil, errors.New("MaxIncomingStreams must be at least 8")
|
|
}
|
|
|
|
if c.FinalMask.QuicParams.Debug {
|
|
os.Setenv("HYSTERIA_BBR_DEBUG", "true")
|
|
os.Setenv("HYSTERIA_BRUTAL_DEBUG", "true")
|
|
}
|
|
|
|
config.QuicParams = &internet.QuicParams{
|
|
Congestion: c.FinalMask.QuicParams.Congestion,
|
|
BbrProfile: profile,
|
|
BrutalUp: up,
|
|
BrutalDown: down,
|
|
UdpHop: &internet.UdpHop{
|
|
Ports: c.FinalMask.QuicParams.UdpHop.PortList.Build().Ports(),
|
|
IntervalMin: int64(c.FinalMask.QuicParams.UdpHop.Interval.From),
|
|
IntervalMax: int64(c.FinalMask.QuicParams.UdpHop.Interval.To),
|
|
},
|
|
InitStreamReceiveWindow: c.FinalMask.QuicParams.InitStreamReceiveWindow,
|
|
MaxStreamReceiveWindow: c.FinalMask.QuicParams.MaxStreamReceiveWindow,
|
|
InitConnReceiveWindow: c.FinalMask.QuicParams.InitConnectionReceiveWindow,
|
|
MaxConnReceiveWindow: c.FinalMask.QuicParams.MaxConnectionReceiveWindow,
|
|
MaxIdleTimeout: c.FinalMask.QuicParams.MaxIdleTimeout,
|
|
KeepAlivePeriod: c.FinalMask.QuicParams.KeepAlivePeriod,
|
|
DisablePathMtuDiscovery: c.FinalMask.QuicParams.DisablePathMTUDiscovery,
|
|
MaxIncomingStreams: c.FinalMask.QuicParams.MaxIncomingStreams,
|
|
}
|
|
}
|
|
}
|
|
|
|
return config, nil
|
|
}
|