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 }