/src/pdns/pdns/nsecrecords.cc
Line | Count | Source |
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 | | */ |
22 | | #ifdef HAVE_CONFIG_H |
23 | | #include "config.h" |
24 | | #endif |
25 | | #include "dnsrecords.hh" |
26 | | |
27 | | class NSECBitmapGenerator |
28 | | { |
29 | | public: |
30 | 615 | NSECBitmapGenerator(DNSPacketWriter& pw_): pw(pw_) |
31 | 615 | { |
32 | 615 | memset(res, 0, sizeof(res)); |
33 | 615 | } |
34 | | |
35 | | void set(uint16_t type) |
36 | 993 | { |
37 | 993 | uint16_t bit = type % 256; |
38 | 993 | int window = static_cast<int>(type / 256); |
39 | | |
40 | 993 | if (window != oldWindow) { |
41 | 616 | if (oldWindow > -1) { |
42 | 369 | res[0] = static_cast<unsigned char>(oldWindow); |
43 | 369 | res[1] = static_cast<unsigned char>(len); |
44 | 369 | tmp.assign(res, res+len+2); |
45 | 369 | pw.xfrBlob(tmp); |
46 | 369 | } |
47 | 616 | memset(res, 0, sizeof(res)); |
48 | 616 | oldWindow = window; |
49 | 616 | } |
50 | 993 | res[2+bit/8] |= 1 << (7-(bit%8)); |
51 | 993 | len=1+bit/8; |
52 | 993 | } |
53 | | |
54 | | void finish() |
55 | 615 | { |
56 | 615 | res[0] = static_cast<unsigned char>(oldWindow); |
57 | 615 | res[1] = static_cast<unsigned char>(len); |
58 | 615 | if (len) { |
59 | 247 | tmp.assign(res, res+len+2); |
60 | 247 | pw.xfrBlob(tmp); |
61 | 247 | } |
62 | 615 | } |
63 | | |
64 | | private: |
65 | | DNSPacketWriter& pw; |
66 | | /* one byte for the window, |
67 | | one for the length, |
68 | | then the maximum of 32 bytes */ |
69 | | uint8_t res[34]; |
70 | | int oldWindow{-1}; |
71 | | int len{0}; |
72 | | string tmp; |
73 | | }; |
74 | | |
75 | | void NSECBitmap::toPacket(DNSPacketWriter& pw) const |
76 | 615 | { |
77 | 615 | NSECBitmapGenerator nbg(pw); |
78 | 615 | if (d_bitset) { |
79 | 0 | size_t found = 0; |
80 | 0 | size_t l_count = d_bitset->count(); |
81 | 0 | for(size_t idx = 0; idx < nbTypes && found < l_count; ++idx){ |
82 | 0 | if (!d_bitset->test(idx)) { |
83 | 0 | continue; |
84 | 0 | } |
85 | 0 | found++; |
86 | 0 | nbg.set(idx); |
87 | 0 | } |
88 | 0 | } |
89 | 615 | else { |
90 | 993 | for (const auto& type : d_set) { |
91 | 993 | nbg.set(type); |
92 | 993 | } |
93 | 615 | } |
94 | | |
95 | 615 | nbg.finish(); |
96 | 615 | } |
97 | | |
98 | | void NSECBitmap::fromPacket(PacketReader& pr) |
99 | 9.85k | { |
100 | 9.85k | string bitmap; |
101 | 9.85k | pr.xfrBlob(bitmap); |
102 | | |
103 | | // 00 06 20 00 00 00 00 03 -> NS RRSIG NSEC ( 2, 46, 47 ) counts from left |
104 | 9.85k | if(bitmap.empty()) { |
105 | 4.87k | return; |
106 | 4.87k | } |
107 | | |
108 | 4.98k | if(bitmap.size() < 2) { |
109 | 17 | throw MOADNSException("NSEC record with impossibly small bitmap"); |
110 | 17 | } |
111 | | |
112 | 39.4k | for(unsigned int n = 0; n+1 < bitmap.size();) { |
113 | 35.8k | uint8_t window=static_cast<uint8_t>(bitmap[n++]); |
114 | 35.8k | uint8_t blen=static_cast<uint8_t>(bitmap[n++]); |
115 | | |
116 | | // end if zero padding and ensure packet length |
117 | 35.8k | if (window == 0 && blen == 0) { |
118 | 1.04k | break; |
119 | 1.04k | } |
120 | | |
121 | 34.7k | if (blen > 32) { |
122 | 306 | throw MOADNSException("NSEC record with invalid bitmap length"); |
123 | 306 | } |
124 | | |
125 | 34.4k | if (n + blen > bitmap.size()) { |
126 | 54 | throw MOADNSException("NSEC record with bitmap length > packet length"); |
127 | 54 | } |
128 | | |
129 | 221k | for(unsigned int k=0; k < blen; k++) { |
130 | 186k | uint8_t val=bitmap[n++]; |
131 | 1.68M | for(int bit = 0; bit < 8 ; ++bit , val>>=1) { |
132 | 1.49M | if(val & 1) { |
133 | 696k | set((7-bit) + 8*(k) + 256*window); |
134 | 696k | } |
135 | 1.49M | } |
136 | 186k | } |
137 | 34.4k | } |
138 | 4.96k | } |
139 | | |
140 | | string NSECBitmap::getZoneRepresentation() const |
141 | 1.51k | { |
142 | 1.51k | string ret; |
143 | | |
144 | 1.51k | if (d_bitset) { |
145 | 51 | size_t found = 0; |
146 | 51 | size_t l_count = d_bitset->count(); |
147 | 1.56M | for(size_t idx = 0; idx < nbTypes && found < l_count; ++idx) { |
148 | 1.56M | if (!d_bitset->test(idx)) { |
149 | 1.55M | continue; |
150 | 1.55M | } |
151 | 12.7k | found++; |
152 | | |
153 | 12.7k | ret+=" "; |
154 | 12.7k | ret+=DNSRecordContent::NumberToType(idx); |
155 | 12.7k | } |
156 | 51 | } |
157 | 1.46k | else { |
158 | 7.21k | for(const auto& type : d_set) { |
159 | 7.21k | ret+=" "; |
160 | 7.21k | ret+=DNSRecordContent::NumberToType(type); |
161 | 7.21k | } |
162 | 1.46k | } |
163 | | |
164 | 1.51k | return ret; |
165 | 1.51k | } |
166 | | |
167 | | void NSECRecordContent::report(const ReportIsOnlyCallableByReportAllTypes& /* unused */) |
168 | 4 | { |
169 | 4 | regist(1, 47, &make, &make, "NSEC"); |
170 | 4 | } |
171 | | |
172 | | std::shared_ptr<DNSRecordContent> NSECRecordContent::make(const string& content) |
173 | 604 | { |
174 | 604 | return std::make_shared<NSECRecordContent>(content); |
175 | 604 | } |
176 | | |
177 | | NSECRecordContent::NSECRecordContent(const string& content, const ZoneName& zone) |
178 | 604 | { |
179 | 604 | RecordTextReader rtr(content, zone); |
180 | 604 | rtr.xfrName(d_next); |
181 | | |
182 | 5.08k | while(!rtr.eof()) { |
183 | 4.47k | uint16_t type; |
184 | 4.47k | rtr.xfrType(type); |
185 | 4.47k | set(type); |
186 | 4.47k | } |
187 | 604 | } |
188 | | |
189 | | void NSECRecordContent::toPacket(DNSPacketWriter& pw) const |
190 | 406 | { |
191 | 406 | pw.xfrName(d_next); |
192 | 406 | d_bitmap.toPacket(pw); |
193 | 406 | } |
194 | | |
195 | | std::shared_ptr<NSECRecordContent::DNSRecordContent> NSECRecordContent::make(const DNSRecord & /* dr */, PacketReader& pr) |
196 | 6.09k | { |
197 | 6.09k | auto ret=std::make_shared<NSECRecordContent>(); |
198 | 6.09k | pr.xfrName(ret->d_next); |
199 | | |
200 | 6.09k | ret->d_bitmap.fromPacket(pr); |
201 | | |
202 | 6.09k | return ret; |
203 | 6.09k | } |
204 | | |
205 | | string NSECRecordContent::getZoneRepresentation(bool /* noDot */) const |
206 | 1.02k | { |
207 | 1.02k | string ret; |
208 | 1.02k | RecordTextWriter rtw(ret); |
209 | 1.02k | rtw.xfrName(d_next); |
210 | | |
211 | 1.02k | return ret + d_bitmap.getZoneRepresentation(); |
212 | 1.02k | } |
213 | | |
214 | | ////// begin of NSEC3 |
215 | | |
216 | | void NSEC3RecordContent::report(const ReportIsOnlyCallableByReportAllTypes& /* unused */) |
217 | 4 | { |
218 | 4 | regist(1, 50, &make, &make, "NSEC3"); |
219 | 4 | } |
220 | | |
221 | | std::shared_ptr<DNSRecordContent> NSEC3RecordContent::make(const string& content) |
222 | 300 | { |
223 | 300 | return std::make_shared<NSEC3RecordContent>(content); |
224 | 300 | } |
225 | | |
226 | | NSEC3RecordContent::NSEC3RecordContent(const string& content, const ZoneName& zone) |
227 | 300 | { |
228 | 300 | RecordTextReader rtr(content, zone); |
229 | 300 | rtr.xfr8BitInt(d_algorithm); |
230 | 300 | rtr.xfr8BitInt(d_flags); |
231 | 300 | rtr.xfr16BitInt(d_iterations); |
232 | | |
233 | 300 | rtr.xfrHexBlob(d_salt); |
234 | 300 | rtr.xfrBase32HexBlob(d_nexthash); |
235 | | |
236 | 822 | while(!rtr.eof()) { |
237 | 522 | uint16_t type; |
238 | 522 | rtr.xfrType(type); |
239 | 522 | set(type); |
240 | 522 | } |
241 | 300 | } |
242 | | |
243 | | void NSEC3RecordContent::toPacket(DNSPacketWriter& pw) const |
244 | 196 | { |
245 | 196 | pw.xfr8BitInt(d_algorithm); |
246 | 196 | pw.xfr8BitInt(d_flags); |
247 | 196 | pw.xfr16BitInt(d_iterations); |
248 | 196 | pw.xfr8BitInt(d_salt.length()); |
249 | 196 | pw.xfrBlob(d_salt); |
250 | | |
251 | 196 | pw.xfr8BitInt(d_nexthash.length()); |
252 | 196 | pw.xfrBlob(d_nexthash); |
253 | | |
254 | 196 | d_bitmap.toPacket(pw); |
255 | 196 | } |
256 | | |
257 | | std::shared_ptr<NSEC3RecordContent::DNSRecordContent> NSEC3RecordContent::make(const DNSRecord& /* dr */, PacketReader& pr) |
258 | 2.21k | { |
259 | 2.21k | auto ret=std::make_shared<NSEC3RecordContent>(); |
260 | 2.21k | pr.xfr8BitInt(ret->d_algorithm); |
261 | 2.21k | pr.xfr8BitInt(ret->d_flags); |
262 | 2.21k | pr.xfr16BitInt(ret->d_iterations); |
263 | 2.21k | uint8_t len; |
264 | 2.21k | pr.xfr8BitInt(len); |
265 | 2.21k | pr.xfrBlob(ret->d_salt, len); |
266 | | |
267 | 2.21k | pr.xfr8BitInt(len); |
268 | 2.21k | pr.xfrBlob(ret->d_nexthash, len); |
269 | | |
270 | 2.21k | ret->d_bitmap.fromPacket(pr); |
271 | 2.21k | return ret; |
272 | 2.21k | } |
273 | | |
274 | | string NSEC3RecordContent::getZoneRepresentation(bool /* noDot */) const |
275 | 417 | { |
276 | 417 | string ret; |
277 | 417 | RecordTextWriter rtw(ret); |
278 | 417 | rtw.xfr8BitInt(d_algorithm); |
279 | 417 | rtw.xfr8BitInt(d_flags); |
280 | 417 | rtw.xfr16BitInt(d_iterations); |
281 | | |
282 | 417 | rtw.xfrHexBlob(d_salt); |
283 | 417 | rtw.xfrBase32HexBlob(d_nexthash); |
284 | | |
285 | 417 | return ret + d_bitmap.getZoneRepresentation(); |
286 | 417 | } |
287 | | |
288 | | |
289 | | void NSEC3PARAMRecordContent::report(const ReportIsOnlyCallableByReportAllTypes& /* unused */) |
290 | 4 | { |
291 | 4 | regist(1, 51, &make, &make, "NSEC3PARAM"); |
292 | 4 | regist(254, 51, &make, &make, "NSEC3PARAM"); |
293 | 4 | } |
294 | | |
295 | | std::shared_ptr<DNSRecordContent> NSEC3PARAMRecordContent::make(const string& content) |
296 | 42 | { |
297 | 42 | return std::make_shared<NSEC3PARAMRecordContent>(content); |
298 | 42 | } |
299 | | |
300 | | NSEC3PARAMRecordContent::NSEC3PARAMRecordContent(const string& content, const ZoneName& zone) |
301 | 42 | { |
302 | 42 | RecordTextReader rtr(content, zone); |
303 | 42 | rtr.xfr8BitInt(d_algorithm); |
304 | 42 | rtr.xfr8BitInt(d_flags); |
305 | 42 | rtr.xfr16BitInt(d_iterations); |
306 | 42 | rtr.xfrHexBlob(d_salt); |
307 | 42 | } |
308 | | |
309 | | void NSEC3PARAMRecordContent::toPacket(DNSPacketWriter& pw) const |
310 | 17 | { |
311 | 17 | pw.xfr8BitInt(d_algorithm); |
312 | 17 | pw.xfr8BitInt(d_flags); |
313 | 17 | pw.xfr16BitInt(d_iterations); |
314 | 17 | pw.xfr8BitInt(d_salt.length()); |
315 | | // cerr<<"salt: '"<<makeHexDump(d_salt)<<"', "<<d_salt.length()<<endl; |
316 | 17 | pw.xfrBlob(d_salt); |
317 | 17 | } |
318 | | |
319 | | std::shared_ptr<NSEC3PARAMRecordContent::DNSRecordContent> NSEC3PARAMRecordContent::make(const DNSRecord& /* dr */, PacketReader& pr) |
320 | 1.01k | { |
321 | 1.01k | auto ret=std::make_shared<NSEC3PARAMRecordContent>(); |
322 | 1.01k | pr.xfr8BitInt(ret->d_algorithm); |
323 | 1.01k | pr.xfr8BitInt(ret->d_flags); |
324 | 1.01k | pr.xfr16BitInt(ret->d_iterations); |
325 | 1.01k | uint8_t len; |
326 | 1.01k | pr.xfr8BitInt(len); |
327 | 1.01k | pr.xfrHexBlob(ret->d_salt, len); |
328 | 1.01k | return ret; |
329 | 1.01k | } |
330 | | |
331 | | string NSEC3PARAMRecordContent::getZoneRepresentation(bool /* noDot */) const |
332 | 61 | { |
333 | 61 | string ret; |
334 | 61 | RecordTextWriter rtw(ret); |
335 | 61 | rtw.xfr8BitInt(d_algorithm); |
336 | 61 | rtw.xfr8BitInt(d_flags); |
337 | 61 | rtw.xfr16BitInt(d_iterations); |
338 | 61 | rtw.xfrHexBlob(d_salt); |
339 | 61 | return ret; |
340 | 61 | } |
341 | | |
342 | | ////// end of NSEC3 |
343 | | |
344 | | ////// begin of CSYNC |
345 | | |
346 | | void CSYNCRecordContent::report(const ReportIsOnlyCallableByReportAllTypes& /* unused */) |
347 | 4 | { |
348 | 4 | regist(1, 62, &make, &make, "CSYNC"); |
349 | 4 | } |
350 | | |
351 | | std::shared_ptr<DNSRecordContent> CSYNCRecordContent::make(const string& content) |
352 | 64 | { |
353 | 64 | return std::make_shared<CSYNCRecordContent>(content); |
354 | 64 | } |
355 | | |
356 | | CSYNCRecordContent::CSYNCRecordContent(const string& content, const ZoneName& zone) |
357 | 64 | { |
358 | 64 | RecordTextReader rtr(content, zone); |
359 | 64 | rtr.xfr32BitInt(d_serial); |
360 | 64 | rtr.xfr16BitInt(d_flags); |
361 | | |
362 | 511 | while(!rtr.eof()) { |
363 | 447 | uint16_t type; |
364 | 447 | rtr.xfrType(type); |
365 | 447 | set(type); |
366 | 447 | } |
367 | 64 | } |
368 | | |
369 | | void CSYNCRecordContent::toPacket(DNSPacketWriter& pw) const |
370 | 31 | { |
371 | 31 | pw.xfr32BitInt(d_serial); |
372 | 31 | pw.xfr16BitInt(d_flags); |
373 | | |
374 | 31 | d_bitmap.toPacket(pw); |
375 | 31 | } |
376 | | |
377 | | std::shared_ptr<CSYNCRecordContent::DNSRecordContent> CSYNCRecordContent::make(const DNSRecord& /* dr */, PacketReader& pr) |
378 | 2.16k | { |
379 | 2.16k | auto ret=std::make_shared<CSYNCRecordContent>(); |
380 | 2.16k | pr.xfr32BitInt(ret->d_serial); |
381 | 2.16k | pr.xfr16BitInt(ret->d_flags); |
382 | | |
383 | 2.16k | ret->d_bitmap.fromPacket(pr); |
384 | 2.16k | return ret; |
385 | 2.16k | } |
386 | | |
387 | | string CSYNCRecordContent::getZoneRepresentation(bool /* noDot */) const |
388 | 81 | { |
389 | 81 | string ret; |
390 | 81 | RecordTextWriter rtw(ret); |
391 | 81 | rtw.xfr32BitInt(d_serial); |
392 | 81 | rtw.xfr16BitInt(d_flags); |
393 | | |
394 | 81 | return ret + d_bitmap.getZoneRepresentation(); |
395 | 81 | } |
396 | | |
397 | | ////// end of CSYNC |