#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];
}
}
- 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))
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;
}
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()) {
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) {
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();