diff --git a/README.md b/README.md index ec457e5..9eac9ba 100644 --- a/README.md +++ b/README.md @@ -95,3 +95,5 @@ took full advantage of the basic application armoring features provided by the operating system. Indeed, only one or two models even came close, and no brand did well consistently across all models tested" + +* [A PPPoE Implementation for Linux](https://static.usenix.org/publications/library/proceedings/als00/2000papers/papers/full_papers/skoll/skoll_html/index.html): "Many DSL service providers use PPPoE for residential broadband Internet access. This paper briefly describes the PPPoE protocol, presents strategies for implementing it under Linux and describes in detail a user-space implementation of a PPPoE client." diff --git a/overlay.nix b/overlay.nix index bf6e47c..5dc9ef3 100644 --- a/overlay.nix +++ b/overlay.nix @@ -3,4 +3,50 @@ final: prev: { s6-init-files = final.callPackage ./pkgs/s6-init-files {}; strace = prev.strace.override { libunwind = null; }; liminix = final.callPackage ./pkgs/liminix-tools {}; + pppoe = prev.rpPPPoE.overrideAttrs (o: { + # use newer rp-pppoe, it builds cleanly + src = final.fetchFromGitHub { + owner = "dfskoll"; + repo = "rp-pppoe"; + rev = "7cfd8c0405d14cf1c8d799d41d8207fd707979c1"; + hash = "sha256-MFdCwNj8c52blxEuXH5ltT2yYDmKMH5MLUgtddZV25E="; + }; + }); + ppp = + (prev.ppp.override { + libpcap = null; + }).overrideAttrs (o : { + stripAllList = [ "bin" ]; + buildInputs = []; + + # patches = + # o.patches ++ + # [(final.fetchpatch { + # name = "ipv6-script-options.patch"; + # url = "https://github.com/ppp-project/ppp/commit/874c2a4a9684bf6938643c7fa5ff1dd1cf80aea4.patch"; + # sha256 = "sha256-K46CKpDpm1ouj6jFtDs9IUMHzlRMRP+rMPbMovLy3o4="; + # })]; + + postPatch = '' + sed -i -e 's@_PATH_VARRUN@"/run/"@' pppd/main.c + sed -i -e 's@^FILTER=y@# FILTER unset@' pppd/Makefile.linux + sed -i -e 's/-DIPX_CHANGE/-UIPX_CHANGE/g' pppd/Makefile.linux + ''; + buildPhase = '' + runHook preBuild + make -C pppd CC=$CC USE_TDB= HAVE_MULTILINK= USE_EAPTLS= USE_CRYPT=y + make -C pppd/plugins/pppoe CC=$CC + make -C pppd/plugins/pppol2tp CC=$CC + runHook postBuild; + ''; + installPhase = '' + runHook preInstall + mkdir -p $out/bin $out/lib/pppd/2.4.9 + cp pppd/pppd pppd/plugins/pppoe/pppoe-discovery $out/bin + cp pppd/plugins/pppoe/pppoe.so $out/lib/pppd/2.4.9 + cp pppd/plugins/pppol2tp/{open,pppo}l2tp.so $out/lib/pppd/2.4.9 + runHook postInstall + ''; + postFixup = ""; + }); } diff --git a/pkgs/liminix-tools/default.nix b/pkgs/liminix-tools/default.nix index 46852ee..3d5858c 100644 --- a/pkgs/liminix-tools/default.nix +++ b/pkgs/liminix-tools/default.nix @@ -77,6 +77,7 @@ in { name = "${interface.device}.odhcp"; run = "odhcpcd ${interface.device}"; }; + pppoe = callPackage ./networking/pppoe.nix {}; }; services = { inherit longrun oneshot bundle target; diff --git a/pkgs/liminix-tools/networking/pppoe.nix b/pkgs/liminix-tools/networking/pppoe.nix new file mode 100644 index 0000000..b98d9c4 --- /dev/null +++ b/pkgs/liminix-tools/networking/pppoe.nix @@ -0,0 +1,48 @@ +{ + liminix +, lib +, busybox +, ppp +, pppoe +, writeShellScript +} : +let + inherit (liminix.services) longrun; + ip-up = writeShellScript "ip-up" '' +action=$1 +env > /run/udhcp.values + +set_address() { + ip address replace $ip/$mask dev $interface + mkdir -p data/outputs + for i in lease mask ip router siaddr dns serverid subnet opt53 interface ; do + echo ''${!i} > data/outputs/$i + done +} +case $action in + deconfig) + ip address flush $interface + ip link set up dev $interface + ;; + bound) + # this doesn't actually replace, it adds a new address. + set_address + ;; + renew) + set_address + ;; + nak) + echo "received NAK on $interface" + ;; +esac +''; + +in +interface: { + synchronous ? false +, ppp-options ? [] +, ... +} @ args: longrun { + name = "${interface.device}.ppppoe"; + run = "${ppp}/bin/pppd pty '${pppoe}/bin/pppoe -I ${interface.device}' ${lib.concatStringsSep " " ppp-options}" ; +} diff --git a/tests/pppoe/configuration.nix b/tests/pppoe/configuration.nix new file mode 100644 index 0000000..75193ed --- /dev/null +++ b/tests/pppoe/configuration.nix @@ -0,0 +1,47 @@ +{ config, pkgs, ... } : +let + inherit (pkgs.liminix.networking) interface address pppoe; + inherit (pkgs.liminix.services) oneshot longrun bundle target output; +in rec { + services.loopback = + let iface = interface { type = "loopback"; device = "lo";}; + in bundle { + name = "loopback"; + contents = [ + (address iface { family = "inet4"; addr ="127.0.0.1";}) + (address iface { family = "inet6"; addr ="::1";}) + ]; + }; + + kernel.config = { + "PPP" = "y"; + "PPPOE" = "y"; + "PPPOL2TP" = "y"; + }; + + services.pppoe = + let iface = interface { type = "hardware"; device = "eth0"; }; + in pppoe iface {}; + + services.defaultroute4 = + let iface = services.pppoe; + in oneshot { + name = "defaultroute4"; + up = '' + ip route add default gw $(cat ${output iface "address"}) + echo "1" > /sys/net/ipv4/$(cat ${output iface "ifname"}) + ''; + down = '' + ip route del default gw $(cat ${output iface "address"}) + echo "0" > /sys/net/ipv4/$(cat ${output iface "ifname"}) + ''; + dependencies = [iface]; + }; + + services.default = target { + name = "default"; + contents = with services; [ loopback defaultroute4 ]; + }; + + systemPackages = [ pkgs.hello ] ; +} diff --git a/tests/pppoe/run.sh b/tests/pppoe/run.sh new file mode 100755 index 0000000..4c87b63 --- /dev/null +++ b/tests/pppoe/run.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env sh + + +set -e + +cleanup(){ + echo "do cleanup"; +} +trap cleanup EXIT +trap 'echo "command $(eval echo $BASH_COMMAND) failed with exit code $?"; exit $?' ERR + +NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1 nix-build '' -I liminix-config=./configuration.nix --arg device "import " -A outputs.default $* + + +if ! ( echo "cont" | socat - unix-connect:../support/ppp-server/qemu-monitor); then + echo "need pppoe server running" + exit 1 +fi + +../../scripts/run-qemu.sh result/vmlinux result/squashfs