mirror of
https://github.com/wyx2685/V2bX.git
synced 2025-01-23 02:18:13 -05:00
15c36a9580
refactor limiter fix getLink bug add connection limit move limit config to ControllerConfig del dynamic speed limit (next version will be re add) del online ip sync (next version will be re add)
288 lines
8.9 KiB
Go
288 lines
8.9 KiB
Go
package node
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"github.com/Yuzuki616/V2bX/api/panel"
|
|
"github.com/Yuzuki616/V2bX/common/file"
|
|
"github.com/Yuzuki616/V2bX/conf"
|
|
"github.com/Yuzuki616/V2bX/node/lego"
|
|
"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 *inbound.StreamSetting.Network == "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 *inbound.StreamSetting.Network == "ws" {
|
|
inbound.StreamSetting.WSSettings = &coreConf.WebSocketConfig{
|
|
AcceptProxyProtocol: config.EnableProxyProtocol} //Enable proxy protocol
|
|
}
|
|
// Set TLS and XTLS settings
|
|
if config.EnableTls && config.CertConfig.CertMode != "none" {
|
|
inbound.StreamSetting.Security = "tls"
|
|
certFile, keyFile, err := getCertFile(config.CertConfig)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
tlsSettings := &coreConf.TLSConfig{
|
|
RejectUnknownSNI: config.CertConfig.RejectUnknownSni,
|
|
}
|
|
tlsSettings.Certs = append(tlsSettings.Certs, &coreConf.TLSCertConfig{CertFile: certFile, KeyFile: keyFile, OcspStapling: 3600})
|
|
inbound.StreamSetting.TLSSettings = tlsSettings
|
|
}
|
|
// 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 config.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.CertFile == "" || certConfig.KeyFile == "" {
|
|
return "", "", fmt.Errorf("cert file path or key file path not exist")
|
|
}
|
|
switch certConfig.CertMode {
|
|
case "file":
|
|
return certConfig.CertFile, certConfig.KeyFile, nil
|
|
case "dns", "http":
|
|
if file.IsExist(certConfig.CertFile) && file.IsExist(certConfig.KeyFile) {
|
|
return certConfig.CertFile, certConfig.KeyFile, nil
|
|
}
|
|
l, err := lego.New(certConfig)
|
|
if err != nil {
|
|
return "", "", fmt.Errorf("create lego object error: %s", err)
|
|
}
|
|
err = l.CreateCert()
|
|
if err != nil {
|
|
return "", "", fmt.Errorf("create cert error: %s", err)
|
|
}
|
|
return certConfig.CertFile, certConfig.KeyFile, nil
|
|
}
|
|
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
|
|
}
|