GUADEC PSA: WiFi fails due to dhclient lease miscalculation

The DHCP server at GUADEC apparently gives out infinite leases, which have a value of 0xFFFFFFFF (in seconds).  Leaving aside the question of whether infinite leases are actually a good idea at a conference where many people come and go (hint: they usually aren’t),  why won’t it just @#%@#%!&&* connect?

By default NetworkManager uses dhclient for DHCP, and that usually works fairly well.  It’s a well-understood program developed by the ISC that’s used by millions every day.  But dhclient apparently fails with infinite leases.  Here’s the dhclient code:

    #define DHCP_SEC_MAX  0xFFFFFFFF

/*
* The ISC timer library doesn’t seem to like negative values
* and can’t accept any values above 4G-1 seconds so we limit
* the values to 0 <= value < 4G-1.  We do it before
* checking the trace option so that both the trace code and
* the working code use the same values.
*/

sec  = when->tv_sec – cur_tv.tv_sec;
usec = when->tv_usec – cur_tv.tv_usec;

<…>
} else if (sec > DHCP_SEC_MAX) {
log_error(“Timeout requested too large ”
“reducing to 2^^32-1″);
sec = DHCP_SEC_MAX;
<…>
}

isc_interval_set(&interval, sec & DHCP_SEC_MAX, usec * 1000);
status = isc_time_nowplusinterval(&expires, &interval);
if (status != ISC_R_SUCCESS) {
log_fatal(“Unable to set up timer: %s”,
isc_result_totext(status));
}

The code attempts to add a timeout that triggers when the lease expires; “when” is the lease interval coming from the DHCP server (which is 0xFFFFFFFF, remember).  “cur_tv” is just gettimeofday().  Let’s enumerate the fail purely for pedagogic purposes:

  • Despite the comment and logged error, the code makes no attempt to limit the value to UINT_MAX – 1.  Even if it did, this wouldn’t help; see below.  So now we’re passing UINT_MAX into isc_time_nowplusinterval() as interval->seconds.  Condensed code for that function:

isc_result_t isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) {
struct timeval tv;

if (gettimeofday(&tv, NULL) == -1)
return (ISC_R_UNEXPECTED);

/* Ensure the resulting seconds value fits in the size of an
* unsigned int.  (It is written this way as a slight optimization;
* note that even if both values == INT_MAX, then when added
* and getting another 1 added below the result is UINT_MAX.)
*/
if ((tv.tv_sec > INT_MAX || i->seconds > INT_MAX) &&
((long long)tv.tv_sec + i->seconds > UINT_MAX))
return (ISC_R_RANGE);

<…>

  • tv.tv_sec could be greater than INT_MAX since time_t is often 8 bytes wide.  So this code is much more likely to fail in early 2038.
  • Oops!  i->seconds is UINT_MAX, and clearly that’s larger than INT_MAX.  So onward to the next bit.
  • Oops I did it again!  I played with your timer!  The second check passes (unless you have a time machine and you like 1970) because tv.tv_sec is the current time (clearly a large value) and i->seconds is already UINT_MAX.
  • An error is returned, and your lease fails.

Looks like this code just doesn’t expect to deal with large values of Unix time; hopefully that’ll get corrected soon.  The Red Hat bug report for this is bug 662254.

What can I do?

NetworkManager supports two different DHCP clients, selectable at runtime.  Install dhcpcd, set dhcp=dhcpcd in the [main] section of /etc/NetworkManager/NetworkManager.conf, restart NM, and voila, DHCP.

2 Responses to “GUADEC PSA: WiFi fails due to dhclient lease miscalculation”

  1. mclasen says:

    Hey Dan,

    what package is that ?

    $ sudo yum install dhcpcd
    No package dhcpcd available.

  2. spider says:

    How do I install dhcpcd on a current fedora 17 release?

    [spider@clarus]~/Documents/gnome-testing% yum provides ‘*/dhcpcd’
    logcheck-1.3.14-6.fc17.noarch : Analyzes log files and sends noticeable events
    : as email
    Repo : fedora
    Matched from:
    Filename : /etc/logcheck/ignore.d.workstation/dhcpcd

    rear-1.13.0-1.fc17.noarch : Relax and Recover (Rear) is a Linux Disaster
    : Recovery framework
    Repo : updates
    Matched from:
    Filename : /usr/share/rear/skel/default/var/lib/dhcpcd

    No binary for it that I can find..