udhcp: optionally support RFC3397 (by Gabriel L. Somlo <somlo@cmu.edu>)

This commit is contained in:
Denis Vlasenko 2007-02-27 21:15:08 +00:00
parent 966bb43766
commit 5066473d41
6 changed files with 77 additions and 21 deletions

View File

@ -65,3 +65,11 @@ config FEATURE_UDHCP_DEBUG
the background. the background.
See http://udhcp.busybox.net for further details. See http://udhcp.busybox.net for further details.
config FEATURE_RFC3397
bool "Support for RFC3397 domain search (experimental)"
default n
depends on APP_UDHCPD || APP_UDHCPC
help
If selected, both client and server will support passing of domain
search lists via option 119, specified in RFC3397.

View File

@ -16,3 +16,4 @@ lib-$(CONFIG_APP_UDHCPD) += dhcpd.o arpping.o files.o leases.o \
serverpacket.o static_leases.o serverpacket.o static_leases.o
lib-$(CONFIG_APP_DUMPLEASES) += dumpleases.o lib-$(CONFIG_APP_DUMPLEASES) += dumpleases.o
lib-$(CONFIG_APP_DHCPRELAY) += dhcprelay.o lib-$(CONFIG_APP_DHCPRELAY) += dhcprelay.o
lib-$(CONFIG_FEATURE_RFC3397) += domain_codec.o

View File

@ -104,6 +104,12 @@ static void attach_option(struct option_set **opt_list,
if (!existing) { if (!existing) {
DEBUG("Attaching option %s to list", option->name); DEBUG("Attaching option %s to list", option->name);
#if ENABLE_FEATURE_RFC3397
if ((option->flags & TYPE_MASK) == OPTION_STR1035)
/* reuse buffer and length for RFC1035-formatted string */
buffer = dname_enc(NULL, 0, buffer, &length);
#endif
/* make a new option */ /* make a new option */
new = xmalloc(sizeof(struct option_set)); new = xmalloc(sizeof(struct option_set));
new->data = xmalloc(length + 2); new->data = xmalloc(length + 2);
@ -117,12 +123,22 @@ static void attach_option(struct option_set **opt_list,
new->next = *curr; new->next = *curr;
*curr = new; *curr = new;
#if ENABLE_FEATURE_RFC3397
if ((option->flags & TYPE_MASK) == OPTION_STR1035 && buffer != NULL)
free(buffer);
#endif
return; return;
} }
/* add it to an existing option */ /* add it to an existing option */
DEBUG("Attaching option %s to existing member of list", option->name); DEBUG("Attaching option %s to existing member of list", option->name);
if (option->flags & OPTION_LIST) { if (option->flags & OPTION_LIST) {
#if ENABLE_FEATURE_RFC3397
if ((option->flags & TYPE_MASK) == OPTION_STR1035)
/* reuse buffer and length for RFC1035-formatted string */
buffer = dname_enc(existing->data + 2,
existing->data[OPT_LEN], buffer, &length);
#endif
if (existing->data[OPT_LEN] + length <= 255) { if (existing->data[OPT_LEN] + length <= 255) {
existing->data = xrealloc(existing->data, existing->data = xrealloc(existing->data,
existing->data[OPT_LEN] + length + 3); existing->data[OPT_LEN] + length + 3);
@ -137,6 +153,10 @@ static void attach_option(struct option_set **opt_list,
memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer, length); memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer, length);
existing->data[OPT_LEN] += length; existing->data[OPT_LEN] += length;
} /* else, ignore the data, we could put this in a second option in the future */ } /* else, ignore the data, we could put this in a second option in the future */
#if ENABLE_FEATURE_RFC3397
if ((option->flags & TYPE_MASK) == OPTION_STR1035 && buffer != NULL)
free(buffer);
#endif
} /* else, ignore the new data */ } /* else, ignore the new data */
} }
@ -183,6 +203,9 @@ static int read_opt(const char *const_line, void *arg)
if (retval) retval = read_ip(val, buffer + 4); if (retval) retval = read_ip(val, buffer + 4);
break; break;
case OPTION_STRING: case OPTION_STRING:
#if ENABLE_FEATURE_RFC3397
case OPTION_STR1035:
#endif
length = strlen(val); length = strlen(val);
if (length > 0) { if (length > 0) {
if (length > 254) length = 254; if (length > 254) length = 254;

View File

@ -11,7 +11,7 @@
/* supported options are easily added here */ /* supported options are easily added here */
const struct dhcp_option dhcp_options[] = { const struct dhcp_option dhcp_options[] = {
/* name[10] flags code */ /* name[12] flags code */
{"subnet", OPTION_IP | OPTION_REQ, 0x01}, {"subnet", OPTION_IP | OPTION_REQ, 0x01},
{"timezone", OPTION_S32, 0x02}, {"timezone", OPTION_S32, 0x02},
{"router", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x03}, {"router", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x03},
@ -43,6 +43,9 @@ const struct dhcp_option dhcp_options[] = {
{"tftp", OPTION_STRING, 0x42}, {"tftp", OPTION_STRING, 0x42},
{"bootfile", OPTION_STRING, 0x43}, {"bootfile", OPTION_STRING, 0x43},
{"userclass", OPTION_STRING, 0x4D}, {"userclass", OPTION_STRING, 0x4D},
#if ENABLE_FEATURE_RFC3397
{"search", OPTION_STR1035 | OPTION_LIST | OPTION_REQ, 0x77},
#endif
/* MSIE's "Web Proxy Autodiscovery Protocol" support */ /* MSIE's "Web Proxy Autodiscovery Protocol" support */
{"wpad", OPTION_STRING, 0xfc}, {"wpad", OPTION_STRING, 0xfc},
{"", 0x00, 0x00} {"", 0x00, 0x00}
@ -54,6 +57,9 @@ const unsigned char option_lengths[] = {
[OPTION_IP_PAIR] = 8, [OPTION_IP_PAIR] = 8,
[OPTION_BOOLEAN] = 1, [OPTION_BOOLEAN] = 1,
[OPTION_STRING] = 1, [OPTION_STRING] = 1,
#if ENABLE_FEATURE_RFC3397
[OPTION_STR1035] = 1,
#endif
[OPTION_U8] = 1, [OPTION_U8] = 1,
[OPTION_U16] = 2, [OPTION_U16] = 2,
[OPTION_S16] = 2, [OPTION_S16] = 2,

View File

@ -9,6 +9,9 @@ enum {
OPTION_IP=1, OPTION_IP=1,
OPTION_IP_PAIR, OPTION_IP_PAIR,
OPTION_STRING, OPTION_STRING,
#if ENABLE_FEATURE_RFC3397
OPTION_STR1035, /* RFC1035 compressed domain name list */
#endif
OPTION_BOOLEAN, OPTION_BOOLEAN,
OPTION_U8, OPTION_U8,
OPTION_U16, OPTION_U16,
@ -33,5 +36,9 @@ uint8_t *get_option(struct dhcpMessage *packet, int code);
int end_option(uint8_t *optionptr); int end_option(uint8_t *optionptr);
int add_option_string(uint8_t *optionptr, uint8_t *string); int add_option_string(uint8_t *optionptr, uint8_t *string);
int add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data); int add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data);
#if ENABLE_FEATURE_RFC3397
char *dname_dec(const uint8_t *cstr, int clen, const char *pre);
uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen);
#endif
#endif #endif

View File

@ -19,6 +19,9 @@ static const int max_option_length[] = {
[OPTION_IP] = sizeof("255.255.255.255 "), [OPTION_IP] = sizeof("255.255.255.255 "),
[OPTION_IP_PAIR] = sizeof("255.255.255.255 ") * 2, [OPTION_IP_PAIR] = sizeof("255.255.255.255 ") * 2,
[OPTION_STRING] = 1, [OPTION_STRING] = 1,
#if ENABLE_FEATURE_RFC3397
[OPTION_STR1035] = 1,
#endif
[OPTION_BOOLEAN] = sizeof("yes "), [OPTION_BOOLEAN] = sizeof("yes "),
[OPTION_U8] = sizeof("255 "), [OPTION_U8] = sizeof("255 "),
[OPTION_U16] = sizeof("65535 "), [OPTION_U16] = sizeof("65535 "),
@ -53,21 +56,23 @@ static int mton(struct in_addr *mask)
} }
/* Fill dest with the text of option 'option'. */ /* Allocate and fill with the text of option 'option'. */
static void fill_options(char *dest, uint8_t *option, static char *alloc_fill_opts(uint8_t *option, const struct dhcp_option *type_p)
const struct dhcp_option *type_p)
{ {
int type, optlen; int len, type, optlen;
uint16_t val_u16; uint16_t val_u16;
int16_t val_s16; int16_t val_s16;
uint32_t val_u32; uint32_t val_u32;
int32_t val_s32; int32_t val_s32;
int len = option[OPT_LEN - 2]; char *dest, *ret;
dest += sprintf(dest, "%s=", type_p->name);
len = option[OPT_LEN - 2];
type = type_p->flags & TYPE_MASK; type = type_p->flags & TYPE_MASK;
optlen = option_lengths[type]; optlen = option_lengths[type];
dest = ret = xmalloc(upper_length(len, type) + strlen(type_p->name) + 2);
dest += sprintf(ret, "%s=", type_p->name);
for (;;) { for (;;) {
switch (type) { switch (type) {
case OPTION_IP_PAIR: case OPTION_IP_PAIR:
@ -103,13 +108,21 @@ static void fill_options(char *dest, uint8_t *option,
case OPTION_STRING: case OPTION_STRING:
memcpy(dest, option, len); memcpy(dest, option, len);
dest[len] = '\0'; dest[len] = '\0';
return; /* Short circuit this case */ return ret; /* Short circuit this case */
#if ENABLE_FEATURE_RFC3397
case OPTION_STR1035:
/* unpack option into dest; use ret for prefix (i.e., "optname=") */
dest = dname_dec(option, len, ret);
free(ret);
return dest;
#endif
} }
option += optlen; option += optlen;
len -= optlen; len -= optlen;
if (len <= 0) break; if (len <= 0) break;
dest += sprintf(dest, " "); dest += sprintf(dest, " ");
} }
return ret;
} }
@ -155,9 +168,7 @@ static char **fill_envp(struct dhcpMessage *packet)
temp = get_option(packet, dhcp_options[i].code); temp = get_option(packet, dhcp_options[i].code);
if (!temp) if (!temp)
continue; continue;
envp[j] = xmalloc(upper_length(temp[OPT_LEN - 2], envp[j++] = alloc_fill_opts(temp, &dhcp_options[i]);
dhcp_options[i].flags & TYPE_MASK) + strlen(dhcp_options[i].name) + 2);
fill_options(envp[j++], temp, &dhcp_options[i]);
/* Fill in a subnet bits option for things like /24 */ /* Fill in a subnet bits option for things like /24 */
if (dhcp_options[i].code == DHCP_SUBNET) { if (dhcp_options[i].code == DHCP_SUBNET) {