]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/nsec3dig.cc
Meson: Add systemd feature support for service files
[thirdparty/pdns.git] / pdns / nsec3dig.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 */
870a0fe4
AT
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
54ebc117
PD
25#include "dnsparser.hh"
26#include "sstuff.hh"
27#include "misc.hh"
28#include "dnswriter.hh"
29#include "dnsrecords.hh"
30#include "statbag.hh"
31#include "base32.hh"
32#include "dnssecinfra.hh"
fa8fd4d2 33
54ebc117
PD
34
35StatBag S;
36
37typedef std::pair<string,string> nsec3;
38typedef set<nsec3> nsec3set;
9ff464a7 39typedef map<string, int> nsec3types;
54ebc117 40
050e6877 41static string nsec3Hash(const DNSName &qname, const string &salt, unsigned int iters)
54ebc117 42{
28e2e78e
KM
43 NSEC3PARAMRecordContent ns3prc;
44 ns3prc.d_iterations = iters;
45 ns3prc.d_salt = salt;
46 return toBase32Hex(hashQNameWithSalt(ns3prc, qname));
54ebc117
PD
47}
48
9ff464a7 49static void proveOrDeny(const nsec3set &nsec3s, const nsec3types &nsec3t, const DNSName &qname, const string &salt, unsigned int iters, set<DNSName> &proven, set<DNSName> &denied)
54ebc117
PD
50{
51 string hashed = nsec3Hash(qname, salt, iters);
52
df69c422 53 // cerr<<"proveOrDeny(.., '"<<qname<<"', ..)"<<endl;
54ebc117
PD
54 // cerr<<"hashed: "<<hashed<<endl;
55 for(nsec3set::const_iterator pos=nsec3s.begin(); pos != nsec3s.end(); ++pos) {
56 string base=(*pos).first;
57 string next=(*pos).second;
58
59 if(hashed == base)
60 {
d2a2bbe7 61 proven.insert(qname);
9ff464a7 62 cout<<qname.toString()<<" ("<<hashed<<") proven by base ("<<nsec3t.at(base)<<" types) of "<<base<<".."<<next<<endl;
54ebc117
PD
63 }
64 if(hashed == next)
65 {
d2a2bbe7 66 proven.insert(qname);
9d7fa327 67 cout<<qname.toString()<<" ("<<hashed<<") proven by next of "<<base<<".."<<next<<endl;
54ebc117
PD
68 }
69 if((hashed > base && hashed < next) ||
70 (next < base && (hashed < next || hashed > base)))
71 {
d2a2bbe7 72 denied.insert(qname);
9d7fa327 73 cout<<qname.toString()<<" ("<<hashed<<") denied by "<<base<<".."<<next<<endl;
54ebc117 74 }
3e1cf1ed
PD
75 if (base == next && base != hashed)
76 {
77 denied.insert(qname);
9d7fa327 78 cout<<qname.toString()<<" ("<<hashed<<") denied by "<<base<<".."<<next<<endl;
3e1cf1ed 79 }
54ebc117 80 }
54ebc117
PD
81}
82
050e6877 83static void usage() {
7b7543ad
PL
84 cerr<<"nsec3dig"<<endl;
85 cerr<<"Syntax: nsec3dig IP-ADDRESS PORT QUESTION QUESTION-TYPE [recurse]\n";
86}
87
54ebc117
PD
88int main(int argc, char** argv)
89try
90{
91 bool recurse=false;
92
93 reportAllTypes();
94
7b7543ad
PL
95 for (int i = 1; i < argc; i++) {
96 if ((string) argv[i] == "--help") {
97 usage();
98 return EXIT_SUCCESS;
99 }
100
101 if ((string) argv[i] == "--version") {
102 cerr<<"nsec3dig "<<VERSION<<endl;
103 return EXIT_SUCCESS;
104 }
105 }
106
54ebc117 107 if(argc < 5) {
7b7543ad 108 usage();
54ebc117
PD
109 exit(EXIT_FAILURE);
110 }
111
54ebc117
PD
112 if(argc > 5 && strcmp(argv[5], "recurse")==0)
113 {
114 recurse=true;
115 }
116
117 vector<uint8_t> packet;
eaedd091 118 DNSName qname(argv[3]);
54ebc117
PD
119 DNSPacketWriter pw(packet, qname, DNSRecordContent::TypeToNumber(argv[4]));
120
121 if(recurse)
122 {
123 pw.getHeader()->rd=true;
7103fdd8 124 pw.getHeader()->cd=true;
54ebc117
PD
125 }
126
127 pw.addOpt(2800, 0, EDNSOpts::DNSSECOK);
128 pw.commit();
129
d4eba262 130
54ebc117 131 ComboAddress dest(argv[1] + (*argv[1]=='@'), atoi(argv[2]));
d4eba262 132 Socket sock(dest.sin4.sin_family, SOCK_STREAM);
c5c4fbdc
PD
133 sock.connect(dest);
134 uint16_t len;
135 len = htons(packet.size());
136 if(sock.write((char *) &len, 2) != 2)
3f81d239 137 throw PDNSException("tcp write failed");
c5c4fbdc 138
16657041 139 sock.writen(string(packet.begin(), packet.end()));
54ebc117 140
c5c4fbdc 141 if(sock.read((char *) &len, 2) != 2)
3f81d239 142 throw PDNSException("tcp read failed");
c5c4fbdc
PD
143
144 len=ntohs(len);
2bbc9eb0 145 auto creply = std::make_unique<char[]>(len);
c5c4fbdc
PD
146 int n=0;
147 int numread;
148 while(n<len) {
c2826d2e 149 numread=sock.read(creply.get()+n, len-n);
c5c4fbdc 150 if(numread<0)
3f81d239 151 throw PDNSException("tcp read failed");
c5c4fbdc
PD
152 n+=numread;
153 }
154
c2826d2e 155 string reply(creply.get(), len);
54ebc117 156
27c0050c 157 MOADNSParser mdp(false, reply);
eaedd091 158 cout<<"Reply to question for qname='"<<mdp.d_qname<<"', qtype="<<DNSRecordContent::NumberToType(mdp.d_qtype)<<endl;
54ebc117
PD
159 cout<<"Rcode: "<<mdp.d_header.rcode<<", RD: "<<mdp.d_header.rd<<", QR: "<<mdp.d_header.qr;
160 cout<<", TC: "<<mdp.d_header.tc<<", AA: "<<mdp.d_header.aa<<", opcode: "<<mdp.d_header.opcode<<endl;
161
9d7fa327
PD
162 set<DNSName> names;
163 set<DNSName> namesseen;
164 set<DNSName> namestocheck;
54ebc117 165 nsec3set nsec3s;
9ff464a7 166 nsec3types nsec3t;
54ebc117 167 string nsec3salt;
59c892fe 168 int nsec3iters = 0;
54ebc117
PD
169 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
170 if(i->first.d_type == QType::NSEC3)
171 {
f809c028 172 // cerr<<"got nsec3 ["<<i->first.d_name<<"]"<<endl;
54ebc117 173 // cerr<<i->first.d_content->getZoneRepresentation()<<endl;
d06dcda4 174 const auto r = getRR<NSEC3RecordContent>(i->first);
27d4a65b
RG
175 if (!r) {
176 continue;
177 }
54ebc117
PD
178 // nsec3.insert(new nsec3()
179 // cerr<<toBase32Hex(r.d_nexthash)<<endl;
e32a8d46 180 nsec3s.emplace(toLower(i->first.d_name.getRawLabel(0)), toBase32Hex(r->d_nexthash));
27d4a65b
RG
181 nsec3salt = r->d_salt;
182 nsec3iters = r->d_iterations;
e32a8d46 183 nsec3t.emplace(toLower(i->first.d_name.getRawLabel(0)), r->numberOfTypesSet());
54ebc117
PD
184 }
185 else
186 {
f809c028 187 // cerr<<"namesseen.insert('"<<i->first.d_name<<"')"<<endl;
188 names.insert(i->first.d_name);
189 namesseen.insert(i->first.d_name);
c5c4fbdc
PD
190 }
191
192 if(i->first.d_type == QType::CNAME)
193 {
d06dcda4 194 namesseen.insert(DNSName(i->first.getContent()->getZoneRepresentation()));
54ebc117
PD
195 }
196
b8a6d4f7 197 cout << i->first.d_place - 1 << "\t" << i->first.d_name.toString() << "\t" << i->first.d_ttl << "\tIN\t" << DNSRecordContent::NumberToType(i->first.d_type);
d06dcda4 198 cout << "\t" << i->first.getContent()->getZoneRepresentation() << "\n";
54ebc117
PD
199 }
200
201#if 0
202 cerr<<"got "<<names.size()<<" names"<<endl;
203 for(set<string>::const_iterator pos=names.begin(); pos != names.end(); ++pos) {
204 cerr<<"name: "<<*pos<<endl;
205 }
206 cerr<<"got "<<nsec3s.size()<<" names"<<endl;
207 for(nsec3set::const_iterator pos=nsec3s.begin(); pos != nsec3s.end(); ++pos) {
208 cerr<<"nsec3: "<<(*pos).first<<".."<<(*pos).second<<endl;
209 }
210#endif
211
212 cout<<"== nsec3 prove/deny report follows =="<<endl;
9d7fa327
PD
213 set<DNSName> proven;
214 set<DNSName> denied;
eaedd091 215 namesseen.insert(qname);
2010ac95 216 for(const auto &name: namesseen)
df69c422 217 {
2010ac95 218 DNSName shorter(name);
df69c422
PD
219 do {
220 namestocheck.insert(shorter);
9d7fa327 221 } while(shorter.chopOff());
df69c422 222 }
2010ac95 223 for(const auto &name: namestocheck)
df69c422 224 {
9ff464a7
PD
225 proveOrDeny(nsec3s, nsec3t, name, nsec3salt, nsec3iters, proven, denied);
226 proveOrDeny(nsec3s, nsec3t, g_wildcarddnsname+name, nsec3salt, nsec3iters, proven, denied);
df69c422 227 }
d2a2bbe7 228
eaedd091 229 if(names.count(qname))
d2a2bbe7 230 {
75a89ce6
PD
231 cout<<"== qname found in names, investigating NSEC3s in case it's a wildcard"<<endl;
232 // exit(EXIT_SUCCESS);
d2a2bbe7 233 }
75a89ce6 234 // cout<<"== qname not found in names, investigating denial"<<endl;
d2a2bbe7
PD
235 if(proven.count(qname))
236 {
237 cout<<"qname found proven, NODATA response?"<<endl;
238 exit(EXIT_SUCCESS);
239 }
9d7fa327
PD
240 DNSName shorter=qname;
241 DNSName encloser;
242 DNSName nextcloser;
243 DNSName prev(qname);
244 while(shorter.chopOff())
d2a2bbe7
PD
245 {
246 if(proven.count(shorter))
247 {
248 encloser=shorter;
249 nextcloser=prev;
9d7fa327
PD
250 cout<<"found closest encloser at "<<encloser.toString()<<endl;
251 cout<<"next closer is "<<nextcloser.toString()<<endl;
d2a2bbe7
PD
252 break;
253 }
254 prev=shorter;
255 }
9d7fa327 256 if(encloser.countLabels() && nextcloser.countLabels())
d2a2bbe7
PD
257 {
258 if(denied.count(nextcloser))
259 {
9d7fa327 260 cout<<"next closer ("<<nextcloser.toString()<<") is denied correctly"<<endl;
d2a2bbe7
PD
261 }
262 else
263 {
9d7fa327 264 cout<<"next closer ("<<nextcloser.toString()<<") NOT denied"<<endl;
d2a2bbe7 265 }
12c06211 266 DNSName wcplusencloser=g_wildcarddnsname+encloser;
9d7fa327 267 if(denied.count(wcplusencloser))
d2a2bbe7 268 {
9d7fa327 269 cout<<"wildcard at encloser ("<<wcplusencloser.toString()<<") is denied correctly"<<endl;
d2a2bbe7 270 }
9d7fa327 271 else if(proven.count(wcplusencloser))
75a89ce6 272 {
9d7fa327 273 cout<<"wildcard at encloser ("<<wcplusencloser.toString()<<") is proven"<<endl;
75a89ce6 274 }
d2a2bbe7
PD
275 else
276 {
9d7fa327 277 cout<<"wildcard at encloser ("<<wcplusencloser.toString()<<") is NOT denied or proven"<<endl;
d2a2bbe7
PD
278 }
279 }
280 exit(EXIT_SUCCESS);
54ebc117
PD
281}
282catch(std::exception &e)
283{
284 cerr<<"Fatal: "<<e.what()<<endl;
285}
7e7c31aa
PD
286catch(PDNSException &e)
287{
288 cerr<<"Fatal: "<<e.reason<<endl;
289}