mirror of
https://github.com/wyx2685/V2bX.git
synced 2025-01-22 09:58:14 -05:00
feat: remote dns for sing
This commit is contained in:
parent
b85a78209a
commit
cecfffd081
@ -85,9 +85,10 @@ func serverHandle(_ *cobra.Command, _ []string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Info("Nodes started")
|
log.Info("Nodes started")
|
||||||
dns := os.Getenv("XRAY_DNS_PATH")
|
xdns := os.Getenv("XRAY_DNS_PATH")
|
||||||
|
sdns := os.Getenv("SING_DNS_PATH")
|
||||||
if watch {
|
if watch {
|
||||||
err = c.Watch(config, dns, func() {
|
err = c.Watch(config, xdns, sdns, func() {
|
||||||
nodes.Close()
|
nodes.Close()
|
||||||
err = vc.Close()
|
err = vc.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -5,9 +5,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type SingConfig struct {
|
type SingConfig struct {
|
||||||
LogConfig SingLogConfig `json:"Log"`
|
LogConfig SingLogConfig `json:"Log"`
|
||||||
NtpConfig SingNtpConfig `json:"NTP"`
|
NtpConfig SingNtpConfig `json:"NTP"`
|
||||||
OriginalPath string `json:"OriginalPath"`
|
DnsConfigPath string `json:"DnsConfigPath"`
|
||||||
|
OriginalPath string `json:"OriginalPath"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SingLogConfig struct {
|
type SingLogConfig struct {
|
||||||
@ -35,6 +36,7 @@ type SingOptions struct {
|
|||||||
EnableProxyProtocol bool `json:"EnableProxyProtocol"`
|
EnableProxyProtocol bool `json:"EnableProxyProtocol"`
|
||||||
TCPFastOpen bool `json:"EnableTFO"`
|
TCPFastOpen bool `json:"EnableTFO"`
|
||||||
SniffEnabled bool `json:"EnableSniff"`
|
SniffEnabled bool `json:"EnableSniff"`
|
||||||
|
EnableDNS bool `json:"EnableDNS"`
|
||||||
DomainStrategy option.DomainStrategy `json:"DomainStrategy"`
|
DomainStrategy option.DomainStrategy `json:"DomainStrategy"`
|
||||||
SniffOverrideDestination bool `json:"SniffOverrideDestination"`
|
SniffOverrideDestination bool `json:"SniffOverrideDestination"`
|
||||||
FallBackConfigs *FallBackConfigForSing `json:"FallBackConfigs"`
|
FallBackConfigs *FallBackConfigForSing `json:"FallBackConfigs"`
|
||||||
@ -59,6 +61,7 @@ type FallBack struct {
|
|||||||
|
|
||||||
func NewSingOptions() *SingOptions {
|
func NewSingOptions() *SingOptions {
|
||||||
return &SingOptions{
|
return &SingOptions{
|
||||||
|
EnableDNS: false,
|
||||||
EnableProxyProtocol: false,
|
EnableProxyProtocol: false,
|
||||||
TCPFastOpen: false,
|
TCPFastOpen: false,
|
||||||
SniffEnabled: true,
|
SniffEnabled: true,
|
||||||
|
@ -5,10 +5,12 @@ import (
|
|||||||
"github.com/fsnotify/fsnotify"
|
"github.com/fsnotify/fsnotify"
|
||||||
"log"
|
"log"
|
||||||
"path"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *Conf) Watch(filePath, dnsPath string, reload func()) error {
|
func (p *Conf) Watch(filePath, xDnsPath string, sDnsPath string, reload func()) error {
|
||||||
watcher, err := fsnotify.NewWatcher()
|
watcher, err := fsnotify.NewWatcher()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("new watcher error: %s", err)
|
return fmt.Errorf("new watcher error: %s", err)
|
||||||
@ -28,9 +30,10 @@ func (p *Conf) Watch(filePath, dnsPath string, reload func()) error {
|
|||||||
pre = time.Now()
|
pre = time.Now()
|
||||||
go func() {
|
go func() {
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
if e.Name == dnsPath {
|
switch filepath.Base(strings.TrimSuffix(e.Name, "~")) {
|
||||||
|
case filepath.Base(xDnsPath), filepath.Base(sDnsPath):
|
||||||
log.Println("DNS file changed, reloading...")
|
log.Println("DNS file changed, reloading...")
|
||||||
} else {
|
default:
|
||||||
log.Println("config dir changed, reloading...")
|
log.Println("config dir changed, reloading...")
|
||||||
}
|
}
|
||||||
*p = *New()
|
*p = *New()
|
||||||
@ -52,8 +55,14 @@ func (p *Conf) Watch(filePath, dnsPath string, reload func()) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("watch file error: %s", err)
|
return fmt.Errorf("watch file error: %s", err)
|
||||||
}
|
}
|
||||||
if dnsPath != "" {
|
if xDnsPath != "" {
|
||||||
err = watcher.Add(path.Dir(dnsPath))
|
err = watcher.Add(path.Dir(xDnsPath))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("watch dns file error: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if sDnsPath != "" {
|
||||||
|
err = watcher.Add(path.Dir(sDnsPath))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("watch dns file error: %s", err)
|
return fmt.Errorf("watch dns file error: %s", err)
|
||||||
}
|
}
|
||||||
|
81
core/sing/dns.go
Normal file
81
core/sing/dns.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package sing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"github.com/InazumaV/V2bX/api/panel"
|
||||||
|
"github.com/goccy/go-json"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func updateDNSConfig(node *panel.NodeInfo) (err error) {
|
||||||
|
dnsPath := os.Getenv("SING_DNS_PATH")
|
||||||
|
if len(node.RawDNS.DNSJson) != 0 {
|
||||||
|
err = saveDnsConfig(node.RawDNS.DNSJson, dnsPath)
|
||||||
|
} else if len(node.RawDNS.DNSMap) != 0 {
|
||||||
|
dnsConfig := DNSConfig{
|
||||||
|
Servers: []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"tag": "default",
|
||||||
|
"address": "https://8.8.8.8/dns-query",
|
||||||
|
"detour": "direct",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for id, value := range node.RawDNS.DNSMap {
|
||||||
|
dnsConfig.Servers = append(dnsConfig.Servers,
|
||||||
|
map[string]interface{}{
|
||||||
|
"tag": id,
|
||||||
|
"address": value["address"],
|
||||||
|
"address_resolver": "default",
|
||||||
|
"detour": "direct",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
rule := map[string]interface{}{
|
||||||
|
"server": id,
|
||||||
|
"disable_cache": true,
|
||||||
|
}
|
||||||
|
for _, ruleType := range []string{"domain_suffix", "domain_keyword", "domain_regex", "geosite"} {
|
||||||
|
var domains []string
|
||||||
|
for _, v := range value["domains"].([]string) {
|
||||||
|
split := strings.SplitN(v, ":", 2)
|
||||||
|
prefix := strings.ToLower(split[0])
|
||||||
|
if prefix == ruleType || (prefix == "domain" && ruleType == "domain_suffix") {
|
||||||
|
if len(split) > 1 {
|
||||||
|
domains = append(domains, split[1])
|
||||||
|
}
|
||||||
|
if len(domains) > 0 {
|
||||||
|
rule[ruleType] = domains
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dnsConfig.Rules = append(dnsConfig.Rules, rule)
|
||||||
|
}
|
||||||
|
dnsConfigJSON, err := json.MarshalIndent(dnsConfig, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
log.WithField("err", err).Error("Error marshaling dnsConfig to JSON")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = saveDnsConfig(dnsConfigJSON, dnsPath)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveDnsConfig(dns []byte, dnsPath string) (err error) {
|
||||||
|
currentData, err := os.ReadFile(dnsPath)
|
||||||
|
if err != nil {
|
||||||
|
log.WithField("err", err).Error("Failed to read SING_DNS_PATH")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !bytes.Equal(currentData, dns) {
|
||||||
|
if err = os.Truncate(dnsPath, 0); err != nil {
|
||||||
|
log.WithField("err", err).Error("Failed to clear SING DNS PATH file")
|
||||||
|
}
|
||||||
|
if err = os.WriteFile(dnsPath, dns, 0644); err != nil {
|
||||||
|
log.WithField("err", err).Error("Failed to write DNS to SING DNS PATH file")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
@ -30,6 +30,10 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return option.Inbound{}, fmt.Errorf("the listen ip not vail")
|
return option.Inbound{}, fmt.Errorf("the listen ip not vail")
|
||||||
}
|
}
|
||||||
|
var domainStrategy option.DomainStrategy
|
||||||
|
if c.SingOptions.EnableDNS {
|
||||||
|
domainStrategy = c.SingOptions.DomainStrategy
|
||||||
|
}
|
||||||
listen := option.ListenOptions{
|
listen := option.ListenOptions{
|
||||||
Listen: (*option.ListenAddress)(&addr),
|
Listen: (*option.ListenAddress)(&addr),
|
||||||
ListenPort: uint16(info.Common.ServerPort),
|
ListenPort: uint16(info.Common.ServerPort),
|
||||||
@ -38,7 +42,7 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
|
|||||||
InboundOptions: option.InboundOptions{
|
InboundOptions: option.InboundOptions{
|
||||||
SniffEnabled: c.SingOptions.SniffEnabled,
|
SniffEnabled: c.SingOptions.SniffEnabled,
|
||||||
SniffOverrideDestination: c.SingOptions.SniffOverrideDestination,
|
SniffOverrideDestination: c.SingOptions.SniffOverrideDestination,
|
||||||
DomainStrategy: c.SingOptions.DomainStrategy,
|
DomainStrategy: domainStrategy,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
var tls option.InboundTLSOptions
|
var tls option.InboundTLSOptions
|
||||||
@ -203,6 +207,10 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *Box) AddNode(tag string, info *panel.NodeInfo, config *conf.Options) error {
|
func (b *Box) AddNode(tag string, info *panel.NodeInfo, config *conf.Options) error {
|
||||||
|
err := updateDNSConfig(info)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("build dns error: %s", err)
|
||||||
|
}
|
||||||
c, err := getInboundOptions(tag, info, config)
|
c, err := getInboundOptions(tag, info, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -26,6 +26,11 @@ import (
|
|||||||
|
|
||||||
var _ adapter.Service = (*Box)(nil)
|
var _ adapter.Service = (*Box)(nil)
|
||||||
|
|
||||||
|
type DNSConfig struct {
|
||||||
|
Servers []map[string]interface{} `json:"servers"`
|
||||||
|
Rules []map[string]interface{} `json:"rules"`
|
||||||
|
}
|
||||||
|
|
||||||
type Box struct {
|
type Box struct {
|
||||||
createdAt time.Time
|
createdAt time.Time
|
||||||
router adapter.Router
|
router adapter.Router
|
||||||
@ -68,6 +73,17 @@ func New(c *conf.CoreConfig) (vCore.Core, error) {
|
|||||||
ServerPort: c.SingConfig.NtpConfig.ServerPort,
|
ServerPort: c.SingConfig.NtpConfig.ServerPort,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
os.Setenv("SING_DNS_PATH", "")
|
||||||
|
if c.SingConfig.DnsConfigPath != "" {
|
||||||
|
if f, err := os.Open(c.SingConfig.DnsConfigPath); err != nil {
|
||||||
|
log.Error("Failed to read DNS config file")
|
||||||
|
} else {
|
||||||
|
if err = json.NewDecoder(f).Decode(&option.DNSOptions{}); err != nil {
|
||||||
|
log.Error("Failed to unmarshal DNS config")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os.Setenv("SING_DNS_PATH", c.SingConfig.DnsConfigPath)
|
||||||
|
}
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
ctx = service.ContextWithDefaultRegistry(ctx)
|
ctx = service.ContextWithDefaultRegistry(ctx)
|
||||||
ctx = pause.ContextWithDefaultManager(ctx)
|
ctx = pause.ContextWithDefaultManager(ctx)
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
coreConf "github.com/xtls/xray-core/infra/conf"
|
coreConf "github.com/xtls/xray-core/infra/conf"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func updateDNSConfig(node *panel.NodeInfo) (err error) {
|
func updateDNSConfig(node *panel.NodeInfo) (err error) {
|
||||||
@ -57,7 +56,5 @@ func saveDnsConfig(dns []byte, dnsPath string) (err error) {
|
|||||||
log.WithField("err", err).Error("Failed to write DNS to XRAY DNS PATH file")
|
log.WithField("err", err).Error("Failed to write DNS to XRAY DNS PATH file")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Println("reloading config")
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
"Level": "error",
|
"Level": "error",
|
||||||
"Timestamp": true
|
"Timestamp": true
|
||||||
},
|
},
|
||||||
|
"DnsConfigPath": "/etc/V2bX/dns.json",
|
||||||
"NTP": {
|
"NTP": {
|
||||||
"Enable": true,
|
"Enable": true,
|
||||||
"Server": "time.apple.com",
|
"Server": "time.apple.com",
|
||||||
@ -28,6 +29,7 @@
|
|||||||
"ListenIP": "0.0.0.0",
|
"ListenIP": "0.0.0.0",
|
||||||
"SendIP": "0.0.0.0",
|
"SendIP": "0.0.0.0",
|
||||||
"EnableProxyProtocol": false,
|
"EnableProxyProtocol": false,
|
||||||
|
"EnableDNS": true
|
||||||
"DomainStrategy": "ipv4_only",
|
"DomainStrategy": "ipv4_only",
|
||||||
"LimitConfig": {
|
"LimitConfig": {
|
||||||
"EnableRealtime": false,
|
"EnableRealtime": false,
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
"Server": "time.apple.com",
|
"Server": "time.apple.com",
|
||||||
"ServerPort": 0
|
"ServerPort": 0
|
||||||
},
|
},
|
||||||
|
"DnsConfigPath": "/etc/V2bX/dns.json",
|
||||||
// SingBox源配置文件目录,用于引用标准SingBox配置文件
|
// SingBox源配置文件目录,用于引用标准SingBox配置文件
|
||||||
"OriginalPath": "/etc/V2bX/sing_origin.json"
|
"OriginalPath": "/etc/V2bX/sing_origin.json"
|
||||||
},
|
},
|
||||||
@ -113,7 +114,9 @@
|
|||||||
// 开启 TCP Fast Open
|
// 开启 TCP Fast Open
|
||||||
"EnableTFO": true,
|
"EnableTFO": true,
|
||||||
|
|
||||||
// 设置 Domain Strategy
|
// 开启 DNS
|
||||||
|
"EnableDNS" : true,
|
||||||
|
// 设置 Domain Strategy 需要开启 DNS ,默认 AsIS
|
||||||
// 可选 prefer_ipv4 / prefer_ipv6 / ipv4_only / ipv6_only
|
// 可选 prefer_ipv4 / prefer_ipv6 / ipv4_only / ipv6_only
|
||||||
"DomainStrategy": "ipv4_only",
|
"DomainStrategy": "ipv4_only",
|
||||||
|
|
||||||
|
@ -9,5 +9,5 @@
|
|||||||
"SendIP": "0.0.0.0",
|
"SendIP": "0.0.0.0",
|
||||||
"EnableProxyProtocol": false,
|
"EnableProxyProtocol": false,
|
||||||
"EnableTFO": true,
|
"EnableTFO": true,
|
||||||
"DomainStrategy": "ipv4_only"
|
"DNSType": "ipv4_only"
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user