dhcp: skip IP and time options that are shorter than four bytes

ip_opt() copies four bytes whatever the option length says, so a
subnet, router, DNS, server id or broadcast option shorter than four
bytes stores the start of the next option as the address. long_opt()
does not look at the length at all and always moves on by six bytes, so
a lease, renewal or rebind option of another length puts the parser out
of step for the rest of the packet.

Both now read the length. An address or time shorter than four bytes is
skipped, a longer one is taken from its first four bytes and stepped
over whole, and a skipped time leaves the previous value alone.

Found in the code, not on the wire; no server here sends such options.
BANK3 is 47 bytes smaller on the KP_9000_6XHML_X2.
This commit is contained in:
DrDoof committed 2026-09-25 07:45:03 +02:00
1 parent 770926abd1
commit 456a4d9d3f
1 file changed
+17 -13
+17 -13
View File
@@ -232,19 +232,21 @@ void ip_opt(__xdata uint8_t * ip)
{ {
dhcp_state.opt_ptr++; dhcp_state.opt_ptr++;
uint8_t len = DHCP_OPT[dhcp_state.opt_ptr++]; uint8_t len = DHCP_OPT[dhcp_state.opt_ptr++];
*ip++ = DHCP_OPT[dhcp_state.opt_ptr++]; if (len >= 4)
*ip++ = DHCP_OPT[dhcp_state.opt_ptr++]; memcpy(ip, &DHCP_OPT[dhcp_state.opt_ptr], 4);
*ip++ = DHCP_OPT[dhcp_state.opt_ptr++];
*ip++ = DHCP_OPT[dhcp_state.opt_ptr++];
// There may be more than one IP option, such as 2 DNS servers advertised // There may be more than one IP option, such as 2 DNS servers advertised
dhcp_state.opt_ptr += len - 4; dhcp_state.opt_ptr += len;
} }
void long_opt(void) uint8_t long_opt(void)
{ {
dhcp_state.opt_ptr++; dhcp_state.opt_ptr++;
dhcp_state.opt_ptr++; uint8_t len = DHCP_OPT[dhcp_state.opt_ptr++];
if (len < 4) {
dhcp_state.opt_ptr += len;
return 0;
}
long_value = DHCP_OPT[dhcp_state.opt_ptr++]; long_value = DHCP_OPT[dhcp_state.opt_ptr++];
long_value <<= 8; long_value <<= 8;
long_value |= DHCP_OPT[dhcp_state.opt_ptr++]; long_value |= DHCP_OPT[dhcp_state.opt_ptr++];
@@ -252,6 +254,8 @@ void long_opt(void)
long_value |= DHCP_OPT[dhcp_state.opt_ptr++]; long_value |= DHCP_OPT[dhcp_state.opt_ptr++];
long_value <<= 8; long_value <<= 8;
long_value |= DHCP_OPT[dhcp_state.opt_ptr++]; long_value |= DHCP_OPT[dhcp_state.opt_ptr++];
dhcp_state.opt_ptr += len - 4;
return 1;
} }
@@ -275,16 +279,16 @@ void parse_opts(void)
ip_opt(&dhcp_state.broadcast[0]); ip_opt(&dhcp_state.broadcast[0]);
break; break;
case DHCP_LEASE: case DHCP_LEASE:
long_opt(); if (long_opt())
dhcp_state.lease = long_value; dhcp_state.lease = long_value;
break; break;
case DHCP_REBIND: case DHCP_REBIND:
long_opt(); if (long_opt())
dhcp_state.rebind = long_value; dhcp_state.rebind = long_value;
break; break;
case DHCP_RENEWAL: case DHCP_RENEWAL:
long_opt(); if (long_opt())
dhcp_state.renewal = long_value; dhcp_state.renewal = long_value;
break; break;
case DHCP_END: case DHCP_END:
break; break;