klibc-bot for KUMAAN
2012-May-22 09:00 UTC
[klibc] [klibc:master] ipconfig: Write $DOMAINSEARCH as domain-search
Commit-ID: 2f1c2933bc4cceb4766c4a7aedebe12c82be775d Gitweb: http://git.kernel.org/?p=libs/klibc/klibc.git;a=commit;h=2f1c2933bc4cceb4766c4a7aedebe12c82be775d Author: KUMAAN <9maaan at gmail.com> AuthorDate: Tue, 23 Aug 2011 14:57:08 +0900 Committer: maximilian attems <max at stro.at> CommitDate: Tue, 22 May 2012 10:52:43 +0200 [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/627166This 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 at gmail.com> Acked-by: H. Peter Anvin <hpa at zytor.com> Signed-off-by: maximilian attems <max at stro.at> --- usr/kinit/ipconfig/bootp_packet.h | 10 ++ usr/kinit/ipconfig/bootp_proto.c | 240 ++++++++++++++++++++++++++++++++++++- usr/kinit/ipconfig/dhcp_proto.c | 3 +- usr/kinit/ipconfig/main.c | 2 + 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 6016e5f..1ef505e 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 e3d50e3..150ebfa 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 8ca2614..0c907e9 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 148ccb6..476384a 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 f419880..cd853b6 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 */ };