diff --git a/tun.go b/tun.go index f070795..067607a 100644 --- a/tun.go +++ b/tun.go @@ -37,6 +37,8 @@ type Options struct { MTU uint32 AutoRoute bool StrictRoute bool + Inet4RouteAddress []netip.Prefix + Inet6RouteAddress []netip.Prefix IncludeUID []ranges.Range[uint32] ExcludeUID []ranges.Range[uint32] IncludeAndroidUser []int diff --git a/tun_darwin.go b/tun_darwin.go index b7d9048..e849bec 100644 --- a/tun_darwin.go +++ b/tun_darwin.go @@ -241,27 +241,42 @@ func configure(tunFd int, ifIndex int, name string, options Options) error { } if options.AutoRoute { if len(options.Inet4Address) > 0 { - for _, subnet := range []netip.Prefix{ - 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{4, 0, 0, 0}), 6), - netip.PrefixFrom(netip.AddrFrom4([4]byte{8, 0, 0, 0}), 5), - netip.PrefixFrom(netip.AddrFrom4([4]byte{16, 0, 0, 0}), 4), - netip.PrefixFrom(netip.AddrFrom4([4]byte{32, 0, 0, 0}), 3), - netip.PrefixFrom(netip.AddrFrom4([4]byte{64, 0, 0, 0}), 2), - netip.PrefixFrom(netip.AddrFrom4([4]byte{128, 0, 0, 0}), 1), - } { + var routes []netip.Prefix + if len(options.Inet4RouteAddress) > 0 { + routes = append(options.Inet4RouteAddress, netip.PrefixFrom(options.Inet4Address[0].Addr().Next(), 32)) + } else { + routes = []netip.Prefix{ + 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{4, 0, 0, 0}), 6), + netip.PrefixFrom(netip.AddrFrom4([4]byte{8, 0, 0, 0}), 5), + netip.PrefixFrom(netip.AddrFrom4([4]byte{16, 0, 0, 0}), 4), + netip.PrefixFrom(netip.AddrFrom4([4]byte{32, 0, 0, 0}), 3), + netip.PrefixFrom(netip.AddrFrom4([4]byte{64, 0, 0, 0}), 2), + netip.PrefixFrom(netip.AddrFrom4([4]byte{128, 0, 0, 0}), 1), + } + } + for _, subnet := range routes { err = addRoute(subnet, options.Inet4Address[0].Addr()) if err != nil { - return E.Cause(err, "add ipv4 route "+subnet.String()) + return E.Cause(err, "add ipv4 route ", subnet) } } } 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) - err = addRoute(subnet, options.Inet6Address[0].Addr()) - if err != nil { - return E.Cause(err, "add ipv6 route "+subnet.String()) + var routes []netip.Prefix + if len(options.Inet6RouteAddress) > 0 { + routes = append(options.Inet6RouteAddress, netip.PrefixFrom(options.Inet6Address[0].Addr().Next(), 128)) + } else { + routes = []netip.Prefix{ + netip.PrefixFrom(netip.AddrFrom16([16]byte{32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}), 3), + } + } + for _, subnet := range routes { + err = addRoute(subnet, options.Inet6Address[0].Addr()) + if err != nil { + return E.Cause(err, "add ipv6 route ", subnet) + } } } } diff --git a/tun_linux.go b/tun_linux.go index ac19064..be78840 100644 --- a/tun_linux.go +++ b/tun_linux.go @@ -171,26 +171,52 @@ func (t *NativeTun) routes(tunLink netlink.Link) []netlink.Route { var routes []netlink.Route if len(t.options.Inet4Address) > 0 { if t.options.AutoRoute { + if len(t.options.Inet4RouteAddress) > 0 { + for _, addr := range t.options.Inet4RouteAddress { + routes = append(routes, netlink.Route{ + Dst: &net.IPNet{ + IP: addr.Addr().AsSlice(), + Mask: net.CIDRMask(addr.Bits(), 32), + }, + LinkIndex: tunLink.Attrs().Index, + Table: t.options.TableIndex, + }) + } + } else { + routes = append(routes, netlink.Route{ + Dst: &net.IPNet{ + IP: net.IPv4zero, + Mask: net.CIDRMask(0, 32), + }, + LinkIndex: tunLink.Attrs().Index, + Table: t.options.TableIndex, + }) + } + } + } + if len(t.options.Inet6Address) > 0 { + if len(t.options.Inet6RouteAddress) > 0 { + for _, addr := range t.options.Inet6RouteAddress { + routes = append(routes, netlink.Route{ + Dst: &net.IPNet{ + IP: addr.Addr().AsSlice(), + Mask: net.CIDRMask(addr.Bits(), 128), + }, + LinkIndex: tunLink.Attrs().Index, + Table: t.options.TableIndex, + }) + } + } else { routes = append(routes, netlink.Route{ Dst: &net.IPNet{ - IP: net.IPv4zero, - Mask: net.CIDRMask(0, 32), + IP: net.IPv6zero, + Mask: net.CIDRMask(0, 128), }, LinkIndex: tunLink.Attrs().Index, Table: t.options.TableIndex, }) } } - if len(t.options.Inet6Address) > 0 { - routes = append(routes, netlink.Route{ - Dst: &net.IPNet{ - IP: net.IPv6zero, - Mask: net.CIDRMask(0, 128), - }, - LinkIndex: tunLink.Attrs().Index, - Table: t.options.TableIndex, - }) - } return routes } diff --git a/tun_windows.go b/tun_windows.go index 631de64..12cfb40 100644 --- a/tun_windows.go +++ b/tun_windows.go @@ -108,15 +108,33 @@ func (t *NativeTun) configure() error { } } else { if len(t.options.Inet4Address) > 0 { - err := luid.AddRoute(netip.PrefixFrom(netip.IPv4Unspecified(), 0), netip.IPv4Unspecified(), 0) - if err != nil { - return E.Cause(err, "set ipv4 route") + if len(t.options.Inet4RouteAddress) > 0 { + for _, addr := range t.options.Inet4RouteAddress { + err := luid.AddRoute(addr, netip.IPv4Unspecified(), 0) + if err != nil { + return E.Cause(err, "add ipv4 route: ", addr) + } + } + } else { + err := luid.AddRoute(netip.PrefixFrom(netip.IPv4Unspecified(), 0), netip.IPv4Unspecified(), 0) + if err != nil { + return E.Cause(err, "set ipv4 route") + } } } if len(t.options.Inet6Address) > 0 { - err := luid.AddRoute(netip.PrefixFrom(netip.IPv6Unspecified(), 0), netip.IPv6Unspecified(), 0) - if err != nil { - return E.Cause(err, "set ipv6 route") + if len(t.options.Inet6RouteAddress) > 0 { + for _, addr := range t.options.Inet6RouteAddress { + err := luid.AddRoute(addr, netip.IPv6Unspecified(), 0) + if err != nil { + return E.Cause(err, "add ipv6 route: ", addr) + } + } + } else { + err := luid.AddRoute(netip.PrefixFrom(netip.IPv6Unspecified(), 0), netip.IPv6Unspecified(), 0) + if err != nil { + return E.Cause(err, "set ipv6 route") + } } } }