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