2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
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.
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.
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.
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.
25 anonymizing and stripping tcpdumps of irrelevant traffic, so operators can send non-privacy violating dumps
30 read a packet, check if it has the QR bit set.
32 If the question has the response bit set, obfuscate the destination IP address
33 otherwise, obfuscate the response IP address
43 #include "ipcipher.hh"
44 #include "namespaces.hh"
45 #include <boost/program_options.hpp>
50 namespace po
= boost::program_options
;
51 po::variables_map g_vm
;
57 virtual ~IPObfuscator()
60 virtual uint32_t obf4(uint32_t orig
)=0;
61 virtual struct in6_addr
obf6(const struct in6_addr
& orig
)=0;
64 class IPSeqObfuscator
: public IPObfuscator
67 IPSeqObfuscator() : d_romap(d_ipmap
), d_ro6map(d_ip6map
), d_counter(0)
74 static std::unique_ptr
<IPObfuscator
> make()
76 return std::unique_ptr
<IPObfuscator
>(new IPSeqObfuscator());
79 uint32_t obf4(uint32_t orig
) override
81 if(d_romap
.count(orig
))
84 return d_ipmap
[orig
]=d_counter
++;
88 struct in6_addr
obf6(const struct in6_addr
& orig
) override
91 if(d_ro6map
.count(orig
))
94 val
=d_ip6map
[orig
]=d_counter
++;
99 memset(&ret
, 0, sizeof(ret
));
100 memcpy(((char*)&ret
)+12, &val
, 4);
105 map
<uint32_t, uint32_t> d_ipmap
;
106 const decltype(d_ipmap
)& d_romap
;
109 bool operator()(const struct in6_addr
&a
, const struct in6_addr
&b
) const
111 return memcmp(&a
, &b
, sizeof(a
)) < 0;
114 // For IPv6 addresses
115 map
<struct in6_addr
, uint32_t, cmp
> d_ip6map
;
116 const decltype(d_ip6map
)& d_ro6map
;
118 // The counter that we'll convert to an IP address
122 class IPCipherObfuscator
: public IPObfuscator
125 IPCipherObfuscator(const std::string
& key
, bool decrypt
) : d_key(key
), d_decrypt(decrypt
)
127 if(d_key
.size()!=16) {
128 throw std::runtime_error("IPCipher requires a 128 bit key");
132 ~IPCipherObfuscator()
134 static std::unique_ptr
<IPObfuscator
> make(std::string key
, bool decrypt
)
136 return std::unique_ptr
<IPObfuscator
>(new IPCipherObfuscator(key
, decrypt
));
139 uint32_t obf4(uint32_t orig
) override
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
;
149 struct in6_addr
obf6(const struct in6_addr
& orig
) override
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
;
165 cerr
<<"Syntax: dnswasher INFILE1 [INFILE2..] OUTFILE"<<endl
;
168 int main(int argc
, char** argv
)
171 po::options_description
desc("Allowed 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");
179 po::options_description alloptions
;
180 po::options_description
hidden("hidden options");
182 ("infiles", po::value
<vector
<string
>>(), "PCAP source file(s)")
183 ("outfile", po::value
<string
>(), "outfile");
186 alloptions
.add(desc
).add(hidden
);
187 po::positional_options_description p
;
191 po::store(po::command_line_parser(argc
, argv
).options(alloptions
).positional(p
).run(), g_vm
);
194 if(g_vm
.count("help")) {
200 if(g_vm
.count("version")) {
201 cout
<<"dnswasher "<<VERSION
<<endl
;
205 if(!g_vm
.count("outfile")) {
206 cout
<<"Missing outfile"<<endl
;
211 bool doDecrypt
= g_vm
.count("decrypt");
213 PcapPacketWriter
pw(g_vm
["outfile"].as
<string
>());
214 std::unique_ptr
<IPObfuscator
> ipo
;
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")) {
220 if(B64Decode(g_vm
["key"].as
<string
>(), key
) < 0) {
221 cerr
<<"Invalidly encoded base64 key provided"<<endl
;
224 ipo
= IPCipherObfuscator::make(key
, doDecrypt
);
226 else if(!g_vm
.count("key") && g_vm
.count("passphrase")) {
227 string key
= makeIPCipherKey(g_vm
["passphrase"].as
<string
>());
229 ipo
= IPCipherObfuscator::make(key
, doDecrypt
);
232 cerr
<<"Can't specify both 'key' and 'passphrase'"<<endl
;
236 for(const auto& inf
: g_vm
["infiles"].as
<vector
<string
>>()) {
237 PcapPacketReader
pr(inf
);
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
;
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
;
249 *dst
=ipo
->obf4(*dst
);
251 *src
=ipo
->obf4(*src
);
254 } else if (pr
.d_ip
->ip_v
== 6) {
255 auto src
=&pr
.d_ip6
->ip6_src
;
256 auto dst
=&pr
.d_ip6
->ip6_dst
;
259 *dst
=ipo
->obf6(*dst
);
261 *src
=ipo
->obf6(*src
);
262 // IPv6 checksum does not cover source/destination addresses
267 cerr
<<"Saw "<<pr
.d_correctpackets
<<" correct packets, "<<pr
.d_runts
<<" runts, "<< pr
.d_oversized
<<" oversize, "<<
268 pr
.d_nonetheripudp
<<" unknown encaps"<<endl
;
271 catch(std::exception
& e
)
273 cerr
<<"Fatal: "<<e
.what()<<endl
;