Compare commits

...
Sign in to create a new pull request.

21 commits

Author SHA1 Message Date
sinavir
3b7662e45a
feat(ap): init ap-dev
All checks were successful
Run pre-commit on all files / pre-commit (push) Successful in 22s
2025-02-20 01:06:56 +01:00
sinavir
e8d446d2b0
feat(hive): Add more personalisation for liminix hosts 2025-02-11 16:51:15 +01:00
sinavir
11391dc4f2
feat(ap-v01): Add usteer
Some checks failed
Check meta / check_dns (pull_request) Successful in 16s
Check meta / check_meta (pull_request) Successful in 16s
Build all the nodes / ap01 (pull_request) Failing after 18s
Build all the nodes / netcore02 (pull_request) Successful in 21s
Check workflows / check_workflows (pull_request) Failing after 29s
Run pre-commit on all files / pre-commit (push) Successful in 41s
Build the shell / build-shell (pull_request) Successful in 37s
Run pre-commit on all files / pre-commit (pull_request) Successful in 38s
Build all the nodes / hypervisor03 (pull_request) Successful in 1m42s
Build all the nodes / rescue01 (pull_request) Successful in 1m47s
Build all the nodes / geo01 (pull_request) Successful in 2m31s
Build all the nodes / hypervisor02 (pull_request) Successful in 2m43s
Build all the nodes / hypervisor01 (pull_request) Successful in 2m47s
Build all the nodes / build01 (pull_request) Successful in 2m51s
Build all the nodes / bridge01 (pull_request) Successful in 2m54s
Build all the nodes / geo02 (pull_request) Successful in 3m4s
Build all the nodes / web01 (pull_request) Successful in 2m50s
Build all the nodes / vault01 (pull_request) Successful in 2m53s
Build all the nodes / storage01 (pull_request) Successful in 3m11s
Build all the nodes / web02 (pull_request) Successful in 3m1s
Build all the nodes / web03 (pull_request) Successful in 3m3s
Build all the nodes / compute01 (pull_request) Successful in 3m31s
Build all the nodes / tower01 (pull_request) Successful in 4m14s
2025-02-10 09:44:44 +01:00
0c3062a5c5
refactor(liminix): Refactor liminix meta nodes
Some checks failed
Check meta / check_meta (pull_request) Successful in 15s
Check meta / check_dns (pull_request) Successful in 16s
Check workflows / check_workflows (pull_request) Failing after 16s
Build all the nodes / netcore02 (pull_request) Successful in 21s
Run pre-commit on all files / pre-commit (push) Successful in 27s
Build all the nodes / ap01 (pull_request) Failing after 31s
Build the shell / build-shell (pull_request) Successful in 24s
Run pre-commit on all files / pre-commit (pull_request) Successful in 24s
Build all the nodes / hypervisor03 (pull_request) Successful in 1m54s
Build all the nodes / bridge01 (pull_request) Successful in 1m55s
Build all the nodes / tower01 (pull_request) Successful in 1m54s
Build all the nodes / rescue01 (pull_request) Successful in 1m57s
Build all the nodes / build01 (pull_request) Successful in 2m44s
Build all the nodes / hypervisor02 (pull_request) Successful in 2m47s
Build all the nodes / storage01 (pull_request) Successful in 3m1s
Build all the nodes / hypervisor01 (pull_request) Successful in 3m9s
Build all the nodes / geo02 (pull_request) Successful in 3m11s
Build all the nodes / geo01 (pull_request) Successful in 3m41s
Build all the nodes / vault01 (pull_request) Successful in 3m40s
Build all the nodes / web03 (pull_request) Successful in 3m29s
Build all the nodes / compute01 (pull_request) Successful in 3m46s
Build all the nodes / web01 (pull_request) Successful in 3m45s
Build all the nodes / web02 (pull_request) Successful in 3m39s
2025-02-06 11:02:44 +01:00
sinavir
099fc058c8
feat(npins/liminix): Update
Some checks failed
Check meta / check_dns (pull_request) Successful in 16s
Check meta / check_meta (pull_request) Successful in 16s
Build all the nodes / ap01 (pull_request) Failing after 23s
Build all the nodes / netcore02 (pull_request) Successful in 23s
Run pre-commit on all files / pre-commit (push) Successful in 26s
Check workflows / check_workflows (pull_request) Failing after 29s
Build the shell / build-shell (pull_request) Successful in 28s
Run pre-commit on all files / pre-commit (pull_request) Successful in 41s
Build all the nodes / build01 (pull_request) Successful in 1m33s
Build all the nodes / hypervisor01 (pull_request) Successful in 1m38s
Build all the nodes / rescue01 (pull_request) Successful in 1m40s
Build all the nodes / tower01 (pull_request) Successful in 1m42s
Build all the nodes / bridge01 (pull_request) Successful in 1m43s
Build all the nodes / geo01 (pull_request) Successful in 1m47s
Build all the nodes / hypervisor03 (pull_request) Successful in 1m57s
Build all the nodes / geo02 (pull_request) Successful in 2m3s
Build all the nodes / hypervisor02 (pull_request) Successful in 2m6s
Build all the nodes / storage01 (pull_request) Successful in 2m5s
Build all the nodes / web02 (pull_request) Successful in 1m46s
Build all the nodes / web03 (pull_request) Successful in 1m45s
Build all the nodes / vault01 (pull_request) Successful in 1m55s
Build all the nodes / compute01 (pull_request) Successful in 2m26s
Build all the nodes / web01 (pull_request) Successful in 2m23s
This brings cosmetic stuff
2025-02-04 23:38:57 +01:00
sinavir
d0ac1b673e
feat(ap-v01): Use static address for admin vlan 2025-02-04 23:38:57 +01:00
9a4f9c2ca3
feat(ap01): WIP 2025-02-04 23:25:57 +01:00
sinavir
c9dc36ed08
feat(scripts): Add zyxel exploit script
All checks were successful
Check meta / check_meta (pull_request) Successful in 15s
Check meta / check_dns (pull_request) Successful in 15s
Run pre-commit on all files / pre-commit (push) Successful in 24s
Check workflows / check_workflows (pull_request) Successful in 25s
Build all the nodes / netcore02 (pull_request) Successful in 29s
Build all the nodes / ap01 (pull_request) Successful in 41s
Build the shell / build-shell (pull_request) Successful in 26s
Run pre-commit on all files / pre-commit (pull_request) Successful in 23s
Build all the nodes / hypervisor02 (pull_request) Successful in 1m46s
Build all the nodes / hypervisor01 (pull_request) Successful in 1m47s
Build all the nodes / hypervisor03 (pull_request) Successful in 2m6s
Build all the nodes / build01 (pull_request) Successful in 2m12s
Build all the nodes / bridge01 (pull_request) Successful in 2m15s
Build all the nodes / tower01 (pull_request) Successful in 2m15s
Build all the nodes / web02 (pull_request) Successful in 1m54s
Build all the nodes / geo02 (pull_request) Successful in 2m19s
Build all the nodes / web03 (pull_request) Successful in 1m52s
Build all the nodes / storage01 (pull_request) Successful in 2m26s
Build all the nodes / rescue01 (pull_request) Successful in 2m35s
Build all the nodes / vault01 (pull_request) Successful in 2m23s
Build all the nodes / geo01 (pull_request) Successful in 2m40s
Build all the nodes / web01 (pull_request) Successful in 2m31s
Build all the nodes / compute01 (pull_request) Successful in 2m59s
2025-02-03 13:30:03 +01:00
sinavir
6fffa8eb13
feat(ap01/lavitate): Add admin vlan dhcp in levitation
All checks were successful
Check meta / check_dns (pull_request) Successful in 15s
Check meta / check_meta (pull_request) Successful in 15s
Check workflows / check_workflows (pull_request) Successful in 16s
Run pre-commit on all files / pre-commit (push) Successful in 23s
Build all the nodes / netcore02 (pull_request) Successful in 21s
Build the shell / build-shell (pull_request) Successful in 24s
Build all the nodes / ap01 (pull_request) Successful in 1m15s
Run pre-commit on all files / pre-commit (pull_request) Successful in 23s
Build all the nodes / geo02 (pull_request) Successful in 1m25s
Build all the nodes / bridge01 (pull_request) Successful in 2m28s
Build all the nodes / geo01 (pull_request) Successful in 2m48s
Build all the nodes / compute01 (pull_request) Successful in 2m57s
Build all the nodes / storage01 (pull_request) Successful in 2m44s
Build all the nodes / web02 (pull_request) Successful in 2m42s
Build all the nodes / tower01 (pull_request) Successful in 2m45s
Build all the nodes / build01 (pull_request) Successful in 3m3s
Build all the nodes / hypervisor02 (pull_request) Successful in 2m53s
Build all the nodes / hypervisor01 (pull_request) Successful in 2m55s
Build all the nodes / web03 (pull_request) Successful in 2m49s
Build all the nodes / rescue01 (pull_request) Successful in 3m4s
Build all the nodes / vault01 (pull_request) Successful in 3m8s
Build all the nodes / hypervisor03 (pull_request) Successful in 3m23s
Build all the nodes / web01 (pull_request) Successful in 3m32s
Else we would need to change the switch config when rebuilding the AP
2025-02-03 12:47:59 +01:00
sinavir
8a9e5c16a5
fix(ap01/levitate): Add iproute to levitated system else we don't have the network 2025-02-03 12:47:54 +01:00
sinavir
69ebe92e2c
feat: Add TODO before release
All checks were successful
Check meta / check_meta (pull_request) Successful in 16s
Check workflows / check_workflows (pull_request) Successful in 17s
Check meta / check_dns (pull_request) Successful in 20s
Build all the nodes / ap01 (pull_request) Successful in 33s
Build all the nodes / netcore02 (pull_request) Successful in 34s
Run pre-commit on all files / pre-commit (push) Successful in 39s
Build the shell / build-shell (pull_request) Successful in 49s
Build all the nodes / hypervisor01 (pull_request) Successful in 1m31s
Build all the nodes / rescue01 (pull_request) Successful in 1m40s
Build all the nodes / web02 (pull_request) Successful in 1m41s
Build all the nodes / storage01 (pull_request) Successful in 2m4s
Build all the nodes / geo01 (pull_request) Successful in 2m7s
Build all the nodes / geo02 (pull_request) Successful in 2m12s
Build all the nodes / bridge01 (pull_request) Successful in 2m17s
Build all the nodes / build01 (pull_request) Successful in 2m19s
Build all the nodes / hypervisor02 (pull_request) Successful in 2m19s
Build all the nodes / tower01 (pull_request) Successful in 2m18s
Build all the nodes / hypervisor03 (pull_request) Successful in 2m26s
Build all the nodes / compute01 (pull_request) Successful in 2m40s
Build all the nodes / vault01 (pull_request) Successful in 2m27s
Build all the nodes / web03 (pull_request) Successful in 2m10s
Build all the nodes / web01 (pull_request) Successful in 2m50s
Run pre-commit on all files / pre-commit (pull_request) Successful in 24s
2025-01-31 17:41:15 +01:00
sinavir
966e1ed038
fix(ap01/radius-secret): Use environment variable for radius secret
This is a hack, please fix it in the next iteration of the project
2025-01-31 17:35:31 +01:00
sinavir
8b25a202c1
feat(ap01/ssid): Same SSID everywhere 2025-01-30 00:34:04 +01:00
sinavir
4991f19111
feat(ap01/networking): Enable dynamic vlans and drop useless bridge 2025-01-30 00:34:04 +01:00
sinavir
b21712efb4
fix(LICENSE): Add license information 2025-01-30 00:34:04 +01:00
1a06074607
chore(machines/ap01/recovery): better scope for pkgs and add zyxel-bootconfig to levitation
This is useful to reconfigure A/B in memory.

Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2025-01-30 00:34:04 +01:00
94201ea7d0
feat(scripts/liminix): add a basic liminix rebuild
This script requires manual efforts on the operator end not to fuck up
too hard.

This adds min-copy-closure and min-garbage-collect to the development
shell.

Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2025-01-30 00:34:04 +01:00
31488162d6
feat(scripts/liminix): make it easy to extract the firmware part of the Zyxel NWA FIT image
This is useful when reflashing the system from scratch in the levitation
mode.

Note that doing this will reset the UBI counter to zero, this is bad for
wear leveling.

Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2025-01-30 00:34:04 +01:00
c86e1ec669
feat(machines/ap01/recovery): pass the parent hostname with live indicator
This makes the experience nicer.

Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2025-01-30 00:34:04 +01:00
ad3cd0871a
feat(machines/ap01/recovery): fix levitation dependencies
We should use the right DHCPv4.

Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2025-01-30 00:34:04 +01:00
af966bc6d1
feat(machines/ap01): add default VLAN and admin VLAN
Put DHCPv4 on the default VLAN now.

Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2025-01-30 00:34:04 +01:00
33 changed files with 832 additions and 201 deletions

View file

@ -187,11 +187,17 @@ in
}))
pkgs.npins
pkgs.rage
# SSO testing
pkgs.kanidm
pkgs.freeradius
pkgs.picocom # for serial access
# Daemon-less copy closure for Liminix systems.
(pkgs.callPackage (sources.liminix + "/pkgs/min-copy-closure") { nix = pkgs.lix; })
# Daemon-less garbage collection for Liminix systems.
(pkgs.callPackage (sources.liminix + "/pkgs/min-collect-garbage") { nix = pkgs.lix; })
(pkgs.callPackage ./lib/colmena {
colmena = pkgs.callPackage "${sources.colmena}/package.nix" { };
})

View file

@ -83,7 +83,7 @@ let
meta = (import ./meta) lib;
nodeMeta = meta.nodes.${node};
nodePath = "machines/${category node}/${node}";
nodePath = "machines/${category node}/${nodeMeta.nodeDir}";
};
in

View file

@ -0,0 +1,46 @@
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
#
# SPDX-License-Identifier: EUPL-1.2
{
modulesPath,
sourcePkgs,
name,
...
}:
{
imports = [
"${modulesPath}/wlan.nix"
"${modulesPath}/network"
"${modulesPath}/hostapd"
"${modulesPath}/usteer"
"${modulesPath}/ssh"
"${modulesPath}/ntp"
"${modulesPath}/vlan"
"${modulesPath}/bridge"
"${modulesPath}/jitter-rng"
"${modulesPath}/pki"
"${modulesPath}/ubus"
# System-level configuration
./system.nix
# Configures our own WLAN.
./wlan.nix
# Configures our IPv4/IPv6 addresses, e.g. DHCPv4 on VLAN 0, SLAAC on VLAN 3001.
./addresses.nix
# Configures a basic local DNS.
./dns.nix
# Configures our management layer, e.g. SSH server + DGNum FAI keys.
./management.nix
# Configures our recovery system, e.g. a levitation script.
./recovery.nix
# ubus
./ipc.nix
# Metadata on the system for field recovery.
./metadata.nix
# TODO: god that's so a fucking hack.
(import "${modulesPath}/../devices/zyxel-nwa50ax").module
];
hostname = name;
nixpkgs.source = sourcePkgs.path;
}

View file

@ -0,0 +1,27 @@
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
#
# SPDX-License-Identifier: EUPL-1.2
{ config, nodeMeta, ... }:
let
svc = config.system.service;
inherit (nodeMeta.extraNodeSettings) ap-no;
adminIp = "192.168.1.${builtins.toString (ap-no + 10)}";
in
{
# Our bridging is a bit complicated, therefore, we need iproute2.
programs.iproute2.enable = true;
services.admin-ip = svc.network.address.build {
interface = config.hardware.networkInterfaces.lan;
address = adminIp;
prefixLength = 24;
family = "inet";
};
services.admin-defaultroute4 = svc.network.route.build {
via = "192.168.1.254";
target = "default";
dependencies = [ config.services.admin-ip ];
};
}

View file

@ -0,0 +1,25 @@
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
#
# SPDX-License-Identifier: EUPL-1.2
{ pkgs, lib, ... }:
let
inherit (pkgs.pseudofile) dir symlink;
# TODO: imho, DNS should be static and provided by the router?
dns = [
"8.8.8.8"
"8.8.4.4"
"1.0.0.1"
];
resolvconf = pkgs.writeText "resolv.conf" (
lib.concatMapStringsSep "\n" (dns: ''echo "nameserver ${dns}" >> resolv.conf'') dns
);
in
{
# TODO: support dynamic reconfiguration once we are in the target VLAN?
filesystem = dir {
etc = dir {
"resolv.conf" = symlink "${resolvconf}";
};
};
}

View file

@ -10,6 +10,7 @@ in
# SSH keys are handled by the access control module.
dgn-access-control.enable = true;
users.root = {
# TODO: Change this well-known password
passwd = "$6$Z2MiaMXkpUJRPl2/$fxVE3iD/n208CISM2F6OnWj0Qq0QG2tTQqLCjU80PFJJGIwNLLyOp6SeYH3dH20OvJX1loZRETrThZfIPw.rb/";
};
services.sshd = svc.ssh.build { allowRoot = true; };

View file

@ -0,0 +1,53 @@
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
#
# SPDX-License-Identifier: EUPL-1.2
{
config,
pkgs,
modulesPath,
...
}:
let
parentConfig = config;
in
{
defaultProfile.packages = [
# Levitate enable us to mass-reinstall the system on the fly.
# TODO: Test levitation
(pkgs.levitate.override {
config = {
imports = [
"${modulesPath}/network"
"${modulesPath}/ssh"
"${modulesPath}/hardware.nix"
"${modulesPath}/kernel"
"${modulesPath}/outputs/tftpboot.nix"
"${modulesPath}/outputs.nix"
# FIXME: DHCP has a hidden deps on this, shoud be done in a more intelligent way upstream
"${modulesPath}/iproute2.nix"
(_: {
# FIXME: DHCP has a hidden deps on this, shoud be done in a more intelligent way upstream
programs.iproute2.enable = true;
services = {
inherit (parentConfig.services)
sshd
admin-ip
admin-defaultroute4
;
};
})
];
hostname = "${parentConfig.hostname}-live";
nixpkgs.buildPlatform = builtins.currentSystem;
defaultProfile.packages = with pkgs; [
mtdutils
zyxel-bootconfig
];
# Only keep root, which should inherit from DGN access control's root permissions.
users.root = config.users.root;
};
})
];
}

View file

@ -0,0 +1,34 @@
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
#
# SPDX-License-Identifier: EUPL-1.2
{ pkgs, config, ... }:
let
svc = config.system.service;
in
{
# Get moar random please
services = {
jitter = svc.jitter-rng.build { };
packet_forwarding = svc.network.forward.build { };
ntp = config.system.service.ntp.build {
pools = {
"pool.ntp.org" = [ "iburst" ];
};
dependencies = [ config.services.jitter ];
};
};
boot.tftp = {
serverip = "192.0.2.10";
ipaddr = "192.0.2.12";
};
defaultProfile.packages = with pkgs; [
zyxel-bootconfig
iw
min-collect-garbage
ubus
];
}

View file

@ -2,14 +2,28 @@
#
# SPDX-License-Identifier: EUPL-1.2
{ config, pkgs, ... }:
{
config,
pkgs,
lib,
nodeMeta,
...
}:
let
svc = config.system.service;
inherit (nodeMeta.extraNodeSettings) ap-no;
hex = x: lib.fixedWidthString 2 "0" (lib.toHexString x);
mac-1 = "02:5B:6B:00:00:${hex ap-no}";
mac-2 = "02:5B:6B:01:00:${hex ap-no}";
secrets-1 = {
ssid = "DGNum 2G (N)";
ssid = "DGNum";
};
secrets-2 = {
ssid = "DGNum 5G (AX)";
ssid = "DGNum";
};
baseParams = {
country_code = "FR";
@ -22,6 +36,9 @@ let
wpa = 2;
wpa_pairwise = "TKIP CCMP";
rsn_pairwise = "CCMP";
bss_transition = 1;
rrm_neighbor_report = 1;
rrm_beacon_report = 1;
};
radiusKeyMgmt = {
@ -42,7 +59,7 @@ let
vht_capab = "[MAX-MPDU-7991][SU-BEAMFORMEE][SU-BEAMFORMER][RXLDPC][SHORT-GI-80][MAX-A-MPDU-LEN-EXP3][RX-ANTENNA-PATTERN][TX-ANTENNA-PATTERN][TX-STBC-2BY1][RX-STBC-1][MU-BEAMFORMER]";
vht_oper_chwidth = 1;
he_oper_chwidth = 1;
channel = 36;
channel = 36; # TODO understand interferences
vht_oper_centr_freq_seg0_idx = 42;
he_oper_centr_freq_seg0_idx = 42;
require_vht = 1;
@ -52,7 +69,7 @@ let
ieee8021x = 1;
eapol_version = 2;
use_pae_group_addr = 1;
dynamic_vlan = 0;
dynamic_vlan = 3;
vlan_tagged_interface = "lan";
};
@ -64,7 +81,14 @@ let
# No DNS here, hostapd do not support this mode.
auth_server_addr = "129.199.195.129";
auth_server_port = 1812;
auth_server_shared_secret = "read it online";
auth_server_shared_secret =
let
secret = builtins.getEnv "RADIUS_SECRET";
in
if secret == "" then
lib.warn "Using a dummy RADIUS secret. Please do not use in production" "DUMMYSECRET"
else
secret;
};
mkWifiSta =
@ -77,10 +101,22 @@ let
};
in
{
hardware.wlanMacAddresses = {
wlan0 = mac-1;
wlan1 = mac-2;
};
services = {
usteer = svc.usteer.build {
ifname = "lan";
dependencies = [
# TODO is it the right stuff to deend on ?
config.services.hostap-1-ready
config.services.hostap-2-ready
];
};
# wlan0 is the 2.4GHz interface.
hostap-1 = mkWifiSta (
baseParams // radiusKeyMgmt
baseParams // clientRadius // externalRadius // radiusKeyMgmt
) config.hardware.networkInterfaces.wlan0 secrets-1;
hostap-1-ready = svc.hostapd-ready.build {
interface = config.hardware.networkInterfaces.wlan0;

View file

@ -5,6 +5,7 @@
{
modulesPath,
sourcePkgs,
name,
...
}:
{
@ -12,6 +13,7 @@
"${modulesPath}/wlan.nix"
"${modulesPath}/network"
"${modulesPath}/hostapd"
"${modulesPath}/usteer"
"${modulesPath}/ssh"
"${modulesPath}/ntp"
"${modulesPath}/vlan"
@ -29,6 +31,8 @@
./addresses.nix
# Configures a basic local DNS.
./dns.nix
# Add ubus daemon
./ipc.nix
# Configures our management layer, e.g. SSH server + DGNum FAI keys.
./management.nix
# Configures our recovery system, e.g. a levitation script.
@ -39,6 +43,6 @@
(import "${modulesPath}/../devices/zyxel-nwa50ax").module
];
hostname = "ap01-prototype";
hostname = name;
nixpkgs.source = sourcePkgs.path;
}

View file

@ -0,0 +1,25 @@
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
#
# SPDX-License-Identifier: EUPL-1.2
{ config, nodeMeta, ... }:
let
svc = config.system.service;
inherit (nodeMeta.extraNodeSettings) building floor ap-no;
# FIXME switch to ipv6 tu be able to scale
adminIp = "10.0.253.${builtins.toString (ap-no + floor * 8 + building * 32 + 2)}";
in
{
services.admin-ip = svc.network.address.build {
interface = config.services.admin-vlan;
address = adminIp;
prefixLength = 24;
family = "inet";
};
services.admin-defaultroute4 = svc.network.route.build {
via = "10.0.253.1";
target = "default";
dependencies = [ config.services.admin-ip ];
};
}

View file

@ -0,0 +1,25 @@
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
#
# SPDX-License-Identifier: EUPL-1.2
{ pkgs, lib, ... }:
let
inherit (pkgs.pseudofile) dir symlink;
# TODO: imho, DNS should be static and provided by the router?
dns = [
"8.8.8.8"
"8.8.4.4"
"1.0.0.1"
];
resolvconf = pkgs.writeText "resolv.conf" (
lib.concatMapStringsSep "\n" (dns: ''echo "nameserver ${dns}" >> resolv.conf'') dns
);
in
{
# TODO: support dynamic reconfiguration once we are in the target VLAN?
filesystem = dir {
etc = dir {
"resolv.conf" = symlink "${resolvconf}";
};
};
}

View file

@ -0,0 +1,12 @@
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
#
# SPDX-License-Identifier: EUPL-1.2
{ config, ... }:
let
svc = config.system.service;
in
{
# ubus socket for various needs.
services.ubus = svc.ubus.build { };
}

View file

@ -0,0 +1,20 @@
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
#
# SPDX-License-Identifier: EUPL-1.2
{ config, ... }:
let
svc = config.system.service;
in
{
# Our bridging is a bit complicated, therefore, we need iproute2.
programs.iproute2.enable = true;
services = {
admin-vlan = svc.vlan.build {
ifname = "admin";
primary = config.hardware.networkInterfaces.lan;
vid = "3001";
};
};
}

View file

@ -0,0 +1,17 @@
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
#
# SPDX-License-Identifier: EUPL-1.2
{ config, ... }:
let
svc = config.system.service;
in
{
# SSH keys are handled by the access control module.
dgn-access-control.enable = true;
users.root = {
# TODO: Change this well-known password
passwd = "$6$Z2MiaMXkpUJRPl2/$fxVE3iD/n208CISM2F6OnWj0Qq0QG2tTQqLCjU80PFJJGIwNLLyOp6SeYH3dH20OvJX1loZRETrThZfIPw.rb/";
};
services.sshd = svc.ssh.build { allowRoot = true; };
}

View file

@ -0,0 +1,19 @@
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
#
# SPDX-License-Identifier: EUPL-1.2
{ pkgs, ... }:
let
inherit (pkgs.pseudofile) dir;
in
{
filesystem = dir {
etc = dir {
"nixpkgs.version" = {
type = "f";
file = "${pkgs.lib.version}";
mode = "0444";
};
};
};
}

View file

@ -0,0 +1,68 @@
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
#
# SPDX-License-Identifier: EUPL-1.2
{
config,
pkgs,
modulesPath,
...
}:
let
svc = config.system.service;
parentConfig = config;
in
{
defaultProfile.packages = [
# Levitate enable us to mass-reinstall the system on the fly.
# TODO: Test levitation
(pkgs.levitate.override {
config = {
imports = [
"${modulesPath}/network"
"${modulesPath}/ssh"
"${modulesPath}/hardware.nix"
"${modulesPath}/kernel"
"${modulesPath}/outputs/tftpboot.nix"
"${modulesPath}/outputs.nix"
# FIXME: DHCP has a hidden deps on this, shoud be done in a more intelligent way upstream
"${modulesPath}/iproute2.nix"
(
{ config, ... }:
{
# FIXME: DHCP has a hidden deps on this, shoud be done in a more intelligent way upstream
programs.iproute2.enable = true;
services = {
# In this situation, we fallback to the appro VLAN but keep admin vlan.
# Simplest DHCPv4 we can find.
dhcpv4 = svc.network.dhcp.client.build {
interface = parentConfig.hardware.networkInterfaces.lan;
};
inherit (parentConfig.services)
sshd
admin-vlan
admin-ip
admin-defaultroute4
;
defaultroute4 = svc.network.route.build {
via = "$(output ${config.services.dhcpv4} router)";
target = "default";
dependencies = [ config.services.dhcpv4 ];
};
};
}
)
];
hostname = "${parentConfig.hostname}-live";
nixpkgs.buildPlatform = builtins.currentSystem;
defaultProfile.packages = with pkgs; [
mtdutils
zyxel-bootconfig
];
# Only keep root, which should inherit from DGN access control's root permissions.
users.root = config.users.root;
};
})
];
}

View file

@ -0,0 +1,131 @@
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
#
# SPDX-License-Identifier: EUPL-1.2
{
config,
pkgs,
lib,
nodeMeta,
...
}:
let
svc = config.system.service;
inherit (nodeMeta.extraNodeSettings) building floor ap-no;
hex = x: lib.fixedWidthString 2 "0" (lib.toHexString x);
mac-1 = "02:5B:6A:${hex (building * 4)}:${hex floor}:${hex ap-no}";
mac-2 = "02:5B:6A:${hex (building * 4 + 1)}:${hex floor}:${hex ap-no}";
secrets-1 = {
ssid = "DGNum 2G";
};
secrets-2 = {
ssid = "DGNum 5G";
};
baseParams = {
country_code = "FR";
hw_mode = "g";
channel = 6;
wmm_enabled = 1;
ieee80211n = 1;
ht_capab = "[LDPC][GF][HT40-][HT40+][SHORT-GI-40][MAX-AMSDU-7935][TX-STBC]";
auth_algs = 1;
wpa = 2;
wpa_pairwise = "TKIP CCMP";
rsn_pairwise = "CCMP";
};
radiusKeyMgmt = {
wpa_key_mgmt = "WPA-EAP";
};
modernParams = {
hw_mode = "a";
he_su_beamformer = 1;
he_su_beamformee = 1;
he_mu_beamformer = 1;
preamble = 1;
# Allow radar detection.
ieee80211d = 1;
ieee80211h = 1;
ieee80211ac = 1;
ieee80211ax = 1;
vht_capab = "[MAX-MPDU-7991][SU-BEAMFORMEE][SU-BEAMFORMER][RXLDPC][SHORT-GI-80][MAX-A-MPDU-LEN-EXP3][RX-ANTENNA-PATTERN][TX-ANTENNA-PATTERN][TX-STBC-2BY1][RX-STBC-1][MU-BEAMFORMER]";
vht_oper_chwidth = 1;
he_oper_chwidth = 1;
channel = 36; # TODO understand interferences
vht_oper_centr_freq_seg0_idx = 42;
he_oper_centr_freq_seg0_idx = 42;
require_vht = 1;
};
clientRadius = {
ieee8021x = 1;
eapol_version = 2;
use_pae_group_addr = 1;
dynamic_vlan = 3;
vlan_tagged_interface = "lan";
};
externalRadius = {
# TODO: when we have proper IPAM, set the right value here.
own_ip_addr = "127.0.0.1";
nas_identifier = "ap01.dgnum.eu";
# No DNS here, hostapd do not support this mode.
auth_server_addr = "129.199.195.129";
auth_server_port = 1812;
auth_server_shared_secret =
let
secret = builtins.getEnv "RADIUS_SECRET";
in
if secret == "" then
lib.warn "Using a dummy RADIUS secret. Please do not use in production" "DUMMYSECRET"
else
secret;
};
mkWifiSta =
params: interface: secrets:
svc.hostapd.build {
inherit interface;
package = pkgs.hostapd-radius;
params = params // secrets;
dependencies = [ config.services.jitter ];
};
in
{
hardware.wlanMacAddresses = {
wlan0 = mac-1;
wlan1 = mac-2;
};
services = {
# wlan0 is the 2.4GHz interface.
hostap-1 = mkWifiSta (
baseParams // clientRadius // externalRadius // radiusKeyMgmt
) config.hardware.networkInterfaces.wlan0 secrets-1;
hostap-1-ready = svc.hostapd-ready.build {
interface = config.hardware.networkInterfaces.wlan0;
};
# wlan1 is the 5GHz interface, e.g. AX capable.
hostap-2 = mkWifiSta (
baseParams // clientRadius // externalRadius // radiusKeyMgmt // modernParams
) config.hardware.networkInterfaces.wlan1 secrets-2;
# Oneshot that waits until the hostapd has set the interface in operational state.
hostap-2-ready = svc.hostapd-ready.build {
interface = config.hardware.networkInterfaces.wlan1;
};
usteer = svc.usteer.build {
ifname = "lan";
dependencies = with config.services; [
# FIXME: is it the right stuff to depend on
hostap-1-ready
hostap-2-ready
admin-defaultroute4
];
};
};
}

View file

@ -1,22 +0,0 @@
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
#
# SPDX-License-Identifier: EUPL-1.2
{ config, ... }:
let
svc = config.system.service;
in
{
services.dhcpv4 = svc.network.dhcp.client.build {
interface = config.services.int;
dependencies = [
config.services.bridge.components.lan
];
};
services.defaultroute4 = svc.network.route.build {
via = "$(output ${config.services.dhcpv4} router)";
target = "default";
dependencies = [ config.services.dhcpv4 ];
};
}

View file

@ -1,34 +0,0 @@
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
#
# SPDX-License-Identifier: EUPL-1.2
{ config, pkgs, ... }:
let
inherit (pkgs.liminix.services) oneshot;
inherit (pkgs.pseudofile) dir symlink;
inherit (pkgs) serviceFns;
in
{
# TODO: support dynamic reconfiguration once we are in the target VLAN?
services.resolvconf = oneshot rec {
name = "resolvconf";
up = ''
. ${serviceFns}
( in_outputs ${name}
for i in $(output ${config.services.dhcpv4} dns); do
echo "nameserver $i" >> resolv.conf
done
)
'';
dependencies = [
config.services.dhcpv4
];
};
filesystem = dir {
etc = dir {
"resolv.conf" = symlink "${config.services.resolvconf}/.outputs/resolv.conf";
};
};
}

View file

@ -1,43 +0,0 @@
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
#
# SPDX-License-Identifier: EUPL-1.2
{ config, ... }:
let
svc = config.system.service;
in
{
services.int = svc.bridge.primary.build {
ifname = "int";
macAddressFromInterface = config.hardware.networkInterfaces.lan;
};
services.bridge = svc.bridge.members.build {
primary = config.services.int;
members = {
lan.member = config.hardware.networkInterfaces.lan;
wlan0 = {
member = config.hardware.networkInterfaces.wlan0;
# Bridge only once hostapd is ready.
dependencies = [ config.services.hostap-1-ready ];
};
wlan1 = {
member = config.hardware.networkInterfaces.wlan1;
# Bridge only once hostapd is ready.
dependencies = [ config.services.hostap-2-ready ];
};
};
};
# Default VLAN
# services.vlan-apro = svc.vlan.build {
# vlanId = 0;
# interface = config.services.int;
# };
# # Administration VLAN
# services.vlan-admin = svc.vlan.build {
# vlan = 3001;
# interface = config.services.int;
# };
}

View file

@ -1,49 +0,0 @@
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
#
# SPDX-License-Identifier: EUPL-1.2
{
config,
pkgs,
modulesPath,
...
}:
let
svc = config.system.service;
in
{
defaultProfile.packages = with pkgs; [
# Levitate enable us to mass-reinstall the system on the fly.
(levitate.override {
config = {
imports = [
"${modulesPath}/network"
"${modulesPath}/ssh"
"${modulesPath}/hardware.nix"
"${modulesPath}/kernel"
"${modulesPath}/outputs/tftpboot.nix"
"${modulesPath}/outputs.nix"
];
nixpkgs.buildPlatform = builtins.currentSystem;
services = {
# In this situation, we fallback to the appro VLAN.
# TODO: add support for the admin VLAN.
# Simplest DHCPv4 we can find.
dhcpv4 = svc.network.dhcp.client.build {
interface = config.hardware.networkInterfaces.lan;
};
inherit (config.services) sshd;
defaultroute4 = svc.network.route.build {
via = "$(output ${config.services.dhcpv4} router)";
target = "default";
dependencies = [ config.services.dhcpv4 ];
};
};
defaultProfile.packages = [ mtdutils ];
# Only keep root, which should inherit from DGN access control's root permissions.
users.root = config.users.root;
};
})
];
}

View file

@ -1,32 +1,32 @@
age-encryption.org/v1
-> ssh-ed25519 jIXfPA 2nFaxyP7O4GWU7U3wmET5sNrnFq72b9DEhiKEgWVrFk
l8uXfCBkTHogzVoUY0WOYhA99fodoT+N0HunacULydI
-> ssh-ed25519 QlRB9Q qDalihZE404oPOVHYQR5GIvozXNh4wNxhUa5Zwfz2DU
X8qvWf7qprbh0xu/uOHGsNLTQc8efYsgveH9R9kZZZw
-> ssh-ed25519 r+nK/Q mksHDhPoKKxQpk4sQPHapdq87EaJmgdmoVxMYjsAang
FTYHyxLp4nGOWJu1135yN/lQkGgAD9Jy4JJpMKFktrk
-> ssh-ed25519 jIXfPA TdfYeqsPJBf26CO1Bh74K8qxqR1MX3VUvZ/e73+oDXQ
KoA/I5kVXxryQ86qjfzq67Aiar+qDZF9OoF4MsNDqe4
-> ssh-ed25519 QlRB9Q ZaPziTdzqf0vCkCiLWAUJbnROaZ7Mz+Xgw1viEMWM2s
I0peAEQPbaXL9eHQ/OraNuqJPCxIwjpxIxhvgAifATY
-> ssh-ed25519 r+nK/Q kgmK60IgdW4QFdKqBQ6S9JmQVoRvpmffVaoNWzfV5Bc
ru8etu+7QOmnAoJv8BLtEK0SuDfhB75l525ORrDirvM
-> ssh-rsa krWCLQ
jEPt5eWP6NmpOikLhs1uPVo7kxHgg1y7WwdOPyR0z2vpFD2BWGlIi/BvnlE3OO5n
jtvDjAauWU0X2JarfdY9mY8MoPjT9qQ/ukxuVAHi5CoL/I1JCqcbuftssYY0B7Ab
SMfbyxjK8aIT1/4EQhMoWm0tuIylvgTBagL03Lw5mbyRqDkbpI/6YC9401YjT7Ts
dCDGIFAYM2BA7TuJiZr881ypUdU9rlm5rss1ZLMj90jyJPJC4SDYbzE0BoBat9l0
dYUrYGhGgZ1cDd6D6mPf6H95muiGHIhxaE8c+LdK/rKCSH9Rf6mfn/Ab/xvnaDNn
GW/WD0EpmdzpWVPby68+KA
-> ssh-ed25519 /vwQcQ 5DoMxdoK+KiHXKwwOpb7/1FZIEzAa/2/1l8yyxey6iw
RzmUkqZQLM5/jDXG9fxhZmfAywgVMjH9Y3O66BnhCSQ
-> ssh-ed25519 0R97PA g+uW/jfwHB3m0AdWxb9vPRjeaowhEx1Uoc2R0CVStlA
m5XvSEVQ8DiA7BSTsxVn6S1zv92CpbyZxSgUI3ObE4c
-> ssh-ed25519 JGx7Ng BtdJpskbfPyywYeFbmQw3HGPTLv5ri6x4bFocr9l6H8
88aFw+MCJLqMU/W/ikYDUZEAi0ImaPVbSc7cAZPbs/I
-> ssh-ed25519 5SY7Kg +JUMQfaxl7Orym43LVeqUyno0JfUbVnB+xv7smpdRhE
6K+Ewq1FhrXB2eYdljlsYpIfmVv49E4jSBsphgDpRJk
-> ssh-ed25519 p/Mg4Q AITnEN+Q41fEA2tkvVOKGCDZiuCXanG+qaiF5X4ukiA
NvP/HXOliNvi8tngH9PU90E616CPlh/QgkZ052H8wtk
-> ssh-ed25519 +mFdtQ RuaXIQNZ3s9C27XtpVTExJlAhYDYXRQni+Hwot0wrzU
WctqqoGS2hVfOZSU3ihCg5eI7PnxM7dkOJKM9DJ90Wk
-> ssh-ed25519 5rrg4g cAqJQ8z6T46YwzahtcTJxXZHklCGrupVCja5U/g+ZmM
wERu5T6rOi5/0qPSXeOnfA0Szg7/pbYFTW0Ys1yWq40
-> ssh-ed25519 oRtTqQ NF73c0d1qM4nVt2bEdWTEDjDcz/ZMCObn/7cDZfkVGA
Mivm+WWVqAfNs5pLwGmINIsmxlEZi7m7bQIRxGkf3/Q
--- 8R1h+xsovrLq+5QI1CoTXc9TBTQugnROZpOAHWBwG1w
G“Þ"û¤‡ã8ƒÈî&NF}x£ksyÖ\£.i§<69>קF¢¯}ê-ÍÁÓšLbì;{
QsgW7OvOB3cOz9MZI1PQ6Fe208WS+Sv/TWcucjD9i28U6Bty1KYeSwMH/zyzLuSe
51TqJTnkb+xGcqw3RvKiM58HMFcl6INmOI8otGxfCQSX7p3/QxiGQBbIgRblxtWB
8Jf55hgfh+1+vwTcM+BlBRWz4K581MeQiF2jj6ihfJNwTZ7Q9jNvgzF42znEyZyE
QTHoR9ROA/HqLgcrui1L7QnBlP1Y9Bt/oMCh4jFwHfcc6NeHF+I6AEeQNAHH9iNX
2+1RsJnQrTM+H204GrpVK78e1B5uCjvq/LeoWSQ3pFD9PwdM6JW2WfkB4FSCriAI
7ZAg64qNahyjX+J+KDlrwQ
-> ssh-ed25519 /vwQcQ MBPiBQdz65VVKMxJDlTCFUfG084K0ZcGpPJc5RKKND4
jH9fRJ/tcGQpZQ+pGNw9lXcRbPS8LLsuwe4EUsaFGDM
-> ssh-ed25519 0R97PA bvY5a3GO1CfVmCPJwBfFGJcS+Zkr2QRENa0WyzqspGc
YgxthAE4TIPlweuH8cWaOmVGqomc2yfLdzjO8G8bytw
-> ssh-ed25519 JGx7Ng 11We2girRvmkDm8eWkTZnazm7Ly0tmECFTdSFnBKIQQ
VQ+jlP1sk+SPkHARgAly9U7W0HVbpvZvxLN4V5l6JwE
-> ssh-ed25519 bUjjig Zt2Br6ls9INAJ5aQZ/az+6+rIpDCf/NCJP2zusdggms
3k0NOSVDpbQFEflEvyTzKv1/zXUBVN5ub9jjOe4EybM
-> ssh-ed25519 +mFdtQ inTgQzJVaYt8JZjtrjVzZzW9PscvBnZWkXIpEQYtdFI
O/Z7ccZam386C6r2UVJS+OMwG8nZ57RmUy+VJEgWJEY
-> ssh-ed25519 5rrg4g ApGMepP+32epekSxCfLGJs6uI38WPjWxtdk+q1Lvx0I
huEBiiNzTcz5hPUs+INfDyfeqKtl+mYE38PUizHktyI
-> ssh-ed25519 oRtTqQ QBBeZ0kLMPuDmO0hT7LvMs31WuVZATUSyxtCxgMzHgQ
HooCKv78+xzYnOwaYXbRNVH1XpG1e8tY0PB246nkFU8
-> G8<-grease
58RFQqg54Xu8pavoh6wbEnJl7J8XJ5rgaVq1bxokhQ
--- +gYhV/IjEqBw3YKDEeSbepgAIIO6A/BcpsYrwCy+Ezs
萠%7図殤チx盟~YヨワZチ{儖情リM<EFBE98>Hハ<48>ソ Xセ<58>ナk@モ9<EFBE93>

View file

@ -14,9 +14,12 @@
# deployment = {}; # Colmena deployment options
# nixpkgs = "unstable" or "22.11"; # nixpkgs version
# }
let
nix-lib = import ../../lib/nix-lib;
inherit (nix-lib) mapFuse;
{
ap01 = {
mkDevAp = ap-no: {
"ap-dev-${builtins.toString ap-no}" = {
site = "unknown";
adminGroups = [ "fai" ];
@ -24,9 +27,102 @@
stateVersion = null;
nodeDir = "ap-dev";
nixpkgs = {
system = "zyxel-nwa50ax";
version = "24.05";
};
deployment.tags = [
"ap-dev"
];
extraNodeSettings = {
inherit ap-no;
vendor-mac = null;
};
}
};
};
mkAP' = building: floor: ap-no: {
"ap-v01-${builtins.toString building}-${builtins.toString floor}-${builtins.toString ap-no}" = {
site = "unknown";
adminGroups = [ "fai" ];
hashedPassword = "$y$j9T$DMOQEWOYFHjNS0myrXp4x/$MG33VSdXGvib.99eN.AbvyVdNNJw4ERjAwK4.ULJe/A";
stateVersion = null;
nodeDir = "ap-v01";
nixpkgs = {
system = "zyxel-nwa50ax";
version = "24.05";
};
deployment = {
tags = [ "ap-dev" ];
targetHost = "10.0.253.1"; # TODO
};
extraNodeSettings = {
inherit building floor ap-no;
vendor-mac = null;
};
};
};
/*
Generate all APs nodes for a building. It takes a building definition and returns
an attributes set containing all nodes of the AP for the building.
Building definition:
* building-no is the index of the building
* floors is the range {from, to{ of floors that contains an AP
* ap-nos is the range [from, to{ of AP numbers
Type: AttrSet -> AttrSet
*/
mkAPs-building =
{
building-no,
floors,
ap-nos,
}:
mapFuse (f: mapFuse (mkAP' building-no f) (mkRange ap-nos)) (mkRange floors);
APs = {
hypnos-1 = {
building-no = 0;
floors = {
from = 0;
to = 3;
};
ap-nos = {
from = 1;
to = 7;
};
};
hypnos-2 = {
building-no = 1;
floors = {
from = 0;
to = 3;
};
ap-nos = {
from = 1;
to = 3;
};
};
};
mkRange = { from, to }: builtins.genList (x: x + from) (to - from);
in
{ }
// builtins.foldl' (nodes: building: nodes // mkAPs-building building) { } (builtins.attrValues APs)
// mapFuse mkDevAp [
0
1
]

View file

@ -210,6 +210,17 @@ in
default = null;
description = "VM cluster where the VM is located";
};
extraNodeSettings = mkOption {
type = attrs;
default = { };
description = "Freeform attribute set to customize the node";
};
nodeDir = mkOption {
type = str;
description = "Path to access node configuration";
};
};
config = {
@ -228,6 +239,7 @@ in
mkIf (ip != [ ]) (mkDefault (builtins.head ip));
});
nodeDir = mkDefault name;
};
}
)

View file

@ -153,10 +153,10 @@
"type": "Git",
"url": "https://git.dgnum.eu/DGNum/liminix"
},
"branch": "main",
"revision": "1322de1ee0cdb19fead79e12ab279ee0b575019a",
"branch": "mdebray/usteer",
"revision": "420b1764c5b5b91c3ddada6dec9bc594847b3cc5",
"url": null,
"hash": "07nk6nik97k8a57cf17dcj3gn2lbhw1myymrxpqc2aqa3haj754k"
"hash": "168qhll6qw5x9v9300mizpshhgmsvvwzp6786z7l1s3jqk3ygf6d"
},
"linkal": {
"type": "Git",

13
scripts/export_secret.sh Executable file
View file

@ -0,0 +1,13 @@
# SPDX-FileCopyrightText: 2024 Maurice Debray <maurice.debray@dgnum.eu>
#
# SPDX-License-Identifier: EUPL-1.2
DECRYPT=()
if [ -f "$HOME/.ssh/id_rsa" ]; then
DECRYPT+=(-i "$HOME/.ssh/id_rsa")
fi
if [ -f "$HOME/.ssh/id_ed25519" ]; then
DECRYPT+=(-i "$HOME/.ssh/id_ed25519")
fi
export RADIUS_SECRET=$(rage "${DECRYPT[@]}" -d ./machines/nixos/vault01/secrets/radius-ap-radius-secret_file)

View file

@ -0,0 +1,16 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p ubootTools
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
#
# SPDX-License-Identifier: EUPL-1.2
usage() {
echo "extract the firmware part to write it manually from a Zyxel NWA FIT image"
echo "$0 <zyxel_nwa_fit_image_path> <firmware_output_file>"
}
ZYXEL_NWA_FIT="$1"
FIRMWARE_OUTPUT="$2"
dumpimage -T flat_dt -p 0 $ZYXEL_NWA_FIT -o $FIRMWARE_OUTPUT

35
scripts/ftp_zeroday.sh Executable file
View file

@ -0,0 +1,35 @@
#!/usr/bin/env nix-shell
#!nix-shell -p inetutils -i bash
# SPDX-FileCopyrightText: 2024 Maurice Debray <maurice.debray@dgnum.eu>
#
# SPDX-License-Identifier: EUPL-1.2
#
# Tribute to RaitoBezarius for finding the exploit
set -euxo pipefail
usage() {
echo "./ftp_zeroday.sh [FIT-IMAGE] [IP]"
}
if [ "$#" -ne 2 ]; then
usage
exit 1
fi
if ! [ -e "$1" ]; then
echo "$1 not found" >&2
exit 2
fi
IMAGE="$1"
IP="$2"
echo "Trying to flash $IMAGE to $IP..."
# TODO: make it exit cleanly
ftp -niv <<EOF
open $IP
user admin 1234
binary
put $IMAGE
EOF

58
scripts/liminix-rebuild.sh Executable file
View file

@ -0,0 +1,58 @@
#!/usr/bin/env bash
# SPDX-FileCopyrightText: 2024 Daniel Barlow <dan@telent.net>
#
# SPDX-License-Identifier: MIT
# TODO: support automatic levitation when the rebuild counts does not fit in the target.
# TODO: support preflight checks where we detect the environment we are booted in (this requires the levitation to write a special file).
# TODO: use colmena to know the target host and focus on the node name.
set -Eeuo pipefail
ssh_command=${SSH_COMMAND-ssh}
root_prefix=${ROOT_PREFIX-/}
reboot="reboot"
case "$1" in
"--no-reboot")
unset reboot
shift
;;
"--fast")
reboot="soft"
shift
;;
"--live")
echo "Root prefix changed from $root_prefix to /mnt"
root_prefix="/mnt"
shift
;;
esac
target_host=$1
shift
if [ -z "$target_host" ] ; then
echo Usage: liminix-rebuild \[--no-reboot\] target-host params
exit 1
fi
if toplevel="$(nom-build $(colmena eval -E "{ nodes, ... }: nodes.$@.config.system.outputs.systemConfiguration" --instantiate))"; then
echo systemConfiguration $toplevel aimed at $root_prefix
sleep 3
min-copy-closure --root "$root_prefix" $target_host $toplevel
$ssh_command $target_host "$root_prefix/$toplevel/bin/install" "$root_prefix"
case "$reboot" in
reboot)
$ssh_command $target_host "sync; source /etc/profile; reboot"
;;
soft)
$ssh_command $target_host $toplevel/bin/restart-services
;;
*)
;;
esac
else
echo Rebuild failed
fi