Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4.0.x - DHCP v4 encoder loops forever if given a string option > 255 octets #2601

Closed
nchaigne opened this issue Apr 5, 2019 · 10 comments
Closed

Comments

@nchaigne
Copy link
Contributor

nchaigne commented Apr 5, 2019

Issue type

  • Defect - Unexpected behaviour (obvious or verified by project member).

Defect

Calling DHCP v4 encoder function (fr_dhcpv4_packet_encode) with a value pair containing a value (string or octets) too long for a DHCP option (> 255) makes it loop forever.

Function encode_rfc_hdr calls encode_value, which returns -1 if there is not enough space.
Then it tries again. But there will never be enough space in 255 octets, so it loops forever.

Proposed fix:

Have function fr_dhcpv4_encode_option check the length of the value pair it has to encode to DHCP options. If it exceeds 255, return an error.

if (vp->vp_length > 255) {
        fr_strerror_printf("Attribute \"%s\" value is too large for a DHCP option", vp->da->name);
        return -1;
}
@alandekok
Copy link
Member

RFC 2131 says:

The values to be passed in an 'option' tag may be too long to fit in
the 255 octets available to a single option (e.g., a list of routers
in a 'router' option [21]). Options may appear only once, unless
otherwise specified in the options document. The client concatenates
the values of multiple instances of the same option into a single
parameter list for configuration.

We should just chop up the "too long" inputs into multiple options.

The RADIUS encoder does the same thing for some attributes.

@nchaigne
Copy link
Contributor Author

nchaigne commented Apr 5, 2019

OK, thanks for the RFC pointer.
Not so trivial then... I'll let you figure out how to fix this. :)

No urgency whatsoever of course.

@alandekok
Copy link
Member

I don't see it looping forever in a test case, so I'm not sure what's wrong there.

I'll push a fix to split the option automatically

@nchaigne
Copy link
Contributor Author

nchaigne commented Apr 5, 2019

You can reproduce it with dhcpclient, e.g. with a 256 octets-long option:

echo "DHCP-Client-Hardware-Address=\"01:02:03:04:05:06\", DHCP-Merit-Dump-File=\"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456\"" | dhcpclient 1.2.3.4 discover

alandekok added a commit that referenced this issue Apr 5, 2019
"0" is a valid return value from encode_option, which means
that it couldn't do anything
@alandekok
Copy link
Member

The issue here I think is "256", and not "300". :( It loops forever if fr_dhcpv4_encode_option() returns 0. Other values are OK.

I've pushed a fix so it doesn't loop forever. The larger fix of splitting data across multiple options will take more time.

alandekok added a commit that referenced this issue Apr 5, 2019
this currently only works for RFC attributes.  A fix for TLVs
is the next step
@alandekok
Copy link
Member

The fixes above should work. I've added the example to the test cases

@nchaigne
Copy link
Contributor Author

nchaigne commented Apr 8, 2019

Thanks for the fixes.

I tried with an option 82 larger than 255 bytes. Encoding seems to work, but Wireshark is not happy ("no room left in option for suboption value"). But maybe it's just too dumb to decode such long options...

My DHCP server returns an option 82 with a length of 0.
(Likely, the server doesn't know how to handle these long options either.)

However, FreeRADIUS cannot decode the reply: fr_dhcpv4_packet_decode fails. Seems it doesn't like an option with a length of 0.
I think this should be allowed.

@nchaigne
Copy link
Contributor Author

nchaigne commented Apr 8, 2019

A sub-option (82.n) of 253 octets is encoded in two options: one of length 0, and the other of length 255 (containing the sub-option of 253 octets).
While technically not incorrect, this is a bit weird (and unnecessary).

@nchaigne
Copy link
Contributor Author

nchaigne commented Apr 8, 2019

Thanks for these last fixes, it seems ok now.

Wireshark is still unhappy when a long sub-option is split across two options, but RFC 3396 clearly states how long options should be handled and I believe FreeRADIUS is now compliant :) (unless there's another RFC that says something different about sub-options...)

@alandekok
Copy link
Member

Thanks for the review and update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants