]> granicus.if.org Git - pdns/commitdiff
made dnswasher support ipcipher
authorbert hubert <bert.hubert@netherlabs.nl>
Fri, 16 Feb 2018 09:03:39 +0000 (10:03 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 25 Mar 2019 09:22:41 +0000 (10:22 +0100)
pdns/Makefile.am
pdns/dnswasher.cc

index 23a71deebd2f2b8b94e029ed0f770b01ec915857..acfc9d5c7456478cb35a507722a449a6f5019b9a 100644 (file)
@@ -881,18 +881,22 @@ speedtest_LDADD = $(LIBCRYPTO_LIBS) \
        $(RT_LIBS)
 
 dnswasher_SOURCES = \
+       base64.cc \
        dnslabeltext.cc \
        dnsname.hh dnsname.cc \
        dnsparser.hh \
        dnspcap.cc dnspcap.hh \
        dnswasher.cc \
        dnswriter.hh \
+       ipcipher.cc ipcipher.hh ../ext/ipcrypt/ipcrypt.c ../ext/ipcrypt/ipcrypt.h \
        logger.cc \
        misc.cc \
        qtype.cc \
        statbag.cc \
        unix_utility.cc
 
+dnswasher_LDFLAGS =    $(AM_LDFLAGS) $(BOOST_PROGRAM_OPTIONS_LDFLAGS)  $(LIBCRYPTO_LDFLAGS) 
+dnswasher_LDADD =      $(BOOST_PROGRAM_OPTIONS_LIBS) $(LIBCRYPTO_LIBS)
 
 dnsbulktest_SOURCES = \
        base32.cc \
index c105f3bea635cb486d492ac92eb244bc57e3b445..0f81c385be7db7b2df6c9e3bcc25728ffce18e69 100644 (file)
@@ -40,19 +40,40 @@ otherwise, obfuscate the response IP address
 #include "statbag.hh"
 #include "dnspcap.hh"
 #include "iputils.hh"
-
+#include "ipcipher.hh"
 #include "namespaces.hh"
+#include <boost/program_options.hpp>
+#include "base64.hh"
 
 StatBag S;
 
+namespace po = boost::program_options;
+po::variables_map g_vm;
+
+
 class IPObfuscator
 {
 public:
-  IPObfuscator() : d_romap(d_ipmap), d_ro6map(d_ip6map), d_counter(0)
+  virtual uint32_t obf4(uint32_t orig)=0;
+  virtual struct in6_addr obf6(const struct in6_addr& orig)=0;
+};
+
+class IPSeqObfuscator : public IPObfuscator
+{
+public:
+  IPSeqObfuscator() : d_romap(d_ipmap), d_ro6map(d_ip6map), d_counter(0)
   {
   }
 
-  uint32_t obf4(uint32_t orig)
+  ~IPSeqObfuscator()
+  {}
+
+  static std::unique_ptr<IPObfuscator> make()
+  {
+    return std::unique_ptr<IPObfuscator>(new IPSeqObfuscator());
+  }
+  
+  uint32_t obf4(uint32_t orig) override
   {
     if(d_romap.count(orig))
       return d_ipmap[orig];
@@ -61,7 +82,7 @@ public:
     }
   }
 
-  struct in6_addr obf6(const struct in6_addr& orig)
+  struct in6_addr obf6(const struct in6_addr& orig) override
   {
     uint32_t val;
     if(d_ro6map.count(orig))
@@ -95,6 +116,48 @@ private:
   uint32_t d_counter;
 };
 
+class IPCipherObfuscator : public IPObfuscator
+{
+public:
+  IPCipherObfuscator(const std::string& key, bool decrypt)  : d_key(key), d_decrypt(decrypt)
+  {
+    if(d_key.size()!=16) {
+      throw std::runtime_error("IPCipher requires a 128 bit key");
+    }
+  }
+
+  ~IPCipherObfuscator()
+  {}
+  static std::unique_ptr<IPObfuscator> make(std::string key, bool decrypt)
+  {
+    return std::unique_ptr<IPObfuscator>(new IPCipherObfuscator(key, decrypt));
+  }
+  
+  uint32_t obf4(uint32_t orig) override
+  {
+    ComboAddress ca;
+    ca.sin4.sin_family = AF_INET;
+    ca.sin4.sin_addr.s_addr = orig;
+    ca = d_decrypt ? decryptCA(ca, d_key) : encryptCA(ca, d_key);
+    return ca.sin4.sin_addr.s_addr;
+
+  }
+
+  struct in6_addr obf6(const struct in6_addr& orig) override
+  {
+    ComboAddress ca;
+    ca.sin4.sin_family = AF_INET6;
+    ca.sin6.sin6_addr = orig;
+    ca = d_decrypt ? decryptCA(ca, d_key) : encryptCA(ca, d_key);
+    return ca.sin6.sin6_addr;
+  }
+
+private:
+  std::string d_key;
+  bool d_decrypt;
+};
+
+
 void usage() {
   cerr<<"Syntax: dnswasher INFILE1 [INFILE2..] OUTFILE"<<endl;
 }
@@ -102,29 +165,73 @@ void usage() {
 int main(int argc, char** argv)
 try
 {
-  for (int i = 1; i < argc; i++) {
-    if ((string) argv[i] == "--help") {
-      usage();
-      exit(EXIT_SUCCESS);
-    }
+  po::options_description desc("Allowed options");
+  desc.add_options()
+    ("help,h", "produce help message")
+    ("version", "show version number")
+    ("key,k", po::value<string>(), "base64 encoded 128 bit key for ipcipher")
+    ("passphrase,p", po::value<string>(), "passphrase for ipcipher (will be used to derive key)")
+    ("decrypt,d", "decrypt IP addresses with ipcipher");
+  
+  po::options_description alloptions;
+  po::options_description hidden("hidden options");
+  hidden.add_options()
+    ("infiles", po::value<vector<string>>(), "PCAP source file(s)")
+    ("outfile", po::value<string>(), "outfile");
 
-    if ((string) argv[i] == "--version") {
-      cerr<<"dnswasher "<<VERSION<<endl;
-      exit(EXIT_SUCCESS);
-    }
+
+  alloptions.add(desc).add(hidden);
+  po::positional_options_description p;
+  p.add("infiles", 1);
+  p.add("outfile", 1);
+
+  po::store(po::command_line_parser(argc, argv).options(alloptions).positional(p).run(), g_vm);
+  po::notify(g_vm);
+
+  if(g_vm.count("help")) {
+    usage();
+    cout<<desc<<endl;
+    exit(EXIT_SUCCESS);
   }
 
-  if(argc < 3) {
+  if(g_vm.count("version")) {
+    cout<<"dnswasher "<<VERSION<<endl;
+    exit(EXIT_SUCCESS);
+  }
+
+  if(!g_vm.count("outfile")) {
+    cout<<"Missing outfile"<<endl;
     usage();
-    exit(1);
+    exit(EXIT_FAILURE);
+  }
+
+  bool doDecrypt = g_vm.count("decrypt");
+  
+  PcapPacketWriter pw(g_vm["outfile"].as<string>());
+  std::unique_ptr<IPObfuscator> ipo;
+
+  if(!g_vm.count("key") && !g_vm.count("passphrase"))
+    ipo = IPSeqObfuscator::make();
+  else if(g_vm.count("key") && !g_vm.count("passphrase")) {
+    string key;
+    if(B64Decode(g_vm["key"].as<string>(), key) < 0) {
+      cerr<<"Invalidly encoded base64 key provided"<<endl;
+      exit(EXIT_FAILURE);
+    }
+    ipo = IPCipherObfuscator::make(key, doDecrypt);
+  }
+  else if(!g_vm.count("key") && g_vm.count("passphrase")) {
+    string key = makeIPCipherKey(g_vm["passphrase"].as<string>());
+    
+    ipo = IPCipherObfuscator::make(key, doDecrypt);
+  }
+  else {
+    cerr<<"Can't specify both 'key' and 'passphrase'"<<endl;
+    exit(EXIT_FAILURE);
   }
 
-  PcapPacketWriter pw(argv[argc-1]);
-  IPObfuscator ipo;
-  // 0          1   2   3    - argc == 4
-  // dnswasher in1 in2 out
-  for(int n=1; n < argc -1; ++n) {
-    PcapPacketReader pr(argv[n]);
+  for(const auto& inf : g_vm["infiles"].as<vector<string>>()) {
+    PcapPacketReader pr(inf);
     pw.setPPR(pr);
 
     while(pr.getUDPPacket()) {
@@ -136,9 +243,9 @@ try
           uint32_t *dst=(uint32_t*)&pr.d_ip->ip_dst;
           
           if(dh->qr)
-            *dst=htonl(ipo.obf4(*dst));
+            *dst=ipo->obf4(*dst);
           else
-            *src=htonl(ipo.obf4(*src));
+            *src=ipo->obf4(*src);
           
           pr.d_ip->ip_sum=0;
         } else if (pr.d_ip->ip_v == 6) {
@@ -146,9 +253,9 @@ try
           auto dst=&pr.d_ip6->ip6_dst;
           
           if(dh->qr)
-            *dst=ipo.obf6(*dst);
+            *dst=ipo->obf6(*dst);
           else
-            *src=ipo.obf6(*src);
+            *src=ipo->obf6(*src);
           // IPv6 checksum does not cover source/destination addresses
         }
         pw.write();