diff --git a/sys/include/net/ipv6/addr.h b/sys/include/net/ipv6/addr.h index e9d3fd40ba..13b30e6f73 100644 --- a/sys/include/net/ipv6/addr.h +++ b/sys/include/net/ipv6/addr.h @@ -720,8 +720,8 @@ char *ipv6_addr_to_str(char *result, const ipv6_addr_t *addr, uint8_t result_len * RFC 5952 * * - * @param[in] result The resulting byte representation - * @param[in] addr An IPv6 address string representation + * @param[out] result The resulting byte representation + * @param[in] addr An IPv6 address string representation * * @return @p result, on success * @return NULL, if @p addr was malformed @@ -729,6 +729,27 @@ char *ipv6_addr_to_str(char *result, const ipv6_addr_t *addr, uint8_t result_len */ ipv6_addr_t *ipv6_addr_from_str(ipv6_addr_t *result, const char *addr); +/** + * @brief Converts an IPv6 address from a buffer of characters to a + * byte-represented IPv6 address + * + * @see + * RFC 5952 + * + * + * @note @p addr_len should be between 0 and IPV6_ADDR_MAX_STR_LEN + * + * @param[out] result The resulting byte representation + * @param[in] addr An IPv6 address string representation + * @param[in] addr_len The amount of characters to parse + * + * @return @p result, on success + * @return NULL, if @p addr was malformed + * @return NULL, if @p result or @p addr was NULL + */ +ipv6_addr_t *ipv6_addr_from_buf(ipv6_addr_t *result, const char *addr, + size_t addr_len); + /** * @brief split IPv6 address string representation and return remaining string * diff --git a/sys/net/network_layer/ipv6/addr/ipv6_addr_from_str.c b/sys/net/network_layer/ipv6/addr/ipv6_addr_from_str.c index 9c28b015e4..870879d086 100644 --- a/sys/net/network_layer/ipv6/addr/ipv6_addr_from_str.c +++ b/sys/net/network_layer/ipv6/addr/ipv6_addr_from_str.c @@ -38,18 +38,20 @@ #define HEX_U "0123456789ABCDEF" /* based on inet_pton6() by Paul Vixie */ -ipv6_addr_t *ipv6_addr_from_str(ipv6_addr_t *result, const char *addr) +ipv6_addr_t *ipv6_addr_from_buf(ipv6_addr_t *result, const char *addr, + size_t addr_len) { uint8_t *colonp = 0; + const char *start = addr; #ifdef MODULE_IPV4_ADDR const char *curtok = addr; #endif uint32_t val = 0; - char ch; uint8_t saw_xdigit = 0; uint8_t i = 0; - if ((result == NULL) || (addr == NULL)) { + if ((result == NULL) || (addr == NULL) || (addr_len == 0) || + (addr_len > IPV6_ADDR_MAX_STR_LEN)) { return NULL; } @@ -62,7 +64,8 @@ ipv6_addr_t *ipv6_addr_from_str(ipv6_addr_t *result, const char *addr) } } - while ((ch = *addr++) != '\0') { + while ((size_t)(addr - start) < addr_len) { + char ch = *addr++; const char *pch; const char *xdigits; @@ -109,8 +112,8 @@ ipv6_addr_t *ipv6_addr_from_str(ipv6_addr_t *result, const char *addr) #ifdef MODULE_IPV4_ADDR if (ch == '.' && ((i + sizeof(ipv4_addr_t)) <= sizeof(ipv6_addr_t)) && - ipv4_addr_from_str((ipv4_addr_t *)(&(result->u8[i])), - curtok) != NULL) { + ipv4_addr_from_buf((ipv4_addr_t *)(&(result->u8[i])), + curtok, addr_len - (curtok - start)) != NULL) { i += sizeof(ipv4_addr_t); saw_xdigit = 0; break; /* '\0' was seen by ipv4_addr_from_str(). */ @@ -151,6 +154,15 @@ ipv6_addr_t *ipv6_addr_from_str(ipv6_addr_t *result, const char *addr) return result; } +ipv6_addr_t *ipv6_addr_from_str(ipv6_addr_t *result, const char *addr) +{ + if ((result == NULL) || (addr == NULL)) { + return NULL; + } + + return ipv6_addr_from_buf(result, addr, strlen(addr)); +} + /** * @} */ diff --git a/tests/unittests/tests-ipv6_addr/tests-ipv6_addr.c b/tests/unittests/tests-ipv6_addr/tests-ipv6_addr.c index 62a3dd6ad2..18b0578207 100644 --- a/tests/unittests/tests-ipv6_addr/tests-ipv6_addr.c +++ b/tests/unittests/tests-ipv6_addr/tests-ipv6_addr.c @@ -1056,6 +1056,30 @@ static void test_ipv6_addr_split_prefix__with_prefix(void) TEST_ASSERT_EQUAL_INT(strcmp("fd00:dead:beef::1", a), 0); } +static void test_ipv6_addr_from_buf__success(void) +{ + ipv6_addr_t a = { { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 255, 255, 255, 255 + } + }; + ipv6_addr_t result; + +#ifdef MODULE_IPV4_ADDR + TEST_ASSERT_NOT_NULL(ipv6_addr_from_buf(&result, "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255%tap0", 45)); +#else + TEST_ASSERT_NOT_NULL(ipv6_addr_from_buf(&result, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%tap0", 39)); +#endif + TEST_ASSERT(ipv6_addr_equal(&a, &result)); +} + +static void test_ipv6_addr_from_buf__too_long_len(void) +{ + ipv6_addr_t result; + + TEST_ASSERT_NULL(ipv6_addr_from_buf(&result, "::1", IPV6_ADDR_MAX_STR_LEN + 1)); +} + Test *tests_ipv6_addr_tests(void) { EMB_UNIT_TESTFIXTURES(fixtures) { @@ -1148,6 +1172,8 @@ Test *tests_ipv6_addr_tests(void) new_TestFixture(test_ipv6_addr_split_iface__with_iface), new_TestFixture(test_ipv6_addr_split_prefix__no_prefix), new_TestFixture(test_ipv6_addr_split_prefix__with_prefix), + new_TestFixture(test_ipv6_addr_from_buf__success), + new_TestFixture(test_ipv6_addr_from_buf__too_long_len), }; EMB_UNIT_TESTCALLER(ipv6_addr_tests, NULL, NULL, fixtures);