Odd Public WiFi breaks dhclient(8) but works for iPhone (Fix!)

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Odd Public WiFi breaks dhclient(8) but works for iPhone (Fix!)

Kenneth R Westerback-2
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 | Threaded
Open this post in threaded view
|

Re: Odd Public WiFi breaks dhclient(8) but works for iPhone (Fix!)

Il Ka
Another approach is to extend subnet by decreasing mask to include router to
client subnet.
I.e.: 10.112.38.73/16.

dhcp-options(5), RFC-2132: "The router option specifies a list of IP
addresses for routers on the client's subnet."

From my point of view dhcp server in your example violates RFC, it is
misconfigured
and should not work at all.



--
Sent from: http://openbsd-archive.7691.n7.nabble.com/openbsd-dev-tech-f151936.html

Reply | Threaded
Open this post in threaded view
|

Re: Odd Public WiFi breaks dhclient(8) but works for iPhone (Fix!)

Il Ka
In reply to this post by Kenneth R Westerback-2
I just checked how openbsd dhcpd handles this:

subnet 10.10.10.0  netmask 255.255.255.0 {
        option routers 20.10.10.1;

        range 10.10.10.10 10.10.10.50;
}

It starts fine and happily sends unusable configuration to client.

dhcpcd (dhcp client I use on linux-based client) installed funny routes:
0.0.0.0 -- 20.10.10.1
20.10.10.1 -- 0.0.0.0

So, Internet connection does not work.

I can't tell openbsd team what to do, but here are my thoughts:
If we believe that router should always be in client network then we should
fix dhcpd also making it to refuse to run with this configuration, should
not we?

If dhcpd accepts this config that means openbsd treats it as valid.
Then, we should not fix client also.

In theory one may need to send router address to client to be accessed
by different interface configured by different dhcp server (or, even,
manually).
But as far as I understand RFC, this is not allowed.



--
Sent from: http://openbsd-archive.7691.n7.nabble.com/openbsd-dev-tech-f151936.html

Reply | Threaded
Open this post in threaded view
|

Re: Odd Public WiFi breaks dhclient(8) but works for iPhone (Fix!)

Stuart Henderson
On 2018/06/10 13:20, Il Ka wrote:
> Another approach is to extend subnet by decreasing mask to include router to
> client subnet.
> I.e.: 10.112.38.73/16.

I think that's the wrong approach, because it will send packets directly
to addresses which should be sent to the router.

> From my point of view dhcp server in your example violates RFC, it is
> misconfigured
> and should not work at all.

Which RFC? All I see relating to this is "The router option specifies a
list of IP addresses for routers on the client's subnet. Routers SHOULD
be listed in order of preference" which doesn't go into details about
allowed addresses.

We already deal with this for the case fairly common in VPS where the
client gets a /32 with a router outside the subnet (which is a good
thing, it means they can use a vlan per client without using 2x or 4x
the number of addresses). The DHCP RFCs are so old they didn't really
have reason to give much thought to conserving IP addresses.


On 2018/06/10 16:01, Il Ka wrote:

> I just checked how openbsd dhcpd handles this:
>
> subnet 10.10.10.0  netmask 255.255.255.0 {
>         option routers 20.10.10.1;
>
>         range 10.10.10.10 10.10.10.50;
> }
>
> It starts fine and happily sends unusable configuration to client.
>
> dhcpcd (dhcp client I use on linux-based client) installed funny routes:
> 0.0.0.0 -- 20.10.10.1
> 20.10.10.1 -- 0.0.0.0
>
> So, Internet connection does not work.

The route entries are bound to be a bit funny with this.

How did you configure the rest of networking on the router to cope
with this setup?

Reply | Threaded
Open this post in threaded view
|

Re: Odd Public WiFi breaks dhclient(8) but works for iPhone (Fix!)

Il Ka
>Which RFC?
It says "IP addresses for routers on the client's subnet", so my idea was
that router must be on client subnet.

>We already deal with this for the case fairly common in VPS where the
>client gets a /32 with a router outside the subnet
But how does it work from client side?
Does your dhcpd server send static route to router?

>How did you configure the rest of networking on the router to cope
>with this setup?

I have interface with 10.10.10.1 and dhcpd server with configuration
provided above,
I then run dhcpcd (I have not tried it with ICS dhcp client) and got broken
routing.

Here is my point: in some installations gateway may reside outside of client
network.
Is it valid?

If it is, then why do we need to fix client (why do we need this patch?)?
It it is not, then should not dhcpd log warnings about such configuration?




--
Sent from: http://openbsd-archive.7691.n7.nabble.com/openbsd-dev-tech-f151936.html

Reply | Threaded
Open this post in threaded view
|

Re: Odd Public WiFi breaks dhclient(8) but works for iPhone (Fix!)

Stuart Henderson
On 2018/06/11 07:39, Il Ka wrote:
> >Which RFC?
> It says "IP addresses for routers on the client's subnet", so my idea was
> that router must be on client subnet.
>
> >We already deal with this for the case fairly common in VPS where the
> >client gets a /32 with a router outside the subnet
> But how does it work from client side?
> Does your dhcpd server send static route to router?

The general case: you run dhclient, it works.

> >How did you configure the rest of networking on the router to cope
> >with this setup?
>
> I have interface with 10.10.10.1 and dhcpd server with configuration
> provided above,
> I then run dhcpcd (I have not tried it with ICS dhcp client) and got broken
> routing.

So you tell the client that the router is at 20.10.10.1, but you don't have
anything at 20.10.10.1. This cannot possibly work, the client can't find the
lladdr of the gateway - it's not a valid test.

> Here is my point: in some installations gateway may reside outside of client
> network.
> Is it valid?

It works on other OS. It works on OpenBSD for the /32 case.

> If it is, then why do we need to fix client (why do we need this patch?)?

It doesn't work on OpenBSD for the non-/32 case.

> It it is not, then should not dhcpd log warnings about such configuration?

A warning? Perhaps. You proposed making it an error before, which I don't
think is helpful. For a start it would make it harder to test krw's diff :-)

Reply | Threaded
Open this post in threaded view
|

Re: Odd Public WiFi breaks dhclient(8) but works for iPhone (Fix!)

Il Ka
>>This cannot possibly work, the client can't find the
lladdr of the gateway

Oops, I now see my experiment was not valid: dhcpcd adds route to router but
can't reach it.
I added alias and it now works, thank you.

So, dhcp client assumes that router anounced by server is always reachable
by
interface that got configuration via dhcp.
Something that is not written explicitly in RFC, but seems to be de-facto
standard,
and it now supported by openbsd, thanks to this patch.



--
Sent from: http://openbsd-archive.7691.n7.nabble.com/openbsd-dev-tech-f151936.html

Reply | Threaded
Open this post in threaded view
|

Re: Odd Public WiFi breaks dhclient(8) but works for iPhone (Fix!)

Kenneth R Westerback-2
In reply to this post by Kenneth R Westerback-2
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 | Threaded
Open this post in threaded view
|

Re: Odd Public WiFi breaks dhclient(8) but works for iPhone (Fix!)

Claudio Jeker
On Tue, Jun 12, 2018 at 06:01:49PM -0400, Kenneth R Westerback wrote:

> 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.
>

I like it. Two comments though.


> 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)) {

If addrmask.s_addr == INADDR_BROADCAST then gatewaynet = gateway.s_addr
and so I think (gatewaynet != addrnet) unless addr.s_addr = gateway.s_addr
(which is not valid or working). So I think

                        gatewaynet = gateway.s_addr & addrmask.s_addr;
                        if (gatewaynet != addrnet) {

is enough to check the direct route case.


>   /*
>   * 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
                                                             ^
                                      Since when we have 32 hours of IP?

Maybe also add cloning to "add a direct route for the gateway."

>   * 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);
>   }
>
>

Anyway just nitpicking. Diff is OK claudio@

--
:wq Claudio