mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-10-21 11:33:20 +00:00
Add dns_server_address and dns_search_domain rule items
This commit is contained in:
parent
c8d9ae4acf
commit
a2df2cdc1f
24 changed files with 722 additions and 20 deletions
|
|
@ -73,6 +73,12 @@ type DNSTransportWithPreferredDomain interface {
|
|||
PreferredDomain(domain string) bool
|
||||
}
|
||||
|
||||
type DNSTransportWithConfiguration interface {
|
||||
DNSTransport
|
||||
ServerAddresses() []netip.Addr
|
||||
SearchDomains() []string
|
||||
}
|
||||
|
||||
type DNSTransportWithEnvironment interface {
|
||||
DNSTransport
|
||||
Environment() []string
|
||||
|
|
|
|||
|
|
@ -80,9 +80,10 @@ func NormalizeWIFIBSSID(bssid string) string {
|
|||
|
||||
type NetworkInterface struct {
|
||||
control.Interface
|
||||
Type C.InterfaceType
|
||||
DNSServers []string
|
||||
Gateways []netip.Addr
|
||||
Expensive bool
|
||||
Constrained bool
|
||||
Type C.InterfaceType
|
||||
DNSServers []string
|
||||
DNSSearchDomains []string
|
||||
Gateways []netip.Addr
|
||||
Expensive bool
|
||||
Constrained bool
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"net/netip"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
|
|
@ -38,8 +39,9 @@ func RegisterTransport(registry *dns.TransportRegistry) {
|
|||
}
|
||||
|
||||
var (
|
||||
_ adapter.DNSTransport = (*Transport)(nil)
|
||||
_ adapter.DNSTransportWithEnvironment = (*Transport)(nil)
|
||||
_ adapter.DNSTransport = (*Transport)(nil)
|
||||
_ adapter.DNSTransportWithConfiguration = (*Transport)(nil)
|
||||
_ adapter.DNSTransportWithEnvironment = (*Transport)(nil)
|
||||
)
|
||||
|
||||
var errInterfaceIsCellular = E.New("interface is cellular")
|
||||
|
|
@ -139,12 +141,37 @@ func (t *Transport) Start(stage adapter.StartStage, scope *adapter.Scope) error
|
|||
func (t *Transport) Reset() {
|
||||
t.refreshAccess.Lock()
|
||||
defer t.refreshAccess.Unlock()
|
||||
state := t.savedState.Swap(nil)
|
||||
if state != nil && state.serverScope != nil {
|
||||
state := t.savedState.Load()
|
||||
if state == nil {
|
||||
return
|
||||
}
|
||||
t.savedState.Store(&transportState{
|
||||
search: state.search,
|
||||
servers: state.servers,
|
||||
})
|
||||
if state.serverScope != nil {
|
||||
state.serverScope.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transport) ServerAddresses() []netip.Addr {
|
||||
state := t.loadState()
|
||||
if state == nil {
|
||||
return nil
|
||||
}
|
||||
return common.Map(state.servers, func(it M.Socksaddr) netip.Addr {
|
||||
return it.Addr
|
||||
})
|
||||
}
|
||||
|
||||
func (t *Transport) SearchDomains() []string {
|
||||
state := t.loadState()
|
||||
if state == nil {
|
||||
return nil
|
||||
}
|
||||
return state.search
|
||||
}
|
||||
|
||||
func (t *Transport) Environment() []string {
|
||||
state := t.savedState.Load()
|
||||
if state == nil {
|
||||
|
|
@ -207,14 +234,22 @@ func (t *Transport) exchangeCold(ctx context.Context, message *mDNS.Msg, callbac
|
|||
}
|
||||
|
||||
func (t *Transport) Fetch() []M.Socksaddr {
|
||||
state := t.loadState()
|
||||
if state == nil {
|
||||
return nil
|
||||
}
|
||||
return state.servers
|
||||
}
|
||||
|
||||
func (t *Transport) loadState() *transportState {
|
||||
state := t.savedState.Load()
|
||||
if state == nil || state.lastError != nil {
|
||||
return nil
|
||||
}
|
||||
if len(state.servers) > 0 && time.Since(state.updatedAt) >= C.DHCPTTL {
|
||||
if time.Since(state.updatedAt) >= C.DHCPTTL {
|
||||
t.startRefresh()
|
||||
}
|
||||
return state.servers
|
||||
return state
|
||||
}
|
||||
|
||||
func (t *Transport) fetch(ctx context.Context) error {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package local
|
|||
|
||||
import (
|
||||
"context"
|
||||
"net/netip"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
|
|
@ -12,8 +13,10 @@ import (
|
|||
"github.com/sagernet/sing-box/dns/transport/mdns"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
|
||||
mDNS "github.com/miekg/dns"
|
||||
|
|
@ -26,6 +29,7 @@ func RegisterTransport(registry *dns.TransportRegistry) {
|
|||
var (
|
||||
_ adapter.DNSTransport = (*Transport)(nil)
|
||||
_ adapter.DNSTransportWithPreferredDomain = (*Transport)(nil)
|
||||
_ adapter.DNSTransportWithConfiguration = (*Transport)(nil)
|
||||
_ adapter.DNSTransportWithEnvironment = (*Transport)(nil)
|
||||
)
|
||||
|
||||
|
|
@ -132,6 +136,19 @@ func (t *Transport) PreferredDomain(domain string) bool {
|
|||
return t.preferredResolver.PreferredDomain(domain)
|
||||
}
|
||||
|
||||
func (t *Transport) ServerAddresses() []netip.Addr {
|
||||
if t.resolved != nil {
|
||||
return t.resolved.ServerAddresses()
|
||||
}
|
||||
return common.Map(t.configSource.Configuration().Servers, func(it M.Socksaddr) netip.Addr {
|
||||
return it.Addr
|
||||
})
|
||||
}
|
||||
|
||||
func (t *Transport) SearchDomains() []string {
|
||||
return t.configSource.Configuration().Search
|
||||
}
|
||||
|
||||
func (t *Transport) Environment() []string {
|
||||
if t.resolved != nil {
|
||||
return t.resolved.Environment()
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package local
|
|||
|
||||
import (
|
||||
"context"
|
||||
"net/netip"
|
||||
|
||||
mDNS "github.com/miekg/dns"
|
||||
)
|
||||
|
|
@ -11,5 +12,6 @@ type ResolvedResolver interface {
|
|||
Close() error
|
||||
Reset()
|
||||
Environment() []string
|
||||
ServerAddresses() []netip.Addr
|
||||
ExchangeAsync(ctx context.Context, message *mDNS.Msg, callback func(response *mDNS.Msg, err error))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,9 +69,10 @@ type DBusResolvedResolver struct {
|
|||
}
|
||||
|
||||
type resolvedServerSet struct {
|
||||
scopes []*resolvedScope
|
||||
signature []string
|
||||
serverScope *adapter.Scope
|
||||
scopes []*resolvedScope
|
||||
serverAddresses []netip.Addr
|
||||
signature []string
|
||||
serverScope *adapter.Scope
|
||||
}
|
||||
|
||||
// Match levels of dns_scope_good_domain() in systemd-resolved: a routing or search
|
||||
|
|
@ -244,6 +245,14 @@ func (t *DBusResolvedResolver) Environment() []string {
|
|||
return serverSet.signature
|
||||
}
|
||||
|
||||
func (t *DBusResolvedResolver) ServerAddresses() []netip.Addr {
|
||||
serverSet := t.savedServerSet.Load()
|
||||
if serverSet == nil {
|
||||
return nil
|
||||
}
|
||||
return serverSet.serverAddresses
|
||||
}
|
||||
|
||||
func (t *DBusResolvedResolver) ExchangeAsync(ctx context.Context, message *mDNS.Msg, callback func(response *mDNS.Msg, err error)) {
|
||||
serverSet := t.savedServerSet.Load()
|
||||
if serverSet == nil {
|
||||
|
|
@ -569,6 +578,7 @@ func (t *DBusResolvedResolver) checkResolved(ctx context.Context) (*resolvedServ
|
|||
}
|
||||
serverSet.scopes = append(serverSet.scopes, scope)
|
||||
for _, serverSpecification := range scopeSpecification.servers {
|
||||
serverSet.serverAddresses = append(serverSet.serverAddresses, serverSpecification.address)
|
||||
serverSet.signature = append(serverSet.signature, scopeSpecification.interfaceName+"/"+M.SocksaddrFrom(serverSpecification.address, serverSpecification.port).String())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,11 @@
|
|||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
!!! quote "Changes in sing-box 1.15.0"
|
||||
|
||||
:material-plus: [dns_server_address](#dns_server_address)
|
||||
:material-plus: [dns_search_domain](#dns_search_domain)
|
||||
|
||||
!!! quote "Changes in sing-box 1.14.0"
|
||||
|
||||
:material-plus: [source_mac_address](#source_mac_address)
|
||||
|
|
@ -178,6 +183,16 @@ icon: material/alert-decagram
|
|||
"local",
|
||||
"ts-dns"
|
||||
],
|
||||
"dns_server_address": {
|
||||
"local": [
|
||||
"192.168.1.1/32"
|
||||
]
|
||||
},
|
||||
"dns_search_domain": {
|
||||
"ts-dns": [
|
||||
"example.ts.net"
|
||||
]
|
||||
},
|
||||
"wifi_ssid": [
|
||||
"My WIFI"
|
||||
],
|
||||
|
|
@ -535,6 +550,36 @@ Match specified DNS servers' preferred domains.
|
|||
| `openconnect` | Match split DNS and search domains pushed by the VPN server |
|
||||
| `resolved` | Match split DNS and search domains from systemd-resolved links |
|
||||
|
||||
#### dns_server_address
|
||||
|
||||
!!! question "Since sing-box 1.15.0"
|
||||
|
||||
Match specified DNS servers' server addresses.
|
||||
|
||||
| Type | Match |
|
||||
|---------------|-----------------------------------------------|
|
||||
| `local` | Match system DNS servers |
|
||||
| `dhcp` | Match DNS servers from DHCP |
|
||||
| `resolved` | Match DNS servers from systemd-resolved links |
|
||||
| `tailscale` | Match DNS resolvers of the tailnet |
|
||||
| `openvpn` | Match DNS servers pushed by the VPN server |
|
||||
| `openconnect` | Match DNS servers pushed by the VPN server |
|
||||
|
||||
#### dns_search_domain
|
||||
|
||||
!!! question "Since sing-box 1.15.0"
|
||||
|
||||
Match specified DNS servers' search domains.
|
||||
|
||||
| Type | Match |
|
||||
|---------------|--------------------------------------------------|
|
||||
| `local` | Match system search domains |
|
||||
| `dhcp` | Match search domains from DHCP |
|
||||
| `resolved` | Match search domains from systemd-resolved links |
|
||||
| `tailscale` | Match search domains of the tailnet |
|
||||
| `openvpn` | Match search domains pushed by the VPN server |
|
||||
| `openconnect` | Match search domains pushed by the VPN server |
|
||||
|
||||
#### wifi_ssid
|
||||
|
||||
!!! quote ""
|
||||
|
|
|
|||
|
|
@ -2,6 +2,11 @@
|
|||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
!!! quote "sing-box 1.15.0 中的更改"
|
||||
|
||||
:material-plus: [dns_server_address](#dns_server_address)
|
||||
:material-plus: [dns_search_domain](#dns_search_domain)
|
||||
|
||||
!!! quote "sing-box 1.14.0 中的更改"
|
||||
|
||||
:material-plus: [source_mac_address](#source_mac_address)
|
||||
|
|
@ -178,6 +183,16 @@ icon: material/alert-decagram
|
|||
"local",
|
||||
"ts-dns"
|
||||
],
|
||||
"dns_server_address": {
|
||||
"local": [
|
||||
"192.168.1.1/32"
|
||||
]
|
||||
},
|
||||
"dns_search_domain": {
|
||||
"ts-dns": [
|
||||
"example.ts.net"
|
||||
]
|
||||
},
|
||||
"wifi_ssid": [
|
||||
"My WIFI"
|
||||
],
|
||||
|
|
@ -529,6 +544,36 @@ Available values: `wifi`, `cellular`, `ethernet` and `other`.
|
|||
| `openconnect` | 匹配 VPN 服务器推送的分流 DNS 和搜索域 |
|
||||
| `resolved` | 匹配 systemd-resolved 链路中的分流域名和搜索域 |
|
||||
|
||||
#### dns_server_address
|
||||
|
||||
!!! question "自 sing-box 1.15.0 起"
|
||||
|
||||
匹配指定 DNS 服务器的服务器地址。
|
||||
|
||||
| 类型 | 匹配 |
|
||||
|---------------|----------------------------------|
|
||||
| `local` | 匹配系统 DNS 服务器 |
|
||||
| `dhcp` | 匹配通过 DHCP 获取的 DNS 服务器 |
|
||||
| `resolved` | 匹配 systemd-resolved 链路中的 DNS 服务器 |
|
||||
| `tailscale` | 匹配 tailnet 的 DNS 解析器 |
|
||||
| `openvpn` | 匹配 VPN 服务器推送的 DNS 服务器 |
|
||||
| `openconnect` | 匹配 VPN 服务器推送的 DNS 服务器 |
|
||||
|
||||
#### dns_search_domain
|
||||
|
||||
!!! question "自 sing-box 1.15.0 起"
|
||||
|
||||
匹配指定 DNS 服务器的搜索域。
|
||||
|
||||
| 类型 | 匹配 |
|
||||
|---------------|-------------------------------|
|
||||
| `local` | 匹配系统搜索域 |
|
||||
| `dhcp` | 匹配通过 DHCP 获取的搜索域 |
|
||||
| `resolved` | 匹配 systemd-resolved 链路中的搜索域 |
|
||||
| `tailscale` | 匹配 tailnet 的搜索域 |
|
||||
| `openvpn` | 匹配 VPN 服务器推送的搜索域 |
|
||||
| `openconnect` | 匹配 VPN 服务器推送的搜索域 |
|
||||
|
||||
#### wifi_ssid
|
||||
|
||||
!!! quote ""
|
||||
|
|
|
|||
|
|
@ -2,6 +2,11 @@
|
|||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! quote "Changes in sing-box 1.15.0"
|
||||
|
||||
:material-plus: [dns_server_address](#dns_server_address)
|
||||
:material-plus: [dns_search_domain](#dns_search_domain)
|
||||
|
||||
!!! quote "Changes in sing-box 1.14.0"
|
||||
|
||||
:material-plus: [source_mac_address](#source_mac_address)
|
||||
|
|
@ -168,6 +173,16 @@ icon: material/new-box
|
|||
"tailscale",
|
||||
"wireguard"
|
||||
],
|
||||
"dns_server_address": {
|
||||
"local": [
|
||||
"192.168.1.1/32"
|
||||
]
|
||||
},
|
||||
"dns_search_domain": {
|
||||
"ts-dns": [
|
||||
"example.ts.net"
|
||||
]
|
||||
},
|
||||
"source_mac_address": [
|
||||
"00:11:22:33:44:55"
|
||||
],
|
||||
|
|
@ -471,6 +486,36 @@ Match specified outbounds' preferred routes.
|
|||
| `wireguard` | Match peers's allowed IPs |
|
||||
| `bridge` | Match all addresses except local addresses of the machine, only in [pre-match](/configuration/shared/pre-match/) |
|
||||
|
||||
#### dns_server_address
|
||||
|
||||
!!! question "Since sing-box 1.15.0"
|
||||
|
||||
Match specified DNS servers' server addresses.
|
||||
|
||||
| Type | Match |
|
||||
|---------------|-----------------------------------------------|
|
||||
| `local` | Match system DNS servers |
|
||||
| `dhcp` | Match DNS servers from DHCP |
|
||||
| `resolved` | Match DNS servers from systemd-resolved links |
|
||||
| `tailscale` | Match DNS resolvers of the tailnet |
|
||||
| `openvpn` | Match DNS servers pushed by the VPN server |
|
||||
| `openconnect` | Match DNS servers pushed by the VPN server |
|
||||
|
||||
#### dns_search_domain
|
||||
|
||||
!!! question "Since sing-box 1.15.0"
|
||||
|
||||
Match specified DNS servers' search domains.
|
||||
|
||||
| Type | Match |
|
||||
|---------------|--------------------------------------------------|
|
||||
| `local` | Match system search domains |
|
||||
| `dhcp` | Match search domains from DHCP |
|
||||
| `resolved` | Match search domains from systemd-resolved links |
|
||||
| `tailscale` | Match search domains of the tailnet |
|
||||
| `openvpn` | Match search domains pushed by the VPN server |
|
||||
| `openconnect` | Match search domains pushed by the VPN server |
|
||||
|
||||
#### source_mac_address
|
||||
|
||||
!!! question "Since sing-box 1.14.0"
|
||||
|
|
|
|||
|
|
@ -2,6 +2,11 @@
|
|||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! quote "sing-box 1.15.0 中的更改"
|
||||
|
||||
:material-plus: [dns_server_address](#dns_server_address)
|
||||
:material-plus: [dns_search_domain](#dns_search_domain)
|
||||
|
||||
!!! quote "sing-box 1.14.0 中的更改"
|
||||
|
||||
:material-plus: [source_mac_address](#source_mac_address)
|
||||
|
|
@ -166,6 +171,16 @@ icon: material/new-box
|
|||
"tailscale",
|
||||
"wireguard"
|
||||
],
|
||||
"dns_server_address": {
|
||||
"local": [
|
||||
"192.168.1.1/32"
|
||||
]
|
||||
},
|
||||
"dns_search_domain": {
|
||||
"ts-dns": [
|
||||
"example.ts.net"
|
||||
]
|
||||
},
|
||||
"source_mac_address": [
|
||||
"00:11:22:33:44:55"
|
||||
],
|
||||
|
|
@ -469,6 +484,36 @@ icon: material/new-box
|
|||
| `wireguard` | 匹配对端的 allowed IPs |
|
||||
| `bridge` | 匹配除本机本地地址外的所有地址,仅在[预匹配](/zh/configuration/shared/pre-match/)中 |
|
||||
|
||||
#### dns_server_address
|
||||
|
||||
!!! question "自 sing-box 1.15.0 起"
|
||||
|
||||
匹配指定 DNS 服务器的服务器地址。
|
||||
|
||||
| 类型 | 匹配 |
|
||||
|---------------|----------------------------------|
|
||||
| `local` | 匹配系统 DNS 服务器 |
|
||||
| `dhcp` | 匹配通过 DHCP 获取的 DNS 服务器 |
|
||||
| `resolved` | 匹配 systemd-resolved 链路中的 DNS 服务器 |
|
||||
| `tailscale` | 匹配 tailnet 的 DNS 解析器 |
|
||||
| `openvpn` | 匹配 VPN 服务器推送的 DNS 服务器 |
|
||||
| `openconnect` | 匹配 VPN 服务器推送的 DNS 服务器 |
|
||||
|
||||
#### dns_search_domain
|
||||
|
||||
!!! question "自 sing-box 1.15.0 起"
|
||||
|
||||
匹配指定 DNS 服务器的搜索域。
|
||||
|
||||
| 类型 | 匹配 |
|
||||
|---------------|-------------------------------|
|
||||
| `local` | 匹配系统搜索域 |
|
||||
| `dhcp` | 匹配通过 DHCP 获取的搜索域 |
|
||||
| `resolved` | 匹配 systemd-resolved 链路中的搜索域 |
|
||||
| `tailscale` | 匹配 tailnet 的搜索域 |
|
||||
| `openvpn` | 匹配 VPN 服务器推送的搜索域 |
|
||||
| `openconnect` | 匹配 VPN 服务器推送的搜索域 |
|
||||
|
||||
#### source_mac_address
|
||||
|
||||
!!! question "自 sing-box 1.14.0 起"
|
||||
|
|
|
|||
128
docs/schema.json
128
docs/schema.json
|
|
@ -1513,6 +1513,38 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"dns_server_address": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/$defs/IPAddressOrPrefix"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/IPAddressOrPrefix"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"dns_search_domain": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"rule_set": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
@ -9811,6 +9843,38 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"dns_server_address": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/$defs/IPAddressOrPrefix"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/IPAddressOrPrefix"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"dns_search_domain": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"rule_set": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
@ -10428,6 +10492,38 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"dns_server_address": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/$defs/IPAddressOrPrefix"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/IPAddressOrPrefix"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"dns_search_domain": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"rule_set": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
@ -15601,6 +15697,38 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"dns_server_address": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/$defs/IPAddressOrPrefix"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/IPAddressOrPrefix"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"dns_search_domain": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"rule_set": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -58,6 +58,35 @@ func (p *platformTransport) PreferredDomain(domain string) bool {
|
|||
return p.preferredResolver.PreferredDomain(domain)
|
||||
}
|
||||
|
||||
func (p *platformTransport) ServerAddresses() []netip.Addr {
|
||||
if p.networkManager == nil {
|
||||
return nil
|
||||
}
|
||||
defaultInterface := p.networkManager.DefaultNetworkInterface()
|
||||
if defaultInterface == nil {
|
||||
return nil
|
||||
}
|
||||
var serverAddresses []netip.Addr
|
||||
for _, server := range defaultInterface.DNSServers {
|
||||
serverAddr, err := netip.ParseAddr(server)
|
||||
if err == nil {
|
||||
serverAddresses = append(serverAddresses, serverAddr)
|
||||
}
|
||||
}
|
||||
return serverAddresses
|
||||
}
|
||||
|
||||
func (p *platformTransport) SearchDomains() []string {
|
||||
if p.networkManager == nil {
|
||||
return nil
|
||||
}
|
||||
defaultInterface := p.networkManager.DefaultNetworkInterface()
|
||||
if defaultInterface == nil {
|
||||
return nil
|
||||
}
|
||||
return defaultInterface.DNSSearchDomains
|
||||
}
|
||||
|
||||
func (p *platformTransport) Environment() []string {
|
||||
if p.networkManager == nil {
|
||||
return nil
|
||||
|
|
@ -180,5 +209,6 @@ func (c *ExchangeContext) ErrnoCode(code int32) {
|
|||
var (
|
||||
_ adapter.DNSTransport = (*platformTransport)(nil)
|
||||
_ adapter.DNSTransportWithPreferredDomain = (*platformTransport)(nil)
|
||||
_ adapter.DNSTransportWithConfiguration = (*platformTransport)(nil)
|
||||
_ adapter.DNSTransportWithEnvironment = (*platformTransport)(nil)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -129,10 +129,11 @@ type NetworkInterface struct {
|
|||
Addresses StringIterator
|
||||
Flags int32
|
||||
|
||||
Type int32
|
||||
DNSServer StringIterator
|
||||
Gateway StringIterator
|
||||
Metered bool
|
||||
Type int32
|
||||
DNSServer StringIterator
|
||||
DNSSearchDomain StringIterator
|
||||
Gateway StringIterator
|
||||
Metered bool
|
||||
}
|
||||
|
||||
type WIFIState struct {
|
||||
|
|
|
|||
|
|
@ -143,8 +143,9 @@ func (w *platformInterfaceWrapper) NetworkInterfaces() ([]adapter.NetworkInterfa
|
|||
Addresses: common.Map(iteratorToArray[string](netInterface.Addresses), netip.MustParsePrefix),
|
||||
Flags: linkFlags(uint32(netInterface.Flags)),
|
||||
},
|
||||
Type: C.InterfaceType(netInterface.Type),
|
||||
DNSServers: iteratorToArray[string](netInterface.DNSServer),
|
||||
Type: C.InterfaceType(netInterface.Type),
|
||||
DNSServers: iteratorToArray[string](netInterface.DNSServer),
|
||||
DNSSearchDomains: iteratorToArray[string](netInterface.DNSSearchDomain),
|
||||
Gateways: common.Filter(common.Map(iteratorToArray[string](netInterface.Gateway), func(it string) netip.Addr {
|
||||
gateway, _ := netip.ParseAddr(it)
|
||||
return gateway.Unmap().WithZone("")
|
||||
|
|
|
|||
|
|
@ -178,6 +178,8 @@ type RawDefaultRule struct {
|
|||
SourceMACAddress badoption.Listable[string] `json:"source_mac_address,omitempty"`
|
||||
SourceHostname badoption.Listable[string] `json:"source_hostname,omitempty"`
|
||||
PreferredBy badoption.Listable[string] `json:"preferred_by,omitempty"`
|
||||
DNSServerAddress *badjson.TypedMap[string, badoption.Listable[*badoption.Prefixable]] `json:"dns_server_address,omitempty"`
|
||||
DNSSearchDomain *badjson.TypedMap[string, badoption.Listable[string]] `json:"dns_search_domain,omitempty"`
|
||||
RuleSet badoption.Listable[string] `json:"rule_set,omitempty" reference:"rule_set"`
|
||||
RuleSetIPCIDRMatchSource bool `json:"rule_set_ip_cidr_match_source,omitempty"`
|
||||
Invert bool `json:"invert,omitempty"`
|
||||
|
|
|
|||
|
|
@ -173,6 +173,8 @@ type RawDefaultDNSRule struct {
|
|||
SourceMACAddress badoption.Listable[string] `json:"source_mac_address,omitempty"`
|
||||
SourceHostname badoption.Listable[string] `json:"source_hostname,omitempty"`
|
||||
PreferredBy badoption.Listable[string] `json:"preferred_by,omitempty"`
|
||||
DNSServerAddress *badjson.TypedMap[string, badoption.Listable[*badoption.Prefixable]] `json:"dns_server_address,omitempty"`
|
||||
DNSSearchDomain *badjson.TypedMap[string, badoption.Listable[string]] `json:"dns_search_domain,omitempty"`
|
||||
RuleSet badoption.Listable[string] `json:"rule_set,omitempty" reference:"rule_set"`
|
||||
RuleSetIPCIDRMatchSource bool `json:"rule_set_ip_cidr_match_source,omitempty"`
|
||||
MatchResponse *DNSRuleMatchResponse `json:"match_response,omitempty"`
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ type DNSTransport struct {
|
|||
closed bool
|
||||
routes []openConnectDNSRoute
|
||||
searchDomains []string
|
||||
serverAddresses []netip.Addr
|
||||
defaultResolvers []adapter.DNSTransport
|
||||
resolverScope *adapter.Scope
|
||||
}
|
||||
|
|
@ -83,6 +84,7 @@ func (t *DNSTransport) Start(stage adapter.StartStage, scope *adapter.Scope) err
|
|||
t.closed = true
|
||||
t.routes = nil
|
||||
t.searchDomains = nil
|
||||
t.serverAddresses = nil
|
||||
t.defaultResolvers = nil
|
||||
t.resolverScope = nil
|
||||
t.access.Unlock()
|
||||
|
|
@ -116,6 +118,7 @@ func (t *DNSTransport) Start(stage adapter.StartStage, scope *adapter.Scope) err
|
|||
|
||||
func (t *DNSTransport) updateConfiguration(configuration openconnecttransport.Configuration) {
|
||||
resolverByAddress := make(map[netip.Addr]adapter.DNSTransport)
|
||||
var serverAddresses []netip.Addr
|
||||
resolverFor := func(address netip.Addr) adapter.DNSTransport {
|
||||
if !address.IsValid() {
|
||||
return nil
|
||||
|
|
@ -124,6 +127,7 @@ func (t *DNSTransport) updateConfiguration(configuration openconnecttransport.Co
|
|||
if loaded {
|
||||
return resolver
|
||||
}
|
||||
serverAddresses = append(serverAddresses, address)
|
||||
resolver = transport.NewUDPRaw(
|
||||
t.logger,
|
||||
dns.NewTransportAdapter(C.DNSTypeUDP, t.Tag()+"/"+address.String(), nil),
|
||||
|
|
@ -217,6 +221,7 @@ func (t *DNSTransport) updateConfiguration(configuration openconnecttransport.Co
|
|||
oldResolverScope := t.resolverScope
|
||||
t.routes = routes
|
||||
t.searchDomains = searchDomains
|
||||
t.serverAddresses = serverAddresses
|
||||
t.defaultResolvers = defaultResolvers
|
||||
t.resolverScope = resolverScope
|
||||
t.access.Unlock()
|
||||
|
|
@ -239,6 +244,18 @@ func (t *DNSTransport) Reset() {
|
|||
}
|
||||
}
|
||||
|
||||
func (t *DNSTransport) ServerAddresses() []netip.Addr {
|
||||
t.access.RLock()
|
||||
defer t.access.RUnlock()
|
||||
return t.serverAddresses
|
||||
}
|
||||
|
||||
func (t *DNSTransport) SearchDomains() []string {
|
||||
t.access.RLock()
|
||||
defer t.access.RUnlock()
|
||||
return t.searchDomains
|
||||
}
|
||||
|
||||
func (t *DNSTransport) PreferredDomain(domain string) bool {
|
||||
canonicalDomain := mDNS.Fqdn(canonicalOpenConnectDomain(domain))
|
||||
t.access.RLock()
|
||||
|
|
@ -369,3 +386,8 @@ func (t *DNSTransport) collectResolversLocked() []adapter.DNSTransport {
|
|||
}
|
||||
return resolvers
|
||||
}
|
||||
|
||||
var (
|
||||
_ adapter.DNSTransportWithPreferredDomain = (*DNSTransport)(nil)
|
||||
_ adapter.DNSTransportWithConfiguration = (*DNSTransport)(nil)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ type DNSTransport struct {
|
|||
closed bool
|
||||
routes map[string][]adapter.DNSTransport
|
||||
searchDomains []string
|
||||
serverAddresses []netip.Addr
|
||||
defaultResolvers []adapter.DNSTransport
|
||||
resolverScope *adapter.Scope
|
||||
}
|
||||
|
|
@ -88,6 +89,7 @@ func (t *DNSTransport) Start(stage adapter.StartStage, scope *adapter.Scope) err
|
|||
t.closed = true
|
||||
t.routes = nil
|
||||
t.searchDomains = nil
|
||||
t.serverAddresses = nil
|
||||
t.defaultResolvers = nil
|
||||
t.resolverScope = nil
|
||||
t.access.Unlock()
|
||||
|
|
@ -133,6 +135,7 @@ func (t *DNSTransport) updateResolvers(configuration ovpntransport.Configuration
|
|||
return left.Priority - right.Priority
|
||||
})
|
||||
var selectedResolvers []adapter.DNSTransport
|
||||
var serverAddresses []netip.Addr
|
||||
if len(servers) > 0 {
|
||||
server := servers[0]
|
||||
if server.DNSSEC == "yes" {
|
||||
|
|
@ -148,6 +151,7 @@ func (t *DNSTransport) updateResolvers(configuration ovpntransport.Configuration
|
|||
return t.failResolverUpdate(resolverScope, err)
|
||||
}
|
||||
selectedResolvers = append(selectedResolvers, resolver)
|
||||
serverAddresses = append(serverAddresses, address.Addr())
|
||||
}
|
||||
if len(selectedResolvers) == 0 {
|
||||
return t.failResolverUpdate(resolverScope, E.New("DNS server ", server.Priority, " has no addresses"))
|
||||
|
|
@ -170,6 +174,7 @@ func (t *DNSTransport) updateResolvers(configuration ovpntransport.Configuration
|
|||
return t.failResolverUpdate(resolverScope, err)
|
||||
}
|
||||
selectedResolvers = append(selectedResolvers, resolver)
|
||||
serverAddresses = append(serverAddresses, address)
|
||||
}
|
||||
if len(configuration.DNSRoutes) > 0 {
|
||||
if len(selectedResolvers) == 0 {
|
||||
|
|
@ -196,6 +201,7 @@ func (t *DNSTransport) updateResolvers(configuration ovpntransport.Configuration
|
|||
oldResolverScope := t.resolverScope
|
||||
t.routes = routes
|
||||
t.searchDomains = searchDomains
|
||||
t.serverAddresses = serverAddresses
|
||||
t.defaultResolvers = defaultResolvers
|
||||
t.resolverScope = resolverScope
|
||||
t.access.Unlock()
|
||||
|
|
@ -213,6 +219,7 @@ func (t *DNSTransport) failResolverUpdate(resolverScope *adapter.Scope, updateEr
|
|||
oldResolverScope := t.resolverScope
|
||||
t.routes = nil
|
||||
t.searchDomains = nil
|
||||
t.serverAddresses = nil
|
||||
t.defaultResolvers = nil
|
||||
t.resolverScope = nil
|
||||
t.access.Unlock()
|
||||
|
|
@ -290,6 +297,18 @@ func (t *DNSTransport) Raw() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (t *DNSTransport) ServerAddresses() []netip.Addr {
|
||||
t.access.RLock()
|
||||
defer t.access.RUnlock()
|
||||
return t.serverAddresses
|
||||
}
|
||||
|
||||
func (t *DNSTransport) SearchDomains() []string {
|
||||
t.access.RLock()
|
||||
defer t.access.RUnlock()
|
||||
return t.searchDomains
|
||||
}
|
||||
|
||||
func (t *DNSTransport) PreferredDomain(domain string) bool {
|
||||
t.access.RLock()
|
||||
defer t.access.RUnlock()
|
||||
|
|
@ -428,3 +447,8 @@ func restoreOpenVPNOriginalQuestion(response *mDNS.Msg, expandedName string, ori
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
_ adapter.DNSTransportWithPreferredDomain = (*DNSTransport)(nil)
|
||||
_ adapter.DNSTransportWithConfiguration = (*DNSTransport)(nil)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ type DNSTransport struct {
|
|||
hosts map[string][]netip.Addr
|
||||
magicHosts nDNSResolver.MagicDNSHosts
|
||||
searchDomains []string
|
||||
serverAddresses []netip.Addr
|
||||
defaultResolvers []adapter.DNSTransport
|
||||
resolverScope *adapter.Scope
|
||||
}
|
||||
|
|
@ -102,6 +103,7 @@ func (t *DNSTransport) Start(stage adapter.StartStage, scope *adapter.Scope) err
|
|||
t.routes = nil
|
||||
t.hosts = nil
|
||||
t.magicHosts = nil
|
||||
t.serverAddresses = nil
|
||||
t.defaultResolvers = nil
|
||||
t.resolverScope = nil
|
||||
t.access.Unlock()
|
||||
|
|
@ -137,6 +139,7 @@ func (t *DNSTransport) updateDNSServers(routeConfig *router.Config, dnsConfig *n
|
|||
})
|
||||
resolverScope := adapter.NewScope(t.ctx, t.logger)
|
||||
routes := make(map[string][]adapter.DNSTransport)
|
||||
var serverAddresses []netip.Addr
|
||||
for domain, resolvers := range dnsConfig.Routes {
|
||||
var myResolvers []adapter.DNSTransport
|
||||
for _, resolver := range resolvers {
|
||||
|
|
@ -145,6 +148,10 @@ func (t *DNSTransport) updateDNSServers(routeConfig *router.Config, dnsConfig *n
|
|||
return E.Errors(err, resolverScope.Close())
|
||||
}
|
||||
myResolvers = append(myResolvers, myResolver)
|
||||
serverAddrPort, isIPResolver := resolver.IPPort()
|
||||
if isIPResolver {
|
||||
serverAddresses = append(serverAddresses, serverAddrPort.Addr())
|
||||
}
|
||||
}
|
||||
routes[mDNS.CanonicalName(domain.WithTrailingDot())] = myResolvers
|
||||
}
|
||||
|
|
@ -162,6 +169,10 @@ func (t *DNSTransport) updateDNSServers(routeConfig *router.Config, dnsConfig *n
|
|||
return E.Errors(err, resolverScope.Close())
|
||||
}
|
||||
defaultResolvers = append(defaultResolvers, myResolver)
|
||||
serverAddrPort, isIPResolver := resolver.IPPort()
|
||||
if isIPResolver {
|
||||
serverAddresses = append(serverAddresses, serverAddrPort.Addr())
|
||||
}
|
||||
}
|
||||
|
||||
t.access.Lock()
|
||||
|
|
@ -171,6 +182,7 @@ func (t *DNSTransport) updateDNSServers(routeConfig *router.Config, dnsConfig *n
|
|||
t.hosts = hosts
|
||||
t.magicHosts = t.endpoint.server.ExportLocalBackend().ExportMagicDNSHosts()
|
||||
t.searchDomains = searchDomains
|
||||
t.serverAddresses = common.Uniq(serverAddresses)
|
||||
t.defaultResolvers = defaultResolvers
|
||||
t.resolverScope = resolverScope
|
||||
t.access.Unlock()
|
||||
|
|
@ -285,6 +297,18 @@ func (t *DNSTransport) Raw() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (t *DNSTransport) ServerAddresses() []netip.Addr {
|
||||
t.access.RLock()
|
||||
defer t.access.RUnlock()
|
||||
return t.serverAddresses
|
||||
}
|
||||
|
||||
func (t *DNSTransport) SearchDomains() []string {
|
||||
t.access.RLock()
|
||||
defer t.access.RUnlock()
|
||||
return t.searchDomains
|
||||
}
|
||||
|
||||
func (t *DNSTransport) PreferredDomain(domain string) bool {
|
||||
t.access.RLock()
|
||||
hosts := t.hosts
|
||||
|
|
@ -515,3 +539,8 @@ func (t *DNSTransport) routePrefixesSnapshot() []netip.Prefix {
|
|||
defer t.access.RUnlock()
|
||||
return append([]netip.Prefix(nil), t.routePrefixes...)
|
||||
}
|
||||
|
||||
var (
|
||||
_ adapter.DNSTransportWithPreferredDomain = (*DNSTransport)(nil)
|
||||
_ adapter.DNSTransportWithConfiguration = (*DNSTransport)(nil)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -283,6 +283,16 @@ func NewDefaultRule(ctx context.Context, logger log.ContextLogger, options optio
|
|||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if options.DNSServerAddress != nil && options.DNSServerAddress.Size() > 0 {
|
||||
item := NewDNSServerAddressItem(ctx, options.DNSServerAddress)
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if options.DNSSearchDomain != nil && options.DNSSearchDomain.Size() > 0 {
|
||||
item := NewDNSSearchDomainItem(ctx, options.DNSSearchDomain)
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.RuleSet) > 0 {
|
||||
//nolint:staticcheck
|
||||
if options.Deprecated_RulesetIPCIDRMatchSource {
|
||||
|
|
|
|||
|
|
@ -377,6 +377,16 @@ func NewDefaultDNSRule(ctx context.Context, logger log.ContextLogger, options op
|
|||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if options.DNSServerAddress != nil && options.DNSServerAddress.Size() > 0 {
|
||||
item := NewDNSServerAddressItem(ctx, options.DNSServerAddress)
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if options.DNSSearchDomain != nil && options.DNSSearchDomain.Size() > 0 {
|
||||
item := NewDNSSearchDomainItem(ctx, options.DNSSearchDomain)
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if options.RuleSetIPCIDRAcceptEmpty { //nolint:staticcheck
|
||||
if legacyDNSMode {
|
||||
deprecated.Report(ctx, deprecated.OptionRuleSetIPCIDRAcceptEmpty)
|
||||
|
|
|
|||
72
route/rule/rule_item_dns_search_domain.go
Normal file
72
route/rule/rule_item_dns_search_domain.go
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
package rule
|
||||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/json/badjson"
|
||||
"github.com/sagernet/sing/common/json/badoption"
|
||||
"github.com/sagernet/sing/service"
|
||||
|
||||
mDNS "github.com/miekg/dns"
|
||||
)
|
||||
|
||||
var _ RuleItem = (*DNSSearchDomainItem)(nil)
|
||||
|
||||
type DNSSearchDomainItem struct {
|
||||
ctx context.Context
|
||||
transportTags []string
|
||||
searchDomains [][]string
|
||||
transports []adapter.DNSTransportWithConfiguration
|
||||
description string
|
||||
}
|
||||
|
||||
func NewDNSSearchDomainItem(ctx context.Context, searchDomains *badjson.TypedMap[string, badoption.Listable[string]]) *DNSSearchDomainItem {
|
||||
item := &DNSSearchDomainItem{
|
||||
ctx: ctx,
|
||||
}
|
||||
var entryDescriptions []string
|
||||
for _, entry := range searchDomains.Entries() {
|
||||
item.transportTags = append(item.transportTags, entry.Key)
|
||||
item.searchDomains = append(item.searchDomains, common.Map(entry.Value, mDNS.CanonicalName))
|
||||
entryDescriptions = append(entryDescriptions, entry.Key+"="+strings.Join(entry.Value, ","))
|
||||
}
|
||||
item.description = "dns_search_domain=[" + strings.Join(entryDescriptions, " ") + "]"
|
||||
return item
|
||||
}
|
||||
|
||||
func (r *DNSSearchDomainItem) Start() error {
|
||||
transportManager := service.FromContext[adapter.DNSTransportManager](r.ctx)
|
||||
for _, transportTag := range r.transportTags {
|
||||
rawTransport, loaded := transportManager.Transport(transportTag)
|
||||
if !loaded {
|
||||
return E.New("DNS server not found: ", transportTag)
|
||||
}
|
||||
transportWithConfiguration, withConfiguration := rawTransport.(adapter.DNSTransportWithConfiguration)
|
||||
if !withConfiguration {
|
||||
return E.New("DNS server type does not support dns_search_domain: ", rawTransport.Type())
|
||||
}
|
||||
r.transports = append(r.transports, transportWithConfiguration)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *DNSSearchDomainItem) Match(metadata *adapter.InboundContext) bool {
|
||||
for i, transport := range r.transports {
|
||||
domains := r.searchDomains[i]
|
||||
if !slices.ContainsFunc(transport.SearchDomains(), func(searchDomain string) bool {
|
||||
return slices.Contains(domains, mDNS.CanonicalName(searchDomain))
|
||||
}) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *DNSSearchDomainItem) String() string {
|
||||
return r.description
|
||||
}
|
||||
78
route/rule/rule_item_dns_server_address.go
Normal file
78
route/rule/rule_item_dns_server_address.go
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
package rule
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/netip"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/json/badjson"
|
||||
"github.com/sagernet/sing/common/json/badoption"
|
||||
"github.com/sagernet/sing/service"
|
||||
)
|
||||
|
||||
var _ RuleItem = (*DNSServerAddressItem)(nil)
|
||||
|
||||
type DNSServerAddressItem struct {
|
||||
ctx context.Context
|
||||
transportTags []string
|
||||
serverAddresses [][]netip.Prefix
|
||||
transports []adapter.DNSTransportWithConfiguration
|
||||
description string
|
||||
}
|
||||
|
||||
func NewDNSServerAddressItem(ctx context.Context, serverAddresses *badjson.TypedMap[string, badoption.Listable[*badoption.Prefixable]]) *DNSServerAddressItem {
|
||||
item := &DNSServerAddressItem{
|
||||
ctx: ctx,
|
||||
}
|
||||
var entryDescriptions []string
|
||||
for _, entry := range serverAddresses.Entries() {
|
||||
prefixes := make([]netip.Prefix, 0, len(entry.Value))
|
||||
for _, prefixable := range entry.Value {
|
||||
prefixes = append(prefixes, prefixable.Build(netip.Prefix{}))
|
||||
}
|
||||
item.transportTags = append(item.transportTags, entry.Key)
|
||||
item.serverAddresses = append(item.serverAddresses, prefixes)
|
||||
entryDescriptions = append(entryDescriptions, entry.Key+"="+strings.Join(common.Map(prefixes, netip.Prefix.String), ","))
|
||||
}
|
||||
item.description = "dns_server_address=[" + strings.Join(entryDescriptions, " ") + "]"
|
||||
return item
|
||||
}
|
||||
|
||||
func (r *DNSServerAddressItem) Start() error {
|
||||
transportManager := service.FromContext[adapter.DNSTransportManager](r.ctx)
|
||||
for _, transportTag := range r.transportTags {
|
||||
rawTransport, loaded := transportManager.Transport(transportTag)
|
||||
if !loaded {
|
||||
return E.New("DNS server not found: ", transportTag)
|
||||
}
|
||||
transportWithConfiguration, withConfiguration := rawTransport.(adapter.DNSTransportWithConfiguration)
|
||||
if !withConfiguration {
|
||||
return E.New("DNS server type does not support dns_server_address: ", rawTransport.Type())
|
||||
}
|
||||
r.transports = append(r.transports, transportWithConfiguration)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *DNSServerAddressItem) Match(metadata *adapter.InboundContext) bool {
|
||||
for i, transport := range r.transports {
|
||||
prefixes := r.serverAddresses[i]
|
||||
if !slices.ContainsFunc(transport.ServerAddresses(), func(address netip.Addr) bool {
|
||||
unwrappedAddress := address.Unmap().WithZone("")
|
||||
return slices.ContainsFunc(prefixes, func(prefix netip.Prefix) bool {
|
||||
return prefix.Contains(unwrappedAddress)
|
||||
})
|
||||
}) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *DNSServerAddressItem) String() string {
|
||||
return r.description
|
||||
}
|
||||
|
|
@ -36,6 +36,7 @@ func RegisterTransport(registry *dns.TransportRegistry) {
|
|||
var (
|
||||
_ adapter.DNSTransport = (*Transport)(nil)
|
||||
_ adapter.DNSTransportWithPreferredDomain = (*Transport)(nil)
|
||||
_ adapter.DNSTransportWithConfiguration = (*Transport)(nil)
|
||||
_ adapter.DNSTransportWithEnvironment = (*Transport)(nil)
|
||||
)
|
||||
|
||||
|
|
@ -165,6 +166,47 @@ func (t *Transport) Environment() []string {
|
|||
return environment
|
||||
}
|
||||
|
||||
func (t *Transport) ServerAddresses() []netip.Addr {
|
||||
if t.service == nil {
|
||||
return nil
|
||||
}
|
||||
t.service.linkAccess.RLock()
|
||||
defer t.service.linkAccess.RUnlock()
|
||||
var serverAddresses []netip.Addr
|
||||
for _, link := range t.service.links {
|
||||
for _, address := range link.address {
|
||||
serverAddr, loaded := netip.AddrFromSlice(address.Address)
|
||||
if loaded {
|
||||
serverAddresses = append(serverAddresses, serverAddr)
|
||||
}
|
||||
}
|
||||
for _, address := range link.addressEx {
|
||||
serverAddr, loaded := netip.AddrFromSlice(address.Address)
|
||||
if loaded {
|
||||
serverAddresses = append(serverAddresses, serverAddr)
|
||||
}
|
||||
}
|
||||
}
|
||||
return serverAddresses
|
||||
}
|
||||
|
||||
func (t *Transport) SearchDomains() []string {
|
||||
if t.service == nil {
|
||||
return nil
|
||||
}
|
||||
t.service.linkAccess.RLock()
|
||||
defer t.service.linkAccess.RUnlock()
|
||||
var searchDomains []string
|
||||
for _, link := range t.service.links {
|
||||
for _, domain := range link.domain {
|
||||
if !domain.RoutingOnly && domain.Domain != "." {
|
||||
searchDomains = append(searchDomains, domain.Domain)
|
||||
}
|
||||
}
|
||||
}
|
||||
return searchDomains
|
||||
}
|
||||
|
||||
func (t *Transport) updateTransports(link *TransportLink) error {
|
||||
t.linkAccess.Lock()
|
||||
defer t.linkAccess.Unlock()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue