mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-10-27 13:36:57 +00:00
dns: Add neighbor-based hostname resolution to local server
This commit is contained in:
@@ -110,6 +110,12 @@ func (r *neighborResolver) LookupMAC(address netip.Addr) (net.HardwareAddr, bool
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (r *neighborResolver) LookupAddresses(hostname string) []netip.Addr {
|
||||
r.access.RLock()
|
||||
defer r.access.RUnlock()
|
||||
return lookupAddressesByHostname(hostname, r.ipToHostname, r.macToHostname, r.neighborIPToMAC, r.leaseIPToMAC)
|
||||
}
|
||||
|
||||
func (r *neighborResolver) LookupHostname(address netip.Addr) (string, bool) {
|
||||
r.access.RLock()
|
||||
defer r.access.RUnlock()
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"strings"
|
||||
|
||||
"github.com/sagernet/sing-box/dns"
|
||||
)
|
||||
|
||||
func lookupAddressesByHostname(
|
||||
hostname string,
|
||||
ipToHostname map[netip.Addr]string,
|
||||
macToHostname map[string]string,
|
||||
ipToMACTables ...map[netip.Addr]net.HardwareAddr,
|
||||
) []netip.Addr {
|
||||
hostname = dns.FqdnToDomain(hostname)
|
||||
if hostname == "" {
|
||||
return nil
|
||||
}
|
||||
resultSet := make(map[netip.Addr]struct{})
|
||||
var result []netip.Addr
|
||||
addAddress := func(address netip.Addr) {
|
||||
if isScopedIPv6Address(address) {
|
||||
return
|
||||
}
|
||||
if _, exists := resultSet[address]; exists {
|
||||
return
|
||||
}
|
||||
resultSet[address] = struct{}{}
|
||||
result = append(result, address)
|
||||
}
|
||||
for address, entryHostname := range ipToHostname {
|
||||
if strings.EqualFold(entryHostname, hostname) {
|
||||
addAddress(address)
|
||||
}
|
||||
}
|
||||
for mac, entryHostname := range macToHostname {
|
||||
if !strings.EqualFold(entryHostname, hostname) {
|
||||
continue
|
||||
}
|
||||
for _, table := range ipToMACTables {
|
||||
for address, entryMAC := range table {
|
||||
if entryMAC.String() == mac {
|
||||
addAddress(address)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func isScopedIPv6Address(address netip.Addr) bool {
|
||||
// DNS AAAA records cannot carry an interface zone.
|
||||
return address.Is6() && (address.IsLinkLocalUnicast() || address.Zone() != "")
|
||||
}
|
||||
@@ -114,6 +114,12 @@ func (r *neighborResolver) LookupMAC(address netip.Addr) (net.HardwareAddr, bool
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (r *neighborResolver) LookupAddresses(hostname string) []netip.Addr {
|
||||
r.access.RLock()
|
||||
defer r.access.RUnlock()
|
||||
return lookupAddressesByHostname(hostname, r.ipToHostname, r.macToHostname, r.neighborIPToMAC, r.leaseIPToMAC)
|
||||
}
|
||||
|
||||
func (r *neighborResolver) LookupHostname(address netip.Addr) (string, bool) {
|
||||
r.access.RLock()
|
||||
defer r.access.RUnlock()
|
||||
|
||||
@@ -46,6 +46,12 @@ func (r *platformNeighborResolver) LookupMAC(address netip.Addr) (net.HardwareAd
|
||||
return extractMACFromEUI64(address)
|
||||
}
|
||||
|
||||
func (r *platformNeighborResolver) LookupAddresses(hostname string) []netip.Addr {
|
||||
r.access.RLock()
|
||||
defer r.access.RUnlock()
|
||||
return lookupAddressesByHostname(hostname, r.ipToHostname, r.macToHostname, r.ipToMAC)
|
||||
}
|
||||
|
||||
func (r *platformNeighborResolver) LookupHostname(address netip.Addr) (string, bool) {
|
||||
r.access.RLock()
|
||||
defer r.access.RUnlock()
|
||||
|
||||
+31
-32
@@ -63,7 +63,7 @@ func NewRouter(ctx context.Context, logFactory log.Factory, options option.Route
|
||||
rules: make([]adapter.Rule, 0, len(options.Rules)),
|
||||
ruleSetMap: make(map[string]adapter.RuleSet),
|
||||
needFindProcess: hasRule(options.Rules, isProcessRule) || hasDNSRule(dnsOptions.Rules, isProcessDNSRule) || options.FindProcess,
|
||||
needFindNeighbor: hasRule(options.Rules, isNeighborRule) || hasDNSRule(dnsOptions.Rules, isNeighborDNSRule) || options.FindNeighbor,
|
||||
needFindNeighbor: hasRule(options.Rules, isNeighborRule) || hasDNSRule(dnsOptions.Rules, isNeighborDNSRule) || hasLocalNeighborDNSServer(dnsOptions.Servers) || options.FindNeighbor,
|
||||
leaseFiles: options.DHCPLeaseFiles,
|
||||
pauseManager: service.FromContext[pause.Manager](ctx),
|
||||
platformInterface: service.FromContext[adapter.PlatformInterface](ctx),
|
||||
@@ -99,6 +99,36 @@ func (r *Router) Initialize(rules []option.Rule, ruleSets []option.RuleSet) erro
|
||||
func (r *Router) Start(stage adapter.StartStage) error {
|
||||
monitor := taskmonitor.New(r.logger, C.StartTimeout)
|
||||
switch stage {
|
||||
case adapter.StartStateInitialize:
|
||||
if r.needFindNeighbor {
|
||||
if r.platformInterface != nil && r.platformInterface.UsePlatformNeighborResolver() {
|
||||
monitor.Start("initialize neighbor resolver")
|
||||
resolver := newPlatformNeighborResolver(r.logger, r.platformInterface)
|
||||
err := resolver.Start()
|
||||
monitor.Finish()
|
||||
if err != nil {
|
||||
r.logger.Error(E.Cause(err, "start neighbor resolver"))
|
||||
} else {
|
||||
r.neighborResolver = resolver
|
||||
}
|
||||
} else {
|
||||
monitor.Start("initialize neighbor resolver")
|
||||
resolver, err := newNeighborResolver(r.logger, r.leaseFiles)
|
||||
monitor.Finish()
|
||||
if err != nil {
|
||||
if err != os.ErrInvalid {
|
||||
r.logger.Error(E.Cause(err, "create neighbor resolver"))
|
||||
}
|
||||
} else {
|
||||
err = resolver.Start()
|
||||
if err != nil {
|
||||
r.logger.Error(E.Cause(err, "start neighbor resolver"))
|
||||
} else {
|
||||
r.neighborResolver = resolver
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case adapter.StartStateStart:
|
||||
var startContext *adapter.HTTPStartContext
|
||||
if len(r.ruleSets) > 0 {
|
||||
@@ -128,7 +158,6 @@ func (r *Router) Start(stage adapter.StartStage) error {
|
||||
}
|
||||
r.network.Initialize(r.ruleSets)
|
||||
needFindProcess := r.needFindProcess
|
||||
needFindNeighbor := r.needFindNeighbor
|
||||
for _, ruleSet := range r.ruleSets {
|
||||
metadata := ruleSet.Metadata()
|
||||
if metadata.ContainsProcessRule {
|
||||
@@ -163,36 +192,6 @@ func (r *Router) Start(stage adapter.StartStage) error {
|
||||
processCache.SetLifetime(200 * time.Millisecond)
|
||||
r.processCache = processCache
|
||||
}
|
||||
r.needFindNeighbor = needFindNeighbor
|
||||
if needFindNeighbor {
|
||||
if r.platformInterface != nil && r.platformInterface.UsePlatformNeighborResolver() {
|
||||
monitor.Start("initialize neighbor resolver")
|
||||
resolver := newPlatformNeighborResolver(r.logger, r.platformInterface)
|
||||
err := resolver.Start()
|
||||
monitor.Finish()
|
||||
if err != nil {
|
||||
r.logger.Error(E.Cause(err, "start neighbor resolver"))
|
||||
} else {
|
||||
r.neighborResolver = resolver
|
||||
}
|
||||
} else {
|
||||
monitor.Start("initialize neighbor resolver")
|
||||
resolver, err := newNeighborResolver(r.logger, r.leaseFiles)
|
||||
monitor.Finish()
|
||||
if err != nil {
|
||||
if err != os.ErrInvalid {
|
||||
r.logger.Error(E.Cause(err, "create neighbor resolver"))
|
||||
}
|
||||
} else {
|
||||
err = resolver.Start()
|
||||
if err != nil {
|
||||
r.logger.Error(E.Cause(err, "start neighbor resolver"))
|
||||
} else {
|
||||
r.neighborResolver = resolver
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case adapter.StartStatePostStart:
|
||||
for i, rule := range r.rules {
|
||||
monitor.Start("initialize rule[", i, "]")
|
||||
|
||||
@@ -60,3 +60,19 @@ func isWIFIRule(rule option.DefaultRule) bool {
|
||||
func isWIFIDNSRule(rule option.DefaultDNSRule) bool {
|
||||
return len(rule.WIFISSID) > 0 || len(rule.WIFIBSSID) > 0
|
||||
}
|
||||
|
||||
func hasLocalNeighborDNSServer(servers []option.DNSServerOptions) bool {
|
||||
for _, server := range servers {
|
||||
if server.Type != C.DNSTypeLocal {
|
||||
continue
|
||||
}
|
||||
localOptions, isLocal := server.Options.(*option.LocalDNSServerOptions)
|
||||
if !isLocal {
|
||||
continue
|
||||
}
|
||||
if len(localOptions.NeighborDomain) > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user