Add support for multi tun address prefix

This commit is contained in:
世界 2022-09-05 21:48:18 +08:00
parent 197b599075
commit 2f5a02c140
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
4 changed files with 192 additions and 138 deletions

4
tun.go
View file

@ -32,8 +32,8 @@ type WinTun interface {
type Options struct { type Options struct {
Name string Name string
Inet4Address netip.Prefix Inet4Address []netip.Prefix
Inet6Address netip.Prefix Inet6Address []netip.Prefix
MTU uint32 MTU uint32
AutoRoute bool AutoRoute bool
StrictRoute bool StrictRoute bool

View file

@ -45,10 +45,14 @@ func Open(options Options) (Tun, error) {
return nil, err return nil, err
} }
nativeTun := &NativeTun{ nativeTun := &NativeTun{
tunFile: os.NewFile(uintptr(tunFd), "utun"), tunFile: os.NewFile(uintptr(tunFd), "utun"),
mtu: options.MTU, mtu: options.MTU,
inet4Address: string(options.Inet4Address.Addr().AsSlice()), }
inet6Address: string(options.Inet6Address.Addr().AsSlice()), if len(options.Inet4Address) > 0 {
nativeTun.inet4Address = string(options.Inet4Address[0].Addr().AsSlice())
}
if len(options.Inet6Address) > 0 {
nativeTun.inet6Address = string(options.Inet6Address[0].Addr().AsSlice())
} }
var ok bool var ok bool
nativeTun.tunWriter, ok = bufio.CreateVectorisedWriter(nativeTun.tunFile) nativeTun.tunWriter, ok = bufio.CreateVectorisedWriter(nativeTun.tunFile)
@ -155,83 +159,87 @@ func configure(tunFd int, ifIndex int, name string, options Options) error {
if err != nil { if err != nil {
return err return err
} }
if options.Inet4Address.IsValid() { if len(options.Inet4Address) > 0 {
ifReq := ifAliasReq{ for _, address := range options.Inet4Address {
Addr: unix.RawSockaddrInet4{ ifReq := ifAliasReq{
Len: unix.SizeofSockaddrInet4, Addr: unix.RawSockaddrInet4{
Family: unix.AF_INET, Len: unix.SizeofSockaddrInet4,
Addr: options.Inet4Address.Addr().As4(), Family: unix.AF_INET,
}, Addr: address.Addr().As4(),
Dstaddr: unix.RawSockaddrInet4{ },
Len: unix.SizeofSockaddrInet4, Dstaddr: unix.RawSockaddrInet4{
Family: unix.AF_INET, Len: unix.SizeofSockaddrInet4,
Addr: options.Inet4Address.Addr().As4(), Family: unix.AF_INET,
}, Addr: address.Addr().As4(),
Mask: unix.RawSockaddrInet4{ },
Len: unix.SizeofSockaddrInet4, Mask: unix.RawSockaddrInet4{
Family: unix.AF_INET, Len: unix.SizeofSockaddrInet4,
Addr: netip.MustParseAddr(net.IP(net.CIDRMask(options.Inet4Address.Bits(), 32)).String()).As4(), Family: unix.AF_INET,
}, Addr: netip.MustParseAddr(net.IP(net.CIDRMask(address.Bits(), 32)).String()).As4(),
} },
copy(ifReq.Name[:], name) }
err = useSocket(unix.AF_INET, unix.SOCK_DGRAM, 0, func(socketFd int) error { copy(ifReq.Name[:], name)
if _, _, errno := unix.Syscall( err = useSocket(unix.AF_INET, unix.SOCK_DGRAM, 0, func(socketFd int) error {
syscall.SYS_IOCTL, if _, _, errno := unix.Syscall(
uintptr(socketFd), syscall.SYS_IOCTL,
uintptr(unix.SIOCAIFADDR), uintptr(socketFd),
uintptr(unsafe.Pointer(&ifReq)), uintptr(unix.SIOCAIFADDR),
); errno != 0 { uintptr(unsafe.Pointer(&ifReq)),
return os.NewSyscallError("SIOCAIFADDR", errno) ); errno != 0 {
return os.NewSyscallError("SIOCAIFADDR", errno)
}
return nil
})
if err != nil {
return err
} }
return nil
})
if err != nil {
return err
} }
} }
if options.Inet6Address.IsValid() { if len(options.Inet6Address) > 0 {
ifReq6 := ifAliasReq6{ for _, address := range options.Inet6Address {
Addr: unix.RawSockaddrInet6{ ifReq6 := ifAliasReq6{
Len: unix.SizeofSockaddrInet6, Addr: unix.RawSockaddrInet6{
Family: unix.AF_INET6, Len: unix.SizeofSockaddrInet6,
Addr: options.Inet6Address.Addr().As16(), Family: unix.AF_INET6,
}, Addr: address.Addr().As16(),
Mask: unix.RawSockaddrInet6{ },
Len: unix.SizeofSockaddrInet6, Mask: unix.RawSockaddrInet6{
Family: unix.AF_INET6, Len: unix.SizeofSockaddrInet6,
Addr: netip.MustParseAddr(net.IP(net.CIDRMask(options.Inet6Address.Bits(), 128)).String()).As16(), Family: unix.AF_INET6,
}, Addr: netip.MustParseAddr(net.IP(net.CIDRMask(address.Bits(), 128)).String()).As16(),
Flags: IN6_IFF_NODAD | IN6_IFF_SECURED, },
Lifetime: addrLifetime6{ Flags: IN6_IFF_NODAD | IN6_IFF_SECURED,
Vltime: ND6_INFINITE_LIFETIME, Lifetime: addrLifetime6{
Pltime: ND6_INFINITE_LIFETIME, Vltime: ND6_INFINITE_LIFETIME,
}, Pltime: ND6_INFINITE_LIFETIME,
} },
if options.Inet6Address.Bits() == 128 {
ifReq6.Dstaddr = unix.RawSockaddrInet6{
Len: unix.SizeofSockaddrInet6,
Family: unix.AF_INET6,
Addr: options.Inet6Address.Addr().Next().As16(),
} }
} if address.Bits() == 128 {
copy(ifReq6.Name[:], name) ifReq6.Dstaddr = unix.RawSockaddrInet6{
err = useSocket(unix.AF_INET6, unix.SOCK_DGRAM, 0, func(socketFd int) error { Len: unix.SizeofSockaddrInet6,
if _, _, errno := unix.Syscall( Family: unix.AF_INET6,
syscall.SYS_IOCTL, Addr: address.Addr().Next().As16(),
uintptr(socketFd), }
uintptr(SIOCAIFADDR_IN6), }
uintptr(unsafe.Pointer(&ifReq6)), copy(ifReq6.Name[:], name)
); errno != 0 { err = useSocket(unix.AF_INET6, unix.SOCK_DGRAM, 0, func(socketFd int) error {
return os.NewSyscallError("SIOCAIFADDR_IN6", errno) if _, _, errno := unix.Syscall(
syscall.SYS_IOCTL,
uintptr(socketFd),
uintptr(SIOCAIFADDR_IN6),
uintptr(unsafe.Pointer(&ifReq6)),
); errno != 0 {
return os.NewSyscallError("SIOCAIFADDR_IN6", errno)
}
return nil
})
if err != nil {
return err
} }
return nil
})
if err != nil {
return err
} }
} }
if options.AutoRoute { if options.AutoRoute {
if options.Inet4Address.IsValid() { if len(options.Inet4Address) > 0 {
for _, subnet := range []netip.Prefix{ for _, subnet := range []netip.Prefix{
netip.PrefixFrom(netip.AddrFrom4([4]byte{1, 0, 0, 0}), 8), netip.PrefixFrom(netip.AddrFrom4([4]byte{1, 0, 0, 0}), 8),
netip.PrefixFrom(netip.AddrFrom4([4]byte{2, 0, 0, 0}), 7), netip.PrefixFrom(netip.AddrFrom4([4]byte{2, 0, 0, 0}), 7),
@ -242,15 +250,15 @@ func configure(tunFd int, ifIndex int, name string, options Options) error {
netip.PrefixFrom(netip.AddrFrom4([4]byte{64, 0, 0, 0}), 2), netip.PrefixFrom(netip.AddrFrom4([4]byte{64, 0, 0, 0}), 2),
netip.PrefixFrom(netip.AddrFrom4([4]byte{128, 0, 0, 0}), 1), netip.PrefixFrom(netip.AddrFrom4([4]byte{128, 0, 0, 0}), 1),
} { } {
err = addRoute(subnet, options.Inet4Address.Addr()) err = addRoute(subnet, options.Inet4Address[0].Addr())
if err != nil { if err != nil {
return err return err
} }
} }
} }
if options.Inet6Address.IsValid() { if len(options.Inet6Address) > 0 {
subnet := netip.PrefixFrom(netip.AddrFrom16([16]byte{32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}), 3) subnet := netip.PrefixFrom(netip.AddrFrom16([16]byte{32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}), 3)
err = addRoute(subnet, options.Inet6Address.Addr()) err = addRoute(subnet, options.Inet6Address[0].Addr())
if err != nil { if err != nil {
return err return err
} }

View file

@ -101,19 +101,22 @@ func (t *NativeTun) configure(tunLink netlink.Link) error {
return err return err
} }
if t.options.Inet4Address.IsValid() { if len(t.options.Inet4Address) > 0 {
addr4, _ := netlink.ParseAddr(t.options.Inet4Address.String()) for _, address := range t.options.Inet4Address {
err = netlink.AddrAdd(tunLink, addr4) addr4, _ := netlink.ParseAddr(address.String())
if err != nil { err = netlink.AddrAdd(tunLink, addr4)
return err if err != nil {
return err
}
} }
} }
if len(t.options.Inet6Address) > 0 {
if t.options.Inet6Address.IsValid() { for _, address := range t.options.Inet6Address {
addr6, _ := netlink.ParseAddr(t.options.Inet6Address.String()) addr6, _ := netlink.ParseAddr(address.String())
err = netlink.AddrAdd(tunLink, addr6) err = netlink.AddrAdd(tunLink, addr6)
if err != nil { if err != nil {
return err return err
}
} }
} }
@ -122,14 +125,20 @@ func (t *NativeTun) configure(tunLink netlink.Link) error {
return err return err
} }
err = t.setRoute(tunLink)
if err != nil {
_ = t.unsetRoute0(tunLink)
return err
}
if t.options.AutoRoute { if t.options.AutoRoute {
err = t.unsetRoute0(tunLink) err = t.unsetRules()
if err != nil { if err != nil {
return E.Cause(err, "cleanup rules") return E.Cause(err, "cleanup rules")
} }
err = t.setRoute(tunLink) err = t.setRules()
if err != nil { if err != nil {
_ = t.unsetRoute0(tunLink) _ = t.unsetRules()
return err return err
} }
if runtime.GOOS == "android" { if runtime.GOOS == "android" {
@ -141,8 +150,9 @@ func (t *NativeTun) configure(tunLink netlink.Link) error {
func (t *NativeTun) Close() error { func (t *NativeTun) Close() error {
var errors []error var errors []error
errors = append(errors, t.unsetRoute())
if t.options.AutoRoute { if t.options.AutoRoute {
errors = append(errors, t.unsetRoute()) errors = append(errors, t.unsetRules())
} }
if t.interfaceCallback != nil { if t.interfaceCallback != nil {
t.options.InterfaceMonitor.UnregisterCallback(t.interfaceCallback) t.options.InterfaceMonitor.UnregisterCallback(t.interfaceCallback)
@ -154,25 +164,57 @@ const tunTableIndex = 2022
func (t *NativeTun) routes(tunLink netlink.Link) []netlink.Route { func (t *NativeTun) routes(tunLink netlink.Link) []netlink.Route {
var routes []netlink.Route var routes []netlink.Route
if t.options.Inet4Address.IsValid() { if len(t.options.Inet4Address) > 0 {
routes = append(routes, netlink.Route{ for _, address := range t.options.Inet4Address {
Dst: &net.IPNet{ if address.Bits() != 32 {
IP: net.IPv4zero, continue
Mask: net.CIDRMask(0, 32), }
}, routes = append(routes, netlink.Route{
LinkIndex: tunLink.Attrs().Index, Dst: &net.IPNet{
Table: tunTableIndex, IP: address.Addr().AsSlice(),
}) Mask: net.CIDRMask(address.Bits(), 32),
},
LinkIndex: tunLink.Attrs().Index,
Table: unix.RT_TABLE_MAIN,
Scope: unix.RT_SCOPE_LINK,
})
}
if t.options.AutoRoute {
routes = append(routes, netlink.Route{
Dst: &net.IPNet{
IP: net.IPv4zero,
Mask: net.CIDRMask(0, 32),
},
LinkIndex: tunLink.Attrs().Index,
Table: tunTableIndex,
})
}
} }
if t.options.Inet6Address.IsValid() { if len(t.options.Inet6Address) > 0 {
routes = append(routes, netlink.Route{ for _, address := range t.options.Inet6Address {
Dst: &net.IPNet{ if address.Bits() != 128 {
IP: net.IPv6zero, continue
Mask: net.CIDRMask(0, 128), }
}, routes = append(routes, netlink.Route{
LinkIndex: tunLink.Attrs().Index, Dst: &net.IPNet{
Table: tunTableIndex, IP: address.Addr().AsSlice(),
}) Mask: net.CIDRMask(address.Bits(), 128),
},
LinkIndex: tunLink.Attrs().Index,
Table: unix.RT_TABLE_MAIN,
Scope: unix.RT_SCOPE_LINK,
})
}
if t.options.AutoRoute {
routes = append(routes, netlink.Route{
Dst: &net.IPNet{
IP: net.IPv6zero,
Mask: net.CIDRMask(0, 128),
},
LinkIndex: tunLink.Attrs().Index,
Table: tunTableIndex,
})
}
} }
return routes return routes
} }
@ -185,11 +227,11 @@ const (
func (t *NativeTun) rules() []*netlink.Rule { func (t *NativeTun) rules() []*netlink.Rule {
var p4, p6 bool var p4, p6 bool
var pRule int var pRule int
if t.options.Inet4Address.IsValid() { if len(t.options.Inet4Address) > 0 {
p4 = true p4 = true
pRule += 1 pRule += 1
} }
if t.options.Inet6Address.IsValid() { if len(t.options.Inet6Address) > 0 {
p6 = true p6 = true
pRule += 1 pRule += 1
} }
@ -281,12 +323,14 @@ func (t *NativeTun) rules() []*netlink.Rule {
if runtime.GOOS != "android" { if runtime.GOOS != "android" {
if p4 { if p4 {
it = netlink.NewRule() for _, address := range t.options.Inet4Address {
it.Priority = priority it = netlink.NewRule()
it.Dst = t.options.Inet4Address.Masked() it.Priority = priority
it.Table = tunTableIndex it.Dst = address.Masked()
it.Family = unix.AF_INET it.Table = tunTableIndex
rules = append(rules, it) it.Family = unix.AF_INET
rules = append(rules, it)
}
priority++ priority++
} }
/*if p6 { /*if p6 {
@ -361,13 +405,15 @@ func (t *NativeTun) rules() []*netlink.Rule {
it.Family = unix.AF_INET it.Family = unix.AF_INET
rules = append(rules, it) rules = append(rules, it)
it = netlink.NewRule() for _, address := range t.options.Inet4Address {
it.Priority = priority it = netlink.NewRule()
it.IifName = "lo" it.Priority = priority
it.Src = t.options.Inet4Address.Masked() it.IifName = "lo"
it.Table = tunTableIndex it.Src = address.Masked()
it.Family = unix.AF_INET it.Table = tunTableIndex
rules = append(rules, it) it.Family = unix.AF_INET
rules = append(rules, it)
}
} }
priority++ priority++
} }
@ -426,7 +472,7 @@ func (t *NativeTun) setRoute(tunLink netlink.Link) error {
return E.Cause(err, "add route ", i) return E.Cause(err, "add route ", i)
} }
} }
return t.setRules() return nil
} }
func (t *NativeTun) setRules() error { func (t *NativeTun) setRules() error {
@ -451,7 +497,7 @@ func (t *NativeTun) unsetRoute0(tunLink netlink.Link) error {
for _, route := range t.routes(tunLink) { for _, route := range t.routes(tunLink) {
_ = netlink.RouteDel(&route) _ = netlink.RouteDel(&route)
} }
return t.unsetRules() return nil
} }
func (t *NativeTun) unsetRules() error { func (t *NativeTun) unsetRules() error {

View file

@ -57,41 +57,41 @@ func Open(options Options) (WinTun, error) {
func (t *NativeTun) configure() error { func (t *NativeTun) configure() error {
luid := winipcfg.LUID(t.adapter.LUID()) luid := winipcfg.LUID(t.adapter.LUID())
if t.options.Inet4Address.IsValid() { if len(t.options.Inet4Address) > 0 {
err := luid.SetIPAddressesForFamily(winipcfg.AddressFamily(windows.AF_INET), []netip.Prefix{t.options.Inet4Address}) err := luid.SetIPAddressesForFamily(winipcfg.AddressFamily(windows.AF_INET), t.options.Inet4Address)
if err != nil { if err != nil {
return E.Cause(err, "set ipv4 address") return E.Cause(err, "set ipv4 address")
} }
} }
if t.options.Inet6Address.IsValid() { if len(t.options.Inet6Address) > 0 {
err := luid.SetIPAddressesForFamily(winipcfg.AddressFamily(windows.AF_INET6), []netip.Prefix{t.options.Inet6Address}) err := luid.SetIPAddressesForFamily(winipcfg.AddressFamily(windows.AF_INET6), t.options.Inet6Address)
if err != nil { if err != nil {
return E.Cause(err, "set ipv6 address") return E.Cause(err, "set ipv6 address")
} }
} }
err := luid.SetDNS(winipcfg.AddressFamily(windows.AF_INET), []netip.Addr{t.options.Inet4Address.Addr().Next()}, nil) err := luid.SetDNS(winipcfg.AddressFamily(windows.AF_INET), []netip.Addr{t.options.Inet4Address[0].Addr().Next()}, nil)
if err != nil { if err != nil {
return E.Cause(err, "set ipv4 dns") return E.Cause(err, "set ipv4 dns")
} }
err = luid.SetDNS(winipcfg.AddressFamily(windows.AF_INET6), []netip.Addr{t.options.Inet6Address.Addr().Next()}, nil) err = luid.SetDNS(winipcfg.AddressFamily(windows.AF_INET6), []netip.Addr{t.options.Inet6Address[0].Addr().Next()}, nil)
if err != nil { if err != nil {
return E.Cause(err, "set ipv6 dns") return E.Cause(err, "set ipv6 dns")
} }
if t.options.AutoRoute { if t.options.AutoRoute {
if t.options.Inet4Address.IsValid() { if len(t.options.Inet4Address) > 0 {
err = luid.AddRoute(netip.PrefixFrom(netip.IPv4Unspecified(), 0), netip.IPv4Unspecified(), 0) err = luid.AddRoute(netip.PrefixFrom(netip.IPv4Unspecified(), 0), netip.IPv4Unspecified(), 0)
if err != nil { if err != nil {
return E.Cause(err, "set ipv4 route") return E.Cause(err, "set ipv4 route")
} }
} }
if t.options.Inet6Address.IsValid() { if len(t.options.Inet6Address) > 0 {
err = luid.AddRoute(netip.PrefixFrom(netip.IPv6Unspecified(), 0), netip.IPv6Unspecified(), 0) err = luid.AddRoute(netip.PrefixFrom(netip.IPv6Unspecified(), 0), netip.IPv6Unspecified(), 0)
if err != nil { if err != nil {
return E.Cause(err, "set ipv6 route") return E.Cause(err, "set ipv6 route")
} }
} }
} }
if t.options.Inet4Address.IsValid() { if len(t.options.Inet4Address) > 0 {
var inetIf *winipcfg.MibIPInterfaceRow var inetIf *winipcfg.MibIPInterfaceRow
inetIf, err = luid.IPInterface(winipcfg.AddressFamily(windows.AF_INET)) inetIf, err = luid.IPInterface(winipcfg.AddressFamily(windows.AF_INET))
if err != nil { if err != nil {
@ -112,7 +112,7 @@ func (t *NativeTun) configure() error {
return E.Cause(err, "set ipv4 options") return E.Cause(err, "set ipv4 options")
} }
} }
if t.options.Inet6Address.IsValid() { if len(t.options.Inet6Address) > 0 {
var inet6If *winipcfg.MibIPInterfaceRow var inet6If *winipcfg.MibIPInterfaceRow
inet6If, err = luid.IPInterface(winipcfg.AddressFamily(windows.AF_INET6)) inet6If, err = luid.IPInterface(winipcfg.AddressFamily(windows.AF_INET6))
if err != nil { if err != nil {