# ICMP redirects, host routes, and expiries



## scotia (Mar 9, 2019)

Hi all,

Last week when someone decided to dig up the street and cut my phone line, I set up an RPi and tethered it to my iPhone, and changed the default route on my ADSL router to my RPi (instead of the Dialer interface).  Anyhoo as expected all my VMs started getting ICMP redirects from the ADSL router indicating that the RPi has a better next hop, and everything worked swimmingly.  The VMs route tables starting filling up with host routes, etc.

Anyway when the ADSL came back up and I removed the route to the RPi I noticed that many sites were now unreachable from my VMs; of course the culprit was the routing table dynamic host routes.  A quick `route flush` and the problem was solved.

Here's an example of a dynamic host route:

```
Destination        Gateway            Flags      Netif     Expire
216.239.32.10      10.1.1.36          UGHD       bge0
```

The obvious question is - when do these routes expire?  If they do, why is the expiry column empty?  And if they don't, why don't they?  I can't find any tuneables in sysctl which hints at such a timeout.  Given that you can safely ignore redirects (albeit to the detriment of the configured default gateway), it wouldn't hurt for these routes to be removed after a timeout.

I did find `net.inet.tcp.hostcache.expire`, which defaults to 3600 seconds, but when adding a host route statically or via the kernel that value doesn't appear in `netstat`.

I can't quite understand the `route add` command with regard to the -expire parameter:


> Note that -expire accepts expiration time of the route as the number of seconds since the Epoch (see time(3)).  When the first character of the number is “+” or “-”, it is interpreted as a value relative to the current time.


Reading this I would expect to supply an epoch value, which would remain unchanged in the `netstat` Expire column, and upon that time arriving, the route would be flushed.  However:


```
# route delete 1.1.1.1 ; route add 1.1.1.1 10.1.1.1 -expire `/bin/date -v "+20S" +"%s"` -nostatic ; netstat -rn -f inet | grep '1\.1\.1\.1' ; echo "sleeping..." ; sleep 3 ; netstat -rn -f inet | grep '1\.1\.1\.1'
delete host 1.1.1.1
add host 1.1.1.1: gateway 10.1.1.1
1.1.1.1            10.1.1.1           UGH        bge0 1551424856
sleeping...
1.1.1.1            10.1.1.1           UGH        bge0 1551424853
```

That's odd.  Why is Expire decrementing?  Waiting more than 20 seconds just shows the route still decrementing.

Other oddities:


```
# route delete 1.1.1.1 ; route add 1.1.1.1 10.1.1.1 -expire 1000000 -nostatic ; netstat -rn -f inet | grep '1\.1\.1\.1' ; echo "sleeping..." ; sleep 3 ; netstat -rn -f inet | grep '1\.1\.1\.1'
delete host 1.1.1.1
add host 1.1.1.1: gateway 10.1.1.1
1.1.1.1            10.1.1.1           UGH        bge0 321263
sleeping...
1.1.1.1            10.1.1.1           UGH        bge0 321260
```

Not sure where that value came from.  Putting a lower epoch in doesn't work at all:

```
# route delete 1.1.1.1 ; route add 1.1.1.1 10.1.1.1 -expire 100000 -nostatic ; netstat -rn -f inet | grep '1\.1\.1\.1' ; echo "sleeping..." ; sleep 3 ; netstat -rn -f inet | grep '1\.1\.1\.1'
delete host 1.1.1.1
add host 1.1.1.1: gateway 10.1.1.1
1.1.1.1            10.1.1.1           UGH        bge0
sleeping...
1.1.1.1            10.1.1.1           UGH        bge0
```


Thanks,
Scott
P.S.: oddly enough, tethering to my iPhone XS or my iPhone 6 using either USB or WiFi would reliably crash the phone and cause a reboot.  It wasn't until I used my venerable iPhone 5 that tethering didn't crash the phone.


----------

