Jan 292018
 

NOTE: if you’re using something other than OSX, say, FreeBSD, then a previous blog post might be the solution you are looking for.

I suggest skipping to the final paragraph before you implement any of what is below.

You fire up your laptop, connect via WIFI, you get an IP address.

You plug in an ethernet cable, you get an IP address.

This is how things should work. It’s expected. It’s automatic.

Sometimes you get the same IP address, sometimes you don’t. It depends on the configuration.

What I want is for each of my devices to get the same IP each time they connect to a specific network.

In my past configurations, this has always been easy: watch for the MAC address of the laptop and act upon that.

However, recent hardware acquisitions have bought in a new situation which makes MAC addresses insufficient for identification. Specifically, my MacBook Pro has no ethernet jack. It uses an external dongle:

Select Series USB-C 3-Port USB 3.0 Hub and Gigabit Ethernet Adapter

Select Series USB-C 3-Port USB 3.0 Hub and Gigabit Ethernet Adapter

Select Series USB-C 3-Port USB 3.0 Hub and Gigabit Ethernet Adapter

Select Series USB-C 3-Port USB 3.0 Hub and Gigabit Ethernet Adapter

I also have a Thunderboltâ„¢ 3 Express Dock HD. I have referred to it as a docking station, but really, it’s a hub. It can provide a wired ethernet connection.

How does this affect DHCP? I have two MacBook Pro laptops, both use USB-C and depending on the situation, either one of them might be using the dongle or the docking station. Each of these two devices contains an ethernet device with a MAC address. Therefore, I had to find another way to distinguish between one laptop and the other.

In this blog post:

  • OSX 10.13.2
  • FreeBSD 11.1
  • isc-dhcp43-server-4.3.6_1
  • All MAC addresses are made up
  • The IP addresses have been altered

By MAC address

This is a standard entry in a dhcpd.conf configuration file:

        host pro2 {
                hardware ethernet 72:16:05:e3:93:c6;
                fixed-address air02.int.unixathome.org;
        }

This is a fine approach, if the MAC address (72:16:05:e3:93:c6) is always with the same computer. In my case, it is not. Fortunately, there is more information within the DHCP protocol to help us out.

I did not find this easy to figure out, but it makes good sense once you know what to look for.

Watching the traffic

tcpdump is a great way to watch what is going on. Here is what I saw:

$ sudo tcpdump -s 1518 -l -n -v -e -i ix0 port 67 or port 68
20:48:00.694058 3b:de:79:ea:93:fa > 96:00:e9:5e:8e:5f, ethertype IPv4 (0x0800), length 342: (tos 0x0, ttl 64, id 8673, offset 0, flags [none], proto UDP (17), length 328)
    10.123.43.1.67 > 10.23.4.13.67: BOOTP/DHCP, Request from c4:b3:01:b3:90:ec, length 300, hops 1, xid 0xf3ef95f7, Flags [none]
	  Gateway-IP 10.154.30.1
	  Client-Ethernet-Address 81:d6:68:68:c6:45
	  Vendor-rfc1048 Extensions
	    Magic Cookie 0x63825363
	    DHCP-Message Option 53, length 1: Discover
	    Parameter-Request Option 55, length 10: 
	      Subnet-Mask, Classless-Static-Route, Default-Gateway, Domain-Name-Server
	      Domain-Name, Option 119, Option 252, LDAP
	      Netbios-Name-Server, Netbios-Node
	    MSZ Option 57, length 2: 1500
	    Client-ID Option 61, length 7: ether c4:b3:01:b3:90:ec
	    Lease-Time Option 51, length 4: 7776000
	    Hostname Option 12, length 5: "air01"
	    Agent-Information Option 82, length 11: 
	      Circuit-ID SubOption 1, length 9: re2_vlan4

This is my laptop putting out a DHCP request. The key line is: Hostname Option 12, length 5: “air01”.

In my OSX laptop, that value is taken from the Computer Name as found at System Preferences > Sharing.

Computer Name

Computer Name

NOTE: In System Preferences > Network > Advanced > TCP/IP there is another value, DHCP Client ID. If you set a value (say XXXXXXXXXXXXXXX) there, it appear in the tcpdump output like this:

Client-ID Option 61, length 16: "XXXXXXXXXXXXXXX"

If you’re going to use that, value, you will need to adjust the code I used below.

Don’t do this

In an earlier failed attempt, I tried this:

        host pro02 {
                hardware ethernet 72:16:05:e3:93:c6;
                option host-name "air01";
                fixed-address air01.int.unixathome.org;
        }

However, host-name is used to pass information to the client, not from the client. This approach was doomed.

Then I tried this:

        host pro02 {
                hardware ethernet 72:16:05:e3:93:c6;
                option dhcp-client-identifier "air01";
                fixed-address air01.int.unixathome.org;
        }

That didn’t work either.

But by that time I’d already posted to Twitter.

How to use Hostname

This reply mentioning match didn’t mean anything to me until I saw posts such as How can I configure a DHCP server to assign addresses based on the OS that is running Solved maybe! and dhcpd class match on hostname or mac address.

I also read [SOLVED] ISC DHCP – class matching based on mac address which gave me some good ideas.

But it was Sending DHCP IP based on clients hostname which gave me the first clue. After a bunch of testing and failure, I came up with this:

class "air01" {
  match if ( option host-name = "air01");
}

...

subnet 10.12.34.0 netmask 255.255.255.0 {
        # option definitions common to all supported networks...
        option domain-name "int.unixathome.org";
        option domain-name-servers 10.12.34.1, 10.12.34.33, 10.12.34.113;

        option routers 10.12.34.1;

        pool {
                allow members of "air01";
                range 10.12.34.101 10.12.34.101;
        }

        pool {
                range 10.12.34.200 10.12.34.250;
        }
}

The first statement creates a class. Then, later in the configuration file I specify two pools, one for the laptop, and one for everything else. The laptop pool is exactly one IP address, by design.

Expanding this

Following on from this, I created classes for two other laptops:

class "dvlMacBookPro" {
  match if ( option host-name = "dvl-MacBook-Pro");
}

class "pro02" {
  match if ( option host-name = "pro02");
}

And two more pools for those laptops:

        pool {
                allow members of "dvlMacBookPro";
                range 10.12.34.102 10.12.34.102;
        }

        pool {
                allow members of "pro02";
                range 10.12.34.103 10.12.34.103;
        }

It works

Sure, this works, but is it not best practice. Before I publish this blog post, I’m going to ask around….

After asking around

On the reddit-homelab IRC channel, varesa mentioned:

>> host foo {
>> hardware ethernet a:b:c:d:e:f;
>> if substring(option vendor-class-identifier, 0, 4) = “MSFT” {
>> fixed-address 192.168.2.10;
>> } else {
>> fixed-address 192.168.2.15;
>> }
>> }

perhaps better:

host dongle { if laptop1 { fixed-address laptop1; } else { … } } ‘

I was unable to get either of these approaches to work because if does not seem to allow fixed-address within it.

My post to the ISC DHCP mailing list has no replies to date. I should rephrase and repost.

Website Pin Facebook Twitter Myspace Friendfeed Technorati del.icio.us Digg Google StumbleUpon Premium Responsive