liminix

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

router-with-l2tp.nix (6760B)


      1 # A demonstration config for a home/soho router with PPPoE upstream
      2 # and fallback to an L2TP tunnel over a USB WWAN device
      3 
      4 {
      5   config,
      6   pkgs,
      7   lib,
      8   ...
      9 }:
     10 let
     11   secrets = import ./extneder-secrets.nix;
     12   rsecrets = import ./rotuer-secrets.nix;
     13 
     14   # https://support.aa.net.uk/Category:Incoming_L2TP says:
     15   # "Please use the DNS name (l2tp.aa.net.uk) instead of hardcoding an
     16   # IP address; IP addresses can and do change. If you have to use an
     17   # IP, use 194.4.172.12, but do check the DNS for l2tp.aa.net.uk in
     18   # case it changes."
     19 
     20   # but (1) we don't want to use the wwan stick's dns as our main
     21   # resolver: it's provided by some mobile ISP and they aren't
     22   # necessarily the best at providing unfettered services without
     23   # deciding to do something weird; (2) it's not simple to arrange
     24   # that xl2tpd gets a different resolver than every other process;
     25   # (3) there's no way to specify an lns address to xl2tpd at runtime
     26   # except by rewriting its config file. So what we will do is lookup
     27   # the lns hostname using the mobile ISP's dns server and then refuse
     28   # to start l2tp unless the expected lns address is one of the
     29   # addresses returned. I think this satisfies "do check the DNS"
     30 
     31   lns = {
     32     hostname = "l2tp.aaisp.net.uk";
     33     address = "194.4.172.12";
     34   };
     35 
     36   inherit (pkgs.liminix.services) oneshot target;
     37   inherit (pkgs.liminix) outputRef;
     38   svc = config.system.service;
     39   wirelessConfig = {
     40     country_code = "GB";
     41     inherit (rsecrets) wpa_passphrase;
     42     wmm_enabled = 1;
     43   };
     44 in
     45 rec {
     46   boot = {
     47     tftp = {
     48       serverip = "10.0.0.1";
     49       ipaddr = "10.0.0.8";
     50     };
     51   };
     52 
     53   imports = [
     54     ../modules/wwan
     55     ../modules/network
     56     ../modules/ssh
     57     ../modules/usb.nix
     58     ../modules/ppp
     59     ../modules/round-robin
     60     ../modules/health-check
     61     ../modules/secrets
     62     ../modules/profiles/gateway.nix
     63     ../modules/dhcp4c
     64 
     65   ];
     66   hostname = "thing";
     67 
     68   services.wan-address-for-secrets = svc.network.address.build {
     69     interface = config.hardware.networkInterfaces.wan;
     70     family = "inet";
     71     address = "10.0.0.10";
     72     prefixLength = 24;
     73   };
     74 
     75   services.secrets = svc.secrets.outboard.build {
     76     name = "secret-service";
     77     url = "http://10.0.0.1/liminix/examples/real-secrets.json";
     78     username = "demo";
     79     password = "demo";
     80     interval = 5;
     81     dependencies = [ services.wan-address-for-secrets ];
     82   };
     83 
     84   services.wwan = svc.wwan.huawei-e3372.build {
     85     apn = "data.uk";
     86     username = "user";
     87     password = "one2one";
     88     authType = "chap";
     89   };
     90 
     91   profile.gateway = {
     92     lan = {
     93       interfaces = with config.hardware.networkInterfaces; [
     94         # EDIT: these are the interfaces exposed by the gl.inet gl-ar750:
     95         # if your device has more or differently named lan interfaces,
     96         # specify them here
     97         wlan
     98         wlan5
     99         lan
    100       ];
    101       inherit (rsecrets.lan) prefix;
    102       address = {
    103         family = "inet";
    104         address = "${rsecrets.lan.prefix}.1";
    105         prefixLength = 24;
    106       };
    107       dhcp = {
    108         start = 10;
    109         end = 240;
    110         hosts =
    111           { } // lib.optionalAttrs (builtins.pathExists ./static-leases.nix) (import ./static-leases.nix);
    112         localDomain = "lan";
    113       };
    114     };
    115     wan =
    116       let
    117         secret = outputRef config.services.secrets;
    118         username = secret "ppp/username";
    119         password = secret "ppp/password";
    120       in
    121       {
    122         interface =
    123           let
    124             pppoe = svc.pppoe.build {
    125               interface = config.hardware.networkInterfaces.wan;
    126               debug = true;
    127               inherit username password;
    128             };
    129 
    130             l2tp =
    131               let
    132                 check-address = oneshot rec {
    133                   name = "check-lns-address";
    134                   up = "grep -Fx ${lns.address} $(output_path ${services.lns-address} addresses)";
    135                   dependencies = [ services.lns-address ];
    136                 };
    137                 route = svc.network.route.build {
    138                   via = "$(output ${services.bootstrap-dhcpc} router)";
    139                   target = lns.address;
    140                   dependencies = [
    141                     services.bootstrap-dhcpc
    142                     check-address
    143                   ];
    144                 };
    145                 l2tpd = svc.l2tp.build {
    146                   lns = lns.address;
    147                   inherit username password;
    148                   dependencies = [
    149                     config.services.lns-address
    150                     route
    151                     check-address
    152                   ];
    153                 };
    154               in
    155               svc.health-check.build {
    156                 service = l2tpd;
    157                 threshold = 3;
    158                 interval = 2;
    159                 healthCheck = pkgs.writeAshScript "ping-check" { } "ping 1.1.1.1";
    160               };
    161           in
    162           svc.round-robin.build {
    163             name = "wan";
    164             services = [
    165               pppoe
    166               l2tp
    167             ];
    168           };
    169         dhcp6.enable = true;
    170       };
    171 
    172     wireless.networks = {
    173       "${rsecrets.ssid}" = {
    174         interface = config.hardware.networkInterfaces.wlan;
    175         hw_mode = "g";
    176         channel = "6";
    177         ieee80211n = 1;
    178       }
    179       // wirelessConfig
    180       // {
    181         wpa_passphrase = outputRef config.services.secrets "wpa_passphrase";
    182       };
    183 
    184       "${rsecrets.ssid}5" = rec {
    185         interface = config.hardware.networkInterfaces.wlan5;
    186         hw_mode = "a";
    187         channel = 36;
    188         ht_capab = "[HT40+]";
    189         vht_oper_chwidth = 1;
    190         vht_oper_centr_freq_seg0_idx = channel + 6;
    191         ieee80211n = 1;
    192         ieee80211ac = 1;
    193       }
    194       // wirelessConfig
    195       // {
    196         wpa_passphrase = outputRef config.services.secrets "wpa_passphrase";
    197       };
    198     };
    199   };
    200 
    201   services.bootstrap-dhcpc = svc.dhcp4c.client.build {
    202     interface = config.services.wwan;
    203     dependencies = [ config.services.hostname ];
    204   };
    205 
    206   services.sshd = svc.ssh.build {
    207     authorizedKeys = outputRef config.services.secrets "ssh/authorizedKeys";
    208   };
    209 
    210   services.lns-address =
    211     let
    212       ns = "$(output_word ${services.bootstrap-dhcpc} dns 1)";
    213       route-to-bootstrap-nameserver = svc.network.route.build {
    214         via = "$(output ${services.bootstrap-dhcpc} router)";
    215         target = ns;
    216         dependencies = [ services.bootstrap-dhcpc ];
    217       };
    218     in
    219     oneshot rec {
    220       name = "resolve-l2tp-server";
    221       dependencies = [
    222         services.bootstrap-dhcpc
    223         route-to-bootstrap-nameserver
    224       ];
    225       up = ''
    226         (in_outputs ${name}
    227          DNSCACHEIP="${ns}" ${pkgs.s6-dns}/bin/s6-dnsip4 ${lns.hostname} \
    228           > addresses
    229         )
    230       '';
    231     };
    232 
    233   users.root = rsecrets.root;
    234 
    235   programs.busybox.options = {
    236     FEATURE_FANCY_TAIL = "y";
    237   };
    238 
    239 }