]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/validate-recursor.cc
Merge pull request #4790 from pieterlexis/manpage-fixes
[thirdparty/pdns.git] / pdns / validate-recursor.cc
1 #include "validate.hh"
2 #include "validate-recursor.hh"
3 #include "syncres.hh"
4 #include "logger.hh"
5
6 DNSSECMode g_dnssecmode{DNSSECMode::ProcessNoValidate};
7 bool g_dnssecLogBogus;
8
9 #define LOG(x) if(g_dnssecLOG) { L <<Logger::Warning << x; }
10
11 class SRRecordOracle : public DNSRecordOracle
12 {
13 public:
14 SRRecordOracle(const ResolveContext& ctx): d_ctx(ctx)
15 {
16 }
17 vector<DNSRecord> get(const DNSName& qname, uint16_t qtype) override
18 {
19 struct timeval tv;
20 gettimeofday(&tv, 0);
21 SyncRes sr(tv);
22 sr.setId(MT->getTid());
23 #ifdef HAVE_PROTOBUF
24 sr.d_initialRequestId = d_ctx.d_initialRequestId;
25 #endif
26
27 vector<DNSRecord> ret;
28 sr.d_doDNSSEC=true;
29 if (qtype == QType::DS || qtype == QType::DNSKEY || qtype == QType::NS)
30 sr.setSkipCNAMECheck(true);
31 sr.beginResolve(qname, QType(qtype), 1, ret);
32 d_queries += sr.d_outqueries;
33 return ret;
34 }
35 const ResolveContext& d_ctx;
36 int d_queries{0};
37 };
38
39 bool checkDNSSECDisabled() {
40 return warnIfDNSSECDisabled("");
41 }
42
43 bool warnIfDNSSECDisabled(const string& msg) {
44 if(g_dnssecmode == DNSSECMode::Off) {
45 if (!msg.empty())
46 L<<Logger::Warning<<msg<<endl;
47 return true;
48 }
49 return false;
50 }
51
52 inline vState increaseDNSSECStateCounter(const vState& state)
53 {
54 g_stats.dnssecResults[state]++;
55 return state;
56 }
57
58 /*
59 * This inline possibly sets currentState based on the new state. It will only
60 * set it to Secure iff the newState is Secure and mayUpgradeToSecure == true.
61 * This should be set by the calling function when checking more than one record
62 * and this is not the first record, this way, we can never go *back* to Secure
63 * from an Insecure vState
64 */
65 inline void processNewState(vState& currentState, const vState& newState, bool& hadNTA, const bool& mayUpgradeToSecure)
66 {
67 if (mayUpgradeToSecure && newState == Secure)
68 currentState = Secure;
69
70 if (newState == Insecure || newState == NTA) // We can never go back to Secure
71 currentState = Insecure;
72
73 if (newState == NTA)
74 hadNTA = true;
75 }
76
77 vState validateRecords(const ResolveContext& ctx, const vector<DNSRecord>& recs)
78 {
79 if(recs.empty())
80 return Insecure; // can't secure nothing
81
82 g_stats.dnssecValidations++;
83
84 cspmap_t cspmap=harvestCSPFromRecs(recs);
85 LOG("Got "<<cspmap.size()<<" RRSETs: "<<endl);
86 int numsigs=0;
87 for(const auto& csp : cspmap) {
88 LOG("Going to validate: "<<csp.first.first<<"/"<<DNSRecordContent::NumberToType(csp.first.second)<<": "<<csp.second.signatures.size()<<" sigs for "<<csp.second.records.size()<<" records"<<endl);
89 numsigs+= csp.second.signatures.size();
90 }
91
92 set<DNSKEYRecordContent> keys;
93 cspmap_t validrrsets;
94
95 SRRecordOracle sro(ctx);
96
97 vState state=Insecure;
98 bool hadNTA = false;
99 if(numsigs) {
100 bool first = true;
101 for(const auto& csp : cspmap) {
102 for(const auto& sig : csp.second.signatures) {
103 vState newState = getKeysFor(sro, sig->d_signer, keys); // XXX check validity here
104
105 if (newState == Bogus) // No hope
106 return increaseDNSSECStateCounter(Bogus);
107
108 processNewState(state, newState, hadNTA, first);
109
110 first = false;
111
112 LOG("! state = "<<vStates[state]<<", now have "<<keys.size()<<" keys"<<endl);
113 for(const auto& k : keys) {
114 LOG("Key: "<<k.getZoneRepresentation()<< " {tag="<<k.getTag()<<"}"<<endl);
115 }
116 }
117 }
118 validateWithKeySet(cspmap, validrrsets, keys);
119 }
120 else {
121 LOG("! no sigs, hoping for Insecure status of "<<recs.begin()->d_name<<endl);
122
123 bool first = true;
124 for(const auto& rec : recs) {
125 vState newState = getKeysFor(sro, rec.d_name, keys);
126
127 if (newState == Bogus) // We're done
128 return increaseDNSSECStateCounter(Bogus);
129
130 processNewState(state, newState, hadNTA, first);
131 first = false;
132
133 LOG("! state = "<<vStates[state]<<", now have "<<keys.size()<<" keys "<<endl);
134 }
135 return increaseDNSSECStateCounter(state);
136 }
137
138 LOG("Took "<<sro.d_queries<<" queries"<<endl);
139 if(validrrsets.size() == cspmap.size())// shortcut - everything was ok
140 return increaseDNSSECStateCounter(Secure);
141
142 if(state == Insecure || keys.empty()) {
143 if (hadNTA) {
144 increaseDNSSECStateCounter(NTA);
145 return Insecure;
146 }
147 return increaseDNSSECStateCounter(Insecure);
148 }
149
150 #if 0
151 cerr<<"! validated "<<validrrsets.size()<<" RRsets out of "<<cspmap.size()<<endl;
152
153 cerr<<"% validated RRs:"<<endl;
154 for(auto i=validrrsets.begin(); i!=validrrsets.end(); i++) {
155 cerr<<"% "<<i->first.first<<"/"<<DNSRecordContent::NumberToType(i->first.second)<<endl;
156 for(auto j=i->second.records.begin(); j!=i->second.records.end(); j++) {
157 cerr<<"\t% > "<<(*j)->getZoneRepresentation()<<endl;
158 }
159 }
160 #endif
161 // cerr<<"Input to validate: "<<endl;
162 for(const auto& csp : cspmap) {
163 LOG(csp.first.first<<"|"<<DNSRecordContent::NumberToType(csp.first.second)<<" with "<<csp.second.signatures.size()<<" signatures"<<endl);
164 if(!csp.second.signatures.empty() && !validrrsets.count(csp.first)) {
165 LOG("Lacks signature, must have one, signatures: "<<csp.second.signatures.size()<<", valid rrsets: "<<validrrsets.count(csp.first)<<endl);
166 return increaseDNSSECStateCounter(Bogus);
167 }
168 }
169 return increaseDNSSECStateCounter(Insecure);
170 }