github.com/apernet/sing-tun@v0.2.6-0.20240323130332-b9f6511036ad/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 /*if p6 { 577 it = netlink.NewRule() 578 it.Priority = priority 579 it.Dst = t.options.Inet6Address.Masked() 580 it.Table = tunTableIndex 581 it.Family = unix.AF_INET6 582 rules = append(rules, it) 583 }*/ 584 if p4 { 585 it = netlink.NewRule() 586 it.Priority = priority 587 it.IPProto = syscall.IPPROTO_ICMP 588 it.Goto = nopPriority 589 it.Family = unix.AF_INET 590 rules = append(rules, it) 591 priority++ 592 } 593 if p6 { 594 it = netlink.NewRule() 595 it.Priority = priority6 596 it.IPProto = syscall.IPPROTO_ICMPV6 597 it.Goto = nopPriority 598 it.Family = unix.AF_INET6 599 rules = append(rules, it) 600 priority6++ 601 } 602 if p4 { 603 it = netlink.NewRule() 604 it.Priority = priority 605 it.Invert = true 606 it.Dport = netlink.NewRulePortRange(53, 53) 607 it.Table = unix.RT_TABLE_MAIN 608 it.SuppressPrefixlen = 0 609 it.Family = unix.AF_INET 610 rules = append(rules, it) 611 } 612 if p6 { 613 it = netlink.NewRule() 614 it.Priority = priority6 615 it.Invert = true 616 it.Dport = netlink.NewRulePortRange(53, 53) 617 it.Table = unix.RT_TABLE_MAIN 618 it.SuppressPrefixlen = 0 619 it.Family = unix.AF_INET6 620 rules = append(rules, it) 621 } 622 } 623 624 if p4 { 625 if t.options.StrictRoute { 626 it = netlink.NewRule() 627 it.Priority = priority 628 it.Table = t.options.TableIndex 629 it.Family = unix.AF_INET 630 rules = append(rules, it) 631 } else { 632 it = netlink.NewRule() 633 it.Priority = priority 634 it.Invert = true 635 it.IifName = "lo" 636 it.Table = t.options.TableIndex 637 it.Family = unix.AF_INET 638 rules = append(rules, it) 639 640 it = netlink.NewRule() 641 it.Priority = priority 642 it.IifName = "lo" 643 it.Src = netip.PrefixFrom(netip.IPv4Unspecified(), 32) 644 it.Table = t.options.TableIndex 645 it.Family = unix.AF_INET 646 rules = append(rules, it) 647 648 for _, address := range t.options.Inet4Address { 649 it = netlink.NewRule() 650 it.Priority = priority 651 it.IifName = "lo" 652 it.Src = address.Masked() 653 it.Table = t.options.TableIndex 654 it.Family = unix.AF_INET 655 rules = append(rules, it) 656 } 657 } 658 priority++ 659 } 660 if p6 { 661 if !t.options.StrictRoute { 662 for _, address := range t.options.Inet6Address { 663 it = netlink.NewRule() 664 it.Priority = priority6 665 it.IifName = "lo" 666 it.Src = address.Masked() 667 it.Table = t.options.TableIndex 668 it.Family = unix.AF_INET6 669 rules = append(rules, it) 670 } 671 priority6++ 672 673 it = netlink.NewRule() 674 it.Priority = priority6 675 it.IifName = "lo" 676 it.Src = netip.PrefixFrom(netip.IPv6Unspecified(), 1) 677 it.Goto = nopPriority 678 it.Family = unix.AF_INET6 679 rules = append(rules, it) 680 681 it = netlink.NewRule() 682 it.Priority = priority6 683 it.IifName = "lo" 684 it.Src = netip.PrefixFrom(netip.AddrFrom16([16]byte{0: 128}), 1) 685 it.Goto = nopPriority 686 it.Family = unix.AF_INET6 687 rules = append(rules, it) 688 689 priority6++ 690 } 691 692 it = netlink.NewRule() 693 it.Priority = priority6 694 it.Table = t.options.TableIndex 695 it.Family = unix.AF_INET6 696 rules = append(rules, it) 697 priority6++ 698 } 699 if p4 { 700 it = netlink.NewRule() 701 it.Priority = nopPriority 702 it.Family = unix.AF_INET 703 rules = append(rules, it) 704 } 705 if p6 { 706 it = netlink.NewRule() 707 it.Priority = nopPriority 708 it.Family = unix.AF_INET6 709 rules = append(rules, it) 710 } 711 return rules 712 } 713 714 func (t *NativeTun) setRoute(tunLink netlink.Link) error { 715 routes, err := t.routes(tunLink) 716 if err != nil { 717 return err 718 } 719 for i, route := range routes { 720 err := netlink.RouteAdd(&route) 721 if err != nil { 722 return E.Cause(err, "add route ", i) 723 } 724 } 725 return nil 726 } 727 728 func (t *NativeTun) setRules() error { 729 for i, rule := range t.rules() { 730 err := netlink.RuleAdd(rule) 731 if err != nil { 732 return E.Cause(err, "add rule ", i, "/", len(t.rules())) 733 } 734 } 735 return nil 736 } 737 738 func (t *NativeTun) unsetRoute() error { 739 if t.options.FileDescriptor > 0 { 740 return nil 741 } 742 tunLink, err := netlink.LinkByName(t.options.Name) 743 if err != nil { 744 return err 745 } 746 return t.unsetRoute0(tunLink) 747 } 748 749 func (t *NativeTun) unsetRoute0(tunLink netlink.Link) error { 750 if routes, err := t.routes(tunLink); err == nil { 751 for _, route := range routes { 752 _ = netlink.RouteDel(&route) 753 } 754 } 755 return nil 756 } 757 758 func (t *NativeTun) unsetRules() error { 759 if t.options.FileDescriptor > 0 { 760 return nil 761 } 762 if len(t.ruleIndex6) > 0 { 763 for _, index := range t.ruleIndex6 { 764 ruleToDel := netlink.NewRule() 765 ruleToDel.Family = unix.AF_INET6 766 ruleToDel.Priority = index 767 err := netlink.RuleDel(ruleToDel) 768 if err != nil { 769 return E.Cause(err, "unset rule6 ", index) 770 } 771 } 772 t.ruleIndex6 = nil 773 } 774 if t.options.AutoRoute { 775 ruleList, err := netlink.RuleList(netlink.FAMILY_ALL) 776 if err != nil { 777 return err 778 } 779 for _, rule := range ruleList { 780 if rule.Priority >= ruleStart && rule.Priority <= ruleEnd { 781 ruleToDel := netlink.NewRule() 782 ruleToDel.Family = rule.Family 783 ruleToDel.Priority = rule.Priority 784 err = netlink.RuleDel(ruleToDel) 785 if err != nil { 786 return E.Cause(err, "unset rule ", rule.Priority, " for ", rule.Family) 787 } 788 } 789 } 790 } 791 return nil 792 } 793 794 func (t *NativeTun) resetRules() error { 795 t.unsetRules() 796 return t.setRules() 797 } 798 799 func (t *NativeTun) routeUpdate(event int) { 800 if event&EventAndroidVPNUpdate == 0 { 801 return 802 } 803 err := t.resetRules() 804 if err != nil { 805 if t.options.Logger != nil { 806 t.options.Logger.Error(E.Cause(err, "reset route")) 807 } 808 } 809 } 810 811 func (t *NativeTun) setSearchDomainForSystemdResolved() { 812 ctlPath, err := exec.LookPath("resolvectl") 813 if err != nil { 814 return 815 } 816 var dnsServer []netip.Addr 817 if len(t.options.Inet4Address) > 0 { 818 dnsServer = append(dnsServer, t.options.Inet4Address[0].Addr().Next()) 819 } 820 if len(t.options.Inet6Address) > 0 { 821 dnsServer = append(dnsServer, t.options.Inet6Address[0].Addr().Next()) 822 } 823 shell.Exec(ctlPath, "domain", t.options.Name, "~.").Start() 824 if t.options.AutoRoute { 825 shell.Exec(ctlPath, "default-route", t.options.Name, "true").Start() 826 shell.Exec(ctlPath, append([]string{"dns", t.options.Name}, common.Map(dnsServer, netip.Addr.String)...)...).Start() 827 } 828 }