Make ndhc RFC6842-compliant.

All this entails is that ndhc needs to check to make sure that if the remote
server sends a dhcp packet with a client identifier, the client identifier
of that packet matches the client identifier that ndhc uses to identify
itself.

If the remote server does not attach a client identifier to its dhcp packets,
then the behavior of ndhc does not change.
This commit is contained in:
Nicholas J. Kain 2014-03-18 03:13:51 -04:00
parent 3d0f46580a
commit cd269c7261
7 changed files with 57 additions and 43 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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);