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