]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/sdig.cc
4 #include "dnsparser.hh"
5 #include "ednsoptions.hh"
8 #include "dnswriter.hh"
9 #include "dnsrecords.hh"
11 #include <boost/array.hpp>
12 #include "ednssubnet.hh"
15 #include "minicurl.hh"
22 string
ttl(uint32_t ttl
)
27 return std::to_string(ttl
);
32 cerr
<<"Syntax: sdig IP-ADDRESS-OR-DOH-URL PORT QUESTION QUESTION-TYPE [dnssec] [ednssubnet SUBNET/MASK] [hidesoadetails] [hidettl] [recurse] [showflags] [tcp] [xpf XPFDATA]"<<endl
;
35 const string
nameForClass(uint16_t qclass
, uint16_t qtype
)
37 if (qtype
== QType::OPT
) return "IN";
40 case QClass::IN
: return "IN";
41 case QClass::CHAOS
: return "CHAOS";
42 case QClass::NONE
: return "NONE";
43 case QClass::ANY
: return "ANY";
44 default: return string("CLASS")+std::to_string(qclass
);
48 int main(int argc
, char** argv
)
55 bool hidesoadetails
=false;
57 boost::optional
<Netmask
> ednsnm
;
58 uint16_t xpfcode
= 0, xpfversion
= 0, xpfproto
= 0;
59 char *xpfsrc
= NULL
, *xpfdst
= NULL
;
61 for(int i
=1; i
<argc
; i
++) {
62 if ((string
) argv
[i
] == "--help") {
67 if ((string
) argv
[i
] == "--version") {
68 cerr
<<"sdig "<<VERSION
<<endl
;
81 for(int i
=5; i
<argc
; i
++) {
82 if (strcmp(argv
[i
], "dnssec") == 0)
84 if (strcmp(argv
[i
], "recurse") == 0)
86 if (strcmp(argv
[i
], "showflags") == 0)
88 if (strcmp(argv
[i
], "hidesoadetails") == 0)
90 if (strcmp(argv
[i
], "hidettl") == 0)
92 if (strcmp(argv
[i
], "tcp") == 0)
94 if (strcmp(argv
[i
], "ednssubnet") == 0) {
96 cerr
<<"ednssubnet needs an argument"<<endl
;
99 ednsnm
=Netmask(argv
[++i
]);
101 if (strcmp(argv
[i
], "xpf") == 0) {
103 cerr
<<"xpf needs five arguments"<<endl
;
106 xpfcode
= atoi(argv
[++i
]);
107 xpfversion
= atoi(argv
[++i
]);
108 xpfproto
= atoi(argv
[++i
]);
115 vector
<uint8_t> packet
;
117 DNSPacketWriter
pw(packet
, DNSName(argv
[3]), DNSRecordContent::TypeToNumber(argv
[4]));
119 if(dnssec
|| ednsnm
|| getenv("SDIGBUFSIZE"))
121 char *sbuf
=getenv("SDIGBUFSIZE");
127 DNSPacketWriter::optvect_t opts
;
131 opts
.push_back(make_pair(EDNSOptionCode::ECS
, makeEDNSSubnetOptsString(eo
)));
134 pw
.addOpt(bufsize
, 0, dnssec
? EDNSOpts::DNSSECOK
: 0, opts
);
140 ComboAddress
src(xpfsrc
), dst(xpfdst
);
141 pw
.startRecord(DNSName("."), xpfcode
, 0, 1, DNSResourceRecord::ADDITIONAL
);
142 // xpf->toPacket(pw);
143 pw
.xfr8BitInt(xpfversion
);
144 pw
.xfr8BitInt(xpfproto
);
145 pw
.xfrCAWithoutPort(xpfversion
, src
);
146 pw
.xfrCAWithoutPort(xpfversion
, dst
);
154 pw
.getHeader()->rd
=true;
158 string
question(packet
.begin(), packet
.end());
164 dest
= ComboAddress(argv
[1] + (*argv
[1]=='@'), atoi(argv
[2]));
170 MiniCurl::MiniCurlHeaders mch
;
171 mch
.insert(std::make_pair("Content-Type", "application/dns-message"));
172 mch
.insert(std::make_pair("Accept", "application/dns-message"));
173 reply
= mc
.postURL(argv
[1], question
, mch
);
175 throw PDNSException("please link sdig against libcurl for DoH support");
179 Socket
sock(dest
.sin4
.sin_family
, SOCK_STREAM
);
182 len
= htons(packet
.size());
183 if(sock
.write((char *) &len
, 2) != 2)
184 throw PDNSException("tcp write failed");
186 sock
.writen(question
);
188 if(sock
.read((char *) &len
, 2) != 2)
189 throw PDNSException("tcp read failed");
192 char *creply
= new char[len
];
196 numread
=sock
.read(creply
+n
, len
-n
);
198 throw PDNSException("tcp read failed");
202 reply
=string(creply
, len
);
207 Socket
sock(dest
.sin4
.sin_family
, SOCK_DGRAM
);
208 sock
.sendTo(question
, dest
);
209 int result
=waitForData(sock
.getHandle(), 10);
211 throw std::runtime_error("Error waiting for data: "+string(strerror(errno
)));
213 throw std::runtime_error("Timeout waiting for data");
214 sock
.recvFrom(reply
, dest
);
216 MOADNSParser
mdp(false, reply
);
217 cout
<<"Reply to question for qname='"<<mdp
.d_qname
.toString()<<"', qtype="<<DNSRecordContent::NumberToType(mdp
.d_qtype
)<<endl
;
218 cout
<<"Rcode: "<<mdp
.d_header
.rcode
<<" ("<<RCode::to_s(mdp
.d_header
.rcode
)<<"), RD: "<<mdp
.d_header
.rd
<<", QR: "<<mdp
.d_header
.qr
;
219 cout
<<", TC: "<<mdp
.d_header
.tc
<<", AA: "<<mdp
.d_header
.aa
<<", opcode: "<<mdp
.d_header
.opcode
<<endl
;
221 for(MOADNSParser::answers_t::const_iterator i
=mdp
.d_answers
.begin(); i
!=mdp
.d_answers
.end(); ++i
) {
222 cout
<<i
->first
.d_place
-1<<"\t"<<i
->first
.d_name
.toString()<<"\t"<<nameForClass(i
->first
.d_class
, i
->first
.d_type
)<<"\t"<<DNSRecordContent::NumberToType(i
->first
.d_type
);
223 if(i
->first
.d_class
== QClass::IN
)
225 if(i
->first
.d_type
== QType::RRSIG
)
227 string zoneRep
= i
->first
.d_content
->getZoneRepresentation();
228 vector
<string
> parts
;
229 stringtok(parts
, zoneRep
);
230 cout
<<"\t"<<ttl(i
->first
.d_ttl
)<<"\t"<< parts
[0]<<" "<<parts
[1]<<" "<<parts
[2]<<" "<<parts
[3]<<" [expiry] [inception] [keytag] "<<parts
[7]<<" ...\n";
233 if(!showflags
&& i
->first
.d_type
== QType::NSEC3
)
235 string zoneRep
= i
->first
.d_content
->getZoneRepresentation();
236 vector
<string
> parts
;
237 stringtok(parts
, zoneRep
);
238 cout
<<"\t"<<ttl(i
->first
.d_ttl
)<<"\t"<< parts
[0]<<" [flags] "<<parts
[2]<<" "<<parts
[3]<<" "<<parts
[4];
239 for(vector
<string
>::iterator iter
= parts
.begin()+5; iter
!= parts
.end(); ++iter
)
244 if(i
->first
.d_type
== QType::DNSKEY
)
246 string zoneRep
= i
->first
.d_content
->getZoneRepresentation();
247 vector
<string
> parts
;
248 stringtok(parts
, zoneRep
);
249 cout
<<"\t"<<ttl(i
->first
.d_ttl
)<<"\t"<< parts
[0]<<" "<<parts
[1]<<" "<<parts
[2]<<" ...\n";
252 if (i
->first
.d_type
== QType::SOA
&& hidesoadetails
)
254 string zoneRep
= i
->first
.d_content
->getZoneRepresentation();
255 vector
<string
> parts
;
256 stringtok(parts
, zoneRep
);
257 cout
<<"\t"<<ttl(i
->first
.d_ttl
)<<"\t"<<parts
[0]<<" "<<parts
[1]<<" [serial] "<<parts
[3]<<" "<<parts
[4]<<" "<<parts
[5]<<" "<<parts
[6]<<"\n";
261 cout
<<"\t"<<ttl(i
->first
.d_ttl
)<<"\t"<< i
->first
.d_content
->getZoneRepresentation()<<"\n";
265 if(getEDNSOpts(mdp
, &edo
)) {
266 // cerr<<"Have "<<edo.d_options.size()<<" options!"<<endl;
267 for(vector
<pair
<uint16_t, string
> >::const_iterator iter
= edo
.d_options
.begin();
268 iter
!= edo
.d_options
.end();
270 if(iter
->first
== EDNSOptionCode::ECS
) {// 'EDNS subnet'
272 if(getEDNSSubnetOptsFromString(iter
->second
, &reso
)) {
273 cerr
<<"EDNS Subnet response: "<<reso
.source
.toString()<<", scope: "<<reso
.scope
.toString()<<", family = "<<reso
.scope
.getNetwork().sin4
.sin_family
<<endl
;
276 else if(iter
->first
== EDNSOptionCode::PADDING
) {
277 cerr
<<"EDNS Padding size: "<<(iter
->second
.size())<<endl
;
280 cerr
<<"Have unknown option "<<(int)iter
->first
<<endl
;
286 catch(std::exception
&e
)
288 cerr
<<"Fatal: "<<e
.what()<<endl
;
290 catch(PDNSException
&e
)
292 cerr
<<"Fatal: "<<e
.reason
<<endl
;