Skip to content

Instantly share code, notes, and snippets.

@Emantor
Created January 14, 2022 18:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Emantor/77b4f59221cc4ab327de749660548841 to your computer and use it in GitHub Desktop.
Save Emantor/77b4f59221cc4ab327de749660548841 to your computer and use it in GitHub Desktop.
router.nix
# Edit this configuration file to define what should be installed on
# your system. Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running ‘nixos-help’).
{ config, pkgs, ... }:
{
imports =
[ # Include the results of the hardware scan.
./hardware-configuration.nix
../../profiles
];
# This is an APU2C4, enable serial output.
boot.kernelParams = [ "console=ttyS0,115200n8" ];
# Flowtables for physical interfaces only work in 5.13+
boot.kernelPackages = pkgs.linuxPackages_latest;
# Use the GRUB 2 boot loader.
boot.loader.grub.enable = true;
boot.loader.grub.version = 2;
boot.loader.grub.device = "/dev/sda";
# This is an APU2C4, enable serial grub2 output.
boot.loader.grub.extraConfig = "
serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1
terminal_input serial
terminal_output serial
";
# boot.loader.grub.efiSupport = true;
# boot.loader.grub.efiInstallAsRemovable = true;
# boot.loader.efi.efiSysMountPoint = "/boot/efi";
# Define on which hard drive you want to install Grub.
# boot.loader.grub.device = "/dev/sda"; # or "nodev" for efi only
networking.hostName = "pseudopolisyard"; # Define your hostname.
networking.domain = "discworld.emantor.de"; # Define your domain.
# networking.wireless.enable = true; # Enables wireless support via wpa_supplicant.
# Set your time zone.
# time.timeZone = "Europe/Amsterdam";
# The global useDHCP flag is deprecated, therefore explicitly set to false here.
# Per-interface useDHCP will be mandatory in the future, so this generated config
# replicates the default behaviour.
environment.systemPackages = with pkgs; [
conntrack-tools
];
networking = {
useDHCP = false;
nat.enable = false;
firewall.enable = false;
nftables = {
enable = true;
ruleset = ''
table inet filter {
# enable flow offloading for better throughput
flowtable f {
hook ingress priority 0;
devices = { enp2s0, enp1s0 };
}
chain output {
type filter hook output priority 100; policy accept;
oifname "lo" ip6 daddr != ::1/128 log prefix "Dropped IPv6 nonlocalhost packet on loopback:" drop
oifname "ppp0" ip6 daddr fe80::/10 icmpv6 type echo-request ct state new,established accept
}
chain input {
type filter hook input priority 0; policy drop;
ct state {established, related} counter accept comment "accept all connections related to connections made by us"
ct state invalid counter drop comment "early drop of invalid packets"
# Allow trusted networks to access the router
iif "enp1s0" counter accept
iif "enp2s0" counter accept
iifname "guest.100*" counter accept
iifname "devices.300*" counter accept
iifname "wg-roadwarrior" counter accept
# DHCPv6
meta nfproto ipv6 udp sport 547 accept comment "DHCPv6 client"
# Wireguard
meta nfproto ipv4 udp dport 51820 accept comment "Wireguard"
# Allow ICMP
ip protocol icmp counter accept comment "accept all ICMP types"
ip6 nexthdr icmpv6 counter accept comment "accept all ICMP types"
# Accept loopback traffic
iif lo accept comment "Accept Loopback traffic"
# Allow returning traffic from ppp0 and drop everthing else
iifname "ppp0" ct state established,related counter accept
iifname "ppp0" drop
iifname "lo" ip6 saddr != ::1/128 log prefix "Dropped IPv6 nonlocalhost packet on loopback:" drop
}
chain forward {
type filter hook forward priority 0; policy drop;
tcp flags syn tcp option maxseg size set rt mtu
ct status dnat counter accept
# enable flow offloading for better throughput
# currently broken, needs further investigation
# ip protocol { tcp, udp } flow offload @f
# Forward ICMPv6
icmpv6 type echo-request limit rate 5/second counter accept
icmpv6 type echo-request counter drop
meta l4proto ipv6-icmp accept
# Allow trusted network WAN access
iif "enp1s0" counter accept comment "Allow all traffic forwarding from LAN "
iif "enp2s0" counter accept comment "Allow VDSL router forwarding"
iifname "wg-roadwarrior" counter accept comment "Allow all traffic forwarding from Wireguard"
iifname "guest.100*" oifname "ppp0" counter accept comment "Allow trusted Guest to WAN"
# Allow established WAN to return
iifname "ppp0" oif "enp1s0" ct state established,related counter accept comment "Allow established back to LANs"
iifname "ppp0" oifname "wg-roadwarrior" ct state established,related counter accept comment "Allow established back to Wireguard"
iifname "ppp0" oifname "guest.100*" ct state established,related counter accept comment "Allow established back to Guest"
}
}
table ip nat {
chain prerouting {
type nat hook prerouting priority -100; policy accept;
iifname "ppp0" tcp dport 53 dnat to 192.168.128.220
iifname "ppp0" udp dport 53 dnat to 192.168.128.220
}
# Setup NAT masquerading on the ppp0 interface
chain postrouting {
type nat hook postrouting priority 100; policy accept;
oifname "ppp0" masquerade
}
}
table arp filter {
chain input {
type filter hook input priority 0; policy accept;
iif enp1s0 limit rate 1/second burst 2 packets accept
}
chain output {
type filter hook output priority 0; policy accept;
}
}
'';
};
};
# Configure network proxy if necessary
# networking.proxy.default = "http://user:password@proxy:port/";
# networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";
# Select internationalisation properties.
# i18n.defaultLocale = "en_US.UTF-8";
# console = {
# font = "Lat2-Terminus16";
# keyMap = "us";
# };
# Enable the X11 windowing system.
# services.xserver.enable = true;
# Configure keymap in X11
# services.xserver.layout = "us";
# services.xserver.xkbOptions = "eurosign:e";
# Enable CUPS to print documents.
# services.printing.enable = true;
# Enable sound.
# sound.enable = true;
# hardware.pulseaudio.enable = true;
# Enable touchpad support (enabled default in most desktopManager).
# services.xserver.libinput.enable = true;
# Define a user account. Don't forget to set a password with ‘passwd’.
# users.users.jane = {
# isNormalUser = true;
# extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user.
# };
# List packages installed in system profile. To search, run:
# $ nix search wget
# environment.systemPackages = with pkgs; [
# vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default.
# wget
# firefox
# ];
# Some programs need SUID wrappers, can be configured further or are
# started in user sessions.
# programs.mtr.enable = true;
# programs.gnupg.agent = {
# enable = true;
# enableSSHSupport = true;
# };
# List services that you want to enable:
# Enable the OpenSSH daemon.
services.openssh.enable = true;
services.resolved = {
enable = true;
domains = [ "discworld.emantor.de" ];
};
networking.nameservers = [ "127.0.0.1" ];
systemd.network = {
enable = true;
netdevs = {
"devices.300" = {
netdevConfig = {
Kind = "vlan";
Name = "devices.300";
};
vlanConfig = {
Id = 300;
};
};
"guest.100" = {
netdevConfig = {
Kind = "vlan";
Name = "guest.100";
};
vlanConfig = {
Id = 100;
};
};
};
networks = {
"ppp" = {
name = "ppp*";
networkConfig = {
KeepConfiguration = "static";
DefaultRouteOnDevice = true;
LinkLocalAddressing = "ipv6";
DHCP = "ipv6";
};
dhcpV6Config = {
ForceDHCPv6PDOtherInformation = true;
PrefixDelegationHint= "::/56";
};
extraConfig = ''
[CAKE]
OverheadBytes = 65
Bandwidth = 40M
'';
};
"enp1s0" = {
name = "enp1s0";
networkConfig = {
Address = "192.168.128.254/24";
Domains = "discworld.emantor.de";
VLAN = [ "devices.300" "guest.100" ];
EmitLLDP = "yes";
IPv6SendRA = true;
DHCPv6PrefixDelegation = true;
};
dhcpV6PrefixDelegationConfig = {
SubnetId = "0x1";
};
ipv6Prefixes = [
{
ipv6PrefixConfig.Prefix = "fd66:a562:1af6:1::/64";
}
];
extraConfig = ''
[CAKE]
OverheadBytes = 38
Bandwidth = 1G
'';
};
"enp2s0" = {
name = "enp2s0";
networkConfig = {
Address = "192.168.1.254/24";
EmitLLDP = "yes";
};
};
"devices.300" = {
name = "devices.300";
networkConfig = {
Address = "172.16.128.254/24";
EmitLLDP = "yes";
IPv6SendRA = false;
};
ipv6Prefixes = [
{
ipv6PrefixConfig.Prefix = "fd66:a562:1af6:300::/64";
}
];
};
"guest.100" = {
name = "guest.100";
networkConfig = {
Address = "192.168.120.254/24";
EmitLLDP = "yes";
IPv6SendRA = true;
DHCPv6PrefixDelegation = true;
};
dhcpV6PrefixDelegationConfig = {
SubnetId = "0x2";
};
ipv6Prefixes = [
{
ipv6PrefixConfig.Prefix = "fd66:a562:1af6:100::/64";
}
];
};
};
};
# Forwarding configuration
boot.kernel.sysctl = {
# if you use ipv4, this is all you need
"net.ipv4.conf.all.forwarding" = true;
# If you want to use it for ipv6
"net.ipv6.conf.all.forwarding" = true;
# source: https://github.com/mdlayher/homelab/blob/master/nixos/routnerr-2/configuration.nix#L52
# By default, not automatically configure any IPv6 addresses.
"net.ipv6.conf.all.accept_ra" = 0;
"net.ipv6.conf.all.autoconf" = 0;
"net.ipv6.conf.all.use_tempaddr" = 0;
};
# PPPoE
services.pppd = {
enable = true;
peers = {
einsundeins = {
# Autostart the PPPoE session on boot
autostart = true;
enable = true;
config = ''
plugin rp-pppoe.so enp2s0
# pppd supports multiple ways of entering credentials,
# this is just 1 way
name "<username>"
persist
maxfail 0
holdoff 5
noipdefault
defaultroute
'';
};
};
};
# DNS
services.unbound = {
enable = true;
settings = {
server = {
access-control = [
"127.0.0.0/8 allow"
"127.0.0.1/32 allow_snoop"
"192.168.128.0/23 allow"
"192.168.120.0/24 allow"
"172.16.128.0/24 allow"
"::1/128 allow_snoop"
];
interface = ["127.0.0.1" "192.168.128.254" "172.16.128.254" "192.168.120.254" "::1"];
val-permissive-mode = "yes";
module-config = "iterator";
local-zone = [
"\"168.192.in-addr.arpa.\" nodefault"
"\"d.f.ip6.arpa.\" nodefault"
];
};
forward-zone = let
fwZone = name: addrs: { name = "${name}"; forward-addr = addrs; };
in
[
(fwZone "." [ "8.8.8.8" "8.8.4.4" ])
];
stub-zone = let
stubZone = name: addrs: { name = "${name}"; stub-addr = addrs; };
in
[
(stubZone "discworld.emantor.de" ["192.168.128.220"])
(stubZone "6.f.a.1.2.6.5.a.6.6.d.f.ip6.arpa" ["192.168.128.220"])
(stubZone "168.192.in-addr.arpa" ["192.168.128.220"])
];
};
};
# DHCP
services.dhcpd4 = {
enable = true;
interfaces = [ "enp1s0" "guest.100" "devices.300"];
extraConfig = ''
ddns-update-style none;
subnet 192.168.128.0 netmask 255.255.255.0 {
range 192.168.128.100 192.168.128.200;
option routers 192.168.128.254;
option ntp-servers 192.168.128.254;
option domain-name-servers 192.168.128.254;
option domain-name "discworld.emantor.de";
}
subnet 172.16.128.0 netmask 255.255.255.0 {
range 172.16.128.100 172.16.128.200;
option routers 172.16.128.254;
option ntp-servers 172.16.128.254;
option domain-name-servers 172.16.128.254;
option domain-name "devices.discworld.emantor.de";
}
subnet 192.168.120.0 netmask 255.255.255.0 {
range 192.168.120.100 192.168.120.200;
option routers 192.168.120.254;
option ntp-servers 192.168.120.254;
option domain-name-servers 192.168.120.254;
option domain-name "guest.discworld.emantor.de";
}
'';
};
# NTP
services.chrony = {
enable = true;
extraConfig = ''
allow 192.168.128
allow 172.16.128
allow 192.168.120
allow 192.168.1
'';
};
systemd.services.restart-ppp = {
enable = true;
unitConfig = {
Description = "Restart pppd-einsundeins service";
};
serviceConfig = {
Type = "oneshot";
ExecStart= [ "${pkgs.systemd}/bin/systemctl restart pppd-einsundeins.service" ];
};
};
systemd.timers.restart-ppp = {
unitConfig = {
Description = "PPP restart in the night";
};
timerConfig = {
OnCalendar = [ "*-*-* 4:00:00" ];
};
wantedBy = [ "default.target" ];
};
# DDNS
services.ddclient = {
enable = true;
use = "web, web=http://ipv4.stratum0.net/myip";
ssl = true;
server = "ipv4.stratum0.net";
username = "discworld.stratum0.net";
domains = [ "discworld.stratum0.net" ];
passwordFile = "/var/keys/ddns-stratum0";
};
# Wireguard
networking.wg-quick.interfaces = {
wg-roadwarrior = {
address = [ "192.168.129.254/24" ];
privateKeyFile = "/var/keys/wg-roadwarrior";
listenPort = 51820;
peers = [{
allowedIPs = [ "192.168.129.12/32" ];
publicKey = "FiwOiRnnMNlTf8nSlIqdzZXWBvbx8WIVAvbi7b/HHE0=";
}{
allowedIPs = [ "192.168.129.11/32" ];
publicKey = "OoaatUQ37OI1HnKNYavgDcp84fF5Ze3k1Q2ELsoqrA0=";
}{
allowedIPs = [ "192.168.129.10/32" ];
publicKey = "Zd0Y+IeApNqd0j22XrYWDAbEwfxObqnNxFDFBNbs70Q=";
}];
};
};
# This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions
# on your system were taken. It‘s perfectly fine and recommended to leave
# this value at the release version of the first install of this system.
# Before changing this value read the documentation for this option
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
system.stateVersion = "21.11"; # Did you read the comment?
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment