mirror of
https://git.sr.ht/~magic_rb/dotfiles
synced 2024-11-29 03:26:13 +01:00
More network test work
Signed-off-by: magic_rb <magic_rb@redalder.org>
This commit is contained in:
parent
e0cc1a7efe
commit
0e7389fcbd
|
@ -1,38 +1,5 @@
|
|||
{self, ...}: {
|
||||
perSystem = {pkgs, ...}: {
|
||||
checks.router = pkgs.stdenv.mkDerivation {
|
||||
name = "router";
|
||||
phases = [
|
||||
"runPhase"
|
||||
];
|
||||
|
||||
env.ROUTER_CMD =
|
||||
(self.nixosConfigurations.liveusb.extendModules {
|
||||
modules = [
|
||||
"${pkgs.path}/nixos/modules/testing/test-instrumentation.nix"
|
||||
];
|
||||
})
|
||||
.config
|
||||
.system
|
||||
.build
|
||||
.vm;
|
||||
|
||||
nativeBuildInputs = with pkgs; [
|
||||
iproute2
|
||||
(python3.withPackages (ps:
|
||||
with ps; [
|
||||
ptpython
|
||||
colorama
|
||||
junit-xml
|
||||
]))
|
||||
];
|
||||
|
||||
runPhase = ''
|
||||
PYTHONPATH=${pkgs.path}/nixos/lib/test-driver python ${./router.py}
|
||||
|
||||
mkdir -p $out
|
||||
touch $out/success
|
||||
'';
|
||||
};
|
||||
};
|
||||
{...}: {
|
||||
imports = [
|
||||
./hel
|
||||
];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
From ce950ae409a3a7d9ba259e61e0f029005a12512e Mon Sep 17 00:00:00 2001
|
||||
From: magic_rb <richard@brezak.sk>
|
||||
Date: Tue, 6 Aug 2024 19:04:43 +0200
|
||||
Subject: [PATCH 1/3] Don't close stdout, stderr when running a script
|
||||
|
||||
Signed-off-by: magic_rb <richard@brezak.sk>
|
||||
---
|
||||
pppd/main.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/pppd/main.c b/pppd/main.c
|
||||
index 8310c98..de6d6f4 100644
|
||||
--- a/pppd/main.c
|
||||
+++ b/pppd/main.c
|
||||
@@ -1918,7 +1918,7 @@ run_program(char *prog, char * const *args, int must_exist, void (*done)(void *)
|
||||
return 0;
|
||||
}
|
||||
|
||||
- pid = ppp_safe_fork(fd_devnull, fd_devnull, fd_devnull);
|
||||
+ pid = ppp_safe_fork(fd_devnull, 1, 2);
|
||||
if (pid == -1) {
|
||||
error("Failed to create child process for %s: %m", prog);
|
||||
return -1;
|
||||
--
|
||||
2.44.1
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
From 761f4fdc1165da91d3b758caa853f8a9f6ff61a2 Mon Sep 17 00:00:00 2001
|
||||
From: magic_rb <richard@brezak.sk>
|
||||
Date: Tue, 6 Aug 2024 19:05:09 +0200
|
||||
Subject: [PATCH 2/3] Call scripts with the same environ as pppd
|
||||
|
||||
Signed-off-by: magic_rb <richard@brezak.sk>
|
||||
---
|
||||
pppd/main.c | 15 ++++++++++++++-
|
||||
1 file changed, 14 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/pppd/main.c b/pppd/main.c
|
||||
index de6d6f4..defb002 100644
|
||||
--- a/pppd/main.c
|
||||
+++ b/pppd/main.c
|
||||
@@ -125,6 +125,8 @@
|
||||
#include "atcp.h"
|
||||
#endif
|
||||
|
||||
+extern char** environ;
|
||||
+
|
||||
/* interface vars */
|
||||
char ifname[IFNAMSIZ]; /* Interface name */
|
||||
int ifunit; /* Interface unit number */
|
||||
@@ -1962,7 +1964,18 @@ run_program(char *prog, char * const *args, int must_exist, void (*done)(void *)
|
||||
|
||||
/* run the program */
|
||||
update_script_environment();
|
||||
- execve(prog, args, script_env);
|
||||
+
|
||||
+ /* combine environs */
|
||||
+ size_t stock_environ_length = strlen(environ);
|
||||
+ size_t script_environ_length = strlen(script_env);
|
||||
+ char** combined_environ = calloc(stock_environ_length + script_environ_length + 1, sizeof(*combined_environ));
|
||||
+ memcpy(combined_environ, script_env, script_environ_length);
|
||||
+ memcpy(combined_environ + script_environ_length, environ, stock_environ_length);
|
||||
+
|
||||
+ printf("invoking with %ul env vars\n", combined_environ);
|
||||
+
|
||||
+ execve(prog, args, environ);
|
||||
+ free(combined_environ);
|
||||
if (must_exist || errno != ENOENT) {
|
||||
/* have to reopen the log, there's nowhere else
|
||||
for the message to go. */
|
||||
--
|
||||
2.44.1
|
||||
|
35
nixos/tests/hel/0003-Wait-for-ip-up-down-scripts.patch
Normal file
35
nixos/tests/hel/0003-Wait-for-ip-up-down-scripts.patch
Normal file
|
@ -0,0 +1,35 @@
|
|||
From bb890feb75093513194058a5fb2d7728d5a07283 Mon Sep 17 00:00:00 2001
|
||||
From: magic_rb <richard@brezak.sk>
|
||||
Date: Fri, 9 Aug 2024 14:33:50 +0200
|
||||
Subject: [PATCH 3/3] Wait for ip up/down scripts
|
||||
|
||||
Signed-off-by: magic_rb <richard@brezak.sk>
|
||||
---
|
||||
pppd/ipcp.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/pppd/ipcp.c b/pppd/ipcp.c
|
||||
index 5d9ff11..49f1e9a 100644
|
||||
--- a/pppd/ipcp.c
|
||||
+++ b/pppd/ipcp.c
|
||||
@@ -1996,7 +1996,7 @@ ipcp_up(fsm *f)
|
||||
*/
|
||||
if (ipcp_script_state == s_down && ipcp_script_pid == 0) {
|
||||
ipcp_script_state = s_up;
|
||||
- ipcp_script(path_ipup, 0);
|
||||
+ ipcp_script(path_ipup, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2045,7 +2045,7 @@ ipcp_down(fsm *f)
|
||||
/* Execute the ip-down script */
|
||||
if (ipcp_script_state == s_up && ipcp_script_pid == 0) {
|
||||
ipcp_script_state = s_down;
|
||||
- ipcp_script(path_ipdown, 0);
|
||||
+ ipcp_script(path_ipdown, 1);
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
2.44.1
|
||||
|
51
nixos/tests/hel/client.nix
Normal file
51
nixos/tests/hel/client.nix
Normal file
|
@ -0,0 +1,51 @@
|
|||
{
|
||||
inputs',
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(lib)
|
||||
concatMap
|
||||
;
|
||||
in {
|
||||
imports = [
|
||||
inputs'.self.nixosModules.ifstate
|
||||
inputs'.self.nixosModules.netnsIf
|
||||
./qemu-vm.nix
|
||||
];
|
||||
nixpkgs.overlays = [
|
||||
inputs'.self.overlays.ifstate
|
||||
];
|
||||
|
||||
environment.systemPackages = [pkgs.tcpdump];
|
||||
|
||||
services.ifstate = {
|
||||
enable = true;
|
||||
|
||||
settings = {
|
||||
interfaces = [
|
||||
{
|
||||
name = "lan";
|
||||
link = {
|
||||
kind = "physical";
|
||||
permaddr = "00:11:22:33:43:00";
|
||||
state = "up";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
networking = {
|
||||
hostName = "client";
|
||||
useDHCP = false;
|
||||
interfaces.lan.useDHCP = true;
|
||||
firewall.enable = false;
|
||||
};
|
||||
|
||||
virtualisation.qemu.options = [
|
||||
"-net nic,model=e1000,macaddr=00:11:22:33:43:00,netdev=lan"
|
||||
"-netdev vde,id=lan,sock=../../../hel/switch"
|
||||
];
|
||||
}
|
112
nixos/tests/hel/default.nix
Normal file
112
nixos/tests/hel/default.nix
Normal file
|
@ -0,0 +1,112 @@
|
|||
{
|
||||
inputs,
|
||||
lib,
|
||||
self,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(lib)
|
||||
singleton
|
||||
concatMap
|
||||
mkDefault
|
||||
mkImageMediaOverride
|
||||
;
|
||||
in {
|
||||
flake.nixosConfigurations.hela = inputs.nixpkgs-stable.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules =
|
||||
singleton
|
||||
(import ./hela.nix);
|
||||
specialArgs = {
|
||||
inputs' = inputs;
|
||||
};
|
||||
};
|
||||
|
||||
flake.nixosConfigurations."jörmungandr" = inputs.nixpkgs-stable.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules =
|
||||
singleton
|
||||
(import ./jormungandr.nix);
|
||||
specialArgs = {
|
||||
inputs' = inputs;
|
||||
};
|
||||
};
|
||||
|
||||
flake.nixosConfigurations.client = inputs.nixpkgs-stable.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules =
|
||||
singleton
|
||||
(import ./client.nix);
|
||||
specialArgs = {
|
||||
inputs' = inputs;
|
||||
};
|
||||
};
|
||||
|
||||
perSystem = {
|
||||
lib,
|
||||
pkgs,
|
||||
system,
|
||||
...
|
||||
}: {
|
||||
checks.router = pkgs.stdenv.mkDerivation {
|
||||
name = "router";
|
||||
phases = [
|
||||
"runPhase"
|
||||
];
|
||||
|
||||
env = {
|
||||
HELA_SYSTEM =
|
||||
(self.nixosConfigurations.hela.extendModules {
|
||||
modules = [
|
||||
"${pkgs.path}/nixos/modules/testing/test-instrumentation.nix"
|
||||
];
|
||||
})
|
||||
.config
|
||||
.system
|
||||
.build
|
||||
.vm;
|
||||
|
||||
CLIENT_SYSTEM =
|
||||
(self.nixosConfigurations.client.extendModules {
|
||||
modules = [
|
||||
"${pkgs.path}/nixos/modules/testing/test-instrumentation.nix"
|
||||
];
|
||||
})
|
||||
.config
|
||||
.system
|
||||
.build
|
||||
.vm;
|
||||
|
||||
JORMUNGANDR_SYSTEM =
|
||||
(self.nixosConfigurations."jörmungandr".extendModules {
|
||||
modules = [
|
||||
"${pkgs.path}/nixos/modules/testing/test-instrumentation.nix"
|
||||
];
|
||||
})
|
||||
.config
|
||||
.system
|
||||
.build
|
||||
.vm;
|
||||
};
|
||||
|
||||
nativeBuildInputs = with pkgs; [
|
||||
iproute2
|
||||
vde2
|
||||
socat
|
||||
(python3.withPackages (ps:
|
||||
with ps; [
|
||||
ptpython
|
||||
colorama
|
||||
junit-xml
|
||||
]))
|
||||
];
|
||||
|
||||
runPhase = ''
|
||||
PYTHONPATH=${pkgs.path}/nixos/lib/test-driver python ${../router.py}
|
||||
|
||||
mkdir -p $out
|
||||
touch $out/success
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
302
nixos/tests/hel/hela.nix
Normal file
302
nixos/tests/hel/hela.nix
Normal file
|
@ -0,0 +1,302 @@
|
|||
{
|
||||
pkgs,
|
||||
config,
|
||||
inputs',
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(lib)
|
||||
mkDefault
|
||||
concatMap
|
||||
mkImageMediaOverride
|
||||
getExe'
|
||||
;
|
||||
|
||||
notnft = inputs'.notnft.lib.${pkgs.stdenv.system};
|
||||
in {
|
||||
_module.args = {inherit notnft;};
|
||||
imports = [
|
||||
inputs'.self.nixosModules.ifstate
|
||||
inputs'.self.nixosModules.notnft-ns
|
||||
./qemu-vm.nix
|
||||
];
|
||||
nixpkgs.overlays = [
|
||||
inputs'.self.overlays.ifstate
|
||||
];
|
||||
|
||||
networking = {
|
||||
hostName = "hela";
|
||||
useDHCP = false;
|
||||
firewall.enable = false;
|
||||
};
|
||||
|
||||
environment.systemPackages = [pkgs.tcpdump];
|
||||
|
||||
networking.notnft.enable = true;
|
||||
networking.notnft.namespaces.default.firewall.interfaces."lan".rules =
|
||||
# ---
|
||||
with notnft.dsl;
|
||||
with payload;
|
||||
# ---
|
||||
{
|
||||
input = [
|
||||
[(is.eq ip.protocol (f: f.icmp)) accept]
|
||||
[(is.eq ip.protocol (f: f.udp)) (is.eq th.dport 67) accept]
|
||||
];
|
||||
};
|
||||
networking.notnft.namespaces.default.rules =
|
||||
# ---
|
||||
with notnft.dsl;
|
||||
with payload;
|
||||
# ---
|
||||
ruleset {
|
||||
filter = add table {family = f: f.inet;} {
|
||||
input =
|
||||
add chain {
|
||||
type = f: f.filter;
|
||||
hook = f: f.input;
|
||||
prio = -300;
|
||||
policy = f: f.drop;
|
||||
}
|
||||
[(is.eq meta.iifname "lan") (jump "input-lan")];
|
||||
};
|
||||
};
|
||||
|
||||
networking.notnft.namespaces.dmz.firewall.interfaces."internet".rules =
|
||||
# ---
|
||||
with notnft.dsl;
|
||||
with payload;
|
||||
# ---
|
||||
{
|
||||
input = [
|
||||
[(is.eq meta.protocol (_: 34915)) accept] # allow PPPoE
|
||||
[drop]
|
||||
];
|
||||
};
|
||||
networking.notnft.namespaces.dmz.rules =
|
||||
# ---
|
||||
with notnft.dsl;
|
||||
with payload;
|
||||
# ---
|
||||
ruleset {
|
||||
filter = add table {family = f: f.inet;} {
|
||||
input =
|
||||
add chain {
|
||||
type = f: f.filter;
|
||||
hook = f: f.input;
|
||||
prio = -300;
|
||||
policy = f: f.drop;
|
||||
}
|
||||
# accept related, established and drop invalid
|
||||
[
|
||||
(vmap ct.state {
|
||||
established = accept;
|
||||
related = accept;
|
||||
invalid = drop;
|
||||
})
|
||||
]
|
||||
[(is.eq meta.iifname "internet") (jump "input-internet")];
|
||||
};
|
||||
};
|
||||
|
||||
services.ifstate = {
|
||||
enable = true;
|
||||
|
||||
settings = {
|
||||
namespaces = {
|
||||
dmz = {
|
||||
interfaces = [
|
||||
{
|
||||
name = "wan";
|
||||
link = {
|
||||
kind = "physical";
|
||||
permaddr = "00:11:22:33:44:10";
|
||||
state = "up";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "internet";
|
||||
link = {
|
||||
kind = "vlan";
|
||||
link = "wan";
|
||||
vlan_id = 6;
|
||||
state = "up";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "iptv";
|
||||
link = {
|
||||
kind = "vlan";
|
||||
link = "wan";
|
||||
vlan_id = 4;
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "telephony";
|
||||
link = {
|
||||
kind = "vlan";
|
||||
link = "wan";
|
||||
vlan_id = 7;
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
interfaces = [
|
||||
{
|
||||
name = "eth1";
|
||||
link = {
|
||||
kind = "physical";
|
||||
address = "00:11:22:33:44:01";
|
||||
state = "down";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "eth2";
|
||||
link = {
|
||||
kind = "physical";
|
||||
address = "00:11:22:33:44:02";
|
||||
state = "down";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "lan0";
|
||||
link = {
|
||||
kind = "physical";
|
||||
address = "00:11:22:33:44:11";
|
||||
master = "lan";
|
||||
state = "up";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "lan1";
|
||||
link = {
|
||||
kind = "physical";
|
||||
address = "00:11:22:33:44:12";
|
||||
master = "lan";
|
||||
state = "up";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "lan2";
|
||||
link = {
|
||||
kind = "physical";
|
||||
address = "00:11:22:33:44:13";
|
||||
master = "lan";
|
||||
state = "up";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "village";
|
||||
link = {
|
||||
kind = "vlan";
|
||||
link = "lan";
|
||||
vlan_id = 1;
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "bastion";
|
||||
link = {
|
||||
kind = "vlan";
|
||||
link = "lan";
|
||||
vlan_id = 2;
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "lan";
|
||||
link = {
|
||||
kind = "bridge";
|
||||
state = "up";
|
||||
};
|
||||
addresses = [
|
||||
"10.10.0.1/24"
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
services.kea.dhcp4 = {
|
||||
enable = true;
|
||||
|
||||
settings = {
|
||||
interfaces-config.interfaces = [
|
||||
"lan"
|
||||
];
|
||||
|
||||
subnet4 = [
|
||||
{
|
||||
pools = [
|
||||
{pool = "10.10.0.2 - 10.10.0.200";}
|
||||
];
|
||||
id = 1;
|
||||
subnet = "10.10.0.0/24";
|
||||
option-data = [
|
||||
{
|
||||
name = "routers";
|
||||
data = "10.10.0.1";
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# reference: https://gist.github.com/c0deaddict/64cc4ee262e428e8d8ff4fe507ab1f9b
|
||||
services.pppd = let
|
||||
rp-pppoe = pkgs.callPackage ./rp-pppoe.nix {};
|
||||
in {
|
||||
enable = true;
|
||||
peers.kpn = {
|
||||
config = ''
|
||||
plugin ${rp-pppoe}/etc/ppp/plugins/rp-pppoe.so
|
||||
nic-internet
|
||||
name "kpn"
|
||||
noauth
|
||||
hide-password
|
||||
debug
|
||||
+ipv6
|
||||
ipv6cp-accept-local
|
||||
noipdefault
|
||||
defaultroute
|
||||
defaultroute6
|
||||
persist
|
||||
maxfail 0
|
||||
holdoff 5
|
||||
mtu 1500
|
||||
mru 1500
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.pppd-kpn = {
|
||||
after = ["ifstate.service"];
|
||||
serviceConfig.NetworkNamespacePath = "/var/run/netns/dmz";
|
||||
};
|
||||
|
||||
virtualisation.qemu.options =
|
||||
(concatMap (index: let
|
||||
index' = toString index;
|
||||
in [
|
||||
"-net nic,model=e1000,macaddr=00:11:22:33:44:0${index'},netdev=eth${index'}"
|
||||
"-netdev stream,id=eth${index'},addr.type=unix,addr.path=/dev/null"
|
||||
# "-netdev vde,id=eth${index'},sock=../../../hel/switch"
|
||||
]) [1 2])
|
||||
++ [
|
||||
"-net nic,model=e1000,macaddr=00:11:22:33:44:10,netdev=wan"
|
||||
"-netdev stream,id=wan,server=on,addr.type=unix,addr.path=../../../midgard/link"
|
||||
# "-netdev vde,id=wan,sock=../../../midgard/switch"
|
||||
|
||||
"-net nic,model=e1000,macaddr=00:11:22:33:44:11,netdev=lan1"
|
||||
"-netdev vde,id=lan1,sock=../../../hel/switch"
|
||||
]
|
||||
++ (concatMap (index: let
|
||||
index' = toString index;
|
||||
in [
|
||||
"-net nic,model=e1000,macaddr=00:11:22:33:44:1${index'},netdev=lan${index'}"
|
||||
"-netdev stream,id=lan${index'},addr.type=unix,addr.path=/dev/null"
|
||||
# "-netdev vde,id=lan${index'},sock=../../../hel/switch"
|
||||
]) [2 3]);
|
||||
}
|
92
nixos/tests/hel/jormungandr.nix
Normal file
92
nixos/tests/hel/jormungandr.nix
Normal file
|
@ -0,0 +1,92 @@
|
|||
{
|
||||
inputs',
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(lib)
|
||||
concatMap
|
||||
getExe'
|
||||
;
|
||||
in {
|
||||
imports = [
|
||||
inputs'.self.nixosModules.ifstate
|
||||
inputs'.self.nixosModules.netnsIf
|
||||
./pppoe-server.nix
|
||||
./qemu-vm.nix
|
||||
];
|
||||
nixpkgs.overlays = [
|
||||
inputs'.self.overlays.ifstate
|
||||
(final: _: {
|
||||
rp-pppoe = final.callPackage ./rp-pppoe.nix {
|
||||
ppp = final.ppp.overrideAttrs (_: {
|
||||
patches = [
|
||||
./0003-Wait-for-ip-up-down-scripts.patch
|
||||
./0002-Call-scripts-with-the-same-environ-as-pppd.patch
|
||||
];
|
||||
});
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
environment.systemPackages = [
|
||||
pkgs.tcpdump
|
||||
];
|
||||
|
||||
services.ifstate = {
|
||||
enable = true;
|
||||
|
||||
settings = {
|
||||
interfaces = [
|
||||
{
|
||||
name = "wan";
|
||||
link = {
|
||||
kind = "physical";
|
||||
permaddr = "00:11:22:33:42:00";
|
||||
state = "up";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "internet";
|
||||
link = {
|
||||
kind = "vlan";
|
||||
link = "wan";
|
||||
vlan_id = 6;
|
||||
state = "up";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "www-br";
|
||||
link = {
|
||||
kind = "bridge";
|
||||
state = "up";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
services.pppoe-server.kpn = {
|
||||
interface = "internet";
|
||||
localAddress = "10.0.0.1";
|
||||
remoteAddressFile = pkgs.writeText "kpn-remote-address-file" ''
|
||||
10.67.15.1
|
||||
'';
|
||||
# ifUpScript = pkgs.writeShellScript "ppd-if-up" ''
|
||||
# ${getExe' pkgs.iproute2 "ip"} link set dev "$PPP_IFACE" master ppp-br
|
||||
# '';
|
||||
};
|
||||
|
||||
networking = {
|
||||
hostName = "jormungandr";
|
||||
useDHCP = false;
|
||||
firewall.enable = false;
|
||||
};
|
||||
|
||||
virtualisation.qemu.options = [
|
||||
"-net nic,model=e1000,macaddr=00:11:22:33:42:00,netdev=wan"
|
||||
"-netdev stream,id=wan,addr.type=unix,addr.path=../../../midgard/link"
|
||||
# "-netdev vde,id=wan,sock=../../../midgard/switch"
|
||||
];
|
||||
}
|
204
nixos/tests/hel/pppoe-server.nix
Normal file
204
nixos/tests/hel/pppoe-server.nix
Normal file
|
@ -0,0 +1,204 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
options,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(lib)
|
||||
mkOption
|
||||
types
|
||||
flip
|
||||
mapAttrs'
|
||||
nameValuePair
|
||||
concatStringsSep
|
||||
concatMapStringsSep
|
||||
pipe
|
||||
optional
|
||||
mapAttrsToList
|
||||
filterAttrs
|
||||
elem
|
||||
mkPackageOption
|
||||
attrNames
|
||||
singleton
|
||||
optionalString
|
||||
;
|
||||
cfg = config.services.pppoe-server;
|
||||
in {
|
||||
options.services.pppoe-server = mkOption {
|
||||
default = {};
|
||||
type = types.attrsOf (types.submodule ({
|
||||
name,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
freeformType = with types;
|
||||
oneOf [int str];
|
||||
options = {
|
||||
package =
|
||||
mkPackageOption pkgs "rp-pppoe" {};
|
||||
interface = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
Which interface should `pppoe-server' bind to, this interface must
|
||||
be an L2 interface and pass PPPoE packets through unchanged.
|
||||
`pppoe-server' initially broadcasts a PADI packet.
|
||||
'';
|
||||
};
|
||||
|
||||
localAddress = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
Which address should be assigned to the local PPP interface. Only
|
||||
one such IP address per daemon is possible.
|
||||
'';
|
||||
};
|
||||
|
||||
startingRemoteAddress = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
description = ''
|
||||
Which starting address to utilize, `pppoe-server' will keep track
|
||||
of assigned addresses and automatically reclaim them as clients
|
||||
disconnect.
|
||||
'';
|
||||
default = null;
|
||||
};
|
||||
|
||||
maxNumberOfConnections = mkOption {
|
||||
type = types.int;
|
||||
description = ''
|
||||
The maximum number of concurrent connections to allow, also limits
|
||||
the number of IP addresses and therefore the range, as a side
|
||||
effect.
|
||||
'';
|
||||
default = 64;
|
||||
};
|
||||
|
||||
remoteAddressFile = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
description = ''
|
||||
Reads the specified file fname which is a text file
|
||||
consisting of one IP address per line. These IP addresses
|
||||
will be assigned to clients. The number of sessions allowed
|
||||
will equal the number of addresses found in the file.
|
||||
The `remoteAddressFile' option overrides both
|
||||
`startingRemoteAddress' and `maxNumberOfConnections'.
|
||||
|
||||
In addition to containing IP addresses, the pool file can
|
||||
contain lines of the form:
|
||||
- `a.b.c.d-e` which includes all IP addresses from`a.b.c.d` to
|
||||
`a.b.c.e`.
|
||||
For example, the line:
|
||||
- `1.2.3.4-7` is equivalent to:
|
||||
```
|
||||
1.2.3.4
|
||||
1.2.3.5
|
||||
1.2.3.6
|
||||
1.2.3.7
|
||||
```
|
||||
'';
|
||||
default = null;
|
||||
};
|
||||
|
||||
ifUpScript = mkOption {
|
||||
type = with types; nullOr path;
|
||||
description = ''
|
||||
Script to run, when the `ppp` interface goes up.
|
||||
'';
|
||||
default = null;
|
||||
};
|
||||
|
||||
ifDownScript = mkOption {
|
||||
type = with types; nullOr path;
|
||||
description = ''
|
||||
Script to run, when the `ppp` interface goes down.
|
||||
'';
|
||||
default = null;
|
||||
};
|
||||
|
||||
pppdSettings = mkOption {
|
||||
type = with types; attrsOf (listOf (oneOf [str int path]));
|
||||
default = {};
|
||||
description = ''
|
||||
Settings passed to PPPD after it is started by `pppoe-server`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
pppdSettings = {
|
||||
ip-up-script = singleton (pkgs.writeShellScript "ip-up-${name}" ''
|
||||
{
|
||||
echo "Signalling ready to systemd"
|
||||
systemd-notify --ready
|
||||
${optionalString (config.ifUpScript != null) config.ifUpScript}
|
||||
} | logger -t pppd-ip-up
|
||||
'');
|
||||
|
||||
ip-down-script = singleton (pkgs.writeShellScript "ip-down-${name}" ''
|
||||
{
|
||||
echo "Signalling stopping to systemd"
|
||||
systemd-notify --stopping
|
||||
${optionalString (config.ifDownScript != null) config.ifDownScript}
|
||||
} | logger -t pppd-ip-down
|
||||
'');
|
||||
};
|
||||
};
|
||||
}));
|
||||
};
|
||||
|
||||
config.systemd.services = flip mapAttrs' cfg (
|
||||
n: v: let
|
||||
pppdSettingsFile =
|
||||
pkgs.writeText "pppd-${n}.conf"
|
||||
((pipe v.pppdSettings [
|
||||
(mapAttrsToList (n: v: n + " " + concatMapStringsSep " " toString v))
|
||||
(concatStringsSep "\n")
|
||||
])
|
||||
+ "\n");
|
||||
in
|
||||
nameValuePair
|
||||
"pppoe-server-${n}"
|
||||
{
|
||||
before = ["network.target"];
|
||||
wants = ["network.target"];
|
||||
after = ["network-pre.target" "ifstate.service"];
|
||||
wantedBy = ["multi-user.target"];
|
||||
|
||||
path = [
|
||||
pkgs.util-linux
|
||||
];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "notify";
|
||||
NotifyAccess = "all";
|
||||
ExecStart =
|
||||
"${v.package}/bin/pppoe-server "
|
||||
+ concatStringsSep " " (
|
||||
[
|
||||
"-F"
|
||||
"-k"
|
||||
"-I ${v.interface}"
|
||||
"-L ${v.localAddress}"
|
||||
"-g ${v.package}/etc/ppp/plugins/rp-pppoe.so"
|
||||
"-O ${pppdSettingsFile}"
|
||||
]
|
||||
++ optional (v.startingRemoteAddress != null)
|
||||
"-R ${v.startingRemoteAddress}"
|
||||
++ optional (v.maxNumberOfConnections != null)
|
||||
"-N ${toString v.maxNumberOfConnections}"
|
||||
++ optional (v.remoteAddressFile != null)
|
||||
"-p ${v.remoteAddressFile}"
|
||||
++ (flip mapAttrsToList
|
||||
(filterAttrs (
|
||||
n: _:
|
||||
!(elem n (attrNames (options.services.pppoe-server.type.getSubOptions [])))
|
||||
)
|
||||
v)
|
||||
(n: v: "-${n} ${toString v}"))
|
||||
);
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
29
nixos/tests/hel/qemu-vm.nix
Normal file
29
nixos/tests/hel/qemu-vm.nix
Normal file
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
inputs',
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(lib)
|
||||
mkDefault
|
||||
mkImageMediaOverride
|
||||
;
|
||||
in {
|
||||
imports = [
|
||||
"${inputs'.nixpkgs-stable}/nixos/modules/virtualisation/qemu-vm.nix"
|
||||
];
|
||||
services.getty.autologinUser = "nixos";
|
||||
users.users.nixos = {
|
||||
isNormalUser = true;
|
||||
extraGroups = ["wheel" "video"];
|
||||
# Allow the graphical user to login without password
|
||||
initialHashedPassword = "";
|
||||
};
|
||||
# Allow the user to log in as root without a password.
|
||||
users.users.root.initialHashedPassword = "";
|
||||
# Allow passwordless sudo from nixos user
|
||||
security.sudo = {
|
||||
enable = mkDefault true;
|
||||
wheelNeedsPassword = mkImageMediaOverride false;
|
||||
};
|
||||
}
|
29
nixos/tests/hel/rp-pppoe.nix
Normal file
29
nixos/tests/hel/rp-pppoe.nix
Normal file
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
stdenv,
|
||||
fetchFromGitHub,
|
||||
ppp,
|
||||
lib,
|
||||
}:
|
||||
stdenv.mkDerivation {
|
||||
name = "rp-pppoe";
|
||||
version = "4.0.0-next";
|
||||
src = fetchFromGitHub {
|
||||
owner = "dfskoll";
|
||||
repo = "rp-pppoe";
|
||||
rev = "5748840ac83e7e54fecb1b0034407379c2d6c324";
|
||||
hash = "sha256-3QXtVu3IfOoJD60h44cqYGPix/2Gl0IKyFTyDwZIc/0=";
|
||||
};
|
||||
buildInputs = [ppp];
|
||||
sourceRoot = "source/src";
|
||||
env.CPATH = lib.concatStringsSep ":" ["${ppp}/include"];
|
||||
makeFlags = [
|
||||
"DESTDIR=$(out)"
|
||||
];
|
||||
configureFlags = [
|
||||
"--enable-plugin"
|
||||
"--prefix=/"
|
||||
];
|
||||
postInstall = ''
|
||||
test -f $out/etc/ppp/plugins/rp-pppoe.so
|
||||
'';
|
||||
}
|
92
nixos/tests/hel/shq
Normal file
92
nixos/tests/hel/shq
Normal file
|
@ -0,0 +1,92 @@
|
|||
{
|
||||
inputs',
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(lib)
|
||||
concatMap
|
||||
getExe'
|
||||
;
|
||||
in {
|
||||
imports = [
|
||||
inputs'.self.nixosModules.ifstate
|
||||
inputs'.self.nixosModules.netnsIf
|
||||
./pppoe-server.nix
|
||||
./qemu-vm.nix
|
||||
];
|
||||
nixpkgs.overlays = [
|
||||
inputs'.self.overlays.ifstate
|
||||
(final: _: {
|
||||
rp-pppoe = final.callPackage ./rp-pppoe.nix {
|
||||
ppp = final.ppp.overrideAttrs (_: {
|
||||
patches = [
|
||||
./0003-Wait-for-ip-up-down-scripts.patch
|
||||
./0002-Call-scripts-with-the-same-environ-as-pppd.patch
|
||||
];
|
||||
});
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
environment.systemPackages = [
|
||||
pkgs.tcpdump
|
||||
];
|
||||
|
||||
services.ifstate = {
|
||||
enable = true;
|
||||
|
||||
settings = {
|
||||
interfaces = [
|
||||
{
|
||||
name = "wan";
|
||||
link = {
|
||||
kind = "physical";
|
||||
permaddr = "00:11:22:33:42:00";
|
||||
state = "up";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "internet";
|
||||
link = {
|
||||
kind = "vlan";
|
||||
link = "wan";
|
||||
vlan_id = 6;
|
||||
state = "up";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "www-br";
|
||||
link = {
|
||||
kind = "bridge";
|
||||
state = "up";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
services.pppoe-server.kpn = {
|
||||
interface = "internet";
|
||||
localAddress = "10.0.0.1";
|
||||
remoteAddressFile = pkgs.writeText "kpn-remote-address-file" ''
|
||||
10.67.15.1
|
||||
'';
|
||||
# ifUpScript = pkgs.writeShellScript "ppd-if-up" ''
|
||||
# ${getExe' pkgs.iproute2 "ip"} link set dev "$PPP_IFACE" master ppp-br
|
||||
# '';
|
||||
};
|
||||
|
||||
networking = {
|
||||
hostName = "jormungandr";
|
||||
useDHCP = false;
|
||||
firewall.enable = false;
|
||||
};
|
||||
|
||||
virtualisation.qemu.options = [
|
||||
"-net nic,model=e1000,macaddr=00:11:22:33:42:00,netdev=wan"
|
||||
"-netdev stream,id=wan,addr.type=unix,addr.path=../../../midgard/link"
|
||||
# "-netdev vde,id=wan,sock=../../../midgard/switch"
|
||||
];
|
||||
}
|
|
@ -1,21 +1,174 @@
|
|||
from test_driver.machine import Machine, StartCommand, NixStartScript
|
||||
from test_driver.logger import TerminalLogger
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
import os
|
||||
import sys
|
||||
import socket
|
||||
import subprocess
|
||||
import pty
|
||||
import time
|
||||
|
||||
hela_system = os.getenv("HELA_SYSTEM")
|
||||
client_system = os.getenv("CLIENT_SYSTEM")
|
||||
jormungandr_system = os.getenv("JORMUNGANDR_SYSTEM")
|
||||
interactive = os.getenv("ROUTER_INTERACTIVE")
|
||||
|
||||
def make_machine(out_dir: Path, tmp_dir: Path) -> Machine:
|
||||
class FileLogger(TerminalLogger):
|
||||
@staticmethod
|
||||
def _eprint(*args: object, **kwargs: Any) -> None:
|
||||
return
|
||||
|
||||
class NixStartScriptSetsid(NixStartScript):
|
||||
def run(
|
||||
self,
|
||||
state_dir: Path,
|
||||
shared_dir: Path,
|
||||
monitor_socket_path: Path,
|
||||
qmp_socket_path: Path,
|
||||
shell_socket_path: Path,
|
||||
allow_reboot: bool,
|
||||
) -> subprocess.Popen:
|
||||
return subprocess.Popen(
|
||||
self.cmd(
|
||||
monitor_socket_path, qmp_socket_path, shell_socket_path, allow_reboot
|
||||
),
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
shell=True,
|
||||
cwd=state_dir,
|
||||
env=self.build_environment(state_dir, shared_dir),
|
||||
)
|
||||
|
||||
def make_machine(*, system: Path, name: str, out_dir: Path | None = None, tmp_dir: Path | None = None) -> Machine:
|
||||
if out_dir is None:
|
||||
out_dir = Path(f"{name}/out")
|
||||
if tmp_dir is None:
|
||||
tmp_dir = Path(f"{name}/tmp")
|
||||
out_dir.mkdir(parents=True, exist_ok=True)
|
||||
tmp_dir.mkdir(parents=True, exist_ok=True)
|
||||
return Machine(
|
||||
out_dir = out_dir.absolute(),
|
||||
tmp_dir = tmp_dir.absolute(),
|
||||
start_command = NixStartScript(os.getenv("ROUTER_CMD") + "/bin/run-nixos-vm"),
|
||||
logger = TerminalLogger(),
|
||||
name = "router",
|
||||
start_command = NixStartScript(system + f"/bin/run-{name}-vm") if not interactive else NixStartScriptSetsid(system + f"/bin/run-{name}-vm"),
|
||||
logger = TerminalLogger() if not interactive else FileLogger(),
|
||||
name = name,
|
||||
keep_vm_state = True,
|
||||
)
|
||||
|
||||
router = make_machine(Path("router/out"), Path("router/tmp"))
|
||||
router.start()
|
||||
router.wait_for_unit("multi-user.target")
|
||||
router.shutdown()
|
||||
def vde_switch(control_socket: Path) -> subprocess.Popen:
|
||||
control_socket.mkdir(parents = True, exist_ok = True)
|
||||
pty_master, pty_slave = pty.openpty()
|
||||
return subprocess.Popen(
|
||||
["vde_switch", "-unix", str(control_socket.absolute()), "--dirmode", "0700"],
|
||||
stdin=pty_slave,
|
||||
)
|
||||
|
||||
def vde_plug_unix(path: Path, control_socket: Path, port: int | None = None) -> subprocess.Popen:
|
||||
port = f"-p {port}" if port is not None else ""
|
||||
return subprocess.Popen(
|
||||
["socat", f"UNIX-LISTEN:{path.absolute()}", f"EXEC:vde_plug {port} {control_socket.absolute()}"],
|
||||
stdin = subprocess.PIPE,
|
||||
stdout = subprocess.PIPE,
|
||||
stderr = subprocess.STDOUT,
|
||||
)
|
||||
|
||||
out_dir = Path(os.getenv("out"))
|
||||
def dump_to_out(path: str | Path, content: bytes):
|
||||
global out_dir
|
||||
|
||||
if not isinstance(path, Path):
|
||||
path = Path(path)
|
||||
|
||||
final_path = out_dir / path
|
||||
final_path.parent.mkdir(parents = True, exist_ok = True)
|
||||
|
||||
fh = open(final_path, "w")
|
||||
fh.write(content)
|
||||
fh.close()
|
||||
|
||||
vde_hel_control_path = Path("hel/switch")
|
||||
vde_hel = vde_switch(vde_hel_control_path)
|
||||
|
||||
vde_midgard_control_path = Path("midgard/switch")
|
||||
vde_midgard = vde_switch(vde_midgard_control_path)
|
||||
|
||||
# kpn_link = subprocess.Popen(
|
||||
# [
|
||||
# "socat",
|
||||
# f"UNIX-LISTEN:{Path('midgard/link.jormungandr').absolute()}",
|
||||
# f"UNIX-LISTEN:{Path('midgard/link.hela').absolute()}"
|
||||
# ]
|
||||
# )
|
||||
|
||||
time.sleep(0.5)
|
||||
|
||||
hela = make_machine(system = hela_system, name = "hela")
|
||||
hela.start()
|
||||
|
||||
time.sleep(0.5)
|
||||
|
||||
client = make_machine(system = client_system, name = "client")
|
||||
client.start()
|
||||
|
||||
jormungandr = make_machine(system = jormungandr_system, name = "jormungandr")
|
||||
jormungandr.start()
|
||||
|
||||
def finalize(exit_code: int) -> None:
|
||||
global hela, client, jormungandr, vde_hel, vde_midgard
|
||||
|
||||
# subprocess.run(["cp", "hela/tmp/vm-state-hela/xchg/tcpdump-dmz-log:0.log", out_dir / "hela-tcpdump-dmz-log:0.log"], check=True)
|
||||
# subprocess.run(["cp", "hela/tmp/vm-state-hela/xchg/tcpdump-dmz-log:1.log", out_dir / "hela-tcpdump-dmz-log:1.log"], check=True)
|
||||
|
||||
# subprocess.run(["cp", "jormungandr/tmp/vm-state-jormungandr/xchg/tcpdump-dmz-log:0.log", out_dir / "jormungandr-tcpdump-dmz-log:0.log"], check=True)
|
||||
# subprocess.run(["cp", "jormungandr/tmp/vm-state-jormungandr/xchg/tcpdump-dmz-log:1.log", out_dir / "jormungandr-tcpdump-dmz-log:1.log"], check=True)
|
||||
|
||||
hela.shutdown()
|
||||
client.shutdown()
|
||||
jormungandr.shutdown()
|
||||
|
||||
vde_hel.terminate()
|
||||
vde_midgard.terminate()
|
||||
|
||||
vde_hel.wait()
|
||||
vde_midgard.wait()
|
||||
|
||||
sys.exit(exit_code)
|
||||
|
||||
try:
|
||||
if interactive:
|
||||
import ptpython
|
||||
|
||||
ptpython.repl.embed(globals(), locals())
|
||||
else:
|
||||
hela.wait_for_unit("multi-user.target")
|
||||
client.wait_for_unit("multi-user.target")
|
||||
jormungandr.wait_for_unit("multi-user.target")
|
||||
|
||||
# hela.wait_until_succeeds("ip netns exec dmz bash -c $'[ $(ip -f inet addr show ppp0 | sed -En -e \\'s/.*inet ([0-9.]+).*/\\1/p\\' | wc -l) -gt 0 ]'")
|
||||
|
||||
dump_to_out("client-default-route", client.succeed("ip route"))
|
||||
dump_to_out("hela-default-route", hela.succeed("ip route"))
|
||||
dump_to_out("hela-dmz-route", hela.succeed("ip netns exec dmz ip route"))
|
||||
|
||||
dump_to_out("client-default-if", client.succeed("ip addr"))
|
||||
dump_to_out("hela-default-if", hela.succeed("ip addr"))
|
||||
dump_to_out("hela-dmz-if", hela.succeed("ip netns exec dmz ip addr"))
|
||||
|
||||
client.succeed("ping -c 1 10.10.0.1")
|
||||
hela.succeed("ping -c 1 10.10.0.2")
|
||||
|
||||
hela.succeed("ip netns exec dmz ping -c 1 10.0.0.1")
|
||||
jormungandr.fail("ping -W 1 -c 1 10.67.15.1")
|
||||
|
||||
# client.succeed("ping -c 1 10.0.0.1")
|
||||
|
||||
# hela.succeed("systemd-run -u tcpdump-dmz-wan -p StandardOutput=append:/tmp/xchg/tcpdump-dmz-log:0.log -p StandardError=append:/tmp/xchg/tcpdump-dmz-log:1.log ip netns exec dmz tcpdump -i internet")
|
||||
# jormungandr.succeed("systemd-run -u tcpdump-dmz-wan -p StandardOutput=append:/tmp/xchg/tcpdump-dmz-log:0.log -p StandardError=append:/tmp/xchg/tcpdump-dmz-log:1.log tcpdump -i internet")
|
||||
|
||||
except Exception as err:
|
||||
print(err)
|
||||
|
||||
finalize(1)
|
||||
|
||||
finalize(0)
|
||||
|
|
Loading…
Reference in a new issue