Skip to content

Commit 1d57468

Browse files
committed
Add DNS mode
1 parent 1cd2ebf commit 1d57468

4 files changed

Lines changed: 103 additions & 58 deletions

File tree

redirect_nftables_rules.go

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -675,7 +675,7 @@ func (r *autoRedirect) nftablesCreateExcludeRules(nft *nftables.Conn, table *nft
675675
nftablesCreateExcludeDestinationIPSet(nft, table, chain, inet6RouteExcludeAddress.ID, inet6RouteExcludeAddress.Name, nftables.TableFamilyIPv6, false)
676676
}
677677

678-
if !r.tunOptions.EXP_DisableDNSHijack && ((chain.Hooknum == nftables.ChainHookPrerouting && chain.Type == nftables.ChainTypeNAT) ||
678+
if r.tunOptions.DNSModeOrDefault() == DNSModeHijack && ((chain.Hooknum == nftables.ChainHookPrerouting && chain.Type == nftables.ChainTypeNAT) ||
679679
(r.tunOptions.AutoRedirectMarkMode && chain.Hooknum == nftables.ChainHookOutput && chain.Type == nftables.ChainTypeNAT)) {
680680
if r.enableIPv4 {
681681
err := r.nftablesCreateDNSHijackRulesForFamily(nft, table, chain, nftables.TableFamilyIPv4, 5, "inet4_local_address_set")
@@ -997,23 +997,19 @@ func (r *autoRedirect) nftablesCreateDNSHijackRulesForFamily(
997997
if err != nil {
998998
return E.Cause(err, "add dns protocol set")
999999
}
1000-
dnsServer := common.Find(r.tunOptions.DNSServers, func(it netip.Addr) bool {
1001-
return it.Is4() == (family == nftables.TableFamilyIPv4)
1002-
})
1003-
if !dnsServer.IsValid() {
1004-
if family == nftables.TableFamilyIPv4 {
1005-
if HasNextAddress(r.tunOptions.Inet4Address[0], 1) {
1006-
dnsServer = r.tunOptions.Inet4Address[0].Addr().Next()
1007-
}
1008-
} else {
1009-
if HasNextAddress(r.tunOptions.Inet6Address[0], 1) {
1010-
dnsServer = r.tunOptions.Inet6Address[0].Addr().Next()
1011-
}
1012-
}
1000+
var dnsServers []netip.Addr
1001+
if family == nftables.TableFamilyIPv4 {
1002+
dnsServers, err = r.tunOptions.Inet4DNSAddress()
1003+
} else {
1004+
dnsServers, err = r.tunOptions.Inet6DNSAddress()
1005+
}
1006+
if err != nil {
1007+
return err
10131008
}
1014-
if !dnsServer.IsValid() {
1009+
if len(dnsServers) == 0 {
10151010
return nil
10161011
}
1012+
dnsServer := dnsServers[0]
10171013
exprs := []expr.Any{
10181014
&expr.Meta{
10191015
Key: expr.MetaKeyNFPROTO,

tun.go

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ import (
99
"strings"
1010
"time"
1111

12+
"github.com/sagernet/sing/common"
1213
"github.com/sagernet/sing/common/buf"
1314
"github.com/sagernet/sing/common/control"
15+
E "github.com/sagernet/sing/common/exceptions"
1416
F "github.com/sagernet/sing/common/format"
1517
"github.com/sagernet/sing/common/logger"
1618
M "github.com/sagernet/sing/common/metadata"
@@ -68,6 +70,12 @@ const (
6870
DefaultIPRoute2AutoRedirectFallbackRuleIndex = 32768
6971
)
7072

73+
const (
74+
DNSModeDisabled = "disabled"
75+
DNSModeNative = "native"
76+
DNSModeHijack = "hijack"
77+
)
78+
7179
type Options struct {
7280
Name string
7381
Inet4Address []netip.Prefix
@@ -78,7 +86,8 @@ type Options struct {
7886
InterfaceScope bool
7987
Inet4Gateway netip.Addr
8088
Inet6Gateway netip.Addr
81-
DNSServers []netip.Addr
89+
DNSMode string
90+
DNSAddress []netip.Addr
8291
IPRoute2TableIndex int
8392
IPRoute2RuleIndex int
8493
IPRoute2AutoRedirectFallbackRuleIndex int
@@ -124,6 +133,57 @@ type Options struct {
124133
EXP_SendMsgX bool
125134
}
126135

136+
func (o *Options) DNSModeOrDefault() string {
137+
if o.DNSMode == "" {
138+
return DNSModeHijack
139+
}
140+
return o.DNSMode
141+
}
142+
143+
func (o *Options) DNSServerAddress() ([]netip.Addr, error) {
144+
inet4DNS, err := o.Inet4DNSAddress()
145+
if err != nil {
146+
return nil, err
147+
}
148+
inet6DNS, err := o.Inet6DNSAddress()
149+
if err != nil {
150+
return nil, err
151+
}
152+
return append(inet4DNS, inet6DNS...), nil
153+
}
154+
155+
func (o *Options) Inet4DNSAddress() ([]netip.Addr, error) {
156+
if len(o.Inet4Address) == 0 {
157+
return nil, nil
158+
}
159+
if len(o.DNSAddress) > 0 {
160+
return common.Filter(o.DNSAddress, netip.Addr.Is4), nil
161+
}
162+
if HasNextAddress(o.Inet4Address[0], 1) {
163+
return []netip.Addr{o.Inet4Address[0].Addr().Next()}, nil
164+
}
165+
if !(len(o.Inet6Address) > 0 && HasNextAddress(o.Inet6Address[0], 1)) {
166+
return nil, E.New("no IPv4 server configured and no usable next address in ", o.Inet6Address[0], " for DNS")
167+
}
168+
return nil, nil
169+
}
170+
171+
func (o *Options) Inet6DNSAddress() ([]netip.Addr, error) {
172+
if len(o.Inet6Address) == 0 {
173+
return nil, nil
174+
}
175+
if len(o.DNSAddress) > 0 {
176+
return common.Filter(o.DNSAddress, netip.Addr.Is6), nil
177+
}
178+
if HasNextAddress(o.Inet6Address[0], 1) {
179+
return []netip.Addr{o.Inet6Address[0].Addr().Next()}, nil
180+
}
181+
if !(len(o.Inet4Address) > 0 && HasNextAddress(o.Inet4Address[0], 1)) {
182+
return nil, E.New("no IPv6 server configured and no usable next address in ", o.Inet6Address[0], " for DNS")
183+
}
184+
return nil, nil
185+
}
186+
127187
func (o *Options) Inet4GatewayAddr() netip.Addr {
128188
if o.Inet4Gateway.IsValid() {
129189
return o.Inet4Gateway

tun_linux.go

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,12 @@ func (t *NativeTun) Start() error {
317317
return E.Cause(err, "set rules")
318318
}
319319

320-
t.setSearchDomainForSystemdResolved()
320+
if t.options.DNSMode != DNSModeDisabled {
321+
err = t.setSearchDomainForSystemdResolved()
322+
if err != nil {
323+
return E.Cause(err, "set search domain")
324+
}
325+
}
321326

322327
if t.options.AutoRoute && runtime.GOOS == "android" {
323328
t.interfaceCallback = t.options.InterfaceMonitor.RegisterCallback(t.routeUpdate)
@@ -332,7 +337,9 @@ func (t *NativeTun) Close() error {
332337
if t.options.EXP_ExternalConfiguration {
333338
return common.Close(common.PtrOrNil(t.tunFile))
334339
}
335-
t.unsetSearchDomainForSystemdResolved()
340+
if t.options.DNSMode != DNSModeDisabled {
341+
t.unsetSearchDomainForSystemdResolved()
342+
}
336343
t.unsetAddresses()
337344
return E.Errors(t.unsetRoute(), t.unsetRules(), common.Close(common.PtrOrNil(t.tunFile)))
338345
}
@@ -1073,37 +1080,24 @@ func (t *NativeTun) routeUpdate(_ *control.Interface, flags int) {
10731080
}
10741081
}
10751082

1076-
func (t *NativeTun) setSearchDomainForSystemdResolved() {
1077-
if t.options.EXP_DisableDNSHijack {
1078-
return
1079-
}
1083+
func (t *NativeTun) setSearchDomainForSystemdResolved() error {
10801084
ctlPath, err := exec.LookPath("resolvectl")
10811085
if err != nil {
1082-
return
1083-
}
1084-
dnsServer := t.options.DNSServers
1085-
if len(dnsServer) == 0 {
1086-
if len(t.options.Inet4Address) > 0 && HasNextAddress(t.options.Inet4Address[0], 1) {
1087-
dnsServer = append(dnsServer, t.options.Inet4Address[0].Addr().Next())
1088-
}
1089-
if len(t.options.Inet6Address) > 0 && HasNextAddress(t.options.Inet6Address[0], 1) {
1090-
dnsServer = append(dnsServer, t.options.Inet6Address[0].Addr().Next())
1091-
}
1086+
return nil
10921087
}
1093-
if len(dnsServer) == 0 {
1094-
return
1088+
dnsAddress, err := t.options.DNSServerAddress()
1089+
if err != nil {
1090+
return err
10951091
}
10961092
go func() {
10971093
_ = shell.Exec(ctlPath, "domain", t.options.Name, "~.").Run()
10981094
_ = shell.Exec(ctlPath, "default-route", t.options.Name, "true").Run()
1099-
_ = shell.Exec(ctlPath, append([]string{"dns", t.options.Name}, common.Map(dnsServer, netip.Addr.String)...)...).Run()
1095+
_ = shell.Exec(ctlPath, append([]string{"dns", t.options.Name}, common.Map(dnsAddress, netip.Addr.String)...)...).Run()
11001096
}()
1097+
return nil
11011098
}
11021099

11031100
func (t *NativeTun) unsetSearchDomainForSystemdResolved() {
1104-
if t.options.EXP_DisableDNSHijack {
1105-
return
1106-
}
11071101
ctlPath, err := exec.LookPath("resolvectl")
11081102
if err != nil {
11091103
return

tun_windows.go

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
"github.com/sagernet/sing-tun/internal/winipcfg"
1717
"github.com/sagernet/sing-tun/internal/winsys"
1818
"github.com/sagernet/sing-tun/internal/wintun"
19-
"github.com/sagernet/sing/common"
2019
E "github.com/sagernet/sing/common/exceptions"
2120
"github.com/sagernet/sing/common/windnsapi"
2221

@@ -81,16 +80,14 @@ func (t *NativeTun) configure() error {
8180
if err != nil {
8281
return E.Cause(err, "set ipv4 address")
8382
}
84-
if t.options.AutoRoute && !t.options.EXP_DisableDNSHijack {
85-
dnsServers := common.Filter(t.options.DNSServers, netip.Addr.Is4)
86-
if len(dnsServers) == 0 && HasNextAddress(t.options.Inet4Address[0], 1) {
87-
dnsServers = []netip.Addr{t.options.Inet4Address[0].Addr().Next()}
83+
if t.options.AutoRoute && t.options.DNSModeOrDefault() != DNSModeDisabled {
84+
dnsServers, err := t.options.Inet4DNSAddress()
85+
if err != nil {
86+
return err
8887
}
89-
if len(dnsServers) > 0 {
90-
err = luid.SetDNS(winipcfg.AddressFamily(windows.AF_INET), dnsServers, nil)
91-
if err != nil {
92-
return E.Cause(err, "set ipv4 dns")
93-
}
88+
err = luid.SetDNS(winipcfg.AddressFamily(windows.AF_INET), dnsServers, nil)
89+
if err != nil {
90+
return E.Cause(err, "set ipv4 dns")
9491
}
9592
} else {
9693
err = luid.SetDNS(winipcfg.AddressFamily(windows.AF_INET), nil, nil)
@@ -104,16 +101,14 @@ func (t *NativeTun) configure() error {
104101
if err != nil {
105102
return E.Cause(err, "set ipv6 address")
106103
}
107-
if t.options.AutoRoute && !t.options.EXP_DisableDNSHijack {
108-
dnsServers := common.Filter(t.options.DNSServers, netip.Addr.Is6)
109-
if len(dnsServers) == 0 && HasNextAddress(t.options.Inet6Address[0], 1) {
110-
dnsServers = []netip.Addr{t.options.Inet6Address[0].Addr().Next()}
104+
if t.options.AutoRoute && t.options.DNSModeOrDefault() != DNSModeDisabled {
105+
dnsServers, err := t.options.Inet6DNSAddress()
106+
if err != nil {
107+
return err
111108
}
112-
if len(dnsServers) > 0 {
113-
err = luid.SetDNS(winipcfg.AddressFamily(windows.AF_INET6), dnsServers, nil)
114-
if err != nil {
115-
return E.Cause(err, "set ipv6 dns")
116-
}
109+
err = luid.SetDNS(winipcfg.AddressFamily(windows.AF_INET6), dnsServers, nil)
110+
if err != nil {
111+
return E.Cause(err, "set ipv6 dns")
117112
}
118113
} else {
119114
err = luid.SetDNS(winipcfg.AddressFamily(windows.AF_INET6), nil, nil)
@@ -334,7 +329,7 @@ func (t *NativeTun) Start() error {
334329
}
335330
}
336331

337-
if !t.options.EXP_DisableDNSHijack {
332+
if t.options.DNSModeOrDefault() == DNSModeHijack {
338333
blockDNSCondition := make([]winsys.FWPM_FILTER_CONDITION0, 1)
339334
blockDNSCondition[0].FieldKey = winsys.FWPM_CONDITION_IP_REMOTE_PORT
340335
blockDNSCondition[0].MatchType = winsys.FWP_MATCH_EQUAL

0 commit comments

Comments
 (0)