3

Context

I'm currently neck deep in building an internet gateway out of an old fanless, headless Intel Atom/ITX computer I had laying around. These are my requirements:

  • have an ipv4 and ipv6 ip provided by my ISP's DCHP assigned to the internet-facing interface
  • recieve an ipv6 prefix provided by my ISP's DHCP.
  • have a static, private IPv4 ip facing the lan.
  • have IPv4 DHCP server on lan-facing interface.
  • have a IPv6 ip set as <prefix>::1/64 on the lan-facing interface
  • have a DHCPv6 server providing stateful assignment of addresses within the prefix provided by my ISP to LAN clients.
  • must be resilient to disconnects and reconnects on both lan and wan facing interfaces.
  • must function as a network appliance: no maintenance beyond security updates.

I want to use Stateful DHCPv6 instead of Stateless DHCP or SLAAC because I will be setting up DDNS managed by my new gateway as well as radius and a few other odds an ends... some of which will be used to determine what ip clients end up with.

I currently have everything working on the ipv4 side. Like clockwork. The gateway itself has a fully functioning dual-stack connection to the internet and can access resources both via ipv4 and ipv6. I've also implemented a netfilter based firewall for both ipv4 and ipv6. I've even got the lan side assigned a static-private ipv4 address and a <prefix>::1/64 address. And I can provide clients on my lan with an ipv4 address, dns, domain, gateway and all the rest via DHCP. Resilience to disconnects and reconnects is provided by ifplugd.

The Problem

What I can't do is provide Stateful IPv6 addresses in the range of <prefix>::0/64 to clients via DHCP. I'm stuck with the reality that dhcpd needs me to set a static name server, static gateway, and static prefix in it's config file... yet all of those are dynamically assigned based on the prefix given by my ISP. I've been through the dhcpd.conf manpage a number of times now and I don't see anything offering a way to assign these dynamically. That dhcpcd stores it's lease data in binary format doesn't help matters. I've found a workable way to query dhcpcd for it's lease data, so that's not a problem anymore.

My next step is to write I've writen some scripts/systemd units to manage querying the data I need from dhcpcd and (re)starting dhcpd with the appropriate flags (will add as an answer soon). But this is clunky and I fear all the ways it could quirk out on what is meant to be a plug-and-go unit. If I have to ssh into my gateway later to fix something... it means I've failed.

My Questions:

  • Am I just missing the obvious here? If so, what am I missing? If I am after another 48 hours of digging through man pages and RFC documents... then it's just going to go right on being missed.
  • Can WIDE or another all-in-one DCHP client/server provide for my lofty goals (radius, server managed DDNS, etc)?
  • Can I use a link-local or private ip for the gateway ip in a different subnet? Like... can fd41:2a0d:e8e4:0::1 be the entry sent as the router option for a subnet of 26AA:A4A4:300:22AF::/64 if all clients have ips for both that and the fd41:2a0d:e8e4:0::/64 subnet? I've read that using the link-local ip of the server is prefered over the globally routable one specifically because of my issue... but the idea of setting a gateway ip outside the subnet it's for just seems wrong. Yes... but it doesn't fully solve my problem.

P.S. Before anyone asks, I started off trying to use dhclient on the wan side (sticking with ISC tools for dns/dhcp), but it didn't want to resolve ipv6 and ipv4 on the same interface and wouldn't let me query an v6 ip and a v6 prefix at the same time. Probably my fault... but I gave up and switched to dhcpcd as a result.

Config Files

radvd.conf:

interface lan {
    AdvManagedFlag on;
    AdvSendAdvert on;
    #AdvAutonomous off;
    AdvOtherConfigFlag on;
    IgnoreIfMissing on;
    AdvDefaultPreference high;
    MaxRtrAdvInterval 60;
};

dhcpcd.conf:

hostname
duid
persistent
option rapid_commit
option classless_static_routes
option interface_mtu
require dhcp_server_identifier
noipv6rs
waitip 6
waitip 4
denyinterfaces lan

interface wan
ipv4
ipv6
dhcp
dhcp6
ipv6rs
ia_na 1
#ia_pd 2 lan
ia_pd 2/::/64 lan/0/64
7
  • I am not sure what the rationale behind the decision is to use DHCPv6 instead of RA, and I don't see how the DDNS fits in, but have a looked at dnsmasq used for DHCPv6?
    – dirkt
    Aug 8, 2019 at 7:18
  • Specifically, the RA gives up any kind of centralized management and lets every device manage it's own ip config. Which is awesome. But it's counter to my needs. And the way DDNS fits in is that I'm not going to leave the clients to request DDNS updates... instead the DHCP server will handle updating the DNS directly... which, again, "requires" centralized management of ip assignment. And that's a no on dnsmasq. Let me dig into it and get back to you. Aug 8, 2019 at 8:05
  • Perhaps I'm missing something, but dnsmasq seems to have the same issue of requiring me to staticaly configure a prefix, dns ip, etc. And, while the thought of having dhcp and dns in a single daemon is appealing... I really don't like how dnsmasq does authoritative dns. But thank you for the suggestion. I keep forgetting dnsmasq offers dhcp functionality. Aug 8, 2019 at 15:22
  • No, dnsmasq will take the IPv6 prefix from an existing interface, and this will be your ISP provided prefix. Not sure what you mean by "DNS IP", do you want another local DNS server in addition to dnsmasq?
    – dirkt
    Aug 9, 2019 at 4:33
  • option domain-name-server <ip address of dns server (which is my gateway's lan ip)>, 2606:4700:4700::1111, 2606:4700:4700::1001 How do I set that dynamically? And WINS? And all the other things dns is used to configure clients for? And I had planned to use BIND9 for authoritative dns on the local lan. I don't like how dnsmasq handles configuration of dns zones for authoritative dns. But the ability to grab the prefix from an existing interface sounds pretty handy. Aug 9, 2019 at 6:25

1 Answer 1

2

So, I said the next step was to write scripts. Well, here they are.

To explain, the solution I've come up with has two main parts. A template for the dhcpd.conf file. And a script to query the needed data from dhcpcd, parse it, apply it to the template, save the result as /var/local/dhcpd6-lan.conf, then restart dhcpd to use the new settings.

The script makes use of dhcpcd's run-hooks feature. Basically, when dhcpcd does anything, including receiving responses from upstream, it runs /etc/dhcpcd.exit-hook with various environment variables set to the values of relevant dhcp configuration options. I've simply written a hook for the DELEGATED6 action which fires when dhcpcd assigns an ip from a ipv6 prefix responce. I had to implement my own logging because dhcpcd-run-hooks appears to squelch all stderr and stdout from hook scripts.

I do not like this solution. I will not be marking it as the accepted solution. I've put much effort into making it as rugged as possible but it still feels like too many points of potential failure. For now, it's getting the job done. I still feel like there has to be a better way.

UPDATE - 8 Months Later:

Well, looks like I was wrong. The scripts I created have proven remarkably reliable. Eight months and not a single hiccup. The scripts have also grown significantly more robust with some potential corner cases cut out, the ability to update many different configuration files, and a simple json state file for tracking the current state. Given the reliability and robustness of this solution at this point, I'm going to go ahead and accept this answer. I may look into improvements with tools like envsubst in the future.

1
  • 1
    envsubst is a handy tool that might help simplify the script a little. May 2, 2020 at 16:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .