diff --git a/src/IPAddr.cc b/src/IPAddr.cc index 09248dadfa..3dc0025c2d 100644 --- a/src/IPAddr.cc +++ b/src/IPAddr.cc @@ -1,5 +1,7 @@ // See the file "COPYING" in the main distribution directory for copyright. +#include +#include #include "IPAddr.h" #include "Reporter.h" @@ -65,13 +67,48 @@ void IPAddr::ReverseMask(int top_bits_to_chop) memcpy(in6.s6_addr, tmp, sizeof(in6.s6_addr)); } +std::string IPAddr::CanonIPv4(const std::string& input) + { + vector parts; + string output; + size_t start = 0; + size_t end; + + do + { + end = input.find('.', start); + string p; + bool in_leading_zeroes = true; + for ( size_t i = start; i != end && i < input.size(); ++i ) + { + if ( in_leading_zeroes && input[i] == '0' ) continue; + in_leading_zeroes = false; + p.push_back(input[i]); + } + + if ( p.size() == 0 ) + p.push_back('0'); + parts.push_back(p); + start = end + 1; + } while ( end != string::npos ); + + for ( size_t i = 0; i < parts.size(); ++i ) + { + if ( i > 0 ) + output += '.'; + output += parts[i]; + } + + return output; + } + void IPAddr::Init(const std::string& s) { if ( s.find(':') == std::string::npos ) // IPv4. { memcpy(in6.s6_addr, v4_mapped_prefix, sizeof(v4_mapped_prefix)); - if ( inet_pton(AF_INET, s.c_str(), &in6.s6_addr[12]) <=0 ) + if ( inet_pton(AF_INET, CanonIPv4(s).c_str(), &in6.s6_addr[12]) <=0 ) { reporter->Error("Bad IP address: %s", s.c_str()); memset(in6.s6_addr, 0, sizeof(in6.s6_addr)); diff --git a/src/IPAddr.h b/src/IPAddr.h index c2e57ea7d1..96e70689b4 100644 --- a/src/IPAddr.h +++ b/src/IPAddr.h @@ -261,6 +261,14 @@ public: unsigned int MemoryAllocation() const { return padded_sizeof(*this); } + /** + * Returns a canonicalized IPv4 dotted-decimal string such that + * leading zeroes of each decimal part are removed. + * + * @param s String containing an IPv4 address in dotted-decimal notation. + */ + static std::string CanonIPv4(const std::string& s); + private: /** * Initializes an address instance from a string representation. diff --git a/testing/btest/Baseline/bifs.to_addr/output b/testing/btest/Baseline/bifs.to_addr/output new file mode 100644 index 0000000000..bcfdd3b6a2 --- /dev/null +++ b/testing/btest/Baseline/bifs.to_addr/output @@ -0,0 +1,8 @@ +to_addr(0.0.0.0) = 0.0.0.0 (SUCCESS) +to_addr(1.2.3.4) = 1.2.3.4 (SUCCESS) +to_addr(01.02.03.04) = 1.2.3.4 (SUCCESS) +to_addr(001.002.003.004) = 1.2.3.4 (SUCCESS) +to_addr(10.20.30.40) = 10.20.30.40 (SUCCESS) +to_addr(100.200.30.40) = 100.200.30.40 (SUCCESS) +to_addr(10.0.0.0) = 10.0.0.0 (SUCCESS) +to_addr(10.00.00.000) = 10.0.0.0 (SUCCESS) diff --git a/testing/btest/bifs/to_addr.bro b/testing/btest/bifs/to_addr.bro new file mode 100644 index 0000000000..67ce79c795 --- /dev/null +++ b/testing/btest/bifs/to_addr.bro @@ -0,0 +1,18 @@ +# @TEST-EXEC: bro %INPUT >output +# @TEST-EXEC: btest-diff output + +function test_to_addr(ip: string, expect: addr) + { + local result = to_addr(ip); + print fmt("to_addr(%s) = %s (%s)", ip, result, + result == expect ? "SUCCESS" : "FAILURE"); + } + +test_to_addr("0.0.0.0", 0.0.0.0); +test_to_addr("1.2.3.4", 1.2.3.4); +test_to_addr("01.02.03.04", 1.2.3.4); +test_to_addr("001.002.003.004", 1.2.3.4); +test_to_addr("10.20.30.40", 10.20.30.40); +test_to_addr("100.200.30.40", 100.200.30.40); +test_to_addr("10.0.0.0", 10.0.0.0); +test_to_addr("10.00.00.000", 10.0.0.0);