Add DNS mode
This commit is contained in:
parent
3c7d6ad82f
commit
47bdde06c3
4 changed files with 103 additions and 58 deletions
|
|
@ -675,7 +675,7 @@ func (r *autoRedirect) nftablesCreateExcludeRules(nft *nftables.Conn, table *nft
|
||||||
nftablesCreateExcludeDestinationIPSet(nft, table, chain, inet6RouteExcludeAddress.ID, inet6RouteExcludeAddress.Name, nftables.TableFamilyIPv6, false)
|
nftablesCreateExcludeDestinationIPSet(nft, table, chain, inet6RouteExcludeAddress.ID, inet6RouteExcludeAddress.Name, nftables.TableFamilyIPv6, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !r.tunOptions.EXP_DisableDNSHijack && ((chain.Hooknum == nftables.ChainHookPrerouting && chain.Type == nftables.ChainTypeNAT) ||
|
if r.tunOptions.DNSModeOrDefault() == DNSModeHijack && ((chain.Hooknum == nftables.ChainHookPrerouting && chain.Type == nftables.ChainTypeNAT) ||
|
||||||
(r.tunOptions.AutoRedirectMarkMode && chain.Hooknum == nftables.ChainHookOutput && chain.Type == nftables.ChainTypeNAT)) {
|
(r.tunOptions.AutoRedirectMarkMode && chain.Hooknum == nftables.ChainHookOutput && chain.Type == nftables.ChainTypeNAT)) {
|
||||||
if r.enableIPv4 {
|
if r.enableIPv4 {
|
||||||
err := r.nftablesCreateDNSHijackRulesForFamily(nft, table, chain, nftables.TableFamilyIPv4, 5, "inet4_local_address_set")
|
err := r.nftablesCreateDNSHijackRulesForFamily(nft, table, chain, nftables.TableFamilyIPv4, 5, "inet4_local_address_set")
|
||||||
|
|
@ -1050,23 +1050,19 @@ func (r *autoRedirect) nftablesCreateDNSHijackRulesForFamily(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "add dns protocol set")
|
return E.Cause(err, "add dns protocol set")
|
||||||
}
|
}
|
||||||
dnsServer := common.Find(r.tunOptions.DNSServers, func(it netip.Addr) bool {
|
var dnsServers []netip.Addr
|
||||||
return it.Is4() == (family == nftables.TableFamilyIPv4)
|
if family == nftables.TableFamilyIPv4 {
|
||||||
})
|
dnsServers, err = r.tunOptions.Inet4DNSAddress()
|
||||||
if !dnsServer.IsValid() {
|
} else {
|
||||||
if family == nftables.TableFamilyIPv4 {
|
dnsServers, err = r.tunOptions.Inet6DNSAddress()
|
||||||
if HasNextAddress(r.tunOptions.Inet4Address[0], 1) {
|
|
||||||
dnsServer = r.tunOptions.Inet4Address[0].Addr().Next()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if HasNextAddress(r.tunOptions.Inet6Address[0], 1) {
|
|
||||||
dnsServer = r.tunOptions.Inet6Address[0].Addr().Next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if !dnsServer.IsValid() {
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(dnsServers) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
dnsServer := dnsServers[0]
|
||||||
exprs := []expr.Any{
|
exprs := []expr.Any{
|
||||||
&expr.Meta{
|
&expr.Meta{
|
||||||
Key: expr.MetaKeyNFPROTO,
|
Key: expr.MetaKeyNFPROTO,
|
||||||
|
|
|
||||||
62
tun.go
62
tun.go
|
|
@ -9,8 +9,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/buf"
|
"github.com/sagernet/sing/common/buf"
|
||||||
"github.com/sagernet/sing/common/control"
|
"github.com/sagernet/sing/common/control"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
F "github.com/sagernet/sing/common/format"
|
F "github.com/sagernet/sing/common/format"
|
||||||
"github.com/sagernet/sing/common/logger"
|
"github.com/sagernet/sing/common/logger"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
|
|
@ -68,6 +70,12 @@ const (
|
||||||
DefaultIPRoute2AutoRedirectFallbackRuleIndex = 32768
|
DefaultIPRoute2AutoRedirectFallbackRuleIndex = 32768
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DNSModeDisabled = "disabled"
|
||||||
|
DNSModeNative = "native"
|
||||||
|
DNSModeHijack = "hijack"
|
||||||
|
)
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Name string
|
Name string
|
||||||
Inet4Address []netip.Prefix
|
Inet4Address []netip.Prefix
|
||||||
|
|
@ -78,7 +86,8 @@ type Options struct {
|
||||||
InterfaceScope bool
|
InterfaceScope bool
|
||||||
Inet4Gateway netip.Addr
|
Inet4Gateway netip.Addr
|
||||||
Inet6Gateway netip.Addr
|
Inet6Gateway netip.Addr
|
||||||
DNSServers []netip.Addr
|
DNSMode string
|
||||||
|
DNSAddress []netip.Addr
|
||||||
IPRoute2TableIndex int
|
IPRoute2TableIndex int
|
||||||
IPRoute2RuleIndex int
|
IPRoute2RuleIndex int
|
||||||
IPRoute2AutoRedirectFallbackRuleIndex int
|
IPRoute2AutoRedirectFallbackRuleIndex int
|
||||||
|
|
@ -124,6 +133,57 @@ type Options struct {
|
||||||
EXP_SendMsgX bool
|
EXP_SendMsgX bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *Options) DNSModeOrDefault() string {
|
||||||
|
if o.DNSMode == "" {
|
||||||
|
return DNSModeHijack
|
||||||
|
}
|
||||||
|
return o.DNSMode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Options) DNSServerAddress() ([]netip.Addr, error) {
|
||||||
|
inet4DNS, err := o.Inet4DNSAddress()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
inet6DNS, err := o.Inet6DNSAddress()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return append(inet4DNS, inet6DNS...), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Options) Inet4DNSAddress() ([]netip.Addr, error) {
|
||||||
|
if len(o.Inet4Address) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if len(o.DNSAddress) > 0 {
|
||||||
|
return common.Filter(o.DNSAddress, netip.Addr.Is4), nil
|
||||||
|
}
|
||||||
|
if HasNextAddress(o.Inet4Address[0], 1) {
|
||||||
|
return []netip.Addr{o.Inet4Address[0].Addr().Next()}, nil
|
||||||
|
}
|
||||||
|
if !(len(o.Inet6Address) > 0 && HasNextAddress(o.Inet6Address[0], 1)) {
|
||||||
|
return nil, E.New("no IPv4 server configured and no usable next address in ", o.Inet6Address[0], " for DNS")
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Options) Inet6DNSAddress() ([]netip.Addr, error) {
|
||||||
|
if len(o.Inet6Address) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if len(o.DNSAddress) > 0 {
|
||||||
|
return common.Filter(o.DNSAddress, netip.Addr.Is6), nil
|
||||||
|
}
|
||||||
|
if HasNextAddress(o.Inet6Address[0], 1) {
|
||||||
|
return []netip.Addr{o.Inet6Address[0].Addr().Next()}, nil
|
||||||
|
}
|
||||||
|
if !(len(o.Inet4Address) > 0 && HasNextAddress(o.Inet4Address[0], 1)) {
|
||||||
|
return nil, E.New("no IPv6 server configured and no usable next address in ", o.Inet6Address[0], " for DNS")
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (o *Options) Inet4GatewayAddr() netip.Addr {
|
func (o *Options) Inet4GatewayAddr() netip.Addr {
|
||||||
if o.Inet4Gateway.IsValid() {
|
if o.Inet4Gateway.IsValid() {
|
||||||
return o.Inet4Gateway
|
return o.Inet4Gateway
|
||||||
|
|
|
||||||
38
tun_linux.go
38
tun_linux.go
|
|
@ -354,7 +354,12 @@ func (t *NativeTun) start() error {
|
||||||
return E.Cause(err, "set rules")
|
return E.Cause(err, "set rules")
|
||||||
}
|
}
|
||||||
|
|
||||||
t.setSearchDomainForSystemdResolved()
|
if t.options.DNSMode != DNSModeDisabled {
|
||||||
|
err = t.setSearchDomainForSystemdResolved()
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "set search domain")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if t.options.AutoRoute && runtime.GOOS == "android" {
|
if t.options.AutoRoute && runtime.GOOS == "android" {
|
||||||
t.interfaceCallback = t.options.InterfaceMonitor.RegisterCallback(t.routeUpdate)
|
t.interfaceCallback = t.options.InterfaceMonitor.RegisterCallback(t.routeUpdate)
|
||||||
|
|
@ -369,7 +374,9 @@ func (t *NativeTun) Close() error {
|
||||||
if t.options.EXP_ExternalConfiguration {
|
if t.options.EXP_ExternalConfiguration {
|
||||||
return common.Close(common.PtrOrNil(t.tunFile))
|
return common.Close(common.PtrOrNil(t.tunFile))
|
||||||
}
|
}
|
||||||
t.unsetSearchDomainForSystemdResolved()
|
if t.options.DNSMode != DNSModeDisabled {
|
||||||
|
t.unsetSearchDomainForSystemdResolved()
|
||||||
|
}
|
||||||
t.unsetAddresses()
|
t.unsetAddresses()
|
||||||
return E.Errors(t.unsetRoute(), t.unsetRules(), common.Close(common.PtrOrNil(t.tunFile)))
|
return E.Errors(t.unsetRoute(), t.unsetRules(), common.Close(common.PtrOrNil(t.tunFile)))
|
||||||
}
|
}
|
||||||
|
|
@ -1190,37 +1197,24 @@ func (t *NativeTun) routeUpdate(_ *control.Interface, flags int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *NativeTun) setSearchDomainForSystemdResolved() {
|
func (t *NativeTun) setSearchDomainForSystemdResolved() error {
|
||||||
if t.options.EXP_DisableDNSHijack {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctlPath, err := exec.LookPath("resolvectl")
|
ctlPath, err := exec.LookPath("resolvectl")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
dnsServer := t.options.DNSServers
|
dnsAddress, err := t.options.DNSServerAddress()
|
||||||
if len(dnsServer) == 0 {
|
if err != nil {
|
||||||
if len(t.options.Inet4Address) > 0 && HasNextAddress(t.options.Inet4Address[0], 1) {
|
return err
|
||||||
dnsServer = append(dnsServer, t.options.Inet4Address[0].Addr().Next())
|
|
||||||
}
|
|
||||||
if len(t.options.Inet6Address) > 0 && HasNextAddress(t.options.Inet6Address[0], 1) {
|
|
||||||
dnsServer = append(dnsServer, t.options.Inet6Address[0].Addr().Next())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(dnsServer) == 0 {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
_ = shell.Exec(ctlPath, "domain", t.options.Name, "~.").Run()
|
_ = shell.Exec(ctlPath, "domain", t.options.Name, "~.").Run()
|
||||||
_ = shell.Exec(ctlPath, "default-route", t.options.Name, "true").Run()
|
_ = shell.Exec(ctlPath, "default-route", t.options.Name, "true").Run()
|
||||||
_ = shell.Exec(ctlPath, append([]string{"dns", t.options.Name}, common.Map(dnsServer, netip.Addr.String)...)...).Run()
|
_ = shell.Exec(ctlPath, append([]string{"dns", t.options.Name}, common.Map(dnsAddress, netip.Addr.String)...)...).Run()
|
||||||
}()
|
}()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *NativeTun) unsetSearchDomainForSystemdResolved() {
|
func (t *NativeTun) unsetSearchDomainForSystemdResolved() {
|
||||||
if t.options.EXP_DisableDNSHijack {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctlPath, err := exec.LookPath("resolvectl")
|
ctlPath, err := exec.LookPath("resolvectl")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ import (
|
||||||
"github.com/sagernet/sing-tun/internal/winipcfg"
|
"github.com/sagernet/sing-tun/internal/winipcfg"
|
||||||
"github.com/sagernet/sing-tun/internal/winsys"
|
"github.com/sagernet/sing-tun/internal/winsys"
|
||||||
"github.com/sagernet/sing-tun/internal/wintun"
|
"github.com/sagernet/sing-tun/internal/wintun"
|
||||||
"github.com/sagernet/sing/common"
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/windnsapi"
|
"github.com/sagernet/sing/common/windnsapi"
|
||||||
|
|
||||||
|
|
@ -81,16 +80,14 @@ func (t *NativeTun) configure() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "set ipv4 address")
|
return E.Cause(err, "set ipv4 address")
|
||||||
}
|
}
|
||||||
if t.options.AutoRoute && !t.options.EXP_DisableDNSHijack {
|
if t.options.AutoRoute && t.options.DNSModeOrDefault() != DNSModeDisabled {
|
||||||
dnsServers := common.Filter(t.options.DNSServers, netip.Addr.Is4)
|
dnsServers, err := t.options.Inet4DNSAddress()
|
||||||
if len(dnsServers) == 0 && HasNextAddress(t.options.Inet4Address[0], 1) {
|
if err != nil {
|
||||||
dnsServers = []netip.Addr{t.options.Inet4Address[0].Addr().Next()}
|
return err
|
||||||
}
|
}
|
||||||
if len(dnsServers) > 0 {
|
err = luid.SetDNS(winipcfg.AddressFamily(windows.AF_INET), dnsServers, nil)
|
||||||
err = luid.SetDNS(winipcfg.AddressFamily(windows.AF_INET), dnsServers, nil)
|
if err != nil {
|
||||||
if err != nil {
|
return E.Cause(err, "set ipv4 dns")
|
||||||
return E.Cause(err, "set ipv4 dns")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = luid.SetDNS(winipcfg.AddressFamily(windows.AF_INET), nil, nil)
|
err = luid.SetDNS(winipcfg.AddressFamily(windows.AF_INET), nil, nil)
|
||||||
|
|
@ -104,16 +101,14 @@ func (t *NativeTun) configure() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "set ipv6 address")
|
return E.Cause(err, "set ipv6 address")
|
||||||
}
|
}
|
||||||
if t.options.AutoRoute && !t.options.EXP_DisableDNSHijack {
|
if t.options.AutoRoute && t.options.DNSModeOrDefault() != DNSModeDisabled {
|
||||||
dnsServers := common.Filter(t.options.DNSServers, netip.Addr.Is6)
|
dnsServers, err := t.options.Inet6DNSAddress()
|
||||||
if len(dnsServers) == 0 && HasNextAddress(t.options.Inet6Address[0], 1) {
|
if err != nil {
|
||||||
dnsServers = []netip.Addr{t.options.Inet6Address[0].Addr().Next()}
|
return err
|
||||||
}
|
}
|
||||||
if len(dnsServers) > 0 {
|
err = luid.SetDNS(winipcfg.AddressFamily(windows.AF_INET6), dnsServers, nil)
|
||||||
err = luid.SetDNS(winipcfg.AddressFamily(windows.AF_INET6), dnsServers, nil)
|
if err != nil {
|
||||||
if err != nil {
|
return E.Cause(err, "set ipv6 dns")
|
||||||
return E.Cause(err, "set ipv6 dns")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = luid.SetDNS(winipcfg.AddressFamily(windows.AF_INET6), nil, nil)
|
err = luid.SetDNS(winipcfg.AddressFamily(windows.AF_INET6), nil, nil)
|
||||||
|
|
@ -334,7 +329,7 @@ func (t *NativeTun) Start() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !t.options.EXP_DisableDNSHijack {
|
if t.options.DNSModeOrDefault() == DNSModeHijack {
|
||||||
blockDNSCondition := make([]winsys.FWPM_FILTER_CONDITION0, 1)
|
blockDNSCondition := make([]winsys.FWPM_FILTER_CONDITION0, 1)
|
||||||
blockDNSCondition[0].FieldKey = winsys.FWPM_CONDITION_IP_REMOTE_PORT
|
blockDNSCondition[0].FieldKey = winsys.FWPM_CONDITION_IP_REMOTE_PORT
|
||||||
blockDNSCondition[0].MatchType = winsys.FWP_MATCH_EQUAL
|
blockDNSCondition[0].MatchType = winsys.FWP_MATCH_EQUAL
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue