]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnswasher.cc
Merge pull request #7870 from omoerbeek/stubquery-fix-arg
[thirdparty/pdns.git] / pdns / dnswasher.cc
CommitLineData
12471842
PL
1/*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
ab06937b
BH
23/** two modes:
24
25anonymizing and stripping tcpdumps of irrelevant traffic, so operators can send non-privacy violating dumps
26for analysis.
27
28algorithm:
29
9be88092 30read a packet, check if it has the QR bit set.
ab06937b
BH
31
32If the question has the response bit set, obfuscate the destination IP address
33otherwise, obfuscate the response IP address
ab06937b
BH
34*/
35
11212b81 36
870a0fe4
AT
37#ifdef HAVE_CONFIG_H
38#include "config.h"
39#endif
ab06937b 40#include "statbag.hh"
ab06937b 41#include "dnspcap.hh"
40ff5c7d 42#include "iputils.hh"
152b0801 43#include "ipcipher.hh"
10f4eea8 44#include "namespaces.hh"
152b0801 45#include <boost/program_options.hpp>
46#include "base64.hh"
ab06937b
BH
47
48StatBag S;
49
152b0801 50namespace po = boost::program_options;
51po::variables_map g_vm;
52
53
ab06937b
BH
54class IPObfuscator
55{
56public:
260936e8
OM
57 virtual ~IPObfuscator()
58 {
59 }
152b0801 60 virtual uint32_t obf4(uint32_t orig)=0;
61 virtual struct in6_addr obf6(const struct in6_addr& orig)=0;
62};
63
64class IPSeqObfuscator : public IPObfuscator
65{
66public:
67 IPSeqObfuscator() : d_romap(d_ipmap), d_ro6map(d_ip6map), d_counter(0)
ab06937b
BH
68 {
69 }
70
152b0801 71 ~IPSeqObfuscator()
72 {}
73
74 static std::unique_ptr<IPObfuscator> make()
75 {
76 return std::unique_ptr<IPObfuscator>(new IPSeqObfuscator());
77 }
488bcb39 78
152b0801 79 uint32_t obf4(uint32_t orig) override
ab06937b
BH
80 {
81 if(d_romap.count(orig))
82 return d_ipmap[orig];
83 else {
84 return d_ipmap[orig]=d_counter++;
85 }
86 }
87
152b0801 88 struct in6_addr obf6(const struct in6_addr& orig) override
cbb0be81 89 {
7856684d 90 uint32_t val;
cbb0be81 91 if(d_ro6map.count(orig))
7856684d 92 val=d_ip6map[orig];
cbb0be81 93 else {
7856684d 94 val=d_ip6map[orig]=d_counter++;
cbb0be81 95 }
7856684d 96 struct in6_addr ret;
647efa8b 97
7856684d 98 val=htonl(val);
647efa8b 99 memset(&ret, 0, sizeof(ret));
7856684d 100 memcpy(((char*)&ret)+12, &val, 4);
101 return ret;
cbb0be81
PL
102 }
103
ab06937b
BH
104private:
105 map<uint32_t, uint32_t> d_ipmap;
7856684d 106 const decltype(d_ipmap)& d_romap;
107
108 struct cmp {
109 bool operator()(const struct in6_addr&a , const struct in6_addr&b) const
110 {
111 return memcmp(&a, &b, sizeof(a)) < 0;
112 }
113 };
cbb0be81 114 // For IPv6 addresses
7856684d 115 map<struct in6_addr, uint32_t, cmp> d_ip6map;
116 const decltype(d_ip6map)& d_ro6map;
117
cbb0be81 118 // The counter that we'll convert to an IP address
ab06937b
BH
119 uint32_t d_counter;
120};
121
152b0801 122class IPCipherObfuscator : public IPObfuscator
123{
124public:
125 IPCipherObfuscator(const std::string& key, bool decrypt) : d_key(key), d_decrypt(decrypt)
126 {
127 if(d_key.size()!=16) {
128 throw std::runtime_error("IPCipher requires a 128 bit key");
129 }
130 }
131
132 ~IPCipherObfuscator()
133 {}
134 static std::unique_ptr<IPObfuscator> make(std::string key, bool decrypt)
135 {
136 return std::unique_ptr<IPObfuscator>(new IPCipherObfuscator(key, decrypt));
137 }
488bcb39 138
152b0801 139 uint32_t obf4(uint32_t orig) override
140 {
141 ComboAddress ca;
142 ca.sin4.sin_family = AF_INET;
143 ca.sin4.sin_addr.s_addr = orig;
144 ca = d_decrypt ? decryptCA(ca, d_key) : encryptCA(ca, d_key);
145 return ca.sin4.sin_addr.s_addr;
146
147 }
148
149 struct in6_addr obf6(const struct in6_addr& orig) override
150 {
151 ComboAddress ca;
152 ca.sin4.sin_family = AF_INET6;
153 ca.sin6.sin6_addr = orig;
154 ca = d_decrypt ? decryptCA(ca, d_key) : encryptCA(ca, d_key);
155 return ca.sin6.sin6_addr;
156 }
157
158private:
159 std::string d_key;
160 bool d_decrypt;
161};
162
163
3d414a24 164void usage() {
e795f590 165 cerr<<"Syntax: dnswasher INFILE1 [INFILE2..] OUTFILE"<<endl;
3d414a24
PL
166}
167
ab06937b
BH
168int main(int argc, char** argv)
169try
170{
152b0801 171 po::options_description desc("Allowed options");
172 desc.add_options()
173 ("help,h", "produce help message")
174 ("version", "show version number")
175 ("key,k", po::value<string>(), "base64 encoded 128 bit key for ipcipher")
176 ("passphrase,p", po::value<string>(), "passphrase for ipcipher (will be used to derive key)")
177 ("decrypt,d", "decrypt IP addresses with ipcipher");
488bcb39 178
152b0801 179 po::options_description alloptions;
180 po::options_description hidden("hidden options");
181 hidden.add_options()
182 ("infiles", po::value<vector<string>>(), "PCAP source file(s)")
183 ("outfile", po::value<string>(), "outfile");
3d414a24 184
152b0801 185
186 alloptions.add(desc).add(hidden);
187 po::positional_options_description p;
188 p.add("infiles", 1);
189 p.add("outfile", 1);
190
191 po::store(po::command_line_parser(argc, argv).options(alloptions).positional(p).run(), g_vm);
192 po::notify(g_vm);
193
194 if(g_vm.count("help")) {
195 usage();
196 cout<<desc<<endl;
197 exit(EXIT_SUCCESS);
3d414a24
PL
198 }
199
152b0801 200 if(g_vm.count("version")) {
201 cout<<"dnswasher "<<VERSION<<endl;
202 exit(EXIT_SUCCESS);
203 }
204
205 if(!g_vm.count("outfile")) {
206 cout<<"Missing outfile"<<endl;
3d414a24 207 usage();
152b0801 208 exit(EXIT_FAILURE);
209 }
210
211 bool doDecrypt = g_vm.count("decrypt");
488bcb39 212
152b0801 213 PcapPacketWriter pw(g_vm["outfile"].as<string>());
214 std::unique_ptr<IPObfuscator> ipo;
215
216 if(!g_vm.count("key") && !g_vm.count("passphrase"))
217 ipo = IPSeqObfuscator::make();
218 else if(g_vm.count("key") && !g_vm.count("passphrase")) {
219 string key;
220 if(B64Decode(g_vm["key"].as<string>(), key) < 0) {
221 cerr<<"Invalidly encoded base64 key provided"<<endl;
222 exit(EXIT_FAILURE);
223 }
224 ipo = IPCipherObfuscator::make(key, doDecrypt);
225 }
226 else if(!g_vm.count("key") && g_vm.count("passphrase")) {
227 string key = makeIPCipherKey(g_vm["passphrase"].as<string>());
488bcb39 228
152b0801 229 ipo = IPCipherObfuscator::make(key, doDecrypt);
230 }
231 else {
232 cerr<<"Can't specify both 'key' and 'passphrase'"<<endl;
233 exit(EXIT_FAILURE);
e2928fdb 234 }
3d414a24 235
152b0801 236 for(const auto& inf : g_vm["infiles"].as<vector<string>>()) {
237 PcapPacketReader pr(inf);
e795f590 238 pw.setPPR(pr);
239
240 while(pr.getUDPPacket()) {
241 if(ntohs(pr.d_udp->uh_dport)==53 || (ntohs(pr.d_udp->uh_sport)==53 && pr.d_len > sizeof(dnsheader))) {
242 dnsheader* dh=(dnsheader*)pr.d_payload;
488bcb39 243
e795f590 244 if (pr.d_ip->ip_v == 4){
245 uint32_t *src=(uint32_t*)&pr.d_ip->ip_src;
246 uint32_t *dst=(uint32_t*)&pr.d_ip->ip_dst;
488bcb39 247
e795f590 248 if(dh->qr)
152b0801 249 *dst=ipo->obf4(*dst);
e795f590 250 else
152b0801 251 *src=ipo->obf4(*src);
488bcb39 252
e795f590 253 pr.d_ip->ip_sum=0;
254 } else if (pr.d_ip->ip_v == 6) {
7856684d 255 auto src=&pr.d_ip6->ip6_src;
256 auto dst=&pr.d_ip6->ip6_dst;
488bcb39 257
e795f590 258 if(dh->qr)
152b0801 259 *dst=ipo->obf6(*dst);
e795f590 260 else
152b0801 261 *src=ipo->obf6(*src);
726b013f 262 // IPv6 checksum does not cover source/destination addresses
e795f590 263 }
264 pw.write();
cbb0be81 265 }
ab06937b 266 }
e795f590 267 cerr<<"Saw "<<pr.d_correctpackets<<" correct packets, "<<pr.d_runts<<" runts, "<< pr.d_oversized<<" oversize, "<<
268 pr.d_nonetheripudp<<" unknown encaps"<<endl;
ab06937b 269 }
ab06937b 270}
adc10f99 271catch(std::exception& e)
ab06937b
BH
272{
273 cerr<<"Fatal: "<<e.what()<<endl;
274}