]> granicus.if.org Git - pdns/commitdiff
implement ComboAddress::truncate() - 24 leaves the first 3 octets for IPv4. 0 leaves...
authorbert hubert <bert.hubert@netherlabs.nl>
Fri, 4 Sep 2015 09:45:20 +0000 (11:45 +0200)
committerbert hubert <bert.hubert@netherlabs.nl>
Fri, 4 Sep 2015 09:45:20 +0000 (11:45 +0200)
pdns/iputils.cc
pdns/iputils.hh
pdns/test-iputils_hh.cc

index ec8fa06055bdbc0c06ee85df595218dcd729d1b0..6e602090974bdc0d3862571a1b07296b761b68ca 100644 (file)
@@ -160,3 +160,36 @@ void fillMSGHdr(struct msghdr* msgh, struct iovec* iov, char* cbuf, size_t cbufs
   msgh->msg_iovlen = 1;
   msgh->msg_flags = 0;
 }
+
+void ComboAddress::truncate(unsigned int bits)
+{
+  uint8_t* start;
+  int len=4;
+  if(sin4.sin_family==AF_INET) {
+    if(bits > 32)
+      return;
+    start = (uint8_t*)&sin4.sin_addr.s_addr;
+    len=4;
+  }
+  else {
+    if(bits > 128)
+      return;
+    start = (uint8_t*)&sin6.sin6_addr.s6_addr;
+    len=16;
+  }
+
+
+  auto tozero= len*8 - bits; // if set to 22, this will clear 1 byte, as it should
+
+  memset(start + len - tozero/8, 0, tozero/8); // blot out the whole bytes on the right
+  
+  auto bitsleft=tozero % 8; // 2 bits left to clear
+
+  // a b c d, to truncate to 22 bits, we just zeroed 'd' and need to zero 2 bits from c
+  // so and by '11111100', which is ~((1<<2)-1)  = ~3
+  uint8_t* place = start + len - 1 - tozero/8; 
+
+
+
+  *place &= (~((1<<bitsleft)-1));
+}
index f1c37c85535fe2949567827f439f69cc8937c297..489bba0b525157fb703540af06db85907705be60 100644 (file)
@@ -204,6 +204,8 @@ union ComboAddress {
     else
       return "["+toString() + "]:" + boost::lexical_cast<string>(ntohs(sin4.sin_port));
   }
+
+  void truncate(unsigned int bits);
 };
 
 /** This exception is thrown by the Netmask class and by extension by the NetmaskGroup class */
index ea6523a0358fb70565cdaebc58b3f3fc4f3da782..89076bd4858eb333cb993b53fd2de9114d921c83 100644 (file)
@@ -4,6 +4,7 @@
 #include "config.h"
 #endif
 #include <boost/test/unit_test.hpp>
+#include <bitset>
 #include "iputils.hh"
 
 using namespace boost;
@@ -34,6 +35,95 @@ BOOST_AUTO_TEST_CASE(test_ComboAddress) {
   BOOST_CHECK_EQUAL(withport.sin4.sin_port, htons(5300));
 }
 
+BOOST_AUTO_TEST_CASE(test_ComboAddressTruncate) {
+  ComboAddress ca4("130.161.252.29");
+  ca4.truncate(24);
+  BOOST_CHECK_EQUAL(ca4.toString(), "130.161.252.0");
+  ca4.truncate(16);
+  BOOST_CHECK_EQUAL(ca4.toString(), "130.161.0.0");
+
+
+
+  ca4 = ComboAddress("130.161.252.29");
+  ComboAddress orig(ca4);
+  for(int n=32; n; --n) {
+    ca4.truncate(n);
+
+    uint32_t p;
+    memcpy(&p, (char*)&ca4.sin4.sin_addr.s_addr, 4);
+    std::bitset<32> result(htonl(p));
+
+    memcpy(&p, (char*)&orig.sin4.sin_addr.s_addr, 4);
+    std::bitset<32> manual(htonl(p));
+
+    auto tokill=32-n;
+    for(int i =0; i< tokill; ++i)
+      manual.set(i, 0);
+
+    BOOST_CHECK_EQUAL(result, manual);
+  }
+
+  ca4 = ComboAddress("130.161.252.29");
+  ca4.truncate(31);
+  BOOST_CHECK_EQUAL(ca4.toString(), "130.161.252.28");
+
+  ca4.truncate(30);
+  BOOST_CHECK_EQUAL(ca4.toString(), "130.161.252.28");
+
+  ca4.truncate(29);
+  BOOST_CHECK_EQUAL(ca4.toString(), "130.161.252.24");
+  
+  ca4.truncate(23);
+  BOOST_CHECK_EQUAL(ca4.toString(), "130.161.252.0");
+
+  ca4.truncate(22);
+  BOOST_CHECK_EQUAL(ca4.toString(), "130.161.252.0");
+
+  ca4.truncate(21);
+  BOOST_CHECK_EQUAL(ca4.toString(), "130.161.248.0");
+
+  ComboAddress ca6("2001:888:2000:1d::2");
+  ca6.truncate(120);
+  BOOST_CHECK_EQUAL(ca6.toString(), "2001:888:2000:1d::");
+  ca6.truncate(64);
+  BOOST_CHECK_EQUAL(ca6.toString(), "2001:888:2000:1d::");
+  ca6.truncate(72);                  // 0102 304 0506 78
+  BOOST_CHECK_EQUAL(ca6.toString(), "2001:888:2000:1d::");
+  ca6.truncate(56);
+  BOOST_CHECK_EQUAL(ca6.toString(), "2001:888:2000::");
+  ca6.truncate(48);
+  BOOST_CHECK_EQUAL(ca6.toString(), "2001:888:2000::");
+  ca6.truncate(32);
+  BOOST_CHECK_EQUAL(ca6.toString(), "2001:888::");
+  ca6.truncate(16);
+  BOOST_CHECK_EQUAL(ca6.toString(), "2001::");
+  ca6.truncate(8);
+  BOOST_CHECK_EQUAL(ca6.toString(), "2000::");
+  
+
+  orig=ca6=ComboAddress("2001:888:2000:1d::2");
+  for(int n=128; n; --n) {
+    ca6.truncate(n);
+
+    std::bitset<128> result, manual;
+    for(int i=0; i < 16; ++i) {
+      result<<=8;
+      result|= std::bitset<128>(*((unsigned char*)&ca6.sin6.sin6_addr.s6_addr + i));
+
+      manual<<=8;
+      manual|= std::bitset<128>(*((unsigned char*)&orig.sin6.sin6_addr.s6_addr + i));
+    }
+
+    auto tokill=128-n;
+    for(int i =0; i< tokill; ++i)
+      manual.set(i, 0);
+
+    BOOST_CHECK_EQUAL(result, manual);
+  }
+
+
+}
+
 BOOST_AUTO_TEST_CASE(test_Netmask) {
   ComboAddress local("127.0.0.1", 53);
   ComboAddress remote("130.161.252.29", 53);