netbird/client/internal/routemanager/systemops_windows.go
Viktor Liu 2475473227
Support client default routes for Linux (#1667)
All routes are now installed in a custom netbird routing table.
Management and wireguard traffic is now marked with a custom fwmark.
When the mark is present the traffic is routed via the main routing table, bypassing the VPN.
When the mark is absent the traffic is routed via the netbird routing table, if:
- there's no match in the main routing table
- it would match the default route in the routing table

IPv6 traffic is blocked when a default route IPv4 route is configured to avoid leakage.
2024-03-21 16:49:28 +01:00

58 lines
1.4 KiB
Go

//go:build windows
package routemanager
import (
"fmt"
"net"
"net/netip"
log "github.com/sirupsen/logrus"
"github.com/yusufpapurcu/wmi"
)
type Win32_IP4RouteTable struct {
Destination string
Mask string
}
func getRoutesFromTable() ([]netip.Prefix, error) {
var routes []Win32_IP4RouteTable
query := "SELECT Destination, Mask FROM Win32_IP4RouteTable"
err := wmi.Query(query, &routes)
if err != nil {
return nil, fmt.Errorf("get routes: %w", err)
}
var prefixList []netip.Prefix
for _, route := range routes {
addr, err := netip.ParseAddr(route.Destination)
if err != nil {
log.Warnf("Unable to parse route destination %s: %v", route.Destination, err)
continue
}
maskSlice := net.ParseIP(route.Mask).To4()
if maskSlice == nil {
log.Warnf("Unable to parse route mask %s", route.Mask)
continue
}
mask := net.IPv4Mask(maskSlice[0], maskSlice[1], maskSlice[2], maskSlice[3])
cidr, _ := mask.Size()
routePrefix := netip.PrefixFrom(addr, cidr)
if routePrefix.IsValid() && routePrefix.Addr().Is4() {
prefixList = append(prefixList, routePrefix)
}
}
return prefixList, nil
}
func addToRouteTableIfNoExists(prefix netip.Prefix, addr string, intf string) error {
return genericAddToRouteTableIfNoExists(prefix, addr, intf)
}
func removeFromRouteTableIfNonSystem(prefix netip.Prefix, addr string, intf string) error {
return genericRemoveFromRouteTableIfNonSystem(prefix, addr, intf)
}