]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnswasher.cc
Merge pull request #14020 from omoerbeek/rec-compiling-rust-dcos
[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
e41aadeb 40
8fd7cf73 41#include "namespaces.hh"
ab06937b 42#include "statbag.hh"
8fd7cf73
OM
43StatBag S;
44
45#ifdef HAVE_IPCIPHER
ab06937b 46#include "dnspcap.hh"
40ff5c7d 47#include "iputils.hh"
152b0801 48#include "ipcipher.hh"
152b0801 49#include <boost/program_options.hpp>
50#include "base64.hh"
ab06937b 51
ab06937b 52
152b0801 53namespace po = boost::program_options;
54po::variables_map g_vm;
55
56
ab06937b
BH
57class IPObfuscator
58{
59public:
abb11ca4 60 virtual ~IPObfuscator() = default;
152b0801 61 virtual uint32_t obf4(uint32_t orig)=0;
62 virtual struct in6_addr obf6(const struct in6_addr& orig)=0;
63};
64
65class IPSeqObfuscator : public IPObfuscator
66{
67public:
68 IPSeqObfuscator() : d_romap(d_ipmap), d_ro6map(d_ip6map), d_counter(0)
ab06937b
BH
69 {
70 }
71
152b0801 72 static std::unique_ptr<IPObfuscator> make()
73 {
2bbc9eb0 74 return std::make_unique<IPSeqObfuscator>();
152b0801 75 }
488bcb39 76
152b0801 77 uint32_t obf4(uint32_t orig) override
ab06937b
BH
78 {
79 if(d_romap.count(orig))
80 return d_ipmap[orig];
81 else {
82 return d_ipmap[orig]=d_counter++;
83 }
84 }
85
152b0801 86 struct in6_addr obf6(const struct in6_addr& orig) override
cbb0be81 87 {
7856684d 88 uint32_t val;
cbb0be81 89 if(d_ro6map.count(orig))
7856684d 90 val=d_ip6map[orig];
cbb0be81 91 else {
7856684d 92 val=d_ip6map[orig]=d_counter++;
cbb0be81 93 }
7856684d 94 struct in6_addr ret;
647efa8b 95
7856684d 96 val=htonl(val);
647efa8b 97 memset(&ret, 0, sizeof(ret));
7856684d 98 memcpy(((char*)&ret)+12, &val, 4);
99 return ret;
cbb0be81
PL
100 }
101
ab06937b
BH
102private:
103 map<uint32_t, uint32_t> d_ipmap;
7856684d 104 const decltype(d_ipmap)& d_romap;
105
106 struct cmp {
107 bool operator()(const struct in6_addr&a , const struct in6_addr&b) const
108 {
109 return memcmp(&a, &b, sizeof(a)) < 0;
110 }
111 };
cbb0be81 112 // For IPv6 addresses
7856684d 113 map<struct in6_addr, uint32_t, cmp> d_ip6map;
114 const decltype(d_ip6map)& d_ro6map;
115
cbb0be81 116 // The counter that we'll convert to an IP address
ab06937b
BH
117 uint32_t d_counter;
118};
119
152b0801 120class IPCipherObfuscator : public IPObfuscator
121{
122public:
123 IPCipherObfuscator(const std::string& key, bool decrypt) : d_key(key), d_decrypt(decrypt)
124 {
125 if(d_key.size()!=16) {
126 throw std::runtime_error("IPCipher requires a 128 bit key");
127 }
128 }
129
224085cc 130 static std::unique_ptr<IPObfuscator> make(const std::string& key, bool decrypt)
152b0801 131 {
2bbc9eb0 132 return std::make_unique<IPCipherObfuscator>(key, decrypt);
152b0801 133 }
488bcb39 134
152b0801 135 uint32_t obf4(uint32_t orig) override
136 {
137 ComboAddress ca;
138 ca.sin4.sin_family = AF_INET;
139 ca.sin4.sin_addr.s_addr = orig;
140 ca = d_decrypt ? decryptCA(ca, d_key) : encryptCA(ca, d_key);
141 return ca.sin4.sin_addr.s_addr;
142
143 }
144
145 struct in6_addr obf6(const struct in6_addr& orig) override
146 {
147 ComboAddress ca;
148 ca.sin4.sin_family = AF_INET6;
149 ca.sin6.sin6_addr = orig;
150 ca = d_decrypt ? decryptCA(ca, d_key) : encryptCA(ca, d_key);
151 return ca.sin6.sin6_addr;
152 }
153
154private:
155 std::string d_key;
156 bool d_decrypt;
157};
158
159
050e6877 160static void usage() {
e795f590 161 cerr<<"Syntax: dnswasher INFILE1 [INFILE2..] OUTFILE"<<endl;
3d414a24
PL
162}
163
ab06937b
BH
164int main(int argc, char** argv)
165try
166{
152b0801 167 po::options_description desc("Allowed options");
168 desc.add_options()
169 ("help,h", "produce help message")
170 ("version", "show version number")
171 ("key,k", po::value<string>(), "base64 encoded 128 bit key for ipcipher")
172 ("passphrase,p", po::value<string>(), "passphrase for ipcipher (will be used to derive key)")
173 ("decrypt,d", "decrypt IP addresses with ipcipher");
488bcb39 174
152b0801 175 po::options_description alloptions;
176 po::options_description hidden("hidden options");
177 hidden.add_options()
178 ("infiles", po::value<vector<string>>(), "PCAP source file(s)")
179 ("outfile", po::value<string>(), "outfile");
3d414a24 180
152b0801 181
182 alloptions.add(desc).add(hidden);
183 po::positional_options_description p;
184 p.add("infiles", 1);
185 p.add("outfile", 1);
186
187 po::store(po::command_line_parser(argc, argv).options(alloptions).positional(p).run(), g_vm);
188 po::notify(g_vm);
189
190 if(g_vm.count("help")) {
191 usage();
192 cout<<desc<<endl;
193 exit(EXIT_SUCCESS);
3d414a24
PL
194 }
195
152b0801 196 if(g_vm.count("version")) {
197 cout<<"dnswasher "<<VERSION<<endl;
198 exit(EXIT_SUCCESS);
199 }
200
201 if(!g_vm.count("outfile")) {
202 cout<<"Missing outfile"<<endl;
3d414a24 203 usage();
152b0801 204 exit(EXIT_FAILURE);
205 }
206
207 bool doDecrypt = g_vm.count("decrypt");
488bcb39 208
152b0801 209 PcapPacketWriter pw(g_vm["outfile"].as<string>());
210 std::unique_ptr<IPObfuscator> ipo;
211
212 if(!g_vm.count("key") && !g_vm.count("passphrase"))
213 ipo = IPSeqObfuscator::make();
214 else if(g_vm.count("key") && !g_vm.count("passphrase")) {
215 string key;
216 if(B64Decode(g_vm["key"].as<string>(), key) < 0) {
217 cerr<<"Invalidly encoded base64 key provided"<<endl;
218 exit(EXIT_FAILURE);
219 }
7d0fefb4 220 ipo = IPCipherObfuscator::make(std::move(key), doDecrypt);
152b0801 221 }
222 else if(!g_vm.count("key") && g_vm.count("passphrase")) {
223 string key = makeIPCipherKey(g_vm["passphrase"].as<string>());
488bcb39 224
7d0fefb4 225 ipo = IPCipherObfuscator::make(std::move(key), doDecrypt);
152b0801 226 }
227 else {
228 cerr<<"Can't specify both 'key' and 'passphrase'"<<endl;
229 exit(EXIT_FAILURE);
e2928fdb 230 }
3d414a24 231
152b0801 232 for(const auto& inf : g_vm["infiles"].as<vector<string>>()) {
233 PcapPacketReader pr(inf);
e795f590 234 pw.setPPR(pr);
235
236 while(pr.getUDPPacket()) {
237 if(ntohs(pr.d_udp->uh_dport)==53 || (ntohs(pr.d_udp->uh_sport)==53 && pr.d_len > sizeof(dnsheader))) {
238 dnsheader* dh=(dnsheader*)pr.d_payload;
488bcb39 239
e795f590 240 if (pr.d_ip->ip_v == 4){
241 uint32_t *src=(uint32_t*)&pr.d_ip->ip_src;
242 uint32_t *dst=(uint32_t*)&pr.d_ip->ip_dst;
488bcb39 243
e795f590 244 if(dh->qr)
152b0801 245 *dst=ipo->obf4(*dst);
e795f590 246 else
152b0801 247 *src=ipo->obf4(*src);
488bcb39 248
e795f590 249 pr.d_ip->ip_sum=0;
250 } else if (pr.d_ip->ip_v == 6) {
7856684d 251 auto src=&pr.d_ip6->ip6_src;
252 auto dst=&pr.d_ip6->ip6_dst;
488bcb39 253
e795f590 254 if(dh->qr)
152b0801 255 *dst=ipo->obf6(*dst);
e795f590 256 else
152b0801 257 *src=ipo->obf6(*src);
726b013f 258 // IPv6 checksum does not cover source/destination addresses
e795f590 259 }
260 pw.write();
cbb0be81 261 }
ab06937b 262 }
e795f590 263 cerr<<"Saw "<<pr.d_correctpackets<<" correct packets, "<<pr.d_runts<<" runts, "<< pr.d_oversized<<" oversize, "<<
264 pr.d_nonetheripudp<<" unknown encaps"<<endl;
ab06937b 265 }
ab06937b 266}
adc10f99 267catch(std::exception& e)
ab06937b
BH
268{
269 cerr<<"Fatal: "<<e.what()<<endl;
270}
e41aadeb
RG
271
272#else
273int main()
274{
275 cerr<<"dnswasher requires ipcipher support, which is not available"<<endl;
276 exit(1);
277}
278#endif /* HAVE_IPCIPHER */