libi2ncommon: (tomj) to_cidr() function, fixed get_mask_bits, ip_type::NETWORK cidr...
authorThomas Jarosch <thomas.jarosch@intra2net.com>
Sat, 4 Sep 2004 20:44:14 +0000 (20:44 +0000)
committerThomas Jarosch <thomas.jarosch@intra2net.com>
Sat, 4 Sep 2004 20:44:14 +0000 (20:44 +0000)
src/ipfunc.cpp
src/ipfunc.hxx
test/ip_range.cpp

index ee44536..bb9e547 100644 (file)
@@ -17,6 +17,8 @@
 using namespace std;
 using namespace ip_type;
 
+#include <iostream>
+
 // 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<string> IP_RANGE::to_cidr(void) const
+{
+    vector<string> 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;
 }
-
index bf2bc52..dead12f 100644 (file)
@@ -12,6 +12,7 @@
 #include <string>
 #include <map>
 #include <set>
+#include <vector>
 
 #include <ip_type.hxx>
 
@@ -46,6 +47,7 @@ class IP_RANGE
         
         // returns the complete IP_RANGE
         std::string to_string(void) const;
+        std::vector<std::string> 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);
 };
 
index a75dd2a..037b0b4 100644 (file)
@@ -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<string> &a, const vector<string> &b)
+        {
+            if (a.size() != b.size())
+                throw runtime_error("vector sizes don't match");
+            
+            for(vector<string>::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<string> cidrs = range.to_cidr();
+            
+            vector<string> 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<string>::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<string> cidrs = range.to_cidr();
+            
+            vector<string> 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<string> cidrs = range.to_cidr();
+            
+            vector<string> 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<string> cidrs = range.to_cidr();
+            
+            vector<string> 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<string> cidrs = range.to_cidr();
+            
+            vector<string> 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<string> cidrs = range.to_cidr();
+            
+            vector<string> 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<string> cidrs = range.to_cidr();
+            
+            vector<string> 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);