diff --git a/CHANGES.md b/CHANGES.md index dfdbfb9f5..65072456d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -19,6 +19,8 @@ Changes from ns-3.37 to ns-3.38 ### New API ### Changes to existing API +* (network) **Ipv4Address** and **Ipv6Address** now do not raise an exception if built from an invalid string. Instead the address is marked as not initialized. + ### Changes to build system diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 9b0031168..ebcfa4b76 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -17,6 +17,8 @@ Release 3-dev ------------- ### New user-visible features +- (network) !1163 Initializing an Ipv[4,6]Address from an invalid string do not raise an exception anymore. Instead the address is marked as not initialized. + ### Bugs fixed diff --git a/src/network/utils/ipv4-address.cc b/src/network/utils/ipv4-address.cc index 4ea4cc868..5c48d8a12 100644 --- a/src/network/utils/ipv4-address.cc +++ b/src/network/utils/ipv4-address.cc @@ -24,63 +24,17 @@ #include +#ifdef __WIN32__ +#include +#else +#include +#endif + namespace ns3 { NS_LOG_COMPONENT_DEFINE("Ipv4Address"); -#define ASCII_DOT (0x2e) -#define ASCII_ZERO (0x30) -#define ASCII_SLASH (0x2f) - -/** - * \brief Converts a string representing an IP address into the address - * \param address the address string - * \returns the address - */ -static uint32_t -AsciiToIpv4Host(const char* address) -{ - NS_LOG_FUNCTION(&address); - uint32_t host = 0; - uint8_t numberOfDots = 0; - const char* ptr = address; - - NS_ASSERT_MSG(*ptr != ASCII_DOT, - "Error, can not build an IPv4 address from an invalid string: " << address); - while (true) - { - uint8_t byte = 0; - while (*ptr != ASCII_DOT && *ptr != 0) - { - byte *= 10; - byte += *ptr - ASCII_ZERO; - ptr++; - } - host <<= 8; - host |= byte; - if (*ptr == 0) - { - break; - } - ptr++; - NS_ASSERT_MSG(*ptr != ASCII_DOT, - "Error, can not build an IPv4 address from an invalid string: " << address); - numberOfDots++; - } - NS_ASSERT_MSG(*(ptr - 1) != ASCII_DOT, - "Error, can not build an IPv4 address from an invalid string: " << address); - NS_ASSERT_MSG(numberOfDots == 3, - "Error, can not build an IPv4 address from an invalid string: " << address); - - return host; -} - -} // namespace ns3 - -namespace ns3 -{ - Ipv4Mask::Ipv4Mask() : m_mask(0x66666666) { @@ -96,7 +50,7 @@ Ipv4Mask::Ipv4Mask(uint32_t mask) Ipv4Mask::Ipv4Mask(const char* mask) { NS_LOG_FUNCTION(this << mask); - if (*mask == ASCII_SLASH) + if (*mask == '/') { uint32_t plen = static_cast(std::atoi(++mask)); NS_ASSERT(plen <= 32); @@ -111,7 +65,11 @@ Ipv4Mask::Ipv4Mask(const char* mask) } else { - m_mask = AsciiToIpv4Host(mask); + if (inet_pton(AF_INET, mask, &m_mask) <= 0) + { + NS_ABORT_MSG("Error, can not build an IPv4 mask from an invalid string: " << mask); + } + m_mask = ntohl(m_mask); } } @@ -219,8 +177,16 @@ Ipv4Address::Ipv4Address(uint32_t address) Ipv4Address::Ipv4Address(const char* address) { NS_LOG_FUNCTION(this << address); - m_address = AsciiToIpv4Host(address); + + if (inet_pton(AF_INET, address, &m_address) <= 0) + { + NS_LOG_LOGIC("Error, can not build an IPv4 address from an invalid string: " << address); + m_address = 0; + m_initialized = false; + return; + } m_initialized = true; + m_address = ntohl(m_address); } uint32_t @@ -242,8 +208,15 @@ void Ipv4Address::Set(const char* address) { NS_LOG_FUNCTION(this << address); - m_address = AsciiToIpv4Host(address); + if (inet_pton(AF_INET, address, &m_address) <= 0) + { + NS_LOG_LOGIC("Error, can not build an IPv4 address from an invalid string: " << address); + m_address = 0; + m_initialized = false; + return; + } m_initialized = true; + m_address = ntohl(m_address); } Ipv4Address diff --git a/src/network/utils/ipv6-address.cc b/src/network/utils/ipv6-address.cc index dfc0b0a53..8c160fd59 100644 --- a/src/network/utils/ipv6-address.cc +++ b/src/network/utils/ipv6-address.cc @@ -17,28 +17,6 @@ * Author: Sebastien Vincent */ -// Part of the Ipv6Address::Print function has been adapted from inet_ntop6 Linux function. -// See http://www.net-snmp.org/dev/agent/inet__ntop_8c_source.html -// Author: Paul Vixie, 1996. -// The inet_ntop6 function was under the copyright below, which is -// compatible with GPLv2, see http://www.gnu.org/licenses/license-list.html#GPLCompatibleLicenses. - -/* Copyright (c) 1996 by Internet Software Consortium. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - */ - #include "ipv6-address.h" #include "mac16-address.h" @@ -49,7 +27,13 @@ #include "ns3/log.h" #include -#include +#include + +#ifdef __WIN32__ +#include +#else +#include +#endif namespace ns3 { @@ -165,151 +149,6 @@ extern "C" } #endif -/** - * \brief Convert an IPv6 C-string into a 128-bit representation. - * - * \param address pointer to the char buffer with the address ascii representation - * \param addr the buffer to store the IPv6 address - * - * \return true if success, false otherwise (bad format, ...) - * - * \note This function is strongly inspired by inet_pton6() from Paul Vixie. - * \todo Handle IPv6 address with decimal value for last four bytes. - */ -static bool -AsciiToIpv6Host(const char* address, uint8_t addr[16]) -{ - NS_LOG_FUNCTION(address << &addr); - static const char xdigits_l[] = "0123456789abcdef"; - static const char xdigits_u[] = "0123456789ABCDEF"; - unsigned char tmp[16]; - unsigned char* tp = tmp; - unsigned char* const endp = tp + 16; - unsigned char* colonp = nullptr; - const char* xdigits = nullptr; -#if 0 - const char* curtok = 0; -#endif - int ch = 0; - int seen_xdigits = 0; - unsigned int val = 0; - - memset(tp, 0x00, 16); - - /* Leading :: requires some special handling. */ - if (*address == ':') - { - if (*++address != ':') - { - return (0); - } - } -#if 0 - curtok = address; -#endif - while ((ch = *address++) != '\0') - { - const char* pch = nullptr; - - if ((pch = strchr((xdigits = xdigits_l), ch)) == nullptr) - { - pch = strchr((xdigits = xdigits_u), ch); - } - - if (pch != nullptr) - { - val <<= 4; - val |= (pch - xdigits); - - if (++seen_xdigits > 4) - { - return (0); - } - continue; - } - if (ch == ':') - { -#if 0 - curtok = address; -#endif - - if (!seen_xdigits) - { - if (colonp) - { - return (0); - } - colonp = tp; - continue; - } - - if (endp - tp < 2) - { - return (0); - } - - *tp++ = (unsigned char)(val >> 8) & 0xff; - *tp++ = (unsigned char)val & 0xff; - seen_xdigits = 0; - val = 0; - continue; - } - - /* \todo Handle IPv4 mapped address (2001::192.168.0.1) */ -#if 0 - if (ch == '.' && (endp - tp > 3 /* NS_INADDRSZ - 1 */)) && - inet_pton4 (curtok, tp) > 0) - { - tp += 4 /*NS_INADDRSZ*/; - seen_xdigits = 0; - break; /* '\0' was seen by inet_pton4(). */ - } -#endif - return (0); - } - - if (seen_xdigits) - { - if (endp - tp < 2) - { - return (0); - } - *tp++ = (unsigned char)(val >> 8) & 0xff; - *tp++ = (unsigned char)val & 0xff; - } - - if (colonp != nullptr) - { - /* - * Since some memmove ()'s erroneously fail to handle - * overlapping regions, we'll do the shift by hand. - */ - const int n = tp - colonp; - int i = 0; - - if (tp == endp) - { - return (0); - } - - for (i = 1; i <= n; i++) - { - endp[-i] = colonp[n - i]; - colonp[n - i] = 0; - } - - tp = endp; - } - - if (tp != endp) - { - return (0); - } - - memcpy(addr, tmp, 16); - return (1); -} - Ipv6Address::Ipv6Address() { NS_LOG_FUNCTION(this); @@ -334,7 +173,14 @@ Ipv6Address::Ipv6Address(const Ipv6Address* addr) Ipv6Address::Ipv6Address(const char* address) { NS_LOG_FUNCTION(this << address); - AsciiToIpv6Host(address, m_address); + + if (inet_pton(AF_INET6, address, m_address) <= 0) + { + memset(m_address, 0x00, 16); + NS_LOG_LOGIC("Error, can not build an IPv6 address from an invalid string: " << address); + m_initialized = false; + return; + } m_initialized = true; } @@ -356,7 +202,13 @@ void Ipv6Address::Set(const char* address) { NS_LOG_FUNCTION(this << address); - AsciiToIpv6Host(address, m_address); + if (inet_pton(AF_INET6, address, m_address) <= 0) + { + memset(m_address, 0x00, 16); + NS_LOG_LOGIC("Error, can not build an IPv6 address from an invalid string: " << address); + m_initialized = false; + return; + } m_initialized = true; } @@ -678,93 +530,12 @@ Ipv6Address::Print(std::ostream& os) const { NS_LOG_FUNCTION(this << &os); - // note: part of this function has been adapted from inet_ntop6 Linux function. - // See http://www.net-snmp.org/dev/agent/inet__ntop_8c_source.html - // Author: Paul Vixie, 1996. + char str[INET6_ADDRSTRLEN]; - if (IsIpv4MappedAddress()) + if (inet_ntop(AF_INET6, m_address, str, INET6_ADDRSTRLEN)) { - os << "::ffff:" << (unsigned int)m_address[12] << "." << (unsigned int)m_address[13] << "." - << (unsigned int)m_address[14] << "." << (unsigned int)m_address[15]; - return; + os << str; } - - uint16_t address[8]; - uint8_t i; - - for (i = 0; i < 8; i++) - { - address[i] = (uint16_t(m_address[2 * i]) << 8) | uint16_t(m_address[2 * i + 1]); - } - - int8_t bestBase = -1; - int8_t bestLen = 0; - int8_t curBase = -1; - int8_t curLen = 0; - - for (i = 0; i < 8; i++) - { - if (address[i] == 0) - { - if (curBase == -1) - { - curBase = i; - curLen = 1; - } - else - { - curLen++; - } - } - else - { - if (curBase != -1) - { - if (bestBase == -1 || curLen > bestLen) - { - bestBase = curBase; - bestLen = curLen; - } - curBase = -1; - } - } - } - if (curBase != -1) - { - if (bestBase == -1 || curLen > bestLen) - { - bestBase = curBase; - bestLen = curLen; - } - } - if (bestBase != -1 && bestLen < 2) - { - bestBase = -1; - } - - for (i = 0; i < 8;) - { - // Are we inside the best run of 0x00's? - if (i == bestBase) - { - os << ':'; - i += bestLen; - continue; - } - // Are we following an initial run of 0x00s or any real hex? - if (i != 0) - { - os << ':'; - } - os << std::hex << (unsigned int)address[i]; - i++; - } - // Was it a trailing run of 0x00's? - if (bestBase != -1 && (bestBase + bestLen) == 8) - { - os << ':'; - } - os << std::dec; } bool @@ -1044,7 +815,10 @@ Ipv6Prefix::Ipv6Prefix() Ipv6Prefix::Ipv6Prefix(const char* prefix) { NS_LOG_FUNCTION(this << prefix); - AsciiToIpv6Host(prefix, m_prefix); + if (inet_pton(AF_INET6, prefix, m_prefix) <= 0) + { + NS_ABORT_MSG("Error, can not build an IPv6 prefix from an invalid string: " << prefix); + } m_prefixLength = GetMinimumPrefixLength(); } @@ -1058,8 +832,10 @@ Ipv6Prefix::Ipv6Prefix(uint8_t prefix[16]) Ipv6Prefix::Ipv6Prefix(const char* prefix, uint8_t prefixLength) { NS_LOG_FUNCTION(this << prefix); - AsciiToIpv6Host(prefix, m_prefix); - + if (inet_pton(AF_INET6, prefix, m_prefix) <= 0) + { + NS_ABORT_MSG("Error, can not build an IPv6 prefix from an invalid string: " << prefix); + } uint8_t autoLength = GetMinimumPrefixLength(); NS_ASSERT_MSG(autoLength <= prefixLength, "Ipv6Prefix: address and prefix are not compatible: " << Ipv6Address(prefix)