lol

nixos/ifstate: init

Marcel 8d8c9633 a956dc12

+755
+2
nixos/doc/manual/release-notes/rl-2511.section.md
··· 60 60 61 61 - [Newt](https://github.com/fosrl/newt), a fully user space WireGuard tunnel client and TCP/UDP proxy, designed to securely expose private resources controlled by Pangolin. Available as [services.newt](options.html#opt-services.newt.enable). 62 62 63 + - [IfState](https://ifstate.net), manage host interface settings in a declarative manner. Available as [networking.ifstate](options.html#opt-networking.ifstate.enable) and [boot.initrd.network.ifstate](options.html#opt-boot.initrd.network.ifstate.enable). 64 + 63 65 - [qBittorrent](https://www.qbittorrent.org/), is a bittorrent client programmed in C++ / Qt that uses libtorrent by Arvid Norberg. Available as [services.qbittorrent](#opt-services.qbittorrent.enable). 64 66 65 67 - [Speedify](https://speedify.com/), a proprietary VPN which allows combining multiple internet connections (Wi-Fi, 4G, 5G, Ethernet, Starlink, Satellite, and more) to improve the stability, speed, and security of online experiences. Available as [services.speedify](#opt-services.speedify.enable).
+1
nixos/modules/module-list.nix
··· 1180 1180 ./services/networking/i2pd.nix 1181 1181 ./services/networking/icecream/daemon.nix 1182 1182 ./services/networking/icecream/scheduler.nix 1183 + ./services/networking/ifstate.nix 1183 1184 ./services/networking/imaginary.nix 1184 1185 ./services/networking/inadyn.nix 1185 1186 ./services/networking/inspircd.nix
+311
nixos/modules/services/networking/ifstate.nix
··· 1 + { 2 + lib, 3 + config, 4 + pkgs, 5 + ... 6 + }: 7 + 8 + let 9 + cfg = config.networking.ifstate; 10 + initrdCfg = config.boot.initrd.network.ifstate; 11 + settingsFormat = { 12 + # override generator in order to: 13 + # - use yq and not remarshal because it matches yaml datatype handling with IfState 14 + # - validate json schema 15 + generate = 16 + name: value: package: 17 + pkgs.runCommand name 18 + { 19 + nativeBuildInputs = with pkgs; [ 20 + yq 21 + check-jsonschema 22 + ]; 23 + value = builtins.toJSON value; 24 + passAsFile = [ "value" ]; 25 + } 26 + '' 27 + yq --yaml-output . $valuePath > $out 28 + check-jsonschema --schemafile "${cfg.package.passthru.jsonschema}" "$out" 29 + sed -i $'s|\'!include |!include \'|' $out 30 + ''; 31 + 32 + inherit (pkgs.formats.yaml { }) type; 33 + }; 34 + initrdInterfaceTypes = builtins.map (interface: interface.link.kind) ( 35 + builtins.attrValues initrdCfg.settings.interfaces 36 + ); 37 + # IfState interface kind to kernel modules mapping 38 + interfaceKernelModules = { 39 + "ifb" = [ "ifb" ]; 40 + "ip6tnl" = [ "ip6tnl" ]; 41 + "ipoib" = [ "ib_ipoib" ]; 42 + "ipvlan" = [ "ipvlan" ]; 43 + "macvlan" = [ "macvlan" ]; 44 + "macvtap" = [ "macvtap" ]; 45 + "team" = [ "team" ]; 46 + "tun" = [ "tun" ]; 47 + "vrf" = [ "vrf" ]; 48 + "vti" = [ "ip_vti" ]; 49 + "vti6" = [ "ip6_vti" ]; 50 + "bond" = [ "bonding" ]; 51 + "bridge" = [ "bridge" ]; 52 + # "physical" = ...; 53 + "dsa" = [ "dsa_core" ]; 54 + "dummy" = [ "dummy" ]; 55 + "veth" = [ "veth" ]; 56 + "vxcan" = [ "vxcan" ]; 57 + "vlan" = [ "8021q" ]; 58 + "vxlan" = [ "vxlan" ]; 59 + "ipip" = [ "ipip" ]; 60 + "sit" = [ "sit" ]; 61 + "gre" = [ "ip_gre" ]; 62 + "gretap" = [ "ip_gre" ]; 63 + "ip6gre" = [ "ip6_gre" ]; 64 + "ip6gretap" = [ "ip6_gre" ]; 65 + "geneve" = [ "geneve" ]; 66 + "wireguard" = [ "wireguard" ]; 67 + "xfrm" = [ "xfrm_interface" ]; 68 + }; 69 + in 70 + { 71 + meta.maintainers = with lib.maintainers; [ marcel ]; 72 + 73 + options = { 74 + networking.ifstate = { 75 + enable = lib.mkEnableOption "networking using IfState"; 76 + 77 + package = lib.mkPackageOption pkgs "ifstate" { }; 78 + 79 + settings = lib.mkOption { 80 + inherit (settingsFormat) type; 81 + default = { }; 82 + description = "Content of IfState's configuration file. See <https://ifstate.net/2.0/schema/> for details."; 83 + }; 84 + }; 85 + 86 + boot.initrd.network.ifstate = { 87 + enable = lib.mkEnableOption "initrd networking using IfState"; 88 + 89 + allowIfstateToDrasticlyIncreaseInitrdSize = lib.mkOption { 90 + type = lib.types.bool; 91 + default = false; 92 + description = "IfState in initrd drastically increases the size of initrd, your boot partition may be too small and/or you may have significantly fewer generations. By setting this option, you acknowledge this fact and keep it in mind when reporting issues."; 93 + }; 94 + 95 + package = lib.mkOption { 96 + type = lib.types.package; 97 + default = cfg.package.override { 98 + withConfigValidation = false; 99 + withWireguard = false; 100 + }; 101 + defaultText = lib.literalExpression "pkgs.ifstate.override { withConfigValidation = false; withWireguard = false; }"; 102 + description = "The initrd IfState package to use."; 103 + }; 104 + 105 + settings = lib.mkOption { 106 + inherit (settingsFormat) type; 107 + default = { }; 108 + description = "Content of IfState's initrd configuration file. See <https://ifstate.net/2.0/schema/> for details."; 109 + }; 110 + 111 + cleanupSettings = lib.mkOption { 112 + inherit (settingsFormat) type; 113 + default = { 114 + # required by json schema 115 + interfaces = { }; 116 + # https://codeberg.org/liske/ifstate/issues/118 117 + namespaces = { }; 118 + }; 119 + description = "Content of IfState's initrd cleanup configuration file. See <https://ifstate.net/2.0/schema/> for details. This configuration gets applied before systemd switches to stage two. The goas is to deconfigurate the whole network in order to prevent access to services, before the firewall is configured. The stage two IfState configuration will start after the firewall is configured."; 120 + }; 121 + }; 122 + }; 123 + 124 + config = lib.mkMerge [ 125 + (lib.mkIf cfg.enable { 126 + assertions = [ 127 + { 128 + assertion = !config.networking.networkmanager.enable; 129 + message = "IfState and NetworkManager cannot be used at the same time, as both configure the network in a conflicting manner."; 130 + } 131 + { 132 + assertion = !config.networking.useDHCP; 133 + message = "IfState and networking.useDHCP cannot be used at the same time, as both configure the network. Please look into IfState hooks to integrate DHCP: https://codeberg.org/liske/ifstate/issues/111"; 134 + } 135 + ]; 136 + 137 + networking.useDHCP = lib.mkDefault false; 138 + 139 + # sane defaults to not let IfState work against the kernel 140 + boot.extraModprobeConfig = '' 141 + options bonding max_bonds=0 142 + options dummy numdummies=0 143 + options ifb numifbs=0 144 + ''; 145 + 146 + environment = { 147 + # ifstatecli command should be available to use user, there are other useful subcommands like check or show 148 + systemPackages = [ cfg.package ]; 149 + # match the default value of the --config flag of IfState 150 + etc."ifstate/ifstate.yaml".source = settingsFormat.generate "ifstate.yaml" cfg.settings cfg.package; 151 + }; 152 + 153 + systemd.services.ifstate = { 154 + description = "IfState"; 155 + 156 + wantedBy = [ 157 + "multi-user.target" 158 + ]; 159 + after = [ 160 + "systemd-udevd.service" 161 + "network-pre.target" 162 + "systemd-sysusers.service" 163 + "systemd-sysctl.service" 164 + ]; 165 + before = [ 166 + "network.target" 167 + "multi-user.target" 168 + "shutdown.target" 169 + "initrd-switch-root.target" 170 + ]; 171 + conflicts = [ 172 + "shutdown.target" 173 + "initrd-switch-root.target" 174 + ]; 175 + wants = [ 176 + "network.target" 177 + ]; 178 + 179 + # mount is always available on nixos, avoid adding additional store paths to the closure 180 + path = [ "/run/wrappers" ]; 181 + 182 + serviceConfig = { 183 + Type = "oneshot"; 184 + ExecStart = "${lib.getExe cfg.package} --config ${ 185 + config.environment.etc."ifstate/ifstate.yaml".source 186 + } apply"; 187 + # because oneshot services do not have a timeout by default 188 + TimeoutStartSec = "2min"; 189 + }; 190 + }; 191 + }) 192 + (lib.mkIf initrdCfg.enable { 193 + assertions = [ 194 + { 195 + assertion = 196 + initrdCfg.package.passthru.features.withWireguard 197 + || !(builtins.any (kind: kind == "wireguard") initrdInterfaceTypes); 198 + message = "IfState initrd package is configured without the `wireguard` feature, but wireguard interfaces are configured. Please see the `boot.initrd.network.ifstate.package` option."; 199 + } 200 + { 201 + assertion = initrdCfg.allowIfstateToDrasticlyIncreaseInitrdSize; 202 + message = "IfState in initrd drastically increases the size of initrd, your boot partition may be too small and/or you may have significantly fewer generations. By setting boot.initrd.network.initrd.allowIfstateToDrasticlyIncreaseInitrdSize to true, you acknowledge this fact and keep it in mind when reporting issues."; 203 + } 204 + { 205 + assertion = cfg.enable; 206 + message = "If IfState is used in initrd, it should also be used for the stage 2 system (networking.ifstate), as initrd IfState does not clean up the network stack like it was before after execution."; 207 + } 208 + { 209 + assertion = config.boot.initrd.systemd.enable; 210 + message = "IfState only supports systemd stage one. See `boot.initrd.systemd.enable` option."; 211 + } 212 + ]; 213 + 214 + environment.etc = { 215 + "ifstate/ifstate.initrd.yaml".source = 216 + settingsFormat.generate "ifstate.initrd.yaml" initrdCfg.settings 217 + initrdCfg.package; 218 + "ifstate/ifstate.initrd-cleanup.yaml".source = 219 + settingsFormat.generate "ifstate.initrd-cleanup.yaml" initrdCfg.cleanupSettings 220 + initrdCfg.package; 221 + }; 222 + 223 + boot.initrd = { 224 + network.udhcpc.enable = lib.mkDefault false; 225 + 226 + # automatic configuration of kernel modules of virtual interface types 227 + availableKernelModules = 228 + let 229 + enableModule = 230 + type: 231 + if builtins.hasAttr type interfaceKernelModules then interfaceKernelModules."${type}" else [ ]; 232 + in 233 + lib.flatten (builtins.map enableModule initrdInterfaceTypes); 234 + 235 + systemd = { 236 + storePaths = [ 237 + (pkgs.runCommand "ifstate-closure" 238 + { 239 + info = pkgs.closureInfo { 240 + rootPaths = [ 241 + initrdCfg.package 242 + # copy whole config closure, because it can reference other files using !include 243 + config.environment.etc."ifstate/ifstate.initrd.yaml".source 244 + config.environment.etc."ifstate/ifstate.initrd-cleanup.yaml".source 245 + ]; 246 + }; 247 + } 248 + '' 249 + mkdir $out 250 + cat "$info"/store-paths | while read path; do 251 + ln -s "$path" "$out/$(basename "$path")" 252 + done 253 + '' 254 + ) 255 + ]; 256 + 257 + services.ifstate-initrd = { 258 + description = "IfState initrd"; 259 + 260 + wantedBy = [ 261 + "initrd.target" 262 + ]; 263 + after = [ 264 + "systemd-udevd.service" 265 + "network-pre.target" 266 + "systemd-sysusers.service" 267 + "systemd-sysctl.service" 268 + ]; 269 + before = [ 270 + "network.target" 271 + "multi-user.target" 272 + "shutdown.target" 273 + "initrd-switch-root.target" 274 + ]; 275 + conflicts = [ 276 + "shutdown.target" 277 + "initrd-switch-root.target" 278 + ]; 279 + wants = [ 280 + "network.target" 281 + ]; 282 + 283 + # mount is always available on nixos, avoid adding additional store paths to the closure 284 + # https://github.com/NixOS/nixpkgs/blob/2b8e2457ebe576ebf41ddfa8452b5b07a8d493ad/nixos/modules/system/boot/systemd/initrd.nix#L550-L551 285 + path = [ 286 + config.boot.initrd.systemd.package.util-linux 287 + ]; 288 + 289 + serviceConfig = { 290 + Type = "oneshot"; 291 + # Otherwise systemd starts ifstate again, after the encryption password was entered by the user 292 + # and we are able to implement the cleanup using ExecStop rather than a separate unit. 293 + RemainAfterExit = true; 294 + # When using network namespaces pyroute2 expects this directory to exists. 295 + # @liske is currently investigating whether this should be considered a bug in pyroute2. 296 + ExecStartPre = "${lib.getExe' pkgs.coreutils "mkdir"} /var/run"; 297 + ExecStart = "${lib.getExe initrdCfg.package} --config ${ 298 + config.environment.etc."ifstate/ifstate.initrd.yaml".source 299 + } apply"; 300 + ExecStop = "${lib.getExe initrdCfg.package} --config ${ 301 + config.environment.etc."ifstate/ifstate.initrd-cleanup.yaml".source 302 + } apply"; 303 + # because oneshot services do not have a timeout by default 304 + TimeoutStartSec = "2min"; 305 + }; 306 + }; 307 + }; 308 + }; 309 + }) 310 + ]; 311 + }
+1
nixos/tests/all-tests.nix
··· 723 723 i3wm = runTest ./i3wm.nix; 724 724 icingaweb2 = runTest ./icingaweb2.nix; 725 725 ifm = runTest ./ifm.nix; 726 + ifstate = import ./ifstate { inherit runTest; }; 726 727 iftop = runTest ./iftop.nix; 727 728 immich = runTest ./web-apps/immich.nix; 728 729 immich-public-proxy = runTest ./web-apps/immich-public-proxy.nix;
+10
nixos/tests/ifstate/default.nix
··· 1 + { runTest }: 2 + 3 + { 4 + initrd = runTest ./initrd.nix; 5 + initrd-partial-broken-config = runTest ./initrd-partial-broken-config.nix; 6 + initrd-wireguard = runTest ./initrd-wireguard.nix; 7 + partial-broken-config = runTest ./partial-broken-config.nix; 8 + ping = runTest ./ping.nix; 9 + wireguard = runTest ./wireguard.nix; 10 + }
+79
nixos/tests/ifstate/initrd-partial-broken-config.nix
··· 1 + let 2 + mkIfStateConfig = id: { 3 + enable = true; 4 + settings.interfaces.eth1 = { 5 + addresses = [ "2001:0db8::${builtins.toString id}/64" ]; 6 + link = { 7 + state = "up"; 8 + kind = "physical"; 9 + }; 10 + }; 11 + }; 12 + in 13 + { 14 + name = "ifstate-initrd-partial-broken-config"; 15 + 16 + nodes = { 17 + server = 18 + { lib, ... }: 19 + { 20 + imports = [ ../../modules/profiles/minimal.nix ]; 21 + 22 + virtualisation.interfaces.eth1.vlan = 1; 23 + 24 + # Initrd IfState enforces stage 2 ifstate using assertion. 25 + networking.ifstate = { 26 + enable = true; 27 + settings.interfaces = { }; 28 + }; 29 + 30 + boot.initrd = { 31 + network = { 32 + enable = true; 33 + ifstate = lib.mkMerge [ 34 + (mkIfStateConfig 1) 35 + { 36 + allowIfstateToDrasticlyIncreaseInitrdSize = true; 37 + 38 + # non-existent interface; ifstate should apply eth1 and do not distrupt the boot process 39 + settings.interfaces.eth2 = { 40 + addresses = [ "2001:0db8:b::dead:beef/64" ]; 41 + link = { 42 + state = "up"; 43 + kind = "physical"; 44 + }; 45 + }; 46 + } 47 + ]; 48 + }; 49 + systemd = { 50 + enable = true; 51 + network.enable = false; 52 + services.boot-blocker = { 53 + before = [ "initrd.target" ]; 54 + wantedBy = [ "initrd.target" ]; 55 + script = "sleep infinity"; 56 + serviceConfig.Type = "oneshot"; 57 + }; 58 + }; 59 + }; 60 + }; 61 + 62 + client = { 63 + imports = [ ../../modules/profiles/minimal.nix ]; 64 + 65 + virtualisation.interfaces.eth1.vlan = 1; 66 + 67 + networking.ifstate = mkIfStateConfig 2; 68 + }; 69 + }; 70 + 71 + testScript = # python 72 + '' 73 + start_all() 74 + client.wait_for_unit("network.target") 75 + 76 + # try to ping the server from the client 77 + client.wait_until_succeeds("ping -c 1 2001:0db8::1") 78 + ''; 79 + }
+121
nixos/tests/ifstate/initrd-wireguard.nix
··· 1 + let 2 + mkNodeIfStateConfig = 3 + { 4 + pkgs, 5 + id, 6 + wgPriv, 7 + wgPeerPubKey, 8 + wgPeerId, 9 + }: 10 + { 11 + enable = true; 12 + settings = { 13 + namespaces.outside.interfaces.eth1 = { 14 + addresses = [ "2001:0db8:a::${builtins.toString id}/64" ]; 15 + link = { 16 + state = "up"; 17 + kind = "physical"; 18 + }; 19 + }; 20 + interfaces = { 21 + wg0 = { 22 + addresses = [ "2001:0db8:b::${builtins.toString id}/64" ]; 23 + link = { 24 + state = "up"; 25 + kind = "wireguard"; 26 + bind_netns = "outside"; 27 + }; 28 + wireguard = { 29 + private_key = "!include ${pkgs.writeText "wg_priv.key" wgPriv}"; 30 + listen_port = 51820; 31 + peers."${wgPeerPubKey}" = { 32 + endpoint = "[2001:0db8:a::${builtins.toString wgPeerId}]:51820"; 33 + allowedips = [ "::/0" ]; 34 + }; 35 + }; 36 + }; 37 + }; 38 + routing.routes = [ 39 + { 40 + to = "2001:0db8:b::/64"; 41 + dev = "wg0"; 42 + } 43 + ]; 44 + }; 45 + }; 46 + in 47 + { 48 + name = "ifstate-initrd-wireguard"; 49 + 50 + nodes = { 51 + foo = 52 + { pkgs, ... }: 53 + { 54 + imports = [ ../../modules/profiles/minimal.nix ]; 55 + 56 + virtualisation.interfaces.eth1.vlan = 1; 57 + 58 + # Initrd IfState enforces stage 2 ifstate using assertion. 59 + networking.ifstate = { 60 + enable = true; 61 + settings.interfaces = { }; 62 + }; 63 + 64 + boot.initrd = { 65 + network = { 66 + enable = true; 67 + ifstate = 68 + mkNodeIfStateConfig { 69 + inherit pkgs; 70 + id = 1; 71 + wgPriv = "6KmLyTyrN9OZIOCkdpiAwoVoeSiwvyI+mtn1wooKSEU="; 72 + wgPeerPubKey = "olFuE7u5pVwSeWLFtrXSvD8+aCDBiKNKCLjLb/dgXiA="; 73 + wgPeerId = 2; 74 + } 75 + // { 76 + package = pkgs.ifstate.override { 77 + withConfigValidation = false; 78 + }; 79 + allowIfstateToDrasticlyIncreaseInitrdSize = true; 80 + }; 81 + }; 82 + systemd = { 83 + enable = true; 84 + network.enable = false; 85 + services.boot-blocker = { 86 + before = [ "initrd.target" ]; 87 + wantedBy = [ "initrd.target" ]; 88 + script = "sleep infinity"; 89 + serviceConfig.Type = "oneshot"; 90 + }; 91 + }; 92 + }; 93 + }; 94 + 95 + bar = 96 + { pkgs, ... }: 97 + { 98 + imports = [ ../../modules/profiles/minimal.nix ]; 99 + 100 + virtualisation.interfaces.eth1.vlan = 1; 101 + 102 + networking = { 103 + ifstate = mkNodeIfStateConfig { 104 + inherit pkgs; 105 + id = 2; 106 + wgPriv = "QN89cvFD0C8z1MSpUaJa1YBXt2MaIQegVkEYROi71Fg="; 107 + wgPeerPubKey = "5qeKbAGc7wh9Xg0MoMXqXCSmp9TawmtI1bVk/vp3Cn4="; 108 + wgPeerId = 1; 109 + }; 110 + }; 111 + }; 112 + }; 113 + testScript = # python 114 + '' 115 + start_all() 116 + 117 + bar.wait_for_unit("default.target") 118 + 119 + bar.wait_until_succeeds("ping -c 1 2001:0db8:b::1") 120 + ''; 121 + }
+65
nixos/tests/ifstate/initrd.nix
··· 1 + let 2 + mkIfStateConfig = id: { 3 + enable = true; 4 + settings.interfaces.eth1 = { 5 + addresses = [ "2001:0db8::${builtins.toString id}/64" ]; 6 + link = { 7 + state = "up"; 8 + kind = "physical"; 9 + }; 10 + }; 11 + }; 12 + in 13 + { 14 + name = "ifstate-initrd"; 15 + 16 + nodes = { 17 + server = { 18 + imports = [ ../../modules/profiles/minimal.nix ]; 19 + 20 + virtualisation.interfaces.eth1.vlan = 1; 21 + 22 + # Initrd IfState enforces stage 2 ifstate using assertion. 23 + networking.ifstate = { 24 + enable = true; 25 + settings.interfaces = { }; 26 + }; 27 + 28 + boot.initrd = { 29 + network = { 30 + enable = true; 31 + ifstate = mkIfStateConfig 1 // { 32 + allowIfstateToDrasticlyIncreaseInitrdSize = true; 33 + }; 34 + }; 35 + systemd = { 36 + enable = true; 37 + network.enable = false; 38 + services.boot-blocker = { 39 + before = [ "initrd.target" ]; 40 + wantedBy = [ "initrd.target" ]; 41 + script = "sleep infinity"; 42 + serviceConfig.Type = "oneshot"; 43 + }; 44 + }; 45 + }; 46 + }; 47 + 48 + client = { 49 + imports = [ ../../modules/profiles/minimal.nix ]; 50 + 51 + virtualisation.interfaces.eth1.vlan = 1; 52 + 53 + networking.ifstate = mkIfStateConfig 2; 54 + }; 55 + }; 56 + 57 + testScript = # python 58 + '' 59 + start_all() 60 + client.wait_for_unit("network.target") 61 + 62 + # try to ping the server from the client 63 + client.wait_until_succeeds("ping -c 1 2001:0db8::1") 64 + ''; 65 + }
+39
nixos/tests/ifstate/partial-broken-config.nix
··· 1 + { 2 + name = "ifstate-partial-broken-config"; 3 + 4 + nodes.machine = { 5 + imports = [ ../../modules/profiles/minimal.nix ]; 6 + 7 + virtualisation.interfaces.eth1.vlan = 1; 8 + 9 + networking.ifstate = { 10 + enable = true; 11 + settings.interfaces = { 12 + eth1 = { 13 + addresses = [ "2001:0db8:a::1/64" ]; 14 + link = { 15 + state = "up"; 16 + kind = "physical"; 17 + }; 18 + }; 19 + # non-existent interface; ifstate should apply eth1 and do not distrupt the boot process 20 + eth2 = { 21 + addresses = [ "2001:0db8:b::1/64" ]; 22 + link = { 23 + state = "up"; 24 + kind = "physical"; 25 + }; 26 + }; 27 + }; 28 + }; 29 + }; 30 + 31 + testScript = # python 32 + '' 33 + start_all() 34 + 35 + machine.wait_for_unit("default.target") 36 + 37 + machine.wait_until_succeeds("ping -c 1 2001:0db8:a::1") 38 + ''; 39 + }
+38
nixos/tests/ifstate/ping.nix
··· 1 + let 2 + mkNode = id: { 3 + imports = [ ../../modules/profiles/minimal.nix ]; 4 + 5 + virtualisation.interfaces.eth1.vlan = 1; 6 + 7 + networking.ifstate = { 8 + enable = true; 9 + settings.interfaces.eth1 = { 10 + addresses = [ "2001:0db8::${builtins.toString id}/64" ]; 11 + link = { 12 + state = "up"; 13 + kind = "physical"; 14 + }; 15 + }; 16 + }; 17 + }; 18 + in 19 + 20 + { 21 + name = "ifstate-ping"; 22 + 23 + nodes = { 24 + foo = mkNode 1; 25 + bar = mkNode 2; 26 + }; 27 + 28 + testScript = # python 29 + '' 30 + start_all() 31 + 32 + foo.wait_for_unit("default.target") 33 + bar.wait_for_unit("default.target") 34 + 35 + foo.wait_until_succeeds("ping -c 1 2001:0db8::2") 36 + bar.wait_until_succeeds("ping -c 1 2001:0db8::1") 37 + ''; 38 + }
+88
nixos/tests/ifstate/wireguard.nix
··· 1 + let 2 + mkNode = 3 + { 4 + id, 5 + wgPriv, 6 + wgPeerPubKey, 7 + wgPeerId, 8 + }: 9 + ( 10 + { pkgs, ... }: 11 + { 12 + imports = [ ../../modules/profiles/minimal.nix ]; 13 + 14 + virtualisation.interfaces.eth1.vlan = 1; 15 + 16 + networking = { 17 + firewall.interfaces.eth1.allowedUDPPorts = [ 51820 ]; 18 + 19 + ifstate = { 20 + enable = true; 21 + settings = { 22 + namespaces.outside.interfaces.eth1 = { 23 + addresses = [ "2001:0db8:a::${builtins.toString id}/64" ]; 24 + link = { 25 + state = "up"; 26 + kind = "physical"; 27 + }; 28 + }; 29 + interfaces = { 30 + wg0 = { 31 + addresses = [ "2001:0db8:b::${builtins.toString id}/64" ]; 32 + link = { 33 + state = "up"; 34 + kind = "wireguard"; 35 + bind_netns = "outside"; 36 + }; 37 + wireguard = { 38 + private_key = "!include ${pkgs.writeText "wg_priv.key" wgPriv}"; 39 + listen_port = 51820; 40 + peers."${wgPeerPubKey}" = { 41 + endpoint = "[2001:0db8:a::${builtins.toString wgPeerId}]:51820"; 42 + allowedips = [ "::/0" ]; 43 + }; 44 + }; 45 + }; 46 + }; 47 + routing.routes = [ 48 + { 49 + to = "2001:0db8:b::/64"; 50 + dev = "wg0"; 51 + } 52 + ]; 53 + }; 54 + }; 55 + }; 56 + } 57 + ); 58 + in 59 + 60 + { 61 + name = "ifstate-wireguard"; 62 + 63 + nodes = { 64 + foo = mkNode { 65 + id = 1; 66 + wgPriv = "6KmLyTyrN9OZIOCkdpiAwoVoeSiwvyI+mtn1wooKSEU="; 67 + wgPeerPubKey = "olFuE7u5pVwSeWLFtrXSvD8+aCDBiKNKCLjLb/dgXiA="; 68 + wgPeerId = 2; 69 + }; 70 + bar = mkNode { 71 + id = 2; 72 + wgPriv = "QN89cvFD0C8z1MSpUaJa1YBXt2MaIQegVkEYROi71Fg="; 73 + wgPeerPubKey = "5qeKbAGc7wh9Xg0MoMXqXCSmp9TawmtI1bVk/vp3Cn4="; 74 + wgPeerId = 1; 75 + }; 76 + }; 77 + 78 + testScript = # python 79 + '' 80 + start_all() 81 + 82 + foo.wait_for_unit("default.target") 83 + bar.wait_for_unit("default.target") 84 + 85 + foo.wait_until_succeeds("ping -c 1 2001:0db8:b::2") 86 + bar.wait_until_succeeds("ping -c 1 2001:0db8:b::1") 87 + ''; 88 + }