router: final fixes, it's now in production
This commit is contained in:
parent
8894e0d89c
commit
561a481f1a
46
flake.nix
46
flake.nix
|
@ -43,6 +43,8 @@
|
||||||
|
|
||||||
outputs = inputs@{ self, nixpkgs, nixos-hardware, impermanence, home-manager, nur, nix-gaming, notlua, notnft, nixos-mailserver, nixos-router, ... }:
|
outputs = inputs@{ self, nixpkgs, nixos-hardware, impermanence, home-manager, nur, nix-gaming, notlua, notnft, nixos-mailserver, nixos-router, ... }:
|
||||||
let
|
let
|
||||||
|
# --impure required for developing
|
||||||
|
# it takes the paths for notlua,notnft,nixos-router from filesystem as opposed to flake inputs
|
||||||
developing = false;
|
developing = false;
|
||||||
# IRL-related stuff I'd rather not put into git
|
# IRL-related stuff I'd rather not put into git
|
||||||
priv =
|
priv =
|
||||||
|
@ -80,7 +82,7 @@
|
||||||
mkPkgs = config: import nixpkgs (config // {
|
mkPkgs = config: import nixpkgs (config // {
|
||||||
overlays = (if config?overlays then config.overlays else [ ]) ++ [ overlay ];
|
overlays = (if config?overlays then config.overlays else [ ]) ++ [ overlay ];
|
||||||
});
|
});
|
||||||
# this is actual config, it gets processed later
|
# this is actual config, it gets processed below
|
||||||
config = {
|
config = {
|
||||||
nixserver = {
|
nixserver = {
|
||||||
modules = [
|
modules = [
|
||||||
|
@ -93,6 +95,7 @@
|
||||||
system = "aarch64-linux";
|
system = "aarch64-linux";
|
||||||
specialArgs.notnft = if developing then (import /${devPath}/notnft { inherit (nixpkgs) lib; }).config.notnft else notnft.lib.${system};
|
specialArgs.notnft = if developing then (import /${devPath}/notnft { inherit (nixpkgs) lib; }).config.notnft else notnft.lib.${system};
|
||||||
specialArgs.router-lib = if developing then import /${devPath}/nixos-router/lib.nix { inherit (nixpkgs) lib; } else nixos-router.lib.${system};
|
specialArgs.router-lib = if developing then import /${devPath}/nixos-router/lib.nix { inherit (nixpkgs) lib; } else nixos-router.lib.${system};
|
||||||
|
specialArgs.server-config = nixosConfigurations.nixserver.config;
|
||||||
modules = [
|
modules = [
|
||||||
./system/hardware/bpi_r3/emmc.nix
|
./system/hardware/bpi_r3/emmc.nix
|
||||||
./system/hosts/router
|
./system/hosts/router
|
||||||
|
@ -104,6 +107,7 @@
|
||||||
system = "aarch64-linux";
|
system = "aarch64-linux";
|
||||||
specialArgs.notnft = if developing then (import /${devPath}/notnft { inherit (nixpkgs) lib; }).config.notnft else notnft.lib.${system};
|
specialArgs.notnft = if developing then (import /${devPath}/notnft { inherit (nixpkgs) lib; }).config.notnft else notnft.lib.${system};
|
||||||
specialArgs.router-lib = if developing then import /${devPath}/nixos-router/lib.nix { inherit (nixpkgs) lib; } else nixos-router.lib.${system};
|
specialArgs.router-lib = if developing then import /${devPath}/nixos-router/lib.nix { inherit (nixpkgs) lib; } else nixos-router.lib.${system};
|
||||||
|
specialArgs.server-config = nixosConfigurations.nixserver.config;
|
||||||
modules = [
|
modules = [
|
||||||
./system/hardware/bpi_r3/sd.nix
|
./system/hardware/bpi_r3/sd.nix
|
||||||
./system/hosts/router
|
./system/hosts/router
|
||||||
|
@ -128,25 +132,8 @@
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
in rec {
|
|
||||||
overlays.default = overlay;
|
# this is the system config processing part
|
||||||
packages = lib.genAttrs [
|
|
||||||
"x86_64-linux"
|
|
||||||
"aarch64-linux"
|
|
||||||
] (system: let self = overlay self (import nixpkgs { inherit system; }); in self );
|
|
||||||
nixosImages.router = let pkgs = import nixpkgs { system = "aarch64-linux"; overlays = [ overlay ]; }; in {
|
|
||||||
emmcImage = pkgs.callPackage ./system/hardware/bpi_r3/image.nix {
|
|
||||||
inherit (nixosConfigurations.router-emmc) config;
|
|
||||||
rootfsImage = nixosConfigurations.router-emmc.config.system.build.rootfsImage;
|
|
||||||
bpiR3Stuff = pkgs.bpiR3StuffEmmc;
|
|
||||||
};
|
|
||||||
sdImage = pkgs.callPackage ./system/hardware/bpi_r3/image.nix {
|
|
||||||
inherit (nixosConfigurations.router-sd) config;
|
|
||||||
rootfsImage = nixosConfigurations.router-sd.config.system.build.rootfsImage;
|
|
||||||
bpiR3Stuff = pkgs.bpiR3StuffSd;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
# this is the system config part
|
|
||||||
nixosConfigurations = builtins.mapAttrs (hostname: args @ { system ? "x86_64-linux", modules, specialArgs ? {}, nixpkgs ? {}, home ? {}, ... }:
|
nixosConfigurations = builtins.mapAttrs (hostname: args @ { system ? "x86_64-linux", modules, specialArgs ? {}, nixpkgs ? {}, home ? {}, ... }:
|
||||||
lib.nixosSystem ({
|
lib.nixosSystem ({
|
||||||
inherit system;
|
inherit system;
|
||||||
|
@ -221,6 +208,25 @@
|
||||||
]);
|
]);
|
||||||
} // (builtins.removeAttrs args [ "home" "modules" "nixpkgs" ])))
|
} // (builtins.removeAttrs args [ "home" "modules" "nixpkgs" ])))
|
||||||
config;
|
config;
|
||||||
|
in {
|
||||||
|
inherit nixosConfigurations;
|
||||||
|
overlays.default = overlay;
|
||||||
|
packages = lib.genAttrs [
|
||||||
|
"x86_64-linux"
|
||||||
|
"aarch64-linux"
|
||||||
|
] (system: let self = overlay self (import nixpkgs { inherit system; }); in self );
|
||||||
|
nixosImages.router = let pkgs = import nixpkgs { system = "aarch64-linux"; overlays = [ overlay ]; }; in {
|
||||||
|
emmcImage = pkgs.callPackage ./system/hardware/bpi_r3/image.nix {
|
||||||
|
inherit (nixosConfigurations.router-emmc) config;
|
||||||
|
rootfsImage = nixosConfigurations.router-emmc.config.system.build.rootfsImage;
|
||||||
|
bpiR3Stuff = pkgs.bpiR3StuffEmmc;
|
||||||
|
};
|
||||||
|
sdImage = pkgs.callPackage ./system/hardware/bpi_r3/image.nix {
|
||||||
|
inherit (nixosConfigurations.router-sd) config;
|
||||||
|
rootfsImage = nixosConfigurations.router-sd.config.system.build.rootfsImage;
|
||||||
|
bpiR3Stuff = pkgs.bpiR3StuffSd;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
# for each hostname, for each user, generate an attribute "${user}@${hostname}"
|
# for each hostname, for each user, generate an attribute "${user}@${hostname}"
|
||||||
homeConfigurations =
|
homeConfigurations =
|
||||||
|
|
|
@ -2,14 +2,11 @@
|
||||||
, e2fsprogs
|
, e2fsprogs
|
||||||
, util-linux
|
, util-linux
|
||||||
, zstd
|
, zstd
|
||||||
|
, stdenvNoCC
|
||||||
, btrfs-progs
|
, btrfs-progs
|
||||||
, vmTools
|
, vmTools
|
||||||
, runCommand
|
, runCommand
|
||||||
, jq
|
|
||||||
, kmod
|
, kmod
|
||||||
, udev
|
|
||||||
, nix
|
|
||||||
, lkl
|
|
||||||
|
|
||||||
, bpiR3Stuff
|
, bpiR3Stuff
|
||||||
, config
|
, config
|
||||||
|
@ -17,7 +14,7 @@
|
||||||
, ... }:
|
, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
imageSize = 7818182656;
|
imageSize = 7818182656; # emmc size
|
||||||
bl2Start = 34;
|
bl2Start = 34;
|
||||||
bl2End = 8191;
|
bl2End = 8191;
|
||||||
envStart = 8192;
|
envStart = 8192;
|
||||||
|
@ -33,26 +30,44 @@ in
|
||||||
# the vm is suuuuuper slow
|
# the vm is suuuuuper slow
|
||||||
# so, do as much as possible outside of it
|
# so, do as much as possible outside of it
|
||||||
# but i still need it to create subvolumes
|
# but i still need it to create subvolumes
|
||||||
|
let
|
||||||
|
template = vmTools.runInLinuxVM (runCommand "bpi-r3-fs-template" {
|
||||||
|
preVM = ''
|
||||||
|
truncate -s ${toString ((rootPartEnd - rootPartStart + 1) * 512)} ./tmp.img
|
||||||
|
${btrfs-progs}/bin/mkfs.btrfs \
|
||||||
|
--label NIXOS_SD \
|
||||||
|
--uuid "44444444-4444-4444-8888-888888888888" \
|
||||||
|
./tmp.img
|
||||||
|
'';
|
||||||
|
nativeBuildInputs = [ btrfs-progs e2fsprogs util-linux kmod ];
|
||||||
|
postVM = ''
|
||||||
|
mkdir -p $out
|
||||||
|
${zstd}/bin/zstd tmp.img -o $out/template.btrfs.zst
|
||||||
|
'';
|
||||||
|
memSize = "4G";
|
||||||
|
QEMU_OPTS = "-drive file=./tmp.img,format=raw,if=virtio,cache=unsafe,werror=report -rtc base=2000-01-01,clock=vm";
|
||||||
|
} ''
|
||||||
|
modprobe btrfs
|
||||||
|
mkdir -p /mnt
|
||||||
|
mount -t btrfs -o space_cache=v2 /dev/vda /mnt
|
||||||
|
btrfs filesystem resize max /mnt
|
||||||
|
btrfs subvolume create /mnt/@boot
|
||||||
|
btrfs subvolume create /mnt/@
|
||||||
|
btrfs subvolume create /mnt/@nix
|
||||||
|
chattr +C /mnt/@boot
|
||||||
|
'');
|
||||||
|
in
|
||||||
|
|
||||||
vmTools.runInLinuxVM (runCommand "bpi-r3-fs" {
|
stdenvNoCC.mkDerivation {
|
||||||
enableParallelBuildingByDefault = true;
|
name = "bpi-r3-fs";
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
btrfs-progs
|
|
||||||
# dosfstools
|
|
||||||
e2fsprogs
|
|
||||||
util-linux # sfdisk
|
util-linux # sfdisk
|
||||||
config.system.build.nixos-install
|
|
||||||
jq
|
|
||||||
kmod
|
|
||||||
udev
|
|
||||||
gptfdisk
|
|
||||||
zstd
|
zstd
|
||||||
nix
|
|
||||||
lkl
|
|
||||||
];
|
];
|
||||||
preVM = ''
|
# ${vmTools.qemu}/bin/qemu-img create -f raw $img 7818182656
|
||||||
|
unpackPhase = "true";
|
||||||
|
buildPhase = ''
|
||||||
img=./result.img
|
img=./result.img
|
||||||
${vmTools.qemu}/bin/qemu-img create -f raw $img 7818182656
|
|
||||||
truncate -s ${toString imageSize} $img
|
truncate -s ${toString imageSize} $img
|
||||||
|
|
||||||
${gptfdisk}/bin/sgdisk -o \
|
${gptfdisk}/bin/sgdisk -o \
|
||||||
|
@ -65,34 +80,17 @@ vmTools.runInLinuxVM (runCommand "bpi-r3-fs" {
|
||||||
$img
|
$img
|
||||||
dd conv=notrunc if=${bpiR3Stuff}/bl2.img of=$img seek=${toString bl2Start}
|
dd conv=notrunc if=${bpiR3Stuff}/bl2.img of=$img seek=${toString bl2Start}
|
||||||
dd conv=notrunc if=${bpiR3Stuff}/fip.bin of=$img seek=${toString fipStart}
|
dd conv=notrunc if=${bpiR3Stuff}/fip.bin of=$img seek=${toString fipStart}
|
||||||
truncate -s ${toString ((rootPartEnd - rootPartStart + 1) * 512)} ./tmp.img
|
|
||||||
${btrfs-progs}/bin/mkfs.btrfs \
|
|
||||||
--label NIXOS_SD \
|
|
||||||
--uuid "44444444-4444-4444-8888-888888888888" \
|
|
||||||
./tmp.img
|
|
||||||
'';
|
'';
|
||||||
# i give up on making this work in a nix derivation, just do the rest in a script (./image.sh)
|
# i give up on making this work in a nix derivation, just do the rest in a script (./image.sh)
|
||||||
# (i could do more in a vm but thats too slow, i could program a custom userspace utility but thats too annoying)
|
# (i could do more in a vm but thats too slow, i could program a custom userspace utility but thats too annoying)
|
||||||
postVM = ''
|
installPhase = ''
|
||||||
# Truncate the file at the end of the last partition
|
|
||||||
img=./result.img
|
|
||||||
mkdir -p $out/boot
|
mkdir -p $out/boot
|
||||||
${config.boot.loader.generic-extlinux-compatible.populateCmd} -c ${config.system.build.toplevel} -d $out/boot -g 0
|
${config.boot.loader.generic-extlinux-compatible.populateCmd} -c ${config.system.build.toplevel} -d $out/boot -g 0
|
||||||
cp ${rootfsImage} $out/rootfs.ext4
|
ln -s ${rootfsImage} $out/rootfs.ext4
|
||||||
cp tmp.img $out/template.btrfs
|
cp ${template}/template.btrfs.zst $out
|
||||||
cp $img $out/image.img
|
zstd $img -o $out/image.img.zst
|
||||||
echo ${toString rootPartStart} > $out/metadata
|
echo ${toString rootPartStart} > $out/metadata
|
||||||
echo ${toString rootPartEnd} >> $out/metadata
|
echo ${toString rootPartEnd} >> $out/metadata
|
||||||
|
ln -s ${bpiR3Stuff}/bl2.img $out/boot0.img
|
||||||
'';
|
'';
|
||||||
memSize = "4G";
|
}
|
||||||
QEMU_OPTS = "-drive file=./tmp.img,format=raw,if=virtio,cache=unsafe,werror=report -rtc base=2000-01-01,clock=vm";
|
|
||||||
} ''
|
|
||||||
modprobe btrfs
|
|
||||||
mkdir -p /mnt
|
|
||||||
mount -t btrfs -o space_cache=v2 /dev/vda /mnt
|
|
||||||
btrfs filesystem resize max /mnt
|
|
||||||
btrfs subvolume create /mnt/@boot
|
|
||||||
btrfs subvolume create /mnt/@
|
|
||||||
btrfs subvolume create /mnt/@nix
|
|
||||||
chattr +C /mnt/@boot
|
|
||||||
'')
|
|
||||||
|
|
|
@ -46,8 +46,8 @@ if [ -z "$1" ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
rootfs="$1/rootfs.ext4"
|
rootfs="$1/rootfs.ext4"
|
||||||
template="$1/template.btrfs"
|
template="$1/template.btrfs.zst"
|
||||||
image="$1/image.img"
|
image="$1/image.img.zst"
|
||||||
boot="$1/boot"
|
boot="$1/boot"
|
||||||
|
|
||||||
metadata0="$(head -n1 "$1/metadata")"
|
metadata0="$(head -n1 "$1/metadata")"
|
||||||
|
@ -58,10 +58,12 @@ if [ -z "$metadata0" ] || [ -z "$metadata1" ] || [[ "$metadata0" == "$metadata1"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
tmp=$(mktemp -d)
|
tmp=$(mktemp -d)
|
||||||
cp "$template" "$tmp/template.btrfs"
|
cp "$template" "$tmp/template.btrfs.zst"
|
||||||
cp "$image" "$tmp/image.img"
|
cp "$image" "$tmp/image.img.zst"
|
||||||
template="$tmp/template.btrfs"
|
template="$tmp/template.btrfs"
|
||||||
image="$tmp/image.img"
|
image="$tmp/image.img"
|
||||||
|
unzstd --rm "$template.zst"
|
||||||
|
unzstd --rm "$image.zst"
|
||||||
chmod +w "$template" "$image"
|
chmod +w "$template" "$image"
|
||||||
|
|
||||||
function cleanup {
|
function cleanup {
|
||||||
|
@ -94,5 +96,4 @@ run umount "$tmp/out"
|
||||||
|
|
||||||
dd conv=notrunc if="$template" of="$image" seek="$metadata0"
|
dd conv=notrunc if="$template" of="$image" seek="$metadata0"
|
||||||
|
|
||||||
zstd --compress "$image"
|
zstd -f --rm --compress "$image" -o ./image.img.zst
|
||||||
cp "$image.zst" ./image.img.zst
|
|
||||||
|
|
|
@ -85,9 +85,6 @@ in {
|
||||||
};
|
};
|
||||||
console.font = "${pkgs.terminus_font}/share/consolefonts/ter-v24n.psf.gz";
|
console.font = "${pkgs.terminus_font}/share/consolefonts/ter-v24n.psf.gz";
|
||||||
networking.useDHCP = true;
|
networking.useDHCP = true;
|
||||||
networking.resolvconf.extraConfig = ''
|
|
||||||
name_servers="127.0.0.1 ::1"
|
|
||||||
'';
|
|
||||||
networking.firewall = {
|
networking.firewall = {
|
||||||
enable = true;
|
enable = true;
|
||||||
allowedTCPPorts = [
|
allowedTCPPorts = [
|
||||||
|
@ -107,12 +104,15 @@ in {
|
||||||
# UNBOUND
|
# UNBOUND
|
||||||
users.users.${config.common.mainUsername}.extraGroups = [ config.services.unbound.group ];
|
users.users.${config.common.mainUsername}.extraGroups = [ config.services.unbound.group ];
|
||||||
|
|
||||||
|
#networking.resolvconf.extraConfig = ''
|
||||||
|
# name_servers="127.0.0.1 ::1"
|
||||||
|
#'';
|
||||||
services.unbound = {
|
services.unbound = {
|
||||||
enable = true;
|
enable = false;
|
||||||
package = pkgs.unbound-with-systemd.override {
|
package = pkgs.unbound-with-systemd.override {
|
||||||
stdenv = pkgs.ccacheStdenv;
|
stdenv = pkgs.ccacheStdenv;
|
||||||
withPythonModule = true;
|
withPythonModule = true;
|
||||||
python = unbound-python;
|
python = pkgs.python3;
|
||||||
};
|
};
|
||||||
localControlSocketPath = "/run/unbound/unbound.ctl";
|
localControlSocketPath = "/run/unbound/unbound.ctl";
|
||||||
resolveLocalQueries = false;
|
resolveLocalQueries = false;
|
||||||
|
@ -142,9 +142,11 @@ in {
|
||||||
remote-control.control-enable = true;
|
remote-control.control-enable = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
systemd.services.unbound.environment = {
|
systemd.services.unbound = lib.mkIf config.services.unbound.enable {
|
||||||
MDNS_ACCEPT_NAMES = "^.*\\.local\\.$";
|
environment = {
|
||||||
PYTHONPATH = "${unbound-python}/${unbound-python.sitePackages}";
|
MDNS_ACCEPT_NAMES = "^.*\\.local\\.$";
|
||||||
|
PYTHONPATH = "${unbound-python}/${unbound-python.sitePackages}";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
# just in case
|
# just in case
|
||||||
networking.hosts."127.0.0.1" = [ "localhost" ] ++ hosted-domains;
|
networking.hosts."127.0.0.1" = [ "localhost" ] ++ hosted-domains;
|
||||||
|
@ -179,6 +181,7 @@ in {
|
||||||
enable = true;
|
enable = true;
|
||||||
ignoreIP = lib.optionals (cfg.lanCidrV4 != "0.0.0.0/0") [ cfg.lanCidrV4 ]
|
ignoreIP = lib.optionals (cfg.lanCidrV4 != "0.0.0.0/0") [ cfg.lanCidrV4 ]
|
||||||
++ (lib.optionals (cfg.lanCidrV6 != "::/0") [ cfg.lanCidrV6 ]);
|
++ (lib.optionals (cfg.lanCidrV6 != "::/0") [ cfg.lanCidrV6 ]);
|
||||||
|
maxretry = 10;
|
||||||
jails.dovecot = ''
|
jails.dovecot = ''
|
||||||
enabled = true
|
enabled = true
|
||||||
filter = dovecot
|
filter = dovecot
|
||||||
|
|
|
@ -681,7 +681,9 @@ def operate(id, event, qstate, qdata):
|
||||||
f.write(new_data)
|
f.write(new_data)
|
||||||
if changed4:
|
if changed4:
|
||||||
for qname in qnames:
|
for qname in qnames:
|
||||||
name4 = NFT_QUERIES[qname]['name4']
|
q = NFT_QUERIES[qname]
|
||||||
|
name4 = q['name4']
|
||||||
|
ips4 = q['ips4']
|
||||||
if name4:
|
if name4:
|
||||||
ip2 = []
|
ip2 = []
|
||||||
for ip in ip4:
|
for ip in ip4:
|
||||||
|
@ -698,7 +700,9 @@ def operate(id, event, qstate, qdata):
|
||||||
add_ips(name4, False, ip2)
|
add_ips(name4, False, ip2)
|
||||||
if changed6:
|
if changed6:
|
||||||
for qname in qnames:
|
for qname in qnames:
|
||||||
name6 = NFT_QUERIES[qname]['name6']
|
q = NFT_QUERIES[qname]
|
||||||
|
name6 = q['name6']
|
||||||
|
ips6 = q['ips6']
|
||||||
if name6:
|
if name6:
|
||||||
ip2 = []
|
ip2 = []
|
||||||
for ip in ip6:
|
for ip in ip6:
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
, notnft
|
, notnft
|
||||||
, lib
|
, lib
|
||||||
, router-lib
|
, router-lib
|
||||||
|
, server-config
|
||||||
, ... }:
|
, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
@ -98,7 +99,8 @@ let
|
||||||
[return];
|
[return];
|
||||||
|
|
||||||
ingress_lan_common = add chain
|
ingress_lan_common = add chain
|
||||||
[(is.eq (fib (f: with f; [ saddr mark iif ]) (f: f.oif)) missing) (log "${logPrefix}oif missing ") drop]
|
# there are some issues with this, disable it for lan
|
||||||
|
# [(is.eq (fib (f: with f; [ saddr mark iif ]) (f: f.oif)) missing) (log "${logPrefix}oif missing ") drop]
|
||||||
[(jump "ingress_common")];
|
[(jump "ingress_common")];
|
||||||
|
|
||||||
ingress_wan_common = add chain
|
ingress_wan_common = add chain
|
||||||
|
@ -151,8 +153,8 @@ let
|
||||||
}
|
}
|
||||||
// lib.genAttrs lans (_: jump "inbound_lan_common")
|
// lib.genAttrs lans (_: jump "inbound_lan_common")
|
||||||
// lib.genAttrs wans (_: jump "inbound_wan_common")
|
// lib.genAttrs wans (_: jump "inbound_wan_common")
|
||||||
))]
|
))];
|
||||||
[(log "${logPrefix}inbound drop ")];
|
#[(log "${logPrefix}inbound drop ")];
|
||||||
|
|
||||||
forward = add chain { type = f: f.filter; hook = f: f.forward; prio = f: f.filter; policy = f: f.drop; }
|
forward = add chain { type = f: f.filter; hook = f: f.forward; prio = f: f.filter; policy = f: f.drop; }
|
||||||
[(vmap ct.state { established = accept; related = accept; invalid = drop; })]
|
[(vmap ct.state { established = accept; related = accept; invalid = drop; })]
|
||||||
|
@ -215,14 +217,7 @@ let
|
||||||
vacuumAddress4 = addToIp parsedGatewayAddr4 2;
|
vacuumAddress4 = addToIp parsedGatewayAddr4 2;
|
||||||
vacuumAddress6 = addToIp parsedGatewayAddr6 2;
|
vacuumAddress6 = addToIp parsedGatewayAddr6 2;
|
||||||
|
|
||||||
# TODO: take from server config?
|
hosted-domains = builtins.attrNames server-config.services.nginx.virtualHosts;
|
||||||
hosted-domains =
|
|
||||||
map
|
|
||||||
(prefix: if prefix == null then cfg.domainName else "${prefix}.${cfg.domainName}")
|
|
||||||
[
|
|
||||||
null "dns" "mumble" "mail" "music" "www" "matrix"
|
|
||||||
"search" "git" "cloud" "ns1" "ns2"
|
|
||||||
];
|
|
||||||
in {
|
in {
|
||||||
router-settings.domainName = "pavluk.org";
|
router-settings.domainName = "pavluk.org";
|
||||||
router-settings.dhcpReservations = [
|
router-settings.dhcpReservations = [
|
||||||
|
@ -237,34 +232,40 @@ in {
|
||||||
{ ipAddress = vacuumAddress6;
|
{ ipAddress = vacuumAddress6;
|
||||||
macAddress = cfg.vacuumMac; }
|
macAddress = cfg.vacuumMac; }
|
||||||
];
|
];
|
||||||
router-settings.dnatRules = [
|
|
||||||
{
|
# dnat to server, take ports from its firewall config
|
||||||
# TODO: take firewall settings from server config
|
router-settings.dnatRules = let
|
||||||
port = notnft.dsl.set [
|
allTcp = server-config.networking.firewall.allowedTCPPorts;
|
||||||
# http
|
allTcpRanges = server-config.networking.firewall.allowedTCPPortRanges;
|
||||||
80 443 8008 8448
|
allUdp = server-config.networking.firewall.allowedUDPPorts;
|
||||||
# mail
|
allUdpRanges = server-config.networking.firewall.allowedUDPPortRanges;
|
||||||
25 587 465 143 993 110 995 4190
|
|
||||||
];
|
tcpAndUdp = builtins.filter (x: x != 22 && builtins.elem x allTcp) allUdp;
|
||||||
tcp = true; udp = false;
|
tcpOnly = builtins.filter (x: x != 22 && !(builtins.elem x allUdp)) allTcp;
|
||||||
target4.address = serverAddress4;
|
udpOnly = builtins.filter (x: x != 22 && !(builtins.elem x allTcp)) allUdp;
|
||||||
target6.address = serverAddress6;
|
|
||||||
}
|
rangesTcpAndUdp = builtins.filter (x: builtins.elem x allTcpRanges) allUdpRanges;
|
||||||
{
|
rangesTcpOnly = builtins.filter (x: !(builtins.elem x allUdpRanges)) allTcpRanges;
|
||||||
# mumble
|
rangesUdpOnly = builtins.filter (x: !(builtins.elem x allTcpRanges)) allUdpRanges;
|
||||||
port = 64738; tcp = true; udp = true;
|
in lib.optional (tcpAndUdp != [ ]) {
|
||||||
target4.address = serverAddress4;
|
port = notnft.dsl.set tcpAndUdp; tcp = true; udp = true;
|
||||||
target6.address = serverAddress6;
|
target4.address = serverAddress4; target6.address = serverAddress6;
|
||||||
}
|
} ++ lib.optional (tcpOnly != [ ]) {
|
||||||
{
|
port = notnft.dsl.set tcpOnly; tcp = true; udp = false;
|
||||||
# expose the default namespace's ssh via port 23
|
target4.address = serverAddress4; target6.address = serverAddress6;
|
||||||
port = 23; tcp = true; udp = false;
|
} ++ lib.optional (udpOnly != [ ]) {
|
||||||
target4.address = gatewayAddr4;
|
port = notnft.dsl.set udpOnly; tcp = false; udp = true;
|
||||||
target4.port = 22;
|
target4.address = serverAddress4; target6.address = serverAddress6;
|
||||||
target6.address = gatewayAddr6;
|
} ++ map (range: {
|
||||||
target6.port = 22;
|
port = notnft.dsl.range range.from range.to; tcp = true; udp = true;
|
||||||
}
|
target4.address = serverAddress4; target6.address = serverAddress6;
|
||||||
];
|
}) rangesTcpAndUdp ++ map (range: {
|
||||||
|
port = notnft.dsl.range range.from range.to; tcp = true; udp = false;
|
||||||
|
target4.address = serverAddress4; target6.address = serverAddress6;
|
||||||
|
}) rangesTcpOnly ++ map (range: {
|
||||||
|
port = notnft.dsl.range range.from range.to; tcp = false; udp = true;
|
||||||
|
target4.address = serverAddress4; target6.address = serverAddress6;
|
||||||
|
}) rangesUdpOnly;
|
||||||
|
|
||||||
imports = [ ./options.nix ];
|
imports = [ ./options.nix ];
|
||||||
system.stateVersion = "22.11";
|
system.stateVersion = "22.11";
|
||||||
|
@ -301,9 +302,11 @@ in {
|
||||||
"net.ipv6.conf.all.forwarding" = true;
|
"net.ipv6.conf.all.forwarding" = true;
|
||||||
};
|
};
|
||||||
services.openssh.enable = true;
|
services.openssh.enable = true;
|
||||||
/*services.fail2ban = {
|
services.fail2ban = {
|
||||||
enable = true;
|
enable = true;
|
||||||
};*/
|
ignoreIP = [ netCidr4 netCidr6 ];
|
||||||
|
maxretry = 10;
|
||||||
|
};
|
||||||
router.enable = true;
|
router.enable = true;
|
||||||
router.interfaces.wlan0 = {
|
router.interfaces.wlan0 = {
|
||||||
bridge = "br0";
|
bridge = "br0";
|
||||||
|
@ -364,7 +367,7 @@ in {
|
||||||
{ service = "wireguard-wg0"; inNetns = false; }
|
{ service = "wireguard-wg0"; inNetns = false; }
|
||||||
];
|
];
|
||||||
systemdLinkLinkConfig.MACAddressPolicy = "none";
|
systemdLinkLinkConfig.MACAddressPolicy = "none";
|
||||||
systemdLinkLinkConfig.MACAddress = "11:22:33:44:55:66";
|
systemdLinkLinkConfig.MACAddress = cfg.routerMac;
|
||||||
dhcpcd.enable = true;
|
dhcpcd.enable = true;
|
||||||
networkNamespace = "wan";
|
networkNamespace = "wan";
|
||||||
};
|
};
|
||||||
|
@ -408,6 +411,34 @@ in {
|
||||||
ipv4.kea.enable = true;
|
ipv4.kea.enable = true;
|
||||||
ipv6.radvd.enable = true;
|
ipv6.radvd.enable = true;
|
||||||
ipv6.kea.enable = true;
|
ipv6.kea.enable = true;
|
||||||
|
};
|
||||||
|
router.networkNamespaces.default = {
|
||||||
|
# set routing table depending on packet mark
|
||||||
|
rules = [
|
||||||
|
{ ipv6 = false; extraArgs = [ "fwmark" wan_table "table" wan_table ]; }
|
||||||
|
{ ipv6 = true; extraArgs = [ "fwmark" wan_table "table" wan_table ]; }
|
||||||
|
# don't add vpn_table as it should be the default
|
||||||
|
{ ipv6 = false; extraArgs = [ "fwmark" iot_table "table" iot_table ]; }
|
||||||
|
{ ipv6 = true; extraArgs = [ "fwmark" iot_table "table" iot_table ]; }
|
||||||
|
] ++ builtins.concatLists (map (rule: let
|
||||||
|
table = if rule.inVpn then 0 else wan_table;
|
||||||
|
forEachPort = func: port:
|
||||||
|
if builtins.isInt port then [ (func port) ]
|
||||||
|
else if port?set then builtins.concatLists (map (forEachPort func) port.set)
|
||||||
|
else if port?range.min then let inherit (port.range) min max; in [ (func "${toString min}-${toString max}") ]
|
||||||
|
else if port?range then let max = builtins.elemAt port.range 1; min = builtins.head port.range; in [ (func "${toString min}-${toString max}" ) ]
|
||||||
|
else throw "Unsupported expr: ${builtins.toJSON port}";
|
||||||
|
gen = len: proto: tgt:
|
||||||
|
forEachPort
|
||||||
|
(port: [ "from" "${tgt.address}/${toString len}" "ipproto" proto "sport" port "table" table ])
|
||||||
|
(if tgt.port == null then rule.port else tgt.port);
|
||||||
|
in lib.optionals (rule.tcp && rule.target4 != null) (map (x: { ipv6 = false; extraArgs = x; }) (gen 32 "tcp" rule.target4))
|
||||||
|
++ lib.optionals (rule.udp && rule.target4 != null) (map (x: { ipv6 = false; extraArgs = x; }) (gen 32 "udp" rule.target4))
|
||||||
|
++ lib.optionals (rule.tcp && rule.target6 != null) (map (x: { ipv6 = true; extraArgs = x; }) (gen 128 "tcp" rule.target6))
|
||||||
|
++ lib.optionals (rule.udp && rule.target6 != null) (map (x: { ipv6 = true; extraArgs = x; }) (gen 128 "udp" rule.target6))
|
||||||
|
|
||||||
|
) (builtins.filter (x: (x.tcp || x.udp) && dnatRuleMode x == "rule") cfg.dnatRules));
|
||||||
|
|
||||||
nftables.stopJsonRules = mkFlushRules {};
|
nftables.stopJsonRules = mkFlushRules {};
|
||||||
nftables.jsonRules = mkRules {
|
nftables.jsonRules = mkRules {
|
||||||
selfIp4 = gatewayAddr4;
|
selfIp4 = gatewayAddr4;
|
||||||
|
@ -541,6 +572,8 @@ in {
|
||||||
ipv6.routes = [
|
ipv6.routes = [
|
||||||
{ extraArgs = [ netCidr6 "via" mainNetnsAddr6 ]; }
|
{ extraArgs = [ netCidr6 "via" mainNetnsAddr6 ]; }
|
||||||
];
|
];
|
||||||
|
};
|
||||||
|
router.networkNamespaces.wan = {
|
||||||
nftables.stopJsonRules = mkFlushRules {};
|
nftables.stopJsonRules = mkFlushRules {};
|
||||||
nftables.jsonRules = mkRules {
|
nftables.jsonRules = mkRules {
|
||||||
selfIp4 = wanNetnsAddr4;
|
selfIp4 = wanNetnsAddr4;
|
||||||
|
@ -600,30 +633,6 @@ in {
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
router.networkNamespaces.default.rules = [
|
|
||||||
{ ipv6 = false; extraArgs = [ "fwmark" wan_table "table" wan_table ]; }
|
|
||||||
{ ipv6 = true; extraArgs = [ "fwmark" wan_table "table" wan_table ]; }
|
|
||||||
# don't add vpn_table as it should be the default
|
|
||||||
{ ipv6 = false; extraArgs = [ "fwmark" iot_table "table" iot_table ]; }
|
|
||||||
{ ipv6 = true; extraArgs = [ "fwmark" iot_table "table" iot_table ]; }
|
|
||||||
] ++ builtins.concatLists (map (rule: let
|
|
||||||
table = if rule.inVpn then 0 else wan_table;
|
|
||||||
forEachPort = func: port:
|
|
||||||
if builtins.isInt port then [ (func port) ]
|
|
||||||
else if port?set then builtins.concatLists (map (forEachPort func) port.set)
|
|
||||||
else if port?range.min then let inherit (port.range) min max; in [ (func "${toString min}-${toString max}") ]
|
|
||||||
else if port?range then let max = builtins.elemAt port.range 1; min = builtins.head port.range; in [ (func "${toString min}-${toString max}" ) ]
|
|
||||||
else throw "Unsupported expr: ${builtins.toJSON port}";
|
|
||||||
gen = len: proto: tgt:
|
|
||||||
forEachPort
|
|
||||||
(port: [ "from" "${tgt.address}/${toString len}" "ipproto" proto "sport" port "table" table ])
|
|
||||||
(if tgt.port == null then rule.port else tgt.port);
|
|
||||||
in lib.optionals (rule.tcp && rule.target4 != null) (map (x: { ipv6 = false; extraArgs = x; }) (gen 32 "tcp" rule.target4))
|
|
||||||
++ lib.optionals (rule.udp && rule.target4 != null) (map (x: { ipv6 = false; extraArgs = x; }) (gen 32 "udp" rule.target4))
|
|
||||||
++ lib.optionals (rule.tcp && rule.target6 != null) (map (x: { ipv6 = true; extraArgs = x; }) (gen 128 "tcp" rule.target6))
|
|
||||||
++ lib.optionals (rule.udp && rule.target6 != null) (map (x: { ipv6 = true; extraArgs = x; }) (gen 128 "udp" rule.target6))
|
|
||||||
|
|
||||||
) (builtins.filter (x: (x.tcp || x.udp) && dnatRuleMode x == "rule") cfg.dnatRules));
|
|
||||||
|
|
||||||
networking.wireguard.interfaces.wg0 = cfg.wireguard // {
|
networking.wireguard.interfaces.wg0 = cfg.wireguard // {
|
||||||
socketNamespace = "wan";
|
socketNamespace = "wan";
|
||||||
|
@ -673,9 +682,9 @@ in {
|
||||||
# load vpn_domains.json and vpn_ips.json, as well as unvpn_domains.json and unvpn_ips.json
|
# load vpn_domains.json and vpn_ips.json, as well as unvpn_domains.json and unvpn_ips.json
|
||||||
# resolve domains and append it to ips and add it to the nftables sets
|
# resolve domains and append it to ips and add it to the nftables sets
|
||||||
environment.NFT_QUERIES = "vpn:force_vpn4,force_vpn6;unvpn:force_unvpn4,force_unvpn6";
|
environment.NFT_QUERIES = "vpn:force_vpn4,force_vpn6;unvpn:force_unvpn4,force_unvpn6";
|
||||||
# it needs to run after br0 has been set up because it sets up the sets
|
# it needs to run after nftables has been set up because it sets up the sets
|
||||||
after = [ "nftables-br0.service" ];
|
after = [ "nftables-default.service" ];
|
||||||
wants = [ "nftables-br0.service" ];
|
wants = [ "nftables-default.service" ];
|
||||||
# allow it to call nft
|
# allow it to call nft
|
||||||
serviceConfig.AmbientCapabilities = [ "CAP_NET_ADMIN" ];
|
serviceConfig.AmbientCapabilities = [ "CAP_NET_ADMIN" ];
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
|
|
||||||
{
|
{
|
||||||
options.router-settings = {
|
options.router-settings = {
|
||||||
|
routerMac = lib.mkOption {
|
||||||
|
description = "router's mac address";
|
||||||
|
type = lib.types.str;
|
||||||
|
};
|
||||||
serverMac = lib.mkOption {
|
serverMac = lib.mkOption {
|
||||||
description = "server's mac address";
|
description = "server's mac address";
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
|
|
|
@ -93,7 +93,7 @@ in {
|
||||||
] ++ lib.optionals config.services.printing.enable [
|
] ++ lib.optionals config.services.printing.enable [
|
||||||
{ directory = /var/lib/cups; user = "root"; group = "root"; mode = "0755"; }
|
{ directory = /var/lib/cups; user = "root"; group = "root"; mode = "0755"; }
|
||||||
] ++ lib.optionals config.services.fail2ban.enable [
|
] ++ lib.optionals config.services.fail2ban.enable [
|
||||||
{ directory = /var/lib/fail2ban; user = "fail2ban"; group = "fail2ban"; mode = "0750"; }
|
{ directory = /var/lib/fail2ban; user = "root"; group = "root"; mode = "0700"; }
|
||||||
] ++ lib.optionals config.services.opendkim.enable [
|
] ++ lib.optionals config.services.opendkim.enable [
|
||||||
{ directory = /var/lib/opendkim; user = "opendkim"; group = "opendkim"; mode = "0700"; }
|
{ directory = /var/lib/opendkim; user = "opendkim"; group = "opendkim"; mode = "0700"; }
|
||||||
] ++ lib.optionals config.services.pleroma.enable [
|
] ++ lib.optionals config.services.pleroma.enable [
|
||||||
|
|
Loading…
Reference in a new issue