diff --git a/ndhc/ndhc.c b/ndhc/ndhc.c index 9ef4c3f..88fa1b2 100644 --- a/ndhc/ndhc.c +++ b/ndhc/ndhc.c @@ -296,10 +296,8 @@ int main(int argc, char **argv) len = strlen(optarg) > 64 ? 64 : strlen(optarg); if (client_config.clientid) free(client_config.clientid); - client_config.clientid = xmalloc(len + 3); - client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID; - client_config.clientid[OPT_LEN] = len + 1; - memcpy(client_config.clientid + 3, optarg, len); + client_config.clientid = + alloc_dhcp_client_id_option(0, (unsigned char *)optarg, len); break; case 'f': client_config.foreground = 1; @@ -317,10 +315,8 @@ int main(int argc, char **argv) len = strlen(optarg) > 64 ? 64 : strlen(optarg); if (client_config.hostname) free(client_config.hostname); - client_config.hostname = xmalloc(len + 3); - client_config.hostname[OPT_CODE] = DHCP_HOST_NAME; - client_config.hostname[OPT_LEN] = len + 1; - memcpy(client_config.hostname + 3, optarg, len); + client_config.hostname = + alloc_option(DHCP_HOST_NAME, (unsigned char *)optarg, len); break; case 'i': client_config.interface = optarg; @@ -376,11 +372,8 @@ int main(int argc, char **argv) } if (!client_config.clientid) { - client_config.clientid = xmalloc(6 + 3); - client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID; - client_config.clientid[OPT_LEN] = 7; - client_config.clientid[OPT_DATA] = 1; - memcpy(client_config.clientid + 3, client_config.arp, 6); + client_config.clientid = + alloc_dhcp_client_id_option(1, client_config.arp, 6); } if (chdir(chroot_dir)) { diff --git a/ndhc/options.c b/ndhc/options.c index ea538ed..e6d83e8 100644 --- a/ndhc/options.c +++ b/ndhc/options.c @@ -8,9 +8,11 @@ #include #include -#include "log.h" #include "options.h" +#include "log.h" +#include "malloc.h" + /* supported options are easily added here */ struct dhcp_option options[] = { /* name[10] flags code */ @@ -56,6 +58,55 @@ int option_lengths[] = { [OPTION_S32] = 4 }; +size_t sizeof_option(unsigned char code, size_t datalen) +{ + if (code == DHCP_PADDING || code == DHCP_END) + return 1; + return 2 + datalen; +} + +// optdata can be NULL +size_t set_option(unsigned char *buf, size_t buflen, unsigned char code, + unsigned char *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; +} + +unsigned char *alloc_option(unsigned char code, unsigned char *optdata, + size_t datalen) +{ + unsigned char *ret; + size_t len = sizeof_option(code, datalen); + ret = xmalloc(len); + set_option(ret, len, code, optdata, datalen); + return ret; +} + +// This is tricky -- the data must be prefixed by one byte indicating the +// type of ARP MAC address (1 for ethernet) or 0 for a purely symbolic +// identifier. +unsigned char *alloc_dhcp_client_id_option(unsigned char type, + unsigned char *idstr, size_t idstrlen) +{ + unsigned char data[idstrlen + 1]; + data[0] = type; + memcpy(data + 1, idstr, idstrlen); + return alloc_option(DHCP_CLIENT_ID, data, sizeof data); +} /* Get an option with bounds checking (warning, result is not aligned) */ uint8_t* get_option(struct dhcpMessage *packet, int code) @@ -161,6 +212,7 @@ int add_simple_option(unsigned char *optionptr, unsigned char code, length = option_lengths[options[i].flags & TYPE_MASK]; } + log_line("aso(): code=0x%02x length=0x%02x", code, length); option[OPT_CODE] = code; option[OPT_LEN] = (unsigned char)length; diff --git a/ndhc/options.h b/ndhc/options.h index 92da936..6af6dda 100644 --- a/ndhc/options.h +++ b/ndhc/options.h @@ -88,6 +88,15 @@ struct option_set { extern struct dhcp_option options[]; extern int option_lengths[]; +size_t sizeof_option(unsigned char code, size_t datalen); +size_t set_option(unsigned char *buf, size_t buflen, unsigned char code, + unsigned char *optdata, size_t datalen); +unsigned char *alloc_option(unsigned char code, unsigned char *optdata, + size_t datalen); + +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); int end_option(uint8_t *optionptr); int add_option_string(unsigned char *optionptr, unsigned char *string);