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

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    10 Jun 2018 13:20:23 -0000
@@ -222,10 +222,13 @@ set_routes(struct in_addr addr, struct i
 {
        const struct in_addr     any = { INADDR_ANY };
        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,14 +251,22 @@ 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 /32 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

Reply via email to