2024-03-21 16:49:28 +01:00
|
|
|
//go:build !android
|
2023-04-17 11:15:37 +02:00
|
|
|
|
2024-03-21 16:49:28 +01:00
|
|
|
//nolint:unused
|
2022-09-05 09:06:35 +02:00
|
|
|
package routemanager
|
|
|
|
|
|
|
|
import (
|
2024-03-21 16:49:28 +01:00
|
|
|
"errors"
|
2022-09-05 09:06:35 +02:00
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"net/netip"
|
2024-03-21 16:49:28 +01:00
|
|
|
"os/exec"
|
|
|
|
"runtime"
|
2023-04-17 11:15:37 +02:00
|
|
|
|
|
|
|
"github.com/libp2p/go-netroute"
|
|
|
|
log "github.com/sirupsen/logrus"
|
2022-09-05 09:06:35 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
var errRouteNotFound = fmt.Errorf("route not found")
|
|
|
|
|
2024-03-21 16:49:28 +01:00
|
|
|
func genericAddRouteForCurrentDefaultGateway(prefix netip.Prefix) error {
|
|
|
|
defaultGateway, err := getExistingRIBRouteGateway(defaultv4)
|
|
|
|
if err != nil && !errors.Is(err, errRouteNotFound) {
|
|
|
|
return fmt.Errorf("get existing route gateway: %s", err)
|
2022-09-05 09:06:35 +02:00
|
|
|
}
|
2023-06-09 12:35:57 +02:00
|
|
|
|
2023-11-24 11:31:22 +01:00
|
|
|
addr := netip.MustParseAddr(defaultGateway.String())
|
|
|
|
|
|
|
|
if !prefix.Contains(addr) {
|
2024-03-21 16:49:28 +01:00
|
|
|
log.Debugf("Skipping adding a new route for gateway %s because it is not in the network %s", addr, prefix)
|
2023-06-09 12:35:57 +02:00
|
|
|
return nil
|
2022-09-05 09:06:35 +02:00
|
|
|
}
|
|
|
|
|
2023-11-24 11:31:22 +01:00
|
|
|
gatewayPrefix := netip.PrefixFrom(addr, 32)
|
|
|
|
|
|
|
|
ok, err := existsInRouteTable(gatewayPrefix)
|
2023-06-09 12:35:57 +02:00
|
|
|
if err != nil {
|
2023-11-24 11:31:22 +01:00
|
|
|
return fmt.Errorf("unable to check if there is an existing route for gateway %s. error: %s", gatewayPrefix, err)
|
2023-06-09 12:35:57 +02:00
|
|
|
}
|
2023-11-24 11:31:22 +01:00
|
|
|
|
2023-06-09 12:35:57 +02:00
|
|
|
if ok {
|
2024-03-21 16:49:28 +01:00
|
|
|
log.Debugf("Skipping adding a new route for gateway %s because it already exists", gatewayPrefix)
|
2022-09-05 09:06:35 +02:00
|
|
|
return nil
|
|
|
|
}
|
2023-06-09 12:35:57 +02:00
|
|
|
|
2023-11-24 11:31:22 +01:00
|
|
|
gatewayHop, err := getExistingRIBRouteGateway(gatewayPrefix)
|
2024-03-21 16:49:28 +01:00
|
|
|
if err != nil && !errors.Is(err, errRouteNotFound) {
|
2023-11-24 11:31:22 +01:00
|
|
|
return fmt.Errorf("unable to get the next hop for the default gateway address. error: %s", err)
|
|
|
|
}
|
2024-03-21 16:49:28 +01:00
|
|
|
log.Debugf("Adding a new route for gateway %s with next hop %s", gatewayPrefix, gatewayHop)
|
|
|
|
return genericAddToRouteTable(gatewayPrefix, gatewayHop.String(), "")
|
2022-09-05 09:06:35 +02:00
|
|
|
}
|
|
|
|
|
2024-03-21 16:49:28 +01:00
|
|
|
func genericAddToRouteTableIfNoExists(prefix netip.Prefix, addr string, intf string) error {
|
|
|
|
ok, err := existsInRouteTable(prefix)
|
2022-09-05 09:06:35 +02:00
|
|
|
if err != nil {
|
2024-03-21 16:49:28 +01:00
|
|
|
return fmt.Errorf("exists in route table: %w", err)
|
2022-09-05 09:06:35 +02:00
|
|
|
}
|
2024-03-21 16:49:28 +01:00
|
|
|
if ok {
|
|
|
|
log.Warnf("Skipping adding a new route for network %s because it already exists", prefix)
|
|
|
|
return nil
|
2023-11-24 11:31:22 +01:00
|
|
|
}
|
|
|
|
|
2024-03-21 16:49:28 +01:00
|
|
|
ok, err = isSubRange(prefix)
|
2023-11-24 11:31:22 +01:00
|
|
|
if err != nil {
|
2024-03-21 16:49:28 +01:00
|
|
|
return fmt.Errorf("sub range: %w", err)
|
2022-09-05 09:06:35 +02:00
|
|
|
}
|
2024-03-21 16:49:28 +01:00
|
|
|
|
|
|
|
if ok {
|
|
|
|
err := genericAddRouteForCurrentDefaultGateway(prefix)
|
|
|
|
if err != nil {
|
|
|
|
log.Warnf("Unable to add route for current default gateway route. Will proceed without it. error: %s", err)
|
2023-11-24 11:31:22 +01:00
|
|
|
}
|
|
|
|
}
|
2024-03-21 16:49:28 +01:00
|
|
|
|
|
|
|
return genericAddToRouteTable(prefix, addr, intf)
|
|
|
|
}
|
|
|
|
|
|
|
|
func genericRemoveFromRouteTableIfNonSystem(prefix netip.Prefix, addr string, intf string) error {
|
|
|
|
return genericRemoveFromRouteTable(prefix, addr, intf)
|
|
|
|
}
|
|
|
|
|
|
|
|
func genericAddToRouteTable(prefix netip.Prefix, addr, _ string) error {
|
|
|
|
cmd := exec.Command("route", "add", prefix.String(), addr)
|
|
|
|
out, err := cmd.Output()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("add route: %w", err)
|
|
|
|
}
|
|
|
|
log.Debugf(string(out))
|
|
|
|
return nil
|
2023-11-24 11:31:22 +01:00
|
|
|
}
|
|
|
|
|
2024-03-21 16:49:28 +01:00
|
|
|
func genericRemoveFromRouteTable(prefix netip.Prefix, addr, _ string) error {
|
|
|
|
args := []string{"delete", prefix.String()}
|
|
|
|
if runtime.GOOS == "darwin" {
|
|
|
|
args = append(args, addr)
|
|
|
|
}
|
|
|
|
cmd := exec.Command("route", args...)
|
|
|
|
out, err := cmd.Output()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("remove route: %w", err)
|
|
|
|
}
|
|
|
|
log.Debugf(string(out))
|
|
|
|
return nil
|
2022-09-05 09:06:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func getExistingRIBRouteGateway(prefix netip.Prefix) (net.IP, error) {
|
|
|
|
r, err := netroute.New()
|
|
|
|
if err != nil {
|
2024-03-21 16:49:28 +01:00
|
|
|
return nil, fmt.Errorf("new netroute: %w", err)
|
2022-09-05 09:06:35 +02:00
|
|
|
}
|
2023-06-09 18:48:21 +02:00
|
|
|
_, gateway, preferredSrc, err := r.Route(prefix.Addr().AsSlice())
|
2022-09-05 09:06:35 +02:00
|
|
|
if err != nil {
|
2024-03-21 16:49:28 +01:00
|
|
|
log.Errorf("Getting routes returned an error: %v", err)
|
2022-09-05 09:06:35 +02:00
|
|
|
return nil, errRouteNotFound
|
|
|
|
}
|
|
|
|
|
2023-06-09 18:48:21 +02:00
|
|
|
if gateway == nil {
|
|
|
|
return preferredSrc, nil
|
|
|
|
}
|
|
|
|
|
2022-10-31 11:54:34 +01:00
|
|
|
return gateway, nil
|
2022-09-05 09:06:35 +02:00
|
|
|
}
|
2024-03-21 16:49:28 +01:00
|
|
|
|
|
|
|
func existsInRouteTable(prefix netip.Prefix) (bool, error) {
|
|
|
|
routes, err := getRoutesFromTable()
|
|
|
|
if err != nil {
|
|
|
|
return false, fmt.Errorf("get routes from table: %w", err)
|
|
|
|
}
|
|
|
|
for _, tableRoute := range routes {
|
|
|
|
if tableRoute == prefix {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func isSubRange(prefix netip.Prefix) (bool, error) {
|
|
|
|
routes, err := getRoutesFromTable()
|
|
|
|
if err != nil {
|
|
|
|
return false, fmt.Errorf("get routes from table: %w", err)
|
|
|
|
}
|
|
|
|
for _, tableRoute := range routes {
|
|
|
|
if isPrefixSupported(tableRoute) && tableRoute.Contains(prefix.Addr()) && tableRoute.Bits() < prefix.Bits() {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false, nil
|
|
|
|
}
|