aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKUMAAN <9maaan@gmail.com>2011-08-23 14:57:08 +0900
committermaximilian attems <max@stro.at>2012-05-22 10:52:43 +0200
commit2f1c2933bc4cceb4766c4a7aedebe12c82be775d (patch)
treea76bf73f47963af78706bc2a5b42da81f9e90bb2
parent72a6e871639c36b949c6aa3d8429100e63d20796 (diff)
downloadklibc-2f1c2933bc4cceb4766c4a7aedebe12c82be775d.tar.gz
[klibc] ipconfig: Write $DOMAINSEARCH as domain-search
This patch requests domain-search option to DHCP servers, and parses domain-search option value in DHCP ACK packet when ipconfig uses DHCP. This patch writes $DOMAINSEARCH as the value to /tmp/net-$DEVICE.conf file. > ipconfig: ignores dhcp options > http://bugs.debian.org/627166 This Debian Bug report requests the option value. The format of $DOMAINSEARCH is domain name list which is separated with ' '. For example, $DOMAINSEARCH is either 'foo1.bar. foo2.bar.', 'foo.', or ''. Signed-off-by: KUMAAN <9maaan@gmail.com> Acked-by: H. Peter Anvin <hpa@zytor.com> Signed-off-by: maximilian attems <max@stro.at>
-rw-r--r--usr/kinit/ipconfig/bootp_packet.h10
-rw-r--r--usr/kinit/ipconfig/bootp_proto.c240
-rw-r--r--usr/kinit/ipconfig/dhcp_proto.c3
-rw-r--r--usr/kinit/ipconfig/main.c2
-rw-r--r--usr/kinit/ipconfig/netdev.h1
5 files changed, 253 insertions, 3 deletions
diff --git a/usr/kinit/ipconfig/bootp_packet.h b/usr/kinit/ipconfig/bootp_packet.h
index 6016e5f3a90240..1ef505e4075e72 100644
--- a/usr/kinit/ipconfig/bootp_packet.h
+++ b/usr/kinit/ipconfig/bootp_packet.h
@@ -28,4 +28,14 @@ struct bootp_hdr {
/* 312 bytes of extensions */
};
+/*
+ * memory size of BOOTP Vendor Extensions/DHCP Options for receiving
+ *
+ * generic_ether_mtu:1500, min_sizeof(ip_hdr):20, sizeof(udp_hdr):8
+ *
+ * #define BOOTP_EXTS_SIZE (1500 - 20 - 8 - sizeof(struct bootp_hdr))
+ */
+/* larger size for backward compatibility of ipconfig */
+#define BOOTP_EXTS_SIZE 1500
+
#endif /* BOOTP_PACKET_H */
diff --git a/usr/kinit/ipconfig/bootp_proto.c b/usr/kinit/ipconfig/bootp_proto.c
index e3d50e32501068..150ebfa7952b81 100644
--- a/usr/kinit/ipconfig/bootp_proto.c
+++ b/usr/kinit/ipconfig/bootp_proto.c
@@ -56,11 +56,226 @@ int bootp_send_request(struct netdev *dev)
}
/*
+ * DESCRIPTION
+ * bootp_ext119_decode() decodes Domain Search Option data.
+ * The decoded string is separated with ' '.
+ * For example, it is either "foo.bar.baz. bar.baz.", "foo.bar.", or "foo.".
+ *
+ * ARGUMENTS
+ * const uint8_t *ext
+ * *ext is a pointer to a DHCP Domain Search Option data. *ext does not
+ * include a tag(code) octet and a length octet in DHCP options.
+ * For example, if *ext is {3, 'f', 'o', 'o', 0}, this function returns
+ * a pointer to a "foo." string.
+ *
+ * int16_t ext_size
+ * ext_size is the memory size of *ext. For example,
+ * if *ext is {3, 'f', 'o', 'o', 0}, ext_size must be 5.
+ *
+ * uint8_t *tmp
+ * *tmp is a pointer to a temporary memory space for decoding.
+ * The memory size must be equal to or more than ext_size.
+ * 'memset(tmp, 0, sizeof(tmp));' is not required, but values in *tmp
+ * are changed in decoding process.
+ *
+ * RETURN VALUE
+ * if OK, a pointer to a decoded string malloc-ed
+ * else , NULL
+ *
+ * SEE ALSO RFC3397
+ */
+static char *bootp_ext119_decode(const void *ext, int16_t ext_size, void *tmp)
+{
+ uint8_t *u8ext;
+ int_fast32_t i;
+ int_fast32_t decoded_size;
+ int_fast8_t currentdomain_is_singledot;
+
+ /* only for validating *ext */
+ uint8_t *is_pointee;
+ int_fast32_t is_pointee_size;
+
+ /* only for structing a decoded string */
+ char *decoded_str;
+ int_fast32_t dst_i;
+
+ if (ext == NULL || ext_size <= 0 || tmp == NULL)
+ return NULL;
+
+ u8ext = (uint8_t *)ext;
+ is_pointee = tmp;
+ memset(is_pointee, 0, (size_t)ext_size);
+ is_pointee_size = 0;
+
+ /*
+ * validate the format of *ext and
+ * calculate the memory size for a decoded string
+ */
+ i = 0;
+ decoded_size = 0;
+ currentdomain_is_singledot = 1;
+ while (1) {
+ if (i >= ext_size)
+ return NULL;
+
+ if (u8ext[i] == 0) {
+ /* Zero-ending */
+ if (currentdomain_is_singledot)
+ decoded_size++; /* for '.' */
+ decoded_size++; /* for ' ' or '\0' */
+ currentdomain_is_singledot = 1;
+ i++;
+ if (i == ext_size)
+ break;
+ is_pointee_size = i;
+ } else if (u8ext[i] < 0x40) {
+ /* Label(sub-domain string) */
+ int j;
+
+ /* loosely validate characters for domain names */
+ if (i + u8ext[i] >= ext_size)
+ return NULL;
+ for (j = i + 1; j <= i + u8ext[i]; j++)
+ if (!(u8ext[j] == '-' ||
+ ('0' <= u8ext[j] && u8ext[j] <= '9') ||
+ ('A' <= u8ext[j] && u8ext[j] <= 'Z') ||
+ ('a' <= u8ext[j] && u8ext[j] <= 'z')))
+ return NULL;
+
+ is_pointee[i] = 1;
+ decoded_size += u8ext[i] + 1; /* for Label + '.' */
+ currentdomain_is_singledot = 0;
+ i += u8ext[i] + 1;
+ } else if (u8ext[i] < 0xc0)
+ return NULL;
+
+ else {
+ /* Compression-pointer (to a prior Label) */
+ int_fast32_t p;
+
+ if (i + 1 >= ext_size)
+ return NULL;
+
+ p = ((0x3f & u8ext[i]) << 8) + u8ext[i + 1];
+ if (!(p < is_pointee_size && is_pointee[p]))
+ return NULL;
+
+ while (1) {
+ /* u8ext[p] was validated */
+ if (u8ext[p] == 0) {
+ /* Zero-ending */
+ decoded_size++;
+ break;
+ } else if (u8ext[p] < 0x40) {
+ /* Label(sub-domain string) */
+ decoded_size += u8ext[p] + 1;
+ p += u8ext[p] + 1;
+ } else {
+ /* Compression-pointer */
+ p = ((0x3f & u8ext[p]) << 8)
+ + u8ext[p + 1];
+ }
+ }
+
+ currentdomain_is_singledot = 1;
+ i += 2;
+ if (i == ext_size)
+ break;
+ is_pointee_size = i;
+ }
+ }
+
+
+ /*
+ * construct a decoded string
+ */
+ decoded_str = malloc(decoded_size);
+ if (decoded_str == NULL)
+ return NULL;
+
+ i = 0;
+ dst_i = 0;
+ currentdomain_is_singledot = 1;
+ while (1) {
+ if (u8ext[i] == 0) {
+ /* Zero-ending */
+ if (currentdomain_is_singledot) {
+ if (dst_i != 0)
+ dst_i++;
+ decoded_str[dst_i] = '.';
+ }
+ dst_i++;
+ decoded_str[dst_i] = ' ';
+
+ currentdomain_is_singledot = 1;
+ i++;
+ if (i == ext_size)
+ break;
+ } else if (u8ext[i] < 0x40) {
+ /* Label(sub-domain string) */
+ if (dst_i != 0)
+ dst_i++;
+ memcpy(&decoded_str[dst_i], &u8ext[i + 1],
+ (size_t)u8ext[i]);
+ dst_i += u8ext[i];
+ decoded_str[dst_i] = '.';
+
+ currentdomain_is_singledot = 0;
+ i += u8ext[i] + 1;
+ } else {
+ /* Compression-pointer (to a prior Label) */
+ int_fast32_t p;
+
+ p = ((0x3f & u8ext[i]) << 8) + u8ext[i + 1];
+ while (1) {
+ if (u8ext[p] == 0) {
+ /* Zero-ending */
+ decoded_str[dst_i++] = '.';
+ decoded_str[dst_i] = ' ';
+ break;
+ } else if (u8ext[p] < 0x40) {
+ /* Label(sub-domain string) */
+ dst_i++;
+ memcpy(&decoded_str[dst_i],
+ &u8ext[p + 1],
+ (size_t)u8ext[p]);
+ dst_i += u8ext[p];
+ decoded_str[dst_i] = '.';
+
+ p += u8ext[p] + 1;
+ } else {
+ /* Compression-pointer */
+ p = ((0x3f & u8ext[p]) << 8)
+ + u8ext[p + 1];
+ }
+ }
+
+ currentdomain_is_singledot = 1;
+ i += 2;
+ if (i == ext_size)
+ break;
+ }
+ }
+ decoded_str[dst_i] = '\0';
+#ifdef DEBUG
+ if (dst_i + 1 != decoded_size) {
+ dprintf("bug:%s():bottom: malloc(%ld), write(%ld)\n",
+ __func__, (long)decoded_size, (long)(dst_i + 1));
+ exit(1);
+ }
+#endif
+ return decoded_str;
+}
+
+/*
* Parse a bootp reply packet
*/
int bootp_parse(struct netdev *dev, struct bootp_hdr *hdr,
uint8_t *exts, int extlen)
{
+ uint8_t ext119_buf[BOOTP_EXTS_SIZE];
+ int16_t ext119_len = 0;
+
dev->bootp.gateway = hdr->giaddr;
dev->ip_addr = hdr->yiaddr;
dev->ip_server = hdr->siaddr;
@@ -143,11 +358,32 @@ int bootp_parse(struct netdev *dev, struct bootp_hdr *hdr,
if (len == 4 && !dev->ip_server)
memcpy(&dev->ip_server, ext, 4);
break;
+ case 119: /* Domain Search Option */
+ if (ext119_len >= 0 &&
+ ext119_len + len <= sizeof(ext119_buf)) {
+ memcpy(ext119_buf + ext119_len,
+ ext, len);
+ ext119_len += len;
+ } else
+ ext119_len = -1;
+
+ break;
}
ext += len;
}
}
+ if (ext119_len > 0) {
+ char *ret;
+ uint8_t ext119_tmp[BOOTP_EXTS_SIZE];
+
+ ret = bootp_ext119_decode(ext119_buf, ext119_len, ext119_tmp);
+ if (ret != NULL) {
+ if (dev->domainsearch != NULL)
+ free(dev->domainsearch);
+ dev->domainsearch = ret;
+ }
+ }
/*
* Got packet.
@@ -165,11 +401,11 @@ int bootp_parse(struct netdev *dev, struct bootp_hdr *hdr,
int bootp_recv_reply(struct netdev *dev)
{
struct bootp_hdr bootp;
- uint8_t bootp_options[312];
+ uint8_t bootp_options[BOOTP_EXTS_SIZE];
struct iovec iov[] = {
/* [0] = ip + udp headers */
[1] = {&bootp, sizeof(struct bootp_hdr)},
- [2] = {bootp_options, 312}
+ [2] = {bootp_options, sizeof(bootp_options)}
};
int ret;
diff --git a/usr/kinit/ipconfig/dhcp_proto.c b/usr/kinit/ipconfig/dhcp_proto.c
index 8ca2614072b16a..0c907e9466a842 100644
--- a/usr/kinit/ipconfig/dhcp_proto.c
+++ b/usr/kinit/ipconfig/dhcp_proto.c
@@ -25,6 +25,7 @@ static uint8_t dhcp_params[] = {
26, /* interface mtu */
28, /* broadcast addr */
40, /* NIS domain name (why?) */
+ 119, /* Domain Search Option */
};
static uint8_t dhcp_discover_hdr[] = {
@@ -158,7 +159,7 @@ static int dhcp_parse(struct netdev *dev, struct bootp_hdr *hdr,
static int dhcp_recv(struct netdev *dev)
{
struct bootp_hdr bootp;
- uint8_t dhcp_options[1500];
+ uint8_t dhcp_options[BOOTP_EXTS_SIZE];
struct iovec iov[] = {
/* [0] = ip + udp header */
[1] = {&bootp, sizeof(struct bootp_hdr)},
diff --git a/usr/kinit/ipconfig/main.c b/usr/kinit/ipconfig/main.c
index 148ccb66fa3b12..476384acbd04b4 100644
--- a/usr/kinit/ipconfig/main.c
+++ b/usr/kinit/ipconfig/main.c
@@ -176,6 +176,8 @@ static void dump_device_config(struct netdev *dev)
write_option(f, "UPTIME", buf21);
sprintf(buf21, "%u", (unsigned int)dev->dhcpleasetime);
write_option(f, "DHCPLEASETIME", buf21);
+ write_option(f, "DOMAINSEARCH", dev->domainsearch == NULL ?
+ "" : dev->domainsearch);
fclose(f);
}
}
diff --git a/usr/kinit/ipconfig/netdev.h b/usr/kinit/ipconfig/netdev.h
index f4198804e60cc2..cd853b6c078b41 100644
--- a/usr/kinit/ipconfig/netdev.h
+++ b/usr/kinit/ipconfig/netdev.h
@@ -43,6 +43,7 @@ struct netdev {
char nisdomainname[SYS_NMLN]; /* nis domain name */
char bootpath[BPLEN]; /* boot path */
char filename[FNLEN]; /* filename */
+ char *domainsearch; /* decoded, NULL or malloc-ed */
long uptime; /* when complete configuration */
struct netdev *next; /* next configured i/f */
};