From a6128955e70b330e09a1a9b2047f3d4ea9cf6a6d Mon Sep 17 00:00:00 2001 From: Daniel Barlow Date: Wed, 21 Aug 2024 23:10:28 +0100 Subject: [PATCH] ppp modules: permit (mostly) same params for l2tp as pppoe this also means that l2tp can use secrets for username/password --- modules/ppp/default.nix | 50 ++++++++++++++++++++++++++++---- modules/ppp/l2tp.nix | 63 +++++++++++++++++++++++++++++------------ modules/ppp/pppoe.nix | 10 +++---- 3 files changed, 95 insertions(+), 28 deletions(-) diff --git a/modules/ppp/default.nix b/modules/ppp/default.nix index 3cea2ae..e609406 100644 --- a/modules/ppp/default.nix +++ b/modules/ppp/default.nix @@ -1,12 +1,18 @@ ## PPP ## === ## -## A PPPoE (PPP over Ethernet) configuration to address the case where -## your Liminix device is connected to an upstream network using +## ``ppoe`` (PPP over Ethernet) provides a service to address the case +## where your Liminix device is connected to an upstream network using ## PPPoE. This is typical for UK broadband connections where the ## physical connection is made by OpenReach ("Fibre To The X") and -## common in some other localities as well: ask your ISP if this is +## common in some other localities as well: check with your ISP if this is ## you. +## +## ``l2tp`` (Layer 2 Tunelling Protocol) provides a service that +## tunnels PPP over the Internet. This may be used by some ISPs in +## conjunction with a DHCP uplink, or other more creative forms of +## network connection + { lib, pkgs, config, ...}: let @@ -34,11 +40,13 @@ in { description = "ethernet interface to run PPPoE over"; }; username = mkOption { - type = liminix.lib.types.replacable; + type = types.nullOr liminix.lib.types.replacable; + default = null; description = "username"; }; password = mkOption { - type = liminix.lib.types.replacable; + type = types.nullOr liminix.lib.types.replacable; + default = null; description = "password"; }; lcpEcho = { @@ -74,6 +82,38 @@ in { type = types.str; description = "hostname or address of the L2TP network server"; }; + username = mkOption { + type = types.nullOr liminix.lib.types.replacable; + default = null; + description = "username"; + }; + password = mkOption { + type = types.nullOr liminix.lib.types.replacable; + default = null; + description = "password"; + }; + lcpEcho = { + adaptive = mkOption { + description = "send LCP echo-request frames only if no traffic was received from the peer since the last echo-request was sent"; + type = types.bool; + default = true; + }; + interval = mkOption { + type = types.nullOr types.int; + default = 3; + description = "send an LCP echo-request frame to the peer every n seconds"; + }; + failure = mkOption { + type = types.nullOr types.int; + default = 3; + description = "terminate connection if n LCP echo-requests are sent without receiving a valid LCP echo-reply"; + }; + }; + debug = mkOption { + description = "log the contents of all control packets sent or received"; + default = false; + type = types.bool; + }; ppp-options = mkOption { type = types.listOf types.str; description = "options supplied on ppp command line"; diff --git a/modules/ppp/l2tp.nix b/modules/ppp/l2tp.nix index 8e20630..78da1a8 100644 --- a/modules/ppp/l2tp.nix +++ b/modules/ppp/l2tp.nix @@ -1,15 +1,22 @@ { liminix +, lib +, output-template , writeAshScript , writeText , serviceFns , xl2tpd } : -{ lns, ppp-options }: +{ lns, + ppp-options, + lcpEcho, + username, + password, + debug +}: let inherit (liminix.services) longrun; - lcp-echo-interval = 4; - lcp-echo-failure = 3; + inherit (lib) optional optionals escapeShellArgs concatStringsSep; name = "${lns}.l2tp"; ip-up = writeAshScript "ip-up" {} '' . ${serviceFns} @@ -32,35 +39,55 @@ let ) echo >/proc/self/fd/10 ''; - ppp-options' = ppp-options ++ [ - "ip-up-script" ip-up - "ipv6-up-script" ip6-up - "ipparam" name - "nodetach" - "usepeerdns" - "lcp-echo-interval" (builtins.toString lcp-echo-interval) - "lcp-echo-failure" (builtins.toString lcp-echo-failure) - "logfd" "2" - ]; + + literal_or_output = + let v = o: ({ + string = builtins.toJSON; + int = builtins.toJSON; + set = (o: "output(${builtins.toJSON o.service}, ${builtins.toJSON o.path})"); + }.${builtins.typeOf o}) o; + in o: "{{ ${v o} }}"; + + ppp-options' = + ["+ipv6" "noauth"] + ++ optional debug "debug" + ++ optionals (username != null) ["name" (literal_or_output username)] + ++ optionals (password != null) ["password" (literal_or_output password)] + ++ optional lcpEcho.adaptive "lcp-echo-adaptive" + ++ optionals (lcpEcho.interval != null) + ["lcp-echo-interval" (builtins.toString lcpEcho.interval)] + ++ optionals (lcpEcho.failure != null) + ["lcp-echo-failure" (builtins.toString lcpEcho.failure)] + ++ ppp-options + ++ ["ip-up-script" ip-up + "ipv6-up-script" ip6-up + "ipparam" name + "nodetach" + "usepeerdns" + "logfd" "2" + ]; + conf = writeText "xl2tpd.conf" '' [lac upstream] lns = ${lns} require authentication = no - pppoptfile = ${writeText "ppp-options" ppp-options'} + pppoptfile = /run/${name}/ppp-options autodial = yes redial = yes redial timeout = 1 max redials = 2 # this gives 1 actual retry, as xl2tpd can't count ''; - control = "/run/xl2tpd/control-${name}"; + control = "/run/${name}/control"; in longrun { inherit name; run = '' - mkdir -p /run/xl2tpd + mkdir -p /run/${name} + chmod 0700 /run/${name} touch ${control} - in_outputs $name - exec ${xl2tpd}/bin/xl2tpd -D -p /run/xl2tpd/${name}.pid -c ${conf} -C ${control} + in_outputs ${name} + echo ${escapeShellArgs ppp-options'} | ${output-template}/bin/output-template '{{' '}}' > /run/${name}/ppp-options + exec ${xl2tpd}/bin/xl2tpd -D -p /run/${name}/${name}.pid -c ${conf} -C ${control} ''; notification-fd = 10; } diff --git a/modules/ppp/pppoe.nix b/modules/ppp/pppoe.nix index ed1b235..772067f 100644 --- a/modules/ppp/pppoe.nix +++ b/modules/ppp/pppoe.nix @@ -47,7 +47,8 @@ let set = (o: "output(${builtins.toJSON o.service}, ${builtins.toJSON o.path})"); }.${builtins.typeOf o}) o; in o: "{{ ${v o} }}"; - ppp-options' = ["+ipv6" "noauth"] + ppp-options' = + ["+ipv6" "noauth"] ++ optional debug "debug" ++ optionals (username != null) ["name" (literal_or_output username)] ++ optionals (password != null) ["password" (literal_or_output password)] @@ -69,12 +70,11 @@ in longrun { inherit name; run = '' - . ${serviceFns} mkdir -p /run/${name} chmod 0700 /run/${name} - echo ${escapeShellArgs ppp-options'} | ${output-template}/bin/output-template '{{' '}}' > /run/${name}/${name}.conf - echo Starting pppoe, pppd pid is $$ - exec ${ppp}/bin/pppd pty "${pppoe}/bin/pppoe ${timeoutOpt} -I $(output ${interface} ifname)" file /run/${name}/${name}.conf + in_outputs ${name} + echo ${escapeShellArgs ppp-options'} | ${output-template}/bin/output-template '{{' '}}' > /run/${name}/ppp-options + exec ${ppp}/bin/pppd pty "${pppoe}/bin/pppoe ${timeoutOpt} -I $(output ${interface} ifname)" file /run/${name}/ppp-options ''; notification-fd = 10; timeout-up = if lcpEcho.failure != null