From 42407d5c628ebcbe6de11332fd3d2dfea6709ef7 Mon Sep 17 00:00:00 2001 From: yuzuki999 Date: Sat, 19 Aug 2023 20:06:42 +0800 Subject: [PATCH] refactor NodeInfo --- api/panel/node.go | 241 +++++++++++++++++++++++-------------------- api/panel/panel.go | 9 +- conf/cert.go | 12 --- core/interface.go | 8 +- core/sing/node.go | 128 ++++++++--------------- core/sing/sing.go | 3 +- core/sing/user.go | 50 ++++----- core/xray/inbound.go | 193 +++++++++++++++------------------- core/xray/user.go | 20 ++-- core/xray/xray.go | 3 +- node/cert.go | 2 +- node/controller.go | 5 +- node/task.go | 50 +++++---- 13 files changed, 333 insertions(+), 391 deletions(-) diff --git a/api/panel/node.go b/api/panel/node.go index fae2f24..6fe226e 100644 --- a/api/panel/node.go +++ b/api/panel/node.go @@ -3,21 +3,45 @@ package panel import ( "encoding/base64" "fmt" + "github.com/InazumaV/V2bX/common/crypt" "reflect" "strconv" "strings" "time" - "github.com/InazumaV/V2bX/common/crypt" "github.com/goccy/go-json" ) -type CommonNodeRsp struct { - Host string `json:"host"` - ServerPort int `json:"server_port"` - ServerName string `json:"server_name"` - Routes []Route `json:"routes"` - BaseConfig BaseConfig `json:"base_config"` +// Security type +const ( + None = 0 + Tls = 1 + Reality = 2 +) + +type NodeInfo struct { + Id int + Type string + Security int + PushInterval time.Duration + PullInterval time.Duration + RawDNS RawDNS + Rules Rules + + // origin + VAllss *VAllssNode + Shadowsocks *ShadowsocksNode + Trojan *TrojanNode + Hysteria *HysteriaNode + Common *CommonNode +} + +type CommonNode struct { + Host string `json:"host"` + ServerPort int `json:"server_port"` + ServerName string `json:"server_name"` + Routes []Route `json:"routes"` + BaseConfig *BaseConfig `json:"base_config"` } type Route struct { @@ -31,45 +55,50 @@ type BaseConfig struct { PullInterval any `json:"pull_interval"` } -type V2rayNodeRsp struct { +// VAllssNode is vmess and vless node info +type VAllssNode struct { + CommonNode Tls int `json:"tls"` + TlsSettings TlsSettings `json:"tls_settings"` Network string `json:"network"` NetworkSettings json.RawMessage `json:"networkSettings"` ServerName string `json:"server_name"` + + // vless only + Flow string `json:"flow"` + RealityConfig RealityConfig } -type ShadowsocksNodeRsp struct { +type TlsSettings struct { + ServerName []string `json:"sever_name"` + ServerPort string `json:"server_port"` + ShortIds []string `json:"short_ids"` + PrivateKey string `json:"-"` +} + +type RealityConfig struct { + Dest string `json:"Dest"` + Xver uint64 `json:"Xver"` + MinClientVer string `json:"MinClientVer"` + MaxClientVer string `json:"MaxClientVer"` + MaxTimeDiff uint64 `json:"MaxTimeDiff"` +} + +type ShadowsocksNode struct { + CommonNode Cipher string `json:"cipher"` ServerKey string `json:"server_key"` } -type HysteriaNodeRsp struct { +type TrojanNode CommonNode + +type HysteriaNode struct { + CommonNode UpMbps int `json:"up_mbps"` DownMbps int `json:"down_mbps"` Obfs string `json:"obfs"` } -type NodeInfo struct { - Id int - Type string - Rules Rules - Host string - Port int - Network string - RawDNS RawDNS - ExtraConfig V2rayExtraConfig - NetworkSettings json.RawMessage - Tls bool - ServerName string - UpMbps int - DownMbps int - ServerKey string - Cipher string - HyObfs string - PushInterval time.Duration - PullInterval time.Duration -} - type RawDNS struct { DNSMap map[string]map[string]interface{} DNSJson []byte @@ -80,24 +109,6 @@ type Rules struct { Protocol []string } -type V2rayExtraConfig struct { - EnableVless string `json:"EnableVless"` - VlessFlow string `json:"VlessFlow"` - EnableReality string `json:"EnableReality"` - RealityConfig *RealityConfig `json:"RealityConfig"` -} - -type RealityConfig struct { - Dest string `yaml:"Dest" json:"Dest"` - Xver string `yaml:"Xver" json:"Xver"` - ServerNames []string `yaml:"ServerNames" json:"ServerNames"` - PrivateKey string `yaml:"PrivateKey" json:"PrivateKey"` - MinClientVer string `yaml:"MinClientVer" json:"MinClientVer"` - MaxClientVer string `yaml:"MaxClientVer" json:"MaxClientVer"` - MaxTimeDiff string `yaml:"MaxTimeDiff" json:"MaxTimeDiff"` - ShortIds []string `yaml:"ShortIds" json:"ShortIds"` -} - func (c *Client) GetNodeInfo() (node *NodeInfo, err error) { const path = "/api/v1/server/UniProxy/config" r, err := c.client. @@ -110,7 +121,6 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) { if r.StatusCode() == 304 { return nil, nil } - // parse common params node = &NodeInfo{ Id: c.NodeId, Type: c.NodeType, @@ -119,26 +129,72 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) { DNSJson: []byte(""), }, } - common := CommonNodeRsp{} - err = json.Unmarshal(r.Body(), &common) - if err != nil { - return nil, fmt.Errorf("decode common params error: %s", err) + // parse protocol params + var cm *CommonNode + switch c.NodeType { + case "vmess", "vless": + rsp := &VAllssNode{} + err = json.Unmarshal(r.Body(), rsp) + if err != nil { + return nil, fmt.Errorf("decode v2ray params error: %s", err) + } + cm = &rsp.CommonNode + node.VAllss = rsp + node.Security = node.VAllss.Tls + if len(rsp.NetworkSettings) > 0 { + /*err = json.Unmarshal(rsp.NetworkSettings, &rsp.RealityConfig) + if err != nil { + return nil, fmt.Errorf("decode reality config error: %s", err) + }*/ + if node.Security == Reality { + key := crypt.GenX25519Private([]byte(strconv.Itoa(c.NodeId) + c.NodeType + c.Token)) + rsp.TlsSettings.PrivateKey = base64.RawURLEncoding.EncodeToString(key) + } + } + case "shadowsocks": + rsp := &ShadowsocksNode{} + err = json.Unmarshal(r.Body(), rsp) + if err != nil { + return nil, fmt.Errorf("decode v2ray params error: %s", err) + } + cm = &rsp.CommonNode + node.Shadowsocks = rsp + node.Security = None + case "trojan": + rsp := &TrojanNode{} + err = json.Unmarshal(r.Body(), rsp) + if err != nil { + return nil, fmt.Errorf("decode v2ray params error: %s", err) + } + cm = (*CommonNode)(rsp) + node.Trojan = rsp + node.Security = Tls + case "hysteria": + rsp := &HysteriaNode{} + err = json.Unmarshal(r.Body(), rsp) + if err != nil { + return nil, fmt.Errorf("decode v2ray params error: %s", err) + } + cm = &rsp.CommonNode + node.Hysteria = rsp + node.Security = Tls } - for i := range common.Routes { + // parse rules and dns + for i := range cm.Routes { var matchs []string - if _, ok := common.Routes[i].Match.(string); ok { - matchs = strings.Split(common.Routes[i].Match.(string), ",") - } else if _, ok = common.Routes[i].Match.([]string); ok { - matchs = common.Routes[i].Match.([]string) + if _, ok := cm.Routes[i].Match.(string); ok { + matchs = strings.Split(cm.Routes[i].Match.(string), ",") + } else if _, ok = cm.Routes[i].Match.([]string); ok { + matchs = cm.Routes[i].Match.([]string) } else { - temp := common.Routes[i].Match.([]interface{}) + temp := cm.Routes[i].Match.([]interface{}) matchs = make([]string, len(temp)) for i := range temp { matchs[i] = temp[i].(string) } } - switch common.Routes[i].Action { + switch cm.Routes[i].Action { case "block": for _, v := range matchs { if strings.HasPrefix(v, "protocol:") { @@ -156,7 +212,7 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) { } if matchs[0] != "main" { node.RawDNS.DNSMap[strconv.Itoa(i)] = map[string]interface{}{ - "address": common.Routes[i].ActionValue, + "address": cm.Routes[i].ActionValue, "domains": domains, } } else { @@ -166,57 +222,16 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) { } } } - node.ServerName = common.ServerName - node.Host = common.Host - node.Port = common.ServerPort - node.PullInterval = intervalToTime(common.BaseConfig.PullInterval) - node.PushInterval = intervalToTime(common.BaseConfig.PushInterval) - // parse protocol params - switch c.NodeType { - case "v2ray": - rsp := V2rayNodeRsp{} - err = json.Unmarshal(r.Body(), &rsp) - if err != nil { - return nil, fmt.Errorf("decode v2ray params error: %s", err) - } - node.Network = rsp.Network - node.NetworkSettings = rsp.NetworkSettings - node.ServerName = rsp.ServerName - if rsp.Tls == 1 { - node.Tls = true - } - err = json.Unmarshal(rsp.NetworkSettings, &node.ExtraConfig) - if err != nil { - return nil, fmt.Errorf("decode v2ray extra error: %s", err) - } - if node.ExtraConfig.EnableReality == "true" { - if node.ExtraConfig.RealityConfig == nil { - node.ExtraConfig.EnableReality = "false" - } else { - key := crypt.GenX25519Private([]byte(strconv.Itoa(c.NodeId) + c.NodeType + c.Token)) - node.ExtraConfig.RealityConfig.PrivateKey = base64.RawURLEncoding.EncodeToString(key) - } - } - case "shadowsocks": - rsp := ShadowsocksNodeRsp{} - err = json.Unmarshal(r.Body(), &rsp) - if err != nil { - return nil, fmt.Errorf("decode v2ray params error: %s", err) - } - node.ServerKey = rsp.ServerKey - node.Cipher = rsp.Cipher - case "trojan": - node.Tls = true - case "hysteria": - rsp := HysteriaNodeRsp{} - err = json.Unmarshal(r.Body(), &rsp) - if err != nil { - return nil, fmt.Errorf("decode v2ray params error: %s", err) - } - node.DownMbps = rsp.DownMbps - node.UpMbps = rsp.UpMbps - node.HyObfs = rsp.Obfs - } + + // set interval + node.PushInterval = intervalToTime(cm.BaseConfig.PushInterval) + node.PullInterval = intervalToTime(cm.BaseConfig.PullInterval) + + node.Common = cm + // clear + cm.Routes = nil + cm.BaseConfig = nil + c.nodeEtag = r.Header().Get("ETag") return } diff --git a/api/panel/panel.go b/api/panel/panel.go index 566b235..78a9ff6 100644 --- a/api/panel/panel.go +++ b/api/panel/panel.go @@ -46,7 +46,14 @@ func New(c *conf.ApiConfig) (*Client, error) { // Check node type c.NodeType = strings.ToLower(c.NodeType) switch c.NodeType { - case "v2ray", "trojan", "shadowsocks", "hysteria": + case "v2ray": + c.NodeType = "vmess" + case + "vmess", + "trojan", + "shadowsocks", + "hysteria", + "vless": default: return nil, fmt.Errorf("unsupported Node type: %s", c.NodeType) } diff --git a/conf/cert.go b/conf/cert.go index 9ef89b1..7ea0014 100644 --- a/conf/cert.go +++ b/conf/cert.go @@ -9,16 +9,4 @@ type CertConfig struct { Provider string `yaml:"Provider"` // alidns, cloudflare, gandi, godaddy.... Email string `yaml:"Email"` DNSEnv map[string]string `yaml:"DNSEnv"` - RealityConfig *RealityConfig `yaml:"RealityConfig"` -} - -type RealityConfig struct { - Dest string `yaml:"Dest" json:"Dest"` - Xver uint64 `yaml:"Xver" json:"Xver"` - ServerNames []string `yaml:"ServerNames" json:"ServerNames"` - PrivateKey string `yaml:"PrivateKey" json:"PrivateKey"` - MinClientVer string `yaml:"MinClientVer" json:"MinClientVer"` - MaxClientVer string `yaml:"MaxClientVer" json:"MaxClientVer"` - MaxTimeDiff uint64 `yaml:"MaxTimeDiff" json:"MaxTimeDiff"` - ShortIds []string `yaml:"ShortIds" json:"ShortIds"` } diff --git a/core/interface.go b/core/interface.go index 7d47148..cfd593a 100644 --- a/core/interface.go +++ b/core/interface.go @@ -6,11 +6,11 @@ import ( ) type AddUsersParams struct { - Tag string - Config *conf.Options - UserInfo []panel.UserInfo - NodeInfo *panel.NodeInfo + Tag string + Users []panel.UserInfo + *panel.NodeInfo } + type Core interface { Start() error Close() error diff --git a/core/sing/node.go b/core/sing/node.go index 2bccf4c..b25f8ff 100644 --- a/core/sing/node.go +++ b/core/sing/node.go @@ -5,7 +5,6 @@ import ( "crypto/rand" "encoding/base64" "fmt" - "github.com/google/uuid" "net/netip" "net/url" "strconv" @@ -33,7 +32,7 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio } listen := option.ListenOptions{ Listen: (*option.ListenAddress)(&addr), - ListenPort: uint16(info.Port), + ListenPort: uint16(info.Common.ServerPort), ProxyProtocol: c.SingOptions.EnableProxyProtocol, TCPFastOpen: c.SingOptions.TCPFastOpen, InboundOptions: option.InboundOptions{ @@ -42,83 +41,56 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio }, } var tls option.InboundTLSOptions - if info.Tls || info.Type == "hysteria" { + switch info.Security { + case panel.Tls: if c.CertConfig == nil { return option.Inbound{}, fmt.Errorf("the CertConfig is not vail") } - tls.Enabled = true - tls.Insecure = true - tls.ServerName = info.ServerName switch c.CertConfig.CertMode { case "none", "": break // disable - case "reality": - if c.CertConfig.RealityConfig == nil { - return option.Inbound{}, fmt.Errorf("RealityConfig is not valid") - } - rc := c.CertConfig.RealityConfig - tls.ServerName = rc.ServerNames[0] - if len(rc.ShortIds) == 0 { - rc.ShortIds = []string{""} - } - dest, _ := strconv.Atoi(rc.Dest) - mtd, _ := strconv.Atoi(strconv.FormatUint(rc.MaxTimeDiff, 10)) - tls.Reality = &option.InboundRealityOptions{ - Enabled: true, - ShortID: rc.ShortIds, - PrivateKey: rc.PrivateKey, - MaxTimeDifference: option.Duration(time.Duration(mtd) * time.Second), - Handshake: option.InboundRealityHandshakeOptions{ - ServerOptions: option.ServerOptions{ - Server: rc.ServerNames[0], - ServerPort: uint16(dest), - }, - }, - } - - case "remote": - if info.ExtraConfig.EnableReality == "true" { - if c.CertConfig.RealityConfig == nil { - return option.Inbound{}, fmt.Errorf("RealityConfig is not valid") - } - rc := info.ExtraConfig.RealityConfig - if len(rc.ShortIds) == 0 { - rc.ShortIds = []string{""} - } - dest, _ := strconv.Atoi(rc.Dest) - mtd, _ := strconv.Atoi(rc.MaxTimeDiff) - tls.Reality = &option.InboundRealityOptions{ - Enabled: true, - ShortID: rc.ShortIds, - PrivateKey: rc.PrivateKey, - MaxTimeDifference: option.Duration(time.Duration(mtd) * time.Second), - Handshake: option.InboundRealityHandshakeOptions{ - ServerOptions: option.ServerOptions{ - Server: rc.ServerNames[0], - ServerPort: uint16(dest), - }, - }, - } - } default: + tls.Enabled = true tls.CertificatePath = c.CertConfig.CertFile tls.KeyPath = c.CertConfig.KeyFile } + case panel.Reality: + tls.Enabled = true + v := info.VAllss + tls.ServerName = v.TlsSettings.PrivateKey + if len(v.TlsSettings.ShortIds) == 0 { + v.TlsSettings.ShortIds = []string{""} + } + dest, _ := strconv.Atoi(v.TlsSettings.ServerPort) + mtd, _ := strconv.Atoi(strconv.FormatUint(v.RealityConfig.MaxTimeDiff, 10)) + tls.Reality = &option.InboundRealityOptions{ + Enabled: true, + ShortID: v.TlsSettings.ShortIds, + PrivateKey: v.TlsSettings.PrivateKey, + MaxTimeDifference: option.Duration(time.Duration(mtd) * time.Second), + Handshake: option.InboundRealityHandshakeOptions{ + ServerOptions: option.ServerOptions{ + Server: v.TlsSettings.ServerName[0], + ServerPort: uint16(dest), + }, + }, + } } in := option.Inbound{ Tag: tag, } switch info.Type { - case "v2ray": + case "vmess", "vless": + n := info.VAllss t := option.V2RayTransportOptions{ - Type: info.Network, + Type: n.Network, } - switch info.Network { + switch n.Network { case "tcp": t.Type = "" case "ws": network := WsNetworkConfig{} - err := json.Unmarshal(info.NetworkSettings, &network) + err := json.Unmarshal(n.NetworkSettings, &network) if err != nil { return option.Inbound{}, fmt.Errorf("decode NetworkSettings error: %s", err) } @@ -141,12 +113,13 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio Headers: h, } case "grpc": - err := json.Unmarshal(info.NetworkSettings, &t.GRPCOptions) + err := json.Unmarshal(n.NetworkSettings, &t.GRPCOptions) if err != nil { return option.Inbound{}, fmt.Errorf("decode NetworkSettings error: %s", err) } } - if info.ExtraConfig.EnableVless == "true" { + tls.ServerName = n.ServerName + if info.Type == "vless" { in.Type = "vless" in.VLESSOptions = option.VLESSInboundOptions{ ListenOptions: listen, @@ -163,8 +136,9 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio } case "shadowsocks": in.Type = "shadowsocks" + n := info.Shadowsocks var keyLength int - switch info.Cipher { + switch n.Cipher { case "2022-blake3-aes-128-gcm": keyLength = 16 case "2022-blake3-aes-256-gcm": @@ -174,13 +148,13 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio } in.ShadowsocksOptions = option.ShadowsocksInboundOptions{ ListenOptions: listen, - Method: info.Cipher, + Method: n.Cipher, } p := make([]byte, keyLength) _, _ = rand.Read(p) randomPasswd := string(p) - if strings.Contains(info.Cipher, "2022") { - in.ShadowsocksOptions.Password = info.ServerKey + if strings.Contains(n.Cipher, "2022") { + in.ShadowsocksOptions.Password = n.ServerKey randomPasswd = base64.StdEncoding.EncodeToString([]byte(randomPasswd)) } in.ShadowsocksOptions.Users = []option.ShadowsocksUser{{ @@ -188,27 +162,9 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio }} case "trojan": in.Type = "trojan" - t := option.V2RayTransportOptions{ - Type: info.Network, - } - switch info.Network { - case "tcp": - t.Type = "" - case "grpc": - err := json.Unmarshal(info.NetworkSettings, &t.GRPCOptions) - if err != nil { - return option.Inbound{}, fmt.Errorf("decode NetworkSettings error: %s", err) - } - } - randomPasswd := uuid.New().String() in.TrojanOptions = option.TrojanInboundOptions{ ListenOptions: listen, - Users: []option.TrojanUser{{ - Name: randomPasswd, - Password: randomPasswd, - }}, - TLS: &tls, - Transport: &t, + TLS: &tls, } if c.SingOptions.FallBackConfigs != nil { // fallback handling @@ -230,9 +186,9 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio in.Type = "hysteria" in.HysteriaOptions = option.HysteriaInboundOptions{ ListenOptions: listen, - UpMbps: info.UpMbps, - DownMbps: info.DownMbps, - Obfs: info.HyObfs, + UpMbps: info.Hysteria.UpMbps, + DownMbps: info.Hysteria.DownMbps, + Obfs: info.Hysteria.Obfs, TLS: &tls, } } diff --git a/core/sing/sing.go b/core/sing/sing.go index 07c7d04..61f7564 100644 --- a/core/sing/sing.go +++ b/core/sing/sing.go @@ -264,7 +264,8 @@ func (b *Box) Router() adapter.Router { func (b *Box) Protocols() []string { return []string{ - "v2ray", + "vmess", + "vless", "shadowsocks", "trojan", "hysteria", diff --git a/core/sing/user.go b/core/sing/user.go index d79b1fd..dd476e8 100644 --- a/core/sing/user.go +++ b/core/sing/user.go @@ -13,58 +13,58 @@ import ( func (b *Box) AddUsers(p *core.AddUsersParams) (added int, err error) { switch p.NodeInfo.Type { - case "v2ray": - if p.NodeInfo.ExtraConfig.EnableVless == "true" { - us := make([]option.VLESSUser, len(p.UserInfo)) - for i := range p.UserInfo { + case "vmess", "vless": + if p.NodeInfo.Type == "vless" { + us := make([]option.VLESSUser, len(p.Users)) + for i := range p.Users { us[i] = option.VLESSUser{ - Name: p.UserInfo[i].Uuid, - Flow: p.NodeInfo.ExtraConfig.VlessFlow, - UUID: p.UserInfo[i].Uuid, + Name: p.Users[i].Uuid, + Flow: p.VAllss.Flow, + UUID: p.Users[i].Uuid, } } err = b.inbounds[p.Tag].(*inbound.VLESS).AddUsers(us) } else { - us := make([]option.VMessUser, len(p.UserInfo)) - for i := range p.UserInfo { + us := make([]option.VMessUser, len(p.Users)) + for i := range p.Users { us[i] = option.VMessUser{ - Name: p.UserInfo[i].Uuid, - UUID: p.UserInfo[i].Uuid, + Name: p.Users[i].Uuid, + UUID: p.Users[i].Uuid, } } err = b.inbounds[p.Tag].(*inbound.VMess).AddUsers(us) } case "shadowsocks": - us := make([]option.ShadowsocksUser, len(p.UserInfo)) - for i := range p.UserInfo { - var password = p.UserInfo[i].Uuid - switch p.NodeInfo.Cipher { + us := make([]option.ShadowsocksUser, len(p.Users)) + for i := range p.Users { + var password = p.Users[i].Uuid + switch p.Shadowsocks.Cipher { case "2022-blake3-aes-128-gcm": password = base64.StdEncoding.EncodeToString([]byte(password[:16])) case "2022-blake3-aes-256-gcm": password = base64.StdEncoding.EncodeToString([]byte(password[:32])) } us[i] = option.ShadowsocksUser{ - Name: p.UserInfo[i].Uuid, + Name: p.Users[i].Uuid, Password: password, } } err = b.inbounds[p.Tag].(*inbound.ShadowsocksMulti).AddUsers(us) case "trojan": - us := make([]option.TrojanUser, len(p.UserInfo)) - for i := range p.UserInfo { + us := make([]option.TrojanUser, len(p.Users)) + for i := range p.Users { us[i] = option.TrojanUser{ - Name: p.UserInfo[i].Uuid, - Password: p.UserInfo[i].Uuid, + Name: p.Users[i].Uuid, + Password: p.Users[i].Uuid, } } err = b.inbounds[p.Tag].(*inbound.Trojan).AddUsers(us) case "hysteria": - us := make([]option.HysteriaUser, len(p.UserInfo)) - for i := range p.UserInfo { + us := make([]option.HysteriaUser, len(p.Users)) + for i := range p.Users { us[i] = option.HysteriaUser{ - Name: p.UserInfo[i].Uuid, - AuthString: p.UserInfo[i].Uuid, + Name: p.Users[i].Uuid, + AuthString: p.Users[i].Uuid, } } err = b.inbounds[p.Tag].(*inbound.Hysteria).AddUsers(us) @@ -72,7 +72,7 @@ func (b *Box) AddUsers(p *core.AddUsersParams) (added int, err error) { if err != nil { return 0, err } - return len(p.UserInfo), err + return len(p.Users), err } func (b *Box) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64) { diff --git a/core/xray/inbound.go b/core/xray/inbound.go index 44320bb..0a45501 100644 --- a/core/xray/inbound.go +++ b/core/xray/inbound.go @@ -6,8 +6,6 @@ import ( "encoding/hex" "errors" "fmt" - "strconv" - "github.com/InazumaV/V2bX/api/panel" "github.com/InazumaV/V2bX/conf" "github.com/goccy/go-json" @@ -17,141 +15,121 @@ import ( ) // BuildInbound build Inbound config for different protocol -func buildInbound(config *conf.Options, nodeInfo *panel.NodeInfo, tag string) (*core.InboundHandlerConfig, error) { +func buildInbound(option *conf.Options, nodeInfo *panel.NodeInfo, tag string) (*core.InboundHandlerConfig, error) { in := &coreConf.InboundDetourConfig{} - // Set network protocol - t := coreConf.TransportProtocol(nodeInfo.Network) - in.StreamSetting = &coreConf.StreamConfig{Network: &t} var err error + var network string switch nodeInfo.Type { case "v2ray": - err = buildV2ray(config, nodeInfo, in) + err = buildV2ray(option, nodeInfo, in) + network = nodeInfo.VAllss.Network case "trojan": - err = buildTrojan(config, in) + err = buildTrojan(option, in) case "shadowsocks": - err = buildShadowsocks(config, nodeInfo, in) + err = buildShadowsocks(option, nodeInfo, in) default: return nil, fmt.Errorf("unsupported node type: %s, Only support: V2ray, Trojan, Shadowsocks", nodeInfo.Type) } if err != nil { return nil, err } + // Set network protocol + t := coreConf.TransportProtocol(network) + in.StreamSetting = &coreConf.StreamConfig{Network: &t} // Set server port in.PortList = &coreConf.PortList{ - Range: []coreConf.PortRange{{From: uint32(nodeInfo.Port), To: uint32(nodeInfo.Port)}}, + Range: []coreConf.PortRange{ + { + From: uint32(nodeInfo.Common.ServerPort), + To: uint32(nodeInfo.Common.ServerPort), + }}, } // Set Listen IP address - ipAddress := net.ParseAddress(config.ListenIP) + ipAddress := net.ParseAddress(option.ListenIP) in.ListenOn = &coreConf.Address{Address: ipAddress} // Set SniffingConfig sniffingConfig := &coreConf.SniffingConfig{ Enabled: true, DestOverride: &coreConf.StringList{"http", "tls"}, } - if config.XrayOptions.DisableSniffing { + if option.XrayOptions.DisableSniffing { sniffingConfig.Enabled = false } in.SniffingConfig = sniffingConfig - if *in.StreamSetting.Network == "tcp" { + switch network { + case "tcp": if in.StreamSetting.TCPSettings != nil { - in.StreamSetting.TCPSettings.AcceptProxyProtocol = config.XrayOptions.EnableProxyProtocol + in.StreamSetting.TCPSettings.AcceptProxyProtocol = option.XrayOptions.EnableProxyProtocol } else { tcpSetting := &coreConf.TCPConfig{ - AcceptProxyProtocol: config.XrayOptions.EnableProxyProtocol, + AcceptProxyProtocol: option.XrayOptions.EnableProxyProtocol, } //Enable proxy protocol in.StreamSetting.TCPSettings = tcpSetting } - } else if *in.StreamSetting.Network == "ws" { + case "ws": in.StreamSetting.WSSettings = &coreConf.WebSocketConfig{ - AcceptProxyProtocol: config.XrayOptions.EnableProxyProtocol} //Enable proxy protocol - } - // Set TLS or Reality settings - if nodeInfo.Tls { - if config.CertConfig == nil { - return nil, errors.New("the CertConfig is not vail") - } - switch config.CertConfig.CertMode { - case "none", "": - break // disable - case "reality": - // Reality - in.StreamSetting.Security = "reality" - d, err := json.Marshal(config.CertConfig.RealityConfig.Dest) - if err != nil { - return nil, fmt.Errorf("marshal reality dest error: %s", err) - } - if len(config.CertConfig.RealityConfig.ShortIds) == 0 { - config.CertConfig.RealityConfig.ShortIds = []string{""} - } - in.StreamSetting.REALITYSettings = &coreConf.REALITYConfig{ - Dest: d, - Xver: config.CertConfig.RealityConfig.Xver, - ServerNames: config.CertConfig.RealityConfig.ServerNames, - PrivateKey: config.CertConfig.RealityConfig.PrivateKey, - MinClientVer: config.CertConfig.RealityConfig.MinClientVer, - MaxClientVer: config.CertConfig.RealityConfig.MaxClientVer, - MaxTimeDiff: config.CertConfig.RealityConfig.MaxTimeDiff, - ShortIds: config.CertConfig.RealityConfig.ShortIds, - } - break - case "remote": - if nodeInfo.ExtraConfig.EnableReality == "true" { - rc := nodeInfo.ExtraConfig.RealityConfig - in.StreamSetting.Security = "reality" - d, err := json.Marshal(rc.Dest) - if err != nil { - return nil, fmt.Errorf("marshal reality dest error: %s", err) - } - if len(rc.ShortIds) == 0 { - rc.ShortIds = []string{""} - } - Xver, _ := strconv.ParseUint(rc.Xver, 10, 64) - MaxTimeDiff, _ := strconv.ParseUint(rc.Xver, 10, 64) - in.StreamSetting.REALITYSettings = &coreConf.REALITYConfig{ - Dest: d, - Xver: Xver, - ServerNames: rc.ServerNames, - PrivateKey: rc.PrivateKey, - MinClientVer: rc.MinClientVer, - MaxClientVer: rc.MaxClientVer, - MaxTimeDiff: MaxTimeDiff, - ShortIds: rc.ShortIds, - } - break - } - default: - { - // Normal tls - in.StreamSetting.Security = "tls" - in.StreamSetting.TLSSettings = &coreConf.TLSConfig{ - Certs: []*coreConf.TLSCertConfig{ - { - CertFile: config.CertConfig.CertFile, - KeyFile: config.CertConfig.KeyFile, - OcspStapling: 3600, - }, - }, - RejectUnknownSNI: config.CertConfig.RejectUnknownSni, - } - } - } - } - // Support ProxyProtocol for any transport protocol - if *in.StreamSetting.Network != "tcp" && - *in.StreamSetting.Network != "ws" && - config.XrayOptions.EnableProxyProtocol { + AcceptProxyProtocol: option.XrayOptions.EnableProxyProtocol} //Enable proxy protocol + default: socketConfig := &coreConf.SocketConfig{ - AcceptProxyProtocol: config.XrayOptions.EnableProxyProtocol, - TFO: config.XrayOptions.EnableTFO, + AcceptProxyProtocol: option.XrayOptions.EnableProxyProtocol, + TFO: option.XrayOptions.EnableTFO, } //Enable proxy protocol in.StreamSetting.SocketSettings = socketConfig } + // Set TLS or Reality settings + switch nodeInfo.Security { + case panel.Tls: + // Normal tls + if option.CertConfig == nil { + return nil, errors.New("the CertConfig is not vail") + } + switch option.CertConfig.CertMode { + case "none", "": + break // disable + default: + in.StreamSetting.Security = "tls" + in.StreamSetting.TLSSettings = &coreConf.TLSConfig{ + Certs: []*coreConf.TLSCertConfig{ + { + CertFile: option.CertConfig.CertFile, + KeyFile: option.CertConfig.KeyFile, + OcspStapling: 3600, + }, + }, + RejectUnknownSNI: option.CertConfig.RejectUnknownSni, + } + } + case panel.Reality: + // Reality + in.StreamSetting.Security = "reality" + v := nodeInfo.VAllss + d, err := json.Marshal(v.RealityConfig.Dest) + if err != nil { + return nil, fmt.Errorf("marshal reality dest error: %s", err) + } + short := nodeInfo.VAllss.TlsSettings.ShortIds + if len(short) == 0 { + short = []string{""} + } + in.StreamSetting.REALITYSettings = &coreConf.REALITYConfig{ + Dest: d, + Xver: v.RealityConfig.Xver, + ServerNames: v.TlsSettings.ServerName, + PrivateKey: v.TlsSettings.PrivateKey, + MinClientVer: v.RealityConfig.MinClientVer, + MaxClientVer: v.RealityConfig.MaxClientVer, + MaxTimeDiff: v.RealityConfig.MaxTimeDiff, + ShortIds: short, + } + break + } in.Tag = tag return in.Build() } func buildV2ray(config *conf.Options, nodeInfo *panel.NodeInfo, inbound *coreConf.InboundDetourConfig) error { - if nodeInfo.ExtraConfig.EnableVless == "true" { + v := nodeInfo.VAllss + if nodeInfo.Type == "vless" { //Set vless inbound.Protocol = "vless" if config.XrayOptions.EnableFallback { @@ -188,22 +166,22 @@ func buildV2ray(config *conf.Options, nodeInfo *panel.NodeInfo, inbound *coreCon } inbound.Settings = (*json.RawMessage)(&s) } - if len(nodeInfo.NetworkSettings) == 0 { + if len(v.NetworkSettings) == 0 { return nil } - switch nodeInfo.Network { + switch v.Network { case "tcp": - err := json.Unmarshal(nodeInfo.NetworkSettings, &inbound.StreamSetting.TCPSettings) + err := json.Unmarshal(v.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) + err := json.Unmarshal(v.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) + err := json.Unmarshal(v.NetworkSettings, &inbound.StreamSetting.GRPCConfig) if err != nil { return fmt.Errorf("unmarshal grpc settings error: %s", err) } @@ -239,8 +217,9 @@ func buildTrojan(config *conf.Options, inbound *coreConf.InboundDetourConfig) er func buildShadowsocks(config *conf.Options, nodeInfo *panel.NodeInfo, inbound *coreConf.InboundDetourConfig) error { inbound.Protocol = "shadowsocks" + s := nodeInfo.Shadowsocks settings := &coreConf.ShadowsocksServerConfig{ - Cipher: nodeInfo.Cipher, + Cipher: s.Cipher, } p := make([]byte, 32) _, err := rand.Read(p) @@ -248,9 +227,9 @@ func buildShadowsocks(config *conf.Options, nodeInfo *panel.NodeInfo, inbound *c return fmt.Errorf("generate random password error: %s", err) } randomPasswd := hex.EncodeToString(p) - cipher := nodeInfo.Cipher - if nodeInfo.ServerKey != "" { - settings.Password = nodeInfo.ServerKey + cipher := s.Cipher + if s.ServerKey != "" { + settings.Password = s.ServerKey randomPasswd = base64.StdEncoding.EncodeToString([]byte(randomPasswd)) cipher = "" } @@ -266,8 +245,8 @@ func buildShadowsocks(config *conf.Options, nodeInfo *panel.NodeInfo, inbound *c } t := coreConf.TransportProtocol("tcp") inbound.StreamSetting = &coreConf.StreamConfig{Network: &t} - s, err := json.Marshal(settings) - inbound.Settings = (*json.RawMessage)(&s) + sets, err := json.Marshal(settings) + inbound.Settings = (*json.RawMessage)(&sets) if err != nil { return fmt.Errorf("marshal shadowsocks settings error: %s", err) } diff --git a/core/xray/user.go b/core/xray/user.go index 2fc6351..a1c86c7 100644 --- a/core/xray/user.go +++ b/core/xray/user.go @@ -71,21 +71,19 @@ func (c *Core) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int6 } func (c *Core) AddUsers(p *vCore.AddUsersParams) (added int, err error) { - users := make([]*protocol.User, 0, len(p.UserInfo)) + users := make([]*protocol.User, 0, len(p.Users)) switch p.NodeInfo.Type { - case "v2ray": - if p.NodeInfo.ExtraConfig.EnableVless == "true" { - users = buildVlessUsers(p.Tag, p.UserInfo, p.NodeInfo.ExtraConfig.VlessFlow) - } else { - users = buildVmessUsers(p.Tag, p.UserInfo) - } + case "vmess": + users = buildVmessUsers(p.Tag, p.Users) + case "vless": + users = buildVlessUsers(p.Tag, p.Users, p.VAllss.Flow) case "trojan": - users = buildTrojanUsers(p.Tag, p.UserInfo) + users = buildTrojanUsers(p.Tag, p.Users) case "shadowsocks": users = buildSSUsers(p.Tag, - p.UserInfo, - p.NodeInfo.Cipher, - p.NodeInfo.ServerKey) + p.Users, + p.Shadowsocks.Cipher, + p.Shadowsocks.ServerKey) default: return 0, fmt.Errorf("unsupported node type: %s", p.NodeInfo.Type) } diff --git a/core/xray/xray.go b/core/xray/xray.go index f03102f..71a4ca7 100644 --- a/core/xray/xray.go +++ b/core/xray/xray.go @@ -188,7 +188,8 @@ func (c *Core) Close() error { func (c *Core) Protocols() []string { return []string{ - "v2ray", + "vmess", + "vless", "shadowsocks", "trojan", } diff --git a/node/cert.go b/node/cert.go index 425efee..55c0cf0 100644 --- a/node/cert.go +++ b/node/cert.go @@ -31,7 +31,7 @@ func (c *Controller) renewCertTask() error { func (c *Controller) requestCert() error { switch c.CertConfig.CertMode { - case "reality", "none", "": + case "none", "": case "file": if c.CertConfig.CertFile == "" || c.CertConfig.KeyFile == "" { return fmt.Errorf("cert file path or key file path not exist") diff --git a/node/controller.go b/node/controller.go index 84daebb..5c25085 100644 --- a/node/controller.go +++ b/node/controller.go @@ -65,7 +65,7 @@ func (c *Controller) Start() error { return fmt.Errorf("update rule error: %s", err) } c.limiter = l - if node.Tls || node.Type == "hysteria" { + if node.Security == panel.Tls { err = c.requestCert() if err != nil { return fmt.Errorf("request cert error: %s", err) @@ -78,8 +78,7 @@ func (c *Controller) Start() error { } added, err := c.server.AddUsers(&vCore.AddUsersParams{ Tag: c.tag, - Config: c.Options, - UserInfo: c.userList, + Users: c.userList, NodeInfo: node, }) if err != nil { diff --git a/node/task.go b/node/task.go index b2c3c03..639fc9e 100644 --- a/node/task.go +++ b/node/task.go @@ -26,9 +26,9 @@ func (c *Controller) startTasks(node *panel.NodeInfo) { _ = c.nodeInfoMonitorPeriodic.Start(false) log.WithField("tag", c.tag).Info("Start report node status") _ = c.userReportPeriodic.Start(false) - if node.Tls { + if node.Security == panel.Tls { switch c.CertConfig.CertMode { - case "reality", "none", "", "file": + case "none", "", "file", "self": default: c.renewCertPeriodic = &task.Task{ Interval: time.Hour * 24, @@ -51,7 +51,7 @@ func (c *Controller) startTasks(node *panel.NodeInfo) { func (c *Controller) nodeInfoMonitor() (err error) { // get node info - newNodeInfo, err := c.apiClient.GetNodeInfo() + newN, err := c.apiClient.GetNodeInfo() if err != nil { log.WithFields(log.Fields{ "tag": c.tag, @@ -60,7 +60,7 @@ func (c *Controller) nodeInfoMonitor() (err error) { return nil } // get user info - newUserInfo, err := c.apiClient.GetUserList() + newU, err := c.apiClient.GetUserList() if err != nil { log.WithFields(log.Fields{ "tag": c.tag, @@ -68,11 +68,11 @@ func (c *Controller) nodeInfoMonitor() (err error) { }).Error("Get user list failed") return nil } - if newNodeInfo != nil { - c.info = newNodeInfo + if newN != nil { + c.info = newN // nodeInfo changed - if newUserInfo != nil { - c.userList = newUserInfo + if newU != nil { + c.userList = newU } c.traffic = make(map[string]int64) // Remove old tag @@ -88,10 +88,10 @@ func (c *Controller) nodeInfoMonitor() (err error) { // Remove Old limiter limiter.DeleteLimiter(c.tag) // Add new Limiter - c.tag = c.buildNodeTag(newNodeInfo) + c.tag = c.buildNodeTag(newN) l := limiter.AddLimiter(c.tag, &c.LimitConfig, c.userList) // check cert - if newNodeInfo.Tls || newNodeInfo.Type == "hysteria" { + if newN.Security == panel.Tls { err = c.requestCert() if err != nil { log.WithFields(log.Fields{ @@ -102,7 +102,7 @@ func (c *Controller) nodeInfoMonitor() (err error) { } } // add new node - err = c.server.AddNode(c.tag, newNodeInfo, c.Options) + err = c.server.AddNode(c.tag, newN, c.Options) if err != nil { log.WithFields(log.Fields{ "tag": c.tag, @@ -112,9 +112,8 @@ func (c *Controller) nodeInfoMonitor() (err error) { } _, err = c.server.AddUsers(&vCore.AddUsersParams{ Tag: c.tag, - Config: c.Options, - UserInfo: c.userList, - NodeInfo: newNodeInfo, + Users: c.userList, + NodeInfo: newN, }) if err != nil { log.WithFields(log.Fields{ @@ -123,7 +122,7 @@ func (c *Controller) nodeInfoMonitor() (err error) { }).Error("Add users failed") return nil } - err = l.UpdateRule(&newNodeInfo.Rules) + err = l.UpdateRule(&newN.Rules) if err != nil { log.WithFields(log.Fields{ "tag": c.tag, @@ -133,15 +132,15 @@ func (c *Controller) nodeInfoMonitor() (err error) { } c.limiter = l // Check interval - if c.nodeInfoMonitorPeriodic.Interval != newNodeInfo.PullInterval && - newNodeInfo.PullInterval != 0 { - c.nodeInfoMonitorPeriodic.Interval = newNodeInfo.PullInterval + if c.nodeInfoMonitorPeriodic.Interval != newN.PullInterval && + newN.PullInterval != 0 { + c.nodeInfoMonitorPeriodic.Interval = newN.PullInterval c.nodeInfoMonitorPeriodic.Close() _ = c.nodeInfoMonitorPeriodic.Start(false) } - if c.userReportPeriodic.Interval != newNodeInfo.PushInterval && - newNodeInfo.PushInterval != 0 { - c.userReportPeriodic.Interval = newNodeInfo.PullInterval + if c.userReportPeriodic.Interval != newN.PushInterval && + newN.PushInterval != 0 { + c.userReportPeriodic.Interval = newN.PullInterval c.userReportPeriodic.Close() _ = c.userReportPeriodic.Start(false) } @@ -151,10 +150,10 @@ func (c *Controller) nodeInfoMonitor() (err error) { } // node no changed, check users - if len(newUserInfo) == 0 { + if len(newU) == 0 { return nil } - deleted, added := compareUserList(c.userList, newUserInfo) + deleted, added := compareUserList(c.userList, newU) if len(deleted) > 0 { // have deleted users err = c.server.DelUsers(deleted, c.tag) @@ -170,9 +169,8 @@ func (c *Controller) nodeInfoMonitor() (err error) { // have added users _, err = c.server.AddUsers(&vCore.AddUsersParams{ Tag: c.tag, - Config: c.Options, NodeInfo: c.info, - UserInfo: added, + Users: added, }) if err != nil { log.WithFields(log.Fields{ @@ -199,7 +197,7 @@ func (c *Controller) nodeInfoMonitor() (err error) { } } } - c.userList = newUserInfo + c.userList = newU if len(added)+len(deleted) != 0 { log.WithField("tag", c.tag). Infof("%d user deleted, %d user added", len(deleted), len(added))