Don't use malloc in ndhc. The only place it was used is in the options code.

Allow the user to specify the vendor identification option value using the
-V switch.  The default value is still "ndhc".
This commit is contained in:
Nicholas J. Kain 2011-07-02 03:48:08 -04:00
parent 7104b56ab9
commit d9571c62cf
5 changed files with 96 additions and 120 deletions

View File

@ -40,15 +40,16 @@ struct client_state_t {
};
struct client_config_t {
char foreground; /* Do not fork */
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 *interface; /* The name of the interface to use */
uint8_t *clientid; /* Optional client id to use (unterminated) */
uint8_t *hostname; /* Optional hostname to use (unterminated) */
int ifindex; /* Index number of the interface to use */
uint8_t arp[6]; /* Our arp address */
char foreground; // Do not fork
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 *interface; // The name of the interface to use
char clientid[64]; // Optional client id to use
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
uint8_t arp[6]; // Our arp address
};
extern struct client_config_t client_config;

View File

@ -54,7 +54,6 @@
#include "cap.h"
#include "strl.h"
#include "pidfile.h"
#include "malloc.h"
#include "io.h"
#define VERSION "1.0"
@ -177,7 +176,7 @@ static void do_work(void)
int main(int argc, char **argv)
{
char chroot_dir[MAX_PATH_LENGTH] = "";
int c, len;
int c;
struct passwd *pwd;
uid_t uid = 0;
gid_t gid = 0;
@ -194,6 +193,7 @@ int main(int argc, char **argv)
{"quit", no_argument, 0, 'q'},
{"request", required_argument, 0, 'r'},
{"version", no_argument, 0, 'v'},
{"vendorid", required_argument, 0, 'V'},
{"user", required_argument, 0, 'u'},
{"chroot", required_argument, 0, 'C'},
{"help", no_argument, 0, '?'},
@ -203,17 +203,14 @@ int main(int argc, char **argv)
/* get options */
while (1) {
int option_index = 0;
c = getopt_long(argc, argv, "c:fbp:H:h:i:np:l:qr:u:C:v", arg_options,
c = getopt_long(argc, argv, "c:fbp:H:h:i:np:l:qr:u:C:vV:", arg_options,
&option_index);
if (c == -1) break;
switch (c) {
case 'c':
len = strlen(optarg) > 64 ? 64 : strlen(optarg);
if (client_config.clientid)
free(client_config.clientid);
client_config.clientid =
alloc_dhcp_client_id_option(0, (uint8_t *)optarg, len);
strlcpy(client_config.clientid, optarg,
sizeof client_config.clientid);
break;
case 'f':
client_config.foreground = 1;
@ -231,11 +228,8 @@ int main(int argc, char **argv)
break;
case 'h':
case 'H':
len = strlen(optarg) > 64 ? 64 : strlen(optarg);
if (client_config.hostname)
free(client_config.hostname);
client_config.hostname =
alloc_option(DHCP_HOST_NAME, (uint8_t *)optarg, len);
strlcpy(client_config.hostname, optarg,
sizeof client_config.hostname);
break;
case 'i':
client_config.interface = optarg;
@ -266,6 +260,10 @@ int main(int argc, char **argv)
printf("ndhc, version " VERSION "\n\n");
exit(EXIT_SUCCESS);
break;
case 'V':
strlcpy(client_config.vendor, optarg,
sizeof client_config.vendor);
break;
default:
show_usage();
}
@ -290,11 +288,6 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE);
}
if (!client_config.clientid) {
client_config.clientid =
alloc_dhcp_client_id_option(1, client_config.arp, 6);
}
open_leasefile();
if (chdir(chroot_dir)) {

View File

@ -24,7 +24,6 @@
#include "options.h"
#include "log.h"
#include "malloc.h"
struct dhcp_option {
char name[10];
@ -123,35 +122,6 @@ static size_t sizeof_option(uint8_t code, size_t datalen)
return 2 + datalen;
}
uint8_t *alloc_option(uint8_t code, uint8_t *optdata, size_t datalen)
{
uint8_t *buf;
size_t len = sizeof_option(code, datalen);
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
// type of ARP MAC address (1 for ethernet) or 0 for a purely symbolic
// identifier.
uint8_t *alloc_dhcp_client_id_option(uint8_t type, uint8_t *idstr,
size_t idstrlen)
{
uint8_t data[idstrlen + 1];
data[0] = type;
memcpy(data + 1, idstr, idstrlen);
return alloc_option(DHCP_CLIENT_ID, data, sizeof data);
}
// Worker function for get_option_data(). Optlen will be set to the length
// of the option data.
static uint8_t *do_get_option_data(uint8_t *buf, ssize_t buflen, int code,
@ -248,74 +218,66 @@ ssize_t get_end_option_idx(struct dhcpmsg *packet)
// add an option string to the options (an option string contains an option
// code, length, then data)
size_t add_option_string(struct dhcpmsg *packet, uint8_t *optstr)
size_t add_option_string(struct dhcpmsg *packet, uint8_t code, char *str,
size_t slen)
{
size_t end = get_end_option_idx(packet);
size_t datalen = optstr[1];
size_t len = sizeof_option(code, slen);
if (slen > 255 || len != slen + 2) {
log_warning("add_option_string: Length checks failed.");
return 0;
}
size_t end = get_end_option_idx(packet);
if (end == -1) {
log_warning("add_option_string: Buffer has no DHCP_END marker");
return 0;
}
// end position + optstr length + option code/length + end option
if (end + datalen + 2 + 1 >= sizeof packet->options) {
log_warning("add_option_string: No space for option 0x%02x", optstr[0]);
if (end + len >= sizeof packet->options) {
log_warning("add_option_string: No space for option 0x%02x", code);
return 0;
}
memcpy(packet->options + end, optstr, datalen + 2);
packet->options[end + datalen + 2] = DHCP_END;
return datalen + 2;
packet->options[end] = code;
packet->options[end+1] = slen;
memcpy(packet->options + end + 2, str, slen);
packet->options[end+len] = DHCP_END;
return len;
}
// XXX: length=1 and length=2 will fail if data is big-endian.
size_t add_u32_option(struct dhcpmsg *packet, uint8_t code, uint32_t data)
{
int length = 0;
uint8_t option[6];
length = option_length(code);
option[0] = code;
option[1] = length;
size_t length = option_length(code);
if (!length) {
log_warning("add_u32_option: option code 0x%02x has 0 length", code);
return 0;
}
if (length == 1) {
uint8_t t = (uint8_t)data;
memcpy(option + 2, &t, 1);
} else if (length == 2) {
uint16_t t = (uint16_t)data;
memcpy(option + 2, &t, 2);
} else if (length == 4) {
uint32_t t = (uint32_t)data;
memcpy(option + 2, &t, 4);
size_t end = get_end_option_idx(packet);
if (end == -1) {
log_warning("add_u32_option: Buffer has no DHCP_END marker");
return 0;
}
return add_option_string(packet, option);
if (end + 2 + length >= sizeof packet->options) {
log_warning("add_u32_option: No space for option 0x%02x", code);
return 0;
}
packet->options[end] = code;
packet->options[end+1] = length;
// XXX: this is broken: it's alignment-safe, but the endianness is wrong
memcpy(packet->options + end + 2, &data, length);
packet->options[end+length+2] = DHCP_END;
return length+2;
}
// Add a paramater request list for stubborn DHCP servers
void add_option_request_list(struct dhcpmsg *packet)
size_t add_option_request_list(struct dhcpmsg *packet)
{
uint8_t reqdata[256];
reqdata[0] = DHCP_PARAM_REQ;
int j = 2;
size_t j = 0;
for (int i = 0; options[i].code; i++) {
if (options[i].type & OPTION_REQ)
reqdata[j++] = options[i].code;
}
reqdata[1] = j - 2;
add_option_string(packet, reqdata);
}
void add_option_vendor_string(struct dhcpmsg *packet)
{
struct vendor {
char vendor;
char length;
char str[sizeof "ndhc"];
} vendor_id = { DHCP_VENDOR, sizeof "ndhc" - 1, "ndhc"};
add_option_string(packet, (uint8_t *)&vendor_id);
return add_option_string(packet, DHCP_PARAM_REQ, (char *)reqdata, j);
}

View File

@ -82,16 +82,12 @@ 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);
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(struct dhcpmsg *packet);
size_t add_option_string(struct dhcpmsg *packet, uint8_t *optstr);
size_t add_option_string(struct dhcpmsg *packet, uint8_t code, char *str,
size_t slen);
size_t add_u32_option(struct dhcpmsg *packet, uint8_t code, uint32_t data);
void add_option_request_list(struct dhcpmsg *packet);
void add_option_vendor_string(struct dhcpmsg *packet);
size_t add_option_request_list(struct dhcpmsg *packet);
#endif

View File

@ -533,6 +533,31 @@ void handle_packet(struct client_state_t *cs)
packet_action(cs, &packet, message);
}
static void add_option_vendor(struct dhcpmsg *packet)
{
size_t len = strlen(client_config.vendor);
if (len)
add_option_string(packet, DHCP_VENDOR, client_config.vendor, len);
else
add_option_string(packet, DHCP_VENDOR, "ndhc", sizeof "ndhc" - 1);
}
static void add_option_clientid(struct dhcpmsg *packet)
{
size_t len = strlen(client_config.clientid);
if (len)
add_option_string(packet, DHCP_CLIENT_ID, client_config.clientid, len);
else
add_option_string(packet, DHCP_CLIENT_ID, (char *)client_config.arp, 6);
}
static void add_option_hostname(struct dhcpmsg *packet)
{
size_t len = strlen(client_config.hostname);
if (len)
add_option_string(packet, DHCP_HOST_NAME, client_config.hostname, len);
}
// Initialize a DHCP client packet that will be sent to a server
static struct dhcpmsg init_packet(char type, uint32_t xid)
{
@ -546,9 +571,8 @@ static struct dhcpmsg init_packet(char type, uint32_t xid)
};
add_u32_option(&packet, DHCP_MESSAGE_TYPE, type);
memcpy(packet.chaddr, client_config.arp, 6);
add_option_string(&packet, client_config.clientid);
if (client_config.hostname)
add_option_string(&packet, client_config.hostname);
add_option_clientid(&packet);
add_option_hostname(&packet);
return packet;
}
@ -560,7 +584,7 @@ int send_discover(struct client_state_t *cs)
add_u32_option(&packet, DHCP_MAX_SIZE,
htons(sizeof(struct ip_udp_dhcp_packet)));
add_option_request_list(&packet);
add_option_vendor_string(&packet);
add_option_vendor(&packet);
log_line("Sending discover...");
return send_dhcp_raw(&packet);
}
@ -573,7 +597,7 @@ int send_selecting(struct client_state_t *cs)
add_u32_option(&packet, DHCP_MAX_SIZE,
htons(sizeof(struct ip_udp_dhcp_packet)));
add_option_request_list(&packet);
add_option_vendor_string(&packet);
add_option_vendor(&packet);
log_line("Sending select for %s...",
inet_ntoa((struct in_addr){.s_addr = cs->clientAddr}));
return send_dhcp_raw(&packet);
@ -586,7 +610,7 @@ int send_renew(struct client_state_t *cs)
add_u32_option(&packet, DHCP_MAX_SIZE,
htons(sizeof(struct ip_udp_dhcp_packet)));
add_option_request_list(&packet);
add_option_vendor_string(&packet);
add_option_vendor(&packet);
log_line("Sending renew...");
return send_dhcp_cooked(&packet, cs->clientAddr, cs->serverAddr);
}
@ -599,7 +623,7 @@ int send_rebind(struct client_state_t *cs)
add_u32_option(&packet, DHCP_MAX_SIZE,
htons(sizeof(struct ip_udp_dhcp_packet)));
add_option_request_list(&packet);
add_option_vendor_string(&packet);
add_option_vendor(&packet);
log_line("Sending rebind...");
return send_dhcp_raw(&packet);
}