diff options
author | KUMAAN <9maaan@gmail.com> | 2011-08-23 14:57:08 +0900 |
---|---|---|
committer | maximilian attems <max@stro.at> | 2012-05-22 10:52:43 +0200 |
commit | 2f1c2933bc4cceb4766c4a7aedebe12c82be775d (patch) | |
tree | a76bf73f47963af78706bc2a5b42da81f9e90bb2 | |
parent | 72a6e871639c36b949c6aa3d8429100e63d20796 (diff) | |
download | klibc-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.h | 10 | ||||
-rw-r--r-- | usr/kinit/ipconfig/bootp_proto.c | 240 | ||||
-rw-r--r-- | usr/kinit/ipconfig/dhcp_proto.c | 3 | ||||
-rw-r--r-- | usr/kinit/ipconfig/main.c | 2 | ||||
-rw-r--r-- | usr/kinit/ipconfig/netdev.h | 1 |
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 */ }; |