You are not logged in.

#1 2018-06-10 13:05:15

anon5
Member
Registered: 2015-10-28
Posts: 8

ip route modification as a post dhcp hook - where?

The problem: When my router reboots, it gets new an IP address from a DHCP server in the LAN, which gives it the default gateway. However the router is the gateway. The router is just a normal x86 and has 2 NICs (LAN and Internet). After obtaining the successful DHCP lease, no device in the LAN can reach the Internet and neither can the router.  ip route becomes the following:

$ ip route show
default via 10.0.0.1 dev enp5s0 proto dhcp src 10.0.0.1 metric 203 
10.0.0.0/24 dev enp5s0 proto dhcp scope link src 10.0.0.1 metric 203 
<ISP IP> dev ppp0 proto kernel scope link src <Outward IP>

<ISP IP> and <Outward IP> are redacted, where <ISP IP> is the IP my router connects to and <Outward IP> is the IP my ISP gives to my router.

Issuing the following 2 lines fixes the problem:

# ip route delete default
# ip route add default dev ppp0

and it becomes:

$ ip route show
default dev ppp0 scope link 
10.0.0.0/24 dev enp5s0 proto dhcp scope link src 10.0.0.1 metric 203 
<ISP IP> dev ppp0 proto kernel scope link src <Outward IP>

The router is supposed to be on 24/7 and periodically it gets a new DHCP lease from the LAN. The DHCP renewal just adds another default route to the list:

$ ip route show
default dev ppp0 scope link 
default via 10.0.0.1 dev enp5s0 proto dhcp src 10.0.0.1 metric 203 
10.0.0.0/24 dev enp5s0 proto dhcp scope link src 10.0.0.1 metric 203 
<ISP IP> dev ppp0 proto kernel scope link src <Outward IP>

The question is: where should the 2 lines that fixes the problem go? I've tried adding them as: IPCustom=('route delete default' 'route add default dev ppp0') to the netctl profies, but that just breaks them. How would one build a dhcp lease hook that is executed after a successful lease renewal?

I could write a C++/Python/Java/shell-script program to check for the ip route changes and just issue the fix whenever it detects changes, but that is just not clean, and potentially has delays and wastes resources. I could also redirect traffic with iptables through a custom program and detect the dhcp lease renewal packets/negotiations, but I would like to avoid doing that. Surely there is a way to do this cleanly?

The setup is the following:
The LAN is 10.0.0.0/24 and has all the devices in it (desktop, laptop, phone etc.). DHCP and DNS servers are run by a pi-hole setup on IP 10.0.0.5. It also maps IPs to MAC addresses and gives them nice readable host names, such as: 10.0.0.1 -> router.

The router uses iptables for firewall and NAT. It also forwards all 53 (DNS) traffic to the pi-hole and only allows 53 traffic to the Internet from the pi-hole, so that no hard-coded addresses, such as those from Android phones can get past the pi-hole.

The Outward IP for the Internet connection is received from a modem with PPPoE and this connection becomes ppp0. The LAN connection is enp5s0.

$ cat /etc/netctl/enp5s0.profile 
Description='Private Interface'
Interface=enp5s0
Connection=ethernet
IP=dhcp
#IPCustom=('route delete default' 'route add default dev ppp0')

Using the IPCustom like the one above, but uncommented, breaks the profile.

I had a static IP for the enp5s0 before, and it didn't overwrite the default ip route. However as the DNS is run by a different computer in the network, the rest of the computers cannot map the router to 10.0.0.1 if the router doesn't ask for the ip from the DHCP server. You could argue that I could just hardcode the router's address to all the host files, but I'm trying to avoid exactly that with the DHCP and DNS servers. Besides when new computers/phones are connected to the network, I'd have to manually change them all.

Is there a post successful dhcp renewal hook for dev X that can just launch a shell script? It is probably a one liner put into the right place, but I haven't been able to find where. Any network guru here who would know?

I think I have provided enough info to describe the problem, but if you'd like to know more, please just ask. I've tried to keep this post as short as possible.

Offline

#2 2018-06-11 08:28:18

rsmarples
Member
Registered: 2009-05-12
Posts: 287

Re: ip route modification as a post dhcp hook - where?

On Linux you can have many default routes. What matters is the metric.
What you should do is ensure the PPP routes have a lower metric than the other routes.
How you assign this metric using netctl, I don't know.

Other solutions, like dhcpcd, automatically adjust the metric depending on interface type. Generally VPN > PPP > LAN > WLAN.

Offline

#3 2018-06-11 23:15:45

anon5
Member
Registered: 2015-10-28
Posts: 8

Re: ip route modification as a post dhcp hook - where?

@rsmarples

Thanks for answering! I knew there was a network guru out here. I didn't know about the metric stuff and that I could have multiple default routes. I learned something new today! So what you are saying is that I shouldn't need to worry about the DHCP making another default route as long as its metric is higher than the one I want to be the first default route.

I noticed that there is a metric argument available for the ip route add command, which works manually, but not from my systemd service.

Here is the systemd service I made:

$ cat /etc/systemd/system/ip.route.fix.service
[Unit]
Description=ppp0 default route fix for the LAN
Requires=sys-devices-virtual-net-ppp0.device
After=sys-devices-virtual-net-ppp0.device

[Service]
Type=oneshot
ExecStart=/etc/ip-route-fix.sh
ExecReload=/etc/ip-route-fix.sh
#ExecStop=
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

That gets executed after the ppp0 gets up. But I noticed that the ip route add default dev ppp0 gives an error: Error: Device for nexthop is not up. when executed as soon as the ppp0 is up. I think it cannot reach the IP gateway given by my ISP that fast, could this be right? However it sets the default dev ppp0 scope link route almost correctly. So I'm not too worried. I would like to get it to work correctly though.

Unfortunately the error also leaves the $EXIT_STATUS code to 2 sad Like so:

# systemctl status ip.route.fix.service
● ip.route.fix.service - ppp0 default route fix for the LAN
   Loaded: loaded (/etc/systemd/system/ip.route.fix.service; enabled; vendor preset: disabled)
   Active: failed (Result: exit-code) since <date/time>; 43s ago
  Process: 622 ExecStart=/etc/ip-route-fix.sh (code=exited, status=2)
 Main PID: 622 (code=exited, status=2)

<date/time> <hostname> systemd[1]: Starting ppp0 default route fix for the LAN...
<date/time> <hostname> ip-route-fix.sh[622]: Error: Device for nexthop is not up.
<date/time> <hostname> systemd[1]: ip.route.fix.service: Main process exited, code=exited, status=2/INVALIDARGUMENT
<date/time> <hostname> systemd[1]: ip.route.fix.service: Failed with result 'exit-code'.
<date/time> <hostname> systemd[1]: Failed to start ppp0 default route fix for the LAN.

It looked a little nasty in the systemctl and made it's state degraded. I fixed this in the script, by checking that the new default ip route has been added correctly:

$ cat /etc/ip-route-fix.sh 
#!/bin/bash
defaults=$(ip route list | grep default | wc -l)
while [ $defaults -gt 0 ]
do
  ((defaults--))
  ip route delete default
done
ip route replace metric 199 default dev ppp0
ip route list | grep default | \
while read line; do
  if [ "$line" == "default dev ppp0 scope link" ]; then
    EXIT_STATUS=0
  elif [ "$line" == "default dev ppp0 scope link metric 199" ]; then
    EXIT_STATUS=0
  fi
done

Everything is working-ish, kind of. What is bizarre is that if I set the ip route replace metric 199 default dev ppp0 manually after a full reboot, the ip route list shows that it has a metric value:

$ ip route list | grep default
default dev ppp0 scope link metric 199

but if the above systemd service sets it, it produces the error Error: Device for nexthop is not up. and it doesn't get the metric:

$ ip route list | grep default
default dev ppp0 scope link

Any idea why is that? Maybe I should just let it "fail" and let the systemd service retry every few seconds until it succeeds setting it up with the metric and without any errors. What I have now just silently ignores the error and checks for the "success" manually. It feels like a hack and not the proper way to do it. The logs still gets an error and the route doesn't get a metric value sad More investigation required...

Last edited by anon5 (2018-06-11 23:22:43)

Offline

#4 2018-06-12 00:30:50

rsmarples
Member
Registered: 2009-05-12
Posts: 287

Re: ip route modification as a post dhcp hook - where?

I'm guessing systemd isn't the correct solution for this, unless some systemd expert knows more.

Offline

#5 2018-06-12 01:12:11

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,441
Website

Re: ip route modification as a post dhcp hook - where?

anon5 wrote:

How would one build a dhcp lease hook that is executed after a successful lease renewal?
...
Is there a post successful dhcp renewal hook for dev X that can just launch a shell script?

dhcpcd hooks are just shell scripts.  And they can respond after a successful lease renewal:

man dhcpcd-run-hooks wrote:

Each time dhcpcd-run-hooks is invoked, $interface is set to the interface that dhcpcd is run on and $reason is to the reason why dhcpcd-run-hooks was invoked...
     BOUND | BOUND6    dhcpcd obtained a new lease from a DHCP server.
     RENEW | RENEW6    dhcpcd renewed it's lease.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

Board footer

Powered by FluxBB