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