diff --git a/api/panel/node.go b/api/panel/node.go index 0519a8d..86f311f 100644 --- a/api/panel/node.go +++ b/api/panel/node.go @@ -1,8 +1,12 @@ package panel import ( + "bytes" "encoding/base64" "fmt" + log "github.com/sirupsen/logrus" + coreConf "github.com/xtls/xray-core/infra/conf" + "os" "reflect" "regexp" "strconv" @@ -72,20 +76,20 @@ type NodeInfo struct { } type V2rayExtraConfig struct { - EnableVless bool `json:"EnableVless"` + EnableVless string `json:"EnableVless"` VlessFlow string `json:"VlessFlow"` - EnableReality bool `json:"EnableReality"` + EnableReality string `json:"EnableReality"` RealityConfig *RealityConfig `json:"RealityConfig"` } type RealityConfig struct { Dest interface{} `yaml:"Dest" json:"Dest"` - Xver uint64 `yaml:"Xver" json:"Xver"` + 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 uint64 `yaml:"MaxTimeDiff" json:"MaxTimeDiff"` + MaxTimeDiff string `yaml:"MaxTimeDiff" json:"MaxTimeDiff"` ShortIds []string `yaml:"ShortIds" json:"ShortIds"` } @@ -130,6 +134,36 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) { node.Rules = append(node.Rules, regexp.MustCompile(v)) } case "dns": + 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") + } + } } } node.ServerName = common.ServerName @@ -155,9 +189,9 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) { if err != nil { return nil, fmt.Errorf("decode v2ray extra error: %s", err) } - if node.ExtraConfig.EnableReality { + if node.ExtraConfig.EnableReality == "true" { if node.ExtraConfig.RealityConfig == nil { - node.ExtraConfig.EnableReality = false + node.ExtraConfig.EnableReality = "false" } else { key := crypt.GenX25519Private([]byte(strconv.Itoa(c.NodeId) + c.NodeType + c.Token + node.ExtraConfig.RealityConfig.PrivateKey)) @@ -173,6 +207,7 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) { node.ServerKey = rsp.ServerKey node.Cipher = rsp.Cipher case "trojan": + node.Tls = true case "hysteria": rsp := HysteriaNodeRsp{} err = json.Unmarshal(r.Body(), &rsp) diff --git a/cmd/server.go b/cmd/server.go index 34ceeae..e8b062d 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -64,8 +64,9 @@ func serverHandle(_ *cobra.Command, _ []string) { log.WithField("err", err).Error("Run nodes failed") return } + dns := os.Getenv("XRAY_DNS_PATH") if watch { - err = c.Watch(config, func() { + err = c.Watch(config, dns, func() { nodes.Close() err = vc.Close() if err != nil { diff --git a/conf/node.go b/conf/node.go index 939fabd..868bd83 100644 --- a/conf/node.go +++ b/conf/node.go @@ -23,6 +23,17 @@ type ControllerConfig struct { CertConfig *CertConfig `yaml:"CertConfig"` } +type RealityConfig struct { + Dest interface{} `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"` +} + type XrayOptions struct { EnableProxyProtocol bool `yaml:"EnableProxyProtocol"` EnableDNS bool `yaml:"EnableDNS"` @@ -97,4 +108,5 @@ 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"` } diff --git a/conf/watch.go b/conf/watch.go index eacf0fa..0a2d0d8 100644 --- a/conf/watch.go +++ b/conf/watch.go @@ -8,7 +8,7 @@ import ( "time" ) -func (p *Conf) Watch(filePath string, reload func()) error { +func (p *Conf) Watch(filePath, dnsPath string, reload func()) error { watcher, err := fsnotify.NewWatcher() if err != nil { return fmt.Errorf("new watcher error: %s", err) @@ -28,7 +28,11 @@ func (p *Conf) Watch(filePath string, reload func()) error { pre = time.Now() go func() { time.Sleep(10 * time.Second) - log.Println("config dir changed, reloading...") + if e.Name == dnsPath { + log.Println("DNS file changed, reloading...") + } else { + log.Println("config dir changed, reloading...") + } *p = *New() err := p.LoadFromPath(filePath) if err != nil { @@ -48,5 +52,11 @@ func (p *Conf) Watch(filePath string, reload func()) error { if err != nil { return fmt.Errorf("watch file error: %s", err) } + if dnsPath != "" { + err = watcher.Add(path.Dir(dnsPath)) + if err != nil { + return fmt.Errorf("watch dns file error: %s", err) + } + } return nil } diff --git a/core/xray/inbound.go b/core/xray/inbound.go index e25f358..55e67b1 100644 --- a/core/xray/inbound.go +++ b/core/xray/inbound.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "errors" "fmt" + "strconv" "github.com/Yuzuki616/V2bX/api/panel" "github.com/Yuzuki616/V2bX/conf" @@ -70,26 +71,50 @@ func buildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag s return nil, errors.New("the CertConfig is not vail") } switch config.CertConfig.CertMode { - case "none", "": // disable - default: - if nodeInfo.ExtraConfig.EnableReality { + 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) + } + 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) } + Xver, _ := strconv.ParseUint(rc.Xver, 10, 64) + MaxTimeDiff, _ := strconv.ParseUint(rc.Xver, 10, 64) in.StreamSetting.REALITYSettings = &coreConf.REALITYConfig{ Dest: d, - Xver: rc.Xver, + Xver: Xver, ServerNames: rc.ServerNames, PrivateKey: rc.PrivateKey, MinClientVer: rc.MinClientVer, MaxClientVer: rc.MaxClientVer, - MaxTimeDiff: rc.MaxTimeDiff, + MaxTimeDiff: MaxTimeDiff, ShortIds: rc.ShortIds, } - } else { + break + } + default: + { // Normal tls in.StreamSetting.Security = "tls" in.StreamSetting.TLSSettings = &coreConf.TLSConfig{ @@ -120,7 +145,7 @@ func buildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag s } func buildV2ray(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, inbound *coreConf.InboundDetourConfig) error { - if nodeInfo.ExtraConfig.EnableVless { + if nodeInfo.ExtraConfig.EnableVless == "true" { //Set vless inbound.Protocol = "vless" if config.XrayOptions.EnableFallback { diff --git a/core/xray/user.go b/core/xray/user.go index f76f009..86d1f36 100644 --- a/core/xray/user.go +++ b/core/xray/user.go @@ -74,7 +74,7 @@ func (c *Core) AddUsers(p *vCore.AddUsersParams) (added int, err error) { users := make([]*protocol.User, 0, len(p.UserInfo)) switch p.NodeInfo.Type { case "v2ray": - if p.NodeInfo.ExtraConfig.EnableVless { + if p.NodeInfo.ExtraConfig.EnableVless == "true" { users = buildVlessUsers(p.Tag, p.UserInfo, p.NodeInfo.ExtraConfig.VlessFlow) } else { users = buildVmessUsers(p.Tag, p.UserInfo) diff --git a/core/xray/xray.go b/core/xray/xray.go index 2520e46..d718094 100644 --- a/core/xray/xray.go +++ b/core/xray/xray.go @@ -1,9 +1,6 @@ package xray import ( - "os" - "sync" - "github.com/Yuzuki616/V2bX/conf" vCore "github.com/Yuzuki616/V2bX/core" "github.com/Yuzuki616/V2bX/core/xray/app/dispatcher" @@ -19,6 +16,8 @@ import ( "github.com/xtls/xray-core/features/routing" statsFeature "github.com/xtls/xray-core/features/stats" coreConf "github.com/xtls/xray-core/infra/conf" + "os" + "sync" ) func init() { @@ -61,6 +60,7 @@ func getCore(c *conf.XrayConfig) *core.Instance { coreLogConfig.ErrorLog = c.LogConfig.ErrorPath // DNS config coreDnsConfig := &coreConf.DNSConfig{} + os.Setenv("XRAY_DNS_PATH", "") if c.DnsConfigPath != "" { if f, err := os.Open(c.DnsConfigPath); err != nil { log.WithField("err", err).Panic("Failed to read DNS config file") @@ -69,6 +69,7 @@ func getCore(c *conf.XrayConfig) *core.Instance { log.WithField("err", err).Panic("Failed to unmarshal DNS config") } } + os.Setenv("XRAY_DNS_PATH", c.DnsConfigPath) } dnsConfig, err := coreDnsConfig.Build() if err != nil { diff --git a/example/config.yml.example b/example/config.yml.example index 697ca57..b6098de 100644 --- a/example/config.yml.example +++ b/example/config.yml.example @@ -30,8 +30,6 @@ Nodes: EnableDNS: false # Use custom DNS config, Please ensure that you set the dns.json well DNSType: AsIs # AsIs, UseIP, UseIPv4, UseIPv6, DNS strategy EnableTFO: false # Enable TCP Fast Open - EnableVless: false # Enable Vless for V2ray Type - VlessFlow: "xtls-rprx-vision" # flow for vless, "xtls-rprx-vision" or "none" or "" EnableProxyProtocol: false # Only works for WebSocket and TCP EnableFallback: false # Only support for Trojan and Vless FallBackConfigs: # Support multiple fallbacks @@ -70,7 +68,7 @@ Nodes: SpeedLimit: 0 # Speed limit, Mbps ExpireTime: 0 # Time limit, sec. CertConfig: - CertMode: dns # Option about how to get certificate: none, file, http, dns, reality. Choose "none" will forcedly disable the tls config. + CertMode: dns # Option about how to get certificate: none, file, http, dns, reality, remote. Choose "none" will forcedly disable the tls config. CertDomain: "node1.test.com" # Domain to cert CertFile: /etc/XrayR/cert/node1.test.com.cert # Provided if the CertMode is file KeyFile: /etc/XrayR/cert/node1.test.com.key