From 0dd2d5d442965cb079cd325aa9e905b7bb05504e Mon Sep 17 00:00:00 2001 From: Luke Granger-Brown Date: Thu, 19 Aug 2021 00:23:09 +0000 Subject: [PATCH] ops/nixos/bgp: more filtering shenanigans --- ops/nixos/lib/bgp.nix | 81 +++++++++++++++++++++++++++++++++- ops/nixos/lib/blade-router.nix | 22 +++++++++ 2 files changed, 101 insertions(+), 2 deletions(-) diff --git a/ops/nixos/lib/bgp.nix b/ops/nixos/lib/bgp.nix index 285e9317c3..803ba51c99 100644 --- a/ops/nixos/lib/bgp.nix +++ b/ops/nixos/lib/bgp.nix @@ -8,23 +8,40 @@ let generateSnippetForIX = { ixName, ix, ... }@args: '' ipv4 table ${ixName}4; ipv6 table ${ixName}6; + filter bgp_in_${ixName}4 + prefix set allnet; + int set allas; + { + if ! (avoid_martians4()) then reject; + ${if ix.remote.must_be_next_hop then "if (bgp_path.first != ${toString ix.remote.asn}) then reject;" else "# no next-hop requirement"} + accept; + } + filter bgp_in_${ixName}6 + prefix set allnet; + int set allas; + { + if ! (avoid_martians6()) then reject; + ${if ix.remote.must_be_next_hop then "if (bgp_path.first != ${toString ix.remote.asn}) then reject;" else "# no next-hop requirement"} + accept; + } protocol pipe ${ixName}pipe_4 { table ${ixName}4; peer table master4; import where ((ro, ${toString ix.local.asn}, ${toString ix.remote.export_community}) ~ bgp_ext_community); - export all; + export filter bgp_in_${ixName}4; }; protocol pipe ${ixName}pipe_6 { table ${ixName}6; peer table master6; import where ((ro, ${toString ix.local.asn}, ${toString ix.remote.export_community}) ~ bgp_ext_community); - export all; + export filter bgp_in_${ixName}6; }; '' + lib.concatImapStringsSep "\n" ( i: v: generateSnippetForRouter (args // { routerNum = i; router = v; }) ) ix.remote.routers; enabledSnippet = { enabled ? true, ... }: "disabled ${if enabled then "off" else "on"};"; passwordSnippet = { password ? null, ... }: if password == null then "# no password" else "password \"${password}\";"; multihopSnippet = { multihop ? null, ... }: if multihop == null then "# not multihop" else "multihop ${toString multihop};"; passiveSnippet = { passive, ... }: "passive ${if passive then "on" else "off"};"; + prefixLimitSnippet = limit: if limit == null then "# no import limit" else "import limit ${toString limit} action restart;"; generateSnippetForRouter = { ixName, ix, routerNum, router, ... }: '' protocol bgp ${ixName}${toString routerNum}_4 { ${enabledSnippet router} @@ -39,6 +56,7 @@ let table ${ixName}4; import all; export where ((ro, ${toString ix.local.asn}, 1000) ~ bgp_ext_community); + ${prefixLimitSnippet ix.remote.prefix_limit.v4} }; }; protocol bgp ${ixName}${toString routerNum}_6 { @@ -54,6 +72,7 @@ let table ${ixName}6; import all; export where ((ro, ${toString ix.local.asn}, 1000) ~ bgp_ext_community); + ${prefixLimitSnippet ix.remote.prefix_limit.v6} }; }; ''; @@ -108,6 +127,18 @@ in { export_community = mkOption { # lukegbgp.config.peering..remote.export_community type = int; }; + prefix_limit.v4 = mkOption { # lukegbgp.config.peering..remote.prefix_limit.v4 + type = nullOr int; + default = null; + }; + prefix_limit.v6 = mkOption { # lukegbgp.config.peering..remote.prefix_limit.v6 + type = nullOr int; + default = null; + }; + must_be_next_hop = mkOption { # lukegbgp.config.peering..remote.must_be_next_hop + type = bool; + default = true; + }; routers = mkOption { # lukegbgp.config.peering..remote.routers type = listOf (submodule { options = { @@ -164,6 +195,52 @@ in { config = '' router id ${config.services.lukegbgp.config.local.routerID}; + function avoid_martians4() + prefix set martians; + { + martians = [ + 169.254.0.0/16+, + 172.16.0.0/12+, + 192.168.0.0/16+, + 192.0.0.0/24+, + 192.0.2.0/24+, + 192.88.99.0/24+, + 198.18.0.0/15+, + 198.51.100.0/24+, + 203.0.113.0/24+, + 10.0.0.0/8+, + 100.64.0.0/10+, + 224.0.0.0/4+, + 240.0.0.0/4+, + 0.0.0.0/32-, + 0.0.0.0/0{25,32}, + 0.0.0.0/0{0,7} ]; + + if net ~ martians then return false; + return true; + } + + function avoid_martians6() + prefix set martians; + { + martians = [ + ::/128-, + ::1/128-, + ::ffff:0:0/96+, + ::ffff:0:0:0/96+, + 64:ff9b::/96+, + 100::/64+, + ::/0{64,128}, + ::/0{0,15}, + 2001:db8::/32+, + fc00::/7+, + fe80::/10+, + ff00::/8+ ]; + + if net ~ martians then return false; + return true; + } + ${generateSnippet config.services.lukegbgp.config.peering {}} protocol kernel { diff --git a/ops/nixos/lib/blade-router.nix b/ops/nixos/lib/blade-router.nix index 89a8c69bbe..50b3eaa3d4 100644 --- a/ops/nixos/lib/blade-router.nix +++ b/ops/nixos/lib/blade-router.nix @@ -153,6 +153,8 @@ in v4 = "195.66.224.254"; v6 = "2001:7f8:4::1553:1"; }]; + prefix_limit.v4 = 0; + prefix_limit.v6 = 0; }; }; peering.linx = linx // { @@ -168,6 +170,7 @@ in v4 = "195.66.225.231"; v6 = "2001:7f8:4::220a:2"; }]; + must_be_next_hop = false; }; }; peering.facebook = linx // { @@ -192,6 +195,8 @@ in v4 = "195.66.226.140"; v6 = "2001:7f8:4::80a6:3"; }]; + prefix_limit.v4 = 100; + prefix_limit.v6 = 100; }; }; peering.openpeering = linx // { @@ -204,6 +209,8 @@ in v4 = "195.66.225.53"; v6 = "2001:7f8:4::5052:1"; }]; + prefix_limit.v4 = 16000; + prefix_limit.v6 = 3000; }; }; peering.freetransitnet = linx // { @@ -216,6 +223,21 @@ in v4 = "195.66.225.105"; v6 = "2001:7f8:4::3:3f9f:2"; }]; + prefix_limit.v4 = 60; + prefix_limit.v6 = 700; + }; + }; + peering.he = linx // { + remote = { + asn = 6939; + export_community = 5005; + routers = [{ + enabled = cfg.linx.enable; + v4 = "195.66.224.21"; + v6 = "2001:7f8:4::1b1b:1"; + }]; + prefix_limit.v4 = 176000; + prefix_limit.v6 = 156000; }; }; export.v4 = [ "92.118.28.0/24" ];