liminix

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

gateway.nix (5103B)


      1 {
      2   config,
      3   pkgs,
      4   lib,
      5   ...
      6 }:
      7 let
      8   svc = config.system.service;
      9   cfg = config.profile.gateway;
     10   inherit (lib)
     11     mkOption
     12     mkEnableOption
     13     mkIf
     14     types
     15     ;
     16   inherit (pkgs) liminix;
     17   inherit (liminix.services) bundle oneshot;
     18   hostaps =
     19     let
     20       defaults = {
     21         auth_algs = 1; # 1=wpa2, 2=wep, 3=both
     22         wpa = 2; # 1=wpa, 2=wpa2, 3=both
     23         wpa_key_mgmt = "WPA-PSK";
     24         wpa_pairwise = "TKIP CCMP"; # auth for wpa (may not need this?)
     25         rsn_pairwise = "CCMP"; # auth for wpa2
     26       };
     27     in
     28     lib.mapAttrs' (
     29       name: value:
     30       let
     31         attrs = defaults // { ssid = name; } // value;
     32       in
     33       lib.nameValuePair "hostap-${name}" (
     34         svc.hostapd.build {
     35           interface = attrs.interface;
     36           params = lib.filterAttrs (k: v: k != "interface") attrs;
     37         }
     38       )
     39     ) cfg.wireless.networks;
     40 in
     41 {
     42 
     43   options.profile.gateway = {
     44     lan = {
     45       interfaces = mkOption {
     46         type = types.listOf liminix.lib.types.interface;
     47         default = [ ];
     48       };
     49       address = mkOption {
     50         type = types.attrs;
     51       };
     52       prefix = mkOption { type = types.str; };
     53       dhcp = {
     54         start = mkOption { type = types.int; };
     55         end = mkOption { type = types.int; };
     56         hosts = mkOption { type = types.attrs; };
     57         localDomain = mkOption { type = types.str; };
     58       };
     59     };
     60 
     61     firewall = {
     62       enable = mkEnableOption "firewall";
     63       rules = mkOption { type = types.attrsOf types.attrs; };
     64       zones = mkOption {
     65         type = types.attrsOf (types.listOf liminix.lib.types.service);
     66         default = {
     67           lan = [ config.services.int ];
     68           wan = [ config.services.wan ];
     69         };
     70       };
     71     };
     72 
     73     wan = {
     74       interface = mkOption { type = liminix.lib.types.interface; };
     75       dhcp6.enable = mkOption { type = types.bool; };
     76     };
     77 
     78     wireless = mkOption {
     79       type = types.attrsOf types.anything;
     80     };
     81   };
     82 
     83   imports = [
     84     ../wlan.nix
     85     ../network
     86     ../ppp
     87     ../dnsmasq
     88     ../dhcp6c
     89     ../firewall
     90     ../hostapd
     91     ../bridge
     92     ../ntp
     93     ../ssh
     94     { config.services = hostaps; }
     95   ];
     96 
     97   config = {
     98     services.int = svc.network.address.build (
     99       {
    100         interface = svc.bridge.primary.build { ifname = "int"; };
    101       }
    102       // cfg.lan.address
    103     );
    104 
    105     services.bridge = svc.bridge.members.build {
    106       primary = config.services.int;
    107       members = cfg.lan.interfaces;
    108     };
    109 
    110     services.wan = cfg.wan.interface;
    111 
    112     services.packet_forwarding = svc.network.forward.build { };
    113 
    114     services.dhcp6c =
    115       let
    116         client = svc.dhcp6c.client.build {
    117           interface = config.services.wan;
    118         };
    119         bundl = bundle {
    120           name = "dhcp6c";
    121           contents = [
    122             (svc.dhcp6c.prefix.build {
    123               inherit client;
    124               interface = config.services.int;
    125             })
    126             (svc.dhcp6c.address.build {
    127               inherit client;
    128               interface = config.services.wan;
    129             })
    130           ];
    131         };
    132       in
    133       mkIf cfg.wan.dhcp6.enable bundl;
    134 
    135     services.dns =
    136       let
    137         interface = config.services.int;
    138         dcfg = cfg.lan.dhcp;
    139       in
    140       svc.dnsmasq.build {
    141         resolvconf = config.services.resolvconf;
    142         inherit interface;
    143         ranges = [
    144           "${cfg.lan.prefix}.${toString dcfg.start},${cfg.lan.prefix}.${toString dcfg.end}"
    145           # ra-stateless: sends router advertisements with the O and A
    146           # bits set, and provides a stateless DHCP service. The client
    147           # will use a SLAAC address, and use DHCP for other
    148           # configuration information.
    149           "::,constructor:$(output ${interface} ifname),ra-stateless"
    150         ];
    151 
    152         hosts = dcfg.hosts;
    153         upstreams = [ "/${dcfg.localDomain}/" ];
    154         domain = dcfg.localDomain;
    155       };
    156 
    157     services.defaultroute4 = svc.network.route.build {
    158       via = "$(output ${config.services.wan} address)";
    159       target = "default";
    160       dependencies = [ config.services.wan ];
    161     };
    162 
    163     services.defaultroute6 = svc.network.route.build {
    164       via = "$(output ${config.services.wan} ipv6-peer-address)";
    165       target = "default";
    166       interface = config.services.wan;
    167     };
    168 
    169     services.firewall = mkIf cfg.firewall.enable (
    170       svc.firewall.build {
    171         extraRules = cfg.firewall.rules;
    172         inherit (cfg.firewall) zones;
    173       }
    174     );
    175 
    176     services.resolvconf = oneshot rec {
    177       dependencies = [ config.services.wan ];
    178       name = "resolvconf";
    179       up = ''
    180         ( in_outputs ${name}
    181          chmod 0755 . # dnsmasq user needs this directory to be readable
    182          echo "nameserver $(output ${config.services.wan} ns1)" > resolv.conf
    183          echo "nameserver $(output ${config.services.wan} ns2)" >> resolv.conf
    184          chmod 0444 resolv.conf
    185         )
    186       '';
    187     };
    188 
    189     filesystem =
    190       let
    191         inherit (pkgs.pseudofile) dir symlink;
    192       in
    193       dir {
    194         etc = dir {
    195           "resolv.conf" = symlink "${config.services.resolvconf}/.outputs/resolv.conf";
    196         };
    197       };
    198   };
    199 }