2022-08-16 01:04:33 -04:00
|
|
|
package panel
|
2022-06-04 00:05:46 -04:00
|
|
|
|
|
|
|
import (
|
2023-07-19 00:03:09 -04:00
|
|
|
"bytes"
|
2023-07-15 07:37:44 -04:00
|
|
|
"encoding/base64"
|
2023-06-08 10:46:33 -04:00
|
|
|
"fmt"
|
2023-07-19 00:03:09 -04:00
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
coreConf "github.com/xtls/xray-core/infra/conf"
|
|
|
|
"os"
|
2023-05-17 21:11:28 -04:00
|
|
|
"reflect"
|
2022-06-04 00:05:46 -04:00
|
|
|
"regexp"
|
2022-12-18 10:31:06 -05:00
|
|
|
"strconv"
|
2023-01-06 12:59:24 -05:00
|
|
|
"strings"
|
2023-05-17 21:11:28 -04:00
|
|
|
"time"
|
2023-07-14 00:54:09 -04:00
|
|
|
|
|
|
|
"github.com/Yuzuki616/V2bX/common/crypt"
|
|
|
|
|
|
|
|
"github.com/goccy/go-json"
|
2022-06-04 00:05:46 -04:00
|
|
|
)
|
|
|
|
|
2023-06-08 10:46:33 -04:00
|
|
|
type CommonNodeRsp struct {
|
2023-06-09 00:36:49 -04:00
|
|
|
Host string `json:"host"`
|
2023-06-08 10:46:33 -04:00
|
|
|
ServerPort int `json:"server_port"`
|
2023-06-09 00:36:49 -04:00
|
|
|
ServerName string `json:"server_name"`
|
2023-06-08 10:46:33 -04:00
|
|
|
Routes []Route `json:"routes"`
|
|
|
|
BaseConfig BaseConfig `json:"base_config"`
|
2022-12-18 10:31:06 -05:00
|
|
|
}
|
2023-06-08 10:46:33 -04:00
|
|
|
|
2022-12-18 10:31:06 -05:00
|
|
|
type Route struct {
|
2023-01-06 12:59:24 -05:00
|
|
|
Id int `json:"id"`
|
|
|
|
Match interface{} `json:"match"`
|
|
|
|
Action string `json:"action"`
|
2022-12-18 10:31:06 -05:00
|
|
|
//ActionValue interface{} `json:"action_value"`
|
|
|
|
}
|
|
|
|
type BaseConfig struct {
|
|
|
|
PushInterval any `json:"push_interval"`
|
|
|
|
PullInterval any `json:"pull_interval"`
|
2022-09-14 21:24:14 -04:00
|
|
|
}
|
2022-06-04 00:05:46 -04:00
|
|
|
|
2023-06-08 10:46:33 -04:00
|
|
|
type V2rayNodeRsp struct {
|
|
|
|
Tls int `json:"tls"`
|
|
|
|
Network string `json:"network"`
|
|
|
|
NetworkSettings json.RawMessage `json:"networkSettings"`
|
|
|
|
ServerName string `json:"server_name"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type ShadowsocksNodeRsp struct {
|
|
|
|
Cipher string `json:"cipher"`
|
|
|
|
ServerKey string `json:"server_key"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type HysteriaNodeRsp struct {
|
|
|
|
UpMbps int `json:"up_mbps"`
|
|
|
|
DownMbps int `json:"down_mbps"`
|
|
|
|
Obfs string `json:"obfs"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type NodeInfo struct {
|
|
|
|
Id int
|
|
|
|
Type string
|
|
|
|
Rules []*regexp.Regexp
|
2023-06-09 00:36:49 -04:00
|
|
|
Host string
|
2023-06-08 10:46:33 -04:00
|
|
|
Port int
|
|
|
|
Network string
|
2023-06-24 20:22:05 -04:00
|
|
|
ExtraConfig V2rayExtraConfig
|
2023-06-08 10:46:33 -04:00
|
|
|
NetworkSettings json.RawMessage
|
|
|
|
Tls bool
|
|
|
|
ServerName string
|
|
|
|
UpMbps int
|
|
|
|
DownMbps int
|
|
|
|
ServerKey string
|
|
|
|
Cipher string
|
|
|
|
HyObfs string
|
|
|
|
PushInterval time.Duration
|
|
|
|
PullInterval time.Duration
|
|
|
|
}
|
|
|
|
|
2023-06-24 20:22:05 -04:00
|
|
|
type V2rayExtraConfig struct {
|
2023-07-19 11:41:42 -04:00
|
|
|
EnableVless string `json:"EnableVless"`
|
2023-07-15 07:37:44 -04:00
|
|
|
VlessFlow string `json:"VlessFlow"`
|
2023-07-19 11:41:42 -04:00
|
|
|
EnableReality string `json:"EnableReality"`
|
2023-07-15 07:37:44 -04:00
|
|
|
RealityConfig *RealityConfig `json:"RealityConfig"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type RealityConfig struct {
|
|
|
|
Dest interface{} `yaml:"Dest" json:"Dest"`
|
2023-07-19 11:41:42 -04:00
|
|
|
Xver string `yaml:"Xver" json:"Xver"`
|
2023-07-15 07:37:44 -04:00
|
|
|
ServerNames []string `yaml:"ServerNames" json:"ServerNames"`
|
|
|
|
PrivateKey string `yaml:"PrivateKey" json:"PrivateKey"`
|
|
|
|
MinClientVer string `yaml:"MinClientVer" json:"MinClientVer"`
|
|
|
|
MaxClientVer string `yaml:"MaxClientVer" json:"MaxClientVer"`
|
2023-07-19 11:41:42 -04:00
|
|
|
MaxTimeDiff string `yaml:"MaxTimeDiff" json:"MaxTimeDiff"`
|
2023-07-15 07:37:44 -04:00
|
|
|
ShortIds []string `yaml:"ShortIds" json:"ShortIds"`
|
2023-06-24 20:22:05 -04:00
|
|
|
}
|
|
|
|
|
2023-06-08 10:46:33 -04:00
|
|
|
func (c *Client) GetNodeInfo() (node *NodeInfo, err error) {
|
2022-12-18 10:31:06 -05:00
|
|
|
const path = "/api/v1/server/UniProxy/config"
|
2023-06-24 19:49:51 -04:00
|
|
|
r, err := c.client.
|
|
|
|
R().
|
|
|
|
SetHeader("If-None-Match", c.etag).
|
|
|
|
Get(path)
|
2022-12-18 10:31:06 -05:00
|
|
|
if err = c.checkResponse(r, path, err); err != nil {
|
|
|
|
return
|
2022-06-04 00:05:46 -04:00
|
|
|
}
|
2023-06-24 19:49:51 -04:00
|
|
|
if r.StatusCode() == 304 {
|
2022-09-14 21:24:14 -04:00
|
|
|
return nil, nil
|
2022-06-04 00:05:46 -04:00
|
|
|
}
|
2023-06-08 10:46:33 -04:00
|
|
|
// parse common params
|
2023-06-09 00:36:49 -04:00
|
|
|
node = &NodeInfo{
|
|
|
|
Id: c.NodeId,
|
|
|
|
Type: c.NodeType,
|
|
|
|
}
|
2023-06-08 10:46:33 -04:00
|
|
|
common := CommonNodeRsp{}
|
|
|
|
err = json.Unmarshal(r.Body(), &common)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("decode common params error: %s", err)
|
|
|
|
}
|
|
|
|
for i := range common.Routes { // parse rules from routes
|
2023-06-24 20:22:05 -04:00
|
|
|
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)
|
|
|
|
} else {
|
|
|
|
temp := common.Routes[i].Match.([]interface{})
|
|
|
|
matchs = make([]string, len(temp))
|
|
|
|
for i := range temp {
|
|
|
|
matchs[i] = temp[i].(string)
|
2023-01-06 12:59:24 -05:00
|
|
|
}
|
2023-06-24 20:22:05 -04:00
|
|
|
}
|
|
|
|
switch common.Routes[i].Action {
|
|
|
|
case "block":
|
2023-01-06 12:59:24 -05:00
|
|
|
for _, v := range matchs {
|
2023-06-08 10:46:33 -04:00
|
|
|
node.Rules = append(node.Rules, regexp.MustCompile(v))
|
2023-01-06 12:59:24 -05:00
|
|
|
}
|
2023-06-24 20:22:05 -04:00
|
|
|
case "dns":
|
2023-07-19 00:03:09 -04:00
|
|
|
if matchs[0] != "main" {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
dnsPath := os.Getenv("XRAY_DNS_PATH")
|
|
|
|
if dnsPath == "" {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
dns := []byte(strings.Join(matchs[1:], ""))
|
|
|
|
currentData, err := os.ReadFile(dnsPath)
|
|
|
|
if err != nil {
|
|
|
|
log.WithField("err", err).Panic("Failed to read XRAY_DNS_PATH")
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if !bytes.Equal(currentData, dns) {
|
|
|
|
coreDnsConfig := &coreConf.DNSConfig{}
|
|
|
|
if err = json.NewDecoder(bytes.NewReader(dns)).Decode(coreDnsConfig); err != nil {
|
|
|
|
log.WithField("err", err).Panic("Failed to unmarshal DNS config")
|
|
|
|
}
|
|
|
|
_, err := coreDnsConfig.Build()
|
|
|
|
if err != nil {
|
|
|
|
log.WithField("err", err).Panic("Failed to understand DNS config, Please check: https://xtls.github.io/config/dns.html for help")
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if err = os.Truncate(dnsPath, 0); err != nil {
|
|
|
|
log.WithField("err", err).Panic("Failed to clear XRAY DNS PATH file")
|
|
|
|
}
|
|
|
|
if err = os.WriteFile(dnsPath, dns, 0644); err != nil {
|
|
|
|
log.WithField("err", err).Panic("Failed to write DNS to XRAY DNS PATH file")
|
|
|
|
}
|
|
|
|
}
|
2022-06-04 00:05:46 -04:00
|
|
|
}
|
|
|
|
}
|
2023-06-09 00:36:49 -04:00
|
|
|
node.ServerName = common.ServerName
|
|
|
|
node.Host = common.Host
|
|
|
|
node.Port = common.ServerPort
|
2023-06-08 10:46:33 -04:00
|
|
|
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
|
|
|
|
}
|
2023-07-14 00:54:09 -04:00
|
|
|
err = json.Unmarshal(rsp.NetworkSettings, &node.ExtraConfig)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("decode v2ray extra error: %s", err)
|
|
|
|
}
|
2023-07-19 11:41:42 -04:00
|
|
|
if node.ExtraConfig.EnableReality == "true" {
|
2023-07-15 07:37:44 -04:00
|
|
|
if node.ExtraConfig.RealityConfig == nil {
|
2023-07-19 11:41:42 -04:00
|
|
|
node.ExtraConfig.EnableReality = "false"
|
2023-07-15 07:37:44 -04:00
|
|
|
} else {
|
|
|
|
key := crypt.GenX25519Private([]byte(strconv.Itoa(c.NodeId) + c.NodeType + c.Token +
|
|
|
|
node.ExtraConfig.RealityConfig.PrivateKey))
|
|
|
|
node.ExtraConfig.RealityConfig.PrivateKey = base64.RawURLEncoding.EncodeToString(key)
|
|
|
|
}
|
2023-06-24 20:22:05 -04:00
|
|
|
}
|
2023-06-08 10:46:33 -04:00
|
|
|
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":
|
|
|
|
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
|
|
|
|
}
|
2023-06-20 05:08:36 -04:00
|
|
|
c.etag = r.Header().Get("ETag")
|
2022-12-18 10:31:06 -05:00
|
|
|
return
|
2022-06-04 00:05:46 -04:00
|
|
|
}
|
2023-05-17 21:11:28 -04:00
|
|
|
|
|
|
|
func intervalToTime(i interface{}) time.Duration {
|
|
|
|
switch reflect.TypeOf(i).Kind() {
|
|
|
|
case reflect.Int:
|
|
|
|
return time.Duration(i.(int)) * time.Second
|
|
|
|
case reflect.String:
|
|
|
|
i, _ := strconv.Atoi(i.(string))
|
|
|
|
return time.Duration(i) * time.Second
|
|
|
|
case reflect.Float64:
|
|
|
|
return time.Duration(i.(float64)) * time.Second
|
2023-05-19 00:38:16 -04:00
|
|
|
default:
|
|
|
|
return time.Duration(reflect.ValueOf(i).Int()) * time.Second
|
2023-05-17 21:11:28 -04:00
|
|
|
}
|
|
|
|
}
|