From c282f5e1f4d375a318451db2693cd47ab6d8f61a Mon Sep 17 00:00:00 2001 From: clerie Date: Fri, 15 Jul 2022 01:16:51 +0200 Subject: [PATCH] Prepare source routing --- hosts/router/10-net-services.nix | 2 + hosts/router/101-net-uplink-a.nix | 2 +- hosts/router/102-net-uplink-b.nix | 2 +- hosts/router/151-net-technik-iot.nix | 2 + hosts/router/201-net-ikt.nix | 2 + hosts/router/202-net-technik.nix | 2 + hosts/router/203-net-hospital.nix | 2 + hosts/router/204-net-zoll.nix | 2 + hosts/router/205-net-leitstelle.nix | 2 + hosts/router/206-net-verwaltung.nix | 2 + hosts/router/208-net-yolo.nix | 2 + hosts/router/209-net-infojurte.nix | 2 + hosts/router/210-net-internation.nix | 2 + hosts/router/211-net-programmtre.nix | 2 + hosts/router/212-net-open-office.nix | 2 + hosts/router/configuration.nix | 2 + hosts/router/ppp.nix | 69 ++++++++++++++++ hosts/router/uplink-selector.nix | 9 +++ modules/default.nix | 1 + modules/uplink-selector/default.nix | 114 +++++++++++++++++++++++++++ 20 files changed, 223 insertions(+), 2 deletions(-) create mode 100644 hosts/router/ppp.nix create mode 100644 hosts/router/uplink-selector.nix create mode 100644 modules/uplink-selector/default.nix diff --git a/hosts/router/10-net-services.nix b/hosts/router/10-net-services.nix index 9a7162c..89ecf5d 100644 --- a/hosts/router/10-net-services.nix +++ b/hosts/router/10-net-services.nix @@ -14,4 +14,6 @@ ]; # Everyone is allowed reaching this, no firewall therefore + + clerie.uplink-selector.interfaces.net-services.uplink = "uplink-a"; } diff --git a/hosts/router/101-net-uplink-a.nix b/hosts/router/101-net-uplink-a.nix index 554258f..3db16c0 100644 --- a/hosts/router/101-net-uplink-a.nix +++ b/hosts/router/101-net-uplink-a.nix @@ -25,7 +25,7 @@ lcp-echo-failure 3 mtu 1492 hide-password - defaultroute + nodefaultroute +ipv6 debug ''; diff --git a/hosts/router/102-net-uplink-b.nix b/hosts/router/102-net-uplink-b.nix index edfbd27..7fd4a93 100644 --- a/hosts/router/102-net-uplink-b.nix +++ b/hosts/router/102-net-uplink-b.nix @@ -25,7 +25,7 @@ lcp-echo-failure 3 mtu 1492 hide-password - defaultroute + nodefaultroute +ipv6 debug ''; diff --git a/hosts/router/151-net-technik-iot.nix b/hosts/router/151-net-technik-iot.nix index 230b5d3..366650d 100644 --- a/hosts/router/151-net-technik-iot.nix +++ b/hosts/router/151-net-technik-iot.nix @@ -40,4 +40,6 @@ # Give technik access to their toys { incomingInterface = "net-technik"; } ]; + + clerie.uplink-selector.interfaces.net-technik-iot.uplink = "uplink-b"; } diff --git a/hosts/router/201-net-ikt.nix b/hosts/router/201-net-ikt.nix index aa14d62..e0498ff 100644 --- a/hosts/router/201-net-ikt.nix +++ b/hosts/router/201-net-ikt.nix @@ -52,4 +52,6 @@ # Allow infrastructure devices to access ikt user devices for downloading software etc { incomingInterface = "net-management"; } ]; + + clerie.uplink-selector.interfaces.net-ikt.uplink = "uplink-b"; } diff --git a/hosts/router/202-net-technik.nix b/hosts/router/202-net-technik.nix index d3d8dca..9d101f7 100644 --- a/hosts/router/202-net-technik.nix +++ b/hosts/router/202-net-technik.nix @@ -53,4 +53,6 @@ # Give the toys access to technik { incomingInterface = "net-technik-iot"; } ]; + + clerie.uplink-selector.interfaces.net-technik.uplink = "uplink-b"; } diff --git a/hosts/router/203-net-hospital.nix b/hosts/router/203-net-hospital.nix index a56789c..3d1b987 100644 --- a/hosts/router/203-net-hospital.nix +++ b/hosts/router/203-net-hospital.nix @@ -51,4 +51,6 @@ clerie.forward-filter.interfaces.net-hospital.rules = [ { incomingInterface = "net-ikt"; } ]; + + clerie.uplink-selector.interfaces.net-hospital.uplink = "uplink-a"; } diff --git a/hosts/router/204-net-zoll.nix b/hosts/router/204-net-zoll.nix index 37c051e..74730d4 100644 --- a/hosts/router/204-net-zoll.nix +++ b/hosts/router/204-net-zoll.nix @@ -51,4 +51,6 @@ clerie.forward-filter.interfaces.net-zoll.rules = [ { incomingInterface = "net-ikt"; } ]; + + clerie.uplink-selector.interfaces.net-zoll.uplink = "uplink-a"; } diff --git a/hosts/router/205-net-leitstelle.nix b/hosts/router/205-net-leitstelle.nix index 9c1bce3..6a6fc51 100644 --- a/hosts/router/205-net-leitstelle.nix +++ b/hosts/router/205-net-leitstelle.nix @@ -51,4 +51,6 @@ clerie.forward-filter.interfaces.net-leitstelle.rules = [ { incomingInterface = "net-ikt"; } ]; + + clerie.uplink-selector.interfaces.net-leitstelle.uplink = "uplink-a"; } diff --git a/hosts/router/206-net-verwaltung.nix b/hosts/router/206-net-verwaltung.nix index 8f640de..f28292c 100644 --- a/hosts/router/206-net-verwaltung.nix +++ b/hosts/router/206-net-verwaltung.nix @@ -51,4 +51,6 @@ clerie.forward-filter.interfaces.net-verwaltung.rules = [ { incomingInterface = "net-ikt"; } ]; + + clerie.uplink-selector.interfaces.net-verwaltung.uplink = "uplink-a"; } diff --git a/hosts/router/208-net-yolo.nix b/hosts/router/208-net-yolo.nix index 56b3661..cabf866 100644 --- a/hosts/router/208-net-yolo.nix +++ b/hosts/router/208-net-yolo.nix @@ -51,4 +51,6 @@ clerie.forward-filter.interfaces.net-yolo.rules = [ { incomingInterface = "net-ikt"; } ]; + + clerie.uplink-selector.interfaces.net-yolo.uplink = "uplink-b"; } diff --git a/hosts/router/209-net-infojurte.nix b/hosts/router/209-net-infojurte.nix index cd68910..c9741eb 100644 --- a/hosts/router/209-net-infojurte.nix +++ b/hosts/router/209-net-infojurte.nix @@ -51,4 +51,6 @@ clerie.forward-filter.interfaces.net-infojurte.rules = [ { incomingInterface = "net-ikt"; } ]; + + clerie.uplink-selector.interfaces.net-infojurte.uplink = "uplink-b"; } diff --git a/hosts/router/210-net-internation.nix b/hosts/router/210-net-internation.nix index dcc15a3..13ead9c 100644 --- a/hosts/router/210-net-internation.nix +++ b/hosts/router/210-net-internation.nix @@ -51,4 +51,6 @@ clerie.forward-filter.interfaces.net-internation.rules = [ { incomingInterface = "net-ikt"; } ]; + + clerie.uplink-selector.interfaces.net-internation.uplink = "uplink-b"; } diff --git a/hosts/router/211-net-programmtre.nix b/hosts/router/211-net-programmtre.nix index 2bd044c..7301879 100644 --- a/hosts/router/211-net-programmtre.nix +++ b/hosts/router/211-net-programmtre.nix @@ -51,4 +51,6 @@ clerie.forward-filter.interfaces.net-programmtre.rules = [ { incomingInterface = "net-ikt"; } ]; + + clerie.uplink-selector.interfaces.net-programmtre.uplink = "uplink-b"; } diff --git a/hosts/router/212-net-open-office.nix b/hosts/router/212-net-open-office.nix index a88bd99..5090fa2 100644 --- a/hosts/router/212-net-open-office.nix +++ b/hosts/router/212-net-open-office.nix @@ -51,4 +51,6 @@ clerie.forward-filter.interfaces.net-open-office.rules = [ { incomingInterface = "net-ikt"; } ]; + + clerie.uplink-selector.interfaces.net-open-office.uplink = "uplink-b"; } diff --git a/hosts/router/configuration.nix b/hosts/router/configuration.nix index c70f2c7..26c872d 100644 --- a/hosts/router/configuration.nix +++ b/hosts/router/configuration.nix @@ -6,6 +6,8 @@ ./hardware-configuration.nix ./nat.nix + ./ppp.nix + ./uplink-selector.nix ./10-net-services.nix ./42-net-management.nix diff --git a/hosts/router/ppp.nix b/hosts/router/ppp.nix new file mode 100644 index 0000000..f5da32f --- /dev/null +++ b/hosts/router/ppp.nix @@ -0,0 +1,69 @@ +{ config, pkgs, ... }: + +{ + # Setting default routes based on interfaces in different tables + environment.etc."ppp/ip-up" = { + text = '' + #! ${pkgs.runtimeShell} -e + + case $IFNAME in + ppp-uplink-a) + ip route flush table 20001 || true + ip route add default dev ppp-uplink-a table 20001 + ;; + ppp-uplink-b) + ip route flush table 20002 || true + ip route add default dev ppp-uplink-b table 20002 + ;; + esac + ''; + mode = "555"; + }; + environment.etc."ppp/ip-down" = { + text = '' + #! ${pkgs.runtimeShell} -e + + case $IFNAME in + ppp-uplink-a) + ip route flush table 20001 || true + ;; + ppp-uplink-b) + ip route flush table 20002 || true + ;; + esac + ''; + mode = "555"; + }; + environment.etc."ppp/ipv6-up" = { + text = '' + #! ${pkgs.runtimeShell} -e + + case $IFNAME in + ppp-uplink-a) + ip -6 route flush table 20001 || true + ip -6 route add default dev ppp-uplink-a table 20001 + ;; + ppp-uplink-b) + ip -6 route flush table 20002 || true + ip -6 route add default dev ppp-uplink-b table 20002 + ;; + esac + ''; + mode = "555"; + }; + environment.etc."ppp/ipv6-down" = { + text = '' + #! ${pkgs.runtimeShell} -e + + case $IFNAME in + ppp-uplink-a) + ip -6 route flush table 20001 || true + ;; + ppp-uplink-b) + ip -6 route flush table 20002 || true + ;; + esac + ''; + mode = "555"; + }; +} diff --git a/hosts/router/uplink-selector.nix b/hosts/router/uplink-selector.nix new file mode 100644 index 0000000..4aa0096 --- /dev/null +++ b/hosts/router/uplink-selector.nix @@ -0,0 +1,9 @@ +{ config, pkgs, ... }: + +{ + clerie.uplink-selector.enable = true; + clerie.uplink-selector.uplinks = { + uplink-a.table = "20001"; + uplink-b.table = "20002"; + }; +} diff --git a/modules/default.nix b/modules/default.nix index 231b916..4335222 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -4,6 +4,7 @@ imports = [ ./yate ./forward-filter + ./uplink-selector ./fieldpoc ]; } diff --git a/modules/uplink-selector/default.nix b/modules/uplink-selector/default.nix new file mode 100644 index 0000000..f917921 --- /dev/null +++ b/modules/uplink-selector/default.nix @@ -0,0 +1,114 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.clerie.uplink-selector; + + startScript = pkgs.writeScriptBin "uplink-selector-start" '' + #! ${pkgs.runtimeShell} -e + + ip46() { + ip "$@" + ip -6 "$@" + } + + ip46 rule flush || true + + # Route everything except default route first + ip46 rule add lookup main suppress_prefixlength 0 prio 10000 + + # Decide which uplink to use + ${concatStrings (mapAttrsToList (iface: ifacecfg: '' + ip46 rule add iif ${iface} lookup ${cfg.uplinks.${ifacecfg.uplink}.table} prio 20000 + '') cfg.interfaces)} + + # Fallback to the main default table + ip46 rule add lookup main prio 32000 + ''; + + stopScript = pkgs.writeScriptBin "uplink-selector-stop" '' + #! ${pkgs.runtimeShell} -e + + ip rule flush || true + ip -6 rule flush || true + ''; + +in + +{ + + options = { + + clerie.uplink-selector = { + enable = mkOption { + type = types.bool; + default = false; + description = + '' + Select a default gateway for each interface manually + ''; + }; + + uplinks = mkOption { + default = { }; + type = with types; attrsOf (submodule { + options = { + table = mkOption { + type = types.str; + example = "5001"; + description = "Route table containing the gateway route of this uplink"; + }; + }; + }); + description = + '' + Uplink interface name + ''; + }; + + interfaces = mkOption { + default = { }; + type = with types; attrsOf (submodule { + options = { + uplink = mkOption { + type = types.nullOr types.str; + example = "uplink-a"; + description = "Name of the uplink that should used as a default gateway by this interface"; + }; + }; + }); + description = + '' + Interface + ''; + }; + }; + + }; + + config = mkIf cfg.enable { + + environment.systemPackages = [ pkgs.iproute2 ]; + + systemd.services.uplink-selector = { + description = "Uplink Selector"; + before = [ "network.target" ]; + wantedBy = [ "network.target" ]; + after = [ "network-pre.target" ]; + + path = [ pkgs.iproute2 ]; + + unitConfig.ConditionCapability = "CAP_NET_ADMIN"; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "@${startScript}/bin/uplink-selector-start uplink-selector-start"; + ExecStop = "@${stopScript}/bin/uplink-selector-stop uplink-selector-stop"; + }; + }; + }; + +}