1
0

Compare commits

...

5 Commits

7 changed files with 182 additions and 75 deletions

View File

@ -13,10 +13,29 @@ of "limen", or "of the threshold". Your router stands at the threshold
of your (online) home and everything you send to/receive from the
outside word goes across it.
## What about NixWRT?
This is an in-progress rewrite of NixWRT, incorporating Lessons
Learned.
## Current status (does it work yet?)
Liminix is pre-1.0. We are still finding new and better ways to do things,
and there is no attempt to maintain backward compatibility with the old
ways. This will change when it settles down.
In general: development mostly happens on the `main` branch, which is
therefore not guaranteed to build or to work on every commit. For the
latest functioning version, see [the CI system](https://build.liminix.org/jobset/liminix/build) and pick a
revision with all jobs green.
In particular, as of July 2023, a significant re-arrangement of
modules and services is ongoing:
* if you are using out-of-tree configurations created before commit
2e50368, especially if they reference things under pkgs.liminix,
they will need updating. Look at changes to examples/rotuer.nix
for guidance
* the same is intermittently true for examples/{extensino,arhcive}.nix
where I've updated rotuer and not updated them to match.
## Documentation
@ -25,6 +44,9 @@ by running
nix-shell -p sphinx --run "make -C doc html"
Rendered documentation corresponding to the latest commit on `main`
is published to [https://www.liminix.org/doc/](https://www.liminix.org/doc/)
## Extremely online

View File

@ -11,7 +11,6 @@ let
secrets = import ./rotuer-secrets.nix;
inherit (pkgs.liminix.networking)
address
hostapd
interface
route;
inherit (pkgs.liminix.services) oneshot longrun bundle target;
@ -35,43 +34,19 @@ in rec {
../modules/standard.nix
../modules/ppp
../modules/dnsmasq
../modules/firewall
../modules/hostapd
];
rootfsType = "jffs2";
hostname = "rotuer";
kernel = {
config = {
BRIDGE = "y";
NETFILTER_XT_MATCH_CONNTRACK = "y";
IP6_NF_IPTABLES= "y"; # do we still need these
IP_NF_IPTABLES= "y"; # if using nftables directly
IP_NF_NAT = "y";
IP_NF_TARGET_MASQUERADE = "y";
NETFILTER = "y";
NETFILTER_ADVANCED = "y";
NETFILTER_XTABLES = "y";
NFT_COMPAT = "y";
NFT_CT = "y";
NFT_LOG = "y";
NFT_MASQ = "y";
NFT_NAT = "y";
NFT_REJECT = "y";
NFT_REJECT_INET = "y";
NF_CONNTRACK = "y";
NF_NAT = "y";
NF_NAT_MASQUERADE = "y";
NF_TABLES= "y";
NF_TABLES_INET = "y";
NF_TABLES_IPV4 = "y";
NF_TABLES_IPV6 = "y";
};
};
services.hostap = hostapd (config.hardware.networkInterfaces.wlan_24) {
services.hostap = config.system.service.hostapd {
interface = config.hardware.networkInterfaces.wlan_24;
params = {
ssid = "liminix";
country_code = "GB";
@ -88,7 +63,8 @@ in rec {
};
};
services.hostap5 = hostapd (config.hardware.networkInterfaces.wlan_5) {
services.hostap5 = config.system.service.hostapd {
interface = config.hardware.networkInterfaces.wlan_5;
params = rec {
ssid = "liminix_5";
country_code = "GB";
@ -220,35 +196,9 @@ in rec {
dependencies = [ services.wan ];
};
services.firewall =
let
script= pkgs.firewallgen "firewall.nft" (import ./rotuer-firewall.nix);
kmodules = pkgs.kernel-modules.override {
kernelSrc = config.system.outputs.kernel.src;
modulesupport = config.system.outputs.kernel.modulesupport;
kconfig = {
NFT_FIB_IPV4 = "m";
NFT_FIB_IPV6 = "m";
NF_TABLES = "m";
NF_CT_PROTO_DCCP = "y";
NF_CT_PROTO_SCTP = "y";
NF_CT_PROTO_UDPLITE = "y";
# NF_CONNTRACK_FTP = "m";
NFT_CT = "m";
};
targets = [
"nft_fib_ipv4"
"nft_fib_ipv6"
];
};
in oneshot {
name = "firewall";
up = ''
sh ${kmodules}/load.sh
${script};
'';
down = "${pkgs.nftables}/bin/nft flush ruleset";
};
services.firewall = config.system.service.firewall {
ruleset = import ./rotuer-firewall.nix;
};
services.packet_forwarding =
let

View File

@ -26,6 +26,11 @@ in {
};
kernel = {
src = mkOption { type = types.package; } ;
modular = mkOption {
type = types.boolean;
default = true;
description = "support loadable kernel modules";
};
extraPatchPhase = mkOption {
default = "true";
type = types.lines;
@ -67,14 +72,15 @@ in {
};
kernel = rec {
modular = true; # disabling this is not yet supported
config = {
IKCONFIG = "y";
IKCONFIG_PROC = "y";
PROC_FS = "y";
KEXEC = "y";
MODULES = "y";
MODULE_SIG = "y";
MODULES = if modular then "y" else "n";
MODULE_SIG = if modular then "y" else "n";
DEBUG_FS = "y";
MIPS_BOOTLOADER_CMDLINE_REQUIRE_COOKIE = "y";

View File

@ -0,0 +1,79 @@
{ lib, pkgs, config, ...}:
let
inherit (lib) mkOption types;
inherit (pkgs.liminix.services) oneshot;
kconf = isModule :
# setting isModule false is utterly untested and mostly
# unimplemented: I say this to preempt any "how on earth is this
# even supposed to work?" questions
let yes = if isModule then "m" else "y";
in {
NFT_FIB_IPV4 = yes;
NFT_FIB_IPV6 = yes;
NF_TABLES = yes;
NF_CT_PROTO_DCCP = "y";
NF_CT_PROTO_SCTP = "y";
NF_CT_PROTO_UDPLITE = "y";
# NF_CONNTRACK_FTP = yes;
NFT_CT = yes;
};
kmodules = pkgs.kernel-modules.override {
kernelSrc = config.system.outputs.kernel.src;
modulesupport = config.system.outputs.kernel.modulesupport;
targets = [
"nft_fib_ipv4"
"nft_fib_ipv6"
];
kconfig = kconf true;
};
loadModules = oneshot {
name = "firewall-modules";
up = "sh ${kmodules}/load.sh";
down = "sh ${kmodules}/unload.sh";
};
in
{
options = {
system.service.firewall = mkOption {
type = types.anything; # types.functionTo pkgs.liminix.lib.types.service;
};
};
config = {
system.service.firewall = params :
let svc = (pkgs.callPackage ./service.nix {}) params;
in svc // { dependencies = svc.dependencies ++ [loadModules]; };
# For historical reasons the kernel config is split between
# monolithic options and modules. TODO: go through this list
# and see what can be moved into the "kconf" definiton above
kernel.config = {
NETFILTER_XT_MATCH_CONNTRACK = "y";
IP6_NF_IPTABLES= "y";
IP_NF_IPTABLES= "y";
IP_NF_NAT = "y";
IP_NF_TARGET_MASQUERADE = "y";
NETFILTER = "y";
NETFILTER_ADVANCED = "y";
NETFILTER_XTABLES = "y";
NFT_COMPAT = "y";
NFT_CT = "y";
NFT_LOG = "y";
NFT_MASQ = "y";
NFT_NAT = "y";
NFT_REJECT = "y";
NFT_REJECT_INET = "y";
NF_CONNTRACK = "y";
NF_NAT = "y";
NF_NAT_MASQUERADE = "y";
NF_TABLES= "y";
NF_TABLES_INET = "y";
NF_TABLES_IPV4 = "y";
NF_TABLES_IPV6 = "y";
};
};
}

View File

@ -0,0 +1,26 @@
{
liminix
, lib
, firewallgen
, nftables
}:
let
inherit (liminix.services) oneshot;
inherit (liminix.lib) typeChecked;
inherit (lib) mkOption types;
t = {
ruleset = mkOption {
type = types.anything; # we could usefully define this more tightly
description = "firewall ruleset";
};
};
in
params:
let
inherit (typeChecked "firewall" t params) ruleset;
script = firewallgen "firewall.nft" ruleset;
in oneshot {
name = "firewall";
up = script;
down = "${nftables}/bin/nft flush ruleset";
}

View File

@ -0,0 +1,13 @@
{ lib, pkgs, config, ...}:
let
inherit (lib) mkOption types;
in {
options = {
system.service.hostapd = mkOption {
type = types.functionTo types.package;
};
};
config = {
system.service.hostapd = pkgs.callPackage ./service.nix {};
};
}

View File

@ -1,23 +1,34 @@
# This is not a friendly interface to configuring a wireless AP: it
# just passes everything straight through to the hostapd config. When
# we've worked out what the sensible options are to expose, we'll add
# them as top-level attributes and rename params to extraParams
{
liminix
, hostapd
, lib
, writeText
}:
interface:
{
params ? {}
, lib
}:
let
inherit (liminix.services) longrun;
inherit (lib) concatStringsSep mapAttrsToList;
inherit (builtins) toString;
inherit (liminix.lib) typeChecked;
inherit (lib) mkOption types;
# This is not a friendly interface to configuring a wireless AP: it
# just passes everything straight through to the hostapd config.
# When we've worked out what the sensible options are to expose,
# we'll add them as top-level attributes and rename params to
# extraParams
t = {
interface = mkOption {
type = liminix.lib.types.service;
};
params = mkOption {
type = types.attrs;
};
};
in
args:
let
inherit (typeChecked "hostapd" t args)
interface params;
name = "${interface.device}.hostapd";
defaults = {
driver = "nl80211";