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