summaryrefslogtreecommitdiffstats
path: root/dhcp.c
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2016-05-11 14:17:15 +0000
committerRoy Marples <roy@marples.name>2016-05-11 14:17:15 +0000
commit3ce1402fdc06ba79429831d7ff8c150bec9aee9c (patch)
treef682449578c5830fd3045eb6888125bebcc06960 /dhcp.c
parent945c2f21f9ae5e57e13f4349fbb57d3e8abb8045 (diff)
downloaddhcpcd-3ce1402fdc06ba79429831d7ff8c150bec9aee9c.tar.xz
Handle truncated DHCP messages, provided only the BOOTP vendor area is
truncated. Fixes [3f10c9b871].
Diffstat (limited to 'dhcp.c')
-rw-r--r--dhcp.c25
1 files changed, 20 insertions, 5 deletions
diff --git a/dhcp.c b/dhcp.c
index cb582f9f..21c1c710 100644
--- a/dhcp.c
+++ b/dhcp.c
@@ -1084,9 +1084,12 @@ make_message(struct bootp **bootpm, const struct interface *ifp, uint8_t type)
*p++ = DHO_END;
len = (size_t)(p - (uint8_t *)bootp);
- /* Pad out to the BOOTP minimum message length.
- * Some DHCP servers incorrectly require this. */
- while (len < BOOTP_MESSAGE_LENTH_MIN) {
+ /* Pad out to the BOOTP message length.
+ * Even if we send a DHCP packet with a variable length vendor area,
+ * some servers / relay agents don't like packets smaller than
+ * a BOOTP message which is fine because that's stipulated
+ * in RFC1542 section 2.1. */
+ while (len < sizeof(*bootp)) {
*p++ = DHO_PAD;
len++;
}
@@ -3136,14 +3139,26 @@ dhcp_handlepacket(void *arg)
"%s: server %s is not destination",
ifp->name, inet_ntoa(from));
}
-
+ /*
+ * DHCP has a variable option area rather than a fixed
+ * vendor area.
+ * Because DHCP uses the BOOTP protocol it should
+ * still send BOOTP sized packets to be RFC compliant.
+ * However some servers send a truncated vendor area.
+ * dhcpcd can work fine without the vendor area being sent.
+ */
bytes = get_udp_data(&bootp, buf);
- if (bytes < sizeof(struct bootp)) {
+ if (bytes < offsetof(struct bootp, vend)) {
logger(ifp->ctx, LOG_ERR,
"%s: truncated packet (%zu) from %s",
ifp->name, bytes, inet_ntoa(from));
continue;
}
+ /* But to make our IS_DHCP macro easy, ensure the vendor
+ * area has at least 4 octets. */
+ while (bytes < offsetof(struct bootp, vend) + 4)
+ bootp[bytes++] = '\0';
+
dhcp_handledhcp(ifp, (struct bootp *)bootp, bytes, &from);
if (state->raw_fd == -1)
break;