From 180ad61f815692fc71531962bea8e8e57478ff15 Mon Sep 17 00:00:00 2001 From: Thomas Jarosch Date: Sat, 4 Sep 2004 20:44:14 +0000 Subject: [PATCH] libi2ncommon: (tomj) to_cidr() function, fixed get_mask_bits, ip_type::NETWORK cidr support --- src/ipfunc.cpp | 173 +++++++++++++++++++++++++++++++++++++++++++- src/ipfunc.hxx | 3 + test/ip_range.cpp | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 382 insertions(+), 2 deletions(-) diff --git a/src/ipfunc.cpp b/src/ipfunc.cpp index ee44536..bb9e547 100644 --- a/src/ipfunc.cpp +++ b/src/ipfunc.cpp @@ -17,6 +17,8 @@ using namespace std; using namespace ip_type; +#include + // can decode IP, IP-IP (as range) and IP/MASK (as network) IP_RANGE::IP_RANGE(const std::string& ip) { @@ -59,9 +61,24 @@ void IP_RANGE::load(type t, const std::string& ip, const std::string& mask_or_en } else if (t==NETWORK) { - if(!inet_aton(ip.c_str(),&ia_ip1) || !inet_aton(mask_or_end.c_str(),&ia_ip2)) + // TODO: Better IP checks: "16" != "0.0.0.16" + if(!inet_aton(ip.c_str(),&ia_ip1)) throw runtime_error("invalid IP given"); + // Check if mask is in cidr notation + if (mask_or_end.find(".") == string::npos) { + unsigned int calc_mask = 0; + istringstream in(mask_or_end); + in >> calc_mask; + + if(calc_mask > 32) + throw runtime_error("invalid cidr mask given"); + + ia_ip2.s_addr = calc_netmask_from_cidr(calc_mask); + } else + if (!inet_aton(mask_or_end.c_str(),&ia_ip2)) + throw runtime_error("invalid IP given"); + this->ip=ia_ip1.s_addr; this->mask=ia_ip2.s_addr; @@ -192,6 +209,47 @@ std::string IP_RANGE::to_string(void) const return output; } +vector IP_RANGE::to_cidr(void) const +{ + vector cidrs; + + if (t==IP) { + cidrs.push_back(to_string()+"/32"); + } else if (t==NETWORK) { + ostringstream out; + out << ip_string(ip) << "/" << get_mask_bits(); + cidrs.push_back(out.str()); + } else if (t==RANGE) { + // do the real work + unsigned int cidr_addr = turn_ip(ip), cidr_end = turn_ip(end); + + // special case: 0.0.0.0-255.255.255.255 + if (cidr_addr == 0 && cidr_end == 0xFFFFFFFF) { + cidrs.push_back("0.0.0.0/0"); + } else { + ostringstream out; + + unsigned int bit = 0, mask = 0; + while (cidr_addr <= cidr_end) { + mask |= (1 << bit); + if ((cidr_addr & mask) || ((cidr_addr | mask) > cidr_end)) { + out.str(""); + out << ip_string(turn_ip(cidr_addr)) << "/" << 32-bit; + cidrs.push_back(out.str()); + + cidr_addr += (1 << bit); + bit = 0; + mask = 0; + } else { + bit++; + } + } + } + } + + return cidrs; +} + unsigned int IP_RANGE::turn_ip(unsigned int src) { int dst; @@ -208,6 +266,8 @@ unsigned int IP_RANGE::turn_ip(unsigned int src) unsigned int IP_RANGE::calc_netmask_bits(unsigned int netmask) { + netmask = turn_ip(netmask); + switch (netmask) { case 0x00000000: @@ -280,6 +340,116 @@ unsigned int IP_RANGE::calc_netmask_bits(unsigned int netmask) } } +unsigned int IP_RANGE::calc_netmask_from_cidr(unsigned int cidr) +{ + unsigned int rtn=0; + + switch (cidr) + { + case 0: + rtn=0x00000000; + break; + case 1: + rtn=0x80000000; + break; + case 2: + rtn=0xC0000000; + break; + case 3: + rtn=0xE0000000; + break; + case 4: + rtn=0xE0000000; + break; + case 5: + rtn=0xF8000000; + break; + case 6: + rtn=0xFC000000; + break; + case 7: + rtn=0xFE000000; + break; + case 8: + rtn=0xFF000000; + break; + case 9: + rtn=0xFF800000; + break; + case 10: + rtn=0xFFC00000; + break; + case 11: + rtn=0xFFE00000; + break; + case 12: + rtn=0xFFF00000; + break; + case 13: + rtn=0xFFF80000; + break; + case 14: + rtn=0xFFFC0000; + break; + case 15: + rtn=0xFFFE0000; + break; + case 16: + rtn=0xFFFF0000; + break; + case 17: + rtn=0xFFFF8000; + break; + case 18: + rtn=0xFFFFC000; + break; + case 19: + rtn=0xFFFFE000; + break; + case 20: + rtn=0xFFFFF000; + break; + case 21: + rtn=0xFFFFF800; + break; + case 22: + rtn=0xFFFFFC00; + break; + case 23: + rtn=0xFFFFFE00; + break; + case 24: + rtn=0xFFFFFF00; + break; + case 25: + rtn=0xFFFFFF80; + break; + case 26: + rtn=0xFFFFFFC0; + break; + case 27: + rtn=0xFFFFFFE0; + break; + case 28: + rtn=0xFFFFFFF0; + break; + case 29: + rtn=0xFFFFFFF8; + break; + case 30: + rtn=0xFFFFFFFC; + break; + case 31: + rtn=0xFFFFFFFE; + break; + case 32: + default: + rtn=0xFFFFFFFF; + } + + return turn_ip(rtn); +} + std::string IP_RANGE::ip_string(unsigned int ip) { struct in_addr ia_ip; @@ -292,4 +462,3 @@ std::string IP_RANGE::ip_string(unsigned int ip) else return buffer; } - diff --git a/src/ipfunc.hxx b/src/ipfunc.hxx index bf2bc52..dead12f 100644 --- a/src/ipfunc.hxx +++ b/src/ipfunc.hxx @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -46,6 +47,7 @@ class IP_RANGE // returns the complete IP_RANGE std::string to_string(void) const; + std::vector to_cidr(void) const; unsigned int get_mask_bits() const { return calc_netmask_bits(mask); } @@ -59,6 +61,7 @@ class IP_RANGE // static IP utility functions static unsigned int turn_ip(unsigned int src); static unsigned int calc_netmask_bits(unsigned int mask); + static unsigned int calc_netmask_from_cidr(unsigned int cidr); static std::string ip_string(unsigned int ip); }; diff --git a/test/ip_range.cpp b/test/ip_range.cpp index a75dd2a..037b0b4 100644 --- a/test/ip_range.cpp +++ b/test/ip_range.cpp @@ -26,6 +26,7 @@ class ip_range : public TestFixture CPPUNIT_TEST(ConstructIP2); CPPUNIT_TEST(ConstructNet1); CPPUNIT_TEST(ConstructNet2); + CPPUNIT_TEST(ConstructNet3); CPPUNIT_TEST(ConstructRange1); CPPUNIT_TEST(ConstructRange2); CPPUNIT_TEST(ConstructRangeSwap); @@ -62,9 +63,22 @@ class ip_range : public TestFixture CPPUNIT_TEST(OperatorPlus2); CPPUNIT_TEST(OperatorPlusOverflow); CPPUNIT_TEST(OperatorMinus); + CPPUNIT_TEST(NetmaskToBits1); + CPPUNIT_TEST(NetmaskToBits2); + CPPUNIT_TEST(NetmaskToBits3); + CPPUNIT_TEST(NetmaskToBits4); + CPPUNIT_TEST(Range2Cidr1); + CPPUNIT_TEST(Range2Cidr2); + CPPUNIT_TEST(Range2Cidr3); + CPPUNIT_TEST(Range2Cidr4); + CPPUNIT_TEST(Range2Cidr5); + CPPUNIT_TEST(Range2Cidr6); + CPPUNIT_TEST(Range2Cidr7); CPPUNIT_TEST_SUITE_END(); + + public: void setUp() { @@ -74,6 +88,19 @@ class ip_range : public TestFixture { } + void compare_vector(const vector &a, const vector &b) + { + if (a.size() != b.size()) + throw runtime_error("vector sizes don't match"); + + for(vector::const_iterator i=a.begin(), ie=a.end(), + check_i = b.begin(); i != ie; i++, check_i++) + { + if (*i != *check_i) + throw runtime_error(*i + " doesn't match " + *check_i); + } + } + void ConstructIP1() { IP_RANGE i("192.168.1.1"); @@ -98,6 +125,12 @@ class ip_range : public TestFixture CPPUNIT_ASSERT_EQUAL(string("192.168.1.0/255.255.255.0"),i.to_string()); } + void ConstructNet3() + { + IP_RANGE i("172.16.0.0/16"); + CPPUNIT_ASSERT_EQUAL(string("172.16.0.0/255.255.0.0"),i.to_string()); + } + void ConstructRange1() { IP_RANGE i("192.168.1.5-192.168.3.1"); @@ -379,6 +412,181 @@ class ip_range : public TestFixture CPPUNIT_ASSERT_EQUAL(256,a-b); } + + void NetmaskToBits1() + { + IP_RANGE a("255.255.255.255"); + int bits = a.calc_netmask_bits(a.get_base()); + CPPUNIT_ASSERT_EQUAL(32,bits); + } + + void NetmaskToBits2() + { + IP_RANGE a("255.255.255.0"); + int bits = a.calc_netmask_bits(a.get_base()); + CPPUNIT_ASSERT_EQUAL(24,bits); + } + + void NetmaskToBits3() + { + IP_RANGE a("255.255.0.0"); + int bits = a.calc_netmask_bits(a.get_base()); + CPPUNIT_ASSERT_EQUAL(16,bits); + } + + void NetmaskToBits4() + { + IP_RANGE a("255.0.0.0"); + int bits = a.calc_netmask_bits(a.get_base()); + CPPUNIT_ASSERT_EQUAL(8,bits); + } + void Range2Cidr1() + { + IP_RANGE range("192.168.1.100-192.168.1.227"); + vector cidrs = range.to_cidr(); + + vector check_cidrs; + check_cidrs.push_back("192.168.1.100/30"); + check_cidrs.push_back("192.168.1.104/29"); + check_cidrs.push_back("192.168.1.112/28"); + check_cidrs.push_back("192.168.1.128/26"); + check_cidrs.push_back("192.168.1.192/27"); + check_cidrs.push_back("192.168.1.224/30"); + +/* + cerr << "Range: " << range.to_string() << endl; + for(vector::const_iterator i=cidrs.begin(), ie=cidrs.end(); i != ie; i++) + cerr << *i << endl; +*/ + compare_vector(cidrs, check_cidrs); + } + + void Range2Cidr2() + { + IP_RANGE range("0.0.0.0-255.255.255.255"); + vector cidrs = range.to_cidr(); + + vector check_cidrs; + check_cidrs.push_back("0.0.0.0/0"); + + compare_vector(cidrs, check_cidrs); + } + + void Range2Cidr3() + { + IP_RANGE range("192.168.1.3"); + vector cidrs = range.to_cidr(); + + vector check_cidrs; + check_cidrs.push_back("192.168.1.3/32"); + + compare_vector(cidrs, check_cidrs); + } + + void Range2Cidr4() + { + IP_RANGE range("172.16.0.0/16"); + vector cidrs = range.to_cidr(); + + vector check_cidrs; + check_cidrs.push_back("172.16.0.0/16"); + + compare_vector(cidrs, check_cidrs); + } + + void Range2Cidr5() + { + IP_RANGE range(ip_type::NETWORK, "172.16.0.0", "255.255.0.0"); + vector cidrs = range.to_cidr(); + + vector check_cidrs; + check_cidrs.push_back("172.16.0.0/16"); + + compare_vector(cidrs, check_cidrs); + } + void Range2Cidr6() + { + IP_RANGE range("192.168.1.0-192.168.2.0"); + vector cidrs = range.to_cidr(); + + vector check_cidrs; + check_cidrs.push_back("192.168.1.0/24"); + check_cidrs.push_back("192.168.2.0/32"); + + compare_vector(cidrs, check_cidrs); + } + + void Range2Cidr7() + { + IP_RANGE range("0.0.0.1-255.255.255.254"); + vector cidrs = range.to_cidr(); + + vector check_cidrs; + check_cidrs.push_back("0.0.0.1/32"); + check_cidrs.push_back("0.0.0.2/31"); + check_cidrs.push_back("0.0.0.4/30"); + check_cidrs.push_back("0.0.0.8/29"); + check_cidrs.push_back("0.0.0.16/28"); + check_cidrs.push_back("0.0.0.32/27"); + check_cidrs.push_back("0.0.0.64/26"); + check_cidrs.push_back("0.0.0.128/25"); + check_cidrs.push_back("0.0.1.0/24"); + check_cidrs.push_back("0.0.2.0/23"); + check_cidrs.push_back("0.0.4.0/22"); + check_cidrs.push_back("0.0.8.0/21"); + check_cidrs.push_back("0.0.16.0/20"); + check_cidrs.push_back("0.0.32.0/19"); + check_cidrs.push_back("0.0.64.0/18"); + check_cidrs.push_back("0.0.128.0/17"); + check_cidrs.push_back("0.1.0.0/16"); + check_cidrs.push_back("0.2.0.0/15"); + check_cidrs.push_back("0.4.0.0/14"); + check_cidrs.push_back("0.8.0.0/13"); + check_cidrs.push_back("0.16.0.0/12"); + check_cidrs.push_back("0.32.0.0/11"); + check_cidrs.push_back("0.64.0.0/10"); + check_cidrs.push_back("0.128.0.0/9"); + check_cidrs.push_back("1.0.0.0/8"); + check_cidrs.push_back("2.0.0.0/7"); + check_cidrs.push_back("4.0.0.0/6"); + check_cidrs.push_back("8.0.0.0/5"); + check_cidrs.push_back("16.0.0.0/4"); + check_cidrs.push_back("32.0.0.0/3"); + check_cidrs.push_back("64.0.0.0/2"); + check_cidrs.push_back("128.0.0.0/2"); + check_cidrs.push_back("192.0.0.0/3"); + check_cidrs.push_back("224.0.0.0/4"); + check_cidrs.push_back("240.0.0.0/5"); + check_cidrs.push_back("248.0.0.0/6"); + check_cidrs.push_back("252.0.0.0/7"); + check_cidrs.push_back("254.0.0.0/8"); + check_cidrs.push_back("255.0.0.0/9"); + check_cidrs.push_back("255.128.0.0/10"); + check_cidrs.push_back("255.192.0.0/11"); + check_cidrs.push_back("255.224.0.0/12"); + check_cidrs.push_back("255.240.0.0/13"); + check_cidrs.push_back("255.248.0.0/14"); + check_cidrs.push_back("255.252.0.0/15"); + check_cidrs.push_back("255.254.0.0/16"); + check_cidrs.push_back("255.255.0.0/17"); + check_cidrs.push_back("255.255.128.0/18"); + check_cidrs.push_back("255.255.192.0/19"); + check_cidrs.push_back("255.255.224.0/20"); + check_cidrs.push_back("255.255.240.0/21"); + check_cidrs.push_back("255.255.248.0/22"); + check_cidrs.push_back("255.255.252.0/23"); + check_cidrs.push_back("255.255.254.0/24"); + check_cidrs.push_back("255.255.255.0/25"); + check_cidrs.push_back("255.255.255.128/26"); + check_cidrs.push_back("255.255.255.192/27"); + check_cidrs.push_back("255.255.255.224/28"); + check_cidrs.push_back("255.255.255.240/29"); + check_cidrs.push_back("255.255.255.248/30"); + check_cidrs.push_back("255.255.255.252/31"); + check_cidrs.push_back("255.255.255.254/32"); + + compare_vector(cidrs, check_cidrs); + } }; CPPUNIT_TEST_SUITE_REGISTRATION(ip_range); -- 1.7.1