diff --git a/examples/demo.nix b/examples/demo.nix index 255f3ac..f242056 100644 --- a/examples/demo.nix +++ b/examples/demo.nix @@ -7,7 +7,7 @@ { config, pkgs, lib, ... } : let - inherit (pkgs.liminix.services) oneshot longrun; + inherit (pkgs.liminix.services) bundle oneshot longrun; inherit (pkgs) serviceFns; # EDIT: you can pick your preferred RFC1918 address space # for NATted connections, if you don't like this one. @@ -25,6 +25,7 @@ in rec { imports = [ ../modules/bridge + ../modules/dhcp6c ../modules/dnsmasq ../modules/firewall ../modules/hostapd @@ -95,11 +96,16 @@ in rec { resolvconf = services.resolvconf; inherit interface; ranges = [ - "${ipv4LocalNet}.10,${ipv4LocalNet}.240" - # ra-stateless: sends router advertisements with the O and A + "${ipv4LocalNet}.10,${ipv4LocalNet}.249" + # EDIT: ... maybe. In this example we use "ra-stateless", + # meaning dnsmasq sends router advertisements with the O and A # bits set, and provides a stateless DHCP service. The client # will use a SLAAC address, and use DHCP for other # configuration information. + # If you didn't understand the preceding sentence then + # the default is _probably_ fine, but if you need + # a DHCP-only IPv6 network or some other different + # configuration, this is the place to change it. "::,constructor:$(output ${interface} ifname),ra-stateless" ]; # EDIT: choose a domain name for the DNS names issued for your @@ -158,34 +164,37 @@ in rec { services.packet_forwarding = svc.network.forward.build { }; - services.dhcp6 = - let - name = "dhcp6c.wan"; - in longrun { - inherit name; - notification-fd = 10; - run = '' - export SERVICE_STATE=/run/service-state/${name} - ${pkgs.odhcp6c}/bin/odhcp6c -s ${pkgs.odhcp-script} -e -v -p /run/${name}.pid -P 48 $(output ${services.wan} ifname) - ) - ''; - dependencies = [ services.wan ]; - }; + # We expect the ISP uses DHCP6 to issue IPv6 addresses. There is a + # service to request address information in the form of a DHCP + # lease, and two dependent services that listen for updates to the + # DHCP address information and update the addresses of the WAN and + # LAN interfaces respectively. - services.acquire-lan-prefix = - let script = pkgs.callPackage ./acquire-delegated-prefix.nix { }; - in longrun { - name = "acquire-lan-prefix"; - run = "${script} /run/service-state/dhcp6c.wan $(output ${services.int} ifname)"; - dependencies = [ services.dhcp6 ]; - }; - - services.acquire-wan-address = - let script = pkgs.callPackage ./acquire-wan-address.nix { }; - in longrun { - name = "acquire-wan-address"; - run = "${script} /run/service-state/dhcp6c.wan $(output ${services.wan} ifname)"; - dependencies = [ services.dhcp6 ]; + services.dhcp6c = + let client = svc.dhcp6c.client.build { + interface = services.wan; + }; + in bundle { + name = "dhcp6c"; + contents = [ + (svc.dhcp6c.prefix.build { + # if your ISP provides you a real IPv6 prefix for your local + # network (usually a /64 or /48 or something in between the + # two), this service subscribes to that "prefix delegation" + # information, and uses it to assign an address to the LAN + # device. dnsmasq will notice this address and use it to + # form the addresses it hands out to devices on the lan + inherit client; + interface = services.int; + }) + (svc.dhcp6c.address.build { + # if your ISP provides you a regular global IPv6 address, + # this service subscribes to that information and assigns + # the address to the WAN device. + inherit client; + interface = services.wan; + }) + ]; }; defaultProfile.packages = with pkgs; [ diff --git a/examples/rotuer.nix b/examples/rotuer.nix index 495a590..8d356b4 100644 --- a/examples/rotuer.nix +++ b/examples/rotuer.nix @@ -9,7 +9,7 @@ { config, pkgs, lib, ... } : let secrets = import ./rotuer-secrets.nix; - inherit (pkgs.liminix.services) oneshot longrun; + inherit (pkgs.liminix.services) oneshot longrun bundle; inherit (pkgs) serviceFns; svc = config.system.service; wirelessConfig = { @@ -38,6 +38,7 @@ in rec { ../modules/network ../modules/ppp ../modules/dnsmasq + ../modules/dhcp6c ../modules/firewall ../modules/hostapd ../modules/bridge @@ -154,39 +155,27 @@ in rec { }; services.firewall = svc.firewall.build { - ruleset = import ./rotuer-firewall.nix; + ruleset = import ./demo-firewall.nix; }; services.packet_forwarding = svc.network.forward.build { }; - services.dhcp6 = - let - name = "dhcp6c.wan"; - in longrun { - inherit name; - notification-fd = 10; - run = '' - export SERVICE_STATE=/run/service-state/${name} - ${pkgs.odhcp6c}/bin/odhcp6c -s ${pkgs.odhcp-script} -e -v -p /run/${name}.pid -P 48 $(output ${services.wan} ifname) - ) - ''; - dependencies = [ services.wan ]; - }; - - services.acquire-lan-prefix = - let script = pkgs.callPackage ./acquire-delegated-prefix.nix { }; - in longrun { - name = "acquire-lan-prefix"; - run = "${script} /run/service-state/dhcp6c.wan $(output ${services.int} ifname)"; - dependencies = [ services.dhcp6 ]; - }; - - services.acquire-wan-address = - let script = pkgs.callPackage ./acquire-wan-address.nix { }; - in longrun { - name = "acquire-wan-address"; - run = "${script} /run/service-state/dhcp6c.wan $(output ${services.wan} ifname)"; - dependencies = [ services.dhcp6 ]; + services.dhcp6c = + let client = svc.dhcp6c.client.build { + interface = services.wan; + }; + in bundle { + name = "dhcp6c"; + contents = [ + (svc.dhcp6c.prefix.build { + inherit client; + interface = services.int; + }) + (svc.dhcp6c.address.build { + inherit client; + interface = services.wan; + }) + ]; }; defaultProfile.packages = with pkgs; [ diff --git a/examples/acquire-delegated-prefix.fnl b/modules/dhcp6c/acquire-delegated-prefix.fnl similarity index 100% rename from examples/acquire-delegated-prefix.fnl rename to modules/dhcp6c/acquire-delegated-prefix.fnl diff --git a/examples/acquire-delegated-prefix.nix b/modules/dhcp6c/acquire-delegated-prefix.nix similarity index 100% rename from examples/acquire-delegated-prefix.nix rename to modules/dhcp6c/acquire-delegated-prefix.nix diff --git a/examples/acquire-wan-address-test.fnl b/modules/dhcp6c/acquire-wan-address-test.fnl similarity index 100% rename from examples/acquire-wan-address-test.fnl rename to modules/dhcp6c/acquire-wan-address-test.fnl diff --git a/examples/acquire-wan-address.fnl b/modules/dhcp6c/acquire-wan-address.fnl similarity index 100% rename from examples/acquire-wan-address.fnl rename to modules/dhcp6c/acquire-wan-address.fnl diff --git a/examples/acquire-wan-address.nix b/modules/dhcp6c/acquire-wan-address.nix similarity index 100% rename from examples/acquire-wan-address.nix rename to modules/dhcp6c/acquire-wan-address.nix diff --git a/modules/dhcp6c/address.nix b/modules/dhcp6c/address.nix new file mode 100644 index 0000000..a00eeb4 --- /dev/null +++ b/modules/dhcp6c/address.nix @@ -0,0 +1,16 @@ +{ + liminix +, lib +, callPackage +}: +{ client, interface } : +let + inherit (liminix.services) longrun; + inherit (lib) mkOption types; + name = "dhcp6c.addr.${client.name}.${interface.name}"; + script = callPackage ./acquire-wan-address.nix { }; +in longrun { + inherit name; + run = "${script} /run/service-state/${client.name} $(output ${interface} ifname)"; + dependencies = [ client interface ]; +} diff --git a/modules/dhcp6c/client.nix b/modules/dhcp6c/client.nix new file mode 100644 index 0000000..5c6a765 --- /dev/null +++ b/modules/dhcp6c/client.nix @@ -0,0 +1,21 @@ +{ + liminix +, lib +, odhcp6c +, odhcp-script +}: +{ interface } : +let + inherit (liminix.services) longrun; + inherit (lib) mkOption types; + name = "dhcp6c.${interface.name}"; +in longrun { + inherit name; + notification-fd = 10; + run = '' + export SERVICE_STATE=/run/service-state/${name} + ${odhcp6c}/bin/odhcp6c -s ${odhcp-script} -e -v -p /run/${name}.pid -P0 $(output ${interface} ifname) + ) + ''; + dependencies = [ interface ]; +} diff --git a/modules/dhcp6c/default.nix b/modules/dhcp6c/default.nix new file mode 100644 index 0000000..d298c85 --- /dev/null +++ b/modules/dhcp6c/default.nix @@ -0,0 +1,52 @@ +## DHCP6 client module +## =================== +## +## This is for use if you have an IPv6-capable upstream that provides +## address information and/or prefix delegation using DHCP6. It +## provides a service to request address information in the form of a +## DHCP lease, and two dependent services that listen for updates +## to the DHCP address information and can be used to update +## addresses of network interfaces that you want to assign those +## prefixes to + +{ lib, pkgs, config, ...}: +let + inherit (lib) mkOption types; + inherit (pkgs.liminix.services) oneshot; + inherit (pkgs) liminix; +in +{ + options = { + system.service.dhcp6c = { + client = mkOption { type = liminix.lib.types.serviceDefn; }; + prefix = mkOption { type = liminix.lib.types.serviceDefn; }; + address = mkOption { type = liminix.lib.types.serviceDefn; }; + }; + }; + config.system.service.dhcp6c = { + client = liminix.callService ./client.nix { + interface = mkOption { + type = liminix.lib.types.interface; + description = "interface (usually WAN) to query for DHCP6"; + }; + }; + address = liminix.callService ./address.nix { + client = mkOption { + type = types.anything; # liminix.lib.types.service; + }; + interface = mkOption { + type = liminix.lib.types.interface; + description = "interface to assign the address to"; + }; + }; + prefix = liminix.callService ./prefix.nix { + client = mkOption { + type = types.anything; # liminix.lib.types.service; + }; + interface = mkOption { + type = liminix.lib.types.interface; + description = "interface to assign ::1 to"; + }; + }; + }; +} diff --git a/modules/dhcp6c/prefix.nix b/modules/dhcp6c/prefix.nix new file mode 100644 index 0000000..b43da66 --- /dev/null +++ b/modules/dhcp6c/prefix.nix @@ -0,0 +1,16 @@ +{ + liminix +, lib +, callPackage +}: +{ client, interface } : +let + inherit (liminix.services) longrun; + inherit (lib) mkOption types; + name = "dhcp6c.prefix.${client.name}.${interface.name}"; + script = callPackage ./acquire-delegated-prefix.nix { }; +in longrun { + inherit name; + run = "${script} /run/service-state/${client.name} $(output ${interface} ifname)"; + dependencies = [ client interface ]; +}