Make the various functions in options.c that take a pointer to an options
buffer and length instead take a pointer to a struct dhcpmsg. This argument list choice implicitly gives safe length checks and is simpler. Remove DHCP_OPTIONS_LENGTH. Fold set_option() into alloc_option(). Make some more functions in options.[ch] static.
This commit is contained in:
parent
63d9763345
commit
55f24fd2a3
@ -120,41 +120,28 @@ int option_valid_list(uint8_t code)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t sizeof_option(uint8_t code, size_t datalen)
|
static size_t sizeof_option(uint8_t code, size_t datalen)
|
||||||
{
|
{
|
||||||
if (code == DHCP_PADDING || code == DHCP_END)
|
if (code == DHCP_PADDING || code == DHCP_END)
|
||||||
return 1;
|
return 1;
|
||||||
return 2 + datalen;
|
return 2 + datalen;
|
||||||
}
|
}
|
||||||
|
|
||||||
// optdata can be NULL
|
uint8_t *alloc_option(uint8_t code, uint8_t *optdata, size_t datalen)
|
||||||
size_t set_option(uint8_t *buf, size_t buflen, uint8_t code, uint8_t *optdata,
|
|
||||||
size_t datalen)
|
|
||||||
{
|
{
|
||||||
|
uint8_t *buf;
|
||||||
|
size_t len = sizeof_option(code, datalen);
|
||||||
|
buf = xmalloc(len);
|
||||||
if (!optdata)
|
if (!optdata)
|
||||||
datalen = 0;
|
datalen = 0;
|
||||||
if (code == DHCP_PADDING || code == DHCP_END) {
|
if ((code == DHCP_PADDING || code == DHCP_END) && len >= 1) {
|
||||||
if (buflen < 1)
|
|
||||||
return 0;
|
|
||||||
buf[0] = code;
|
buf[0] = code;
|
||||||
return 1;
|
} else if (datalen <= 255 && len >= 2 + datalen) {
|
||||||
}
|
|
||||||
|
|
||||||
if (datalen > 255 || buflen < 2 + datalen)
|
|
||||||
return 0;
|
|
||||||
buf[0] = code;
|
buf[0] = code;
|
||||||
buf[1] = datalen;
|
buf[1] = datalen;
|
||||||
memcpy(buf + 2, optdata, datalen);
|
memcpy(buf + 2, optdata, datalen);
|
||||||
return 2 + datalen;
|
|
||||||
}
|
}
|
||||||
|
return buf;
|
||||||
uint8_t *alloc_option(uint8_t code, uint8_t *optdata, size_t datalen)
|
|
||||||
{
|
|
||||||
uint8_t *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
|
// This is tricky -- the data must be prefixed by one byte indicating the
|
||||||
@ -249,16 +236,16 @@ uint8_t *get_option_data(struct dhcpmsg *packet, int code, ssize_t *optlen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* return the position of the 'end' option */
|
/* return the position of the 'end' option */
|
||||||
ssize_t get_end_option_idx(uint8_t *optbuf, size_t bufsize)
|
ssize_t get_end_option_idx(struct dhcpmsg *packet)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < bufsize; ++i) {
|
for (i = 0; i < sizeof packet->options; ++i) {
|
||||||
if (optbuf[i] == DHCP_END)
|
if (packet->options[i] == DHCP_END)
|
||||||
return i;
|
return i;
|
||||||
if (optbuf[i] == DHCP_PADDING)
|
if (packet->options[i] == DHCP_PADDING)
|
||||||
continue;
|
continue;
|
||||||
if (optbuf[i] != DHCP_PADDING)
|
if (packet->options[i] != DHCP_PADDING)
|
||||||
i += optbuf[i+1] + 1;
|
i += packet->options[i+1] + 1;
|
||||||
}
|
}
|
||||||
log_warning("get_end_option_idx(): did not find DHCP_END marker");
|
log_warning("get_end_option_idx(): did not find DHCP_END marker");
|
||||||
return -1;
|
return -1;
|
||||||
@ -266,9 +253,9 @@ ssize_t get_end_option_idx(uint8_t *optbuf, size_t bufsize)
|
|||||||
|
|
||||||
/* add an option string to the options (an option string contains an option
|
/* add an option string to the options (an option string contains an option
|
||||||
* code, length, then data) */
|
* code, length, then data) */
|
||||||
size_t add_option_string(uint8_t *optbuf, size_t buflen, uint8_t *optstr)
|
size_t add_option_string(struct dhcpmsg *packet, uint8_t *optstr)
|
||||||
{
|
{
|
||||||
size_t end = get_end_option_idx(optbuf, buflen);
|
size_t end = get_end_option_idx(packet);
|
||||||
size_t datalen = optstr[1];
|
size_t datalen = optstr[1];
|
||||||
|
|
||||||
if (end == -1) {
|
if (end == -1) {
|
||||||
@ -276,17 +263,16 @@ size_t add_option_string(uint8_t *optbuf, size_t buflen, uint8_t *optstr)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* end position + optstr length + option code/length + end option */
|
/* end position + optstr length + option code/length + end option */
|
||||||
if (end + datalen + 2 + 1 >= buflen) {
|
if (end + datalen + 2 + 1 >= sizeof packet->options) {
|
||||||
log_warning("add_option_string: No space for option 0x%02x", optstr[0]);
|
log_warning("add_option_string: No space for option 0x%02x", optstr[0]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
memcpy(optbuf + end, optstr, datalen + 2);
|
memcpy(packet->options + end, optstr, datalen + 2);
|
||||||
optbuf[end + datalen + 2] = DHCP_END;
|
packet->options[end + datalen + 2] = DHCP_END;
|
||||||
return datalen + 2;
|
return datalen + 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t add_u32_option(uint8_t *optbuf, size_t buflen, uint8_t code,
|
size_t add_u32_option(struct dhcpmsg *packet, uint8_t code, uint32_t data)
|
||||||
uint32_t data)
|
|
||||||
{
|
{
|
||||||
int length = 0;
|
int length = 0;
|
||||||
uint8_t option[6];
|
uint8_t option[6];
|
||||||
@ -311,11 +297,11 @@ size_t add_u32_option(uint8_t *optbuf, size_t buflen, uint8_t code,
|
|||||||
uint32_t t = (uint32_t)data;
|
uint32_t t = (uint32_t)data;
|
||||||
memcpy(option + 2, &t, 4);
|
memcpy(option + 2, &t, 4);
|
||||||
}
|
}
|
||||||
return add_option_string(optbuf, buflen, option);
|
return add_option_string(packet, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add a paramater request list for stubborn DHCP servers */
|
/* Add a paramater request list for stubborn DHCP servers */
|
||||||
void add_option_request_list(uint8_t *optbuf, size_t buflen)
|
void add_option_request_list(struct dhcpmsg *packet)
|
||||||
{
|
{
|
||||||
int i, j = 0;
|
int i, j = 0;
|
||||||
uint8_t reqdata[256];
|
uint8_t reqdata[256];
|
||||||
@ -326,5 +312,5 @@ void add_option_request_list(uint8_t *optbuf, size_t buflen)
|
|||||||
reqdata[j++] = options[i].code;
|
reqdata[j++] = options[i].code;
|
||||||
}
|
}
|
||||||
reqdata[1] = j - 2;
|
reqdata[1] = j - 2;
|
||||||
add_option_string(optbuf, buflen, reqdata);
|
add_option_string(packet, reqdata);
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,6 @@
|
|||||||
|
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
|
|
||||||
#define DHCP_OPTIONS_BUFSIZE 308
|
|
||||||
|
|
||||||
/* DHCP option codes (partial list) */
|
/* DHCP option codes (partial list) */
|
||||||
#define DHCP_PADDING 0x00
|
#define DHCP_PADDING 0x00
|
||||||
#define DHCP_SUBNET 0x01
|
#define DHCP_SUBNET 0x01
|
||||||
@ -84,19 +82,15 @@ const char *option_name(uint8_t code);
|
|||||||
enum option_type option_type(uint8_t code);
|
enum option_type option_type(uint8_t code);
|
||||||
uint8_t option_length(uint8_t code);
|
uint8_t option_length(uint8_t code);
|
||||||
int option_valid_list(uint8_t code);
|
int option_valid_list(uint8_t code);
|
||||||
size_t sizeof_option(uint8_t code, size_t datalen);
|
|
||||||
size_t set_option(uint8_t *buf, size_t buflen, uint8_t code, uint8_t *optdata,
|
|
||||||
size_t datalen);
|
|
||||||
uint8_t *alloc_option(uint8_t code, uint8_t *optdata, size_t datalen);
|
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,
|
uint8_t *alloc_dhcp_client_id_option(uint8_t type, uint8_t *idstr,
|
||||||
size_t idstrlen);
|
size_t idstrlen);
|
||||||
|
|
||||||
uint8_t *get_option_data(struct dhcpmsg *packet, int code, ssize_t *optlen);
|
uint8_t *get_option_data(struct dhcpmsg *packet, int code, ssize_t *optlen);
|
||||||
ssize_t get_end_option_idx(uint8_t *optbuf, size_t bufsize);
|
ssize_t get_end_option_idx(struct dhcpmsg *packet);
|
||||||
size_t add_option_string(uint8_t *optbuf, size_t buflen, uint8_t *optstr);
|
size_t add_option_string(struct dhcpmsg *packet, uint8_t *optstr);
|
||||||
size_t add_u32_option(uint8_t *optbuf, size_t buflen, uint8_t code,
|
size_t add_u32_option(struct dhcpmsg *packet, uint8_t code, uint32_t data);
|
||||||
uint32_t data);
|
void add_option_request_list(struct dhcpmsg *packet);
|
||||||
void add_option_request_list(uint8_t *optbuf, size_t buflen);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -358,12 +358,12 @@ static int send_dhcp_raw(struct dhcpmsg *payload)
|
|||||||
|
|
||||||
// Send packets that are as short as possible, since some servers are buggy
|
// Send packets that are as short as possible, since some servers are buggy
|
||||||
// and drop packets that are longer than 562 bytes.
|
// and drop packets that are longer than 562 bytes.
|
||||||
ssize_t endloc = get_end_option_idx(payload->options, DHCP_OPTIONS_BUFSIZE);
|
ssize_t endloc = get_end_option_idx(payload);
|
||||||
if (endloc < 0) {
|
if (endloc < 0) {
|
||||||
log_error("send_dhcp_raw: attempt to send packet with no DHCP_END");
|
log_error("send_dhcp_raw: attempt to send packet with no DHCP_END");
|
||||||
goto out_fd;
|
goto out_fd;
|
||||||
}
|
}
|
||||||
size_t padding = DHCP_OPTIONS_BUFSIZE - 1 - endloc;
|
size_t padding = sizeof payload->options - 1 - endloc;
|
||||||
size_t iud_len = sizeof(struct ip_udp_dhcp_packet) - padding;
|
size_t iud_len = sizeof(struct ip_udp_dhcp_packet) - padding;
|
||||||
size_t ud_len = sizeof(struct udp_dhcp_packet) - padding;
|
size_t ud_len = sizeof(struct udp_dhcp_packet) - padding;
|
||||||
|
|
||||||
@ -461,13 +461,12 @@ static int send_dhcp_cooked(struct dhcpmsg *payload, uint32_t source_ip,
|
|||||||
goto out_fd;
|
goto out_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t endloc = get_end_option_idx(payload->options,
|
ssize_t endloc = get_end_option_idx(payload);
|
||||||
DHCP_OPTIONS_BUFSIZE);
|
|
||||||
if (endloc < 0) {
|
if (endloc < 0) {
|
||||||
log_error("send_dhcp_cooked: attempt to send packet with no DHCP_END");
|
log_error("send_dhcp_cooked: attempt to send packet with no DHCP_END");
|
||||||
goto out_fd;
|
goto out_fd;
|
||||||
}
|
}
|
||||||
size_t payload_len = sizeof *payload - DHCP_OPTIONS_BUFSIZE - 1 - endloc;
|
size_t payload_len = sizeof *payload - sizeof payload->options - 1 - endloc;
|
||||||
result = safe_write(fd, (const char *)payload, payload_len);
|
result = safe_write(fd, (const char *)payload, payload_len);
|
||||||
if (result == -1)
|
if (result == -1)
|
||||||
log_error("send_dhcp_cooked: write failed: %s", strerror(errno));
|
log_error("send_dhcp_cooked: write failed: %s", strerror(errno));
|
||||||
@ -674,21 +673,17 @@ static struct dhcpmsg init_packet(char type, uint32_t xid)
|
|||||||
.options[0] = DHCP_END,
|
.options[0] = DHCP_END,
|
||||||
.xid = xid,
|
.xid = xid,
|
||||||
};
|
};
|
||||||
add_u32_option(packet.options, DHCP_OPTIONS_BUFSIZE, DHCP_MESSAGE_TYPE,
|
add_u32_option(&packet, DHCP_MESSAGE_TYPE, type);
|
||||||
type);
|
|
||||||
memcpy(packet.chaddr, client_config.arp, 6);
|
memcpy(packet.chaddr, client_config.arp, 6);
|
||||||
add_option_string(packet.options, DHCP_OPTIONS_BUFSIZE,
|
add_option_string(&packet, client_config.clientid);
|
||||||
client_config.clientid);
|
|
||||||
if (client_config.hostname)
|
if (client_config.hostname)
|
||||||
add_option_string(packet.options, DHCP_OPTIONS_BUFSIZE,
|
add_option_string(&packet, client_config.hostname);
|
||||||
client_config.hostname);
|
|
||||||
struct vendor {
|
struct vendor {
|
||||||
char vendor;
|
char vendor;
|
||||||
char length;
|
char length;
|
||||||
char str[sizeof "ndhc"];
|
char str[sizeof "ndhc"];
|
||||||
} vendor_id = { DHCP_VENDOR, sizeof "ndhc" - 1, "ndhc"};
|
} vendor_id = { DHCP_VENDOR, sizeof "ndhc" - 1, "ndhc"};
|
||||||
add_option_string(packet.options, DHCP_OPTIONS_BUFSIZE,
|
add_option_string(&packet, (uint8_t *)&vendor_id);
|
||||||
(uint8_t *)&vendor_id);
|
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -698,13 +693,11 @@ int send_discover(uint32_t xid, uint32_t requested)
|
|||||||
{
|
{
|
||||||
struct dhcpmsg packet = init_packet(DHCPDISCOVER, xid);
|
struct dhcpmsg packet = init_packet(DHCPDISCOVER, xid);
|
||||||
if (requested)
|
if (requested)
|
||||||
add_u32_option(packet.options, DHCP_OPTIONS_BUFSIZE, DHCP_REQUESTED_IP,
|
add_u32_option(&packet, DHCP_REQUESTED_IP, requested);
|
||||||
requested);
|
|
||||||
|
|
||||||
/* Request a RFC-specified max size to work around buggy servers. */
|
/* Request a RFC-specified max size to work around buggy servers. */
|
||||||
add_u32_option(packet.options, DHCP_OPTIONS_BUFSIZE,
|
add_u32_option(&packet, DHCP_MAX_SIZE, htons(576));
|
||||||
DHCP_MAX_SIZE, htons(576));
|
add_option_request_list(&packet);
|
||||||
add_option_request_list(packet.options, DHCP_OPTIONS_BUFSIZE);
|
|
||||||
log_line("Sending discover...");
|
log_line("Sending discover...");
|
||||||
return send_dhcp_raw(&packet);
|
return send_dhcp_raw(&packet);
|
||||||
}
|
}
|
||||||
@ -715,12 +708,10 @@ int send_selecting(uint32_t xid, uint32_t server, uint32_t requested)
|
|||||||
struct dhcpmsg packet = init_packet(DHCPREQUEST, xid);
|
struct dhcpmsg packet = init_packet(DHCPREQUEST, xid);
|
||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
|
|
||||||
add_u32_option(packet.options, DHCP_OPTIONS_BUFSIZE, DHCP_REQUESTED_IP,
|
add_u32_option(&packet, DHCP_REQUESTED_IP, requested);
|
||||||
requested);
|
add_u32_option(&packet, DHCP_SERVER_ID, server);
|
||||||
add_u32_option(packet.options, DHCP_OPTIONS_BUFSIZE, DHCP_SERVER_ID,
|
|
||||||
server);
|
|
||||||
|
|
||||||
add_option_request_list(packet.options, DHCP_OPTIONS_BUFSIZE);
|
add_option_request_list(&packet);
|
||||||
addr.s_addr = requested;
|
addr.s_addr = requested;
|
||||||
log_line("Sending select for %s...", inet_ntoa(addr));
|
log_line("Sending select for %s...", inet_ntoa(addr));
|
||||||
return send_dhcp_raw(&packet);
|
return send_dhcp_raw(&packet);
|
||||||
@ -732,7 +723,7 @@ int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
|
|||||||
struct dhcpmsg packet = init_packet(DHCPREQUEST, xid);
|
struct dhcpmsg packet = init_packet(DHCPREQUEST, xid);
|
||||||
packet.ciaddr = ciaddr;
|
packet.ciaddr = ciaddr;
|
||||||
|
|
||||||
add_option_request_list(packet.options, DHCP_OPTIONS_BUFSIZE);
|
add_option_request_list(&packet);
|
||||||
log_line("Sending renew...");
|
log_line("Sending renew...");
|
||||||
if (server)
|
if (server)
|
||||||
return send_dhcp_cooked(&packet, ciaddr, server);
|
return send_dhcp_cooked(&packet, ciaddr, server);
|
||||||
@ -746,9 +737,8 @@ int send_decline(uint32_t xid, uint32_t server, uint32_t requested)
|
|||||||
struct dhcpmsg packet = init_packet(DHCPDECLINE, xid);
|
struct dhcpmsg packet = init_packet(DHCPDECLINE, xid);
|
||||||
|
|
||||||
/* DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP */
|
/* DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP */
|
||||||
add_u32_option(packet.options, DHCP_OPTIONS_BUFSIZE, DHCP_REQUESTED_IP,
|
add_u32_option(&packet, DHCP_REQUESTED_IP, requested);
|
||||||
requested);
|
add_u32_option(&packet, DHCP_SERVER_ID, server);
|
||||||
add_u32_option(packet.options, DHCP_OPTIONS_BUFSIZE, DHCP_SERVER_ID, server);
|
|
||||||
|
|
||||||
log_line("Sending decline...");
|
log_line("Sending decline...");
|
||||||
return send_dhcp_raw(&packet);
|
return send_dhcp_raw(&packet);
|
||||||
@ -760,9 +750,8 @@ int send_release(uint32_t server, uint32_t ciaddr)
|
|||||||
struct dhcpmsg packet = init_packet(DHCPRELEASE, random_xid());
|
struct dhcpmsg packet = init_packet(DHCPRELEASE, random_xid());
|
||||||
packet.ciaddr = ciaddr;
|
packet.ciaddr = ciaddr;
|
||||||
|
|
||||||
add_u32_option(packet.options, DHCP_OPTIONS_BUFSIZE, DHCP_REQUESTED_IP,
|
add_u32_option(&packet, DHCP_REQUESTED_IP, ciaddr);
|
||||||
ciaddr);
|
add_u32_option(&packet, DHCP_SERVER_ID, server);
|
||||||
add_u32_option(packet.options, DHCP_OPTIONS_BUFSIZE, DHCP_SERVER_ID, server);
|
|
||||||
|
|
||||||
log_line("Sending release...");
|
log_line("Sending release...");
|
||||||
return send_dhcp_cooked(&packet, ciaddr, server);
|
return send_dhcp_cooked(&packet, ciaddr, server);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user