Roy's Blog

A Hacker's musings on Code | Tech | Life

DHCP clients by default send a fair chunk of data which can identify you to the local DHCP server. In return they provide you with a stable IP address and configuration parameters.

At a bare minimum, the hardware address of the interface is sent - this is required to work.

So, how to solve this dilema of wanting total anonymity? The answer is to randomise the hardware address. This will happen when the carrier is down OR dhcpcd starts with the interface down. Then, dhcpcd will use this random hardware address to set a DUID LL which will be used inplace of any saved DUID and set the IAID to all zeros. This combo is used by DHCP and DHCPv6 to identify a lease. As this is randomised each time the carrier comes up you get a different IP address!

Try not to use this on an unstable link as it could drain the DHCP server of addresses :(

But we can't stop there! dhcpcd also sends some identifying options as well! For example, this is sent in the vendor class identifier:
dhcpcd-8.99.0:NetBSD-9.99.17:amd64:x86_64

It does not identify you or the device in anyway, but it does say what software is being used on which hardware. This could be used by DHCP servers to hand out a specific image to download and boot from TFTP for network boot clients.

Now, there are a gazzillion and one DHCP options out there - we don't know what you've configured. So dhcpcd will mask all of them when anonymous mode is activated, unless they are essential for enabling dhcpcd to work correctly on the network. But wait! What if you really want to leak something? Like say your on a corporate network that uses DHCP security and still want to remain anonymous? Well you can! Any request or option after the anonymous option in dhcpcd.conf is turned on. So the placing of the anonymous directive is important, unlike other dhcpcd options. So far this is the only implementation of RFC 7844 which does this :)

This is NOT enabled by default because most people want stable addresses AND a flappy link could drain addresses as disussed earlier.

Continue reading...

Whilst developing Privilege Separation in dhcpcd, I had to come up with an IPC design for it. Of course, that involves creating structures.

So far, my structures in dhcpcd are long lived - or rather the scope is design to live outside of where it was created. As such they are created on the heap and are at the mercy of malloc. Generally I use calloc so that the whole area is inited to zero as uninitialised memory is bad.

So I decided to start out and see if I can just create the structures I need on the stack. Turns out I could! Yay! Now, how to you initialise a structure on the stack to all zeros? First let us consider this structure:

struct ps_addr {
    sa_family_t psa_family;
    union {
        struct in_addr psau_in_addr;
        struct in6_addr psau_in6_addr;
    } psa_u;
#define psa_in_addr     psa_u.psau_in_addr
#define psa_in6_addr    psa_u.psau_in6_addr
};

The first way is memset:

struct ps_addr psa;

memset(&psa, 0, sizeof(psa));
psa.psa_family = AF_INET;

But what if you could avoid memset? Luckily the C standard allows setting any member and will zero all other members. So we can do this:

struct ps_addr psa = { .psa_family = AF_INET };

Wow!!! So simple. This reduces binary size a fair bit. But then I turned on the Memory Sanitiser and boom, it crashed hard. Why?

The answer is simple - padding. Eric S Raymond gives a very good writeup about the problem. Basically, the standard will initialise any unintialised members to zero - but padding added for alignent isn't a member! So we need to ensure that our structure requires zero padding.

Here is the new struct:

struct ps_addr {
    sa_family_t psa_family;
    uint8_t psa_pad[4 - sizeof(sa_family_t)];
    union {
        struct in_addr psau_in_addr;
        struct in6_addr psau_in6_addr;
    } psa_u;
#define psa_in_addr     psa_u.psau_in_addr
#define psa_in6_addr    psa_u.psau_in6_addr
};

And it allows the former structure initialisation to work and memory sanitisers are happy - so happy days :) Now, if anyone can tell me what I can use instead of the magic number 4 in the above I'd be even happier!

Continue reading...

with the following changes:

  • inet: Allow forcing a host route from an interface without a lease
  • dhcpcd: Don't wait for an address family to complete if not using it
  • Linux: fix RA time unit confusion

If you are suffering from IPv6 addresses not transitioning from the tentative state (regression from dhcpcd-8.1 on Linux) you will need to do one of the following after installing dhcpcd:

  • reboot

    OR

  • dhcpcd -x
  • echo 1000 > /proc/sys/net/ipv6/neigh/$interface/retrans_time_ms
  • ip -f inet6 a flush
  • start dhcpcd as normal

ftp://roy.marples.name/pub/dhcpcd/dhcpcd-8.1.5.tar.xz
http://roy.marples.name/downloads/dhcpcd/dhcpcd-8.1.5.tar.xz

Continue reading...

with the following change:

  • options: Fix allocating the script option

This issue has been around since 7.1.0 (bad me) so I've quickly released new versions to fix.

ftp://roy.marples.name/pub/dhcpcd/dhcpcd-8.1.4.tar.xz
http://roy.marples.name/downloads/dhcpcd/dhcpcd-8.1.4.tar.xz

ftp://roy.marples.name/pub/dhcpcd/dhcpcd-7.2.5.tar.xz
http://roy.marples.name/downloads/dhcpcd/dhcpcd-7.2.5.tar.xz

Continue reading...

with the following changes:

  • Linux: prefer ms RA times
  • Linux: Support kernels without PR_SET_MM_MAP
  • dhcpcd: Only report SSID when we have a carrier
  • IPv6ND: Fix reachable test
  • DHCP6: Work better with infinite addresses
  • DHCP6: Suboption 3 of NTP Server is a FQDN
  • DHCP6: Fix deprecating a delegated prefix
  • DHCP: Ensure we have a lease to extract options from

ftp://roy.marples.name/pub/dhcpcd/dhcpcd-8.1.3.tar.xz
http://roy.marples.name/downloads/dhcpcd/dhcpcd-8.1.3.tar.xz

Continue reading...