oxidecomputer/opte

DHCP Hostname option is double encoded on the wire.

Closed this issue · 6 comments

The Hostname option in OPTE's DHCP responses appears to be double encoded, such that the hostname seen by the guest is prefixed with the length of the hostname itself.

For example:

\x07us-west
and
\x04ekke

On the latter VM, the dhcpinfo command shows this:

^Dekke# /sbin/dhcpinfo -c Hostname
0x04
0x65
0x6B
0x6B
0x65
0x00

(You can also see the ^D in the prompt).

There's also a trailing \x0 that should not be there.

I captured a packet trace to confirm what was on the wire, and decoded it with wireshark. That shows:

image

correponding to the byte sequence:

image

After the 0c indicating the Hostname option, there is the length (6) and then the 6 bytes as shown by dhcpinfo above.

Here, for comparison, is a DHCP response from ISC DHCP server, containing both a Hostname (12) and Domainname (15) option:

image

From code inspection, it looks like these are actually being encoded using the label-sequence format of RFC 1035 section 3.1, which is incorrect for DHCP.

Hmm, reading that part of the spec again it seems a bit ambiguous?

RFC 1035 3.1. Name space definitions is where the label length prefix + ending NUL byte encoding comes from:

Domain names in messages are expressed in terms of a sequence of labels. Each label is represented as a one octet length field followed by that number of octets. Since every domain name ends with the null label of the root, a domain name is terminated by a length byte of zero.

RFC 2132 3.14. Host Name Option doesn't explicitly call out the encoding but does say:

The name may or may not be qualified with the local domain name... See RFC 1035 for character set restrictions.

Option 15 (DomainName) we encode the same way.

RFC1035 is around DNS, and I think the cross reference from RFC2132 is just about character encoding restrictions.
I've sampled three DHCP servers (ISC, Cisco and Unifi) and all just put the raw domain name in the option after a length byte, which is how I read RFC2132. This is the same for the HostName(12) and DomainName(15) options.
It's also what happens for the DHCPv6 FQDN option (RFC 4704).

The reason we stuck with DNS-encoding here is due to RFC 4704, Sec 4.2:

To send a fully qualified domain name, the Domain Name field is set
to the DNS-encoded domain name including the terminating zero-length
label. To send a partial name, the Domain Name field is set to the
DNS-encoded domain name without the terminating zero-length label.

So for v6, that's seemingly what the RFC asks for -- and I worked backwards from there under maybe the wrong assumption for v4. Host and Domain name could reasonably just be ASCII in v4, given the way that's worded.

So for v6, that's seemingly what the RFC asks for -- and I worked backwards from there under maybe the wrong assumption for v4. Host and Domain name could reasonably just be ASCII in v4, given the way that's worded.

Makes sense, thanks for the reference. I've updated the commit message in the associated PR to reflect this.