ISC dhcpd and MAC prefixes

We have a network at the office without a firewall. Several of our technical folks run a whole mess of oddball network protocols, and maintaining a network firewall would take more manpower than it’s worth. We hand these techs a network cable and tell them to not let their gear get broken into, and then heckle them mercilessly when their server becomes a haven for Eastern European porn.

But the boss just got back from ClueCon, where he learned about a whole bunch of nasty exploits for older Cisco phones. These techs have VoIP phones on their desks. The decision was made to give the VoIP phones private addresses, overlaid on the public addresses. Yes, a firewall would be much better, but the maintenance overhead was too high in this situation.

Our VoIP phones have have MAC addresses in particular ranges. For example, a certain model of phone has MAC addresses beginning with 00:03:e3, others begin with 00:03:6b, and the third begin with 00:07:eb. If a device’s MAC address begins with one of these, it should get an address in 172.19.22.0/24. Otherwise, it should get an address in the public pool of 192.0.2.0/24. I’m using ISC dhcpd 3.1.

Start by breaking the devices into classes. Each class will have its own IP configuration. dhcpd has a pattern-matching feature that lets you match MAC addresses like this dhcpd.conf snippet.

class "sip-phone" {
match if (binary-to-ascii (16,8,":",substring(hardware, 0, 4)) = "1:0:3:e3")
or (binary-to-ascii (16,8,":",substring(hardware, 0, 4)) = "1:0:3:6b")
or (binary-to-ascii (16,8,":",substring(hardware, 0, 4)) = "1:0:7:eb");
log (info, (binary-to-ascii (16,8,":",substring(hardware, 0, 4))));
}

class "other" {
match if not (binary-to-ascii (16,8,":",substring(hardware, 0, 4)) = "1:0:3:e3")
and not (binary-to-ascii (16,8,":",substring(hardware, 0, 4)) = "1:0:3:6b")
and not (binary-to-ascii (16,8,":",substring(hardware, 0, 4)) = "1:0:7:eb");
log (info, (binary-to-ascii (16,8,":",substring(hardware, 0, 4))));
}

So, if a host has a hardware (MAC) address matching one of the patterns in the “sip-phone” class, it’ll be classified as a sip phone. If the hardware address doesn’t match anything in the sip-phone class, it’ll be classified as other.

What does that horrible string mean? Read dhcp-eval for details, but here’s the short and nasty version. Inside dhcpd, hardware addresses are binary. The binary-to-ascii function transforms a binary field into characters. The 16,8,: tells binary-to-ascii how to parse the binary data and where to separate the characters. The substring function takes a small portion of the ASCII string, specifically places 0 through 4. The characters are a hardware label (a 1 means Ethernet) followed by a colon, followed by the MAC address. So, to match all Ethernet MAC addresses starting with 00:03:e3, we must search for 01:00:03:e3, shown without the leading zeroes as 1:0:3:e3.

The Boolean logic around these comparisons groups the MAC addresses into classes by MAC.

The interesting bit here is the “log” statement. I wanted to see how the binary-to-string and the substring functions mauled the original MAC address. This LAN has a sufficiently small DHCP request rate that I was able to log the first sixteen bytes of each hardware identifier (including the leading 01: for Ethernet). This helped me figure out what the heck I was finding as I struggled through dhcp-eval(5). These logs were written to the DHCP server log. Remove them when you’re done testing.

In this dhcpd.conf snippet we assign the two classes separate address ranges.

shared-network techs {
subnet 172.19.22.0 netmask 255.255.255.0 {
option routers 172.19.22.1;
pool {
allow members of "sip-phone";
range 172.19.22.10 172.19.22.100;
next-server 192.0.2.130;
}
}

subnet 192.0.2.0 netmask 255.255.255.0 {
option routers 192.0.2.1;
pool {
allow members of "other";
range 192.0.2.100 192.0.2.200;
}
}
}

The DHCP server has an interface on this subnet. I added a private IP to the interface, so that it has both 192.0.2.0/24 and a 172.19.22.0/24 addresses. The shared-network statement tells the DHCP server to not be shocked when it sees both subnets on the local interface.

So far, this works.

UPDATE: To all the folks who say that this network could certainly be VLAN’d and firewalled. There is no technical reason this couldn’t happen. The problems are political. Political problems are just as real as technical problems.