Border router, hela

Signed-off-by: magic_rb <magic_rb@redalder.org>
This commit is contained in:
magic_rb 2024-09-04 22:39:43 +02:00
parent f4092bd8fa
commit c234160635
No known key found for this signature in database
GPG key ID: 08D5287CC5DDCA0E
16 changed files with 1608 additions and 72 deletions

View file

@ -109,6 +109,7 @@
nixos/systems/gooseberry
nixos/systems/grasshopper
nixos/systems/inkbook
nixos/systems/hela
nixng/containers/ingress-blowhole
nixng/containers/ingress-toothpick
@ -162,6 +163,7 @@
overlays/perl.nix
overlays/uboot
overlays/linux
overlays/rp-pppoe.nix
inputs.percept.outPath
dev-shells/default.nix

View file

@ -0,0 +1,359 @@
# SPDX-FileCopyrightText: 2022 Richard Brežák <richard@brezak.sk>
#
# SPDX-License-Identifier: LGPL-3.0-or-later
{
inputs,
lib',
config,
...
}: let
inherit
(lib')
flip
mapAttrs
singleton
mkForce
filter
hasPrefix
;
config' = config;
in {
flake.nixosConfigurations.hela = inputs.nixpkgs.lib.nixosSystem {
system = "aarch64-linux";
specialArgs = {
config' = config';
inputs' = inputs;
secret = lib'.loadSecrets inputs.secret;
};
modules =
singleton
(
{
pkgs,
config,
lib,
...
}: {
imports = [
inputs.impermenance.nixosModules.impermanence
inputs.disko.nixosModules.default
inputs.self.nixosModules.ifstate
inputs.self.nixosModules.notnft-ns
../../tests/hel/pppoe-server.nix
../../common/remote_access.nix
./users.nix
./networking.nix
(_: let
mkEthAddrOption = addr:
lib.mkOption {
type = lib.types.str;
default = addr;
readOnly = true;
apply = addr: {
colon = addr;
space = lib.stringAsChars (x:
if x == ":"
then " "
else x)
addr;
};
};
in {
options.bananapi.ethaddr = {
sw = mkEthAddrOption "5e:f3:21:5a:80:f6";
sfp0 = mkEthAddrOption "86:a9:22:2c:dd:6c";
sfp1 = mkEthAddrOption "16:5c:7f:42:c7:76";
wan = mkEthAddrOption "fe:39:64:d0:e4:9b";
slan = mkEthAddrOption "98:35:ed:b0:e3:f5";
lan0 = mkEthAddrOption "52:76:52:a8:40:18";
lan1 = mkEthAddrOption "de:9c:15:bb:f7:b9";
};
})
];
_module.args = {notnft = inputs.notnft.lib.${pkgs.stdenv.system};};
nixpkgs.overlays = [
inputs.self.overlays.ifstate
inputs.self.overlays.linux
inputs.self.overlays.uboot
inputs.self.overlays.rp-pppoe
];
hardware.enableRedistributableFirmware = true;
boot.initrd.includeDefaultModules = false;
boot.kernelPackages =
pkgs.linuxPackagesFor pkgs.linuxBananaPiR4;
hardware.deviceTree.name = "mediatek/mt7988a-bananapi-bpi-r4.dtb";
hardware.deviceTree.overlays = [
{
name = "mt7988a-bananapi-bpi-r4-eth.dtso";
dtsText = ''
/dts-v1/;
/plugin/;
/ {
compatible = "bananapi,bpi-r4", "mediatek,mt7988a";
fragment@1 {
target-path = "/soc/switch@15020000/ports";
__overlay__ {
port@0 {
mac-address = [${config.bananapi.ethaddr.wan.space}];
};
port@1 {
mac-address = [${config.bananapi.ethaddr.slan.space}];
label = "slan";
};
port@2 {
mac-address = [${config.bananapi.ethaddr.lan0.space}];
label = "lan0";
};
port@3 {
mac-address = [${config.bananapi.ethaddr.lan1.space}];
label = "lan1";
};
};
};
fragment@2 {
target-path = "/soc/ethernet@15100000";
__overlay__ {
mac@0 {
mac-address = [${config.bananapi.ethaddr.sw.space}];
};
mac@1 {
mac-address = [${config.bananapi.ethaddr.sfp0.space}];
};
mac@2 {
mac-address = [${config.bananapi.ethaddr.sfp1.space}];
};
};
};
};
'';
}
{
name = "mt7988a-bananapi-bpi-r4-sd.dtso";
dtsText = ''
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* Copyright (C) 2023 MediaTek Inc.
* Author: Frank Wunderlich <frank-w@public-files.de>
*/
/dts-v1/;
/plugin/;
#include <dt-bindings/gpio/gpio.h>
/ {
compatible = "bananapi,bpi-r4", "mediatek,mt7988a";
fragment@1 {
target-path = "/soc/mmc@11230000";
__overlay__ {
pinctrl-names = "default", "state_uhs";
pinctrl-0 = <&mmc0_pins_sdcard>;
pinctrl-1 = <&mmc0_pins_sdcard>;
cd-gpios = <&pio 12 GPIO_ACTIVE_LOW>;
bus-width = <4>;
max-frequency = <52000000>;
cap-sd-highspeed;
vmmc-supply = <&reg_3p3v>;
vqmmc-supply = <&reg_3p3v>;
no-mmc;
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
card@0 {
compatible = "mmc-card";
reg = <0>;
};
};
};
};
'';
}
];
boot.loader.grub.enable = false;
boot.loader.generic-extlinux-compatible.enable = true;
boot.kernelParams = [
"console=ttyS0,115200n8"
"earlycon=uart8250,mmio32,0x11000000"
"pci=pcie_bus_perf"
"pstore_blk.blkdev=/dev/nvme0n1p2"
"pstore_blk.kmsg_size=128"
"best_effort=y"
];
boot.kernelPatches = [
{
name = "Add software padding processing in Ethernet Tx path.";
patch = pkgs.fetchpatch {
url = "https://github.com/frank-w/BPI-Router-Linux/commit/e24807c0681f795246656fed01b9d2d39558f45c.patch";
hash = "sha256-cOa2KSnjeTTWY2TXim/jeYAyPzDqsNStNXdg4dVwAlI=";
};
}
{
name = "Fix software padding processing in Ethernet Tx path.";
patch = pkgs.fetchpatch {
url = "https://github.com/frank-w/BPI-Router-Linux/commit/dc4afd4c934f0a3d3c7a0131d6d0d8078565dcb6.patch";
hash = "sha256-PDB8i/dogBKgH8x7cy4/BZTAgmI5CsGLSBXbvOyMndo=";
};
}
];
disko.rootMountPoint = "/mnt/bpi-r4";
disko.devices = {
nodev = {
"/tmp" = {
fsType = "tmpfs";
mountOptions = [
"size=256M"
"mode=755"
"noexec"
];
};
"/" = {
fsType = "tmpfs";
mountOptions = [
"size=128M"
"mode=755"
"noexec"
];
};
};
disk = {
ssd = {
device = "nvme-nvme.126f-5033313050424242323331323231303037393133-50617472696f74204d2e322050333130203234304742-00000001";
type = "disk";
content = {
type = "gpt";
partitions = {
boot = {
priority = 1;
size = "4G";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
pstore = {
priority = 2;
size = "32M";
content = {
type = "filesystem";
format = "pstore";
};
};
root = {
priority = 3;
size = "100%";
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/persist";
};
};
};
};
};
main = {
device = "/dev/disk/by-id/usb-Generic-_SD_MMC_20120501030900000-0:0";
type = "disk";
content = {
type = "gpt";
partitions = {
bl2 = {
priority = 1;
start = "34";
end = "8191";
alignment = 1;
};
fip = {
priority = 2;
start = "8192";
end = "+4M";
alignment = 1;
};
};
};
# mkdir -p /mnt/bpi-r4/persist/nix
# mount -o bind -m /mnt/bpi-r4/persist/nix /mnt/bpi-r4/nix
#
# if ! [ $(uname -m) = "aarch64" ] && [ -e /run/binfmt/aarch64-linux ] ; then
# nix copy $(readlink /run/binfmt/aarch64-linux) --to /mnt/bpi-r4
# mount -t tmpfs none /mnt/bpi-r4/run -m
# mount -t none -o bind /run/binfmt /mnt/bpi-r4/run/binfmt -m
# fi
postCreateHook = ''
uboot=${pkgs.ubootBananaPiR4}
sgdisk -A 1:set:2 -A 3:set:2 $device
sgdisk --change-name 1:bl2 --change-name 2:fip $device
dd if=$uboot/bl2.img of=$device-part1 status=progress
dd if=$uboot/fip.bin of=$device-part2 status=progress
'';
};
};
};
fileSystems = {
"/persist".neededForBoot = true;
"/nix" = {
device = "/persist/nix";
options = ["bind"];
neededForBoot = true;
};
};
environment.systemPackages = with pkgs; [
tcpdump
ethtool
dnsutils
pciutils
gptfdisk
traceroute
];
environment.persistence."/persist" = {
hideMounts = true;
directories = [
"/var/log"
"/var/lib/nixos"
"/var/lib/systemd/coredump"
"/var/secrets"
];
files = [
"/etc/machine-id"
"/etc/ssh/ssh_host_rsa_key"
"/etc/ssh/ssh_host_rsa_key.pub"
"/etc/ssh/ssh_host_ed25519_key"
"/etc/ssh/ssh_host_ed25519_key.pub"
];
};
time.timeZone = "Europe/Amsterdam";
system.stateVersion = "24.05";
}
);
};
}

View file

@ -0,0 +1,102 @@
{pkgs, ...}: {
environment.systemPackages = [
pkgs.hostapd
];
environment.etc."hostapd.conf".text = ''
driver=nl80211
logger_syslog=127
logger_syslog_level=2
logger_stdout=127
logger_stdout_level=2
country_code=PT
ieee80211d=1
ieee80211h=1
hw_mode=a
beacon_int=100
channel=acs_survey
tx_queue_data2_burst=2.0
#num_global_macaddr=1
ieee80211n=1
ht_coex=0
ht_capab=[HT40+][LDPC][SHORT-GI-20][SHORT-GI-40][TX-STBC][RX-STBC1][MAX-AMSDU-7935]
ieee80211ac=1
vht_oper_chwidth=2
vht_oper_centr_freq_seg0_idx=42 #acs_survey
vht_capab=[RXLDPC][SHORT-GI-80][SHORT-GI-160][TX-STBC-2BY1][SU-BEAMFORMER][SU-BEAMFORMEE][MU-BEAMFORMER][MU-BEAMFORMEE][RX-ANTENNA-PATTERN][TX-ANTENNA-PATTERN][RX-STBC-1][SOUNDING-DIMENSION-3][BF-ANTENNA-3][VHT160][MAX-MPDU-11454][MAX-A-MPDU-LEN-EXP7]
ieee80211ax=1
he_oper_chwidth=2
he_oper_centr_freq_seg0_idx=42 #acs_survey
he_su_beamformer=1
he_su_beamformee=1
he_mu_beamformer=1
he_bss_color=128
he_spr_sr_control=3
he_default_pe_duration=4
he_rts_threshold=1023
he_mu_edca_qos_info_param_count=0
he_mu_edca_qos_info_q_ack=0
he_mu_edca_qos_info_queue_request=0
he_mu_edca_qos_info_txop_request=0
he_mu_edca_ac_be_aifsn=8
he_mu_edca_ac_be_aci=0
he_mu_edca_ac_be_ecwmin=9
he_mu_edca_ac_be_ecwmax=10
he_mu_edca_ac_be_timer=255
he_mu_edca_ac_bk_aifsn=15
he_mu_edca_ac_bk_aci=1
he_mu_edca_ac_bk_ecwmin=9
he_mu_edca_ac_bk_ecwmax=10
he_mu_edca_ac_bk_timer=255
he_mu_edca_ac_vi_ecwmin=5
he_mu_edca_ac_vi_ecwmax=7
he_mu_edca_ac_vi_aifsn=5
he_mu_edca_ac_vi_aci=2
he_mu_edca_ac_vi_timer=255
he_mu_edca_ac_vo_aifsn=5
he_mu_edca_ac_vo_aci=3
he_mu_edca_ac_vo_ecwmin=5
he_mu_edca_ac_vo_ecwmax=7
he_mu_edca_ac_vo_timer=255
interface=wlp1s0
ctrl_interface=/var/run/hostapd
ap_isolate=1
bss_load_update_period=60
chan_util_avg_period=600
disassoc_low_ack=1
skip_inactivity_poll=0
preamble=1
wmm_enabled=1
ignore_broadcast_ssid=0
uapsd_advertisement_enabled=1
utf8_ssid=1
multi_ap=0
sae_require_mfp=1
sae_pwe=2
wpa_passphrase=5quidtoget
wpa_psk_file=/var/run/hostapd-wlp1s0.psk
auth_algs=1
wpa=2
wpa_pairwise=CCMP
ssid=MT7996-233-test-5
bridge=br-lan
wds_bridge=
# snoop_iface=br-lan
wpa_disable_eapol_key_retries=0
wpa_key_mgmt=SAE
okc=1
ieee80211w=2
group_mgmt_cipher=AES-128-CMAC
dynamic_vlan=0
vlan_naming=1
# vlan_no_bridge=1
vlan_file=/var/run/hostapd-phy2-ap0.vlan
qos_map_set=0,0,2,16,1,1,255,255,18,22,24,38,40,40,44,46,48,56
bssid=fe:9c:48:0a:86:32
#default_macaddr
'';
}

View file

@ -0,0 +1,229 @@
{
pkgs,
config,
inputs',
notnft,
...
}: {
imports = [
./networking/border.nix
./networking/hel.nix
./patches.nix
./networking/dmz.nix
./hostapd.nix
];
networking.hostName = "hela";
networking = {
useDHCP = false;
firewall.enable = false;
# interfaces.ppp0.useDHCP = true;
};
# systemd.services.dhcpcd = {
# bindsTo = ["sys-devices-virtual-net-ppp0.device"];
# after = ["sys-devices-virtual-net-ppp0.device"];
# };
boot.kernel.sysctl = {
# Enable forwarding on IPv4 but disable on IPv6
"net.ipv4.conf.all.forwarding" = true;
"net.ipv6.conf.all.forwarding" = false;
};
services.ifstate = {
enable = true;
settings = {
routing.routes = [
{
to = "0.0.0.0/0";
via = "10.1.0.2";
dev = "hel";
}
];
interfaces = [
{
name = "sw";
link = {
kind = "physical";
permaddr = config.bananapi.ethaddr.sw.colon;
state = "up";
};
}
{
name = "sfp0";
link = {
kind = "physical";
permaddr = config.bananapi.ethaddr.sfp0.colon;
state = "up";
};
}
{
name = "sfp1";
link = {
kind = "physical";
permaddr = config.bananapi.ethaddr.sfp1.colon;
state = "up";
};
}
{
name = "wan";
link = {
kind = "dsa";
address = config.bananapi.ethaddr.wan.colon;
link = "sw";
state = "up";
};
}
{
name = "slan";
link = {
kind = "dsa";
address = config.bananapi.ethaddr.slan.colon;
link = "sw";
state = "up";
};
}
{
name = "hel";
link = {
kind = "veth";
peer = "hela";
peer_netns = "hel";
state = "up";
};
addresses = [
"10.1.0.1/19"
];
}
];
};
};
networking.notnft.enable = true;
networking.notnft.namespaces.default.rules =
# ---
with notnft.dsl;
with payload;
# ---
ruleset {
filter = add table {family = f: f.inet;} {
postrouting = add chain {
type = f: f.nat;
hook = f: f.postrouting;
prio = 100;
policy = f: f.accept;
};
prerouting = add chain {
type = f: f.nat;
hook = f: f.prerouting;
prio = 100;
policy = f: f.accept;
};
input =
add chain {
type = f: f.filter;
hook = f: f.input;
prio = -300;
policy = f: f.drop;
}
[(is.eq ip.saddr (set [(cidr "10.1.0.0/19")])) (is.eq ip.daddr "10.1.0.1") (is.eq ip.protocol (f: f.icmp)) accept]
[(is.eq meta.iifname "lo") accept]
# accept related, established and drop invalid
[
(vmap ct.state {
established = accept;
related = accept;
invalid = drop;
})
]
[
(is.eq ip.daddr "10.1.0.1")
(is.eq th.dport 22)
accept
]
[
(log {
prefix = "[drop] root.input: ";
queue-threshold = 1;
group = 2;
})
];
forward =
add chain {
type = f: f.filter;
hook = f: f.forward;
prio = -300;
policy = f: f.drop;
}
[
(log {
prefix = "[drop] root.forward: ";
queue-threshold = 1;
group = 2;
})
];
output = add chain {
type = f: f.filter;
hook = f: f.output;
prio = -300;
policy = f: f.accept;
};
};
};
services.ulogd = {
enable = true;
settings = {
# This one for logging to local file in emulated syslog format.
global.stack = "log2:NFLOG,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,print1:PRINTPKT,emu1:LOGEMU";
log2.group = 2;
emu1 = {
file = "/var/log/nft_root_drop.log";
sync = 1;
};
};
};
systemd.services.sshd = {
after = ["ifstate.service"];
};
systemd.services.kea-dhcp4-server = {
after = ["ifstate.service"];
};
services.kea.dhcp4 = {
enable = true;
settings = {
interfaces-config.interfaces = [
"hel"
];
subnet4 = [
{
pools = [
{pool = "10.1.0.3 - 10.1.0.254";} # dedicate a /24 to dhcp
];
id = 1;
subnet = "10.1.0.0/19";
option-data = [
{
name = "routers";
data = "10.1.0.2";
}
];
}
];
};
};
}

View file

@ -0,0 +1,353 @@
{
pkgs,
notnft,
...
}: {
services.ifstate.settings.namespaces.border = {
routing.routes = [
{
to = "0.0.0.0/0";
dev = "ppp-wan";
}
];
interfaces = [
{
name = "slan-vlan";
link = {
kind = "vlan";
link = "slan";
link_netns = null;
vlan_id = 6;
state = "up";
};
}
# {
# name = "ppp-slan";
# link = {
# kind = "ppp";
# addresses = [
# "192.168.1.1/24"
# ]
# }
# }
{
name = "wan-vlan";
link = {
kind = "vlan";
link = "wan";
link_netns = null;
vlan_id = 6;
state = "up";
};
}
# {
# name = "ppp-wan";
# link = {
# kind = "dummy";
# };
# addresses = [
# "8.8.8.8/32"
# ];
# }
{
name = "dmz";
link = {
kind = "veth";
peer = "border";
peer_netns = "dmz";
state = "up";
};
addresses = [
"10.0.0.1/24"
];
}
];
};
networking.notnft.namespaces.border.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 "lo") accept]
[
(is.eq ip.saddr (set [
(cidr "192.168.1.0" 25)
]))
(is.eq ip.daddr (set [
"192.168.1.1"
"86.80.70.193"
]))
(is.eq ip.protocol (f: f.icmp))
accept
]
[
(is.eq ip.saddr (set [
(cidr "10.0.0.0" 24)
(cidr "10.1.0.0" 19)
]))
(is.eq ip.daddr (set [
"10.0.0.1"
"86.80.70.193"
]))
(is.eq ip.protocol (f: f.icmp))
accept
]
[
(log {
prefix = "[drop] border.input: ";
queue-threshold = 1;
group = 2;
})
drop
];
output =
add chain {
type = f: f.filter;
hook = f: f.output;
prio = -300;
policy = f: f.drop;
}
# accept related, established
[
(vmap ct.state {
established = accept;
related = accept;
})
]
[
(is.eq ip.saddr (set [
"192.168.1.1"
"86.80.70.193"
]))
(is.eq ip.daddr (set [
(cidr "192.168.1.0" 25)
]))
(is.eq ip.protocol (f: f.icmp))
(is.eq icmp.type (f: f.echo-reply))
accept
]
[
(is.eq ip.saddr (set [
"10.0.0.1"
"86.80.70.193"
]))
(is.eq ip.daddr (set [
(cidr "10.0.0.0" 24)
(cidr "10.1.0.0" 19)
]))
(is.eq ip.protocol (f: f.icmp))
(is.eq icmp.type (f: f.echo-reply))
accept
]
[
(log {
prefix = "[drop] border.output: ";
queue-threshold = 1;
group = 2;
})
drop
];
forward =
add chain {
type = f: f.filter;
hook = f: f.forward;
prio = -300;
policy = f: f.drop;
}
# accept related, established
[
(vmap ct.state {
established = accept;
related = accept;
invalid = drop;
})
]
# allow forwarding traffic for the internet
[
(is.ne ip.daddr (cidr "10.0.0.0" 8))
(is.ne ip.daddr (cidr "172.16.0.0" 12))
(is.ne ip.daddr (cidr "192.168.0.0" 16))
(is.eq meta.iifname "ppp-slan")
(is.eq meta.oifname "ppp-wan")
accept
]
# allow forwarding traffic for the internet
[
(is.ne ip.daddr (cidr "10.0.0.0" 8))
(is.ne ip.daddr (cidr "172.16.0.0" 12))
(is.ne ip.daddr (cidr "192.168.0.0" 16))
(is.eq meta.iifname "dmz")
(is.eq meta.oifname "ppp-wan")
accept
]
# accept port forwarding from `slan` to `dmz`
[
(is.eq meta.iifname "ppp-slan")
(is.eq meta.oifname "dmz")
(is."in" ct.status "dnat")
accept
]
# accept port forwarding from `wan` to `slan`
[
(is.eq meta.iifname (set ["ppp-wan" "ppp-slan"]))
(is.eq meta.oifname "ppp-slan")
(is."in" ct.status "dnat")
accept
]
[
(log {
prefix = "[drop] border.forward: ";
queue-threshold = 1;
group = 2;
})
drop
];
prerouting =
add chain {
type = f: f.nat;
hook = f: f.prerouting;
prio = -100;
policy = f: f.accept;
}
[
(is.eq ip.daddr "192.168.1.1")
(is.eq tcp.dport "22")
(dnat {
addr = "10.0.0.2";
port = "22";
})
]
[
(is.eq ip.daddr "86.80.70.193")
(is.eq udp.dport "6666")
(dnat {
addr = "192.168.1.2";
port = "6666";
})
]
[
(is.eq ip.daddr "86.80.70.193")
(is.eq udp.dport "500")
(dnat {
addr = "192.168.1.2";
port = "500";
})
];
postrouting =
add chain {
type = f: f.nat;
hook = f: f.postrouting;
prio = -100;
policy = f: f.accept;
}
[
(is.eq meta.iifname "ppp-slan")
(is.eq meta.oifname "ppp-slan")
(is.eq udp.dport (set [500 6666]))
(is.eq ip.saddr "192.168.1.2")
(is.eq ip.daddr "192.168.1.2")
masquerade
]
[
(is.eq meta.oifname "ppp-wan")
masquerade
];
};
};
services.pppoe-server.kpn = {
interface = "slan-vlan";
localAddress = "192.168.1.1";
remoteAddressFile = pkgs.writeText "kpn-remote-address-file" ''
192.168.1.2
'';
C = "195.190.228.154";
pppdSettings = {
ifname = ["ppp-slan"];
};
};
systemd.services.pppoe-server-kpn = {
after = ["ifstate.service"];
serviceConfig.NetworkNamespacePath = "/var/run/netns/border";
};
services.pppd = {
enable = true;
peers.kpn = {
config = ''
plugin ${pkgs.rp-pppoe}/etc/ppp/plugins/rp-pppoe.so
nic-wan-vlan
name "internet"
password "internet"
noauth
hide-password
debug
+ipv6
ipv6cp-accept-local
noipdefault
defaultroute
defaultroute6
persist
maxfail 0
holdoff 5
mtu 1500
mru 1500
ifname ppp-wan
'';
};
};
systemd.services.pppd-kpn = {
after = ["ifstate.service"];
serviceConfig.NetworkNamespacePath = "/var/run/netns/border";
};
systemd.services.ulogd-border = {
description = "Ulogd Daemon";
wantedBy = ["multi-user.target"];
wants = ["network-pre.target"];
before = ["network-pre.target"];
after = ["ifstate.service"];
serviceConfig = let
settingsFormat = pkgs.formats.ini {listsAsDuplicateKeys = true;};
settingsFile = settingsFormat.generate "ulogd.conf" {
# This one for logging to local file in emulated syslog format.
global.stack = "log2:NFLOG,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,print1:PRINTPKT,emu1:LOGEMU";
log2.group = 2;
emu1 = {
file = "/var/log/nft_border_drop.log";
sync = 1;
};
};
in {
NetworkNamespacePath = "/var/run/netns/border";
ExecStart = "${pkgs.ulogd}/bin/ulogd -c ${settingsFile} --verbose --loglevel ${
toString 5
}";
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
};
};
}

View file

@ -0,0 +1,125 @@
{
pkgs,
notnft,
...
}: {
services.ifstate.settings.namespaces.dmz = {
interfaces = [
{
name = "br-dmz";
link = {
kind = "bridge";
state = "up";
};
}
{
name = "border";
link = {
kind = "veth";
peer = "dmz";
peer_netns = "border";
master = "br-dmz";
state = "up";
};
}
{
name = "hel";
link = {
kind = "veth";
peer = "dmz";
peer_netns = "hel";
master = "br-dmz";
state = "up";
};
}
];
};
# block input, output, forward, only bridge
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;
}
[(is.eq meta.iifname "lo") accept]
[
(log {
prefix = "[drop] dmz.input: ";
queue-threshold = 1;
group = 2;
})
drop
];
output =
add chain {
type = f: f.filter;
hook = f: f.output;
prio = -300;
policy = f: f.drop;
}
[
(log {
prefix = "[drop] dmz.output: ";
queue-threshold = 1;
group = 2;
})
drop
];
forward =
add chain {
type = f: f.filter;
hook = f: f.output;
prio = -300;
policy = f: f.drop;
}
[
(log {
prefix = "[drop] dmz.foward: ";
queue-threshold = 1;
group = 2;
})
drop
];
};
};
systemd.services.ulogd-dmz = {
description = "Ulogd Daemon";
wantedBy = ["multi-user.target"];
wants = ["network-pre.target"];
before = ["network-pre.target"];
after = ["ifstate.service"];
serviceConfig = let
settingsFormat = pkgs.formats.ini {listsAsDuplicateKeys = true;};
settingsFile = settingsFormat.generate "ulogd.conf" {
# This one for logging to local file in emulated syslog format.
global.stack = "log2:NFLOG,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,print1:PRINTPKT,emu1:LOGEMU";
log2.group = 2;
emu1 = {
file = "/var/log/nft_dmz_drop.log";
sync = 1;
};
};
in {
NetworkNamespacePath = "/var/run/netns/dmz";
ExecStart = "${pkgs.ulogd}/bin/ulogd -c ${settingsFile} --verbose --loglevel ${
toString 5
}";
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
};
};
}

View file

@ -0,0 +1,226 @@
{
pkgs,
notnft,
config,
...
}: {
services.ifstate.settings.namespaces.hel = {
routing.routes = [
{
to = "0.0.0.0/0";
via = "10.0.0.1";
dev = "dmz";
}
];
interfaces = [
{
name = "dmz";
link = {
kind = "veth";
peer = "hel";
peer_netns = "dmz";
state = "up";
};
addresses = [
"10.0.0.2/24"
];
}
{
name = "lan";
link = {
kind = "bridge";
state = "up";
};
addresses = [
"10.1.0.2/19"
];
}
{
name = "hela";
link = {
kind = "veth";
master = "lan";
peer = "hel";
peer_netns = null;
state = "up";
};
}
{
name = "lan0";
link = {
kind = "dsa";
address = config.bananapi.ethaddr.lan0.colon;
master = "lan";
link = "sw";
link_netns = null;
state = "up";
};
}
{
name = "lan1";
link = {
kind = "dsa";
address = config.bananapi.ethaddr.lan1.colon;
link = "sw";
link_netns = null;
master = "lan";
state = "up";
};
}
];
};
networking.notnft.namespaces.hel.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 ip.saddr (set [(cidr "10.1.0.0/19")])) (is.eq ip.daddr "10.1.0.2") (is.eq ip.protocol (f: f.icmp)) accept]
# accept related, established and drop invalid
[
(vmap ct.state {
established = accept;
related = accept;
invalid = drop;
})
]
[(is.eq meta.iifname "lo") accept]
[
(log {
prefix = "[drop] hel.input: ";
queue-threshold = 1;
group = 2;
})
];
output = add chain {
type = f: f.filter;
hook = f: f.output;
prio = -300;
policy = f: f.accept;
};
forward =
add chain {
type = f: f.filter;
hook = f: f.forward;
prio = -300;
policy = f: f.drop;
}
# accept related, established and drop invalid
[
(vmap ct.state {
established = accept;
related = accept;
invalid = drop;
})
]
# accept port forwarding from `dmz` to `lan`
[
(is.eq meta.iifname "dmz")
(is.eq meta.oifname "lan")
(is."in" ct.status "dnat")
accept
]
# allow forwarding traffic for the internet
[
(is.eq ip.saddr (cidr "10.1.0.0" 19))
(is.ne ip.daddr (set [
(cidr "10.0.0.0" 8)
(cidr "172.16.0.0" 12)
(cidr "192.168.0.0" 16)
]))
(is.eq meta.iifname "lan")
(is.eq meta.oifname "dmz")
accept
]
# allow forwarding icmp pings to local above this one
[
(is.eq ip.daddr (cidr "10.0.0.0/24"))
(is.eq meta.iifname "lan")
(is.eq meta.oifname "dmz")
(is.eq ip.protocol (f: f.icmp))
(is.eq icmp.type (f: f.echo-request))
accept
]
[
(log {
prefix = "[drop] hel.forward: ";
queue-threshold = 1;
group = 2;
})
];
prerouting =
add chain {
type = f: f.nat;
hook = f: f.prerouting;
prio = -100;
policy = f: f.accept;
}
[
(is.eq ip.daddr "10.0.0.2")
(is.eq tcp.dport "22")
(dnat {
addr = "10.1.0.1";
port = "22";
})
];
postrouting =
add chain {
type = f: f.nat;
hook = f: f.postrouting;
prio = -100;
policy = f: f.accept;
}
[
(is.eq meta.oifname "dmz")
masquerade
];
};
};
systemd.services.ulogd-hel = {
description = "Ulogd Daemon";
wantedBy = ["multi-user.target"];
wants = ["network-pre.target"];
before = ["network-pre.target"];
after = ["ifstate.service"];
serviceConfig = let
settingsFormat = pkgs.formats.ini {listsAsDuplicateKeys = true;};
settingsFile = settingsFormat.generate "ulogd.conf" {
# This one for logging to local file in emulated syslog format.
global.stack = "log2:NFLOG,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,print1:PRINTPKT,emu1:LOGEMU";
log2.group = 2;
emu1 = {
file = "/var/log/nft_hel_drop.log";
sync = 1;
};
};
in {
NetworkNamespacePath = "/var/run/netns/hel";
ExecStart = "${pkgs.ulogd}/bin/ulogd -c ${settingsFile} --verbose --loglevel ${
toString 5
}";
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
};
};
}

View file

@ -0,0 +1,52 @@
{
config,
lib,
pkgs,
...
}: {
systemd.services.ifstate-patch-pre = {
partOf = ["ifstate.service"];
wantedBy = ["ifstate.service"];
before = ["ifstate.service"];
path = [
pkgs.jq
pkgs.iproute2
];
script = ''
# create all network namespaces beforehand
${lib.concatMapStringsSep "\n" (
name: ''
if ! [ -f "/var/run/netns/${name}" ] ; then
ip netns add ${name}
fi
''
) (lib.attrNames config.services.ifstate.settings.namespaces)}
# move all dsa interfaces into their respective namespaces
${lib.concatMapStringsSep "\n" (
interface: ''
ifname="$(ip -json link | jq -r '.[] | select(.address == "${interface.link.address}") | .ifname')"
if ! [ -z "$ifname" ] ; then
ip link set "$ifname" netns ${interface.namespace}
fi
''
) (lib.pipe config.services.ifstate.settings.namespaces [
(lib.mapAttrs (_: settings: settings.interfaces or []))
lib.attrsToList
(lib.concatMap ({
name,
value,
}:
lib.pipe value [
(lib.filter (interface: interface.link.kind == "dsa" && interface.link ? "address"))
(map (interface: interface // {namespace = name;}))
]))
])}
'';
serviceConfig.Type = "oneshot";
};
}

View file

@ -0,0 +1,23 @@
{
inputs',
config',
secret,
...
}: {
imports = [
inputs'.home-manager-unstable.nixosModules.default
../../common/users.nix
];
home-manager.useGlobalPkgs = true;
home-manager.extraSpecialArgs = {
config' = config';
inputs' = inputs';
secret = secret;
};
home-manager.users.main = {
imports = [(inputs'.self + "/home-manager/modules/profiles/server.nix")];
home.stateVersion = "24.05";
};
}

View file

@ -12,35 +12,35 @@
mkImageMediaOverride
;
in {
flake.nixosConfigurations.hela = inputs.nixpkgs-stable.lib.nixosSystem {
system = "x86_64-linux";
modules =
singleton
(import ./hela.nix);
specialArgs = {
inputs' = inputs;
};
};
# 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."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;
};
};
# flake.nixosConfigurations.client = inputs.nixpkgs-stable.lib.nixosSystem {
# system = "x86_64-linux";
# modules =
# singleton
# (import ./client.nix);
# specialArgs = {
# inputs' = inputs;
# };
# };
perSystem = {
lib,

View file

@ -253,9 +253,10 @@ in {
config = ''
plugin ${rp-pppoe}/etc/ppp/plugins/rp-pppoe.so
nic-internet
name "kpn"
name "internet"
noauth
hide-password
password "internet"
debug
+ipv6
ipv6cp-accept-local

View file

@ -23,6 +23,7 @@
attrNames
singleton
optionalString
mkIf
;
cfg = config.services.pppoe-server;
in {
@ -124,6 +125,15 @@ in {
Settings passed to PPPD after it is started by `pppoe-server`.
'';
};
readyOnConnect = mkOption {
type = with types; bool;
default = false;
description = ''
Whether systemd should treat this service as starting, until a client
connects to the PPPoE server. Useful in tests.
'';
};
};
config = {
@ -131,7 +141,7 @@ in {
ip-up-script = singleton (pkgs.writeShellScript "ip-up-${name}" ''
{
echo "Signalling ready to systemd"
systemd-notify --ready
${optionalString config.readyOnConnect "systemd-notify --ready"}
${optionalString (config.ifUpScript != null) config.ifUpScript}
} | logger -t pppd-ip-up
'');
@ -139,7 +149,7 @@ in {
ip-down-script = singleton (pkgs.writeShellScript "ip-down-${name}" ''
{
echo "Signalling stopping to systemd"
systemd-notify --stopping
${optionalString config.readyOnConnect "systemd-notify --stopping"}
${optionalString (config.ifDownScript != null) config.ifDownScript}
} | logger -t pppd-ip-down
'');
@ -171,8 +181,11 @@ in {
];
serviceConfig = {
Type = "notify";
NotifyAccess = "all";
Type =
if v.readyOnConnect
then "notify"
else "simple";
NotifyAccess = mkIf v.readyOnConnect "all";
ExecStart =
"${v.package}/bin/pppoe-server "
+ concatStringsSep " " (
@ -198,6 +211,7 @@ in {
v)
(n: v: "-${n} ${toString v}"))
);
TimeoutStartSec = "infinity";
};
}
);

View file

@ -43,8 +43,8 @@ in
domain = "codeberg.org";
owner = "liske";
repo = "ifstate";
rev = "faf32e8d1b0c9d2fd565976b8cc67d9563551254";
hash = "sha256-16AGyGEbBGVNNlMS2tVu+dmpEkP7aCDwA+//2nMvaqU=";
rev = "74b8232ece29cebdd878d45371c3cdebfc33e4f6";
hash = "sha256-Ttjqi4vSpyq3FN/7xnNlaV+xwA0Ut1V2NRfs7qq0eFg=";
};
meta = {

View file

@ -1,32 +1,37 @@
{
buildLinux,
pkgs,
}:
buildLinux {
version = "6.10-bpi-r4";
modDirVersion = "6.10.0-bpi-r4";
fetchFromGitHub,
lib,
...
} @ args: (buildLinux (args
// {
version = "6.10-bpi-r4";
modDirVersion = "6.10.0-bpi-r4";
src = pkgs.fetchFromGitHub {
owner = "frank-w";
repo = "BPI-Router-Linux";
rev = "a5f209f3f88daf5bacaab883ca30d16d88ff0506";
hash = "sha256-bcgDdJrmHBWBhoy4TynODwG6BRL38tVKHAO6J8GR7IY=";
};
src = fetchFromGitHub {
owner = "frank-w";
repo = "BPI-Router-Linux";
rev = "a5f209f3f88daf5bacaab883ca30d16d88ff0506";
hash = "sha256-bcgDdJrmHBWBhoy4TynODwG6BRL38tVKHAO6J8GR7IY=";
};
defconfig = "mt7988a_bpi-r4_defconfig";
# structuredExtraConfig = with pkgs.lib.kernel; {
# EXTRA_FIRMWARE = freeform "imx/sdma/sdma-imx6q.bin imx/epdc/epdc.fw";
# EXTRA_FIRMWARE_DIR = freeform ((pkgs.symlinkJoin {
# name = "embedded-extra-firmware";
# paths = [
# pkgs.linux-firmware
# epdc-fw
# ];
# })
# + "/lib/firmware");
# # RTW_SDIO_PM_KEEP_POWER = no;
# # RTW_DEBUG = no;
# };
defconfig = "mt7988a_bpi-r4_defconfig";
extraMeta.branch = "6.10-main";
}
autoModules = false;
structuredExtraConfig = with lib.kernel; {
NETFILTER_NETLINK_LOG = module;
NF_CONNTRACK_BRIDGE = module;
BRIDGE_NETFILTER = module;
NFT_BRIDGE_META = module;
NFT_BRIDGE_REJECT = module;
NETFILTER_FAMILY_BRIDGE = yes;
MT7921_COMMON = module;
MT7921E = module;
NFT_LOG = module;
};
extraMeta.branch = "6.10-main";
}))

33
overlays/rp-pppoe.nix Normal file
View file

@ -0,0 +1,33 @@
{...}: {
flake.overlays.rp-pppoe = final: prev: {
rp-pppoe = final.lib.flip final.callPackage {} ({
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
'';
});
};
}

View file

@ -12,6 +12,7 @@
fetchFromGitHub,
buildArmTrustedFirmware,
symlinkJoin,
writeText,
}: let
inherit
(buildPackages)
@ -28,12 +29,7 @@
armTrustedFirmwareMTK = buildArmTrustedFirmware rec {
platform = "mt7988";
# src = fetchFromGitHub {
# owner = "mtk-openwrt";
# repo = "arm-trusted-firmware";
# rev = "bacca82a8cac369470df052a9d801a0ceb9b74ca";
# hash = "sha256-n5D3styntdoKpVH+vpAfDkCciRJjCZf9ivrI9eEdyqw=";
# };
src = fetchFromGitHub {
owner = "frank-w";
repo = "u-boot";
@ -62,6 +58,17 @@
"build/${platform}/release/fip.bin"
];
};
uEnv = writeText "bpi-r4-uEnv.txt" ''
ramdisk_addr_r=0x4c000000
kernel_addr_r=0x46000000
fdt_addr_r=0x45f00000
fdtfile=mediatek/mt7988a-bananapi-bpi-r4.dtb
bootdelay=4
bootcmd=bootflow scan -lb
'';
uboot = buildUBoot {
version = "master";
nativeBuildInputs = [
@ -71,20 +78,25 @@
openssl
bc
];
# BL31 = "${armTrustedFirmwareMTK}/bin/bl31.bin";
src = fetchFromGitHub {
owner = "frank-w";
repo = "u-boot";
rev = "285dd4d9eadb70d1dbd56671c65debade59592c7";
hash = "sha256-5OeVaOw5TA8yrzKMFmvtDb7ebZgNkDzFMnzgGbCMZrE=";
rev = "c608855b059963c05f022aefa0b8a090dd9f83c7";
hash = "sha256-1I4BTUFg869EDgOXOXGiFol72HevNp/vwDq1gczm0mo=";
};
extraConfig = ''
CONFIG_BOOTSTD=y
CONFIG_BOOTSTD_FULL=y
CONFIG_BOOTMETH_EXTLINUX=y
CONFIG_BOOTSTD_DEFAULTS=y
CONFIG_USE_DEFAULT_ENV_FILE=n
CONFIG_DEFAULT_ENV_FILE=""
CONFIG_USE_DEFAULT_ENV_FILE=y
CONFIG_AUTOBOOT=y
'';
prePatch = ''
cp ${uEnv} uEnv_r4.txt
'';
defconfig = "mt7988a_bpir4_sd_defconfig";