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

@ -47,8 +47,12 @@ func Open(options Options) (Tun, error) {
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,22 +159,23 @@ 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 {
for _, address := range options.Inet4Address {
ifReq := ifAliasReq{ ifReq := ifAliasReq{
Addr: unix.RawSockaddrInet4{ Addr: unix.RawSockaddrInet4{
Len: unix.SizeofSockaddrInet4, Len: unix.SizeofSockaddrInet4,
Family: unix.AF_INET, Family: unix.AF_INET,
Addr: options.Inet4Address.Addr().As4(), Addr: address.Addr().As4(),
}, },
Dstaddr: unix.RawSockaddrInet4{ Dstaddr: unix.RawSockaddrInet4{
Len: unix.SizeofSockaddrInet4, Len: unix.SizeofSockaddrInet4,
Family: unix.AF_INET, Family: unix.AF_INET,
Addr: options.Inet4Address.Addr().As4(), Addr: address.Addr().As4(),
}, },
Mask: unix.RawSockaddrInet4{ Mask: unix.RawSockaddrInet4{
Len: unix.SizeofSockaddrInet4, Len: unix.SizeofSockaddrInet4,
Family: unix.AF_INET, Family: unix.AF_INET,
Addr: netip.MustParseAddr(net.IP(net.CIDRMask(options.Inet4Address.Bits(), 32)).String()).As4(), Addr: netip.MustParseAddr(net.IP(net.CIDRMask(address.Bits(), 32)).String()).As4(),
}, },
} }
copy(ifReq.Name[:], name) copy(ifReq.Name[:], name)
@ -189,17 +194,19 @@ func configure(tunFd int, ifIndex int, name string, options Options) error {
return err return err
} }
} }
if options.Inet6Address.IsValid() { }
if len(options.Inet6Address) > 0 {
for _, address := range options.Inet6Address {
ifReq6 := ifAliasReq6{ ifReq6 := ifAliasReq6{
Addr: unix.RawSockaddrInet6{ Addr: unix.RawSockaddrInet6{
Len: unix.SizeofSockaddrInet6, Len: unix.SizeofSockaddrInet6,
Family: unix.AF_INET6, Family: unix.AF_INET6,
Addr: options.Inet6Address.Addr().As16(), Addr: address.Addr().As16(),
}, },
Mask: unix.RawSockaddrInet6{ Mask: unix.RawSockaddrInet6{
Len: unix.SizeofSockaddrInet6, Len: unix.SizeofSockaddrInet6,
Family: unix.AF_INET6, Family: unix.AF_INET6,
Addr: netip.MustParseAddr(net.IP(net.CIDRMask(options.Inet6Address.Bits(), 128)).String()).As16(), Addr: netip.MustParseAddr(net.IP(net.CIDRMask(address.Bits(), 128)).String()).As16(),
}, },
Flags: IN6_IFF_NODAD | IN6_IFF_SECURED, Flags: IN6_IFF_NODAD | IN6_IFF_SECURED,
Lifetime: addrLifetime6{ Lifetime: addrLifetime6{
@ -207,11 +214,11 @@ func configure(tunFd int, ifIndex int, name string, options Options) error {
Pltime: ND6_INFINITE_LIFETIME, Pltime: ND6_INFINITE_LIFETIME,
}, },
} }
if options.Inet6Address.Bits() == 128 { if address.Bits() == 128 {
ifReq6.Dstaddr = unix.RawSockaddrInet6{ ifReq6.Dstaddr = unix.RawSockaddrInet6{
Len: unix.SizeofSockaddrInet6, Len: unix.SizeofSockaddrInet6,
Family: unix.AF_INET6, Family: unix.AF_INET6,
Addr: options.Inet6Address.Addr().Next().As16(), Addr: address.Addr().Next().As16(),
} }
} }
copy(ifReq6.Name[:], name) copy(ifReq6.Name[:], name)
@ -230,8 +237,9 @@ func configure(tunFd int, ifIndex int, name string, options Options) error {
return err 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,37 +101,46 @@ 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 {
addr4, _ := netlink.ParseAddr(address.String())
err = netlink.AddrAdd(tunLink, addr4) err = netlink.AddrAdd(tunLink, addr4)
if err != nil { if err != nil {
return err return err
} }
} }
}
if t.options.Inet6Address.IsValid() { if len(t.options.Inet6Address) > 0 {
addr6, _ := netlink.ParseAddr(t.options.Inet6Address.String()) for _, address := range t.options.Inet6Address {
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
} }
} }
}
err = netlink.LinkSetUp(tunLink) err = netlink.LinkSetUp(tunLink)
if err != nil { if err != nil {
return err return err
} }
if t.options.AutoRoute {
err = t.unsetRoute0(tunLink)
if err != nil {
return E.Cause(err, "cleanup rules")
}
err = t.setRoute(tunLink) err = t.setRoute(tunLink)
if err != nil { if err != nil {
_ = t.unsetRoute0(tunLink) _ = t.unsetRoute0(tunLink)
return err return err
} }
if t.options.AutoRoute {
err = t.unsetRules()
if err != nil {
return E.Cause(err, "cleanup rules")
}
err = t.setRules()
if err != nil {
_ = t.unsetRules()
return err
}
if runtime.GOOS == "android" { if runtime.GOOS == "android" {
t.interfaceCallback = t.options.InterfaceMonitor.RegisterCallback(t.routeUpdate) t.interfaceCallback = t.options.InterfaceMonitor.RegisterCallback(t.routeUpdate)
} }
@ -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
if t.options.AutoRoute {
errors = append(errors, t.unsetRoute()) errors = append(errors, t.unsetRoute())
if t.options.AutoRoute {
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,7 +164,22 @@ 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 {
for _, address := range t.options.Inet4Address {
if address.Bits() != 32 {
continue
}
routes = append(routes, netlink.Route{
Dst: &net.IPNet{
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{ routes = append(routes, netlink.Route{
Dst: &net.IPNet{ Dst: &net.IPNet{
IP: net.IPv4zero, IP: net.IPv4zero,
@ -164,7 +189,23 @@ func (t *NativeTun) routes(tunLink netlink.Link) []netlink.Route {
Table: tunTableIndex, Table: tunTableIndex,
}) })
} }
if t.options.Inet6Address.IsValid() { }
if len(t.options.Inet6Address) > 0 {
for _, address := range t.options.Inet6Address {
if address.Bits() != 128 {
continue
}
routes = append(routes, netlink.Route{
Dst: &net.IPNet{
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{ routes = append(routes, netlink.Route{
Dst: &net.IPNet{ Dst: &net.IPNet{
IP: net.IPv6zero, IP: net.IPv6zero,
@ -174,6 +215,7 @@ func (t *NativeTun) routes(tunLink netlink.Link) []netlink.Route {
Table: tunTableIndex, 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 {
for _, address := range t.options.Inet4Address {
it = netlink.NewRule() it = netlink.NewRule()
it.Priority = priority it.Priority = priority
it.Dst = t.options.Inet4Address.Masked() it.Dst = address.Masked()
it.Table = tunTableIndex it.Table = tunTableIndex
it.Family = unix.AF_INET it.Family = unix.AF_INET
rules = append(rules, it) rules = append(rules, it)
}
priority++ priority++
} }
/*if p6 { /*if p6 {
@ -361,14 +405,16 @@ func (t *NativeTun) rules() []*netlink.Rule {
it.Family = unix.AF_INET it.Family = unix.AF_INET
rules = append(rules, it) rules = append(rules, it)
for _, address := range t.options.Inet4Address {
it = netlink.NewRule() it = netlink.NewRule()
it.Priority = priority it.Priority = priority
it.IifName = "lo" it.IifName = "lo"
it.Src = t.options.Inet4Address.Masked() it.Src = address.Masked()
it.Table = tunTableIndex it.Table = tunTableIndex
it.Family = unix.AF_INET it.Family = unix.AF_INET
rules = append(rules, it) rules = append(rules, it)
} }
}
priority++ priority++
} }
if p6 { if p6 {
@ -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 {