diff options
-rw-r--r-- | include/libbb.h | 4 | ||||
-rw-r--r-- | networking/udhcp/common.c | 3 | ||||
-rw-r--r-- | networking/udhcp/common.h | 1 | ||||
-rw-r--r-- | networking/udhcp/dhcpc.c | 80 |
4 files changed, 84 insertions, 4 deletions
diff --git a/include/libbb.h b/include/libbb.h index f79b69365..f0f54ef82 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -814,9 +814,9 @@ void smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) FAST_F const char *make_human_readable_str(unsigned long long size, unsigned long block_size, unsigned long display_unit) FAST_FUNC; /* Put a string of hex bytes ("1b2e66fe"...), return advanced pointer */ -char *bin2hex(char *buf, const char *cp, int count) FAST_FUNC; +char *bin2hex(char *dst, const char *src, int count) FAST_FUNC; /* Reverse */ -char* hex2bin(char *dst, const char *str, int count) FAST_FUNC; +char* hex2bin(char *dst, const char *src, int count) FAST_FUNC; /* Generate a UUID */ void generate_uuid(uint8_t *buf) FAST_FUNC; diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index 70e34614c..ba41905cc 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c @@ -59,6 +59,7 @@ const struct dhcp_optflag dhcp_optflags[] = { { OPTION_U16 , 0x84 }, /* DHCP_VLAN_ID */ { OPTION_U8 , 0x85 }, /* DHCP_VLAN_PRIORITY */ #endif + { OPTION_6RD , 0xd4 }, /* DHCP_6RD */ { OPTION_STATIC_ROUTES , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */ { OPTION_STRING , 0xfc }, /* DHCP_WPAD */ @@ -126,6 +127,7 @@ const char dhcp_option_strings[] ALIGN1 = "vlanid" "\0" /* DHCP_VLAN_ID */ "vlanpriority" "\0"/* DHCP_VLAN_PRIORITY */ #endif + "ip6rd" "\0" /* DHCP_6RD */ "msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */ "wpad" "\0" /* DHCP_WPAD */ ; @@ -154,6 +156,7 @@ const uint8_t dhcp_option_lengths[] ALIGN1 = { [OPTION_S32] = 4, /* Just like OPTION_STRING, we use minimum length here */ [OPTION_STATIC_ROUTES] = 5, + [OPTION_6RD] = 22, /* ignored by udhcp_str2optset */ }; diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h index 786266810..da0bd38d1 100644 --- a/networking/udhcp/common.h +++ b/networking/udhcp/common.h @@ -88,6 +88,7 @@ enum { OPTION_S32, OPTION_BIN, OPTION_STATIC_ROUTES, + OPTION_6RD, #if ENABLE_FEATURE_UDHCP_RFC3397 OPTION_DNS_STRING, /* RFC1035 compressed domain name list */ OPTION_SIP_SERVERS, diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index ddfe3ccc0..311d4867a 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -100,6 +100,7 @@ static const uint8_t len_of_option_as_string[] = { [OPTION_IP ] = sizeof("255.255.255.255 "), [OPTION_IP_PAIR ] = sizeof("255.255.255.255 ") * 2, [OPTION_STATIC_ROUTES ] = sizeof("255.255.255.255/32 255.255.255.255 "), + [OPTION_6RD ] = sizeof("32 128 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 255.255.255.255 "), [OPTION_STRING ] = 1, #if ENABLE_FEATURE_UDHCP_RFC3397 [OPTION_DNS_STRING ] = 1, /* unused */ @@ -123,6 +124,24 @@ static int sprint_nip(char *dest, const char *pre, const uint8_t *ip) return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]); } +static int sprint_nip6(char *dest, const char *pre, const uint8_t *ip) +{ + char hexstrbuf[16 * 2]; + bin2hex(hexstrbuf, (void*)ip, 16); + return sprintf(dest, "%s" + "%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s", + pre, + hexstrbuf + 0 * 4, + hexstrbuf + 1 * 4, + hexstrbuf + 2 * 4, + hexstrbuf + 3 * 4, + hexstrbuf + 4 * 4, + hexstrbuf + 5 * 4, + hexstrbuf + 6 * 4, + hexstrbuf + 7 * 4 + ); +} + /* really simple implementation, just count the bits */ static int mton(uint32_t mask) { @@ -147,7 +166,8 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ type = optflag->flags & OPTION_TYPE_MASK; optlen = dhcp_option_lengths[type]; - upper_length = len_of_option_as_string[type] * ((unsigned)len / (unsigned)optlen); + upper_length = len_of_option_as_string[type] + * ((unsigned)(len + optlen - 1) / (unsigned)optlen); dest = ret = xmalloc(upper_length + strlen(opt_name) + 2); dest += sprintf(ret, "%s=", opt_name); @@ -232,6 +252,62 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ return ret; } + case OPTION_6RD: { + /* Option binary format (see RFC 5969): + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | OPTION_6RD | option-length | IPv4MaskLen | 6rdPrefixLen | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * | 6rdPrefix | + * | (16 octets) | + * | | + * | | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | 6rdBRIPv4Address(es) | + * . . + * . . + * . . + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * We convert it to a string + * "IPv4MaskLen 6rdPrefixLen 6rdPrefix 6rdBRIPv4Address..." + */ + + /* Sanity check: ensure that our length is at least 22 bytes, that + * IPv4MaskLen <= 32, + * 6rdPrefixLen <= 128, + * 6rdPrefixLen + (32 - IPv4MaskLen) <= 128 + * (2nd condition need no check - it follows from 1st and 3rd). + * If any of these requirements is not fulfilled, return with empty + * value. + */ + if (len >= 22 + && option[0] <= 32 + && (option[1] + 32 - option[0]) <= 128 + ) { + /* IPv4MaskLen */ + dest += sprintf(dest, "%u ", *option++); + /* 6rdPrefixLen */ + dest += sprintf(dest, "%u ", *option++); + /* 6rdPrefix */ + dest += sprint_nip6(dest, "", option); + option += 16; + len -= 1 + 1 + 16; + /* 6rdBRIPv4Address(es) */ + while (1) { + dest += sprint_nip(dest, " ", option); + option += 4; + len -= 4; + if (len < 0) + break; + } + } + + return ret; + } #if ENABLE_FEATURE_UDHCP_RFC3397 case OPTION_DNS_STRING: /* unpack option into dest; use ret for prefix (i.e., "optname=") */ @@ -394,7 +470,7 @@ static char **fill_envp(struct dhcp_packet *packet) len = temp[-OPT_DATA + OPT_LEN]; *curr = xmalloc(sizeof("optNNN=") + 1 + len*2); ofs = sprintf(*curr, "opt%u=", i); - bin2hex(*curr + ofs, (void*) temp, len)[0] = '\0'; + *bin2hex(*curr + ofs, (void*) temp, len) = '\0'; putenv(*curr++); } i++; |