]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/comfun.cc
Merge pull request #14021 from Habbie/auth-lua-join-whitespace
[thirdparty/pdns.git] / pdns / comfun.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 */
ca12836d 22#include "statbag.hh"
23#include "zoneparser-tng.hh"
24#include "namespaces.hh"
25#include "dnsrecords.hh"
26#include <fstream>
27#include <atomic>
28#include <thread>
29#include <unordered_set>
4e998d96 30#include <deque>
ca12836d 31#include "inflighter.cc"
32//#include "malloctrace.hh"
33StatBag S;
34bool g_quiet;
35std::unique_ptr<ofstream> g_powerdns;
36std::atomic<unsigned int> g_count;
37std::atomic<bool> g_stop;
38
39
40struct namecount {
41 set<DNSName> names;
42 unsigned int count;
43 bool isPowerDNS{false};
44};
45
46struct DNSResult
47{
48 string content;
49 int ttl{0};
50 uint16_t qclass;
51};
52
53struct NSQuery
54{
55 ComboAddress a;
56 set<DNSName> nsnames;
57 DNSName qname;
58 unsigned int count;
59};
60
61struct SendReceive
62{
63 typedef int Identifier;
64 typedef DNSResult Answer; // ip
65 int d_socket;
4e998d96 66 std::deque<uint16_t> d_idqueue;
ca12836d 67
68 SendReceive(map<ComboAddress, namecount, ComboAddress::addressOnlyLessThan>& res) : d_res(res)
69 {
70 d_socket = socket(AF_INET, SOCK_DGRAM, 0);
1ce8f718
AT
71 if (d_socket < 0)
72 throw runtime_error("socket(AF_INET, SOCK_DGRAM, 0) failed: " + stringerror());
ca12836d 73 int val=1;
ca12836d 74
1ce8f718
AT
75 if (setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != 0)
76 cerr<<"Failed to turn on SO_REUSEADDR: " << stringerror() << endl;
77
ca12836d 78 for(unsigned int id =0 ; id < std::numeric_limits<uint16_t>::max(); ++id)
79 d_idqueue.push_back(id);
80 }
81
82 ~SendReceive()
83 {
84 close(d_socket);
85 }
86
87 Identifier send(NSQuery& domain)
88 {
89 //cerr<<"Sending query for '"<<domain<<"'"<<endl;
90
91 // send it, copy code from 'sdig'
92 vector<uint8_t> packet;
93
94 DNSPacketWriter pw(packet, domain.qname, QType::TXT, 3);
95
96 if(d_idqueue.empty()) {
97 cerr<<"Exhausted ids!"<<endl;
98 exit(1);
99 }
100 pw.getHeader()->id = d_idqueue.front();
101 d_idqueue.pop_front();
102 pw.getHeader()->rd = 0;
103 pw.getHeader()->qr = 0;
104
105 if(::sendto(d_socket, &*packet.begin(), packet.size(), 0, (struct sockaddr*)&domain.a, domain.a.getSocklen()) < 0)
106 d_senderrors++;
107
108 return pw.getHeader()->id;
109 }
110
111 bool receive(Identifier& id, DNSResult& dr)
112 {
113 if(waitForData(d_socket, 0, 500000) > 0) {
114 char buf[512];
115 ComboAddress from;
116 from.sin4.sin_family = AF_INET;
117 socklen_t socklen=from.getSocklen();
118 int len = recvfrom(d_socket, buf, sizeof(buf),0, (struct sockaddr*)&from, &socklen);
119 if(len < 0) {
120 d_receiveerrors++;
121 return 0;
122 }
123 else {
46d77a35 124 d_received++;
ca12836d 125 }
126 // parse packet, set 'id', fill out 'ip'
127
27c0050c 128 MOADNSParser mdp(false, string(buf, len));
ca12836d 129 if(!g_quiet) {
a8d9bc94 130 cout<<"Reply to question for qname='"<<mdp.d_qname<<"', qtype="<<DNSRecordContent::NumberToType(mdp.d_qtype)<<endl;
ca12836d 131 cout<<"Rcode: "<<mdp.d_header.rcode<<", RD: "<<mdp.d_header.rd<<", QR: "<<mdp.d_header.qr;
132 cout<<", TC: "<<mdp.d_header.tc<<", AA: "<<mdp.d_header.aa<<", opcode: "<<mdp.d_header.opcode<<endl;
133 }
134 id = mdp.d_header.id;
135 d_idqueue.push_back(id);
136 dr.qclass = mdp.d_qclass;
137 dr.content.clear();
138 dr.ttl=0;
139 for(const auto& a : mdp.d_answers) {
140 if(a.first.d_type == QType::TXT) {
141 dr.content=a.first.d_content->getZoneRepresentation();
142 dr.ttl=a.first.d_ttl;
143 }
144 }
145 if(dr.content.empty())
146 dr.content="RCode: "+RCode::to_s(mdp.d_header.rcode);
147 return 1;
148 }
149 return 0;
150 }
151
152 void deliverTimeout(const Identifier& id)
153 {
154 if(!g_quiet) {
155 cout<<"Timeout for id "<<id<<endl;
156 }
157 d_idqueue.push_back(id);
158 }
159
160 void deliverAnswer(NSQuery& domain, const DNSResult& dr, unsigned int usec)
161 {
a8d9bc94 162 cout<<domain.a.toString()<<"\t"<<domain.qname<<"\t";
ca12836d 163 for(const auto& n : domain.nsnames)
a8d9bc94 164 cout<<n<<",";
ca12836d 165 cout<<"\t"<<domain.count<<"\t"<<dr.qclass<<'\t'<<dr.ttl<<": "<<dr.content<<endl;
166
167 if(dr.qclass==1 || toLower(dr.content).find("powerdns") != string::npos || dr.ttl==5) {
168 auto f = d_res.find(domain.a);
169 if(!f->second.isPowerDNS) {
170 (*g_powerdns)<<domain.a.toString()<<'\t'<<domain.count<<'\t';
171 for(const auto& n : domain.nsnames)
a8d9bc94 172 (*g_powerdns)<<n<<'\t';
ca12836d 173 (*g_powerdns)<<"\n";
174 f->second.isPowerDNS=true;
175 }
176
177 }
178
179 }
180 unsigned int d_errors, d_nxdomains, d_nodatas, d_oks, d_unknowns;
46d77a35 181 unsigned int d_received, d_receiveerrors, d_senderrors;
ca12836d 182 map<ComboAddress, namecount, ComboAddress::addressOnlyLessThan>& d_res;
183};
184
185
186struct RESResult
187{
188 vector<ComboAddress> addrs;
189 uint16_t rcode;
190};
191
192typedef DNSName RESQuery;
193
194struct SendReceiveRes
195{
196 typedef int Identifier;
197 typedef RESResult Answer; // ip
198 int d_socket;
4e998d96 199 std::deque<uint16_t> d_idqueue;
ca12836d 200 map<DNSName, vector<ComboAddress>>& d_out;
201 SendReceiveRes(const ComboAddress& remote, map<DNSName,vector<ComboAddress>>& out) : d_out(out)
202 {
203 d_socket = socket(AF_INET, SOCK_DGRAM, 0);
204 int val=1;
1ce8f718
AT
205
206 if (setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != 0)
207 cerr<<"Failed to turn on SO_REUSEADDR: " << stringerror() << endl;
208 if (connect(d_socket, (struct sockaddr*)&remote, remote.getSocklen()) != 0)
209 throw DNSException("connect(" + remote.toStringWithPort() + ") failed: " + stringerror());
ca12836d 210 for(unsigned int id =0 ; id < std::numeric_limits<uint16_t>::max(); ++id)
211 d_idqueue.push_back(id);
212 }
213
214 ~SendReceiveRes()
215 {
216 close(d_socket);
217 }
218
219 Identifier send(RESQuery& domain)
220 {
221 //cerr<<"Sending query for '"<<domain<<"'"<<endl;
222
223 // send it, copy code from 'sdig'
224 vector<uint8_t> packet;
225
226 DNSPacketWriter pw(packet, domain, QType::A);
227
228 if(d_idqueue.empty()) {
229 cerr<<"Exhausted ids!"<<endl;
230 exit(1);
231 }
232 pw.getHeader()->id = d_idqueue.front();
233 d_idqueue.pop_front();
234 pw.getHeader()->rd = 1;
235 pw.getHeader()->qr = 0;
236
237 if(::send(d_socket, &*packet.begin(), packet.size(), 0) < 0) {
a702a96c 238 cout<<"Error sending: "<<stringerror()<<endl;
ca12836d 239 d_senderrors++;
240 }
241
242 return pw.getHeader()->id;
243 }
244
245 bool receive(Identifier& id, RESResult& dr)
246 {
247 if(waitForData(d_socket, 0, 500000) > 0) {
248 char buf[512];
249 ComboAddress from;
250 from.sin4.sin_family = AF_INET;
251 socklen_t socklen=from.getSocklen();
252 int len = recvfrom(d_socket, buf, sizeof(buf),0, (struct sockaddr*)&from, &socklen);
253 if(len < 0) {
254 d_receiveerrors++;
255 return 0;
256 }
257 else {
46d77a35 258 d_received++;
ca12836d 259 }
260 // parse packet, set 'id', fill out 'ip'
261
27c0050c 262 MOADNSParser mdp(false, string(buf, len));
ca12836d 263 if(!g_quiet) {
a8d9bc94 264 cout<<"Reply to question for qname='"<<mdp.d_qname<<"', qtype="<<DNSRecordContent::NumberToType(mdp.d_qtype)<<endl;
ca12836d 265 cout<<"Rcode: "<<mdp.d_header.rcode<<", RD: "<<mdp.d_header.rd<<", QR: "<<mdp.d_header.qr<<", answers: "<<mdp.d_answers.size();
266 cout<<", TC: "<<mdp.d_header.tc<<", AA: "<<mdp.d_header.aa<<", opcode: "<<mdp.d_header.opcode<<endl;
267 }
268 id = mdp.d_header.id;
269 d_idqueue.push_back(id);
270 dr.rcode = mdp.d_header.rcode;
271 dr.addrs.clear();
272 for(const auto& a : mdp.d_answers) {
273 if(a.first.d_name != mdp.d_qname)
274 continue;
275 if(a.first.d_type == QType::A || a.first.d_type == QType::AAAA) {
276 if(!g_quiet)
277 cout<<a.first.d_content->getZoneRepresentation()<<endl;
278 dr.addrs.push_back(getAddr(a.first));
279 }
280 }
281 ++g_count;
282 return 1;
283 }
284 return 0;
285 }
286
287 void deliverTimeout(const Identifier& id)
288 {
289 if(!g_quiet) {
290 cout<<"Timeout for id "<<id<<endl;
291 }
292 ++g_count;
293 d_idqueue.push_back(id);
294 }
295
296 void deliverAnswer(DNSName& domain, const RESResult& dr, unsigned int usec)
297 {
298 d_out[domain]=dr.addrs;
299 cout<<domain<<"\t"<<dr.rcode<<'\t';
300 for(const auto& a : dr.addrs)
301 cout<<a.toString()<<'\t';
302 cout<<'\n';
303 }
304 unsigned int d_errors, d_nxdomains, d_nodatas, d_oks, d_unknowns;
46d77a35 305 unsigned int d_received, d_receiveerrors, d_senderrors;
ca12836d 306};
307
308
1ce8f718 309static void printStats()
ca12836d 310{
311 while(!g_stop) {
312 sleep(1);
313 cerr<<"\r"<<g_count;
314 cerr.flush();
315 }
316 cerr<<"\n";
317}
318
1ce8f718 319static int parseZone(const std::string& str, unsigned int limit)
ca12836d 320{
321 ZoneParserTNG zpt(str);
45bf6885 322 zpt.disableGenerate();
ca12836d 323 DNSResourceRecord rr;
324
325 std::thread stats(printStats);
326
327 map<DNSName,unsigned int> nsnames;
328 map<DNSName,set<ComboAddress,ComboAddress::addressOnlyLessThan> > addresses;
329
330
331 while(zpt.get(rr)) {
332 if(rr.qtype.getCode() == QType::NS)
333 nsnames[DNSName(rr.content)]++;
334 else if(rr.qtype.getCode() == QType::A || rr.qtype.getCode() == QType::AAAA) {
335 DNSRecord dr(rr);
336 addresses[rr.qname].insert(getAddr(dr, 53));
337 }
338 ++g_count;
339 if(g_count == limit)
340 break;
341 }
342 g_stop=true;
343 stats.join();
344
345 cout<<"Got "<<nsnames.size()<<" different nameserver names"<<endl;
346 cout<<"Got at least one address for "<<addresses.size()<<" names"<<endl;
347
348 ofstream ns(str+".nameservers");
349 ofstream needres(str+".needres");
350 for(const auto& a: nsnames) {
351 ns<<a.first<<"\t"<<a.second<<"\t";
352 if(auto hit=rplookup(addresses, a.first)) {
353 for(const auto& b : *hit)
354 ns<<b.toString()<<"\t";
355 }
356 else
357 needres<<a.first<<"\n";
358 ns<<"\n";
359 }
360 return 0;
361}
362
1ce8f718 363static int resolveNS(const std::string& fname)
ca12836d 364{
365 string line;
366 ifstream needres(fname);
367 if(!needres)
368 unixDie("Unable to open file "+fname);
369 vector<DNSName> tores;
370 while(getline(needres,line)) {
371 tores.push_back(DNSName(line));
372 }
373 cerr<<"Going to resolve "<<tores.size()<<" names"<<endl;
374 std::thread stats(printStats);
375 map<DNSName, vector<ComboAddress>> output;
376 SendReceiveRes sr(ComboAddress("192.168.1.2", 53), output);
377 Inflighter<vector<DNSName>, SendReceiveRes> inflighter(tores, sr);
378 inflighter.d_maxInFlight = 1000;
379 inflighter.d_timeoutSeconds = 3;
380 inflighter.d_burst = 100;
381 for(;;) {
382 try {
383 inflighter.run();
384 break;
385 }
386 catch(std::exception& e) {
387 cerr<<"Caught exception: "<<e.what()<<endl;
388 }
389 }
390 g_stop=true;
391 stats.join();
392 return EXIT_SUCCESS;
393}
394
1ce8f718 395static void readRESNames(const std::string& fname, map<DNSName, vector<ComboAddress>>& addrs)
ca12836d 396{
397 ifstream ifs(fname);
398 if(!ifs)
bb99bcf1 399 unixDie("Reading resolved names from "+fname+": "+stringerror());
ca12836d 400 vector<string> parts;
401 string line;
402 addrs.clear();
403 while(getline(ifs, line)) {
404 parts.clear();
405 stringtok(parts, line,"\t");
406 for(unsigned int n=2; n < parts.size(); ++n)
407 addrs[DNSName(parts[0])].push_back(ComboAddress(parts[n], 53));
408 }
409 //EARTH.DOMAINS.SHELTEK.CA. 0 67.15.253.219 67.15.47.188 67.15.253.252 67.15.253.251 67.15.47.189 67.15.253.220
410 cerr<<"Got "<<addrs.size()<<" resolved nameserver names from file"<<endl;
411
412}
413
414int main(int argc, char**argv)
415try
416{
417 g_quiet=true;
418 reportAllTypes();
419 string mode=argv[1];
420 if(mode == "parse-zone") {
421 unsigned int limit = 0;
422 if(argc > 3)
423 limit = atoi(argv[3]);
424
425 return parseZone(argv[2], limit);
426 }
427 else if(mode=="resolve-ns") {
428 return resolveNS(string(argv[2])+".needres");
429 }
430 else if(mode=="scan-ns") {
431 ifstream ns(string(argv[2])+".nameservers");
2bbc9eb0 432 g_powerdns = std::make_unique<std::ofstream>(string(argv[2]) + ".powerdns");
ca12836d 433 string line;
434 int count=0;
435 vector<string> parts;
436
437 struct NSCount
438 {
439 unsigned int count{0};
440 vector<ComboAddress> addrs;
441 };
442 map<DNSName, NSCount> stats;
443 NSCount nscount;
444 // NS1.IHOST2000.COM. 9 162.251.82.122 162.251.82.123 162.251.82.250 162.251.82.251
445 while(getline(ns, line)) {
446 ++count;
447 parts.clear();
448 stringtok(parts, line,"\t");
449 nscount.count=atoi(parts[1].c_str());
450 nscount.addrs.clear();
451 for(unsigned int n = 2; n < parts.size(); ++n)
452 nscount.addrs.push_back(ComboAddress(parts[n], 53));
453 stats.insert({DNSName(parts[0]), nscount});
454 }
455 cerr<<"Had "<<count<<" lines from summary"<<endl;
456
457 map<DNSName, vector<ComboAddress>> lookedup;
458 readRESNames(argv[2]+string(".resolved"), lookedup);
459
460 map<ComboAddress, namecount, ComboAddress::addressOnlyLessThan> pure;
461
462 unsigned int noaddrs=0;
463 for(const auto& s : stats) {
464 auto ptr = &s.second.addrs;
465 if(ptr->empty()) {
466 if(lookedup.count(s.first)) {
467 ptr = &lookedup[s.first];
468 }
469 else {
470 //cout<<"Have no address for "<<s.first.toString()<<endl;
471 noaddrs++;
472 }
473 }
474
475 for(const auto& a : *ptr) {
476 pure[a].count += s.second.count;
477 pure[a].names.insert(s.first);
478 }
479 }
480
481 cerr<<"Have "<<pure.size()<<" IP addresses to query, "<<noaddrs<<" names w/o address"<<endl;
482 SendReceive sr(pure);
483 vector<NSQuery> domains;
484
485 Inflighter<vector<NSQuery>, SendReceive> inflighter(domains, sr);
486 inflighter.d_maxInFlight = 1000;
487 inflighter.d_timeoutSeconds = 3;
488 inflighter.d_burst = 100;
489
490 for(const auto& p : pure) {
491 NSQuery nsq;
492 nsq.a=p.first;
493 nsq.nsnames = p.second.names;
494 nsq.count = p.second.count;
495
496 nsq.qname=DNSName("version.bind");
497 domains.push_back(nsq);
498 nsq.qname=DNSName("id.server");
499 domains.push_back(nsq);
500 nsq.qname=DNSName("bind.version");
501 domains.push_back(nsq);
502 }
503
504 sort(domains.begin(), domains.end(), [](const NSQuery& a, const NSQuery& b) { return b.count < a.count; });
505 for(;;) {
506 try {
507 inflighter.run();
508 break;
509 }
510 catch(std::exception& e) {
511 cerr<<"Caught exception: "<<e.what()<<endl;
512 }
513 }
514 }
515 else if(mode=="score-ns") {
516 std::unordered_set<DNSName> powerdns;
517 ifstream ifs(string(argv[2])+".powerdns");
518 string line;
519 vector<string> parts;
520 while(getline(ifs,line)) {
521 // 64.96.240.53 1234 NS1.UNIREGISTRYMARKET.LINK. NS1.INTERNETTRAFFIC.COM. BUY.INTERNETTRAFFIC.COM. NS3.SECUREDOFFERS.COM. NS3.GI.NET. NS3.IT.GI.NET. NS3.EASILY.NET.
522 parts.clear();
523 stringtok(parts, line);
524 for(unsigned int n=2; n < parts.size(); ++n)
525 powerdns.insert(DNSName(parts[n]));
526 }
527 cerr<<"Have "<<powerdns.size()<<" known NS names that are PowerDNS"<<endl;
528 ZoneParserTNG zpt(argv[2]);
45bf6885 529 zpt.disableGenerate();
ca12836d 530 DNSResourceRecord rr;
531
ca12836d 532 set<DNSName> seen, pdnsdomains;
533 int count=0;
534 while(zpt.get(rr)) {
535 if(!seen.count(rr.qname)) {
536 seen.insert(rr.qname);
537 }
538 if(rr.qtype.getCode() == QType::NS && powerdns.count(DNSName(rr.content)) && !pdnsdomains.count(DNSName(rr.qname))) {
ca12836d 539 pdnsdomains.insert(DNSName(rr.qname));
540 }
541 if(!(count%100000)) {
542 cerr<<"\rUnique domains: "<<seen.size()<<", PowerDNS domains: "<<pdnsdomains.size()<<" ("<<(pdnsdomains.size()*100.0/seen.size())<<"%)";
543 }
544 count++;
545 }
546 cerr<<"\n";
547 }
548 else {
549 cerr<<"Unknown mode "<<argv[1]<<endl;
550 }
551 // cout<<g_mtracer->topAllocatorsString(20)<<endl;
552}
553catch(PDNSException& pe) {
554 cerr<<"Fatal error: "<<pe.reason<<endl;
555}