On Sun, Jun 10, 2018 at 02:15:09PM -0400, Kenneth R Westerback wrote:
> On Sat, Jun 09, 2018 at 02:10:09PM +0200, Claudio Jeker wrote:
> > On Sat, Jun 09, 2018 at 01:31:20PM +0200, Martin Pieuchot wrote:
> > > On 08/06/18(Fri) 18:06, Kenneth R Westerback wrote:
> > > > Testing at the alternate DHCP lab (the one that serves beer) I find
> > > > that its wifi gives me the lease
> > > > 
> > > > lease {
> > > >   fixed-address 10.112.38.73;
> > > >   next-server 0.0.0.0;
> > > >   option subnet-mask 255.255.255.0;
> > > >   option routers 10.112.33.1;
> > > >   option domain-name-servers 63.250.111.34,63.250.111.35,8.8.8.8;
> > > >   option dhcp-lease-time 14400;
> > > >   option dhcp-message-type 5;
> > > >   option dhcp-server-identifier 10.112.38.1;
> > > >   option dhcp-renewal-time 7200;
> > > >   option dhcp-rebinding-time 12600;
> > > >   option dhcp-client-identifier 1:9c:4e:36:d6:7e:f8;
> > > >   epoch 1528494503;
> > > >   renew 5 2018/06/08 23:48:23 UTC;
> > > >   rebind 6 2018/06/09 01:18:23 UTC;
> > > >   expire 6 2018/06/09 01:48:23 UTC;
> > > > }
> > > > 
> > > > See the problem? If so, skip the next paragraph.
> > > > 
> > > > Note that I get an address of 10.112.38.73/24 and a default route of
> > > > 10.112.33.1. When dhclient attempts to add the default route our stack
> > > > rejects the attempt as 10.112.33.1 is unreachable! Not only does this
> > > > mean the outside world is unreachable, /etc/resolv.conf will not be
> > > > updated because the wifi interface will not own the default route, and
> > > > thus DNS will not work!
> > > > 
> > > > As this particular DHCP testing facility not only serves beer but
> > > > provides paper table coverings and a basket of crayons (although I had
> > > > to surrender my blue crayon to a young artist at the next table) I
> > > > was able to do some complex bit calculations and determine that
> > > > 255.255.240.0 would put the default route and the address in the same
> > > > subnet. I therefore added
> > > > 
> > > > supersede subnet-mask 255.255.240.0;
> > > > 
> > > > to my dhclient.conf and viola (sic)! I had net.
> > > > 
> > > > Checking the iPhone I see the same issue, but the iPhone does connect
> > > > to the network without manual magic. A little birdie told me that IOS
> > > > may be playing games with the provided subnet mask to ensure the
> > > > default route is reachable.
> > > 
> > > Can you check what is the configured address' mask on iOS?
> > > 
> > > > I'm wondering if this auto subnet-mask trimming to ensure the default
> > > > route would be reachable is worthwhile adding? Or if it might break
> > > > more situations than it fixes.
> > > 
> > > I'd say that there's nothing more frustrating than having a non functional
> > > network connection after having used dhclient(8).  So I doubt we're going
> > > to break anything.  However I'm wondering what other OSes are doing 
> > > because
> > > I'm not sure we should work around broken configs :)
> > 
> > Isn't this similar to the google cloud dhcp mode where you get a /32 host
> > IP and a gateway (which is not part of the the /32 obviously).
> > IIRC this is what some other systems do more or less.
> > I think a trick could be to insert the gateway as a /32 cloning route then
> > arp would resolve the gateway which I assume works just fine. Now how to
> > do this exactly is an excercise for the reader ;)
> > 
> > 
> > -- 
> > :wq Claudio
> 
> Turning Claudio's idea into a diff gives the diff below.
> 
> Testing at DHCP Lab B gives a routing table
> 
> Internet:
> Destination        Gateway            Flags   Refs      Use   Mtu  Prio Iface 
> Label
> default            10.112.33.1        GS        29      187     -    12 iwn0 
> 224/4              127.0.0.1          URS        0       23 32768     8 lo0  
> 10.112.33/24       10.112.38.215      CS         1        0     -    12 iwn0 
> 10.112.33.1        a4:6c:2a:5e:8a:de  HLch       1        5     -    11 iwn0 
> 10.112.38/24       10.112.38.215      Cn         0        9     -     8 iwn0 
> 10.112.38.215      9c:4e:36:d6:7e:f8  UHLl       0       35     -     1 iwn0 
> 10.112.38.255      10.112.38.215      Hb         0        1     -     1 iwn0 
> 127/8              127.0.0.1          UGRS       0        0 32768     8 lo0  
> 127.0.0.1          127.0.0.1          UHhl       1        2 32768     1 lo0  
> x230$
> 
> and a resolv.conf
> 
> # Generated by iwn0 dhclient
> nameserver 63.250.111.34
> nameserver 63.250.111.35
> nameserver 8.8.8.8
> lookup file bind
> family inet4
> 
> after getting the lease
> 
> lease {
>   fixed-address 10.112.38.215;
>   next-server 0.0.0.0;
>   option subnet-mask 255.255.255.0;
>   option routers 10.112.33.1;
>   option domain-name-servers 63.250.111.34,63.250.111.35,8.8.8.8;
>   option dhcp-lease-time 14400;
>   option dhcp-message-type 5;
>   option dhcp-server-identifier 10.112.38.1;
>   option dhcp-renewal-time 7200;
>   option dhcp-rebinding-time 12600;
>   option dhcp-client-identifier 1:9c:4e:36:d6:7e:f8;
>   epoch 1528651658;
>   renew 0 2018/06/10 19:27:38 UTC;
>   rebind 0 2018/06/10 20:57:38 UTC;
>   expire 0 2018/06/10 21:27:38 UTC;
> }
> 
> And it works! As sending this email proves. :-)
> 
> Now, whether it is a good idea ... none of the Google incantations I
> used turned up evidence that this is a normal behaviour.
> 
> Thoughts/OK's welcome. Editorial advice on making the
> comment more coherent and useful also sought. :-)
> 
> .... Ken
>                                *     -cloning -iface $addr

henning@ points out that the previous diff is adding a /24 route and
not a /32 route as intended. The existing code was relying on the
address mask being 255.255.255.255. a.k.a. INADDR_BROADCAST.

So add a constant 'broadast' alongside the constant 'any' and use that
when adding the /32 routes.

The resulting routing table looks like

Routing tables

Internet:
Destination        Gateway            Flags   Refs      Use   Mtu  Prio Iface 
Label
default            10.112.33.1        UGS        1       30     -    12 iwn0 
default            172.16.4.1         GS         0      352     -     8 em0  
224/4              127.0.0.1          URS        0     1440 32768     8 lo0  
10.112.33.1        a4:6c:2a:5e:8a:de  UHLch      1       11     -    11 iwn0 
10.112.33.1/32     10.112.38.159      UCS        1        0     -    12 iwn0 
10.112.38/24       10.112.38.159      UCn        0       25     -     8 iwn0 
10.112.38.159      9c:4e:36:d6:7e:f8  UHLl       0       17     -     1 iwn0 
10.112.38.255      10.112.38.159      UHb        0        0     -     1 iwn0 
127/8              127.0.0.1          UGRS       0        0 32768     8 lo0  
127.0.0.1          127.0.0.1          UHhl       1        2 32768     1 lo0  
172.16.4/24        172.16.4.87        Cn         1       91     -     4 em0  
172.16.4.1         link#1             HLch       2       38     -     3 em0  
172.16.4.87        3c:97:0e:e7:f4:a5  UHLl       0      138     -     1 em0  
172.16.4.255       172.16.4.87        Hb         0       22     -     1 em0  

If you see this it still works.

.... Ken

Index: kroute.c
===================================================================
RCS file: /cvs/src/sbin/dhclient/kroute.c,v
retrieving revision 1.155
diff -u -p -r1.155 kroute.c
--- kroute.c    6 Feb 2018 00:25:09 -0000       1.155
+++ kroute.c    12 Jun 2018 13:22:53 -0000
@@ -221,11 +221,15 @@ set_routes(struct in_addr addr, struct i
     unsigned int rtstatic_len)
 {
        const struct in_addr     any = { INADDR_ANY };
+       const struct in_addr     broadcast = { INADDR_BROADCAST };
        struct in_addr           dest, gateway, netmask;
+       in_addr_t                addrnet, gatewaynet;
        unsigned int             i, len;
 
        flush_routes(rtstatic, rtstatic_len);
 
+       addrnet = addr.s_addr & addrmask.s_addr;
+
        /* Add classless static routes. */
        i = 0;
        while (i < rtstatic_len) {
@@ -248,19 +252,28 @@ set_routes(struct in_addr addr, struct i
                        /*
                         * DEFAULT ROUTE
                         */
-                       if (addrmask.s_addr == INADDR_BROADCAST) {
+                       gatewaynet = gateway.s_addr & addrmask.s_addr;
+                       if ((addrmask.s_addr == INADDR_BROADCAST) ||
+                           (gatewaynet != addrnet)) {
                                /*
                                 * DIRECT ROUTE TO DEFAULT GATEWAY
                                 *
-                                * To be compatible with ISC DHCP behavior on
-                                * Linux, if we were given a /32 IP assignment
+                                * If the default route gateway is not reachable
+                                * via the address/netmask being configured on
+                                * the interface then add a direct route for
+                                * the gateway. Deals with weird configs seen
+                                * in the wild.
+                                *
+                                * e.g if we were given a /32h IP assignment
                                 * then add a /32 direct route for the gateway
-                                * to make it routable.
+                                * to make it reachable. a.k.a. "make Google
+                                * Cloud DHCP work".
                                 *
-                                * route add -net $gateway -netmask $addrmask
-                                *     -cloning -iface $addr
+                                * route add -net $gateway
+                                *      -netmask 255.255.255.255
+                                *      -cloning -iface $addr
                                 */
-                               add_route(gateway, addrmask, addr,
+                               add_route(gateway, broadcast, addr,
                                    RTF_STATIC | RTF_CLONING);
                        }
                        

Reply via email to