From 55f24fd2a39e093ae565a28128a9364b86fe41a4 Mon Sep 17 00:00:00 2001 From: "Nicholas J. Kain" Date: Mon, 27 Jun 2011 12:53:35 -0400 Subject: [PATCH] Make the various functions in options.c that take a pointer to an options buffer and length instead take a pointer to a struct dhcpmsg. This argument list choice implicitly gives safe length checks and is simpler. Remove DHCP_OPTIONS_LENGTH. Fold set_option() into alloc_option(). Make some more functions in options.[ch] static. --- ndhc/options.c | 70 ++++++++++++++++++++------------------------------ ndhc/options.h | 14 +++------- ndhc/packet.c | 49 ++++++++++++++--------------------- 3 files changed, 51 insertions(+), 82 deletions(-) diff --git a/ndhc/options.c b/ndhc/options.c index f21a2cb..59bbbfe 100644 --- a/ndhc/options.c +++ b/ndhc/options.c @@ -120,41 +120,28 @@ int option_valid_list(uint8_t code) return 0; } -size_t sizeof_option(uint8_t code, size_t datalen) +static size_t sizeof_option(uint8_t code, size_t datalen) { if (code == DHCP_PADDING || code == DHCP_END) return 1; return 2 + datalen; } -// optdata can be NULL -size_t set_option(uint8_t *buf, size_t buflen, uint8_t code, uint8_t *optdata, - size_t datalen) -{ - if (!optdata) - datalen = 0; - if (code == DHCP_PADDING || code == DHCP_END) { - if (buflen < 1) - return 0; - buf[0] = code; - return 1; - } - - if (datalen > 255 || buflen < 2 + datalen) - return 0; - buf[0] = code; - buf[1] = datalen; - memcpy(buf + 2, optdata, datalen); - return 2 + datalen; -} - uint8_t *alloc_option(uint8_t code, uint8_t *optdata, size_t datalen) { - uint8_t *ret; + uint8_t *buf; size_t len = sizeof_option(code, datalen); - ret = xmalloc(len); - set_option(ret, len, code, optdata, datalen); - return ret; + buf = xmalloc(len); + if (!optdata) + datalen = 0; + if ((code == DHCP_PADDING || code == DHCP_END) && len >= 1) { + buf[0] = code; + } else if (datalen <= 255 && len >= 2 + datalen) { + buf[0] = code; + buf[1] = datalen; + memcpy(buf + 2, optdata, datalen); + } + return buf; } // This is tricky -- the data must be prefixed by one byte indicating the @@ -249,16 +236,16 @@ uint8_t *get_option_data(struct dhcpmsg *packet, int code, ssize_t *optlen) } /* return the position of the 'end' option */ -ssize_t get_end_option_idx(uint8_t *optbuf, size_t bufsize) +ssize_t get_end_option_idx(struct dhcpmsg *packet) { size_t i; - for (i = 0; i < bufsize; ++i) { - if (optbuf[i] == DHCP_END) + for (i = 0; i < sizeof packet->options; ++i) { + if (packet->options[i] == DHCP_END) return i; - if (optbuf[i] == DHCP_PADDING) + if (packet->options[i] == DHCP_PADDING) continue; - if (optbuf[i] != DHCP_PADDING) - i += optbuf[i+1] + 1; + if (packet->options[i] != DHCP_PADDING) + i += packet->options[i+1] + 1; } log_warning("get_end_option_idx(): did not find DHCP_END marker"); return -1; @@ -266,9 +253,9 @@ ssize_t get_end_option_idx(uint8_t *optbuf, size_t bufsize) /* add an option string to the options (an option string contains an option * code, length, then data) */ -size_t add_option_string(uint8_t *optbuf, size_t buflen, uint8_t *optstr) +size_t add_option_string(struct dhcpmsg *packet, uint8_t *optstr) { - size_t end = get_end_option_idx(optbuf, buflen); + size_t end = get_end_option_idx(packet); size_t datalen = optstr[1]; if (end == -1) { @@ -276,17 +263,16 @@ size_t add_option_string(uint8_t *optbuf, size_t buflen, uint8_t *optstr) return 0; } /* end position + optstr length + option code/length + end option */ - if (end + datalen + 2 + 1 >= buflen) { + if (end + datalen + 2 + 1 >= sizeof packet->options) { log_warning("add_option_string: No space for option 0x%02x", optstr[0]); return 0; } - memcpy(optbuf + end, optstr, datalen + 2); - optbuf[end + datalen + 2] = DHCP_END; + memcpy(packet->options + end, optstr, datalen + 2); + packet->options[end + datalen + 2] = DHCP_END; return datalen + 2; } -size_t add_u32_option(uint8_t *optbuf, size_t buflen, uint8_t code, - uint32_t data) +size_t add_u32_option(struct dhcpmsg *packet, uint8_t code, uint32_t data) { int length = 0; uint8_t option[6]; @@ -311,11 +297,11 @@ size_t add_u32_option(uint8_t *optbuf, size_t buflen, uint8_t code, uint32_t t = (uint32_t)data; memcpy(option + 2, &t, 4); } - return add_option_string(optbuf, buflen, option); + return add_option_string(packet, option); } /* Add a paramater request list for stubborn DHCP servers */ -void add_option_request_list(uint8_t *optbuf, size_t buflen) +void add_option_request_list(struct dhcpmsg *packet) { int i, j = 0; uint8_t reqdata[256]; @@ -326,5 +312,5 @@ void add_option_request_list(uint8_t *optbuf, size_t buflen) reqdata[j++] = options[i].code; } reqdata[1] = j - 2; - add_option_string(optbuf, buflen, reqdata); + add_option_string(packet, reqdata); } diff --git a/ndhc/options.h b/ndhc/options.h index afdb98d..52cc12d 100644 --- a/ndhc/options.h +++ b/ndhc/options.h @@ -22,8 +22,6 @@ #include "packet.h" -#define DHCP_OPTIONS_BUFSIZE 308 - /* DHCP option codes (partial list) */ #define DHCP_PADDING 0x00 #define DHCP_SUBNET 0x01 @@ -84,19 +82,15 @@ const char *option_name(uint8_t code); enum option_type option_type(uint8_t code); uint8_t option_length(uint8_t code); int option_valid_list(uint8_t code); -size_t sizeof_option(uint8_t code, size_t datalen); -size_t set_option(uint8_t *buf, size_t buflen, uint8_t code, uint8_t *optdata, - size_t datalen); uint8_t *alloc_option(uint8_t code, uint8_t *optdata, size_t datalen); uint8_t *alloc_dhcp_client_id_option(uint8_t type, uint8_t *idstr, size_t idstrlen); uint8_t *get_option_data(struct dhcpmsg *packet, int code, ssize_t *optlen); -ssize_t get_end_option_idx(uint8_t *optbuf, size_t bufsize); -size_t add_option_string(uint8_t *optbuf, size_t buflen, uint8_t *optstr); -size_t add_u32_option(uint8_t *optbuf, size_t buflen, uint8_t code, - uint32_t data); -void add_option_request_list(uint8_t *optbuf, size_t buflen); +ssize_t get_end_option_idx(struct dhcpmsg *packet); +size_t add_option_string(struct dhcpmsg *packet, uint8_t *optstr); +size_t add_u32_option(struct dhcpmsg *packet, uint8_t code, uint32_t data); +void add_option_request_list(struct dhcpmsg *packet); #endif diff --git a/ndhc/packet.c b/ndhc/packet.c index 3dee47f..eb10b7e 100644 --- a/ndhc/packet.c +++ b/ndhc/packet.c @@ -358,12 +358,12 @@ static int send_dhcp_raw(struct dhcpmsg *payload) // Send packets that are as short as possible, since some servers are buggy // and drop packets that are longer than 562 bytes. - ssize_t endloc = get_end_option_idx(payload->options, DHCP_OPTIONS_BUFSIZE); + ssize_t endloc = get_end_option_idx(payload); if (endloc < 0) { log_error("send_dhcp_raw: attempt to send packet with no DHCP_END"); goto out_fd; } - size_t padding = DHCP_OPTIONS_BUFSIZE - 1 - endloc; + size_t padding = sizeof payload->options - 1 - endloc; size_t iud_len = sizeof(struct ip_udp_dhcp_packet) - padding; size_t ud_len = sizeof(struct udp_dhcp_packet) - padding; @@ -461,13 +461,12 @@ static int send_dhcp_cooked(struct dhcpmsg *payload, uint32_t source_ip, goto out_fd; } - ssize_t endloc = get_end_option_idx(payload->options, - DHCP_OPTIONS_BUFSIZE); + ssize_t endloc = get_end_option_idx(payload); if (endloc < 0) { log_error("send_dhcp_cooked: attempt to send packet with no DHCP_END"); goto out_fd; } - size_t payload_len = sizeof *payload - DHCP_OPTIONS_BUFSIZE - 1 - endloc; + size_t payload_len = sizeof *payload - sizeof payload->options - 1 - endloc; result = safe_write(fd, (const char *)payload, payload_len); if (result == -1) log_error("send_dhcp_cooked: write failed: %s", strerror(errno)); @@ -674,21 +673,17 @@ static struct dhcpmsg init_packet(char type, uint32_t xid) .options[0] = DHCP_END, .xid = xid, }; - add_u32_option(packet.options, DHCP_OPTIONS_BUFSIZE, DHCP_MESSAGE_TYPE, - type); + add_u32_option(&packet, DHCP_MESSAGE_TYPE, type); memcpy(packet.chaddr, client_config.arp, 6); - add_option_string(packet.options, DHCP_OPTIONS_BUFSIZE, - client_config.clientid); + add_option_string(&packet, client_config.clientid); if (client_config.hostname) - add_option_string(packet.options, DHCP_OPTIONS_BUFSIZE, - client_config.hostname); + add_option_string(&packet, client_config.hostname); struct vendor { char vendor; char length; char str[sizeof "ndhc"]; } vendor_id = { DHCP_VENDOR, sizeof "ndhc" - 1, "ndhc"}; - add_option_string(packet.options, DHCP_OPTIONS_BUFSIZE, - (uint8_t *)&vendor_id); + add_option_string(&packet, (uint8_t *)&vendor_id); return packet; } @@ -698,13 +693,11 @@ int send_discover(uint32_t xid, uint32_t requested) { struct dhcpmsg packet = init_packet(DHCPDISCOVER, xid); if (requested) - add_u32_option(packet.options, DHCP_OPTIONS_BUFSIZE, DHCP_REQUESTED_IP, - requested); + add_u32_option(&packet, DHCP_REQUESTED_IP, requested); /* Request a RFC-specified max size to work around buggy servers. */ - add_u32_option(packet.options, DHCP_OPTIONS_BUFSIZE, - DHCP_MAX_SIZE, htons(576)); - add_option_request_list(packet.options, DHCP_OPTIONS_BUFSIZE); + add_u32_option(&packet, DHCP_MAX_SIZE, htons(576)); + add_option_request_list(&packet); log_line("Sending discover..."); return send_dhcp_raw(&packet); } @@ -715,12 +708,10 @@ int send_selecting(uint32_t xid, uint32_t server, uint32_t requested) struct dhcpmsg packet = init_packet(DHCPREQUEST, xid); struct in_addr addr; - add_u32_option(packet.options, DHCP_OPTIONS_BUFSIZE, DHCP_REQUESTED_IP, - requested); - add_u32_option(packet.options, DHCP_OPTIONS_BUFSIZE, DHCP_SERVER_ID, - server); + add_u32_option(&packet, DHCP_REQUESTED_IP, requested); + add_u32_option(&packet, DHCP_SERVER_ID, server); - add_option_request_list(packet.options, DHCP_OPTIONS_BUFSIZE); + add_option_request_list(&packet); addr.s_addr = requested; log_line("Sending select for %s...", inet_ntoa(addr)); return send_dhcp_raw(&packet); @@ -732,7 +723,7 @@ int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) struct dhcpmsg packet = init_packet(DHCPREQUEST, xid); packet.ciaddr = ciaddr; - add_option_request_list(packet.options, DHCP_OPTIONS_BUFSIZE); + add_option_request_list(&packet); log_line("Sending renew..."); if (server) return send_dhcp_cooked(&packet, ciaddr, server); @@ -746,9 +737,8 @@ int send_decline(uint32_t xid, uint32_t server, uint32_t requested) struct dhcpmsg packet = init_packet(DHCPDECLINE, xid); /* DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP */ - add_u32_option(packet.options, DHCP_OPTIONS_BUFSIZE, DHCP_REQUESTED_IP, - requested); - add_u32_option(packet.options, DHCP_OPTIONS_BUFSIZE, DHCP_SERVER_ID, server); + add_u32_option(&packet, DHCP_REQUESTED_IP, requested); + add_u32_option(&packet, DHCP_SERVER_ID, server); log_line("Sending decline..."); return send_dhcp_raw(&packet); @@ -760,9 +750,8 @@ int send_release(uint32_t server, uint32_t ciaddr) struct dhcpmsg packet = init_packet(DHCPRELEASE, random_xid()); packet.ciaddr = ciaddr; - add_u32_option(packet.options, DHCP_OPTIONS_BUFSIZE, DHCP_REQUESTED_IP, - ciaddr); - add_u32_option(packet.options, DHCP_OPTIONS_BUFSIZE, DHCP_SERVER_ID, server); + add_u32_option(&packet, DHCP_REQUESTED_IP, ciaddr); + add_u32_option(&packet, DHCP_SERVER_ID, server); log_line("Sending release..."); return send_dhcp_cooked(&packet, ciaddr, server);