Routes-apply.sh - Safely apply routes and revert on error

Have you ever been unsure about applying a certain network route, because you feared mis-routing or losing your own connection?
Now there is a solution to this problem: routes-apply.sh

Many system administrators have surely at least once had a moment where they locked themselves out of a system, because applying a wrong iptables rule. Soon enough, a tool called iptables-apply was developed to prevent this from happening. The script tries to apply a given iptables rule set, wait a specific amount of time for an acknowledgement from the user that the system is still reachable, or otherwise revert the rules.

However, iptables are not the only networking tool that you can use to lock you out of a system. Adding or deleting a wrong route (e.g. default or sending the packets of your connection to a dead end) might lead to the same problem. But to my knowledge, no such tool to safely apply routes exists - or its name is counterintuitive.

That's why I wrote a small bash script to behave exactly like iptables-apply: routes-apply.sh on GitHub

What is basically does:

  • Saving the current routes using ip route save to a temporary file
  • Applying new ip route X commands from a file
  • Waiting for user input to confirm that the system is still reachable.
    • If yes, then it exits with 0
    • If not, it restores the temporarily saved routes and returns 255

After cloning the repository Bash-routes-apply.sh, you need to create a file which contains the routes you want to add or delete. For example:

pi@raspberrypi ~> cat /tmp/routes.txt 
del 10.0.0.0/8 via 192.168.2.1
add 10.10.0.0/16 via 192.168.2.1
add 10.20.0.0/16 via 192.168.200.200
add 10.50.0.0/16 via 192.168.50.50
del default via 192.168.2.1
add default via 192.168.13.37

What's the mistake here? The default gateway is 192.168.2.1 right now and I am connecting over that interface. Deleting that route will inevitable stale my connection, because the pi won't know where to send the packets with my destination address and the new default gateway 192.168.13.37 does not exist.
Bad luck if you don't have another SSH jumphost attached to the same network...

Using the routes-apply.sh tool, the script would notice that the user did not (or was not able to) acknowledge that the new routes work as intended, thus reverting to the previously working ones. Here is a sample run applying the above routes:

pi@raspberrypi ~> sudo bash /tmp/routes-apply.sh /tmp/routes.txt 
[sudo] password for pi: 
[*] Current routes are:

default via 192.168.2.1 dev eth0 proto static 
172.16.10.0/24 dev homelan proto kernel scope link src 172.16.10.3 
192.168.2.0/24 dev eth0 proto kernel scope link src 192.168.2.93 

[*] Saving current routes to /tmp/routes-apply-ch750UWI
[*] Applying route commands from /tmp/routes.txt

++ /usr/bin/ip route del 10.0.0.0/8 via 192.168.2.1
RTNETLINK answers: No such process
++ /usr/bin/ip route add 10.10.0.0/16 via 192.168.2.1
++ /usr/bin/ip route add 10.20.0.0/16 via 192.168.200.200
Error: Nexthop has invalid gateway.
++ /usr/bin/ip route add 10.50.0.0/16 via 192.168.50.50
Error: Nexthop has invalid gateway.
++ /usr/bin/ip route del default via 192.168.2.1

Snip my connection staled, because now the return packets don't know where to go, but after waiting for the timeout of 30 seconds, the routes are reverted and the packets are resend:

++ /usr/bin/ip route add default via 192.168.13.37
Error: Nexthop has invalid gateway.

[*] The routes are now:

10.10.0.0/16 via 192.168.2.1 dev eth0 
172.16.10.0/24 dev homelan proto kernel scope link src 172.16.10.3 
192.168.2.0/24 dev eth0 proto kernel scope link src 192.168.2.93 

[*] Packets still flowing and is the connection alive? (y/N) 
[*] Restoring routes!
[*] The routes are now:

default via 192.168.2.1 dev eth0 proto static 
172.16.10.0/24 dev homelan proto kernel scope link src 172.16.10.3 
192.168.2.0/24 dev eth0 proto kernel scope link src 192.168.2.93 
pi@raspberrypi ~> 

Booom iptables-apply.sh to the rescue :-) Helping us to get a working network connection and shell back.

There is not more to say about this script. Maybe that it's still in its early version and might be improved with more features in the future...

-=-