This commit is contained in:
pocketW 2022-12-19 21:48:29 +11:00
commit ac460c2f71
6 changed files with 117 additions and 22 deletions

View File

@ -3,6 +3,8 @@ package api
import ( import (
"encoding/json" "encoding/json"
"regexp" "regexp"
"github.com/xtls/xray-core/infra/conf"
) )
// Config API config // Config API config
@ -45,6 +47,7 @@ type NodeInfo struct {
ServerKey string ServerKey string
ServiceName string ServiceName string
Header json.RawMessage Header json.RawMessage
NameServerConfig []*conf.NameServerConfig
} }
type UserInfo struct { type UserInfo struct {

View File

@ -15,6 +15,8 @@ import (
"github.com/bitly/go-simplejson" "github.com/bitly/go-simplejson"
"github.com/go-resty/resty/v2" "github.com/go-resty/resty/v2"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/infra/conf"
"github.com/XrayR-project/XrayR/api" "github.com/XrayR-project/XrayR/api"
) )
@ -261,11 +263,12 @@ func (c *APIClient) GetNodeRule() (*[]api.DetectRule, error) {
for i, rule := range nodeInfoResponse.Get("routes").MustArray() { for i, rule := range nodeInfoResponse.Get("routes").MustArray() {
r := rule.(map[string]any) r := rule.(map[string]any)
if r["action"] == "block" { if r["action"] == "block" {
ruleListItem := api.DetectRule{ for ii := range r["match"].([]any) {
ruleList = append(ruleList, api.DetectRule{
ID: i, ID: i,
Pattern: regexp.MustCompile(strings.TrimPrefix(r["match"].(string), "regexp:")), Pattern: regexp.MustCompile(r["match"].([]any)[ii].(string)),
})
} }
ruleList = append(ruleList, ruleListItem)
} }
} }
@ -304,12 +307,26 @@ func (c *APIClient) parseTrojanNodeResponse(nodeInfoResponse *simplejson.Json) (
TLSType: TLSType, TLSType: TLSType,
Host: nodeInfoResponse.Get("host").MustString(), Host: nodeInfoResponse.Get("host").MustString(),
ServiceName: nodeInfoResponse.Get("server_name").MustString(), ServiceName: nodeInfoResponse.Get("server_name").MustString(),
NameServerConfig: parseDNSConfig(nodeInfoResponse),
} }
return nodeInfo, nil return nodeInfo, nil
} }
// parseSSNodeResponse parse the response for the given nodeInfo format // parseSSNodeResponse parse the response for the given nodeInfo format
func (c *APIClient) parseSSNodeResponse(nodeInfoResponse *simplejson.Json) (*api.NodeInfo, error) { func (c *APIClient) parseSSNodeResponse(nodeInfoResponse *simplejson.Json) (*api.NodeInfo, error) {
var header json.RawMessage
if nodeInfoResponse.Get("obfs").MustString() == "http" {
path := "/"
if p := nodeInfoResponse.Get("obfs_settings").Get("path").MustString(); p != "" {
path = p
}
header, _ = json.Marshal(map[string]any{
"type": "http",
"request": map[string]any{
"path": path,
}})
}
// Create GeneralNodeInfo // Create GeneralNodeInfo
return &api.NodeInfo{ return &api.NodeInfo{
NodeType: c.NodeType, NodeType: c.NodeType,
@ -318,6 +335,8 @@ func (c *APIClient) parseSSNodeResponse(nodeInfoResponse *simplejson.Json) (*api
TransportProtocol: "tcp", TransportProtocol: "tcp",
CypherMethod: nodeInfoResponse.Get("cipher").MustString(), CypherMethod: nodeInfoResponse.Get("cipher").MustString(),
ServerKey: nodeInfoResponse.Get("server_key").MustString(), // shadowsocks2022 share key ServerKey: nodeInfoResponse.Get("server_key").MustString(), // shadowsocks2022 share key
NameServerConfig: parseDNSConfig(nodeInfoResponse),
Header: header,
}, nil }, nil
} }
@ -373,5 +392,20 @@ func (c *APIClient) parseV2rayNodeResponse(nodeInfoResponse *simplejson.Json) (*
EnableVless: c.EnableVless, EnableVless: c.EnableVless,
ServiceName: serviceName, ServiceName: serviceName,
Header: header, Header: header,
NameServerConfig: parseDNSConfig(nodeInfoResponse),
}, nil }, nil
} }
func parseDNSConfig(nodeInfoResponse *simplejson.Json) (nameServerList []*conf.NameServerConfig) {
for _, rule := range nodeInfoResponse.Get("routes").MustArray() {
r := rule.(map[string]any)
if r["action"] == "dns" {
nameServerList = append(nameServerList, &conf.NameServerConfig{
Address: &conf.Address{Address: net.ParseAddress(r["action_value"].(string))},
Domains: strings.Split(r["match"].(string), ","),
})
}
}
return
}

View File

@ -140,7 +140,7 @@ func (c *APIClient) parseResponse(res *resty.Response, path string, err error) (
return rtn, nil return rtn, nil
} }
// GetNodeInfo will pull NodeInfo Config from sspanel // GetNodeInfo will pull NodeInfo Config from panel
func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) { func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) {
var nodeType string var nodeType string
switch c.NodeType { switch c.NodeType {
@ -184,7 +184,7 @@ func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) {
return nodeInfo, nil return nodeInfo, nil
} }
// GetUserList will pull user form sspanel // GetUserList will pull user form panel
func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) { func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) {
var nodeType string var nodeType string
switch c.NodeType { switch c.NodeType {
@ -215,16 +215,16 @@ func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) {
user.Email = response.Get("data").GetIndex(i).Get("shadowsocks_user").Get("secret").MustString() user.Email = response.Get("data").GetIndex(i).Get("shadowsocks_user").Get("secret").MustString()
user.Passwd = response.Get("data").GetIndex(i).Get("shadowsocks_user").Get("secret").MustString() user.Passwd = response.Get("data").GetIndex(i).Get("shadowsocks_user").Get("secret").MustString()
user.Method = response.Get("data").GetIndex(i).Get("shadowsocks_user").Get("cipher").MustString() user.Method = response.Get("data").GetIndex(i).Get("shadowsocks_user").Get("cipher").MustString()
user.SpeedLimit = uint64(response.Get("data").GetIndex(i).Get("shadowsocks_user").Get("speed_limit").MustUint64() * 1000000 / 8) user.SpeedLimit = response.Get("data").GetIndex(i).Get("shadowsocks_user").Get("speed_limit").MustUint64() * 1000000 / 8
case "Trojan": case "Trojan":
user.UUID = response.Get("data").GetIndex(i).Get("trojan_user").Get("password").MustString() user.UUID = response.Get("data").GetIndex(i).Get("trojan_user").Get("password").MustString()
user.Email = response.Get("data").GetIndex(i).Get("trojan_user").Get("password").MustString() user.Email = response.Get("data").GetIndex(i).Get("trojan_user").Get("password").MustString()
user.SpeedLimit = uint64(response.Get("data").GetIndex(i).Get("trojan_user").Get("speed_limit").MustUint64() * 1000000 / 8) user.SpeedLimit = response.Get("data").GetIndex(i).Get("trojan_user").Get("speed_limit").MustUint64() * 1000000 / 8
case "V2ray": case "V2ray":
user.UUID = response.Get("data").GetIndex(i).Get("v2ray_user").Get("uuid").MustString() user.UUID = response.Get("data").GetIndex(i).Get("v2ray_user").Get("uuid").MustString()
user.Email = response.Get("data").GetIndex(i).Get("v2ray_user").Get("email").MustString() user.Email = response.Get("data").GetIndex(i).Get("v2ray_user").Get("email").MustString()
user.AlterID = uint16(response.Get("data").GetIndex(i).Get("v2ray_user").Get("alter_id").MustUint64()) user.AlterID = uint16(response.Get("data").GetIndex(i).Get("v2ray_user").Get("alter_id").MustUint64())
user.SpeedLimit = uint64(response.Get("data").GetIndex(i).Get("v2ray_user").Get("speed_limit").MustUint64() * 1000000 / 8) user.SpeedLimit = response.Get("data").GetIndex(i).Get("v2ray_user").Get("speed_limit").MustUint64() * 1000000 / 8
} }
if c.SpeedLimit > 0 { if c.SpeedLimit > 0 {
user.SpeedLimit = uint64((c.SpeedLimit * 1000000) / 8) user.SpeedLimit = uint64((c.SpeedLimit * 1000000) / 8)
@ -269,7 +269,7 @@ func (c *APIClient) GetNodeRule() (*[]api.DetectRule, error) {
return &ruleList, nil return &ruleList, nil
} }
// V2board only support the rule for v2ray // Only support the rule for v2ray
// fix: reuse config response // fix: reuse config response
c.access.Lock() c.access.Lock()
defer c.access.Unlock() defer c.access.Unlock()
@ -300,7 +300,7 @@ func (c *APIClient) ReportIllegal(detectResultList *[]api.DetectResult) error {
return nil return nil
} }
// ParseTrojanNodeResponse parse the response for the given nodeinfor format // ParseTrojanNodeResponse parse the response for the given nodeInfo format
func (c *APIClient) ParseTrojanNodeResponse(nodeInfoResponse *simplejson.Json) (*api.NodeInfo, error) { func (c *APIClient) ParseTrojanNodeResponse(nodeInfoResponse *simplejson.Json) (*api.NodeInfo, error) {
var TLSType = "tls" var TLSType = "tls"
if c.EnableXTLS { if c.EnableXTLS {
@ -315,7 +315,7 @@ func (c *APIClient) ParseTrojanNodeResponse(nodeInfoResponse *simplejson.Json) (
host := inboundInfo.Get("streamSettings").Get("tlsSettings").Get("serverName").MustString() host := inboundInfo.Get("streamSettings").Get("tlsSettings").Get("serverName").MustString()
// Create GeneralNodeInfo // Create GeneralNodeInfo
nodeinfo := &api.NodeInfo{ nodeInfo := &api.NodeInfo{
NodeType: c.NodeType, NodeType: c.NodeType,
NodeID: c.NodeID, NodeID: c.NodeID,
Port: port, Port: port,
@ -324,10 +324,10 @@ func (c *APIClient) ParseTrojanNodeResponse(nodeInfoResponse *simplejson.Json) (
TLSType: TLSType, TLSType: TLSType,
Host: host, Host: host,
} }
return nodeinfo, nil return nodeInfo, nil
} }
// ParseSSNodeResponse parse the response for the given nodeinfo format // ParseSSNodeResponse parse the response for the given nodeInfo format
func (c *APIClient) ParseSSNodeResponse(nodeInfoResponse *simplejson.Json) (*api.NodeInfo, error) { func (c *APIClient) ParseSSNodeResponse(nodeInfoResponse *simplejson.Json) (*api.NodeInfo, error) {
var method, serverPsk string var method, serverPsk string
tmpInboundInfo := nodeInfoResponse.Get("inbounds").MustArray() tmpInboundInfo := nodeInfoResponse.Get("inbounds").MustArray()
@ -350,7 +350,7 @@ func (c *APIClient) ParseSSNodeResponse(nodeInfoResponse *simplejson.Json) (*api
} }
// Create GeneralNodeInfo // Create GeneralNodeInfo
nodeinfo := &api.NodeInfo{ nodeInfo := &api.NodeInfo{
NodeType: c.NodeType, NodeType: c.NodeType,
NodeID: c.NodeID, NodeID: c.NodeID,
Port: port, Port: port,
@ -359,12 +359,12 @@ func (c *APIClient) ParseSSNodeResponse(nodeInfoResponse *simplejson.Json) (*api
ServerKey: serverPsk, ServerKey: serverPsk,
} }
return nodeinfo, nil return nodeInfo, nil
} }
// ParseV2rayNodeResponse parse the response for the given nodeinfor format // ParseV2rayNodeResponse parse the response for the given nodeInfo format
func (c *APIClient) ParseV2rayNodeResponse(nodeInfoResponse *simplejson.Json) (*api.NodeInfo, error) { func (c *APIClient) ParseV2rayNodeResponse(nodeInfoResponse *simplejson.Json) (*api.NodeInfo, error) {
var TLSType string = "tls" var TLSType = "tls"
var path, host, serviceName string var path, host, serviceName string
var header json.RawMessage var header json.RawMessage
var enableTLS bool var enableTLS bool

View File

@ -66,10 +66,12 @@ func (p *Panel) loadCore(panelConfig *Config) *core.Instance {
} }
} }
} }
dnsConfig, err := coreDnsConfig.Build()
if err != nil { // init controller's DNS config
log.Panicf("Failed to understand DNS config, Please check: https://xtls.github.io/config/dns.html for help: %s", err) for _, config := range p.panelConfig.NodesConfig {
config.ControllerConfig.DNSConfig = coreDnsConfig
} }
// Routing config // Routing config
coreRouterConfig := &conf.RouterConfig{} coreRouterConfig := &conf.RouterConfig{}
if panelConfig.RouteConfigPath != "" { if panelConfig.RouteConfigPath != "" {
@ -137,7 +139,6 @@ func (p *Panel) loadCore(panelConfig *Config) *core.Instance {
serial.ToTypedMessage(&proxyman.InboundConfig{}), serial.ToTypedMessage(&proxyman.InboundConfig{}),
serial.ToTypedMessage(&proxyman.OutboundConfig{}), serial.ToTypedMessage(&proxyman.OutboundConfig{}),
serial.ToTypedMessage(policyConfig), serial.ToTypedMessage(policyConfig),
serial.ToTypedMessage(dnsConfig),
serial.ToTypedMessage(routeConfig), serial.ToTypedMessage(routeConfig),
}, },
Inbound: inBoundConfig, Inbound: inBoundConfig,

View File

@ -1,6 +1,8 @@
package controller package controller
import ( import (
"github.com/xtls/xray-core/infra/conf"
"github.com/XrayR-project/XrayR/common/limiter" "github.com/XrayR-project/XrayR/common/limiter"
"github.com/XrayR-project/XrayR/common/mylego" "github.com/XrayR-project/XrayR/common/mylego"
) )
@ -21,6 +23,7 @@ type Config struct {
AutoSpeedLimitConfig *AutoSpeedLimitConfig `mapstructure:"AutoSpeedLimitConfig"` AutoSpeedLimitConfig *AutoSpeedLimitConfig `mapstructure:"AutoSpeedLimitConfig"`
GlobalDeviceLimitConfig *limiter.GlobalDeviceLimitConfig `mapstructure:"GlobalDeviceLimitConfig"` GlobalDeviceLimitConfig *limiter.GlobalDeviceLimitConfig `mapstructure:"GlobalDeviceLimitConfig"`
FallBackConfigs []*FallBackConfig `mapstructure:"FallBackConfigs"` FallBackConfigs []*FallBackConfig `mapstructure:"FallBackConfigs"`
DNSConfig *conf.DNSConfig
} }
type AutoSpeedLimitConfig struct { type AutoSpeedLimitConfig struct {

View File

@ -7,12 +7,15 @@ import (
"time" "time"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/common/task" "github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features"
"github.com/xtls/xray-core/features/inbound" "github.com/xtls/xray-core/features/inbound"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/features/stats" "github.com/xtls/xray-core/features/stats"
"github.com/xtls/xray-core/infra/conf"
"github.com/XrayR-project/XrayR/api" "github.com/XrayR-project/XrayR/api"
"github.com/XrayR-project/XrayR/app/mydispatcher" "github.com/XrayR-project/XrayR/app/mydispatcher"
@ -77,6 +80,13 @@ func (c *Controller) Start() error {
} }
c.nodeInfo = newNodeInfo c.nodeInfo = newNodeInfo
c.Tag = c.buildNodeTag() c.Tag = c.buildNodeTag()
// append remote DNS config and init dns service
err = c.addNewDNS(newNodeInfo)
if err != nil {
return err
}
// Add new tag // Add new tag
err = c.addNewTag(newNodeInfo) err = c.addNewTag(newNodeInfo)
if err != nil { if err != nil {
@ -252,6 +262,13 @@ func (c *Controller) nodeInfoMonitor() (err error) {
log.Print(err) log.Print(err)
return nil return nil
} }
// Add DNS
log.Printf("%s Reload DNS service", c.logPrefix())
if err := c.addNewDNS(newNodeInfo); err != nil {
log.Print(err)
return nil
}
} else { } else {
var deleted, added []api.UserInfo var deleted, added []api.UserInfo
if usersChanged { if usersChanged {
@ -613,3 +630,40 @@ func (c *Controller) certMonitor() error {
} }
return nil return nil
} }
// append remote dns
func (c *Controller) addNewDNS(newNodeInfo *api.NodeInfo) error {
// reserve local DNS
servers := c.config.DNSConfig.Servers
servers = append(servers, newNodeInfo.NameServerConfig...)
dns := conf.DNSConfig{
Servers: servers,
Hosts: c.config.DNSConfig.Hosts,
ClientIP: c.config.DNSConfig.ClientIP,
Tag: c.config.DNSConfig.Tag,
QueryStrategy: c.config.DNSConfig.QueryStrategy,
DisableCache: c.config.DNSConfig.DisableCache,
DisableFallback: c.config.DNSConfig.DisableFallback,
DisableFallbackIfMatch: c.config.DNSConfig.DisableFallbackIfMatch,
}
dnsConfig, err := dns.Build()
if err != nil {
log.Panicf("Failed to understand DNS config, Please check: https://xtls.github.io/config/dns.html for help: %s", err)
}
dnsInstance, err := serial.ToTypedMessage(dnsConfig).GetInstance()
if err != nil {
return err
}
obj, err := core.CreateObject(c.server, dnsInstance)
if err != nil {
return err
}
if feature, ok := obj.(features.Feature); ok {
if err := c.server.AddFeature(feature); err != nil {
return err
}
}
return nil
}