diff --git a/ndhc/dhcp.c b/ndhc/dhcp.c index 9e70c5b..be1da05 100644 --- a/ndhc/dhcp.c +++ b/ndhc/dhcp.c @@ -527,6 +527,15 @@ static int validate_dhcp_packet(struct client_state_t *cs, size_t len, log_line("Packet does not specify a DHCP message type. Ignoring."); return 0; } + char clientid[MAX_DOPT_SIZE]; + size_t cidlen = get_option_clientid(packet, clientid, MAX_DOPT_SIZE); + if (cidlen == 0) + return 1; + if (memcmp(client_config.clientid, clientid, + min_size_t(cidlen, client_config.clientid_len))) { + log_line("Packet clientid does not match our clientid. Ignoring."); + return 0; + } return 1; } @@ -568,7 +577,8 @@ static struct dhcpmsg init_packet(char type, uint32_t xid) }; add_option_msgtype(&packet, type); memcpy(packet.chaddr, client_config.arp, 6); - add_option_clientid(&packet); + add_option_clientid(&packet, client_config.clientid, + client_config.clientid_len); return packet; } diff --git a/ndhc/ndhc.c b/ndhc/ndhc.c index fa714a5..eb6f0dd 100644 --- a/ndhc/ndhc.c +++ b/ndhc/ndhc.c @@ -88,6 +88,7 @@ struct client_state_t cs = { struct client_config_t client_config = { .interface = "eth0", .arp = "\0\0\0\0\0\0", + .clientid_len = 0, }; static void show_usage(void) @@ -202,17 +203,24 @@ static int is_string_hwaddr(char *str, size_t slen) return 0; } -static int get_clientid_mac_string(char *str, size_t slen) +static int get_clientid_string(char *str, size_t slen) { - if (!is_string_hwaddr(str, slen)) + if (!slen) + return -1; + if (!is_string_hwaddr(str, slen)) { + client_config.clientid[0] = 0; + memcpy(&client_config.clientid + 1, str, + min_size_t(slen, sizeof client_config.clientid - 1)); + client_config.clientid_len = slen + 1; return 0; - client_config.clientid[0] = strtol(str, NULL, 16); - client_config.clientid[1] = strtol(str+3, NULL, 16); - client_config.clientid[2] = strtol(str+6, NULL, 16); - client_config.clientid[3] = strtol(str+9, NULL, 16); - client_config.clientid[4] = strtol(str+12, NULL, 16); - client_config.clientid[5] = strtol(str+15, NULL, 16); - client_config.clientid[6] = '\0'; + } + + uint8_t mac[6]; + for (size_t i = 0; i < sizeof mac; ++i) + mac[i] = strtol(str+i*3, NULL, 16); + client_config.clientid[0] = 1; // Ethernet MAC type + memcpy(&client_config.clientid + 1, mac, sizeof mac); + client_config.clientid_len = 7; return 1; } @@ -427,11 +435,7 @@ int main(int argc, char **argv) switch (c) { case 'c': - if (!get_clientid_mac_string(optarg, strlen(optarg))) - strnkcpy(client_config.clientid, optarg, - sizeof client_config.clientid); - else - client_config.clientid_mac = 1; + get_clientid_string(optarg, strlen(optarg)); break; case 'f': client_config.foreground = 1; diff --git a/ndhc/ndhc.h b/ndhc/ndhc.h index 46bad76..0fcf3a1 100644 --- a/ndhc/ndhc.h +++ b/ndhc/ndhc.h @@ -55,9 +55,9 @@ struct client_config_t { char quit_after_lease; // Quit after obtaining lease char abort_if_no_lease; // Abort if no lease char background_if_no_lease; // Fork to background if no lease - char clientid_mac; // If true, then the clientid is a MAC addr char interface[IFNAMSIZ]; // The name of the interface to use char clientid[64]; // Optional client id to use + uint8_t clientid_len; // Length of the clientid char hostname[64]; // Optional hostname to use char vendor[64]; // Vendor identification that will be sent int ifindex; // Index number of the interface to use diff --git a/ndhc/netlink.c b/ndhc/netlink.c index ab81215..a875c63 100644 --- a/ndhc/netlink.c +++ b/ndhc/netlink.c @@ -121,6 +121,11 @@ static int get_if_index_and_mac(const struct nlmsghdr *nlh, client_config.interface, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); memcpy(client_config.arp, mac, 6); + if (client_config.clientid_len < 2) { + client_config.clientid[0] = 1; // Ethernet MAC type + memcpy(&client_config.clientid + 1, mac, 6); + client_config.clientid_len = 7; + } return 1; } return 0; diff --git a/ndhc/options.c b/ndhc/options.c index b65aaa6..adfeedf 100644 --- a/ndhc/options.c +++ b/ndhc/options.c @@ -272,6 +272,11 @@ void add_option_serverid(struct dhcpmsg *packet, uint32_t sid) add_u32_option(packet, DCODE_SERVER_ID, sid); } +void add_option_clientid(struct dhcpmsg *packet, char *clientid, size_t clen) +{ + add_option_string(packet, DCODE_CLIENT_ID, clientid, clen); +} + #ifndef NDHS_BUILD void add_option_maxsize(struct dhcpmsg *packet) { @@ -288,36 +293,12 @@ void add_option_vendor(struct dhcpmsg *packet) add_option_string(packet, DCODE_VENDOR, "ndhc", sizeof "ndhc" - 1); } -void add_option_clientid(struct dhcpmsg *packet) -{ - char buf[sizeof client_config.clientid + 1]; - size_t len = 6; - buf[0] = 1; // Ethernet MAC - if (!client_config.clientid_mac) { - size_t slen = strlen(client_config.clientid); - if (!slen) { - memcpy(buf+1, client_config.arp, len); - } else { - buf[0] = 0; // Not a hardware address - len = slen; - memcpy(buf+1, client_config.clientid, slen); - } - } else - memcpy(buf+1, client_config.clientid, len); - add_option_string(packet, DCODE_CLIENT_ID, buf, len+1); -} - void add_option_hostname(struct dhcpmsg *packet) { size_t len = strlen(client_config.hostname); if (len) add_option_string(packet, DCODE_HOSTNAME, client_config.hostname, len); } -#else -void add_option_clientid(struct dhcpmsg *packet, char *clientid, size_t clen) -{ - add_option_string(packet, DCODE_CLIENT_ID, clientid, clen); -} #endif uint32_t get_option_router(struct dhcpmsg *packet) @@ -368,3 +349,13 @@ uint32_t get_option_leasetime(struct dhcpmsg *packet) } return ret; } + +// Returned buffer is not nul-terminated. +size_t get_option_clientid(struct dhcpmsg *packet, char *cbuf, size_t clen) +{ + if (clen < 1) + return 0; + ssize_t ol = get_dhcp_opt(packet, DCODE_CLIENT_ID, + (uint8_t *)cbuf, clen); + return ol > 0 ? ol : 0; +} diff --git a/ndhc/options.h b/ndhc/options.h index 1ec4ef0..f6d204e 100644 --- a/ndhc/options.h +++ b/ndhc/options.h @@ -71,17 +71,16 @@ void add_option_broadcast(struct dhcpmsg *packet, uint32_t bc); void add_option_msgtype(struct dhcpmsg *packet, uint8_t type); void add_option_reqip(struct dhcpmsg *packet, uint32_t ip); void add_option_serverid(struct dhcpmsg *packet, uint32_t sid); +void add_option_clientid(struct dhcpmsg *packet, char *clientid, size_t clen); #ifndef NDHS_BUILD void add_option_maxsize(struct dhcpmsg *packet); void add_option_vendor(struct dhcpmsg *packet); -void add_option_clientid(struct dhcpmsg *packet); void add_option_hostname(struct dhcpmsg *packet); -#else -void add_option_clientid(struct dhcpmsg *packet, char *clientid, size_t clen); #endif uint32_t get_option_router(struct dhcpmsg *packet); uint8_t get_option_msgtype(struct dhcpmsg *packet); uint32_t get_option_serverid(struct dhcpmsg *packet, int *found); uint32_t get_option_leasetime(struct dhcpmsg *packet); +size_t get_option_clientid(struct dhcpmsg *packet, char *cbuf, size_t clen); #endif diff --git a/ndhc/sys.h b/ndhc/sys.h index f4e528c..cfcff81 100644 --- a/ndhc/sys.h +++ b/ndhc/sys.h @@ -38,6 +38,11 @@ static inline unsigned long long curms() return ts.tv_sec * 1000ULL + ts.tv_nsec / 1000000ULL; } +static inline size_t min_size_t(size_t a, size_t b) +{ + return a < b ? a : b; +} + void epoll_add(int epfd, int fd); void epoll_del(int epfd, int fd);