V2bX/node/inbound.go
yuzuki999 15c36a9580 update
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)
2023-05-16 09:15:29 +08:00

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
}