From 2837bb310c6fbcbf54c06730bdf36c432798bcc8 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Mon, 11 Jun 2018 22:21:31 +0200 Subject: [PATCH] fix ip6addr_aton handling IPv4-mapped addresses ... and added a unit test for it Signed-off-by: Simon Goldschmidt --- src/core/ipv6/ip6_addr.c | 39 +++++++++++++++++++++++++++++++- test/unit/ip6/test_ip6.c | 49 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/src/core/ipv6/ip6_addr.c b/src/core/ipv6/ip6_addr.c index 7ff83d9d..0c747558 100644 --- a/src/core/ipv6/ip6_addr.c +++ b/src/core/ipv6/ip6_addr.c @@ -47,6 +47,10 @@ #include "lwip/ip_addr.h" #include "lwip/def.h" +#if LWIP_IPV4 +#include "lwip/ip4_addr.h" /* for ip6addr_aton to handle IPv4-mapped addresses */ +#endif /* LWIP_IPV4 */ + /* used by IP6_ADDR_ANY(6) in ip6_addr.h */ const ip_addr_t ip6_addr_any = IPADDR6_INIT(0ul, 0ul, 0ul, 0ul); @@ -66,6 +70,9 @@ ip6addr_aton(const char *cp, ip6_addr_t *addr) { u32_t addr_index, zero_blocks, current_block_index, current_block_value; const char *s; +#if LWIP_IPV4 + int check_ipv4_mapped = 0; +#endif /* LWIP_IPV4 */ /* Count the number of colons, to count the number of blocks in a "::" sequence zero_blocks may be 1 even if there are no :: sequences */ @@ -73,6 +80,18 @@ ip6addr_aton(const char *cp, ip6_addr_t *addr) for (s = cp; *s != 0; s++) { if (*s == ':') { zero_blocks--; +#if LWIP_IPV4 + } else if (*s == '.') { + if (zero_blocks == 5) { + check_ipv4_mapped = 1; + /* last block could be the start of an IPv4 address */ + zero_blocks--; + } else { + /* invalid format */ + return 0; + } + break; +#endif /* LWIP_IPV4 */ } else if (!lwip_isxdigit(*s)) { break; } @@ -93,6 +112,22 @@ ip6addr_aton(const char *cp, ip6_addr_t *addr) } } current_block_index++; +#if LWIP_IPV4 + if (check_ipv4_mapped) { + if (current_block_index == 6) { + ip4_addr_t ip4; + int ret = ip4addr_aton(s + 1, &ip4); + if (ret) { + if (addr) { + addr->addr[3] = lwip_htonl(ip4.addr); + current_block_index++; + goto fix_byte_order_and_return; + } + return 1; + } + } + } +#endif /* LWIP_IPV4 */ current_block_value = 0; if (current_block_index > 7) { /* address too long! */ @@ -139,7 +174,9 @@ ip6addr_aton(const char *cp, ip6_addr_t *addr) else { addr->addr[addr_index] = current_block_value << 16; } - +#if LWIP_IPV4 +fix_byte_order_and_return: +#endif /* convert to network byte order. */ for (addr_index = 0; addr_index < 4; addr_index++) { addr->addr[addr_index] = lwip_htonl(addr->addr[addr_index]); diff --git a/test/unit/ip6/test_ip6.c b/test/unit/ip6/test_ip6.c index cf55d5b7..d7de039c 100644 --- a/test/unit/ip6/test_ip6.c +++ b/test/unit/ip6/test_ip6.c @@ -141,6 +141,54 @@ START_TEST(test_ip6_ll_addr) } END_TEST +START_TEST(test_ip6_aton_ipv4mapped) +{ + int ret; + ip_addr_t addr; + ip6_addr_t addr6; + const ip_addr_t addr_expected = IPADDR6_INIT_HOST(0, 0, 0xFFFF, 0xD4CC65D2); + LWIP_UNUSED_ARG(_i); + + /* check IPv6 representation */ + memset(&addr6, 0, sizeof(addr6)); + ret = ip6addr_aton("0:0:0:0:0:FFFF:D4CC:65D2", &addr6); + fail_unless(ret == 1); + fail_unless(memcmp(&addr6, &addr_expected, 16) == 0); + memset(&addr, 0, sizeof(addr)); + ret = ipaddr_aton("0:0:0:0:0:FFFF:D4CC:65D2", &addr); + fail_unless(ret == 1); + fail_unless(memcmp(&addr, &addr_expected, 16) == 0); + + /* check shortened IPv6 representation */ + memset(&addr6, 0, sizeof(addr6)); + ret = ip6addr_aton("::FFFF:D4CC:65D2", &addr6); + fail_unless(ret == 1); + fail_unless(memcmp(&addr6, &addr_expected, 16) == 0); + memset(&addr, 0, sizeof(addr)); + ret = ipaddr_aton("::FFFF:D4CC:65D2", &addr); + fail_unless(ret == 1); + fail_unless(memcmp(&addr, &addr_expected, 16) == 0); + + /* checked mixed representation */ + memset(&addr6, 0, sizeof(addr6)); + ret = ip6addr_aton("::FFFF:212.204.101.210", &addr6); + fail_unless(ret == 1); + fail_unless(memcmp(&addr6, &addr_expected, 16) == 0); + memset(&addr, 0, sizeof(addr)); + ret = ipaddr_aton("::FFFF:212.204.101.210", &addr); + fail_unless(ret == 1); + fail_unless(memcmp(&addr, &addr_expected, 16) == 0); + + /* checked bogus mixed representation */ + memset(&addr6, 0, sizeof(addr6)); + ret = ip6addr_aton("::FFFF:212.204.101.2101", &addr6); + fail_unless(ret == 0); + memset(&addr, 0, sizeof(addr)); + ret = ipaddr_aton("::FFFF:212.204.101.2101", &addr); + fail_unless(ret == 0); + +} +END_TEST /** Create the suite including all tests for this module */ Suite * @@ -148,6 +196,7 @@ ip6_suite(void) { testfunc tests[] = { TESTFUNC(test_ip6_ll_addr), + TESTFUNC(test_ip6_aton_ipv4mapped), }; return create_suite("IPv6", tests, sizeof(tests)/sizeof(testfunc), ip6_setup, ip6_teardown); }