mirror of
https://github.com/wyx2685/V2bX.git
synced 2025-02-02 14:58:14 -05:00
695da4f4c5
change to uniproxy api refactor build inbound refactor limiter and rule add ss2022 support add speedlimit support and more...
304 lines
9.4 KiB
Go
304 lines
9.4 KiB
Go
package controller
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"github.com/Yuzuki616/V2bX/api/panel"
|
|
"github.com/Yuzuki616/V2bX/conf"
|
|
"github.com/Yuzuki616/V2bX/node/controller/legoCmd"
|
|
"github.com/goccy/go-json"
|
|
"github.com/xtls/xray-core/common/net"
|
|
"github.com/xtls/xray-core/core"
|
|
coreConf "github.com/xtls/xray-core/infra/conf"
|
|
)
|
|
|
|
// buildInbound build Inbound config for different protocol
|
|
func buildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag string) (*core.InboundHandlerConfig, error) {
|
|
inbound := &coreConf.InboundDetourConfig{}
|
|
// Set network protocol
|
|
t := coreConf.TransportProtocol(nodeInfo.Network)
|
|
inbound.StreamSetting = &coreConf.StreamConfig{Network: &t}
|
|
var err error
|
|
switch nodeInfo.NodeType {
|
|
case "V2ray":
|
|
err = buildV2ray(config, nodeInfo, inbound)
|
|
case "Trojan":
|
|
err = buildTrojan(config, nodeInfo, inbound)
|
|
case "Shadowsocks":
|
|
err = buildShadowsocks(config, nodeInfo, inbound)
|
|
default:
|
|
return nil, fmt.Errorf("unsupported node type: %s, Only support: V2ray, Trojan, Shadowsocks", nodeInfo.NodeType)
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// Set server port
|
|
inbound.PortList = &coreConf.PortList{
|
|
Range: []coreConf.PortRange{{From: uint32(nodeInfo.ServerPort), To: uint32(nodeInfo.ServerPort)}},
|
|
}
|
|
// Set Listen IP address
|
|
ipAddress := net.ParseAddress(config.ListenIP)
|
|
inbound.ListenOn = &coreConf.Address{Address: ipAddress}
|
|
// Set SniffingConfig
|
|
sniffingConfig := &coreConf.SniffingConfig{
|
|
Enabled: true,
|
|
DestOverride: &coreConf.StringList{"http", "tls"},
|
|
}
|
|
if config.DisableSniffing {
|
|
sniffingConfig.Enabled = false
|
|
}
|
|
inbound.SniffingConfig = sniffingConfig
|
|
if nodeInfo.NodeType == "tcp" {
|
|
if inbound.StreamSetting.TCPSettings != nil {
|
|
inbound.StreamSetting.TCPSettings.AcceptProxyProtocol = config.EnableProxyProtocol
|
|
} else {
|
|
tcpSetting := &coreConf.TCPConfig{
|
|
AcceptProxyProtocol: config.EnableProxyProtocol,
|
|
} //Enable proxy protocol
|
|
inbound.StreamSetting.TCPSettings = tcpSetting
|
|
}
|
|
} else if nodeInfo.NodeType == "ws" {
|
|
inbound.StreamSetting.WSSettings = &coreConf.WebSocketConfig{
|
|
AcceptProxyProtocol: config.EnableProxyProtocol} //Enable proxy protocol
|
|
}
|
|
// Set TLS and XTLS settings
|
|
if nodeInfo.EnableTls && config.CertConfig.CertMode != "none" {
|
|
inbound.StreamSetting.Security = nodeInfo.TLSType
|
|
certFile, keyFile, err := getCertFile(config.CertConfig)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if nodeInfo.TLSType == "tls" {
|
|
tlsSettings := &coreConf.TLSConfig{
|
|
RejectUnknownSNI: config.CertConfig.RejectUnknownSni,
|
|
}
|
|
tlsSettings.Certs = append(tlsSettings.Certs, &coreConf.TLSCertConfig{CertFile: certFile, KeyFile: keyFile, OcspStapling: 3600})
|
|
inbound.StreamSetting.TLSSettings = tlsSettings
|
|
} else if nodeInfo.TLSType == "xtls" {
|
|
xtlsSettings := &coreConf.XTLSConfig{
|
|
RejectUnknownSNI: config.CertConfig.RejectUnknownSni,
|
|
}
|
|
xtlsSettings.Certs = append(xtlsSettings.Certs, &coreConf.XTLSCertConfig{
|
|
CertFile: certFile,
|
|
KeyFile: keyFile,
|
|
OcspStapling: 3600})
|
|
inbound.StreamSetting.XTLSSettings = xtlsSettings
|
|
}
|
|
}
|
|
// Support ProxyProtocol for any transport protocol
|
|
if *inbound.StreamSetting.Network != "tcp" &&
|
|
*inbound.StreamSetting.Network != "ws" &&
|
|
config.EnableProxyProtocol {
|
|
sockoptConfig := &coreConf.SocketConfig{
|
|
AcceptProxyProtocol: config.EnableProxyProtocol,
|
|
} //Enable proxy protocol
|
|
inbound.StreamSetting.SocketSettings = sockoptConfig
|
|
}
|
|
inbound.Tag = tag
|
|
return inbound.Build()
|
|
}
|
|
|
|
func buildV2ray(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, inbound *coreConf.InboundDetourConfig) error {
|
|
if nodeInfo.EnableVless {
|
|
//Set vless
|
|
inbound.Protocol = "vless"
|
|
if config.EnableFallback {
|
|
// Set fallback
|
|
fallbackConfigs, err := buildVlessFallbacks(config.FallBackConfigs)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
s, err := json.Marshal(&coreConf.VLessInboundConfig{
|
|
Decryption: "none",
|
|
Fallbacks: fallbackConfigs,
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("marshal vless fallback config error: %s", err)
|
|
}
|
|
inbound.Settings = (*json.RawMessage)(&s)
|
|
} else {
|
|
var err error
|
|
s, err := json.Marshal(&coreConf.VLessInboundConfig{
|
|
Decryption: "none",
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("marshal vless config error: %s", err)
|
|
}
|
|
inbound.Settings = (*json.RawMessage)(&s)
|
|
}
|
|
} else {
|
|
// Set vmess
|
|
inbound.Protocol = "vmess"
|
|
var err error
|
|
s, err := json.Marshal(&coreConf.VMessInboundConfig{})
|
|
if err != nil {
|
|
return fmt.Errorf("marshal vmess settings error: %s", err)
|
|
}
|
|
inbound.Settings = (*json.RawMessage)(&s)
|
|
}
|
|
switch nodeInfo.Network {
|
|
case "tcp":
|
|
err := json.Unmarshal(nodeInfo.NetworkSettings, &inbound.StreamSetting.TCPSettings)
|
|
if err != nil {
|
|
return fmt.Errorf("unmarshal tcp settings error: %s", err)
|
|
}
|
|
case "ws":
|
|
err := json.Unmarshal(nodeInfo.NetworkSettings, &inbound.StreamSetting.WSSettings)
|
|
if err != nil {
|
|
return fmt.Errorf("unmarshal ws settings error: %s", err)
|
|
}
|
|
case "grpc":
|
|
err := json.Unmarshal(nodeInfo.NetworkSettings, &inbound.StreamSetting.GRPCConfig)
|
|
if err != nil {
|
|
return fmt.Errorf("unmarshal grpc settings error: %s", err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func buildTrojan(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, inbound *coreConf.InboundDetourConfig) error {
|
|
inbound.Protocol = "trojan"
|
|
if config.EnableFallback {
|
|
// Set fallback
|
|
fallbackConfigs, err := buildTrojanFallbacks(config.FallBackConfigs)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
s, err := json.Marshal(&coreConf.TrojanServerConfig{
|
|
Fallbacks: fallbackConfigs,
|
|
})
|
|
inbound.Settings = (*json.RawMessage)(&s)
|
|
if err != nil {
|
|
return fmt.Errorf("marshal trojan fallback config error: %s", err)
|
|
}
|
|
} else {
|
|
s := []byte("{}")
|
|
inbound.Settings = (*json.RawMessage)(&s)
|
|
}
|
|
t := coreConf.TransportProtocol(nodeInfo.Network)
|
|
inbound.StreamSetting = &coreConf.StreamConfig{Network: &t}
|
|
return nil
|
|
}
|
|
|
|
func buildShadowsocks(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, inbound *coreConf.InboundDetourConfig) error {
|
|
inbound.Protocol = "shadowsocks"
|
|
settings := &coreConf.ShadowsocksServerConfig{
|
|
Cipher: nodeInfo.Cipher,
|
|
}
|
|
p := make([]byte, 32)
|
|
_, err := rand.Read(p)
|
|
if err != nil {
|
|
return fmt.Errorf("generate random password error: %s", err)
|
|
}
|
|
randomPasswd := hex.EncodeToString(p)
|
|
cipher := nodeInfo.Cipher
|
|
if nodeInfo.ServerKey != "" {
|
|
settings.Password = nodeInfo.ServerKey
|
|
randomPasswd = base64.StdEncoding.EncodeToString([]byte(randomPasswd))
|
|
cipher = ""
|
|
}
|
|
defaultSSuser := &coreConf.ShadowsocksUserConfig{
|
|
Cipher: cipher,
|
|
Password: randomPasswd,
|
|
}
|
|
settings.Users = append(settings.Users, defaultSSuser)
|
|
settings.NetworkList = &coreConf.NetworkList{"tcp", "udp"}
|
|
settings.IVCheck = true
|
|
if config.DisableIVCheck {
|
|
settings.IVCheck = false
|
|
}
|
|
t := coreConf.TransportProtocol("tcp")
|
|
inbound.StreamSetting = &coreConf.StreamConfig{Network: &t}
|
|
s, err := json.Marshal(settings)
|
|
inbound.Settings = (*json.RawMessage)(&s)
|
|
if err != nil {
|
|
return fmt.Errorf("marshal shadowsocks settings error: %s", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func getCertFile(certConfig *conf.CertConfig) (certFile string, keyFile string, err error) {
|
|
if certConfig.CertMode == "file" {
|
|
if certConfig.CertFile == "" || certConfig.KeyFile == "" {
|
|
return "", "", fmt.Errorf("cert file path or key file path not exist")
|
|
}
|
|
return certConfig.CertFile, certConfig.KeyFile, nil
|
|
} else if certConfig.CertMode == "dns" {
|
|
lego, err := legoCmd.New()
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
certPath, keyPath, err := lego.DNSCert(certConfig.CertDomain, certConfig.Email, certConfig.Provider, certConfig.DNSEnv)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
return certPath, keyPath, err
|
|
} else if certConfig.CertMode == "http" {
|
|
lego, err := legoCmd.New()
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
certPath, keyPath, err := lego.HTTPCert(certConfig.CertDomain, certConfig.Email)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
return certPath, keyPath, err
|
|
}
|
|
return "", "", fmt.Errorf("unsupported certmode: %s", certConfig.CertMode)
|
|
}
|
|
|
|
func buildVlessFallbacks(fallbackConfigs []*conf.FallBackConfig) ([]*coreConf.VLessInboundFallback, error) {
|
|
if fallbackConfigs == nil {
|
|
return nil, fmt.Errorf("you must provide FallBackConfigs")
|
|
}
|
|
vlessFallBacks := make([]*coreConf.VLessInboundFallback, len(fallbackConfigs))
|
|
for i, c := range fallbackConfigs {
|
|
if c.Dest == "" {
|
|
return nil, fmt.Errorf("dest is required for fallback fialed")
|
|
}
|
|
var dest json.RawMessage
|
|
dest, err := json.Marshal(c.Dest)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("marshal dest %s config fialed: %s", dest, err)
|
|
}
|
|
vlessFallBacks[i] = &coreConf.VLessInboundFallback{
|
|
Name: c.SNI,
|
|
Alpn: c.Alpn,
|
|
Path: c.Path,
|
|
Dest: dest,
|
|
Xver: c.ProxyProtocolVer,
|
|
}
|
|
}
|
|
return vlessFallBacks, nil
|
|
}
|
|
|
|
func buildTrojanFallbacks(fallbackConfigs []*conf.FallBackConfig) ([]*coreConf.TrojanInboundFallback, error) {
|
|
if fallbackConfigs == nil {
|
|
return nil, fmt.Errorf("you must provide FallBackConfigs")
|
|
}
|
|
|
|
trojanFallBacks := make([]*coreConf.TrojanInboundFallback, len(fallbackConfigs))
|
|
for i, c := range fallbackConfigs {
|
|
|
|
if c.Dest == "" {
|
|
return nil, fmt.Errorf("dest is required for fallback fialed")
|
|
}
|
|
|
|
var dest json.RawMessage
|
|
dest, err := json.Marshal(c.Dest)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("marshal dest %s config fialed: %s", dest, err)
|
|
}
|
|
trojanFallBacks[i] = &coreConf.TrojanInboundFallback{
|
|
Name: c.SNI,
|
|
Alpn: c.Alpn,
|
|
Path: c.Path,
|
|
Dest: dest,
|
|
Xver: c.ProxyProtocolVer,
|
|
}
|
|
}
|
|
return trojanFallBacks, nil
|
|
}
|