From 0e62d46f8bfa633a7685276f5e7ed06230d56a90 Mon Sep 17 00:00:00 2001 From: "Nicholas J. Kain" Date: Wed, 30 Mar 2011 12:04:38 -0400 Subject: [PATCH] Explicitly track length in get_end_option_idx(). Rename get_options() to get_option_data() and end_options() to get_end_option_idx(). --- ndhc/ifchange.c | 4 ++-- ndhc/options.c | 47 +++++++++++++++++++++++++++-------------------- ndhc/options.h | 4 ++-- ndhc/packet.c | 13 ++++++++----- 4 files changed, 39 insertions(+), 29 deletions(-) diff --git a/ndhc/ifchange.c b/ndhc/ifchange.c index 36a8ad3..9d25dc7 100644 --- a/ndhc/ifchange.c +++ b/ndhc/ifchange.c @@ -1,5 +1,5 @@ /* ifchange.c - functions to call the interface change daemon - * Time-stamp: <2011-03-30 11:33:42 nk> + * Time-stamp: <2011-03-30 12:02:55 nk> * * (c) 2004-2011 Nicholas J. Kain * @@ -180,7 +180,7 @@ static void send_cmd(int sockfd, struct dhcpMessage *packet, return; memset(buf, '\0', sizeof buf); - optdata = get_option(packet, code, &optlen); + optdata = get_option_data(packet, code, &optlen); if (ifchd_cmd(buf, sizeof buf, optdata, optlen, code, option_type(code), option_name(code)) == -1) return; diff --git a/ndhc/options.c b/ndhc/options.c index d1dbe04..31d9f31 100644 --- a/ndhc/options.c +++ b/ndhc/options.c @@ -174,10 +174,10 @@ unsigned char *alloc_dhcp_client_id_option(unsigned char type, return alloc_option(DHCP_CLIENT_ID, data, sizeof data); } -// Worker function for get_option(). Optlen will be set to the length +// Worker function for get_option_data(). Optlen will be set to the length // of the option data. -static uint8_t *do_get_option(uint8_t *buf, ssize_t buflen, int code, - char *overload, ssize_t *optlen) +static uint8_t *do_get_option_data(uint8_t *buf, ssize_t buflen, int code, + char *overload, ssize_t *optlen) { /* option bytes: [code][len]([data1][data2]..[dataLEN]) */ *overload = 0; @@ -221,7 +221,7 @@ static uint8_t *do_get_option(uint8_t *buf, ssize_t buflen, int code, // Get an option with bounds checking (warning, result is not aligned) // optlen will be equal to the length of the option data. -uint8_t *get_option(struct dhcpMessage *packet, int code, ssize_t *optlen) +uint8_t *get_option_data(struct dhcpMessage *packet, int code, ssize_t *optlen) { uint8_t *option, *buf; ssize_t buflen; @@ -230,40 +230,45 @@ uint8_t *get_option(struct dhcpMessage *packet, int code, ssize_t *optlen) buf = packet->options; buflen = sizeof packet->options; - option = do_get_option(buf, buflen, code, &overload, optlen); + option = do_get_option_data(buf, buflen, code, &overload, optlen); if (option) return option; if (overload & 1) { parsed_ff = 1; - option = do_get_option(packet->file, sizeof packet->file, - code, &overload, optlen); + option = do_get_option_data(packet->file, sizeof packet->file, + code, &overload, optlen); if (option) return option; } if (overload & 2) { - option = do_get_option(packet->sname, sizeof packet->sname, - code, &overload, optlen); + option = do_get_option_data(packet->sname, sizeof packet->sname, + code, &overload, optlen); if (option) return option; if (!parsed_ff && overload & 1) - option = do_get_option(packet->file, sizeof packet->file, - code, &overload, optlen); + option = do_get_option_data(packet->file, sizeof packet->file, + code, &overload, optlen); } return option; } /* return the position of the 'end' option */ -int end_option(uint8_t *optionptr) +int get_end_option_idx(uint8_t *optbuf, size_t bufsize) { int i = 0; - - while (i < DHCP_OPTIONS_BUFSIZE && optionptr[i] != DHCP_END) { - if (optionptr[i] != DHCP_PADDING) - i += optionptr[i + OPT_LEN] + OPT_DATA - 1; - i++; + while (i < bufsize && optbuf[i] != DHCP_END) { + if (optbuf[i] != DHCP_PADDING) + i += optbuf[i+1] + 2; + else + i++; + } + if (i < bufsize - 1) + return i; + else { + log_warning("get_end_option_idx(): did not find DHCP_END marker"); + return bufsize - 1; } - return (i < DHCP_OPTIONS_BUFSIZE - 1 ? i : DHCP_OPTIONS_BUFSIZE - 1); } @@ -271,7 +276,8 @@ int end_option(uint8_t *optionptr) * code, length, then data) */ int add_option_string(unsigned char *optionptr, unsigned char *string) { - int end = end_option(optionptr); + // XXX: not real length + int end = get_end_option_idx(optionptr, DHCP_OPTIONS_BUFSIZE); /* end position + string length + option code/length + end option */ if (end + string[OPT_LEN] + 2 + 1 >= DHCP_OPTIONS_BUFSIZE) { @@ -319,7 +325,8 @@ int add_simple_option(unsigned char *optionptr, unsigned char code, /* checking here because it goes towards the head of the packet. */ void add_requests(struct dhcpMessage *packet) { - int end = end_option(packet->options); + // XXX: not real length + int end = get_end_option_idx(packet->options, DHCP_OPTIONS_BUFSIZE); int i, len = 0; packet->options[end + OPT_CODE] = DHCP_PARAM_REQ; diff --git a/ndhc/options.h b/ndhc/options.h index 8f78df1..e749675 100644 --- a/ndhc/options.h +++ b/ndhc/options.h @@ -75,8 +75,8 @@ unsigned char *alloc_option(unsigned char code, unsigned char *optdata, unsigned char *alloc_dhcp_client_id_option(unsigned char type, unsigned char *idstr, size_t idstrlen); -uint8_t *get_option(struct dhcpMessage *packet, int code, ssize_t *optlen); -int end_option(uint8_t *optionptr); +uint8_t *get_option_data(struct dhcpMessage *packet, int code, ssize_t *optlen); +int get_end_option_idx(uint8_t *optbuf, size_t bufsize); int add_option_string(unsigned char *optionptr, unsigned char *string); int add_simple_option(unsigned char *optionptr, unsigned char code, uint32_t data); diff --git a/ndhc/packet.c b/ndhc/packet.c index 29a5709..5202d6b 100644 --- a/ndhc/packet.c +++ b/ndhc/packet.c @@ -105,7 +105,8 @@ int raw_packet(struct dhcpMessage *payload, uint32_t source_ip, * In order to work with those buggy servers, * we truncate packets after end option byte. */ - padding = DHCP_OPTIONS_BUFSIZE - 1 - end_option(packet.data.options); + padding = DHCP_OPTIONS_BUFSIZE - 1 - get_end_option_idx(packet.data.options, + DHCP_OPTIONS_BUFSIZE); packet.ip.protocol = IPPROTO_UDP; packet.ip.saddr = source_ip; @@ -164,7 +165,8 @@ int kernel_packet(struct dhcpMessage *payload, uint32_t source_ip, if (connect(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1) goto out_fd; - padding = DHCP_OPTIONS_BUFSIZE - 1 - end_option(payload->options); + padding = DHCP_OPTIONS_BUFSIZE - 1 - get_end_option_idx(payload->options, + DHCP_OPTIONS_BUFSIZE); result = safe_write(fd, (const char *)payload, DHCP_SIZE - padding); if (result == -1) log_error("kernel_packet: write failed: %s", strerror(errno)); @@ -210,7 +212,7 @@ static void init_selecting_packet(struct client_state_t *cs, ssize_t optlen; /* Must be a DHCPOFFER to one of our xid's */ if (*message == DHCPOFFER) { - if ((temp = get_option(packet, DHCP_SERVER_ID, &optlen))) { + if ((temp = get_option_data(packet, DHCP_SERVER_ID, &optlen))) { /* Memcpy to a temp buffer to force alignment */ memcpy(&cs->serverAddr, temp, 4); cs->xid = packet->xid; @@ -233,7 +235,7 @@ static void dhcp_ack_or_nak_packet(struct client_state_t *cs, unsigned char *temp = NULL; ssize_t optlen; if (*message == DHCPACK) { - if (!(temp = get_option(packet, DHCP_LEASE_TIME, &optlen))) { + if (!(temp = get_option_data(packet, DHCP_LEASE_TIME, &optlen))) { log_line("No lease time received, assuming 1h."); cs->lease = 60 * 60; } else { @@ -293,7 +295,8 @@ void handle_packet(struct client_state_t *cs) return; } - if ((message = get_option(&packet, DHCP_MESSAGE_TYPE, &optlen)) == NULL) { + if ((message = get_option_data(&packet, DHCP_MESSAGE_TYPE, &optlen)) + == NULL) { log_line("couldnt get option from packet -- ignoring"); return; }