]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/rcpgenerator.cc
Include config.h only in .cc files
[thirdparty/pdns.git] / pdns / rcpgenerator.cc
1 /*
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2005 - 2011 PowerDNS.COM BV
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation
8
9 Additionally, the license of this program contains a special
10 exception which allows to distribute the program in binary form when
11 it is linked against OpenSSL.
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 St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include "rcpgenerator.hh"
27 #include "dnsparser.hh"
28 #include "misc.hh"
29 #include <boost/lexical_cast.hpp>
30 #include <boost/algorithm/string.hpp>
31 #include <iostream>
32 #include "base32.hh"
33 #include "base64.hh"
34 #include "namespaces.hh"
35
36 RecordTextReader::RecordTextReader(const string& str, const string& zone) : d_string(str), d_zone(zone), d_pos(0), d_end(str.size())
37 {
38 }
39
40 void RecordTextReader::xfr48BitInt(uint64_t &val)
41 {
42 xfr64BitInt(val);
43 }
44
45 void RecordTextReader::xfr64BitInt(uint64_t &val)
46 {
47 skipSpaces();
48
49 if(!isdigit(d_string.at(d_pos)))
50 throw RecordTextException("expected digits at position "+lexical_cast<string>(d_pos)+" in '"+d_string+"'");
51
52 char *endptr;
53 unsigned long ret=strtoull(d_string.c_str() + d_pos, &endptr, 10);
54 val=ret;
55
56 d_pos = endptr - d_string.c_str();
57 }
58
59
60 void RecordTextReader::xfr32BitInt(uint32_t &val)
61 {
62 skipSpaces();
63
64 if(!isdigit(d_string.at(d_pos)))
65 throw RecordTextException("expected digits at position "+lexical_cast<string>(d_pos)+" in '"+d_string+"'");
66
67 char *endptr;
68 unsigned long ret=pdns_strtoui(d_string.c_str() + d_pos, &endptr, 10);
69 if (ret == UINT_MAX && errno == ERANGE) throw RecordTextException("serial number too large in '"+d_string+"'");
70 val=ret;
71
72 d_pos = endptr - d_string.c_str();
73 }
74
75 void RecordTextReader::xfrTime(uint32_t &val)
76 {
77 struct tm tm;
78 memset(&tm, 0, sizeof(tm));
79
80 string tmp;
81 xfrLabel(tmp); // ends on number, so this works
82
83 sscanf(tmp.c_str(), "%04d%02d%02d" "%02d%02d%02d",
84 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
85 &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
86
87 tm.tm_year-=1900;
88 tm.tm_mon-=1;
89 val=(uint32_t)Utility::timegm(&tm);
90 }
91
92 void RecordTextReader::xfrIP(uint32_t &val)
93 {
94 skipSpaces();
95
96 if(!isdigit(d_string.at(d_pos)))
97 throw RecordTextException("while parsing IP address, expected digits at position "+lexical_cast<string>(d_pos)+" in '"+d_string+"'");
98
99 uint32_t octet=0;
100 val=0;
101 char count=0;
102
103 for(;;) {
104 if(d_string.at(d_pos)=='.') {
105 val<<=8;
106 val+=octet;
107 octet=0;
108 count++;
109 if(count > 3)
110 break;
111 }
112 else if(isdigit(d_string.at(d_pos))) {
113 octet*=10;
114 octet+=d_string.at(d_pos) - '0';
115 if(octet > 255)
116 throw RecordTextException("unable to parse IP address");
117 }
118 else if(dns_isspace(d_string.at(d_pos)))
119 break;
120 else {
121 throw RecordTextException(string("unable to parse IP address, strange character: ")+d_string.at(d_pos));
122 }
123 d_pos++;
124 if(d_pos == d_string.length())
125 break;
126 }
127 if(count<=3) {
128 val<<=8;
129 val+=octet;
130 }
131 val=ntohl(val);
132 }
133
134
135 void RecordTextReader::xfrIP6(std::string &val)
136 {
137 struct in6_addr tmpbuf;
138
139 skipSpaces();
140
141 size_t len;
142 // lookup end of value - think of ::ffff encoding too, has dots in it!
143 for(len=0;
144 d_pos+len < d_string.length() && (isxdigit(d_string.at(d_pos+len)) || d_string.at(d_pos+len) == ':' || d_string.at(d_pos+len)=='.');
145 len++);
146
147 if(!len)
148 throw RecordTextException("while parsing IPv6 address, expected xdigits at position "+lexical_cast<string>(d_pos)+" in '"+d_string+"'");
149
150 // end of value is here, try parse as IPv6
151 string address=d_string.substr(d_pos, len);
152
153 if (inet_pton(AF_INET6, address.c_str(), &tmpbuf) != 1) {
154 throw RecordTextException("while parsing IPv6 address: '" + address + "' is invalid");
155 }
156
157 val = std::string((char*)tmpbuf.s6_addr, 16);
158
159 d_pos += len;
160 }
161
162 bool RecordTextReader::eof()
163 {
164 return d_pos==d_end;
165 }
166
167 void RecordTextReader::xfr16BitInt(uint16_t &val)
168 {
169 uint32_t tmp;
170 xfr32BitInt(tmp);
171 val=tmp;
172 if(val!=tmp)
173 throw RecordTextException("Overflow reading 16 bit integer from record content"); // fixme improve
174 }
175
176 void RecordTextReader::xfr8BitInt(uint8_t &val)
177 {
178 uint32_t tmp;
179 xfr32BitInt(tmp);
180 val=tmp;
181 if(val!=tmp)
182 throw RecordTextException("Overflow reading 8 bit integer from record content"); // fixme improve
183 }
184
185 // this code should leave all the escapes around
186 void RecordTextReader::xfrLabel(string& val, bool)
187 {
188 skipSpaces();
189 val.clear();
190 val.reserve(d_end - d_pos);
191
192 const char* strptr=d_string.c_str();
193 string::size_type begin_pos = d_pos;
194 while(d_pos < d_end) {
195 if(strptr[d_pos]!='\r' && dns_isspace(strptr[d_pos]))
196 break;
197
198 d_pos++;
199 }
200 val.append(strptr+begin_pos, strptr+d_pos);
201
202 if(val.empty())
203 val=d_zone;
204 else if(!d_zone.empty()) {
205 char last=val[val.size()-1];
206
207 if(last =='.')
208 val.resize(val.size()-1);
209 else if(last != '.' && !isdigit(last)) // don't add zone to IP address
210 val+="."+d_zone;
211 }
212 }
213
214 static bool isbase64(char c, bool acceptspace)
215 {
216 if(dns_isspace(c))
217 return acceptspace;
218 if(c >= '0' && c <= '9')
219 return true;
220 if(c >= 'a' && c <= 'z')
221 return true;
222 if(c >= 'A' && c <= 'Z')
223 return true;
224 if(c=='+' || c=='/' || c=='=')
225 return true;
226 return false;
227 }
228
229 void RecordTextReader::xfrBlobNoSpaces(string& val, int len) {
230 skipSpaces();
231 int pos=(int)d_pos;
232 const char* strptr=d_string.c_str();
233 while(d_pos < d_end && isbase64(strptr[d_pos], false))
234 d_pos++;
235
236 string tmp;
237 tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos);
238 boost::erase_all(tmp," ");
239 val.clear();
240 B64Decode(tmp, val);
241
242 if (len>-1 && val.size() != static_cast<size_t>(len))
243 throw RecordTextException("Record length "+lexical_cast<string>(val.size()) + " does not match expected length '"+lexical_cast<string>(len));
244 }
245
246 void RecordTextReader::xfrBlob(string& val, int)
247 {
248 skipSpaces();
249 int pos=(int)d_pos;
250 const char* strptr=d_string.c_str();
251 while(d_pos < d_end && isbase64(strptr[d_pos], true))
252 d_pos++;
253
254 string tmp;
255 tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos);
256 boost::erase_all(tmp," ");
257 val.clear();
258 B64Decode(tmp, val);
259 }
260
261
262 static inline uint8_t hextodec(uint8_t val)
263 {
264 if(val >= '0' && val<='9')
265 return val-'0';
266 else if(val >= 'A' && val<='F')
267 return 10+(val-'A');
268 else if(val >= 'a' && val<='f')
269 return 10+(val-'a');
270 else
271 throw RecordTextException("Unknown hexadecimal character '"+lexical_cast<string>(val)+"'");
272 }
273
274
275 void HEXDecode(const char* begin, const char* end, string& out)
276 {
277 if(end - begin == 1 && *begin=='-') {
278 out.clear();
279 return;
280 }
281 out.clear();
282 out.reserve((end-begin)/2);
283 uint8_t mode=0, val=0;
284 for(; begin != end; ++begin) {
285 if(!isalnum(*begin))
286 continue;
287 if(mode==0) {
288 val = 16*hextodec(*begin);
289 mode=1;
290 } else {
291 val += hextodec(*begin);
292 out.append(1, (char) val);
293 mode = 0;
294 val = 0;
295 }
296 }
297 if(mode)
298 out.append(1, (char) val);
299
300 }
301
302 void RecordTextReader::xfrHexBlob(string& val, bool keepReading)
303 {
304 skipSpaces();
305 int pos=(int)d_pos;
306 while(d_pos < d_end && (keepReading || !dns_isspace(d_string[d_pos])))
307 d_pos++;
308
309 HEXDecode(d_string.c_str()+pos, d_string.c_str() + d_pos, val);
310 }
311
312 void RecordTextReader::xfrBase32HexBlob(string& val)
313 {
314 skipSpaces();
315 int pos=(int)d_pos;
316 while(d_pos < d_end && !dns_isspace(d_string[d_pos]))
317 d_pos++;
318
319 val=fromBase32Hex(string(d_string.c_str()+pos, d_pos-pos));
320 }
321
322
323 void RecordTextWriter::xfrBase32HexBlob(const string& val)
324 {
325 if(!d_string.empty())
326 d_string.append(1,' ');
327
328 d_string.append(toUpper(toBase32Hex(val)));
329 }
330
331
332 void RecordTextReader::xfrText(string& val, bool multi)
333 {
334 val.clear();
335 val.reserve(d_end - d_pos);
336
337 while(d_pos != d_end) {
338 if(!val.empty())
339 val.append(1, ' ');
340
341 skipSpaces();
342 if(d_string[d_pos]!='"') { // special case 'plenus' - without quotes
343 string::size_type pos = d_pos;
344 while(pos != d_end && isalnum(d_string[pos]))
345 pos++;
346 if(pos == d_end) {
347 val.append(1, '"');
348 val.append(d_string.c_str() + d_pos, d_end - d_pos);
349 val.append(1, '"');
350 d_pos = d_end;
351 break;
352 }
353 throw RecordTextException("Data field in DNS should start with quote (\") at position "+lexical_cast<string>(d_pos)+" of '"+d_string+"'");
354 }
355 val.append(1, '"');
356 while(++d_pos < d_end && d_string[d_pos]!='"') {
357 if(d_string[d_pos]=='\\' && d_pos+1!=d_end) {
358 val.append(1, d_string[d_pos++]);
359 }
360 val.append(1, d_string[d_pos]);
361 }
362 val.append(1,'"');
363 if(d_pos == d_end)
364 throw RecordTextException("Data field in DNS should end on a quote (\") in '"+d_string+"'");
365 d_pos++;
366 if(!multi)
367 break;
368 }
369 }
370
371 void RecordTextReader::xfrType(uint16_t& val)
372 {
373 skipSpaces();
374 int pos=(int)d_pos;
375 while(d_pos < d_end && !dns_isspace(d_string[d_pos]))
376 d_pos++;
377
378 string tmp;
379 tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos);
380
381 val=DNSRecordContent::TypeToNumber(tmp);
382 }
383
384
385 void RecordTextReader::skipSpaces()
386 {
387 const char* strptr = d_string.c_str();
388 while(d_pos < d_end && dns_isspace(strptr[d_pos]))
389 d_pos++;
390 if(d_pos == d_end)
391 throw RecordTextException("missing field at the end of record content '"+d_string+"'");
392 }
393
394
395 RecordTextWriter::RecordTextWriter(string& str) : d_string(str)
396 {
397 d_string.clear();
398 }
399
400 void RecordTextWriter::xfr48BitInt(const uint64_t& val)
401 {
402 if(!d_string.empty())
403 d_string.append(1,' ');
404 d_string+=lexical_cast<string>(val);
405 }
406
407
408 void RecordTextWriter::xfr32BitInt(const uint32_t& val)
409 {
410 if(!d_string.empty())
411 d_string.append(1,' ');
412 d_string+=lexical_cast<string>(val);
413 }
414
415 void RecordTextWriter::xfrType(const uint16_t& val)
416 {
417 if(!d_string.empty())
418 d_string.append(1,' ');
419 d_string+=DNSRecordContent::NumberToType(val);
420 }
421
422 // this function is on the fast path for the pdns_recursor
423 void RecordTextWriter::xfrIP(const uint32_t& val)
424 {
425 if(!d_string.empty())
426 d_string.append(1,' ');
427
428 char tmp[17];
429 uint32_t ip=val;
430 uint8_t vals[4];
431
432 memcpy(&vals[0], &ip, sizeof(ip));
433
434 char *pos=tmp;
435
436 for(int n=0; n < 4; ++n) {
437 if(vals[n]<10) {
438 *(pos++)=vals[n]+'0';
439 } else if(vals[n] < 100) {
440 *(pos++)=(vals[n]/10) +'0';
441 *(pos++)=(vals[n]%10) +'0';
442 } else {
443 *(pos++)=(vals[n]/100) +'0';
444 vals[n]%=100;
445 *(pos++)=(vals[n]/10) +'0';
446 *(pos++)=(vals[n]%10) +'0';
447 }
448 if(n!=3)
449 *(pos++)='.';
450 }
451 *pos=0;
452 d_string.append(tmp, pos);
453 }
454
455 void RecordTextWriter::xfrIP6(const std::string& val)
456 {
457 char tmpbuf[16];
458 char addrbuf[40];
459
460 if(!d_string.empty())
461 d_string.append(1,' ');
462
463 val.copy(tmpbuf,16);
464
465 if (inet_ntop(AF_INET6, tmpbuf, addrbuf, sizeof addrbuf) == NULL)
466 throw RecordTextException("Unable to convert to ipv6 address");
467
468 d_string += std::string(addrbuf);
469 }
470
471 void RecordTextWriter::xfrTime(const uint32_t& val)
472 {
473 if(!d_string.empty())
474 d_string.append(1,' ');
475
476 struct tm tm;
477 time_t time=val; // Y2038 bug!
478 Utility::gmtime_r(&time, &tm);
479
480 char tmp[16];
481 snprintf(tmp,sizeof(tmp)-1, "%04d%02d%02d" "%02d%02d%02d",
482 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
483 tm.tm_hour, tm.tm_min, tm.tm_sec);
484
485 d_string += tmp;
486 }
487
488
489 void RecordTextWriter::xfr16BitInt(const uint16_t& val)
490 {
491 xfr32BitInt(val);
492 }
493
494 void RecordTextWriter::xfr8BitInt(const uint8_t& val)
495 {
496 xfr32BitInt(val);
497 }
498
499 // should not mess with the escapes
500 void RecordTextWriter::xfrLabel(const string& val, bool)
501 {
502 if(!d_string.empty())
503 d_string.append(1,' ');
504
505 d_string+=val;
506 }
507
508 void RecordTextWriter::xfrBlobNoSpaces(const string& val, int size)
509 {
510 xfrBlob(val, size);
511 }
512
513 void RecordTextWriter::xfrBlob(const string& val, int)
514 {
515 if(!d_string.empty())
516 d_string.append(1,' ');
517
518 d_string+=Base64Encode(val);
519 }
520
521 void RecordTextWriter::xfrHexBlob(const string& val, bool)
522 {
523 if(!d_string.empty())
524 d_string.append(1,' ');
525
526 if(val.empty()) {
527 d_string.append(1,'-');
528 return;
529 }
530
531 string::size_type limit=val.size();
532 char tmp[5];
533 for(string::size_type n = 0; n < limit; ++n) {
534 snprintf(tmp, sizeof(tmp)-1, "%02x", (unsigned char)val[n]);
535 d_string+=tmp;
536 }
537 }
538
539 void RecordTextWriter::xfrText(const string& val, bool multi)
540 {
541 if(!d_string.empty())
542 d_string.append(1,' ');
543
544 d_string.append(val);
545 }
546
547
548 #ifdef TESTING
549
550 int main(int argc, char**argv)
551 try
552 {
553 RecordTextReader rtr(argv[1], argv[2]);
554
555 unsigned int order, pref;
556 string flags, services, regexp, replacement;
557 string mx;
558
559 rtr.xfrInt(order);
560 rtr.xfrInt(pref);
561 rtr.xfrText(flags);
562 rtr.xfrText(services);
563 rtr.xfrText(regexp);
564 rtr.xfrLabel(replacement);
565
566 cout<<"order: "<<order<<", pref: "<<pref<<"\n";
567 cout<<"flags: \""<<flags<<"\", services: \""<<services<<"\", regexp: \""<<regexp<<"\", replacement: "<<replacement<<"\n";
568
569 string out;
570 RecordTextWriter rtw(out);
571
572 rtw.xfrInt(order);
573 rtw.xfrInt(pref);
574 rtw.xfrText(flags);
575 rtw.xfrText(services);
576 rtw.xfrText(regexp);
577 rtw.xfrLabel(replacement);
578
579 cout<<"Regenerated: '"<<out<<"'\n";
580
581 }
582 catch(std::exception& e)
583 {
584 cerr<<"Fatal: "<<e.what()<<endl;
585 }
586
587 #endif