]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/comfun.cc
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.
23 #include "zoneparser-tng.hh"
24 #include "namespaces.hh"
25 #include "dnsrecords.hh"
29 #include <unordered_set>
30 #include "inflighter.cc"
31 //#include "malloctrace.hh"
34 std::unique_ptr
<ofstream
> g_powerdns
;
35 std::atomic
<unsigned int> g_count
;
36 std::atomic
<bool> g_stop
;
42 bool isPowerDNS
{false};
62 typedef int Identifier
;
63 typedef DNSResult Answer
; // ip
65 deque
<uint16_t> d_idqueue
;
67 SendReceive(map
<ComboAddress
, namecount
, ComboAddress::addressOnlyLessThan
>& res
) : d_res(res
)
69 d_socket
= socket(AF_INET
, SOCK_DGRAM
, 0);
71 setsockopt(d_socket
, SOL_SOCKET
, SO_REUSEADDR
, &val
, sizeof(val
));
73 for(unsigned int id
=0 ; id
< std::numeric_limits
<uint16_t>::max(); ++id
)
74 d_idqueue
.push_back(id
);
82 Identifier
send(NSQuery
& domain
)
84 //cerr<<"Sending query for '"<<domain<<"'"<<endl;
86 // send it, copy code from 'sdig'
87 vector
<uint8_t> packet
;
89 DNSPacketWriter
pw(packet
, domain
.qname
, QType::TXT
, 3);
91 if(d_idqueue
.empty()) {
92 cerr
<<"Exhausted ids!"<<endl
;
95 pw
.getHeader()->id
= d_idqueue
.front();
96 d_idqueue
.pop_front();
97 pw
.getHeader()->rd
= 0;
98 pw
.getHeader()->qr
= 0;
100 if(::sendto(d_socket
, &*packet
.begin(), packet
.size(), 0, (struct sockaddr
*)&domain
.a
, domain
.a
.getSocklen()) < 0)
103 return pw
.getHeader()->id
;
106 bool receive(Identifier
& id
, DNSResult
& dr
)
108 if(waitForData(d_socket
, 0, 500000) > 0) {
111 from
.sin4
.sin_family
= AF_INET
;
112 socklen_t socklen
=from
.getSocklen();
113 int len
= recvfrom(d_socket
, buf
, sizeof(buf
),0, (struct sockaddr
*)&from
, &socklen
);
121 // parse packet, set 'id', fill out 'ip'
123 MOADNSParser
mdp(false, string(buf
, len
));
125 cout
<<"Reply to question for qname='"<<mdp
.d_qname
<<"', qtype="<<DNSRecordContent::NumberToType(mdp
.d_qtype
)<<endl
;
126 cout
<<"Rcode: "<<mdp
.d_header
.rcode
<<", RD: "<<mdp
.d_header
.rd
<<", QR: "<<mdp
.d_header
.qr
;
127 cout
<<", TC: "<<mdp
.d_header
.tc
<<", AA: "<<mdp
.d_header
.aa
<<", opcode: "<<mdp
.d_header
.opcode
<<endl
;
129 id
= mdp
.d_header
.id
;
130 d_idqueue
.push_back(id
);
131 dr
.qclass
= mdp
.d_qclass
;
134 for(const auto& a
: mdp
.d_answers
) {
135 if(a
.first
.d_type
== QType::TXT
) {
136 dr
.content
=a
.first
.d_content
->getZoneRepresentation();
137 dr
.ttl
=a
.first
.d_ttl
;
140 if(dr
.content
.empty())
141 dr
.content
="RCode: "+RCode::to_s(mdp
.d_header
.rcode
);
147 void deliverTimeout(const Identifier
& id
)
150 cout
<<"Timeout for id "<<id
<<endl
;
152 d_idqueue
.push_back(id
);
155 void deliverAnswer(NSQuery
& domain
, const DNSResult
& dr
, unsigned int usec
)
157 cout
<<domain
.a
.toString()<<"\t"<<domain
.qname
<<"\t";
158 for(const auto& n
: domain
.nsnames
)
160 cout
<<"\t"<<domain
.count
<<"\t"<<dr
.qclass
<<'\t'<<dr
.ttl
<<": "<<dr
.content
<<endl
;
162 if(dr
.qclass
==1 || toLower(dr
.content
).find("powerdns") != string::npos
|| dr
.ttl
==5) {
163 auto f
= d_res
.find(domain
.a
);
164 if(!f
->second
.isPowerDNS
) {
165 (*g_powerdns
)<<domain
.a
.toString()<<'\t'<<domain
.count
<<'\t';
166 for(const auto& n
: domain
.nsnames
)
167 (*g_powerdns
)<<n
<<'\t';
169 f
->second
.isPowerDNS
=true;
175 unsigned int d_errors
, d_nxdomains
, d_nodatas
, d_oks
, d_unknowns
;
176 unsigned int d_receiveds
, d_receiveerrors
, d_senderrors
;
177 map
<ComboAddress
, namecount
, ComboAddress::addressOnlyLessThan
>& d_res
;
183 vector
<ComboAddress
> addrs
;
187 typedef DNSName RESQuery
;
189 struct SendReceiveRes
191 typedef int Identifier
;
192 typedef RESResult Answer
; // ip
194 deque
<uint16_t> d_idqueue
;
195 map
<DNSName
, vector
<ComboAddress
>>& d_out
;
196 SendReceiveRes(const ComboAddress
& remote
, map
<DNSName
,vector
<ComboAddress
>>& out
) : d_out(out
)
198 d_socket
= socket(AF_INET
, SOCK_DGRAM
, 0);
200 setsockopt(d_socket
, SOL_SOCKET
, SO_REUSEADDR
, &val
, sizeof(val
));
201 connect(d_socket
, (struct sockaddr
*)&remote
, remote
.getSocklen());
202 for(unsigned int id
=0 ; id
< std::numeric_limits
<uint16_t>::max(); ++id
)
203 d_idqueue
.push_back(id
);
211 Identifier
send(RESQuery
& domain
)
213 //cerr<<"Sending query for '"<<domain<<"'"<<endl;
215 // send it, copy code from 'sdig'
216 vector
<uint8_t> packet
;
218 DNSPacketWriter
pw(packet
, domain
, QType::A
);
220 if(d_idqueue
.empty()) {
221 cerr
<<"Exhausted ids!"<<endl
;
224 pw
.getHeader()->id
= d_idqueue
.front();
225 d_idqueue
.pop_front();
226 pw
.getHeader()->rd
= 1;
227 pw
.getHeader()->qr
= 0;
229 if(::send(d_socket
, &*packet
.begin(), packet
.size(), 0) < 0) {
230 cout
<<"Error sending: "<<stringerror()<<endl
;
234 return pw
.getHeader()->id
;
237 bool receive(Identifier
& id
, RESResult
& dr
)
239 if(waitForData(d_socket
, 0, 500000) > 0) {
242 from
.sin4
.sin_family
= AF_INET
;
243 socklen_t socklen
=from
.getSocklen();
244 int len
= recvfrom(d_socket
, buf
, sizeof(buf
),0, (struct sockaddr
*)&from
, &socklen
);
252 // parse packet, set 'id', fill out 'ip'
254 MOADNSParser
mdp(false, string(buf
, len
));
256 cout
<<"Reply to question for qname='"<<mdp
.d_qname
<<"', qtype="<<DNSRecordContent::NumberToType(mdp
.d_qtype
)<<endl
;
257 cout
<<"Rcode: "<<mdp
.d_header
.rcode
<<", RD: "<<mdp
.d_header
.rd
<<", QR: "<<mdp
.d_header
.qr
<<", answers: "<<mdp
.d_answers
.size();
258 cout
<<", TC: "<<mdp
.d_header
.tc
<<", AA: "<<mdp
.d_header
.aa
<<", opcode: "<<mdp
.d_header
.opcode
<<endl
;
260 id
= mdp
.d_header
.id
;
261 d_idqueue
.push_back(id
);
262 dr
.rcode
= mdp
.d_header
.rcode
;
264 for(const auto& a
: mdp
.d_answers
) {
265 if(a
.first
.d_name
!= mdp
.d_qname
)
267 if(a
.first
.d_type
== QType::A
|| a
.first
.d_type
== QType::AAAA
) {
269 cout
<<a
.first
.d_content
->getZoneRepresentation()<<endl
;
270 dr
.addrs
.push_back(getAddr(a
.first
));
279 void deliverTimeout(const Identifier
& id
)
282 cout
<<"Timeout for id "<<id
<<endl
;
285 d_idqueue
.push_back(id
);
288 void deliverAnswer(DNSName
& domain
, const RESResult
& dr
, unsigned int usec
)
290 d_out
[domain
]=dr
.addrs
;
291 cout
<<domain
<<"\t"<<dr
.rcode
<<'\t';
292 for(const auto& a
: dr
.addrs
)
293 cout
<<a
.toString()<<'\t';
296 unsigned int d_errors
, d_nxdomains
, d_nodatas
, d_oks
, d_unknowns
;
297 unsigned int d_receiveds
, d_receiveerrors
, d_senderrors
;
311 int parseZone(const std::string
& str
, unsigned int limit
)
313 ZoneParserTNG
zpt(str
);
314 zpt
.disableGenerate();
315 DNSResourceRecord rr
;
317 std::thread
stats(printStats
);
319 map
<DNSName
,unsigned int> nsnames
;
320 map
<DNSName
,set
<ComboAddress
,ComboAddress::addressOnlyLessThan
> > addresses
;
324 if(rr
.qtype
.getCode() == QType::NS
)
325 nsnames
[DNSName(rr
.content
)]++;
326 else if(rr
.qtype
.getCode() == QType::A
|| rr
.qtype
.getCode() == QType::AAAA
) {
328 addresses
[rr
.qname
].insert(getAddr(dr
, 53));
337 cout
<<"Got "<<nsnames
.size()<<" different nameserver names"<<endl
;
338 cout
<<"Got at least one address for "<<addresses
.size()<<" names"<<endl
;
340 ofstream
ns(str
+".nameservers");
341 ofstream
needres(str
+".needres");
342 for(const auto& a
: nsnames
) {
343 ns
<<a
.first
<<"\t"<<a
.second
<<"\t";
344 if(auto hit
=rplookup(addresses
, a
.first
)) {
345 for(const auto& b
: *hit
)
346 ns
<<b
.toString()<<"\t";
349 needres
<<a
.first
<<"\n";
355 int resolveNS(const std::string
& fname
)
358 ifstream
needres(fname
);
360 unixDie("Unable to open file "+fname
);
361 vector
<DNSName
> tores
;
362 while(getline(needres
,line
)) {
363 tores
.push_back(DNSName(line
));
365 cerr
<<"Going to resolve "<<tores
.size()<<" names"<<endl
;
366 std::thread
stats(printStats
);
367 map
<DNSName
, vector
<ComboAddress
>> output
;
368 SendReceiveRes
sr(ComboAddress("192.168.1.2", 53), output
);
369 Inflighter
<vector
<DNSName
>, SendReceiveRes
> inflighter(tores
, sr
);
370 inflighter
.d_maxInFlight
= 1000;
371 inflighter
.d_timeoutSeconds
= 3;
372 inflighter
.d_burst
= 100;
378 catch(std::exception
& e
) {
379 cerr
<<"Caught exception: "<<e
.what()<<endl
;
387 void readRESNames(const std::string
& fname
, map
<DNSName
, vector
<ComboAddress
>>& addrs
)
391 unixDie("Reading resolved names from "+fname
+": "+stringerror());
392 vector
<string
> parts
;
395 while(getline(ifs
, line
)) {
397 stringtok(parts
, line
,"\t");
398 for(unsigned int n
=2; n
< parts
.size(); ++n
)
399 addrs
[DNSName(parts
[0])].push_back(ComboAddress(parts
[n
], 53));
401 //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
402 cerr
<<"Got "<<addrs
.size()<<" resolved nameserver names from file"<<endl
;
406 int main(int argc
, char**argv
)
412 if(mode
== "parse-zone") {
413 unsigned int limit
= 0;
415 limit
= atoi(argv
[3]);
417 return parseZone(argv
[2], limit
);
419 else if(mode
=="resolve-ns") {
420 return resolveNS(string(argv
[2])+".needres");
422 else if(mode
=="scan-ns") {
423 ifstream
ns(string(argv
[2])+".nameservers");
424 g_powerdns
= std::unique_ptr
<ofstream
>(new ofstream(string(argv
[2])+".powerdns"));
427 vector
<string
> parts
;
431 unsigned int count
{0};
432 vector
<ComboAddress
> addrs
;
434 map
<DNSName
, NSCount
> stats
;
436 // NS1.IHOST2000.COM. 9 162.251.82.122 162.251.82.123 162.251.82.250 162.251.82.251
437 while(getline(ns
, line
)) {
440 stringtok(parts
, line
,"\t");
441 nscount
.count
=atoi(parts
[1].c_str());
442 nscount
.addrs
.clear();
443 for(unsigned int n
= 2; n
< parts
.size(); ++n
)
444 nscount
.addrs
.push_back(ComboAddress(parts
[n
], 53));
445 stats
.insert({DNSName(parts
[0]), nscount
});
447 cerr
<<"Had "<<count
<<" lines from summary"<<endl
;
449 map
<DNSName
, vector
<ComboAddress
>> lookedup
;
450 readRESNames(argv
[2]+string(".resolved"), lookedup
);
452 map
<ComboAddress
, namecount
, ComboAddress::addressOnlyLessThan
> pure
;
454 unsigned int noaddrs
=0;
455 for(const auto& s
: stats
) {
456 auto ptr
= &s
.second
.addrs
;
458 if(lookedup
.count(s
.first
)) {
459 ptr
= &lookedup
[s
.first
];
462 //cout<<"Have no address for "<<s.first.toString()<<endl;
467 for(const auto& a
: *ptr
) {
468 pure
[a
].count
+= s
.second
.count
;
469 pure
[a
].names
.insert(s
.first
);
473 cerr
<<"Have "<<pure
.size()<<" IP addresses to query, "<<noaddrs
<<" names w/o address"<<endl
;
474 SendReceive
sr(pure
);
475 vector
<NSQuery
> domains
;
477 Inflighter
<vector
<NSQuery
>, SendReceive
> inflighter(domains
, sr
);
478 inflighter
.d_maxInFlight
= 1000;
479 inflighter
.d_timeoutSeconds
= 3;
480 inflighter
.d_burst
= 100;
482 for(const auto& p
: pure
) {
485 nsq
.nsnames
= p
.second
.names
;
486 nsq
.count
= p
.second
.count
;
488 nsq
.qname
=DNSName("version.bind");
489 domains
.push_back(nsq
);
490 nsq
.qname
=DNSName("id.server");
491 domains
.push_back(nsq
);
492 nsq
.qname
=DNSName("bind.version");
493 domains
.push_back(nsq
);
496 sort(domains
.begin(), domains
.end(), [](const NSQuery
& a
, const NSQuery
& b
) { return b
.count
< a
.count
; });
502 catch(std::exception
& e
) {
503 cerr
<<"Caught exception: "<<e
.what()<<endl
;
507 else if(mode
=="score-ns") {
508 std::unordered_set
<DNSName
> powerdns
;
509 ifstream
ifs(string(argv
[2])+".powerdns");
511 vector
<string
> parts
;
512 while(getline(ifs
,line
)) {
513 // 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.
515 stringtok(parts
, line
);
516 for(unsigned int n
=2; n
< parts
.size(); ++n
)
517 powerdns
.insert(DNSName(parts
[n
]));
519 cerr
<<"Have "<<powerdns
.size()<<" known NS names that are PowerDNS"<<endl
;
520 ZoneParserTNG
zpt(argv
[2]);
521 zpt
.disableGenerate();
522 DNSResourceRecord rr
;
524 set
<DNSName
> seen
, pdnsdomains
;
527 if(!seen
.count(rr
.qname
)) {
528 seen
.insert(rr
.qname
);
530 if(rr
.qtype
.getCode() == QType::NS
&& powerdns
.count(DNSName(rr
.content
)) && !pdnsdomains
.count(DNSName(rr
.qname
))) {
531 pdnsdomains
.insert(DNSName(rr
.qname
));
533 if(!(count
%100000)) {
534 cerr
<<"\rUnique domains: "<<seen
.size()<<", PowerDNS domains: "<<pdnsdomains
.size()<<" ("<<(pdnsdomains
.size()*100.0/seen
.size())<<"%)";
541 cerr
<<"Unknown mode "<<argv
[1]<<endl
;
543 // cout<<g_mtracer->topAllocatorsString(20)<<endl;
545 catch(PDNSException
& pe
) {
546 cerr
<<"Fatal error: "<<pe
.reason
<<endl
;