How do DUID/IAIDs work? (DHCP)

Wow fuck i actually had no idea. I didnt read it this closely. I might have to take a look at my advanced settings when I setup a TFTP server later for RPI netboot configs

Ahh that helps. I think the best way to figure out these questions is to trial an error. Its definitely iterative and annoying but the problem I think your facing is the one I faced. Theres no good documentation right? Its very difficult to grab the understanding yourself.

Because the server blob controls a bit of What kind of DUID is issued. Im not entirely sure of the DHCPv6 server can operate in a mixed mode. The type of DUID also matters IIRC if you you are using the RA daemon with regard to its stateful or statelessness. The primary type used in my system is the DUID-LLT meaning its first generated when my DHCP server initializes and its immutable obviously… There is another type. This type is the vendor assigned or partially MAC generated DUID… aka Vendor-assigned unique ID based on Enterprise Number (DUID-EN). That I believe you can change by changing the MAC but I dont know of any distro or DHCP server that works this way out of the box. The way DUID-LLT works is that the DUID consists of a two-octet type field that contains the value 1, a two-octet hardware type code, four octets that signify a time value, followed by the link-layer address of any one network interface that is connected to the DHCP device at the time that the DUID is generated.

To answer your question most of it is likely just conventions set and stuck with. But does this clear up why its generated by the client?

1 Like

Ok, so in RFC 2132, it talks about the type octet:

   A hardware type of 0 (zero) should be used when the value field
   contains an identifier other than a hardware address (e.g. a fully
   qualified domain name).
1 Like

Maybe this RFC provides additional help. You are talking about a dual stack DHCP server with FQDNs involved while assigning DUIDs

https://www.rfc-editor.org/rfc/rfc4703#section-5.2

1 Like

Yeah, I feel like the RFCs kind of gloss over some things which is not normally the case. Like, wtf is this type octet for?

I think the primary issue is IPv6 is a total mess even today. So many people want their own standard implemented and now we are going 6 ways from IP day and we dont know what to put in there. Does that above RFC get closer to touching your specific issue?

1 Like

OH i think I found what you are looking for

Node-specific Client Identifiers for Dynamic Host Configuration Protocol Version Four (DHCPv4)

https://www.rfc-editor.org/rfc/rfc4361

Oh fuck sorry number confusion at this point you already read that. hmmmm

1 Like

Seems to be about DHCP interacting with DNS which is interesting but not what I’m dealing with. That was another thing I was planning to correlate myself (not use something like dnsmasq).

1 Like

it does when people pass a DNS server as a FQDN and also if the DNS server is internal and expected to resolve IPs to that FQDN and reverse resolve IPs to the FQDNs

So the core of the issue @oO.o is that RFCs dont always have complete data anymore. They reference the implementation or paper that has extensive data. See the references section after reading a paragraph of interest to you. Thats what ive found out looking at RFCs newer than about 5 years ago. The exception of course being RFCs without errata with a fully implemented and ratified standard to which I do not believe DHCP 6 is nor are any of the new DNS RFCs (like DOH and DOT)

Sorry I couldnt be of more help or at least come to the expected resolution.

1 Like

Ok, so I think what I’ll do is use the native DUID in Linux and in OpenBSD use my manual hack of passing my own version of it to client-identifier. Should at least create a base from that I can adjust later.

One last question though. Do you know where I can find the IAID in Linux? I know the DUID is in the lease file, but I need the IAID if I’m going to pre-configure static assignments on the dhcp server.

Somewhere in those RFCs it says that software should make both of those values easily available for exactly that reason but I haven’t found the IAID.

1 Like

Don’t sweat it. I think there’s just no good resolution available.

1 Like

You could tell OpenBSD to generate the DUID via LLT form. Im betting OBSD bases its on DUID-EN (mac generated)

On linux its set by the systemd network daemon

https://man7.org/linux/man-pages/man5/systemd.network.5.html

https://man7.org/linux/man-pages/man5/systemd.network.5.html#[DHCPV4]_SECTION_OPTIONS

You can set that

I emphasize that you dont need to set your DUID. Your dude is ephemeral, immutable. Once generated you can use static DHCPv4 assignments to set the 4 address via mac and you can use the DHCPv6 assignments to set via the generated DUID

1 Like

I’m sure for IPv6, but there’s literally no mention of DUID in IPv4 DHCP anywhere in the OpenBSD docs. They likely have a strong opinion about it. Curious what that is…

I believe EN is “enterprise ID” which I think just means an arbitrarily supplied ID.

DUID-LL is the mac address one without the timestamp (type 3).

Yeah I did see that, but I’d like networkd to just do whatever it wants to do and then tell me what the IAID is that it came up with…

I’m also supporting NetworkManager, so I’ll see to what degree I can influence these parameters there. Gnome’s documentation is terrible to navigate though. Ugh.

In networkd, I can specify the whole thing, so I can still use my manual method, just not directly via client-identifier.

1 Like

Sorry I think you might have edited your post after I read it, but you explained it earlier:

Also, when I actually see DUID-LLT described succinctly, it sounds like such a bad idea…

UUID/type 4 makes a lot of sense to me, although I wish they’d let the IAID be 48 bits so that it could just be the MAC address. Seems stingy when an entire octet is reserved just for the DUID type, of which there are only 4…

1 Like

Oh, interesting. NetworkManager lets you set the identifier type:

https://networkmanager.dev/docs/api/latest/nm-settings-nmcli.html

When the property is a hex string (‘aa:bb:cc’) it is interpreted as a binary client ID, in which case the first byte is assumed to be the ‘type’ field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. ‘01:xx:xx:xx:xx:xx:xx’ where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the ‘type’ field is set to 0.

1 Like

I honestly wonder if this is an @wendell question. His knowledge is likely superior to both of ours. I wouldnt want to take too much of his time but we are both struggling with your system specific requirements at this point lol

OR maybe @risk potentially @ThatGuyB and @Dexter_Kane

They are often in the networking section and they do have a lot of knowledge. They really might see somethings both of us have glossed over so far. If they dont know maybe they know someone else on the forum whos a subject matter expert in IPv6

That piece of code @oO.o posted in the first post implements different kinds of DUIDs - including the simplest one that’s basically prefix + 6bytes of a mac address, which isn’t the default for systemd

The manpage for systemd says:

DUIDType=

Specifies how the DUID should be generated. See RFC 3315[1] for a description of all the options.
The following values are understood:

vendor

If "DUIDType=vendor", then the DUID value will be generated using "43793" as the vendor identifier (systemd) and hashed contents of machine-id(5). This is the default if DUIDType= is not specified.

…again, same file you already linked to has it, as well as iaid.

Why do you care?

3 Likes

I don’t have a lot of knowledge on IPv6, I need to work on that. All I know is that the original way of getting a DUID was to flip a bit from the MAC address, if I’m not mistaken, the 32nd bit (in binary, if it was a 1, change it to 0, or vice versa) and you got your DUID. I thought that’s what Linux still did for a while.

I’ll have to read the RFC, I don’t remember learning about IAID.

2 Likes

I know a lot more now than I did when I started the thread. I am only interested in the DUID-UID (type 4) implementation. DUIDType=vendor sounds like DUID-EN (type 2). I believe for type 4, the UID is still calculated from a hash of the machine-id. I was trying to figure out what hashing algorithm was used there so I could anticipate the value.

Same for IAID, I didn’t find exactly how it was generated.

However, now that I realize it’s possible to supply my own DUID and IAID, I’m leaning to that in order to keep it standardized across different operating systems.

2 Likes

A <5-minute code read tells me it’s machine-id (128bits to start, systemd uses this all over the place) concatenated with a constant , sha256-ed, truncated to 128, and then some bits overriden to make it look like a UUID4, even though it’s strictly not.

The interesting property is that it’s basically random, and tied to an install.

With Ansible you then get a choice, do you just generate some random thing and store it in your config, or do you let the host generate something first time you need it, and don’t worry about Ansible.

If you don’t have systemd e.g. on a BSD box, or you want your own predictable thing, you could take the hostname, salt it with something checked in that’s random, sha256 it, override the same bits as systemd if you really really want to for “compatibility”.

I think systemd goes through this trouble to ensure machine-id is not reversible from public network info, … and also it tries hard to not invent yet another random id other than machine-id


I’ll check the sources for the other id.

4 Likes

I already came up with this, which ties the DUID to the motherboard.

- ansible.builtin.set_fact:
    iface: "{{  iface
                | combine( { 'duid': duid_var } ) }}"
  vars:
    duid_var: "{{ ( '0004'
                    + ( ( ansible_system_vendor
                          + ansible_product_name
                          + ansible_product_version
                          + ansible_product_uuid
                          + ansible_product_serial )
                        | hash('sha256') )[:32] )
                  | regex_findall('..')
                  | join(':') }}"

Hmm, maybe I do want to do that… do you have an idea of what that is or do I just need to read the UUID RFC?

I believe modern x86 boards all have a UUID (see ansible_product_uuid), but at least on the Supermicro hardware I tested this on, it was mostly leading zeros with only the last section having an identifier, so I’d rather hash all this stuff instead).

The DUID-UUID RFC specifically mentions using the board’s UUID as an example though.

1 Like