network: allow graceful failure on creation of Ipv[4,6]Address from string

This commit is contained in:
Tommaso Pecorella
2022-10-23 01:23:58 +02:00
parent a1b2f2a22c
commit 0346179372
4 changed files with 66 additions and 313 deletions

View File

@@ -19,6 +19,8 @@ Changes from ns-3.37 to ns-3.38
### New API ### New API
### Changes to existing 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 ### Changes to build system

View File

@@ -17,6 +17,8 @@ Release 3-dev
------------- -------------
### New user-visible features ### 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 ### Bugs fixed

View File

@@ -24,63 +24,17 @@
#include <cstdlib> #include <cstdlib>
#ifdef __WIN32__
#include <WS2tcpip.h>
#else
#include <arpa/inet.h>
#endif
namespace ns3 namespace ns3
{ {
NS_LOG_COMPONENT_DEFINE("Ipv4Address"); 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() Ipv4Mask::Ipv4Mask()
: m_mask(0x66666666) : m_mask(0x66666666)
{ {
@@ -96,7 +50,7 @@ Ipv4Mask::Ipv4Mask(uint32_t mask)
Ipv4Mask::Ipv4Mask(const char* mask) Ipv4Mask::Ipv4Mask(const char* mask)
{ {
NS_LOG_FUNCTION(this << mask); NS_LOG_FUNCTION(this << mask);
if (*mask == ASCII_SLASH) if (*mask == '/')
{ {
uint32_t plen = static_cast<uint32_t>(std::atoi(++mask)); uint32_t plen = static_cast<uint32_t>(std::atoi(++mask));
NS_ASSERT(plen <= 32); NS_ASSERT(plen <= 32);
@@ -111,7 +65,11 @@ Ipv4Mask::Ipv4Mask(const char* mask)
} }
else 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) Ipv4Address::Ipv4Address(const char* address)
{ {
NS_LOG_FUNCTION(this << 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_initialized = true;
m_address = ntohl(m_address);
} }
uint32_t uint32_t
@@ -242,8 +208,15 @@ void
Ipv4Address::Set(const char* address) Ipv4Address::Set(const char* address)
{ {
NS_LOG_FUNCTION(this << 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_initialized = true;
m_address = ntohl(m_address);
} }
Ipv4Address Ipv4Address

View File

@@ -17,28 +17,6 @@
* Author: Sebastien Vincent <vincent@clarinet.u-strasbg.fr> * Author: Sebastien Vincent <vincent@clarinet.u-strasbg.fr>
*/ */
// 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 "ipv6-address.h"
#include "mac16-address.h" #include "mac16-address.h"
@@ -49,7 +27,13 @@
#include "ns3/log.h" #include "ns3/log.h"
#include <iomanip> #include <iomanip>
#include <memory.h> #include <memory>
#ifdef __WIN32__
#include <WS2tcpip.h>
#else
#include <arpa/inet.h>
#endif
namespace ns3 namespace ns3
{ {
@@ -165,151 +149,6 @@ extern "C"
} }
#endif #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() Ipv6Address::Ipv6Address()
{ {
NS_LOG_FUNCTION(this); NS_LOG_FUNCTION(this);
@@ -334,7 +173,14 @@ Ipv6Address::Ipv6Address(const Ipv6Address* addr)
Ipv6Address::Ipv6Address(const char* address) Ipv6Address::Ipv6Address(const char* address)
{ {
NS_LOG_FUNCTION(this << 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; m_initialized = true;
} }
@@ -356,7 +202,13 @@ void
Ipv6Address::Set(const char* address) Ipv6Address::Set(const char* address)
{ {
NS_LOG_FUNCTION(this << 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; m_initialized = true;
} }
@@ -678,93 +530,12 @@ Ipv6Address::Print(std::ostream& os) const
{ {
NS_LOG_FUNCTION(this << &os); NS_LOG_FUNCTION(this << &os);
// note: part of this function has been adapted from inet_ntop6 Linux function. char str[INET6_ADDRSTRLEN];
// See http://www.net-snmp.org/dev/agent/inet__ntop_8c_source.html
// Author: Paul Vixie, 1996.
if (IsIpv4MappedAddress()) if (inet_ntop(AF_INET6, m_address, str, INET6_ADDRSTRLEN))
{ {
os << "::ffff:" << (unsigned int)m_address[12] << "." << (unsigned int)m_address[13] << "." os << str;
<< (unsigned int)m_address[14] << "." << (unsigned int)m_address[15];
return;
} }
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 bool
@@ -1044,7 +815,10 @@ Ipv6Prefix::Ipv6Prefix()
Ipv6Prefix::Ipv6Prefix(const char* prefix) Ipv6Prefix::Ipv6Prefix(const char* prefix)
{ {
NS_LOG_FUNCTION(this << 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(); m_prefixLength = GetMinimumPrefixLength();
} }
@@ -1058,8 +832,10 @@ Ipv6Prefix::Ipv6Prefix(uint8_t prefix[16])
Ipv6Prefix::Ipv6Prefix(const char* prefix, uint8_t prefixLength) Ipv6Prefix::Ipv6Prefix(const char* prefix, uint8_t prefixLength)
{ {
NS_LOG_FUNCTION(this << 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);
}
uint8_t autoLength = GetMinimumPrefixLength(); uint8_t autoLength = GetMinimumPrefixLength();
NS_ASSERT_MSG(autoLength <= prefixLength, NS_ASSERT_MSG(autoLength <= prefixLength,
"Ipv6Prefix: address and prefix are not compatible: " << Ipv6Address(prefix) "Ipv6Prefix: address and prefix are not compatible: " << Ipv6Address(prefix)