+
/*
* dhcp.c Functions to send/receive dhcp packets.
*
packet->id = ntohl(magic);
code = dhcp_get_option((dhcp_packet_t *) packet->data,
- packet->data_len, 53);
+ packet->data_len, PW_DHCP_MESSAGE_TYPE);
if (!code) {
fr_strerror_printf("No message-type option was found in the packet");
rad_free(&packet);
return NULL;
}
- if ((code[1] < 1) || (code[2] == 0) || (code[2] > DHCP_MAX_MESSAGE_TYPE)) {
+ if ((code[1] < 1) || (code[2] == 0) || (code[2] >= DHCP_MAX_MESSAGE_TYPE)) {
fr_strerror_printf("Unknown value %d for message-type option", code[2]);
rad_free(&packet);
return NULL;
char src_ip_buf[256], dst_ip_buf[256];
if ((packet->code >= PW_DHCP_DISCOVER) &&
- (packet->code <= (1024 + DHCP_MAX_MESSAGE_TYPE))) {
+ (packet->code < (1024 + DHCP_MAX_MESSAGE_TYPE))) {
name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
} else {
snprintf(type_buf, sizeof(type_buf), "%d",
char dst_ip_buf[INET6_ADDRSTRLEN];
if ((packet->code >= PW_DHCP_DISCOVER) &&
- (packet->code <= (1024 + DHCP_MAX_MESSAGE_TYPE))) {
+ (packet->code < (1024 + DHCP_MAX_MESSAGE_TYPE))) {
name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
} else {
snprintf(type_buf, sizeof(type_buf), "%d",
uint32_t attr;
/*
+ * Not enough room for the option header, it's a
+ * bad packet.
+ */
+ if ((p + 2) > (data + len)) {
+ fr_pair_list_free(&head);
+ return -1;
+ }
+
+ /*
+ * Not enough room for the option header + data,
+ * it's a bad packet.
+ */
+ if ((p + 2 + p[1]) > (data + len)) {
+ fr_pair_list_free(&head);
+ return -1;
+ }
+
+ /*
* The initial OID string looks like:
* <iana>.0
*
* multiple additional VPs
*/
fr_cursor_init(&cursor, vp_p);
- for (;;) {
- q = memchr(p, '\0', q - p);
+ while (p < end) {
+ q = memchr(p, '\0', end - p);
/* Malformed but recoverable */
if (!q) q = end;
fr_pair_value_bstrncpy(vp, (char const *)p, q - p);
p = q + 1;
+ if (p >= end) break;
+
/* Need another VP for the next round */
- if (p < end) {
- vp = fr_pair_afrom_da(ctx, vp->da);
- if (!vp) {
- fr_pair_list_free(vp_p);
- return -1;
- }
- fr_cursor_insert(&cursor, vp);
- continue;
+ vp = fr_pair_afrom_da(ctx, vp->da);
+ if (!vp) {
+ fr_pair_list_free(vp_p);
+ return -1;
}
- break;
+ fr_cursor_insert(&cursor, vp);
}
}
break;
a_p = p + 2;
/*
+ * Ensure we've not been given a bad length value
+ */
+ if ((a_p + a_len) > q) {
+ fr_strerror_printf("Length field value of option %u is incorrect. "
+ "Got %u bytes, expected <= %zu bytes", p[0], p[1], q - a_p);
+ fr_pair_list_free(out);
+ return -1;
+ }
+
+ /*
* Unknown attribute, create an octets type
* attribute with the contents of the sub-option.
*/
* Decode the header.
*/
for (i = 0; i < 14; i++) {
- char *q;
vp = fr_pair_make(packet, NULL, dhcp_header_names[i], NULL, T_OP_EQ);
if (!vp) {
break;
case PW_TYPE_STRING:
- vp->vp_strvalue = q = talloc_array(vp, char, dhcp_header_sizes[i] + 1);
- vp->type = VT_DATA;
- memcpy(q, p, dhcp_header_sizes[i]);
- q[dhcp_header_sizes[i]] = '\0';
- vp->vp_length = strlen(vp->vp_strvalue);
- if (vp->vp_length == 0) {
- fr_pair_list_free(&vp);
+ /*
+ * According to RFC 2131, these are null terminated strings.
+ * We don't trust everyone to abide by the RFC, though.
+ */
+ if (*p != '\0') {
+ uint8_t *end;
+ int len;
+ end = memchr(p, '\0', dhcp_header_sizes[i]);
+ len = end ? end - p : dhcp_header_sizes[i];
+ fr_pair_value_bstrncpy(vp, p, len);
}
+ if (vp->vp_length == 0) fr_pair_list_free(&vp);
break;
case PW_TYPE_OCTETS:
/*
* Vendor is "MSFT 98"
*/
- vp = fr_pair_find_by_num(head, 63, DHCP_MAGIC_VENDOR, TAG_ANY);
- if (vp && (strcmp(vp->vp_strvalue, "MSFT 98") == 0)) {
+ vp = fr_pair_find_by_num(head, 60, DHCP_MAGIC_VENDOR, TAG_ANY);
+ if (vp && (vp->vp_length >= 7) && (memcmp(vp->vp_octets, "MSFT 98", 7) == 0)) {
vp = fr_pair_find_by_num(head, 262, DHCP_MAGIC_VENDOR, TAG_ANY);
/*
/*
* DHCP-Message-Type is first, for simplicity.
*/
- if ((my_a->da->attr == 53) && (my_b->da->attr != 53)) return -1;
+ if ((my_a->da->attr == PW_DHCP_MESSAGE_TYPE) && (my_b->da->attr != PW_DHCP_MESSAGE_TYPE)) return -1;
+ if ((my_a->da->attr != PW_DHCP_MESSAGE_TYPE) && (my_b->da->attr == PW_DHCP_MESSAGE_TYPE)) return +1;
/*
* Relay-Agent is last
*/
- if ((my_a->da->attr == 82) && (my_b->da->attr != 82)) return 1;
+ if ((my_a->da->attr == PW_DHCP_OPTION_82) && (my_b->da->attr != PW_DHCP_OPTION_82)) return +1;
+ if ((my_a->da->attr != PW_DHCP_OPTION_82) && (my_b->da->attr == PW_DHCP_OPTION_82)) return -1;
if (my_a->da->attr < my_b->da->attr) return -1;
if (my_a->da->attr > my_b->da->attr) return 1;
return -1;
}
+ debug_pair(vp);
*opt_len += len;
p += len;
};
if (!vp) return -1;
if (vp->da->vendor != DHCP_MAGIC_VENDOR) goto next; /* not a DHCP option */
- if (vp->da->attr == 53) goto next; /* already done */
+ if (vp->da->attr == PW_DHCP_MESSAGE_TYPE) goto next; /* already done */
if ((vp->da->attr > 255) && (DHCP_BASE_ATTR(vp->da->attr) != PW_DHCP_OPTION_82)) goto next;
if (vp->da->flags.extended) {
} else {
len = fr_dhcp_vp2data(p, freespace, vp);
+ if (len >= 0) debug_pair(vp);
fr_cursor_next(cursor);
previous = vp->da;
}
p += len;
*opt_len += len;
freespace -= len;
- debug_pair(vp);
} while ((vp = fr_cursor_current(cursor)) && previous && (previous == vp->da) && vp->da->flags.array);
#ifndef NDEBUG
if ((packet->code >= PW_DHCP_DISCOVER) &&
- (packet->code <= (1024 + DHCP_MAX_MESSAGE_TYPE))) {
+ (packet->code < (1024 + DHCP_MAX_MESSAGE_TYPE))) {
name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
} else {
name = "?Unknown?";
p[2] = packet->code - PW_DHCP_OFFSET;
p += 3;
-
/*
* Pre-sort attributes into contiguous blocks so that fr_dhcp_encode_option
* operates correctly. This changes the order of the list, but never mind...
char dst_ip_buf[INET6_ADDRSTRLEN];
if ((packet->code >= PW_DHCP_DISCOVER) &&
- (packet->code <= (1024 + DHCP_MAX_MESSAGE_TYPE))) {
+ (packet->code < (1024 + DHCP_MAX_MESSAGE_TYPE))) {
name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
} else {
snprintf(type_buf, sizeof(type_buf), "%d",
packet->id = xid;
code = dhcp_get_option((dhcp_packet_t *) packet->data,
- packet->data_len, 53);
+ packet->data_len, PW_DHCP_MESSAGE_TYPE);
if (!code) {
fr_strerror_printf("No message-type option was found in the packet");
rad_free(&packet);
char src_ip_buf[256], dst_ip_buf[256];
if ((packet->code >= PW_DHCP_DISCOVER) &&
- (packet->code <= (1024 + DHCP_MAX_MESSAGE_TYPE))) {
+ (packet->code < (1024 + DHCP_MAX_MESSAGE_TYPE))) {
name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
} else {
snprintf(type_buf, sizeof(type_buf), "%d", packet->code - PW_DHCP_OFFSET);