refactor NodeInfo

This commit is contained in:
yuzuki999 2023-08-19 20:06:42 +08:00
parent 42e86bf94c
commit 42407d5c62
13 changed files with 333 additions and 391 deletions

View File

@ -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 {
// 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"`
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)
// 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 common params error: %s", err)
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
}

View File

@ -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)
}

View File

@ -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"`
}

View File

@ -7,10 +7,10 @@ import (
type AddUsersParams struct {
Tag string
Config *conf.Options
UserInfo []panel.UserInfo
NodeInfo *panel.NodeInfo
Users []panel.UserInfo
*panel.NodeInfo
}
type Core interface {
Start() error
Close() error

View File

@ -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,
}
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,
}
}

View File

@ -264,7 +264,8 @@ func (b *Box) Router() adapter.Router {
func (b *Box) Protocols() []string {
return []string{
"v2ray",
"vmess",
"vless",
"shadowsocks",
"trojan",
"hysteria",

View File

@ -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) {

View File

@ -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
AcceptProxyProtocol: option.XrayOptions.EnableProxyProtocol} //Enable proxy protocol
default:
socketConfig := &coreConf.SocketConfig{
AcceptProxyProtocol: option.XrayOptions.EnableProxyProtocol,
TFO: option.XrayOptions.EnableTFO,
} //Enable proxy protocol
in.StreamSetting.SocketSettings = socketConfig
}
// Set TLS or Reality settings
if nodeInfo.Tls {
if config.CertConfig == nil {
switch nodeInfo.Security {
case panel.Tls:
// Normal tls
if option.CertConfig == nil {
return nil, errors.New("the CertConfig is not vail")
}
switch config.CertConfig.CertMode {
switch option.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,
CertFile: option.CertConfig.CertFile,
KeyFile: option.CertConfig.KeyFile,
OcspStapling: 3600,
},
},
RejectUnknownSNI: config.CertConfig.RejectUnknownSni,
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{""}
}
// Support ProxyProtocol for any transport protocol
if *in.StreamSetting.Network != "tcp" &&
*in.StreamSetting.Network != "ws" &&
config.XrayOptions.EnableProxyProtocol {
socketConfig := &coreConf.SocketConfig{
AcceptProxyProtocol: config.XrayOptions.EnableProxyProtocol,
TFO: config.XrayOptions.EnableTFO,
} //Enable proxy protocol
in.StreamSetting.SocketSettings = socketConfig
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)
}

View File

@ -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)
}

View File

@ -188,7 +188,8 @@ func (c *Core) Close() error {
func (c *Core) Protocols() []string {
return []string{
"v2ray",
"vmess",
"vless",
"shadowsocks",
"trojan",
}

View File

@ -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")

View File

@ -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 {

View File

@ -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))