1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-11-02 17:27:50 -04:00
v2fly/infra/conf/v4/transport_internet.go
2021-10-28 18:34:19 +08:00

409 lines
12 KiB
Go

package v4
import (
"encoding/json"
"strings"
"github.com/golang/protobuf/proto"
"github.com/v2fly/v2ray-core/v4/common/protocol"
"github.com/v2fly/v2ray-core/v4/common/serial"
"github.com/v2fly/v2ray-core/v4/infra/conf/cfgcommon"
"github.com/v2fly/v2ray-core/v4/infra/conf/cfgcommon/loader"
"github.com/v2fly/v2ray-core/v4/infra/conf/cfgcommon/socketcfg"
"github.com/v2fly/v2ray-core/v4/infra/conf/cfgcommon/tlscfg"
"github.com/v2fly/v2ray-core/v4/transport/internet"
"github.com/v2fly/v2ray-core/v4/transport/internet/domainsocket"
httpheader "github.com/v2fly/v2ray-core/v4/transport/internet/headers/http"
"github.com/v2fly/v2ray-core/v4/transport/internet/http"
"github.com/v2fly/v2ray-core/v4/transport/internet/kcp"
"github.com/v2fly/v2ray-core/v4/transport/internet/quic"
"github.com/v2fly/v2ray-core/v4/transport/internet/tcp"
"github.com/v2fly/v2ray-core/v4/transport/internet/websocket"
)
var (
kcpHeaderLoader = loader.NewJSONConfigLoader(loader.ConfigCreatorCache{
"none": func() interface{} { return new(NoOpAuthenticator) },
"srtp": func() interface{} { return new(SRTPAuthenticator) },
"utp": func() interface{} { return new(UTPAuthenticator) },
"wechat-video": func() interface{} { return new(WechatVideoAuthenticator) },
"dtls": func() interface{} { return new(DTLSAuthenticator) },
"wireguard": func() interface{} { return new(WireguardAuthenticator) },
}, "type", "")
tcpHeaderLoader = loader.NewJSONConfigLoader(loader.ConfigCreatorCache{
"none": func() interface{} { return new(NoOpConnectionAuthenticator) },
"http": func() interface{} { return new(Authenticator) },
}, "type", "")
)
type KCPConfig struct {
Mtu *uint32 `json:"mtu"`
Tti *uint32 `json:"tti"`
UpCap *uint32 `json:"uplinkCapacity"`
DownCap *uint32 `json:"downlinkCapacity"`
Congestion *bool `json:"congestion"`
ReadBufferSize *uint32 `json:"readBufferSize"`
WriteBufferSize *uint32 `json:"writeBufferSize"`
HeaderConfig json.RawMessage `json:"header"`
Seed *string `json:"seed"`
}
// Build implements Buildable.
func (c *KCPConfig) Build() (proto.Message, error) {
config := new(kcp.Config)
if c.Mtu != nil {
mtu := *c.Mtu
if mtu < 576 || mtu > 1460 {
return nil, newError("invalid mKCP MTU size: ", mtu).AtError()
}
config.Mtu = &kcp.MTU{Value: mtu}
}
if c.Tti != nil {
tti := *c.Tti
if tti < 10 || tti > 100 {
return nil, newError("invalid mKCP TTI: ", tti).AtError()
}
config.Tti = &kcp.TTI{Value: tti}
}
if c.UpCap != nil {
config.UplinkCapacity = &kcp.UplinkCapacity{Value: *c.UpCap}
}
if c.DownCap != nil {
config.DownlinkCapacity = &kcp.DownlinkCapacity{Value: *c.DownCap}
}
if c.Congestion != nil {
config.Congestion = *c.Congestion
}
if c.ReadBufferSize != nil {
size := *c.ReadBufferSize
if size > 0 {
config.ReadBuffer = &kcp.ReadBuffer{Size: size * 1024 * 1024}
} else {
config.ReadBuffer = &kcp.ReadBuffer{Size: 512 * 1024}
}
}
if c.WriteBufferSize != nil {
size := *c.WriteBufferSize
if size > 0 {
config.WriteBuffer = &kcp.WriteBuffer{Size: size * 1024 * 1024}
} else {
config.WriteBuffer = &kcp.WriteBuffer{Size: 512 * 1024}
}
}
if len(c.HeaderConfig) > 0 {
headerConfig, _, err := kcpHeaderLoader.Load(c.HeaderConfig)
if err != nil {
return nil, newError("invalid mKCP header config.").Base(err).AtError()
}
ts, err := headerConfig.(cfgcommon.Buildable).Build()
if err != nil {
return nil, newError("invalid mKCP header config").Base(err).AtError()
}
config.HeaderConfig = serial.ToTypedMessage(ts)
}
if c.Seed != nil {
config.Seed = &kcp.EncryptionSeed{Seed: *c.Seed}
}
return config, nil
}
type TCPConfig struct {
HeaderConfig json.RawMessage `json:"header"`
AcceptProxyProtocol bool `json:"acceptProxyProtocol"`
}
// Build implements Buildable.
func (c *TCPConfig) Build() (proto.Message, error) {
config := new(tcp.Config)
if len(c.HeaderConfig) > 0 {
headerConfig, _, err := tcpHeaderLoader.Load(c.HeaderConfig)
if err != nil {
return nil, newError("invalid TCP header config").Base(err).AtError()
}
ts, err := headerConfig.(cfgcommon.Buildable).Build()
if err != nil {
return nil, newError("invalid TCP header config").Base(err).AtError()
}
config.HeaderSettings = serial.ToTypedMessage(ts)
}
if c.AcceptProxyProtocol {
config.AcceptProxyProtocol = c.AcceptProxyProtocol
}
return config, nil
}
type WebSocketConfig struct {
Path string `json:"path"`
Headers map[string]string `json:"headers"`
AcceptProxyProtocol bool `json:"acceptProxyProtocol"`
MaxEarlyData int32 `json:"maxEarlyData"`
UseBrowserForwarding bool `json:"useBrowserForwarding"`
EarlyDataHeaderName string `json:"earlyDataHeaderName"`
}
// Build implements Buildable.
func (c *WebSocketConfig) Build() (proto.Message, error) {
path := c.Path
header := make([]*websocket.Header, 0, 32)
for key, value := range c.Headers {
header = append(header, &websocket.Header{
Key: key,
Value: value,
})
}
config := &websocket.Config{
Path: path,
Header: header,
MaxEarlyData: c.MaxEarlyData,
UseBrowserForwarding: c.UseBrowserForwarding,
EarlyDataHeaderName: c.EarlyDataHeaderName,
}
if c.AcceptProxyProtocol {
config.AcceptProxyProtocol = c.AcceptProxyProtocol
}
return config, nil
}
type HTTPConfig struct {
Host *cfgcommon.StringList `json:"host"`
Path string `json:"path"`
Method string `json:"method"`
Headers map[string]*cfgcommon.StringList `json:"headers"`
}
// Build implements Buildable.
func (c *HTTPConfig) Build() (proto.Message, error) {
config := &http.Config{
Path: c.Path,
}
if c.Host != nil {
config.Host = []string(*c.Host)
}
if c.Method != "" {
config.Method = c.Method
}
if len(c.Headers) > 0 {
config.Header = make([]*httpheader.Header, 0, len(c.Headers))
headerNames := sortMapKeys(c.Headers)
for _, key := range headerNames {
value := c.Headers[key]
if value == nil {
return nil, newError("empty HTTP header value: " + key).AtError()
}
config.Header = append(config.Header, &httpheader.Header{
Name: key,
Value: append([]string(nil), (*value)...),
})
}
}
return config, nil
}
type QUICConfig struct {
Header json.RawMessage `json:"header"`
Security string `json:"security"`
Key string `json:"key"`
}
// Build implements Buildable.
func (c *QUICConfig) Build() (proto.Message, error) {
config := &quic.Config{
Key: c.Key,
}
if len(c.Header) > 0 {
headerConfig, _, err := kcpHeaderLoader.Load(c.Header)
if err != nil {
return nil, newError("invalid QUIC header config.").Base(err).AtError()
}
ts, err := headerConfig.(cfgcommon.Buildable).Build()
if err != nil {
return nil, newError("invalid QUIC header config").Base(err).AtError()
}
config.Header = serial.ToTypedMessage(ts)
}
var st protocol.SecurityType
switch strings.ToLower(c.Security) {
case "aes-128-gcm":
st = protocol.SecurityType_AES128_GCM
case "chacha20-poly1305":
st = protocol.SecurityType_CHACHA20_POLY1305
default:
st = protocol.SecurityType_NONE
}
config.Security = &protocol.SecurityConfig{
Type: st,
}
return config, nil
}
type DomainSocketConfig struct {
Path string `json:"path"`
Abstract bool `json:"abstract"`
Padding bool `json:"padding"`
}
// Build implements Buildable.
func (c *DomainSocketConfig) Build() (proto.Message, error) {
return &domainsocket.Config{
Path: c.Path,
Abstract: c.Abstract,
Padding: c.Padding,
}, nil
}
type TransportProtocol string
// Build implements Buildable.
func (p TransportProtocol) Build() (string, error) {
switch strings.ToLower(string(p)) {
case "tcp":
return "tcp", nil
case "kcp", "mkcp":
return "mkcp", nil
case "ws", "websocket":
return "websocket", nil
case "h2", "http":
return "http", nil
case "ds", "domainsocket":
return "domainsocket", nil
case "quic":
return "quic", nil
case "gun", "grpc":
return "gun", nil
default:
return "", newError("Config: unknown transport protocol: ", p)
}
}
type StreamConfig struct {
Network *TransportProtocol `json:"network"`
Security string `json:"security"`
TLSSettings *tlscfg.TLSConfig `json:"tlsSettings"`
TCPSettings *TCPConfig `json:"tcpSettings"`
KCPSettings *KCPConfig `json:"kcpSettings"`
WSSettings *WebSocketConfig `json:"wsSettings"`
HTTPSettings *HTTPConfig `json:"httpSettings"`
DSSettings *DomainSocketConfig `json:"dsSettings"`
QUICSettings *QUICConfig `json:"quicSettings"`
GunSettings *GunConfig `json:"gunSettings"`
GRPCSettings *GunConfig `json:"grpcSettings"`
SocketSettings *socketcfg.SocketConfig `json:"sockopt"`
}
// Build implements Buildable.
func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
config := &internet.StreamConfig{
ProtocolName: "tcp",
}
if c.Network != nil {
protocol, err := c.Network.Build()
if err != nil {
return nil, err
}
config.ProtocolName = protocol
}
if strings.EqualFold(c.Security, "tls") {
tlsSettings := c.TLSSettings
if tlsSettings == nil {
tlsSettings = &tlscfg.TLSConfig{}
}
ts, err := tlsSettings.Build()
if err != nil {
return nil, newError("Failed to build TLS config.").Base(err)
}
tm := serial.ToTypedMessage(ts)
config.SecuritySettings = append(config.SecuritySettings, tm)
config.SecurityType = serial.V2Type(tm)
}
if c.TCPSettings != nil {
ts, err := c.TCPSettings.Build()
if err != nil {
return nil, newError("Failed to build TCP config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "tcp",
Settings: serial.ToTypedMessage(ts),
})
}
if c.KCPSettings != nil {
ts, err := c.KCPSettings.Build()
if err != nil {
return nil, newError("Failed to build mKCP config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "mkcp",
Settings: serial.ToTypedMessage(ts),
})
}
if c.WSSettings != nil {
ts, err := c.WSSettings.Build()
if err != nil {
return nil, newError("Failed to build WebSocket config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "websocket",
Settings: serial.ToTypedMessage(ts),
})
}
if c.HTTPSettings != nil {
ts, err := c.HTTPSettings.Build()
if err != nil {
return nil, newError("Failed to build HTTP config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "http",
Settings: serial.ToTypedMessage(ts),
})
}
if c.DSSettings != nil {
ds, err := c.DSSettings.Build()
if err != nil {
return nil, newError("Failed to build DomainSocket config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "domainsocket",
Settings: serial.ToTypedMessage(ds),
})
}
if c.QUICSettings != nil {
qs, err := c.QUICSettings.Build()
if err != nil {
return nil, newError("Failed to build QUIC config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "quic",
Settings: serial.ToTypedMessage(qs),
})
}
if c.GunSettings == nil {
c.GunSettings = c.GRPCSettings
}
if c.GunSettings != nil {
gs, err := c.GunSettings.Build()
if err != nil {
return nil, newError("Failed to build Gun config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "gun",
Settings: serial.ToTypedMessage(gs),
})
}
if c.SocketSettings != nil {
ss, err := c.SocketSettings.Build()
if err != nil {
return nil, newError("Failed to build sockopt.").Base(err)
}
config.SocketSettings = ss
}
return config, nil
}