network: allow graceful failure on creation of Ipv[4,6]Address from string
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -24,63 +24,17 @@
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#ifdef __WIN32__
|
||||
#include <WS2tcpip.h>
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#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<uint32_t>(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
|
||||
|
||||
@@ -17,28 +17,6 @@
|
||||
* 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 "mac16-address.h"
|
||||
@@ -49,7 +27,13 @@
|
||||
#include "ns3/log.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <memory.h>
|
||||
#include <memory>
|
||||
|
||||
#ifdef __WIN32__
|
||||
#include <WS2tcpip.h>
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#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)
|
||||
|
||||
Reference in New Issue
Block a user