5

I have a Debian server at home. The server is my router and provides VPN access to the outside.

I do not have a static IP address; the lease time given by the ISP is two hours.

This cable cell which services the area I live, seems to have at least two different different netblocks for customers, and it is not entirely unusual obtaining a different IP address after a reboot of the Linux server, or less usually, but more importantly in what concerns this question, after some ISP maintenance operations.

I have some services that are dependent on the IP address; and the public IP adddress is used either for external (VPN) access, and for internal reference.

In some services, I use the dynamic DNS name from FreeDNS in order not to have to change an IP address in several locations.

As such, the best method I devised until now is running a script on dhclient-exit hooks. The script is called after DHCP gives/renews an IP, and restart services if the IP is changed.

I also change the IP of my dynamic DNS name on /etc/hosts, for solving possible problems of using the old IP before the change at FreeDNS side trickles down to me.

The script I wrote for dhclient-exit-hooks.d is this one; exit_status should be 0 if all went ok with dhclient.

#!/bin/bash

PATH=$PATH:/usr/bin

if ! [[ -v exit_status ]]
then
   exit 1
fi

if [ $exit_status -eq 0 ]
then
   IP=`ip addr show eth0.101 | grep inet | awk ' { print $2 } ' | cut -f1 -d "/"`
   OLDIP=`awk ' /xxxx.mooo.com/ { print  $1 } '   /etc/hosts`
   if [ $reason = "REBOOT" ] || [ $reason = "BOUND" ] || [ $IP != $OLDIP ] 
   then
      sed -i "s/^[0-9\.]* xxxx.mooo.com/$IP xxxx.mooo.com/g" /etc/hosts
      timeout 60 /opt/bin/iptables.sh
      timeout 60 /etc/init.d/ipsec restart
      timeout 60 /etc/init.d/asterisk restart
      timeout 120 /etc/init.d/bind9 restart
      timeout 60 /usr/bin/wget -O - http://freedns.afraid.org/dynamic/update.php?XXXXXXXXXXXX > /dev/null
   fi
fi

I am aware of other posts that also recommend using dhclient-exit-hooks.d; however my question is a way to automate the restarting and configuration of those services upon an IP address change.

Rui F Ribeiro
  • 56,709
  • 26
  • 150
  • 232
  • Define "better"? What's wrong with this method? Is there a problem with it, where something doesn't exactly work? Since you're getting your IP address from DHCP, running it from the DHCP client seems like the best method, to me. Remember the old adage, "if it ain't broken, don't fix it"... – Wouter Verhelst Mar 20 '16 at 07:59
  • A bit complicated, too much dependent on the DHCP client, slight probability of getting hang services. You are absolutely right in the KISS part. – Rui F Ribeiro Mar 20 '16 at 08:42
  • 1
    Complicated? Seems simple enough. Dependent on the DHCP client? That seems like a feature, not a bug (anything else would require you to poll the IP address every so often, which is... well, not a good idea). Hung services? There are plenty of good monitoring tools out there which you can use to automatically restart services that are hung... Personally, I think your setup is cool, and I might actually duplicate it at home :-) – Wouter Verhelst Mar 21 '16 at 15:31
  • I edited it out with a view on having possible hang up services. And yep, there is monit. I do really need the IPsec part to be working with the right IP, as I use the VPN to have access to everything from the outside, including voIP and ssh. Hmmm I have started encrypting DNS in the meanwhile, will have to see if I need to add it to the restarted services. – Rui F Ribeiro Mar 21 '16 at 15:47

3 Answers3

3

As Wouter commented, your existing setup seems pretty decent already.

If you want something less dependent on dhclient, you could have a look at the many dynamic DNS clients packaged in Debian.

For example, ddclient can react to DHCP changes or simply monitor an Ethernet interface; when the IP address changes (and only then), it can update a dynamic DNS entry (on any number of providers), as well as run a separate script (which would cover both your use-cases).

Rui F Ribeiro
  • 56,709
  • 26
  • 150
  • 232
Stephen Kitt
  • 434,908
  • The dynamic DNS entry is quite a good idea, thanks. I should not have modified the original question with the edited timeouts, as it should also been part of the answer. There is still something missing about the way I had dhcpd configured...I have to test BIND better, had a race problem that I am not sure it is 100% solved. – Rui F Ribeiro Apr 14 '16 at 06:18
3

I propose to further simplify/split up your solution following the principle of separation of concerns:

  • a script /etc/dhcp/dhclient-exit-hooks.d/trigger_on_ip_change should only decide whether action needs to be taken and defer the action to a separate script /usr/local/bin/act_on_ip_change
  • the script /usr/local/bin/act_on_ip_change should only execute the necessary changes

The reasons for separating those concerns are:

  • you can test separately whether dhclient is triggering correctly (without actually modifying anything on your system during debugging)
  • you can test the "change making" without the need to renew (and thus potential loose) your IP
  • you can execute /usr/local/bin/act_on_ip_change manually in case there's a need
  • the parts are much easier to understand

In short, I'd suggest to have this in /etc/dhcp/dhclient-exit-hooks.d/trigger_on_ip_change_action:

# based on /etc/dhcp/dhclient-exit-hooks.d/debug

if [ "$reason" = "BOUND" -a "$old_ip_address" != "$new_ip_address" ]; then
  /usr/local/bin/act_on_ip_change
fi
0

In the end, I ended up simplifying things a bit my setup to act on IP addresses changes.

The Internet NAT was changed to MASQUERADE, so I do not have to act on it; the iptables rules left the dhclient-exit-hooks.d, installing iptables-persistent.

iptables -A POSTROUTING -o eth0.101 ! -p esp -j MASQUERADE
apt-get install iptables-persistent
iptables-save > /etc/iptables/rules.v4

BIND stopped failing on boot because it recognises dependencies on iptables going up now.

I also do not restart BIND now. Furthermore, BIND is now dependent on dnscrypt-proxy crypt to leave to the Internet, so it is only binded to the internal interfaces (which do not change).

Whist the variable exit_status is mentioned in the dhclient-exit-hooks.d documentation, apparently there is some confusion, and it is only used to pass exit status to DHCP, and not to get it.

So the final script is:

#!/bin/bash

PATH=$PATH:/usr/bin


IP=`ip addr show eth0.101 | grep inet | awk ' { print $2 } ' | cut -f1 -d "/"`
OLDIP=`awk ' /xxxx.mooo.com/ { print  $1 } '   /etc/hosts`
# if reboot or IP changed
if [ $reason = "REBOOT" ] || [ $reason = "BOUND" ] || [ $IP != $OLDIP ] 
   then
      # put it in hosts 
      sed -i "s/^[0-9\.]* xxxx.mooo.com/$IP xxxx.mooo.com/g" /etc/hosts
      timeout 60 /etc/init.d/ipsec restart
      timeout 60 /etc/init.d/asterisk restart
      # update FreeDNS service
      timeout 60 /usr/bin/wget -O - http://freedns.afraid.org/dynamic/update.php?XXXX > /dev/null
fi

As for the absence of exit_status, these are the vars presented in dhclient-exit-hooks.d upon boot:

requested_broadcast_address=1
new_network_number=95.94.xx.0
new_ip_address=95.94.xx.xx
new_dhcp_message_type=5
pid=1100
new_time_offset=0
new_routers=95.94.xx.xx
new_expiry=1462482903
new_subnet_mask=255.255.240.0
interface=eth0.101
requested_time_offset=1
new_domain_name=netcabo.pt
reason=REBOOT
new_time_servers=212.113.176.129 212.113.176.65
requested_routers=1
PATH=/usr/sbin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/bin
requested_subnet_mask=1
new_log_servers=212.113.188.209
new_dhcp_server_identifier=79.169.255.254
new_domain_name_servers=0.0.0.0 8.8.8.8
new_broadcast_address=95.94.xx.255
new_dhcp_renewal_time=7200
new_dhcp_rebinding_time=12600
PWD=/
new_next_server=0.0.0.0
new_dhcp_lease_time=14400
Rui F Ribeiro
  • 56,709
  • 26
  • 150
  • 232
  • 1
    An additional useful service is DNS-o-matic (https://www.dnsomatic.com/). It's not useful if you just need to update one service, but I have to update both FreeDNS and HE's tunnel broker for my IPv6 tunnel and this lets me do it with only a single update (critical for things like DD-WRT that require hasty hacking to allow multiple update targets). – Todd Knarr May 05 '16 at 17:36
  • Cool stuff. Thanks for the heads up @ToddKnarr – Rui F Ribeiro May 05 '16 at 18:33