DHCP requests without "end option" (255) silently discarded

Seems there is a Bug/Feature introduced by ROS v7 related to non-conforming DHCP Discovery request packages.
After update from some ROS v6.xx to v7.20.8 our Mikrotik routers DHCP server silently discards/ignores malformed DHCP discovery request packages, sent by some old automation device within our network.
https://datatracker.ietf.org/doc/html/rfc2131#section-4.1 clearly states that the last “option” in a DHCP package must be the “end option”. Nevertheless there are devices/hardware in the wild which send packages without this mandatory option.
Previous DHCP server versions (ROS <v7) accepted these without complaining and issued leases without problem.
Now we face the problem that we need at least one old version DHCP server within our network to serve "old devices”, which we cannot update and rely on, as there is no obvious setting in v7 ROS to enable “old tolerant” behaviour.

similar issue: https://apps.juniper.net/feature-explorer/feature/5971?fn=Allow%20DHCP%20clients%20to%20send%20packets%20without%20Option%20255

Read this: Cisco DHCPDISCOVER packet ignored by ROSv6.49.19, v7.12.1 & v7.20.4 DHCP server

ROSv6.42.12 and all prior ROS versions handled my malformed DHCP requests without any issue since years. I hope Mikrotik will not insist on this new behavior of strictly discarding malformed packages. There should be at least an option to allow, IMHO. Otherwise I cannot use ROS as DHCP server anymore.
Security/CVEs is not an agument against, I think, because we are talking about UDP packets without any security at all.

Considering the robustness principle ‘be conservative in what you do, be liberal in what you accept from others’ RouterOS should accept DHCP client messages without an end option. Let me explain.

A problem with many RFCs is sloppy wording. Mistakes and ambiguities may cause interoperability issues. More recent RFCs are better than older ones in this respect.

RFC 2132, section 3.2 (End Option):

The end option marks the end of valid information in the vendor field. Subsequent octets should be filled with pad options.

A small mistake here is ‘vendor field’, a leftover from BOOTP missed by reviewers. In DHCP it is called the options field.

RFC 2132, section 9.3 (Option Overload):

This option is used to indicate that the DHCP 'sname' or 'file' fields are being overloaded by using them to carry DHCP options. A DHCP server inserts this option if the returned parameters will exceed the usual space allotted for options.

RFC 2131, section 4.1 (Constructing and sending DHCP messages):

If the options in a DHCP message extend into the 'sname' and 'file' fields, the 'option overload' option MUST appear in the 'options' field, with value 1, 2 or 3, as specified in RFC 1533. If the 'option overload' option is present in the 'options' field, the options in the 'options' field MUST be terminated by an 'end' option, and MAY contain one or more 'pad' options to fill the options field. The options in the 'sname' and 'file' fields (if in use as indicated by the 'options overload' option) MUST begin with the first octet of the field, MUST be terminated by an 'end' option, and MUST be followed by 'pad' options to fill the remainder of the field. Any individual option in the 'options', 'sname' and 'file' fields MUST be entirely contained in that field.

Reading this carefully it can be easily seen that no end option is required in the options field if there is no overload option.

Now comes the tricky part. RFC 2132 defines the overload option as an option for server messages. In client messages it makes no sense as client messages will never need it. But what if a DHCP client message does contain this option?

A better specification would have stated that DHCP clients must not send the overload option and that DHCP servers must ignore it when received (and thus accept client messages without an end option in the options field). IMHO this is exactly what RouterOS should do.

Just my two cents.

1 Like

That is a conclusion similar to my: Cisco DHCPDISCOVER packet ignored by ROSv6.49.19, v7.12.1 & v7.20.4 DHCP server - #27 by BartoszP

Tha main problem is that obeying RFCs makes a lot of installations obsolete or unmanagable due to older nonupgradable devices but on the other hand there are complains that newer software does not follow RFCs and tollerates malformed data what then causes problems due to zylions side effects of different implementations of "what to do with malformed data".

So ... we need to answer to: "Strict rules and predictible results or let our installations work as we do not touch them?.

P.S.
I assume proper implementations of RFCs.

Accepting a DHCP client message without an end option would still be a proper implementation of RFC 2131.

The case in Cisco DHCPDISCOVER packet ignored by ROSv6.49.19, v7.12.1 & v7.20.4 DHCP server is different, but that message should also be accepted indeed (I agree with your conclusion).

The Cisco DHCP client message in that topic has at least two problems: it contains option 52 which has no business in client messages, and it is more or less oversized with a ridiculous amount of padding after the end option. I already argued that the presence of option 52 should not be an issue (it should be ignored).

The message size should not be an issue either. RFC 2131 section 2 states that ‘A DHCP client must be prepared to receive DHCP messages with an 'options' field of at least length 312 octets. This requirement implies that a DHCP client must be prepared to receive a message of up to 576 octets, the minimum IP datagram size an IP host must be prepared to accept.’ RFC 2131 does however not define a minimum acceptable message size for a DHCP server, probably because client messages never are that large. Even assuming the same minimum for the server, there is nothing that forbids accepting larger messages.

The real question is: how much of an effort are you willing to make to accommodate broken but widely used clients, or to fix issues that arise from implementation variations as a result of poor specifications? Without compromising on security, of course.

Adding to my previous post: a robust client would add an end option in the options field even if this is not strictly required (be conservative in what you do). The Microsoft Windows DHCP client even goes an extra mile. RFC 2132 section 3.2 mandates that ‘Subsequent octets [after the end option] should be filled with pad options.’ The Microsoft client even adds padding (4 bytes to be exact) if no padding would be required, i.e. when the end option is the last byte of a 32-bit word in the DHCP message. I assume that Microsoft at some point encountered a case where a broken DHCP server required at least one byte of padding after the end option and decided that customers were best served by adding the padding. The padding could of course also be just a bug :thinking:

Could be added just to let blindly read 32bits of some inner union {} used by their implementation that could be "packed/optimized out" just to minimal size or could be always "full size" left to put objects at addresses optimized for fast reading/writing. Windows ARM implementation also could influenced such a move.

Also Fortinet routers offer an option to make the world go around:
https://community.fortinet.com/t5/FortiGate/Technical-Tip-How-FortiGate-handles-DHCPDISCOVER-messages-that/ta-p/299181

Besides from that, inspired by Kingfisher63’s detailed explanations, I decided to have a closer look at the DHCP/BOOTP RFCs by myself – with following conclusion:

The RFCs are not so bad, indeed the are quite helpful and make it simple to create a conforming options parser without ambiguities. Pls correct me if I am wrong:

  1. begin options parsing at start of ‘options’ field and expect the four-octet 'magic cookie'.
  2. within loop until end of 'options' field (end of DHCP UDP packet payload), read the options:
    • if it is 'end option' (simply 0xFF octet) do break the loop immediately and continue with 3
    • if it's padding option, just skip it (simply a 0x00 octet)
    • read variable length option -- but do not go past end of 'options' field, i.e. end of message -- that would would clearly indicate a malformed message.
  3. check whether 'option overload (52)' was among the options in 'options' field. If so, apply processing of 'file' and/or 'sname' field like done for the 'options' field in step 2.

As you can see the 'end option' is not really required at all. Instead every field could be simply filled up to natural end with 'pad option's (0-octets).
So, why insist on it ??? Take it if it is there, ignore otherwise. But please do not error-out effectively saving: "I did understand you well, no ambiguities, but you forgot the dot at end of your last sentence, therefore I will ignore you. Pls go back to school."

Your algorithm is a nice example of the accept part of the robustness principle. One might indeed ask why is there an end option in the first place.

The RFCs are of course not really bad. If that were the case, we would not have the internet as we know it. And as I said, newer RFCs are (much) better than the old(er) ones. The latter also have been augmented in or superseded by later RFCs.

A little thought experiment. Define a protocol and hand the specification to two or more parties to create protocol implementations. Those parties are not allowed to communicate with each other during development. In a perfect world the resulting implementations would interoperate without a glitch. Unfortunately reality is quite different.

In the early days of the internet there were the TCP and IP bake off sessions (see for example RFC 1025). Manufacturers would bring their equipment to conference venues to test interoperability. This led to numerous improvements of the applicable RFCs and a better understanding how to write them. Some were even completely rewritten. Exciting times!

SOLVED for the moment, as long as there is no Fix in ROS:

As it is so simple to trick a DHCP server, I decided to sniff all DHCP requests in local network segment, check for missing 'end option' -- add if needed -- and re-broadcast. Works like charm and requires only a spare Linux machine/VM.

Here it is, if someone needs it: GitHub - norbertmm/dhcp_fix_endoption: Tool for DHCP request re-broadcast with missing "end option" fixed