From 1a4b249a9527c88ea2f573fea9fda39bb025b5b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Duda?= Date: Wed, 15 May 2019 17:55:05 +0200 Subject: [PATCH] [ip6] add support for parsing embedded IPv4 address (#3819) This commit facilitates the creation of the IPv6 address for NAT64 usage. --- src/core/net/ip6_address.cpp | 68 ++++++++++-- src/core/net/ip6_address.hpp | 1 + tests/unit/Makefile.am | 4 + tests/unit/test_ip6_address.cpp | 187 ++++++++++++++++++++++++++++++++ 4 files changed, 251 insertions(+), 9 deletions(-) create mode 100644 tests/unit/test_ip6_address.cpp diff --git a/src/core/net/ip6_address.cpp b/src/core/net/ip6_address.cpp index 0e3eddcc3..5d34de995 100644 --- a/src/core/net/ip6_address.cpp +++ b/src/core/net/ip6_address.cpp @@ -259,15 +259,17 @@ bool Address::operator!=(const Address &aOther) const otError Address::FromString(const char *aBuf) { - otError error = OT_ERROR_NONE; - uint8_t *dst = reinterpret_cast(mFields.m8); - uint8_t *endp = reinterpret_cast(mFields.m8 + 15); - uint8_t *colonp = NULL; - uint16_t val = 0; - uint8_t count = 0; - bool first = true; - char ch; - uint8_t d; + otError error = OT_ERROR_NONE; + uint8_t * dst = reinterpret_cast(mFields.m8); + uint8_t * endp = reinterpret_cast(mFields.m8 + 15); + uint8_t * colonp = NULL; + const char *colonc = NULL; + uint16_t val = 0; + uint8_t count = 0; + bool first = true; + bool hasIp4 = false; + char ch; + uint8_t d; memset(mFields.m8, 0, 16); @@ -304,8 +306,18 @@ otError Address::FromString(const char *aBuf) break; } + colonc = aBuf; + continue; } + else if (ch == '.') + { + hasIp4 = true; + + // Do not count bytes of the embedded IPv4 address. + endp -= kIp4AddressSize; + break; + } else { VerifyOrExit('0' <= ch && ch <= '9', error = OT_ERROR_PARSE); @@ -326,6 +338,44 @@ otError Address::FromString(const char *aBuf) *endp-- = 0; } + if (hasIp4) + { + val = 0; + + // Reset the start and end pointers. + dst = reinterpret_cast(mFields.m8 + 12); + endp = reinterpret_cast(mFields.m8 + 15); + + for (;;) + { + ch = *colonc++; + + if (ch == '.' || ch == '\0' || ch == ' ') + { + VerifyOrExit(dst <= endp, error = OT_ERROR_PARSE); + + *dst++ = static_cast(val); + val = 0; + + if (ch == '\0' || ch == ' ') + { + // Check if embedded IPv4 address had exactly four parts. + VerifyOrExit(dst == endp + 1, error = OT_ERROR_PARSE); + break; + } + } + else + { + VerifyOrExit('0' <= ch && ch <= '9', error = OT_ERROR_PARSE); + + val = (10 * val) + (ch & 0xf); + + // Single part of IPv4 address has to fit in one byte. + VerifyOrExit(val <= 0xff, error = OT_ERROR_PARSE); + } + } + } + exit: return error; } diff --git a/src/core/net/ip6_address.hpp b/src/core/net/ip6_address.hpp index 8389a47c7..3d3fe6404 100644 --- a/src/core/net/ip6_address.hpp +++ b/src/core/net/ip6_address.hpp @@ -402,6 +402,7 @@ private: enum { kInterfaceIdentifierOffset = 8, ///< Interface Identifier offset in bytes. + kIp4AddressSize = 4 ///< Size of the IPv4 address. }; } OT_TOOL_PACKED_END; diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am index ba21193e7..9ac7344f2 100644 --- a/tests/unit/Makefile.am +++ b/tests/unit/Makefile.am @@ -108,6 +108,7 @@ check_PROGRAMS += \ test-child-table \ test-heap \ test-hmac-sha256 \ + test-ip6-address \ test-link-quality \ test-lowpan \ test-mac-frame \ @@ -187,6 +188,9 @@ test_heap_SOURCES = test_platform.cpp test_heap.cpp test_hmac_sha256_LDADD = $(COMMON_LDADD) test_hmac_sha256_SOURCES = test_platform.cpp test_hmac_sha256.cpp +test_ip6_address_LDADD = $(COMMON_LDADD) +test_ip6_address_SOURCES = test_platform.cpp test_ip6_address.cpp + test_link_quality_LDADD = $(COMMON_LDADD) test_link_quality_SOURCES = test_platform.cpp test_link_quality.cpp diff --git a/tests/unit/test_ip6_address.cpp b/tests/unit/test_ip6_address.cpp new file mode 100644 index 000000000..b54cd7133 --- /dev/null +++ b/tests/unit/test_ip6_address.cpp @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2019, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "net/ip6_address.hpp" +#include "utils/wrap_string.h" + +#include "test_util.h" + +struct Ip6AddressStringTestVector{ + const char * mString; + const uint8_t mAddr[OT_IP6_ADDRESS_SIZE]; + otError mError; +}; + +static void checkAddressFromString(Ip6AddressStringTestVector *aTestVector) +{ + otError error; + ot::Ip6::Address address; + + error = address.FromString(aTestVector->mString); + + VerifyOrQuit(error == aTestVector->mError, "Ip6::Address::FromString returned unexpected error code\n"); + + if (error == OT_ERROR_NONE) + { + VerifyOrQuit(0 == memcmp(address.mFields.m8, aTestVector->mAddr, OT_IP6_ADDRESS_SIZE), + "Ip6::Address::FromString parsing failed\n"); + } +} + +void TestIp6AddressFromString(void) +{ + Ip6AddressStringTestVector testVectors[] = + { + // Valid full IPv6 address. + { + "0102:0304:0506:0708:090a:0b0c:0d0e:0f00", + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00}, + OT_ERROR_NONE + }, + + // Valid full IPv6 address with mixed capital and small letters. + { + "0102:0304:0506:0708:090a:0B0C:0d0E:0F00", + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00}, + OT_ERROR_NONE + }, + + // Short prefix and full IID. + { + "fd11::abcd:e0e0:d10e:0001", + {0xfd, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xab, 0xcd, 0xe0, 0xe0, 0xd1, 0x0e, 0x00, 0x01}, + OT_ERROR_NONE + }, + + // Valid IPv6 address with unnecessary :: symbol. + { + "fd11:1234:5678:abcd::abcd:e0e0:d10e:1000", + {0xfd, 0x11, 0x12, 0x34, 0x56, 0x78, 0xab, 0xcd, + 0xab, 0xcd, 0xe0, 0xe0, 0xd1, 0x0e, 0x10, 0x00}, + OT_ERROR_NONE + }, + + // Short multicast address. + { + "ff03::0b", + {0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b}, + OT_ERROR_NONE + }, + + // Unspecified address. + { + "::", + {0}, + OT_ERROR_NONE + }, + + // Valid embedded IPv4 address. + { + "64:ff9b::100.200.15.4", + {0x00, 0x64, 0xff, 0x9b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x64, 0xc8, 0x0f, 0x04}, + OT_ERROR_NONE + }, + + // Valid embedded IPv4 address. + { + "2001:db8::abc:def1:127.0.0.1", + {0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0xbc, 0xde, 0xf1, 0x7f, 0x00, 0x00, 0x01}, + OT_ERROR_NONE + }, + + // Two :: should cause a parse error. + { + "2001:db8::a::b", + {0}, + OT_ERROR_PARSE + }, + + // The "g" and "h" are not the hex characters. + { + "2001:db8::abcd:efgh", + {0}, + OT_ERROR_PARSE + }, + + // Too many colons. + { + "1:2:3:4:5:6:7:8:9", + {0}, + OT_ERROR_PARSE + }, + + // Too many characters in a single part. + { + "2001:db8::abc:def12:1:2", + {0}, + OT_ERROR_PARSE + }, + + // Invalid embedded IPv4 address. + { + "64:ff9b::123.231.0.257", + {0}, + OT_ERROR_PARSE + }, + + // Invalid embedded IPv4 address. + { + "64:ff9b::1.22.33", + {0}, + OT_ERROR_PARSE + }, + + // Invalid embedded IPv4 address. + { + "64:ff9b::1.22.33.44.5", + {0}, + OT_ERROR_PARSE + }, + + }; + + for (uint32_t index = 0; index < OT_ARRAY_LENGTH(testVectors); index++) + { + checkAddressFromString(&testVectors[index]); + } +} + +#ifdef ENABLE_TEST_MAIN +int main(void) +{ + TestIp6AddressFromString(); + printf("All tests passed\n"); + return 0; +} +#endif