Untabify options.[ch].
This commit is contained in:
parent
09613fd77a
commit
6265a0e973
326
ndhc/options.c
326
ndhc/options.c
@ -1,5 +1,5 @@
|
|||||||
/* options.c - DHCP options handling
|
/* options.c - DHCP options handling
|
||||||
* Time-stamp: <2011-03-30 16:31:50 nk>
|
* Time-stamp: <2011-03-30 16:34:41 nk>
|
||||||
*
|
*
|
||||||
* (c) 2004-2011 Nicholas J. Kain <njkain at gmail dot com>
|
* (c) 2004-2011 Nicholas J. Kain <njkain at gmail dot com>
|
||||||
*
|
*
|
||||||
@ -27,9 +27,9 @@
|
|||||||
#include "malloc.h"
|
#include "malloc.h"
|
||||||
|
|
||||||
struct dhcp_option {
|
struct dhcp_option {
|
||||||
char name[10];
|
char name[10];
|
||||||
enum option_type type;
|
enum option_type type;
|
||||||
uint8_t code;
|
uint8_t code;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Marks an option that will be sent on the parameter request list to the
|
// Marks an option that will be sent on the parameter request list to the
|
||||||
@ -81,238 +81,238 @@ enum option_type option_type(uint8_t code)
|
|||||||
static const char bad_option_name[] = "BADOPTION";
|
static const char bad_option_name[] = "BADOPTION";
|
||||||
const char *option_name(uint8_t code)
|
const char *option_name(uint8_t code)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; options[i].code; ++i)
|
for (i = 0; options[i].code; ++i)
|
||||||
if (options[i].code == code)
|
if (options[i].code == code)
|
||||||
return options[i].name;
|
return options[i].name;
|
||||||
return bad_option_name;
|
return bad_option_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t option_type_length(enum option_type type)
|
static uint8_t option_type_length(enum option_type type)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case OPTION_IP: return 4;
|
case OPTION_IP: return 4;
|
||||||
case OPTION_U8: return 1;
|
case OPTION_U8: return 1;
|
||||||
case OPTION_U16: return 2;
|
case OPTION_U16: return 2;
|
||||||
case OPTION_S16: return 2;
|
case OPTION_S16: return 2;
|
||||||
case OPTION_U32: return 4;
|
case OPTION_U32: return 4;
|
||||||
case OPTION_S32: return 4;
|
case OPTION_S32: return 4;
|
||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t option_length(uint8_t code)
|
uint8_t option_length(uint8_t code)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; options[i].code; i++)
|
for (i = 0; options[i].code; i++)
|
||||||
if (options[i].code == code)
|
if (options[i].code == code)
|
||||||
return option_type_length(options[i].type & 0xf);
|
return option_type_length(options[i].type & 0xf);
|
||||||
log_warning("option_length: unknown length for code 0x%02x", code);
|
log_warning("option_length: unknown length for code 0x%02x", code);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int option_valid_list(uint8_t code)
|
int option_valid_list(uint8_t code)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; options[i].code; ++i)
|
for (i = 0; options[i].code; ++i)
|
||||||
if ((options[i].code == code) && (options[i].type & OPTION_LIST))
|
if ((options[i].code == code) && (options[i].type & OPTION_LIST))
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t sizeof_option(uint8_t code, size_t datalen)
|
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
|
// optdata can be NULL
|
||||||
size_t set_option(uint8_t *buf, size_t buflen, uint8_t code, uint8_t *optdata,
|
size_t set_option(uint8_t *buf, size_t buflen, uint8_t code, uint8_t *optdata,
|
||||||
size_t datalen)
|
size_t datalen)
|
||||||
{
|
{
|
||||||
if (!optdata)
|
if (!optdata)
|
||||||
datalen = 0;
|
datalen = 0;
|
||||||
if (code == DHCP_PADDING || code == DHCP_END) {
|
if (code == DHCP_PADDING || code == DHCP_END) {
|
||||||
if (buflen < 1)
|
if (buflen < 1)
|
||||||
return 0;
|
return 0;
|
||||||
buf[0] = code;
|
buf[0] = code;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (datalen > 255 || buflen < 2 + datalen)
|
if (datalen > 255 || buflen < 2 + datalen)
|
||||||
return 0;
|
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 2 + 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 *ret;
|
uint8_t *ret;
|
||||||
size_t len = sizeof_option(code, datalen);
|
size_t len = sizeof_option(code, datalen);
|
||||||
ret = xmalloc(len);
|
ret = xmalloc(len);
|
||||||
set_option(ret, len, code, optdata, datalen);
|
set_option(ret, len, code, optdata, datalen);
|
||||||
return ret;
|
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
|
||||||
// type of ARP MAC address (1 for ethernet) or 0 for a purely symbolic
|
// type of ARP MAC address (1 for ethernet) or 0 for a purely symbolic
|
||||||
// identifier.
|
// identifier.
|
||||||
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 data[idstrlen + 1];
|
uint8_t data[idstrlen + 1];
|
||||||
data[0] = type;
|
data[0] = type;
|
||||||
memcpy(data + 1, idstr, idstrlen);
|
memcpy(data + 1, idstr, idstrlen);
|
||||||
return alloc_option(DHCP_CLIENT_ID, data, sizeof data);
|
return alloc_option(DHCP_CLIENT_ID, data, sizeof data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Worker function for get_option_data(). Optlen will be set to the length
|
// Worker function for get_option_data(). Optlen will be set to the length
|
||||||
// of the option data.
|
// of the option data.
|
||||||
static uint8_t *do_get_option_data(uint8_t *buf, ssize_t buflen, int code,
|
static uint8_t *do_get_option_data(uint8_t *buf, ssize_t buflen, int code,
|
||||||
char *overload, ssize_t *optlen)
|
char *overload, ssize_t *optlen)
|
||||||
{
|
{
|
||||||
/* option bytes: [code][len]([data1][data2]..[dataLEN]) */
|
/* option bytes: [code][len]([data1][data2]..[dataLEN]) */
|
||||||
*overload = 0;
|
*overload = 0;
|
||||||
while (buflen > 0) {
|
while (buflen > 0) {
|
||||||
// Advance over padding.
|
// Advance over padding.
|
||||||
if (buf[0] == DHCP_PADDING) {
|
if (buf[0] == DHCP_PADDING) {
|
||||||
buflen--;
|
buflen--;
|
||||||
buf++;
|
buf++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We hit the end.
|
// We hit the end.
|
||||||
if (buf[0] == DHCP_END) {
|
if (buf[0] == DHCP_END) {
|
||||||
*optlen = 0;
|
*optlen = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
buflen -= buf[1] + 2;
|
buflen -= buf[1] + 2;
|
||||||
if (buflen < 0) {
|
if (buflen < 0) {
|
||||||
log_warning("Bad dhcp data: option length would exceed options field length");
|
log_warning("Bad dhcp data: option length would exceed options field length");
|
||||||
*optlen = 0;
|
*optlen = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf[0] == code) {
|
if (buf[0] == code) {
|
||||||
*optlen = buf[1];
|
*optlen = buf[1];
|
||||||
return buf + 2;
|
return buf + 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf[0] == DHCP_OPTION_OVERLOAD) {
|
if (buf[0] == DHCP_OPTION_OVERLOAD) {
|
||||||
if (buf[1] == 1)
|
if (buf[1] == 1)
|
||||||
*overload |= buf[2];
|
*overload |= buf[2];
|
||||||
/* fall through */
|
/* fall through */
|
||||||
}
|
}
|
||||||
buf += buf[1] + 2;
|
buf += buf[1] + 2;
|
||||||
}
|
}
|
||||||
log_warning("Bad dhcp data: unmarked end of options field");
|
log_warning("Bad dhcp data: unmarked end of options field");
|
||||||
*optlen = 0;
|
*optlen = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get an option with bounds checking (warning, result is not aligned)
|
// Get an option with bounds checking (warning, result is not aligned)
|
||||||
// optlen will be equal to the length of the option data.
|
// optlen will be equal to the length of the option data.
|
||||||
uint8_t *get_option_data(struct dhcpMessage *packet, int code, ssize_t *optlen)
|
uint8_t *get_option_data(struct dhcpMessage *packet, int code, ssize_t *optlen)
|
||||||
{
|
{
|
||||||
uint8_t *option, *buf;
|
uint8_t *option, *buf;
|
||||||
ssize_t buflen;
|
ssize_t buflen;
|
||||||
char overload, parsed_ff = 0;
|
char overload, parsed_ff = 0;
|
||||||
|
|
||||||
buf = packet->options;
|
buf = packet->options;
|
||||||
buflen = sizeof packet->options;
|
buflen = sizeof packet->options;
|
||||||
|
|
||||||
option = do_get_option_data(buf, buflen, code, &overload, optlen);
|
option = do_get_option_data(buf, buflen, code, &overload, optlen);
|
||||||
if (option)
|
if (option)
|
||||||
return option;
|
return option;
|
||||||
|
|
||||||
if (overload & 1) {
|
if (overload & 1) {
|
||||||
parsed_ff = 1;
|
parsed_ff = 1;
|
||||||
option = do_get_option_data(packet->file, sizeof packet->file,
|
option = do_get_option_data(packet->file, sizeof packet->file,
|
||||||
code, &overload, optlen);
|
code, &overload, optlen);
|
||||||
if (option)
|
if (option)
|
||||||
return option;
|
return option;
|
||||||
}
|
}
|
||||||
if (overload & 2) {
|
if (overload & 2) {
|
||||||
option = do_get_option_data(packet->sname, sizeof packet->sname,
|
option = do_get_option_data(packet->sname, sizeof packet->sname,
|
||||||
code, &overload, optlen);
|
code, &overload, optlen);
|
||||||
if (option)
|
if (option)
|
||||||
return option;
|
return option;
|
||||||
if (!parsed_ff && overload & 1)
|
if (!parsed_ff && overload & 1)
|
||||||
option = do_get_option_data(packet->file, sizeof packet->file,
|
option = do_get_option_data(packet->file, sizeof packet->file,
|
||||||
code, &overload, optlen);
|
code, &overload, optlen);
|
||||||
}
|
}
|
||||||
return option;
|
return option;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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(uint8_t *optbuf, size_t bufsize)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < bufsize; ++i) {
|
for (i = 0; i < bufsize; ++i) {
|
||||||
if (optbuf[i] == DHCP_END)
|
if (optbuf[i] == DHCP_END)
|
||||||
return i;
|
return i;
|
||||||
if (optbuf[i] == DHCP_PADDING)
|
if (optbuf[i] == DHCP_PADDING)
|
||||||
continue;
|
continue;
|
||||||
if (optbuf[i] != DHCP_PADDING)
|
if (optbuf[i] != DHCP_PADDING)
|
||||||
i += optbuf[i+1] + 1;
|
i += optbuf[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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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(uint8_t *optbuf, size_t buflen, uint8_t *optstr)
|
||||||
{
|
{
|
||||||
size_t end = get_end_option_idx(optbuf, buflen);
|
size_t end = get_end_option_idx(optbuf, buflen);
|
||||||
size_t datalen = optstr[1];
|
size_t datalen = optstr[1];
|
||||||
|
|
||||||
if (end == -1) {
|
if (end == -1) {
|
||||||
log_warning("add_option_string: Buffer has no DHCP_END marker");
|
log_warning("add_option_string: Buffer has no DHCP_END marker");
|
||||||
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 >= buflen) {
|
||||||
log_warning("Option 0x%02x did not fit into the packet!", optstr[0]);
|
log_warning("Option 0x%02x did not fit into the packet!", optstr[0]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
memcpy(optbuf + end, optstr, datalen + 2);
|
memcpy(optbuf + end, optstr, datalen + 2);
|
||||||
optbuf[end + datalen + 2] = DHCP_END;
|
optbuf[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(uint8_t *optbuf, size_t buflen, uint8_t code,
|
||||||
uint32_t data)
|
uint32_t data)
|
||||||
{
|
{
|
||||||
int length = 0;
|
int length = 0;
|
||||||
uint8_t option[6];
|
uint8_t option[6];
|
||||||
|
|
||||||
length = option_length(code);
|
length = option_length(code);
|
||||||
|
|
||||||
log_line("add_u32_option: code=0x%02x length=0x%02x", code, length);
|
log_line("add_u32_option: code=0x%02x length=0x%02x", code, length);
|
||||||
option[0] = code;
|
option[0] = code;
|
||||||
option[1] = length;
|
option[1] = length;
|
||||||
|
|
||||||
if (!length) {
|
if (!length) {
|
||||||
log_warning("add_u32_option: option code 0x%02x has 0 length", code);
|
log_warning("add_u32_option: option code 0x%02x has 0 length", code);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length == 1) {
|
if (length == 1) {
|
||||||
uint8_t t = (uint8_t)data;
|
uint8_t t = (uint8_t)data;
|
||||||
memcpy(option + 2, &t, 1);
|
memcpy(option + 2, &t, 1);
|
||||||
} else if (length == 2) {
|
} else if (length == 2) {
|
||||||
uint16_t t = (uint16_t)data;
|
uint16_t t = (uint16_t)data;
|
||||||
memcpy(option + 2, &t, 2);
|
memcpy(option + 2, &t, 2);
|
||||||
} else if (length == 4) {
|
} else if (length == 4) {
|
||||||
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(optbuf, buflen, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add a paramater request list for stubborn DHCP servers */
|
/* Add a paramater request list for stubborn DHCP servers */
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* options.h - DHCP options handling
|
/* options.h - DHCP options handling
|
||||||
* Time-stamp: <2011-03-30 16:07:24 nk>
|
* Time-stamp: <2011-03-30 16:34:55 nk>
|
||||||
*
|
*
|
||||||
* (c) 2004-2011 Nicholas J. Kain <njkain at gmail dot com>
|
* (c) 2004-2011 Nicholas J. Kain <njkain at gmail dot com>
|
||||||
*
|
*
|
||||||
@ -70,14 +70,14 @@
|
|||||||
#define DHCP_END 0xff
|
#define DHCP_END 0xff
|
||||||
|
|
||||||
enum option_type {
|
enum option_type {
|
||||||
OPTION_NONE = 0,
|
OPTION_NONE = 0,
|
||||||
OPTION_IP = 1,
|
OPTION_IP = 1,
|
||||||
OPTION_STRING = 2,
|
OPTION_STRING = 2,
|
||||||
OPTION_U8 = 3,
|
OPTION_U8 = 3,
|
||||||
OPTION_U16 = 4,
|
OPTION_U16 = 4,
|
||||||
OPTION_S16 = 5,
|
OPTION_S16 = 5,
|
||||||
OPTION_U32 = 6,
|
OPTION_U32 = 6,
|
||||||
OPTION_S32 = 7
|
OPTION_S32 = 7
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *option_name(uint8_t code);
|
const char *option_name(uint8_t code);
|
||||||
@ -86,17 +86,17 @@ 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 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 set_option(uint8_t *buf, size_t buflen, uint8_t code, uint8_t *optdata,
|
||||||
size_t datalen);
|
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 dhcpMessage *packet, int code, ssize_t *optlen);
|
uint8_t *get_option_data(struct dhcpMessage *packet, int code, ssize_t *optlen);
|
||||||
ssize_t get_end_option_idx(uint8_t *optbuf, size_t bufsize);
|
ssize_t get_end_option_idx(uint8_t *optbuf, size_t bufsize);
|
||||||
size_t add_option_string(uint8_t *optbuf, size_t buflen, uint8_t *optstr);
|
size_t add_option_string(uint8_t *optbuf, size_t buflen, uint8_t *optstr);
|
||||||
size_t add_u32_option(uint8_t *optbuf, size_t buflen, uint8_t code,
|
size_t add_u32_option(uint8_t *optbuf, size_t buflen, uint8_t code,
|
||||||
uint32_t data);
|
uint32_t data);
|
||||||
void add_option_request_list(uint8_t *optbuf, size_t buflen);
|
void add_option_request_list(uint8_t *optbuf, size_t buflen);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user