]>
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: "<<strerror(errno
)<<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 DNSResourceRecord rr
;
316 std::thread
stats(printStats
);
318 map
<DNSName
,unsigned int> nsnames
;
319 map
<DNSName
,set
<ComboAddress
,ComboAddress::addressOnlyLessThan
> > addresses
;
323 if(rr
.qtype
.getCode() == QType::NS
)
324 nsnames
[DNSName(rr
.content
)]++;
325 else if(rr
.qtype
.getCode() == QType::A
|| rr
.qtype
.getCode() == QType::AAAA
) {
327 addresses
[rr
.qname
].insert(getAddr(dr
, 53));
336 cout
<<"Got "<<nsnames
.size()<<" different nameserver names"<<endl
;
337 cout
<<"Got at least one address for "<<addresses
.size()<<" names"<<endl
;
339 ofstream
ns(str
+".nameservers");
340 ofstream
needres(str
+".needres");
341 for(const auto& a
: nsnames
) {
342 ns
<<a
.first
<<"\t"<<a
.second
<<"\t";
343 if(auto hit
=rplookup(addresses
, a
.first
)) {
344 for(const auto& b
: *hit
)
345 ns
<<b
.toString()<<"\t";
348 needres
<<a
.first
<<"\n";
354 int resolveNS(const std::string
& fname
)
357 ifstream
needres(fname
);
359 unixDie("Unable to open file "+fname
);
360 vector
<DNSName
> tores
;
361 while(getline(needres
,line
)) {
362 tores
.push_back(DNSName(line
));
364 cerr
<<"Going to resolve "<<tores
.size()<<" names"<<endl
;
365 std::thread
stats(printStats
);
366 map
<DNSName
, vector
<ComboAddress
>> output
;
367 SendReceiveRes
sr(ComboAddress("192.168.1.2", 53), output
);
368 Inflighter
<vector
<DNSName
>, SendReceiveRes
> inflighter(tores
, sr
);
369 inflighter
.d_maxInFlight
= 1000;
370 inflighter
.d_timeoutSeconds
= 3;
371 inflighter
.d_burst
= 100;
377 catch(std::exception
& e
) {
378 cerr
<<"Caught exception: "<<e
.what()<<endl
;
386 void readRESNames(const std::string
& fname
, map
<DNSName
, vector
<ComboAddress
>>& addrs
)
390 unixDie("Reading resolved names from "+fname
+": "+string(strerror(errno
)));
391 vector
<string
> parts
;
394 while(getline(ifs
, line
)) {
396 stringtok(parts
, line
,"\t");
397 for(unsigned int n
=2; n
< parts
.size(); ++n
)
398 addrs
[DNSName(parts
[0])].push_back(ComboAddress(parts
[n
], 53));
400 //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
401 cerr
<<"Got "<<addrs
.size()<<" resolved nameserver names from file"<<endl
;
405 int main(int argc
, char**argv
)
411 if(mode
== "parse-zone") {
412 unsigned int limit
= 0;
414 limit
= atoi(argv
[3]);
416 return parseZone(argv
[2], limit
);
418 else if(mode
=="resolve-ns") {
419 return resolveNS(string(argv
[2])+".needres");
421 else if(mode
=="scan-ns") {
422 ifstream
ns(string(argv
[2])+".nameservers");
423 g_powerdns
= make_unique
<ofstream
>(string(argv
[2])+".powerdns");
426 vector
<string
> parts
;
430 unsigned int count
{0};
431 vector
<ComboAddress
> addrs
;
433 map
<DNSName
, NSCount
> stats
;
435 // NS1.IHOST2000.COM. 9 162.251.82.122 162.251.82.123 162.251.82.250 162.251.82.251
436 while(getline(ns
, line
)) {
439 stringtok(parts
, line
,"\t");
440 nscount
.count
=atoi(parts
[1].c_str());
441 nscount
.addrs
.clear();
442 for(unsigned int n
= 2; n
< parts
.size(); ++n
)
443 nscount
.addrs
.push_back(ComboAddress(parts
[n
], 53));
444 stats
.insert({DNSName(parts
[0]), nscount
});
446 cerr
<<"Had "<<count
<<" lines from summary"<<endl
;
448 map
<DNSName
, vector
<ComboAddress
>> lookedup
;
449 readRESNames(argv
[2]+string(".resolved"), lookedup
);
451 map
<ComboAddress
, namecount
, ComboAddress::addressOnlyLessThan
> pure
;
453 unsigned int noaddrs
=0;
454 for(const auto& s
: stats
) {
455 auto ptr
= &s
.second
.addrs
;
457 if(lookedup
.count(s
.first
)) {
458 ptr
= &lookedup
[s
.first
];
461 //cout<<"Have no address for "<<s.first.toString()<<endl;
466 for(const auto& a
: *ptr
) {
467 pure
[a
].count
+= s
.second
.count
;
468 pure
[a
].names
.insert(s
.first
);
472 cerr
<<"Have "<<pure
.size()<<" IP addresses to query, "<<noaddrs
<<" names w/o address"<<endl
;
473 SendReceive
sr(pure
);
474 vector
<NSQuery
> domains
;
476 Inflighter
<vector
<NSQuery
>, SendReceive
> inflighter(domains
, sr
);
477 inflighter
.d_maxInFlight
= 1000;
478 inflighter
.d_timeoutSeconds
= 3;
479 inflighter
.d_burst
= 100;
481 for(const auto& p
: pure
) {
484 nsq
.nsnames
= p
.second
.names
;
485 nsq
.count
= p
.second
.count
;
487 nsq
.qname
=DNSName("version.bind");
488 domains
.push_back(nsq
);
489 nsq
.qname
=DNSName("id.server");
490 domains
.push_back(nsq
);
491 nsq
.qname
=DNSName("bind.version");
492 domains
.push_back(nsq
);
495 sort(domains
.begin(), domains
.end(), [](const NSQuery
& a
, const NSQuery
& b
) { return b
.count
< a
.count
; });
501 catch(std::exception
& e
) {
502 cerr
<<"Caught exception: "<<e
.what()<<endl
;
506 else if(mode
=="score-ns") {
507 std::unordered_set
<DNSName
> powerdns
;
508 ifstream
ifs(string(argv
[2])+".powerdns");
510 vector
<string
> parts
;
511 while(getline(ifs
,line
)) {
512 // 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.
514 stringtok(parts
, line
);
515 for(unsigned int n
=2; n
< parts
.size(); ++n
)
516 powerdns
.insert(DNSName(parts
[n
]));
518 cerr
<<"Have "<<powerdns
.size()<<" known NS names that are PowerDNS"<<endl
;
519 ZoneParserTNG
zpt(argv
[2]);
520 DNSResourceRecord rr
;
522 set
<DNSName
> seen
, pdnsdomains
;
525 if(!seen
.count(rr
.qname
)) {
526 seen
.insert(rr
.qname
);
528 if(rr
.qtype
.getCode() == QType::NS
&& powerdns
.count(DNSName(rr
.content
)) && !pdnsdomains
.count(DNSName(rr
.qname
))) {
529 pdnsdomains
.insert(DNSName(rr
.qname
));
531 if(!(count
%100000)) {
532 cerr
<<"\rUnique domains: "<<seen
.size()<<", PowerDNS domains: "<<pdnsdomains
.size()<<" ("<<(pdnsdomains
.size()*100.0/seen
.size())<<"%)";
539 cerr
<<"Unknown mode "<<argv
[1]<<endl
;
541 // cout<<g_mtracer->topAllocatorsString(20)<<endl;
543 catch(PDNSException
& pe
) {
544 cerr
<<"Fatal error: "<<pe
.reason
<<endl
;