69e6eb5a89
We use (abuse, arguably) the nixos module system for typechecking. Un the plus side, it gives us documentation of the options and their expected types. On the downside, the error message doesn't tell us the file in which the error was encountered. (This is subject to change, if I can find a better way)
335 lines
8.5 KiB
Nix
335 lines
8.5 KiB
Nix
# This is not part of Liminix per se. This is my "scratchpad"
|
|
# configuration for the device I'm testing with.
|
|
#
|
|
# Parts of it do do things that Liminix eventually needs to do, but
|
|
# don't look in here for solutions - just for identifying the
|
|
# problems.
|
|
|
|
|
|
{ config, pkgs, lib, ... } :
|
|
let
|
|
secrets = import ./rotuer-secrets.nix;
|
|
inherit (pkgs.liminix.networking)
|
|
address
|
|
dnsmasq
|
|
hostapd
|
|
interface
|
|
route;
|
|
inherit (pkgs.liminix.services) oneshot longrun bundle target;
|
|
inherit (pkgs)
|
|
dropbear
|
|
ifwait
|
|
writeText
|
|
writeFennelScript
|
|
serviceFns;
|
|
in rec {
|
|
boot = {
|
|
tftp = {
|
|
freeSpaceBytes = 3 * 1024 * 1024;
|
|
serverip = "10.0.0.1";
|
|
ipaddr = "10.0.0.8";
|
|
};
|
|
};
|
|
|
|
imports = [
|
|
../modules/wlan.nix
|
|
../modules/standard.nix
|
|
../modules/ppp.nix
|
|
];
|
|
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) {
|
|
params = {
|
|
ssid = "liminix";
|
|
country_code = "GB";
|
|
hw_mode="g";
|
|
channel = "2";
|
|
wmm_enabled = 1;
|
|
ieee80211n = 1;
|
|
inherit (secrets) wpa_passphrase;
|
|
auth_algs = 1; # 1=wpa2, 2=wep, 3=both
|
|
wpa = 2; # 1=wpa, 2=wpa2, 3=both
|
|
wpa_key_mgmt = "WPA-PSK";
|
|
wpa_pairwise = "TKIP CCMP"; # auth for wpa (may not need this?)
|
|
rsn_pairwise = "CCMP"; # auth for wpa2
|
|
};
|
|
};
|
|
|
|
services.hostap5 = hostapd (config.hardware.networkInterfaces.wlan_5) {
|
|
params = rec {
|
|
ssid = "liminix_5";
|
|
country_code = "GB";
|
|
hw_mode="a";
|
|
channel = 36;
|
|
ht_capab = "[HT40+]";
|
|
vht_oper_chwidth = 1;
|
|
vht_oper_centr_freq_seg0_idx = channel + 6;
|
|
ieee80211ac = 1;
|
|
|
|
wmm_enabled = 1;
|
|
inherit (secrets) wpa_passphrase;
|
|
auth_algs = 1; # 1=wpa2, 2=wep, 3=both
|
|
wpa = 2; # 1=wpa, 2=wpa2, 3=both
|
|
wpa_key_mgmt = "WPA-PSK";
|
|
wpa_pairwise = "TKIP CCMP"; # auth for wpa (may not need this?)
|
|
rsn_pairwise = "CCMP"; # auth for wpa2
|
|
};
|
|
};
|
|
|
|
services.int =
|
|
let iface = interface {
|
|
type = "bridge";
|
|
device = "int";
|
|
};
|
|
in address iface {
|
|
family = "inet4"; address ="10.8.0.1"; prefixLength = 16;
|
|
};
|
|
|
|
services.bridge =
|
|
let
|
|
primary = services.int;
|
|
addif = dev: oneshot {
|
|
name = "add-${dev.device}-to-bridge";
|
|
up = "${ifwait}/bin/ifwait -v ${dev.device} running && ip link set dev ${dev.device} master ${primary.device}";
|
|
down = "ip link set dev ${dev} nomaster";
|
|
dependencies = [ primary dev ];
|
|
};
|
|
in bundle {
|
|
name = "bridge-members";
|
|
contents = with config.hardware.networkInterfaces; map addif [
|
|
wlan_24 lan wlan_5
|
|
];
|
|
};
|
|
|
|
services.ntp =
|
|
let config = writeText "chrony.conf" ''
|
|
pool pool.ntp.org iburst
|
|
dumpdir /run/chrony
|
|
makestep 1.0 3
|
|
'';
|
|
in longrun {
|
|
name = "ntp";
|
|
run = "${pkgs.chrony}/bin/chronyd -f ${config} -d";
|
|
};
|
|
|
|
services.sshd = longrun {
|
|
name = "sshd";
|
|
# env -i clears the environment so we don't pass anything weird to
|
|
# ssh sessions. Dropbear params are
|
|
# -e pass environment to child
|
|
# -E log to stderr
|
|
# -R create hostkeys if needed
|
|
# -P pid-file
|
|
# -F don't fork into background
|
|
|
|
run = ''
|
|
if test -d /persist; then
|
|
mkdir -p /persist/secrets/dropbear
|
|
ln -s /persist/secrets/dropbear /run
|
|
fi
|
|
PATH=${lib.makeBinPath config.defaultProfile.packages}:/bin
|
|
exec env -i ENV=/etc/ashrc PATH=$PATH ${dropbear}/bin/dropbear -e -E -R -P /run/dropbear.pid -F
|
|
'';
|
|
};
|
|
|
|
users.dnsmasq = {
|
|
uid = 51; gid= 51; gecos = "DNS/DHCP service user";
|
|
dir = "/run/dnsmasq";
|
|
shell = "/bin/false";
|
|
};
|
|
users.root = secrets.root;
|
|
|
|
groups.dnsmasq = {
|
|
gid = 51; usernames = ["dnsmasq"];
|
|
};
|
|
groups.system.usernames = ["dnsmasq"];
|
|
|
|
services.dns =
|
|
let interface = services.int;
|
|
in dnsmasq {
|
|
resolvconf = services.resolvconf;
|
|
inherit interface;
|
|
ranges = [
|
|
"10.8.0.10,10.8.0.240"
|
|
"::,constructor:${interface.device},ra-stateless"
|
|
];
|
|
domain = "fake.liminix.org";
|
|
};
|
|
|
|
services.wan =
|
|
let iface = config.hardware.networkInterfaces.wan;
|
|
in config.system.service.pppoe {
|
|
interface = iface;
|
|
ppp-options = [
|
|
"debug" "+ipv6" "noauth"
|
|
"name" secrets.l2tp.name
|
|
"password" secrets.l2tp.password
|
|
];
|
|
};
|
|
|
|
services.resolvconf = oneshot rec {
|
|
dependencies = [ services.wan ];
|
|
name = "resolvconf";
|
|
up = ''
|
|
. ${serviceFns}
|
|
( in_outputs ${name}
|
|
echo "nameserver $(output ${services.wan} ns1)" > resolv.conf
|
|
echo "nameserver $(output ${services.wan} ns2)" >> resolv.conf
|
|
)
|
|
'';
|
|
down = ''
|
|
rm -rf /run/service-state/${name}/
|
|
'';
|
|
};
|
|
|
|
services.defaultroute4 = route {
|
|
name = "defaultroute4";
|
|
via = "$(output ${services.wan} address)";
|
|
target = "default";
|
|
dependencies = [ services.wan ];
|
|
};
|
|
|
|
services.defaultroute6 = route {
|
|
name = "defaultroute6";
|
|
via = "$(output ${services.wan} ipv6-peer-address)";
|
|
target = "default";
|
|
dev = "$(output ${services.wan} ifname)";
|
|
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.packet_forwarding =
|
|
let
|
|
ip4 = "/proc/sys/net/ipv4/conf/all/forwarding";
|
|
ip6 = "/proc/sys/net/ipv6/conf/all/forwarding";
|
|
in oneshot {
|
|
name = "let-the-ip-flow";
|
|
up = ''
|
|
echo 1 > ${ip4}
|
|
echo 1 > ${ip6}
|
|
'';
|
|
down = ''
|
|
echo 0 > ${ip4};
|
|
echo 0 > ${ip6};
|
|
'';
|
|
dependencies = [ services.firewall ];
|
|
};
|
|
|
|
services.dhcp6 =
|
|
let
|
|
name = "dhcp6c.wan";
|
|
in longrun {
|
|
inherit name;
|
|
notification-fd = 10;
|
|
run = ''
|
|
export SERVICE_STATE=/run/service-state/${name}
|
|
${pkgs.odhcp6c}/bin/odhcp6c -s ${pkgs.odhcp-script} -e -v -p /run/${name}.pid -P 48 $(output ${services.wan} ifname)
|
|
)
|
|
'';
|
|
dependencies = [ services.wan ];
|
|
};
|
|
|
|
services.acquire-lan-prefix =
|
|
let script = pkgs.callPackage ./acquire-delegated-prefix.nix { };
|
|
in longrun {
|
|
name = "acquire-lan-prefix";
|
|
run = "${script} /run/service-state/dhcp6c.wan ${services.int.device}";
|
|
dependencies = [ services.dhcp6 ];
|
|
};
|
|
|
|
services.acquire-wan-address =
|
|
let script = pkgs.callPackage ./acquire-wan-address.nix { };
|
|
in longrun {
|
|
name = "acquire-wan-address";
|
|
run = "${script} /run/service-state/dhcp6c.wan $(output ${services.wan} ifname)";
|
|
dependencies = [ services.dhcp6 ];
|
|
};
|
|
|
|
services.default = target {
|
|
name = "default";
|
|
contents = with config.services; [
|
|
config.hardware.networkInterfaces.lo
|
|
config.hardware.networkInterfaces.lan
|
|
int
|
|
bridge
|
|
hostap
|
|
hostap5
|
|
ntp
|
|
defaultroute4
|
|
defaultroute6
|
|
packet_forwarding
|
|
dns
|
|
resolvconf
|
|
sshd
|
|
config.services.hostname
|
|
dhcp6
|
|
acquire-lan-prefix
|
|
acquire-wan-address
|
|
];
|
|
};
|
|
defaultProfile.packages = with pkgs; [
|
|
min-collect-garbage
|
|
];
|
|
}
|