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:
parent
7104b56ab9
commit
d9571c62cf
@ -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;
|
||||
|
43
ndhc/ndhc.c
43
ndhc/ndhc.c
@ -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;
|
||||
@ -188,32 +187,30 @@ int main(int argc, char **argv)
|
||||
{"pidfile", required_argument, 0, 'p'},
|
||||
{"leasefile", required_argument, 0, 'l'},
|
||||
{"hostname", required_argument, 0, 'H'},
|
||||
{"hostname", required_argument, 0, 'h'},
|
||||
{"hostname", required_argument, 0, 'h'},
|
||||
{"interface", required_argument, 0, 'i'},
|
||||
{"now", no_argument, 0, 'n'},
|
||||
{"quit", no_argument, 0, 'q'},
|
||||
{"request", required_argument, 0, 'r'},
|
||||
{"version", no_argument, 0, 'v'},
|
||||
{"user", required_argument, 0, 'u'},
|
||||
{"chroot", required_argument, 0, 'C'},
|
||||
{"help", no_argument, 0, '?'},
|
||||
{"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, '?'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
/* 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)) {
|
||||
|
106
ndhc/options.c
106
ndhc/options.c
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user