check_http

The Name field in a check_http-rule is the name of the rule, not the host!

I tripped on this when I tried to check an URL and the certificate age of the same host. The certificate check failed with TCP Connection failed, since there already was a rule by that name. Not very helpful error message, BTW…

DDNS with bind and perl

Problem

You have a crappy internet provider who hands out dynamic IPv4 addresses and IPv6 prefixes, but you can’t remember all those numbers and want to use DNS as intended. Actually, I have 2 internet providers, Vodafone and Telekom, each with its own problems . Vodafone’s IPv6 prefix seems to be static for now, but they blessed me with DS-Lite after the update to 400 Mbit. Telekom has a dual stack, but the public IPv4 address and the delegated IPv6 prefixes are highly dynamic.

What you need

  1. A DNS zone and control over the zone file, so you can delegate a subdomain to another name server
  2. The “another name server” with a static IP. If you don’t have that, stop reading!
  3. a script for the dynamic updates

I have a root server and a DNS zone at Hetzner. The root Server has a static IPv4 address and IPv6 prefix. Also, they let you edit the pure bind zone file via a text box, not a form! Since I’m a perl guy, I did the script in my favorite perfect and easy readable language.

Configure your “another name server”

Install bind on your box with the static IP. Then generate a key for dynamic updates. Do not use dnssec-keygen as described in various tutorials. You will fail! Use ddns-confgen instead and follow the instructions in the comment. Your zone file should look something like this:

...
// THE key
key "ddns-key.dyn.d-tor.org" { 
       algorithm hmac-sha256; 
       secret "base64stufffromddns-confgen="; 
};
// THE dynamic zone
zone "dyn.d-tor.org." { 
       update-policy { grant ddns-key.dyn.d-tor.org zonesub ANY; }; 
       type master; 
       file "dyn.d-tor.org.hosts"; 
};
...

The above snippet configures the zone dyn.d-tor.org and allows updates to anyone who has THE key. Next, create the initial zone file in the directory specified by the “directory” directive in named.conf (on ArchLinux it’s the default /var/named, thus /var/name/dyn.d-tor.org.hosts):

$ORIGIN . 
$TTL 600        ; 10 minutes 
dyn.d-tor.org           IN SOA  valhalla.d-tor.org. me.d-tor.org. ( 
  1          ; serial 
  500        ; refresh (8 minutes 20 seconds) 
  500        ; retry (8 minutes 20 seconds) 
  86400      ; expire (1 day) 
  500        ; minimum (8 minutes 20 seconds) 
) 
  NS      valhalla.d-tor.org.

Then restart/reconfigure bind and check for errors:

# systemctl restart named
# journalctl -u named

If you have ip(6)tables running, allow access to port 53 UDP and TCP for good measure:

# iptables -I INPUT 2 -p udp --dport 53 -j ACCEPT
# iptables -I INPUT 2 -p tcp --dport 53 -j ACCEPT
# iptables -I INPUT 2 -p udp --dport 53 -j ACCEPT
# iptables -I INPUT 2 -p tcp --dport 53 -j ACCEPT

Copy the key to the box where you want to update from, e.g. /etc/ddns.key and set permissions to 600. It should contain only the key section:

key "ddns-key.dyn.d-tor.org" { 
       algorithm hmac-sha256; 
       secret "base64stufffromddns-confgen="; 
};

Now test it:

# nsupdate -k /etc/ddns.key <<EOF
> server 2a02:4f8:2a:254e::2
> update delete blub.dyn.d-tor.org A
> update add blub.dyn.d-tor.org 200 A 191.139.50.71
> send
> EOF

If you’ve done everything right:

# host blub.dyn.d-tor.org 2a02:4f8:2a:254e::2
blub.dyn.d-tor.org has address 191.139.50.71

Delegate the Zone

Now we need to delegate dyn.d-tor.org to 2a02:4f8:2a:254e::2. Add this to the zone file on your authoritative name server (in my case, Hetzner):

...
dyn IN NS dyndns ; delegation to dyndns.d-tor.org
dyndns IN AAAA 2a02:4f8:2a:254e::2 ; IPv6 glue record for dyndns.d-tor.org
dyndns IN A <IPv4.address.of.dyndns> ; IPv4 glue record
...

Wait for the information to spread. Check with dnstracer:

# dnstracer -s . dyn.d-tor.org

If you get a result, we can continue 🙂

THE script

Write a script that extracts the IP addresses from your interfaces and uses nsupdate to update the records. It shouldn’t be that hard. Sorry, I can’t provide mine, because it is very specific to my setup.

Multi-homed: Telekom, Vodafone and Hetzner

Problem

I refined my network configuration a bit, because there was a problem: When I pinged the Vodafone IPv6 address of hadante from my new, shiny Hetzner box, it wouldn’t answer, because I got the policy routing wrong.

Initially I routed everyting to Hetzner via the Vodafone interface, but that’s plain wrong. This way hadante even sent packets originating from Telekom IP’s via the Vodafone interface, with the Telekom IP as source. What I really wanted:

  1. answer requests to the Vodafone interface via Vodafone
  2. make Telekom the default route

Answer requests to the Vodafone IP

The solution was easy: create a rule to send everything from the Vodafone interface out there. Unfortunately, nothing is as easy as it seems. Because the Vodafone-IPv6-Prefix is semi-static, systemd-networkd policy routing doesn’t work. The routing table can be filled automatically:

[Match] 
Name=ext 

[Network] 
DHCP=yes 
IPv6Token=::dead:b0a1 

[DHCP] 
RouteMetric=4096 
RouteTable=199 

[IPv6AcceptRA] 
RouteTable=199

The RouteTable directive adds the routes acquired by DHCP and Router Announcments to the routing table 199 (aka kd, see /etc/iproute2/rt_tables), but without a rule it doesn’t do anything. The IPv6Token directive sets the IPv6 address to <prefix>::dead:b0a1, by the way.

The rule is added by a perl script written by yours truly. It does something like this (pseudo perl code):

...
$old = <old IPv6 address>;
$new = <new IPv6 address>;
# match old prefix
$old =~ m#^([[:xdigit:]]{1,4}:[[:xdigit:]]{1,4}:[[:xdigit:]]{1,4}:[[:xdigit:]]{1,4}:)#;
# delete old rule
system("/usr/bin/ip -6 rule dele from $1:/64 table kd");
# match new prefix
$new =m#^([[:xdigit:]]{1,4}:[[:xdigit:]]{1,4}:[[:xdigit:]]{1,4}:[[:xdigit:]]{1,4}:)#;
# add new rule
system("/usr/bin/ip -6 rule add from $1:/64 lookup kd");
...

This way both the Telekom IP and the Vodafone IP work from anywhere. As a bonus, IPv6 requests to Hetzner from the delegated Telekom IPv6 network now work, too 🙂

Configuring the Telekom interface

During my network configuration spree I tried to configure the Telekom interface with systemd-networkd instead of dhcpcd, but that didn’t work, unfortunately. I couldn’t get the prefix delegation to the internal interface to work. Supposedly systemd-networkd can do it, but the documentation is, let’s say, sparse at best. After several attempts I gave up and reverted to dhcpcd, as described in this post.