557 lines
17 KiB
Nix
557 lines
17 KiB
Nix
{
|
|
modulesPath,
|
|
repoFlake,
|
|
packages',
|
|
pkgs,
|
|
lib,
|
|
config,
|
|
nodeFlake,
|
|
nodeName,
|
|
system,
|
|
...
|
|
}: let
|
|
inherit
|
|
(nodeFlake.inputs)
|
|
bpir3
|
|
nixos-nftables-firewall
|
|
;
|
|
in {
|
|
disabledModules = [
|
|
# "services/networking/hostapd.nix"
|
|
];
|
|
|
|
imports = [
|
|
# nodeFlake.inputs.disko.nixosModules.disko
|
|
repoFlake.inputs.sops-nix.nixosModules.sops
|
|
|
|
../../profiles/common/user.nix
|
|
|
|
"${bpir3}/lib/sd-image-mt7986.nix"
|
|
|
|
nixos-nftables-firewall.nixosModules.default
|
|
|
|
# TODO
|
|
# ./network.nix
|
|
# ./monitoring.nix
|
|
{
|
|
services.openssh.enable = true;
|
|
services.openssh.settings.PermitRootLogin = "yes";
|
|
|
|
users.commonUsers = {
|
|
enable = true;
|
|
enableNonRoot = false;
|
|
rootPasswordFile = config.sops.secrets.passwords-root.path;
|
|
};
|
|
|
|
sops.secrets.passwords-root = {
|
|
sopsFile = ../../../../secrets/${nodeName}/secrets.yaml;
|
|
neededForUsers = true;
|
|
format = "yaml";
|
|
};
|
|
}
|
|
];
|
|
|
|
# sops.secrets.ssh_host_ed25519_key = {
|
|
# sopsFile = ../../../../secrets/${nodeName}/secrets.yaml;
|
|
# format = "yaml";
|
|
|
|
# path = "/etc/ssh/ssh_host_ed25519_key";
|
|
# mode = "0600";
|
|
# };
|
|
# sops.secrets.ssh_host_ed25519_key_pub = {
|
|
# sopsFile = ../../../../secrets/${nodeName}/secrets.yaml;
|
|
# format = "yaml";
|
|
|
|
# path = "/etc/ssh/ssh_host_ed25519_key.pub";
|
|
# mode = "0600";
|
|
# };
|
|
# sops.secrets.ssh_host_rsa_key = {
|
|
# sopsFile = ../../../../secrets/${nodeName}/secrets.yaml;
|
|
# format = "yaml";
|
|
|
|
# path = "/etc/ssh/ssh_host_rsa_key";
|
|
# mode = "0600";
|
|
# };
|
|
# sops.secrets.ssh_host_rsa_key_pub = {
|
|
# sopsFile = ../../../../secrets/${nodeName}/secrets.yaml;
|
|
# format = "yaml";
|
|
|
|
# path = "/etc/ssh/ssh_host_rsa_key.pub";
|
|
# mode = "0644";
|
|
# };
|
|
|
|
boot = {
|
|
kernel = {
|
|
sysctl = {
|
|
"net.ipv4.conf.all.forwarding" = true;
|
|
"net.ipv6.conf.all.forwarding" = true;
|
|
};
|
|
};
|
|
};
|
|
|
|
networking = {
|
|
hostName = nodeName;
|
|
useNetworkd = true;
|
|
useDHCP = false;
|
|
|
|
# No local firewall.
|
|
nat.enable = lib.mkForce false;
|
|
firewall.enable = lib.mkForce false;
|
|
|
|
# Use the nftables firewall instead of the base nixos scripted rules.
|
|
# This flake provides a similar utility to the base nixos scripting.
|
|
# https://github.com/thelegy/nixos-nftables-firewall/tree/main
|
|
nftables = {
|
|
enable = true;
|
|
stopRuleset = "";
|
|
firewall = {
|
|
enable = true;
|
|
zones = {
|
|
lan.interfaces = ["br-lan"];
|
|
wan.interfaces = ["wan" "lan0"];
|
|
};
|
|
rules = {
|
|
lan = {
|
|
from = ["lan"];
|
|
to = ["fw"];
|
|
verdict = "accept";
|
|
};
|
|
outbound = {
|
|
from = ["lan"];
|
|
to = ["lan" "wan"];
|
|
verdict = "accept";
|
|
};
|
|
nat = {
|
|
from = ["lan"];
|
|
to = ["wan"];
|
|
masquerade = true;
|
|
};
|
|
|
|
incoming-wan = {
|
|
from = ["wan"];
|
|
to = ["fw"];
|
|
allowedTCPPortRanges = [
|
|
{
|
|
from = 22;
|
|
to = 22;
|
|
}
|
|
];
|
|
verdict = "drop";
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
systemd.network = {
|
|
wait-online.anyInterface = true;
|
|
netdevs = {
|
|
# Create the VLANs
|
|
"00-vlan-100" = {
|
|
Name = "vlan100";
|
|
Kind = "vlan";
|
|
};
|
|
|
|
# Create the bridge interfaces
|
|
"20-br-lan" = {
|
|
netdevConfig = {
|
|
Kind = "bridge";
|
|
Name = "br-lan";
|
|
VLANFiltering = true;
|
|
DefaultPVID = 10;
|
|
};
|
|
};
|
|
};
|
|
networks = {
|
|
# Connect the bridge ports to the bridge
|
|
"30-lan1" = {
|
|
matchConfig.Name = "lan1";
|
|
networkConfig = {
|
|
Bridge = "br-lan";
|
|
ConfigureWithoutCarrier = true;
|
|
};
|
|
linkConfig.RequiredForOnline = "enslaved";
|
|
};
|
|
"30-lan2" = {
|
|
matchConfig.Name = "lan2";
|
|
networkConfig = {
|
|
Bridge = "br-lan";
|
|
ConfigureWithoutCarrier = true;
|
|
};
|
|
linkConfig.RequiredForOnline = "enslaved";
|
|
};
|
|
"30-lan3" = {
|
|
matchConfig.Name = "lan3";
|
|
networkConfig = {
|
|
Bridge = "br-lan";
|
|
ConfigureWithoutCarrier = true;
|
|
};
|
|
linkConfig.RequiredForOnline = "enslaved";
|
|
};
|
|
# Configure the bridge for its desired function
|
|
"40-br-lan" = {
|
|
matchConfig.Name = "br-lan";
|
|
bridgeConfig = {};
|
|
address = [
|
|
"192.168.10.1/24"
|
|
];
|
|
networkConfig = {
|
|
ConfigureWithoutCarrier = true;
|
|
};
|
|
# Don't wait for it as it also would wait for wlan and DFS which takes around 5 min
|
|
linkConfig.RequiredForOnline = "no";
|
|
};
|
|
# use lan0 as secondary WAN interface
|
|
"10-lan0-wan" = {
|
|
matchConfig.Name = "lan0";
|
|
networkConfig = {
|
|
# start a DHCP Client for IPv4 Addressing/Routing
|
|
DHCP = "ipv4";
|
|
# accept Router Advertisements for Stateless IPv6 Autoconfiguraton (SLAAC)
|
|
IPv6AcceptRA = true;
|
|
DNSOverTLS = true;
|
|
DNSSEC = true;
|
|
IPv6PrivacyExtensions = false;
|
|
IPForward = true;
|
|
};
|
|
# Don't wait for it as it also would wait for wlan and DFS which takes around 5 min
|
|
linkConfig.RequiredForOnline = "no";
|
|
};
|
|
"10-wan" = {
|
|
matchConfig.Name = "wan";
|
|
networkConfig = {
|
|
# start a DHCP Client for IPv4 Addressing/Routing
|
|
DHCP = "ipv4";
|
|
# accept Router Advertisements for Stateless IPv6 Autoconfiguraton (SLAAC)
|
|
IPv6AcceptRA = true;
|
|
DNSOverTLS = true;
|
|
DNSSEC = true;
|
|
IPv6PrivacyExtensions = false;
|
|
IPForward = true;
|
|
};
|
|
# make routing on this interface a dependency for network-online.target
|
|
linkConfig.RequiredForOnline = "routable";
|
|
};
|
|
};
|
|
};
|
|
|
|
# wireless access point
|
|
services.hostapd = {
|
|
enable = true;
|
|
radios = let
|
|
mkBssid = i: "34:56:ce:0f:ed:4${builtins.toString i}";
|
|
in {
|
|
wlan0 = {
|
|
band = "2g";
|
|
countryCode = "CH";
|
|
channel = 0; # ACS
|
|
|
|
# use 'iw phy#1 info' to determine your VHT capabilities
|
|
wifi4 = {
|
|
enable = true;
|
|
capabilities = ["HT40+" "LDPC" "SHORT-GI-20" "SHORT-GI-40" "TX-STBC" "RX-STBC1" "MAX-AMSDU-7935"];
|
|
};
|
|
networks = {
|
|
wlan0 = {
|
|
ssid = "justtestingwifi-wpa3";
|
|
authentication = {
|
|
mode = "wpa3-sae";
|
|
# saePasswordsFile = config.sops.secrets.wifiPassword.path;
|
|
saePasswords = [
|
|
{
|
|
password = "justtestingwifi";
|
|
# vlanid = 100;
|
|
}
|
|
];
|
|
};
|
|
|
|
# generated with https://miniwebtool.com/mac-address-generator/
|
|
bssid = mkBssid 0;
|
|
settings = {
|
|
bridge = "br-lan";
|
|
};
|
|
};
|
|
|
|
wlan0-1 = {
|
|
ssid = "justtestingwifi-compat";
|
|
authentication = {
|
|
mode = "wpa3-sae-transition";
|
|
# saePasswordsFile = config.sops.secrets.wifiPassword.path;
|
|
saePasswords = [
|
|
{
|
|
password = "justtestingwifi";
|
|
# vlanid = 100;
|
|
}
|
|
];
|
|
wpaPskFile = pkgs.writeText "pskfile" ''
|
|
00:00:00:00:00:00 justtestingwifi
|
|
# vlanid=100 00:00:00:00:00:00 justtestingwifi-vlan
|
|
'';
|
|
};
|
|
|
|
# generated with https://miniwebtool.com/mac-address-generator/
|
|
bssid = mkBssid 1;
|
|
settings = {
|
|
bridge = "br-lan";
|
|
};
|
|
};
|
|
|
|
# Uncomment when needed otherwise remove
|
|
# wlan0-1 = {
|
|
# ssid = "koteczkowo3";
|
|
# authentication = {
|
|
# mode = "none"; # this is overriden by settings
|
|
# };
|
|
# managementFrameProtection = "optional";
|
|
# bssid = "e6:02:43:07:00:00";
|
|
# settings = {
|
|
# bridge = "br-lan";
|
|
# wpa = lib.mkForce 2;
|
|
# wpa_key_mgmt = "WPA-PSK";
|
|
# wpa_pairwise = "CCMP";
|
|
# wpa_psk_file = config.sops.secrets.legacyWifiPassword.path;
|
|
# };
|
|
# };
|
|
};
|
|
};
|
|
# wlan1 = {
|
|
# band = "5g";
|
|
# # channels with 160 MHz width in Poland: 36, 52, 100 i 116
|
|
# channel = 0; # ACS
|
|
# countryCode = "PL";
|
|
|
|
# # use 'iw phy#1 info' to determine your VHT capabilities
|
|
# wifi4 = {
|
|
# enable = true;
|
|
# capabilities = ["HT40+" "LDPC" "SHORT-GI-20" "SHORT-GI-40" "TX-STBC" "RX-STBC1" "MAX-AMSDU-7935"];
|
|
# };
|
|
# wifi5 = {
|
|
# enable = true;
|
|
# operatingChannelWidth = "160";
|
|
# capabilities = ["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-4" "BF-ANTENNA-4" "VHT160" "MAX-MPDU-11454" "MAX-A-MPDU-LEN-EXP7"];
|
|
# };
|
|
# wifi6 = {
|
|
# enable = true;
|
|
# singleUserBeamformer = true;
|
|
# singleUserBeamformee = true;
|
|
# multiUserBeamformer = true;
|
|
# operatingChannelWidth = "160";
|
|
# };
|
|
# settings = {
|
|
# # these two are mandatory for wifi 5 & 6 to work
|
|
# vht_oper_centr_freq_seg0_idx = 50;
|
|
# he_oper_centr_freq_seg0_idx = 50;
|
|
|
|
# # The "tx_queue_data2_burst" parameter in Linux refers to the burst size for
|
|
# # transmitting data packets from the second data queue of a network interface.
|
|
# # It determines the number of packets that can be sent in a burst.
|
|
# # Adjusting this parameter can impact network throughput and latency.
|
|
# tx_queue_data2_burst = 2;
|
|
|
|
# # The "he_bss_color" parameter in Wi-Fi 6 (802.11ax) refers to the BSS Color field in the HE (High Efficiency) MAC header.
|
|
# # BSS Color is a mechanism introduced in Wi-Fi 6 to mitigate interference and improve network efficiency in dense deployment scenarios.
|
|
# # It allows multiple overlapping Basic Service Sets (BSS) to differentiate and coexist in the same area without causing excessive interference.
|
|
# he_bss_color = 63; # was set to 128 by openwrt but range of possible values in 2.10 is 1-63
|
|
|
|
# # Magic values that were set by openwrt but I didn't bother inspecting every single one
|
|
# 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_aci=0; missing in 2.10
|
|
# he_mu_edca_ac_be_aifsn = 8;
|
|
# 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;
|
|
# };
|
|
# networks = {
|
|
# wlan1 = {
|
|
# ssid = "koteczkowo5";
|
|
# authentication = {
|
|
# mode = "wpa3-sae";
|
|
# saePasswordsFile = config.sops.secrets.wifiPassword.path; # Use saePasswordsFile if possible.
|
|
# };
|
|
# bssid = "36:b9:02:21:08:a2";
|
|
# settings = {
|
|
# bridge = "br-lan";
|
|
# };
|
|
# };
|
|
# };
|
|
# };
|
|
};
|
|
};
|
|
|
|
services.resolved.enable = false;
|
|
|
|
services.dnsmasq = {
|
|
enable = true;
|
|
settings = {
|
|
# upstream DNS servers
|
|
server = ["9.9.9.9" "8.8.8.8" "1.1.1.1"];
|
|
# sensible behaviours
|
|
domain-needed = true;
|
|
bogus-priv = true;
|
|
no-resolv = true;
|
|
|
|
dhcp-range = ["br-lan,192.168.10.50,192.168.10.254,24h"];
|
|
interface = "br-lan";
|
|
dhcp-host = "192.168.10.1";
|
|
|
|
# local domains
|
|
local = "/lan/";
|
|
domain = "lan";
|
|
expand-hosts = true;
|
|
|
|
# don't use /etc/hosts as this would advertise ${nodeName} as localhost
|
|
no-hosts = true;
|
|
address = "/${nodeName}.lan/192.168.10.1";
|
|
};
|
|
};
|
|
|
|
# The service irqbalance is useful as it assigns certain IRQ calls to specific CPUs instead of letting the first CPU core to handle everything. This is supposed to increase performance by hitting CPU cache more often.
|
|
services.irqbalance.enable = true;
|
|
|
|
# disko.devices = {
|
|
# disk = {
|
|
# nvme0n1 = {
|
|
# device = "/dev/nvme0n1";
|
|
# type = "disk";
|
|
# content = {
|
|
# type = "table";
|
|
# format = "gpt";
|
|
# partitions = [
|
|
# {
|
|
# name = "var-log";
|
|
# start = "1MiB";
|
|
# end = "20G";
|
|
# content = {
|
|
# type = "filesystem";
|
|
# format = "ext4";
|
|
# mountpoint = "/var/log";
|
|
# };
|
|
# }
|
|
# {
|
|
# name = "tmp";
|
|
# start = "20G";
|
|
# end = "60G";
|
|
# content = {
|
|
# type = "filesystem";
|
|
# format = "ext4";
|
|
# mountpoint = "/tmp";
|
|
# };
|
|
# }
|
|
# {
|
|
# name = "var";
|
|
# start = "60G";
|
|
# end = "100G";
|
|
# content = {
|
|
# type = "filesystem";
|
|
# format = "ext4";
|
|
# mountpoint = "/var";
|
|
# };
|
|
# }
|
|
# {
|
|
# name = "swap";
|
|
# start = "100G";
|
|
# end = "100%";
|
|
# content = {
|
|
# type = "swap";
|
|
# randomEncryption = false;
|
|
# };
|
|
# }
|
|
# ];
|
|
# };
|
|
# };
|
|
# };
|
|
# };
|
|
|
|
system.stateVersion = "23.05";
|
|
|
|
boot.kernelPackages = pkgs.linuxPackages_bpir3;
|
|
# boot.kernelPackages = bpir3.packages.aarch64-linux.linuxPackages_bpir3;
|
|
# We exclude a number of modules included in the default list. A non-insignificant amount do
|
|
# not apply to embedded hardware like this, so simply skip the defaults.
|
|
#
|
|
# Custom kernel is required as a lot of MTK components misbehave when built as modules.
|
|
# They fail to load properly, leaving the system without working ethernet, they'll oops on
|
|
# remove. MTK-DSA parts and PCIe were observed to do this.
|
|
boot.initrd.includeDefaultModules = false;
|
|
boot.initrd.kernelModules = ["rfkill" "cfg80211" "mt7915e"];
|
|
boot.initrd.availableKernelModules = ["nvme"];
|
|
|
|
boot.kernelParams = ["console=ttyS0,115200"];
|
|
hardware.enableRedistributableFirmware = true;
|
|
# Wireless hardware exists, regulatory database is essential.
|
|
hardware.wirelessRegulatoryDatabase = true;
|
|
|
|
# Extlinux compatible with custom uboot patches in this repo, which also provide unique
|
|
# MAC addresses instead of the non-unique one that gets used by a lot of MTK devices...
|
|
boot.loader.grub.enable = false;
|
|
boot.loader.generic-extlinux-compatible.enable = true;
|
|
# Known to work with u-boot; bz2, lzma, and lz4 should be safe too, need to test.
|
|
boot.initrd.compressor = "gzip";
|
|
hardware.deviceTree.filter = "mt7986a-bananapi-bpi-r3.dtb";
|
|
|
|
hardware.deviceTree.overlays = [
|
|
{
|
|
name = "bpir3-sd-enable";
|
|
dtsFile = "${bpir3}/bpir3-dts/mt7986a-bananapi-bpi-r3-sd.dts";
|
|
}
|
|
{
|
|
name = "bpir3-nand-enable";
|
|
dtsFile = "${bpir3}/bpir3-dts/mt7986a-bananapi-bpi-r3-nand.dts";
|
|
}
|
|
{
|
|
name = "bpi-r3 wifi training data";
|
|
dtsFile = "${bpir3}/bpir3-dts/mt7986a-bananapi-bpi-r3-wirless.dts";
|
|
}
|
|
{
|
|
name = "reset button disable";
|
|
dtsFile = "${bpir3}/bpir3-dts/mt7986a-bananapi-bpi-r3-pcie-button.dts";
|
|
}
|
|
{
|
|
name = "mt7986a efuses";
|
|
dtsFile = "${bpir3}/bpir3-dts/mt7986a-efuse-device-tree-node.dts";
|
|
}
|
|
];
|
|
|
|
boot.initrd.preDeviceCommands = ''
|
|
if [ ! -d /sys/bus/pci/devices/0000:01:00.0 ]; then
|
|
if [ -d /sys/bus/pci/devices/0000:00:00.0 ]; then
|
|
# Remove PCI bridge, then rescan. NVMe init crashes if PCI bridge not removed first
|
|
echo 1 > /sys/bus/pci/devices/0000:00:00.0/remove
|
|
# Rescan brings PCI root back and brings the NVMe device in.
|
|
echo 1 > /sys/bus/pci/rescan
|
|
else
|
|
info "PCIe bridge missing"
|
|
fi
|
|
fi
|
|
'';
|
|
|
|
environment.systemPackages = [
|
|
pkgs.ethtool
|
|
];
|
|
}
|