Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/chayleaf/nixos-router

A NixOS router framework
https://github.com/chayleaf/nixos-router

networking nix nixos nixos-module router

Last synced: about 1 month ago
JSON representation

A NixOS router framework

Awesome Lists containing this project

README

        

# nixos-router

This project has an ambitious goal of creating a framework for writing
NixOS router configurations - in other words, being the
[simple-nixos-mailserver](https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/)
of the networking world, but without the "simple" part, because
networking is hard. This may include complex features like running
multiple DHCP servers, using network namespaces, having interfaces turn
on and off while the rest of the system keeps working, etc.

Sadly, NixOS is written without such requirements in mind. That means
this project has to create the code from scratch. This is both a
blessing and a curse - we can't reuse the existing code, but we can
write new, better code that is more flexible.

That said, I'm not using this at an enterprise or an ISP, this is simply
for my home router config (yes, overkill, I know). So this is bound to
not fit everybody's needs right now. Obviously, I'm willing to add more
features even at the cost of breaking existing configs if necessary
(after all, this project is in its infancy).

I'll try to keep breaking changes to a minimum, but as I said, I can't
guarantee they won't happen (even NixOS has them).

There are separate branches for stable NixOS versions (like the 24.05
branch for NixOS 24.05), each branch will only be supported until the
next stable NixOS release. Support entails non-breaking bugfixes and
certain backports. For nixos-unstable, use the master branch.

I doubt it would be easy to upstream these changes to nixpkgs, as it
would introduce many breaking changes on top of breaking changes, so I
am not willing to work on it. Some parts are more upstreamable, such as
allowing JSON nftables rulesets, while other are less upstreamable,
like... most parts of this repo, which are a reimplementation of
scripted networking, which some nixpkgs members want to get rid of in
general (in favor of systemd-networkd).

When [this](https://github.com/systemd/systemd/issues/11103) gets
closed, I might be able to migrate to systemd-networkd. This may be the
time when `networking.interfaces` and this repo become compatible again.

This module expects you to use nftables, so it modifies NixOS's default
settings to use nftables. Firewall is still set to use iptables, but if
you set `networking.nftables.enable` to `true`, it should use nftables.

## Roadmap

I think the next logical step for this project is adding nftables
options for common scenarios like NAT, so this is what I want to do
next. Right now you're expected to create the nftables rules from
scratch, but something like `networking.nat` (but with more
customizability) could be nice. Another potential way to improve this is
adding the missing virtual device types (currently only bridges and veth
pairs are supported; `networking` has bridge, bond, MacVLAN, 6-to-4,
VLAN, Open vSwitch device support).

## See also

- [notnft](https://github.com/chayleaf/notnft) - a Nix DSL for writing
JSON nftables rules. If you use the included NixOS module, it is
automatically used for type checking JSON nftables rules.
- [My router
config](https://github.com/chayleaf/dotfiles/blob/master/system/hosts/router/default.nix)
using this framework.

## Options

See [the wiki](https://github.com/chayleaf/nixos-router/wiki/Options)
for an automatically built option list. This is a manually condensed
version of the option list.

- `router.enable` - whether to do anything at all
- `router.networkNamespaces` - per-network namespace config.
- A special namespace `default` is available for configuring the
default namespace.
- `.extraStartCommands` - extra commands to execute at
network namespace start
- `.extraStopCommands` - extra commands to execute at
network namespace stop
- `.rules` - IP routing rules to add for this namespace via
`ip rule`
- `.ipv6` - whether this rule is an IPv6 rule
- `.extraArgs` - arguments to pass to the `ip rule`
command. May be a list or a string.
- `.sysctl` - per-netns sysctl config
- This is useful because with separate network namespaces, sysctl
config is separate to some extent as well (e.g. forwarding rules)
- `.nftables` - nftables config to run in this namespace
(see `router.nftables` for options)
- Difference from `networking.nftables` - this supports JSON
rulesets, and lets you specify custom stop/reload rules, while
`networking.nftables` always flushes the ruleset on stop. Also, it
supports loading static rules and file-based rules at the same
time. One-way `networking.nftables` operability is supported.
- `.nftables.textFile` - `.nft` file to load
- `.nftables.textRules` - nft rules to load
- `.nftables.jsonFile` - `.json` file to load
- `.nftables.jsonRules` - JSON rules to load
- `.nftables.{stopTextFile,stopTextRules,stopJsonFile,stopJsonRules}` -
same as above, but get executed *before first start* and at
stop/reload time. Basically, they are supposed to undo the changes
this ruleset applies, or do nothing if it's not applied anyway.
They default to `flush ruleset` if no stop rules are set.
- `router.tunnels.` - IP tunnels
- `.mode` - tunnel mode (`gre | ipip | isatap | sit | vti`)
- `.remote` - remote address
- `.local` - local address
- `.ttl` - time to live
- `router.veths.` - veth pairs
- `.peerName` - peer name (second device to be created at the
same time)
- `router.interfaces.` - per-interface config
- Difference from `networking.interfaces` - it's just subtly
different... Many features were added that `networking.interfaces`
is incompatible with. This means you can't use it together with
`networking.interfaces`, as both `router.interfaces` and
`networking.interfaces` expect having to set the interfaces up.
- `.bridge` - bridge name to enslave this device to
- `.vlans.*` - VLAN filtering configuration
- `.vid` - VLAN id filter
- `.untagged` - whether this should match untagged traffic
(defaults to false)
- `.extraInitCommands` - extra commands to execute before
bridge/address configuration
- `.networkNamespace` - the network namespace where this device
and all dependent services will run
- `.dependentServices` - services that should depend on this
interface
- each is either a string (service name) or an attrset with the key
`service` and the rest being attrs to to pass to
`router-lib.mkServiceForIf'`, for example, you can set `inNetns`
to false to not use this interface's network namespace.
- `.systemdLink.linkConfig` - values to add to
[systemd.link(5)](https://www.freedesktop.org/software/systemd/man/systemd.link.html)
`[Link]` config for this interface
- `.systemdLink.matchConfig` - values to add to
[systemd.link(5)](https://www.freedesktop.org/software/systemd/man/systemd.link.html)
`[Match]` config for this interface. Defaults to `{ OriginalName =
""; }`
- `.hostapd` - run hostapd to turn this device into a wireless
access point
- `.hostapd.enable` - enable hostapd
- `.hostapd.settings` - hostapd settings (attrset). See
example
[hostapd.conf](https://w1.fi/cgit/hostap/plain/hostapd/hostapd.conf)
for a list of options. Personally, I copied OpenWRT configs for
my router.
- There's a way to host multiple ssids on a single interface in
hostapd (on supported interfaces), this module doesn't currently
support it
- `.dhcpcd` - run `dhcpcd` on this interface.
- The reasons for adding it here:
- `dhcpcd` may fail in rare cases when not specifing the interface
list in the command line, which I do here.
- Strong caution is needed when running a single `dhcpcd` on many
interfaces, as settings may "leak" into other interfaces.
Example of an option you need to be careful with is IPv6 router
solicitation (ipv6rs).
- `.dhcpcd.enable` - enable dhcpcd on this interface
- `.dhcpcd.extraConfig` - extra text config for dhcpcd
- `.ipv4` - IPv4-specific config:
- `.ipv4.enableForwarding` - sets `forwarding` sysctl for
this device so it can forward packets it receives.
- `.ipv4.rpFilter` - set `rp_filter` value for this device to
check reverse path and block non-existent IPs (value 2) or IPs
coming from the wrong interfaces (value 1). Alternatively, you can
ignore this and query fib in nftables.
- `.ipv4.addresses` - IPv4 addresses of this device
- `.address` - the address
- `.prefixLength` - network prefix length
- `.assign` - whether to actually assign the address to this
device (defaults to `false` if the first octet is zero and
`true` otherwise). If not, it will simply be used as default
value for service config.
- `.gateways` - for DHCP servers - the IPv4 gateways for
this network. If not set, `address` is used as the sole gateway.
- `.dns` - for DHCP servers - IPv4 DNS servers for this
network.
- `.keaSettings` - prefix-specific Kea settings (only used
if Kea is enabled). `pools` has sane defaults (reserve 16
addresses before and after the interface address and
before and after prefix start/end, make the rest available
for DHCP clients), `option-data` defaults to whatever you
set in `gateways` and `dns`. If you want to unset those
settings, overwrite `pools` and `option-data` with empty
(or non-empty) lists.
- `.ipv4.routes` - List of IPv4 route to add when this device
is online.
- `.extraArgs` - arguments to pass to the `ip -4 add`
command. May be a list or a string.
- There is no other options for `routes`, that's it.
- `.ipv4.kea` - Kea settings (maintained replacement for
dhcpd)
- `.ipv4.kea.enable` - enable Kea
- `.ipv4.kea.extraArgs` - extra args to pass to Kea
- `.ipv4.kea.configFile` - Kea config file (if this is set,
all other Kea settings are ignored)
- `.ipv4.kea.settings` - Kea settings. Defaults to one
`subnet4` (see `addresses.keaSettings` for a way to configure
it), `valid-lifetime = 4000`, `lease-database` set to a file at
`/var/lib/kea/dhcp4-${interface}.leases`, and obviously
`interfaces-config` set. You may overwrite any of it.
- `.ipv6` - IPv6-specific config:
- `.ipv6.enableForwarding` - sets `forwarding` sysctl for
this device so it can forward packets it receives. Obviously,
you better setup a firewall if you do this.
- `.ipv6.addresses` - List of IPv6 addresses of this device
- `.address` - the address
- `.prefixLength` - network prefix length
- `.assign` - whether to actually assign the address to this
device (defaults to `false` if the first octet is zero and
`true` otherwise). Otherwise, it will simply be used as
default value for service config.
- `.gateways` - for DHCP servers - the IPv6 gateways for
this network. If empty, I don't know what happens, you guess.
- Each gateway may be a string in the CIDR notation.
Alternatively, it may be an attrset with the following
attrs:
- `.address` - the address
- `.prefixLength` - network prefix length
- `.radvdSettings` - radvd `route` settings for this
gateway (attrset)
- `.coreradSettings` - CoreRAD `route` settings for
this gateway (attrset)
- `.dns` - for DHCP servers - IPv6 DNS servers for this
network.
- Each DNS server may be a string (the DNS address).
Alternatively, if may be an attrset with the following attrs:
- `address` - the DNS server address
- `radvdSettings` - radvd `RDNSS` settings for this
DNS server (attrset)
- `coreradSettings` - CoreRAD `rdnss` settings for this
DNS server (attrset)
- `.keaSettings` - prefix-specific Kea settings (only used
if Kea is enabled). `pools` has sane defaults (reserve 16
addresses before and after the interface address and
before and after prefix start/end, make the rest available
for DHCP clients), `option-data` defaults to whatever you
set in `dns`. If you want to unset it settings, overwrite
`pools` and `option-data` with empty (or non-empty) lists.
- `.radvdSettings` - radvd per-prefix settings (attrset).
`AdvAutonomous` defaults to `true` if `AdvManagedFlag` is set to
true in per-interface radvd settings.
- `.coreradSettings` - CoreRAD per-prefix settings
(attrset). `autonomous` defaults to `true` if `managed` is set
to true in per-interface CoreRAD settings.
- `.ipv6.routes` - List of IPv6 routes to add when this
device is online.
- `.extraArgs` - arguments to pass to the `ip -6 add`
command. May be a list or a string.
- There is no other options for `routes`, that's it.
- `.ipv6.kea` - Kea settings (maintained replacement for
dhcpd)
- `.ipv6.kea.enable` - enable Kea
- `.ipv6.kea.extraArgs` - extra args to pass to Kea
- `.ipv6.kea.configFile` - Kea config file (if this is set,
all other Kea settings are ignored)
- `.ipv6.kea.settings` - Kea settings. Defaults to one
`subnet6` (see `addresses.*.keaSettings` for a way to configure
it), `valid-lifetime = 4000`, `preferred-lifetime = 3000`
`lease-database` set to a file at
`/var/lib/kea/dhcp6-${interface}.leases`, and obviously
`interfaces-config` set. You may overwrite any of it.
- `.ipv6.radvd` - radvd settings (IPv6 router advertisement
daemon)
- `.ipv6.radvd.enable` - enable radvd
- `.ipv6.radvd.interfaceSettings` - per-interface settings
(attrs). Defaults to `AdvSendAdvert = true`, if any DHCP server
(e.g. Kea) is enabled then `AdvManagedFlag` and
`AdvOtherConfigFlag` default to true as well.
- `.ipv6.corerad` - CoreRAD settings (IPv6 router
advertisement daemon)
- `.ipv6.corerad.enable` - enable radvd
- `.ipv6.corerad.interfaceSettings` - per-interface
settings (attrs). Defaults to `advertise = true`, if any DHCP
server (e.g. Kea) is enabled then `managed` and `other_config`
default to true as well.
- `.ipv6.corerad.settings` - general CoreRAD settings
(useful for setting `debug` options)