github.com/sagernet/sing-tun@v0.3.0-beta.5/tun_linux.go (about)

     1  package tun
     2  
     3  import (
     4  	"math/rand"
     5  	"net"
     6  	"net/netip"
     7  	"os"
     8  	"os/exec"
     9  	"runtime"
    10  	"sync"
    11  	"syscall"
    12  	"unsafe"
    13  
    14  	"github.com/sagernet/netlink"
    15  	"github.com/sagernet/sing/common"
    16  	"github.com/sagernet/sing/common/buf"
    17  	"github.com/sagernet/sing/common/bufio"
    18  	E "github.com/sagernet/sing/common/exceptions"
    19  	N "github.com/sagernet/sing/common/network"
    20  	"github.com/sagernet/sing/common/rw"
    21  	"github.com/sagernet/sing/common/shell"
    22  	"github.com/sagernet/sing/common/x/list"
    23  
    24  	"golang.org/x/sys/unix"
    25  )
    26  
    27  var _ LinuxTUN = (*NativeTun)(nil)
    28  
    29  type NativeTun struct {
    30  	tunFd             int
    31  	tunFile           *os.File
    32  	tunWriter         N.VectorisedWriter
    33  	interfaceCallback *list.Element[DefaultInterfaceUpdateCallback]
    34  	options           Options
    35  	ruleIndex6        []int
    36  	gsoEnabled        bool
    37  	gsoBuffer         []byte
    38  	gsoToWrite        []int
    39  	gsoReadAccess     sync.Mutex
    40  	tcpGROAccess      sync.Mutex
    41  	tcp4GROTable      *tcpGROTable
    42  	tcp6GROTable      *tcpGROTable
    43  	txChecksumOffload bool
    44  }
    45  
    46  func New(options Options) (Tun, error) {
    47  	var nativeTun *NativeTun
    48  	if options.FileDescriptor == 0 {
    49  		tunFd, err := open(options.Name, options.GSO)
    50  		if err != nil {
    51  			return nil, err
    52  		}
    53  		tunLink, err := netlink.LinkByName(options.Name)
    54  		if err != nil {
    55  			return nil, E.Errors(err, unix.Close(tunFd))
    56  		}
    57  		nativeTun = &NativeTun{
    58  			tunFd:   tunFd,
    59  			tunFile: os.NewFile(uintptr(tunFd), "tun"),
    60  			options: options,
    61  		}
    62  		err = nativeTun.configure(tunLink)
    63  		if err != nil {
    64  			return nil, E.Errors(err, unix.Close(tunFd))
    65  		}
    66  	} else {
    67  		nativeTun = &NativeTun{
    68  			tunFd:   options.FileDescriptor,
    69  			tunFile: os.NewFile(uintptr(options.FileDescriptor), "tun"),
    70  			options: options,
    71  		}
    72  	}
    73  	var ok bool
    74  	nativeTun.tunWriter, ok = bufio.CreateVectorisedWriter(nativeTun.tunFile)
    75  	if !ok {
    76  		panic("create vectorised writer")
    77  	}
    78  	return nativeTun, nil
    79  }
    80  
    81  func (t *NativeTun) FrontHeadroom() int {
    82  	if t.gsoEnabled {
    83  		return virtioNetHdrLen
    84  	}
    85  	return 0
    86  }
    87  
    88  func (t *NativeTun) Read(p []byte) (n int, err error) {
    89  	if t.gsoEnabled {
    90  		n, err = t.tunFile.Read(t.gsoBuffer)
    91  		if err != nil {
    92  			return
    93  		}
    94  		var sizes [1]int
    95  		n, err = handleVirtioRead(t.gsoBuffer[:n], [][]byte{p}, sizes[:], 0)
    96  		if err != nil {
    97  			return
    98  		}
    99  		if n == 0 {
   100  			return
   101  		}
   102  		n = sizes[0]
   103  		return
   104  	} else {
   105  		return t.tunFile.Read(p)
   106  	}
   107  }
   108  
   109  func (t *NativeTun) Write(p []byte) (n int, err error) {
   110  	if t.gsoEnabled {
   111  		err = t.BatchWrite([][]byte{p}, virtioNetHdrLen)
   112  		if err != nil {
   113  			return
   114  		}
   115  		n = len(p)
   116  		return
   117  	}
   118  	return t.tunFile.Write(p)
   119  }
   120  
   121  func (t *NativeTun) WriteVectorised(buffers []*buf.Buffer) error {
   122  	if t.gsoEnabled {
   123  		n := buf.LenMulti(buffers)
   124  		buffer := buf.NewSize(virtioNetHdrLen + n)
   125  		buffer.Truncate(virtioNetHdrLen)
   126  		buf.CopyMulti(buffer.Extend(n), buffers)
   127  		_, err := t.tunFile.Write(buffer.Bytes())
   128  		buffer.Release()
   129  		return err
   130  	} else {
   131  		return t.tunWriter.WriteVectorised(buffers)
   132  	}
   133  }
   134  
   135  func (t *NativeTun) BatchSize() int {
   136  	if !t.gsoEnabled {
   137  		return 1
   138  	}
   139  	/* // Not works on some devices: https://github.com/SagerNet/sing-box/issues/1605
   140  	batchSize := int(gsoMaxSize/t.options.MTU) * 2
   141  	if batchSize > idealBatchSize {
   142  		batchSize = idealBatchSize
   143  	}
   144  	return batchSize*/
   145  	return idealBatchSize
   146  }
   147  
   148  func (t *NativeTun) BatchRead(buffers [][]byte, offset int, readN []int) (n int, err error) {
   149  	t.gsoReadAccess.Lock()
   150  	defer t.gsoReadAccess.Unlock()
   151  	n, err = t.tunFile.Read(t.gsoBuffer)
   152  	if err != nil {
   153  		return
   154  	}
   155  	return handleVirtioRead(t.gsoBuffer[:n], buffers, readN, offset)
   156  }
   157  
   158  func (t *NativeTun) BatchWrite(buffers [][]byte, offset int) error {
   159  	t.tcpGROAccess.Lock()
   160  	defer func() {
   161  		t.tcp4GROTable.reset()
   162  		t.tcp6GROTable.reset()
   163  		t.tcpGROAccess.Unlock()
   164  	}()
   165  	t.gsoToWrite = t.gsoToWrite[:0]
   166  	err := handleGRO(buffers, offset, t.tcp4GROTable, t.tcp6GROTable, &t.gsoToWrite)
   167  	if err != nil {
   168  		return err
   169  	}
   170  	offset -= virtioNetHdrLen
   171  	for _, bufferIndex := range t.gsoToWrite {
   172  		_, err = t.tunFile.Write(buffers[bufferIndex][offset:])
   173  		if err != nil {
   174  			return err
   175  		}
   176  	}
   177  	return nil
   178  }
   179  
   180  var controlPath string
   181  
   182  func init() {
   183  	const defaultTunPath = "/dev/net/tun"
   184  	const androidTunPath = "/dev/tun"
   185  	if rw.FileExists(androidTunPath) {
   186  		controlPath = androidTunPath
   187  	} else {
   188  		controlPath = defaultTunPath
   189  	}
   190  }
   191  
   192  func open(name string, vnetHdr bool) (int, error) {
   193  	fd, err := unix.Open(controlPath, unix.O_RDWR, 0)
   194  	if err != nil {
   195  		return -1, err
   196  	}
   197  
   198  	var ifr struct {
   199  		name  [16]byte
   200  		flags uint16
   201  		_     [22]byte
   202  	}
   203  
   204  	copy(ifr.name[:], name)
   205  	ifr.flags = unix.IFF_TUN | unix.IFF_NO_PI
   206  	if vnetHdr {
   207  		ifr.flags |= unix.IFF_VNET_HDR
   208  	}
   209  	_, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), unix.TUNSETIFF, uintptr(unsafe.Pointer(&ifr)))
   210  	if errno != 0 {
   211  		unix.Close(fd)
   212  		return -1, errno
   213  	}
   214  
   215  	if err = unix.SetNonblock(fd, true); err != nil {
   216  		unix.Close(fd)
   217  		return -1, err
   218  	}
   219  
   220  	return fd, nil
   221  }
   222  
   223  func (t *NativeTun) configure(tunLink netlink.Link) error {
   224  	err := netlink.LinkSetMTU(tunLink, int(t.options.MTU))
   225  	if err == unix.EPERM {
   226  		// unprivileged
   227  		return nil
   228  	} else if err != nil {
   229  		return err
   230  	}
   231  
   232  	if len(t.options.Inet4Address) > 0 {
   233  		for _, address := range t.options.Inet4Address {
   234  			addr4, _ := netlink.ParseAddr(address.String())
   235  			err = netlink.AddrAdd(tunLink, addr4)
   236  			if err != nil {
   237  				return err
   238  			}
   239  		}
   240  	}
   241  	if len(t.options.Inet6Address) > 0 {
   242  		for _, address := range t.options.Inet6Address {
   243  			addr6, _ := netlink.ParseAddr(address.String())
   244  			err = netlink.AddrAdd(tunLink, addr6)
   245  			if err != nil {
   246  				return err
   247  			}
   248  		}
   249  	}
   250  
   251  	if t.options.GSO {
   252  		var vnetHdrEnabled bool
   253  		vnetHdrEnabled, err = checkVNETHDREnabled(t.tunFd, t.options.Name)
   254  		if err != nil {
   255  			return E.Cause(err, "enable offload: check IFF_VNET_HDR enabled")
   256  		}
   257  		if !vnetHdrEnabled {
   258  			return E.Cause(err, "enable offload: IFF_VNET_HDR not enabled")
   259  		}
   260  		err = setTCPOffload(t.tunFd)
   261  		if err != nil {
   262  			return err
   263  		}
   264  		t.gsoEnabled = true
   265  		t.gsoBuffer = make([]byte, virtioNetHdrLen+int(gsoMaxSize))
   266  		t.tcp4GROTable = newTCPGROTable()
   267  		t.tcp6GROTable = newTCPGROTable()
   268  	}
   269  
   270  	var rxChecksumOffload bool
   271  	rxChecksumOffload, err = checkChecksumOffload(t.options.Name, unix.ETHTOOL_GRXCSUM)
   272  	if err == nil && !rxChecksumOffload {
   273  		_ = setChecksumOffload(t.options.Name, unix.ETHTOOL_SRXCSUM)
   274  	}
   275  
   276  	if t.options._TXChecksumOffload {
   277  		var txChecksumOffload bool
   278  		txChecksumOffload, err = checkChecksumOffload(t.options.Name, unix.ETHTOOL_GTXCSUM)
   279  		if err != nil {
   280  			return err
   281  		}
   282  		if err == nil && !txChecksumOffload {
   283  			err = setChecksumOffload(t.options.Name, unix.ETHTOOL_STXCSUM)
   284  			if err != nil {
   285  				return err
   286  			}
   287  		}
   288  		t.txChecksumOffload = true
   289  	}
   290  
   291  	err = netlink.LinkSetUp(tunLink)
   292  	if err != nil {
   293  		return err
   294  	}
   295  
   296  	if t.options.TableIndex == 0 {
   297  		for {
   298  			t.options.TableIndex = int(rand.Uint32())
   299  			routeList, fErr := netlink.RouteListFiltered(netlink.FAMILY_ALL, &netlink.Route{Table: t.options.TableIndex}, netlink.RT_FILTER_TABLE)
   300  			if len(routeList) == 0 || fErr != nil {
   301  				break
   302  			}
   303  		}
   304  	}
   305  
   306  	err = t.setRoute(tunLink)
   307  	if err != nil {
   308  		_ = t.unsetRoute0(tunLink)
   309  		return err
   310  	}
   311  
   312  	err = t.unsetRules()
   313  	if err != nil {
   314  		return E.Cause(err, "cleanup rules")
   315  	}
   316  	err = t.setRules()
   317  	if err != nil {
   318  		_ = t.unsetRules()
   319  		return err
   320  	}
   321  
   322  	t.setSearchDomainForSystemdResolved()
   323  
   324  	if t.options.AutoRoute && runtime.GOOS == "android" {
   325  		t.interfaceCallback = t.options.InterfaceMonitor.RegisterCallback(t.routeUpdate)
   326  	}
   327  	return nil
   328  }
   329  
   330  func (t *NativeTun) Close() error {
   331  	if t.interfaceCallback != nil {
   332  		t.options.InterfaceMonitor.UnregisterCallback(t.interfaceCallback)
   333  	}
   334  	return E.Errors(t.unsetRoute(), t.unsetRules(), common.Close(common.PtrOrNil(t.tunFile)))
   335  }
   336  
   337  func (t *NativeTun) TXChecksumOffload() bool {
   338  	return t.txChecksumOffload
   339  }
   340  
   341  func prefixToIPNet(prefix netip.Prefix) *net.IPNet {
   342  	return &net.IPNet{
   343  		IP:   prefix.Addr().AsSlice(),
   344  		Mask: net.CIDRMask(prefix.Bits(), prefix.Addr().BitLen()),
   345  	}
   346  }
   347  
   348  func (t *NativeTun) routes(tunLink netlink.Link) ([]netlink.Route, error) {
   349  	routeRanges, err := t.options.BuildAutoRouteRanges(false)
   350  	if err != nil {
   351  		return nil, err
   352  	}
   353  	return common.Map(routeRanges, func(it netip.Prefix) netlink.Route {
   354  		return netlink.Route{
   355  			Dst:       prefixToIPNet(it),
   356  			LinkIndex: tunLink.Attrs().Index,
   357  			Table:     t.options.TableIndex,
   358  		}
   359  	}), nil
   360  }
   361  
   362  const (
   363  	ruleStart = 9000
   364  	ruleEnd   = ruleStart + 10
   365  )
   366  
   367  func (t *NativeTun) nextIndex6() int {
   368  	ruleList, err := netlink.RuleList(netlink.FAMILY_V6)
   369  	if err != nil {
   370  		return -1
   371  	}
   372  	var minIndex int
   373  	for _, rule := range ruleList {
   374  		if rule.Priority > 0 && (minIndex == 0 || rule.Priority < minIndex) {
   375  			minIndex = rule.Priority
   376  		}
   377  	}
   378  	minIndex--
   379  	t.ruleIndex6 = append(t.ruleIndex6, minIndex)
   380  	return minIndex
   381  }
   382  
   383  func (t *NativeTun) rules() []*netlink.Rule {
   384  	if !t.options.AutoRoute {
   385  		if len(t.options.Inet6Address) > 0 {
   386  			it := netlink.NewRule()
   387  			it.Priority = t.nextIndex6()
   388  			it.Table = t.options.TableIndex
   389  			it.Family = unix.AF_INET6
   390  			it.OifName = t.options.Name
   391  			return []*netlink.Rule{it}
   392  		}
   393  		return nil
   394  	}
   395  
   396  	var p4, p6 bool
   397  	var pRule int
   398  	if len(t.options.Inet4Address) > 0 {
   399  		p4 = true
   400  		pRule += 1
   401  	}
   402  	if len(t.options.Inet6Address) > 0 {
   403  		p6 = true
   404  		pRule += 1
   405  	}
   406  	if pRule == 0 {
   407  		return []*netlink.Rule{}
   408  	}
   409  
   410  	var rules []*netlink.Rule
   411  	var it *netlink.Rule
   412  
   413  	excludeRanges := t.options.ExcludedRanges()
   414  	priority := ruleStart
   415  	priority6 := priority
   416  	nopPriority := ruleEnd
   417  
   418  	for _, excludeRange := range excludeRanges {
   419  		if p4 {
   420  			it = netlink.NewRule()
   421  			it.Priority = priority
   422  			it.UIDRange = netlink.NewRuleUIDRange(excludeRange.Start, excludeRange.End)
   423  			it.Goto = nopPriority
   424  			it.Family = unix.AF_INET
   425  			rules = append(rules, it)
   426  		}
   427  		if p6 {
   428  			it = netlink.NewRule()
   429  			it.Priority = priority6
   430  			it.UIDRange = netlink.NewRuleUIDRange(excludeRange.Start, excludeRange.End)
   431  			it.Goto = nopPriority
   432  			it.Family = unix.AF_INET6
   433  			rules = append(rules, it)
   434  		}
   435  	}
   436  	if len(excludeRanges) > 0 {
   437  		if p4 {
   438  			priority++
   439  		}
   440  		if p6 {
   441  			priority6++
   442  		}
   443  	}
   444  	if len(t.options.IncludeInterface) > 0 {
   445  		matchPriority := priority + 2*len(t.options.IncludeInterface) + 1
   446  		for _, includeInterface := range t.options.IncludeInterface {
   447  			if p4 {
   448  				it = netlink.NewRule()
   449  				it.Priority = priority
   450  				it.IifName = includeInterface
   451  				it.Goto = matchPriority
   452  				it.Family = unix.AF_INET
   453  				rules = append(rules, it)
   454  				priority++
   455  			}
   456  			if p6 {
   457  				it = netlink.NewRule()
   458  				it.Priority = priority6
   459  				it.IifName = includeInterface
   460  				it.Goto = matchPriority
   461  				it.Family = unix.AF_INET6
   462  				rules = append(rules, it)
   463  				priority6++
   464  			}
   465  		}
   466  		if p4 {
   467  			it = netlink.NewRule()
   468  			it.Priority = priority
   469  			it.Family = unix.AF_INET
   470  			it.Goto = nopPriority
   471  			rules = append(rules, it)
   472  			priority++
   473  
   474  			it = netlink.NewRule()
   475  			it.Priority = matchPriority
   476  			it.Family = unix.AF_INET
   477  			rules = append(rules, it)
   478  			priority++
   479  		}
   480  		if p6 {
   481  			it = netlink.NewRule()
   482  			it.Priority = priority6
   483  			it.Family = unix.AF_INET6
   484  			it.Goto = nopPriority
   485  			rules = append(rules, it)
   486  			priority6++
   487  
   488  			it = netlink.NewRule()
   489  			it.Priority = matchPriority
   490  			it.Family = unix.AF_INET6
   491  			rules = append(rules, it)
   492  			priority6++
   493  		}
   494  	} else if len(t.options.ExcludeInterface) > 0 {
   495  		for _, excludeInterface := range t.options.ExcludeInterface {
   496  			if p4 {
   497  				it = netlink.NewRule()
   498  				it.Priority = priority
   499  				it.IifName = excludeInterface
   500  				it.Goto = nopPriority
   501  				it.Family = unix.AF_INET
   502  				rules = append(rules, it)
   503  				priority++
   504  			}
   505  			if p6 {
   506  				it = netlink.NewRule()
   507  				it.Priority = priority6
   508  				it.IifName = excludeInterface
   509  				it.Goto = nopPriority
   510  				it.Family = unix.AF_INET6
   511  				rules = append(rules, it)
   512  				priority6++
   513  			}
   514  		}
   515  	}
   516  
   517  	if runtime.GOOS == "android" && t.options.InterfaceMonitor.AndroidVPNEnabled() {
   518  		const protectedFromVPN = 0x20000
   519  		if p4 || t.options.StrictRoute {
   520  			it = netlink.NewRule()
   521  			if t.options.InterfaceMonitor.OverrideAndroidVPN() {
   522  				it.Mark = protectedFromVPN
   523  			}
   524  			it.Mask = protectedFromVPN
   525  			it.Priority = priority
   526  			it.Family = unix.AF_INET
   527  			it.Goto = nopPriority
   528  			rules = append(rules, it)
   529  			priority++
   530  		}
   531  		if p6 || t.options.StrictRoute {
   532  			it = netlink.NewRule()
   533  			if t.options.InterfaceMonitor.OverrideAndroidVPN() {
   534  				it.Mark = protectedFromVPN
   535  			}
   536  			it.Mask = protectedFromVPN
   537  			it.Family = unix.AF_INET6
   538  			it.Priority = priority6
   539  			it.Goto = nopPriority
   540  			rules = append(rules, it)
   541  			priority6++
   542  		}
   543  	}
   544  
   545  	if t.options.StrictRoute {
   546  		if !p4 {
   547  			it = netlink.NewRule()
   548  			it.Priority = priority
   549  			it.Family = unix.AF_INET
   550  			it.Type = unix.FR_ACT_UNREACHABLE
   551  			rules = append(rules, it)
   552  			priority++
   553  		}
   554  		if !p6 {
   555  			it = netlink.NewRule()
   556  			it.Priority = priority6
   557  			it.Family = unix.AF_INET6
   558  			it.Type = unix.FR_ACT_UNREACHABLE
   559  			rules = append(rules, it)
   560  			priority6++
   561  		}
   562  	}
   563  
   564  	if runtime.GOOS != "android" {
   565  		if p4 {
   566  			for _, address := range t.options.Inet4Address {
   567  				it = netlink.NewRule()
   568  				it.Priority = priority
   569  				it.Dst = address.Masked()
   570  				it.Table = t.options.TableIndex
   571  				it.Family = unix.AF_INET
   572  				rules = append(rules, it)
   573  			}
   574  			priority++
   575  
   576  			it = netlink.NewRule()
   577  			it.Priority = priority
   578  			it.Table = t.options.TableIndex
   579  			it.SuppressPrefixlen = 0
   580  			it.Family = unix.AF_INET
   581  			rules = append(rules, it)
   582  			priority++
   583  		}
   584  		if p6 {
   585  			it = netlink.NewRule()
   586  			it.Priority = priority6
   587  			it.Table = t.options.TableIndex
   588  			it.SuppressPrefixlen = 0
   589  			it.Family = unix.AF_INET6
   590  			rules = append(rules, it)
   591  			priority6++
   592  		}
   593  		if p4 && !t.options.StrictRoute {
   594  			it = netlink.NewRule()
   595  			it.Priority = priority
   596  			it.Invert = true
   597  			it.Dport = netlink.NewRulePortRange(53, 53)
   598  			it.Table = unix.RT_TABLE_MAIN
   599  			it.SuppressPrefixlen = 0
   600  			it.Family = unix.AF_INET
   601  			rules = append(rules, it)
   602  
   603  			it = netlink.NewRule()
   604  			it.Priority = priority
   605  			it.IPProto = syscall.IPPROTO_ICMP
   606  			it.Goto = nopPriority
   607  			it.Family = unix.AF_INET
   608  			rules = append(rules, it)
   609  			priority++
   610  		}
   611  		if p6 && !t.options.StrictRoute {
   612  			it = netlink.NewRule()
   613  			it.Priority = priority6
   614  			it.Invert = true
   615  			it.Dport = netlink.NewRulePortRange(53, 53)
   616  			it.Table = unix.RT_TABLE_MAIN
   617  			it.SuppressPrefixlen = 0
   618  			it.Family = unix.AF_INET6
   619  			rules = append(rules, it)
   620  
   621  			it = netlink.NewRule()
   622  			it.Priority = priority6
   623  			it.IPProto = syscall.IPPROTO_ICMPV6
   624  			it.Goto = nopPriority
   625  			it.Family = unix.AF_INET6
   626  			rules = append(rules, it)
   627  			priority6++
   628  		}
   629  	}
   630  
   631  	if p4 {
   632  		if t.options.StrictRoute {
   633  			it = netlink.NewRule()
   634  			it.Priority = priority
   635  			it.Table = t.options.TableIndex
   636  			it.Family = unix.AF_INET
   637  			rules = append(rules, it)
   638  		} else {
   639  			it = netlink.NewRule()
   640  			it.Priority = priority
   641  			it.Invert = true
   642  			it.IifName = "lo"
   643  			it.Table = t.options.TableIndex
   644  			it.Family = unix.AF_INET
   645  			rules = append(rules, it)
   646  
   647  			it = netlink.NewRule()
   648  			it.Priority = priority
   649  			it.IifName = "lo"
   650  			it.Src = netip.PrefixFrom(netip.IPv4Unspecified(), 32)
   651  			it.Table = t.options.TableIndex
   652  			it.Family = unix.AF_INET
   653  			rules = append(rules, it)
   654  
   655  			for _, address := range t.options.Inet4Address {
   656  				it = netlink.NewRule()
   657  				it.Priority = priority
   658  				it.IifName = "lo"
   659  				it.Src = address.Masked()
   660  				it.Table = t.options.TableIndex
   661  				it.Family = unix.AF_INET
   662  				rules = append(rules, it)
   663  			}
   664  		}
   665  		priority++
   666  	}
   667  	if p6 {
   668  		if !t.options.StrictRoute {
   669  			for _, address := range t.options.Inet6Address {
   670  				it = netlink.NewRule()
   671  				it.Priority = priority6
   672  				it.IifName = "lo"
   673  				it.Src = address.Masked()
   674  				it.Table = t.options.TableIndex
   675  				it.Family = unix.AF_INET6
   676  				rules = append(rules, it)
   677  			}
   678  			priority6++
   679  
   680  			it = netlink.NewRule()
   681  			it.Priority = priority6
   682  			it.IifName = "lo"
   683  			it.Src = netip.PrefixFrom(netip.IPv6Unspecified(), 1)
   684  			it.Goto = nopPriority
   685  			it.Family = unix.AF_INET6
   686  			rules = append(rules, it)
   687  
   688  			it = netlink.NewRule()
   689  			it.Priority = priority6
   690  			it.IifName = "lo"
   691  			it.Src = netip.PrefixFrom(netip.AddrFrom16([16]byte{0: 128}), 1)
   692  			it.Goto = nopPriority
   693  			it.Family = unix.AF_INET6
   694  			rules = append(rules, it)
   695  
   696  			priority6++
   697  		}
   698  
   699  		it = netlink.NewRule()
   700  		it.Priority = priority6
   701  		it.Table = t.options.TableIndex
   702  		it.Family = unix.AF_INET6
   703  		rules = append(rules, it)
   704  		priority6++
   705  	}
   706  	if p4 {
   707  		it = netlink.NewRule()
   708  		it.Priority = nopPriority
   709  		it.Family = unix.AF_INET
   710  		rules = append(rules, it)
   711  	}
   712  	if p6 {
   713  		it = netlink.NewRule()
   714  		it.Priority = nopPriority
   715  		it.Family = unix.AF_INET6
   716  		rules = append(rules, it)
   717  	}
   718  	return rules
   719  }
   720  
   721  func (t *NativeTun) setRoute(tunLink netlink.Link) error {
   722  	routes, err := t.routes(tunLink)
   723  	if err != nil {
   724  		return err
   725  	}
   726  	for i, route := range routes {
   727  		err := netlink.RouteAdd(&route)
   728  		if err != nil {
   729  			return E.Cause(err, "add route ", i)
   730  		}
   731  	}
   732  	return nil
   733  }
   734  
   735  func (t *NativeTun) setRules() error {
   736  	for i, rule := range t.rules() {
   737  		err := netlink.RuleAdd(rule)
   738  		if err != nil {
   739  			return E.Cause(err, "add rule ", i, "/", len(t.rules()))
   740  		}
   741  	}
   742  	return nil
   743  }
   744  
   745  func (t *NativeTun) unsetRoute() error {
   746  	if t.options.FileDescriptor > 0 {
   747  		return nil
   748  	}
   749  	tunLink, err := netlink.LinkByName(t.options.Name)
   750  	if err != nil {
   751  		return err
   752  	}
   753  	return t.unsetRoute0(tunLink)
   754  }
   755  
   756  func (t *NativeTun) unsetRoute0(tunLink netlink.Link) error {
   757  	if routes, err := t.routes(tunLink); err == nil {
   758  		for _, route := range routes {
   759  			_ = netlink.RouteDel(&route)
   760  		}
   761  	}
   762  	return nil
   763  }
   764  
   765  func (t *NativeTun) unsetRules() error {
   766  	if t.options.FileDescriptor > 0 {
   767  		return nil
   768  	}
   769  	if len(t.ruleIndex6) > 0 {
   770  		for _, index := range t.ruleIndex6 {
   771  			ruleToDel := netlink.NewRule()
   772  			ruleToDel.Family = unix.AF_INET6
   773  			ruleToDel.Priority = index
   774  			err := netlink.RuleDel(ruleToDel)
   775  			if err != nil {
   776  				return E.Cause(err, "unset rule6 ", index)
   777  			}
   778  		}
   779  		t.ruleIndex6 = nil
   780  	}
   781  	if t.options.AutoRoute {
   782  		ruleList, err := netlink.RuleList(netlink.FAMILY_ALL)
   783  		if err != nil {
   784  			return err
   785  		}
   786  		for _, rule := range ruleList {
   787  			if rule.Priority >= ruleStart && rule.Priority <= ruleEnd {
   788  				ruleToDel := netlink.NewRule()
   789  				ruleToDel.Family = rule.Family
   790  				ruleToDel.Priority = rule.Priority
   791  				err = netlink.RuleDel(ruleToDel)
   792  				if err != nil {
   793  					return E.Cause(err, "unset rule ", rule.Priority, " for ", rule.Family)
   794  				}
   795  			}
   796  		}
   797  	}
   798  	return nil
   799  }
   800  
   801  func (t *NativeTun) resetRules() error {
   802  	t.unsetRules()
   803  	return t.setRules()
   804  }
   805  
   806  func (t *NativeTun) routeUpdate(event int) {
   807  	if event&EventAndroidVPNUpdate == 0 {
   808  		return
   809  	}
   810  	err := t.resetRules()
   811  	if err != nil {
   812  		if t.options.Logger != nil {
   813  			t.options.Logger.Error(E.Cause(err, "reset route"))
   814  		}
   815  	}
   816  }
   817  
   818  func (t *NativeTun) setSearchDomainForSystemdResolved() {
   819  	ctlPath, err := exec.LookPath("resolvectl")
   820  	if err != nil {
   821  		return
   822  	}
   823  	var dnsServer []netip.Addr
   824  	if len(t.options.Inet4Address) > 0 {
   825  		dnsServer = append(dnsServer, t.options.Inet4Address[0].Addr().Next())
   826  	}
   827  	if len(t.options.Inet6Address) > 0 {
   828  		dnsServer = append(dnsServer, t.options.Inet6Address[0].Addr().Next())
   829  	}
   830  	go shell.Exec(ctlPath, "domain", t.options.Name, "~.").Run()
   831  	if t.options.AutoRoute {
   832  		go shell.Exec(ctlPath, "default-route", t.options.Name, "true").Run()
   833  		go shell.Exec(ctlPath, append([]string{"dns", t.options.Name}, common.Map(dnsServer, netip.Addr.String)...)...).Run()
   834  	}
   835  }