]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/rcpgenerator.cc
update pdns_recursor to support boost 1.37.0 (thanks Darix)
[thirdparty/pdns.git] / pdns / rcpgenerator.cc
CommitLineData
4192ca66
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
38e655b6 3 Copyright (C) 2005 - 2007 PowerDNS.COM BV
4192ca66
BH
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 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
06bd9ccf 16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
4192ca66
BH
17*/
18
19#include "rcpgenerator.hh"
20133c59 20#include "dnsparser.hh"
cbf0e7f3 21#include "misc.hh"
4192ca66
BH
22#include <boost/lexical_cast.hpp>
23#include <iostream>
8c1c9170 24#include "base64.hh"
4192ca66
BH
25using namespace boost;
26
27RecordTextReader::RecordTextReader(const string& str, const string& zone) : d_string(str), d_zone(zone), d_pos(0), d_end(str.size())
28{
29}
30
341930bb
BH
31void RecordTextReader::xfr48BitInt(uint64_t &val)
32{
33 xfr64BitInt(val);
34}
35
36void RecordTextReader::xfr64BitInt(uint64_t &val)
37{
38 skipSpaces();
39
40 if(!isdigit(d_string.at(d_pos)))
41 throw RecordTextException("expected digits at position "+lexical_cast<string>(d_pos)+" in '"+d_string+"'");
42
43 char *endptr;
44 unsigned long ret=strtoull(d_string.c_str() + d_pos, &endptr, 10);
45 val=ret;
46
47 d_pos = endptr - d_string.c_str();
48}
49
50
cbf0e7f3 51void RecordTextReader::xfr32BitInt(uint32_t &val)
4192ca66
BH
52{
53 skipSpaces();
54
55 if(!isdigit(d_string.at(d_pos)))
56 throw RecordTextException("expected digits at position "+lexical_cast<string>(d_pos)+" in '"+d_string+"'");
57
58 char *endptr;
59 unsigned long ret=strtoul(d_string.c_str() + d_pos, &endptr, 10);
60 val=ret;
61
62 d_pos = endptr - d_string.c_str();
63}
64
8bf26468
BH
65void RecordTextReader::xfrTime(uint32_t &val)
66{
67 struct tm tm;
68 memset(&tm, 0, sizeof(tm));
69
70 string tmp;
71 xfrLabel(tmp); // ends on number, so this works
72
73 sscanf(tmp.c_str(), "%04d%02d%02d" "%02d%02d%02d",
74 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
75 &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
76
77 tm.tm_year-=1900;
78 tm.tm_min-=1;
79
705f31ae 80 val=(uint32_t)mktime(&tm);
8bf26468
BH
81}
82
cbf0e7f3
BH
83void RecordTextReader::xfrIP(uint32_t &val)
84{
85 skipSpaces();
86
87 if(!isdigit(d_string.at(d_pos)))
aab4adb0 88 throw RecordTextException("while parsing IP address, expected digits at position "+lexical_cast<string>(d_pos)+" in '"+d_string+"'");
1149fa0b
BH
89
90 uint32_t octet=0;
91 val=0;
92 char count=0;
cbf0e7f3 93
1149fa0b
BH
94 for(;;) {
95 if(d_string.at(d_pos)=='.') {
96 val<<=8;
97 val+=octet;
98 octet=0;
99 count++;
100 if(count > 3)
101 break;
102 }
103 else if(isdigit(d_string.at(d_pos))) {
104 octet*=10;
105 octet+=d_string.at(d_pos) - '0';
106 if(octet > 255)
107 throw RecordTextException("unable to parse IP address");
108 }
109 else if(dns_isspace(d_string.at(d_pos)))
110 break;
111 else
112 throw RecordTextException("unable to parse IP address, strange character: "+d_string.at(d_pos));
113
114 d_pos++;
115 if(d_pos == d_string.length())
116 break;
117 }
118 if(count<=3) {
119 val<<=8;
120 val+=octet;
121 }
122 val=ntohl(val);
cbf0e7f3
BH
123}
124
125
20133c59
BH
126bool RecordTextReader::eof()
127{
128 return d_pos==d_end;
129}
130
cbf0e7f3
BH
131void RecordTextReader::xfr16BitInt(uint16_t &val)
132{
133 uint32_t tmp;
134 xfr32BitInt(tmp);
135 val=tmp;
136 if(val!=tmp)
137 throw RecordTextException("Overflow reading 16 bit integer from record content"); // fixme improve
138}
139
8c1c9170
BH
140void RecordTextReader::xfr8BitInt(uint8_t &val)
141{
142 uint32_t tmp;
143 xfr32BitInt(tmp);
144 val=tmp;
145 if(val!=tmp)
146 throw RecordTextException("Overflow reading 8 bit integer from record content"); // fixme improve
147}
148
35ce8576 149void RecordTextReader::xfrLabel(string& val, bool)
4192ca66
BH
150{
151 skipSpaces();
29a14b24
BH
152 val.clear();
153 val.reserve(d_end - d_pos);
154
d39704c0 155 const char* strptr=d_string.c_str();
29a14b24 156 while(d_pos < d_end) {
0a1825d6 157 if(strptr[d_pos]!='\r' && dns_isspace(strptr[d_pos]))
29a14b24
BH
158 break;
159
38e655b6 160 if(strptr[d_pos]=='\\' && d_pos < d_end - 1 && strptr[d_pos+1]!='.') // leave the \. escape around
29a14b24
BH
161 d_pos++;
162
d39704c0 163 val.append(1, strptr[d_pos]);
4192ca66 164 d_pos++;
29a14b24 165 }
4192ca66 166
4192ca66
BH
167 if(val.empty())
168 val=d_zone;
bca6643b 169 else if(!d_zone.empty()) {
cbf0e7f3
BH
170 char last=val[val.size()-1];
171
b0d4fb45
BH
172 if(last =='.')
173 val.resize(val.size()-1);
174 else if(last != '.' && !isdigit(last)) // don't add zone to IP address
cbf0e7f3
BH
175 val+="."+d_zone;
176 }
4192ca66
BH
177}
178
06ffdc52 179void RecordTextReader::xfrBlob(string& val, int)
8c1c9170
BH
180{
181 skipSpaces();
705f31ae 182 int pos=(int)d_pos;
d39704c0
BH
183 const char* strptr=d_string.c_str();
184 while(d_pos < d_end && !dns_isspace(strptr[d_pos]))
8c1c9170
BH
185 d_pos++;
186
20133c59
BH
187 string tmp;
188 tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos);
189 val.clear();
190 B64Decode(tmp, val);
8c1c9170
BH
191}
192
59a0f653
BH
193
194static inline uint8_t hextodec(uint8_t val)
195{
196 if(val >= '0' && val<='9')
197 return val-'0';
198 else if(val >= 'A' && val<='F')
199 return 10+(val-'A');
200 else if(val >= 'a' && val<='f')
201 return 10+(val-'a');
202 else
203 throw RecordTextException("Unknown hexadecimal character '"+lexical_cast<string>(val)+"'");
204}
205
206
207void HEXDecode(const char* begin, const char* end, string& val)
208{
209 if((end - begin)%2)
210 throw RecordTextException("Hexadecimal blob with odd number of characters");
211
705f31ae 212 int limit=(int)(end-begin)/2;
59a0f653
BH
213 val.resize(limit);
214 for(int n=0; n < limit; ++n) {
215 val[n] = hextodec(begin[2*n])*16 + hextodec(begin[2*n+1]);
216 }
217}
218
219void RecordTextReader::xfrHexBlob(string& val)
220{
221 skipSpaces();
705f31ae 222 int pos=(int)d_pos;
59a0f653
BH
223 while(d_pos < d_end && !dns_isspace(d_string[d_pos]))
224 d_pos++;
225
226 HEXDecode(d_string.c_str()+pos, d_string.c_str() + d_pos, val);
227}
228
ef6a78d5 229void RecordTextReader::xfrText(string& val, bool multi)
4192ca66 230{
4192ca66
BH
231 val.clear();
232 val.reserve(d_end - d_pos);
ef6a78d5
BH
233
234 while(d_pos != d_end) {
235 if(!val.empty())
236 val.append(1, ' ');
237
238 skipSpaces();
239 if(d_string[d_pos]!='"')
240 throw RecordTextException("Data field in DNS should start with quote (\") at position "+lexical_cast<string>(d_pos)+" of '"+d_string+"'");
241
242 val.append(1, '"');
243 while(++d_pos < d_end && d_string[d_pos]!='"') {
244 if(d_string[d_pos]=='\\' && d_pos+1!=d_end) {
245 val.append(1, d_string[d_pos++]);
246 }
247 val.append(1, d_string[d_pos]);
4192ca66 248 }
ef6a78d5
BH
249 val.append(1,'"');
250 if(d_pos == d_end)
251 throw RecordTextException("Data field in DNS should end on a quote (\") in '"+d_string+"'");
252 d_pos++;
253 if(!multi)
254 break;
4192ca66 255 }
4192ca66
BH
256}
257
20133c59
BH
258void RecordTextReader::xfrType(uint16_t& val)
259{
260 skipSpaces();
705f31ae 261 int pos=(int)d_pos;
ec486449 262 while(d_pos < d_end && !dns_isspace(d_string[d_pos]))
20133c59
BH
263 d_pos++;
264
265 string tmp;
266 tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos);
267
268 val=DNSRecordContent::TypeToNumber(tmp);
269}
4192ca66 270
8c1c9170 271
4192ca66
BH
272void RecordTextReader::skipSpaces()
273{
d39704c0
BH
274 const char* strptr = d_string.c_str();
275 while(d_pos < d_end && dns_isspace(strptr[d_pos]))
4192ca66 276 d_pos++;
4192ca66
BH
277 if(d_pos == d_end)
278 throw RecordTextException("missing field at the end of record content '"+d_string+"'");
279}
280
281
282RecordTextWriter::RecordTextWriter(string& str) : d_string(str)
283{
284 d_string.clear();
285}
286
341930bb 287void RecordTextWriter::xfr48BitInt(const uint64_t& val)
4192ca66
BH
288{
289 if(!d_string.empty())
290 d_string.append(1,' ');
291 d_string+=lexical_cast<string>(val);
292}
293
20133c59 294
341930bb
BH
295void RecordTextWriter::xfr32BitInt(const uint32_t& val)
296{
297 if(!d_string.empty())
298 d_string.append(1,' ');
299 d_string+=lexical_cast<string>(val);
300}
20133c59
BH
301
302void RecordTextWriter::xfrType(const uint16_t& val)
303{
304 if(!d_string.empty())
305 d_string.append(1,' ');
306 d_string+=DNSRecordContent::NumberToType(val);
307}
308
ec486449 309// this function is on the fast path for the pdns_recursor
cbf0e7f3
BH
310void RecordTextWriter::xfrIP(const uint32_t& val)
311{
312 if(!d_string.empty())
313 d_string.append(1,' ');
314
ec486449 315 char tmp[17];
1149fa0b
BH
316 uint32_t ip=htonl(val);
317 uint8_t vals[4];
318
319 memcpy(&vals[0], &ip, sizeof(ip));
320
321 char *pos=tmp;
322
323 for(int n=0; n < 4; ++n) {
324 if(vals[n]<10) {
325 *(pos++)=vals[n]+'0';
326 } else if(vals[n] < 100) {
327 *(pos++)=(vals[n]/10) +'0';
328 *(pos++)=(vals[n]%10) +'0';
329 } else {
330 *(pos++)=(vals[n]/100) +'0';
331 vals[n]%=100;
332 *(pos++)=(vals[n]/10) +'0';
333 *(pos++)=(vals[n]%10) +'0';
334 }
335 if(n!=3)
336 *(pos++)='.';
337 }
338 *pos=0;
339 d_string.append(tmp, pos);
cbf0e7f3
BH
340}
341
342
8bf26468
BH
343void RecordTextWriter::xfrTime(const uint32_t& val)
344{
345 if(!d_string.empty())
346 d_string.append(1,' ');
347
348 struct tm tm;
349 time_t time=val; // Y2038 bug!
d3b729e8 350#ifndef WIN32
8bf26468 351 gmtime_r(&time, &tm);
d3b729e8
BH
352#else
353 struct tm* tmptr;
354 tmptr=gmtime(&time);
355 if(!tmptr)
356 throw RecordTextException("Unable to convert timestamp into pretty printable time");
357 tm=*tmptr;
358#endif
8bf26468
BH
359
360 char tmp[16];
361 snprintf(tmp,sizeof(tmp)-1, "%04d%02d%02d" "%02d%02d%02d",
362 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
363 tm.tm_hour, tm.tm_min, tm.tm_sec);
364
365 d_string += tmp;
366}
367
368
cbf0e7f3
BH
369void RecordTextWriter::xfr16BitInt(const uint16_t& val)
370{
371 xfr32BitInt(val);
372}
373
8c1c9170
BH
374void RecordTextWriter::xfr8BitInt(const uint8_t& val)
375{
376 xfr32BitInt(val);
377}
378
cbf0e7f3 379
bca6643b 380void RecordTextWriter::xfrLabel(const string& val, bool)
4192ca66
BH
381{
382 if(!d_string.empty())
383 d_string.append(1,' ');
29a14b24
BH
384 if(val.find(' ')==string::npos)
385 d_string+=val;
386 else {
387 d_string.reserve(d_string.size()+val.size()+3);
388 for(string::size_type pos=0; pos < val.size() ; ++pos)
ec486449 389 if(dns_isspace(val[pos]))
29a14b24
BH
390 d_string+="\\ ";
391 else if(val[pos]=='\\')
392 d_string.append(1,'\\');
393 else
394 d_string.append(1,val[pos]);
395 }
7738a23f 396 // d_string.append(1,'.');
4192ca66
BH
397}
398
06ffdc52 399void RecordTextWriter::xfrBlob(const string& val, int)
8c1c9170
BH
400{
401 if(!d_string.empty())
402 d_string.append(1,' ');
403
404 d_string+=Base64Encode(val);
405}
406
59a0f653
BH
407void RecordTextWriter::xfrHexBlob(const string& val)
408{
409 if(!d_string.empty())
410 d_string.append(1,' ');
411
412 string::size_type limit=val.size();
413 char tmp[5];
414 for(string::size_type n = 0; n < limit; ++n) {
415 snprintf(tmp, sizeof(tmp)-1, "%02x", (unsigned char)val[n]);
416 d_string+=tmp;
417 }
418}
419
ef6a78d5 420void RecordTextWriter::xfrText(const string& val, bool multi)
4192ca66
BH
421{
422 if(!d_string.empty())
423 d_string.append(1,' ');
4192ca66 424
ef6a78d5 425 d_string.append(val);
4192ca66
BH
426}
427
428
429#ifdef TESTING
430
431int main(int argc, char**argv)
432try
433{
434 RecordTextReader rtr(argv[1], argv[2]);
435
436 unsigned int order, pref;
437 string flags, services, regexp, replacement;
438 string mx;
439
440 rtr.xfrInt(order);
441 rtr.xfrInt(pref);
cbf0e7f3
BH
442 rtr.xfrText(flags);
443 rtr.xfrText(services);
444 rtr.xfrText(regexp);
4192ca66
BH
445 rtr.xfrLabel(replacement);
446
447 cout<<"order: "<<order<<", pref: "<<pref<<"\n";
448 cout<<"flags: \""<<flags<<"\", services: \""<<services<<"\", regexp: \""<<regexp<<"\", replacement: "<<replacement<<"\n";
449
450 string out;
451 RecordTextWriter rtw(out);
452
453 rtw.xfrInt(order);
454 rtw.xfrInt(pref);
cbf0e7f3
BH
455 rtw.xfrText(flags);
456 rtw.xfrText(services);
457 rtw.xfrText(regexp);
4192ca66
BH
458 rtw.xfrLabel(replacement);
459
460 cout<<"Regenerated: '"<<out<<"'\n";
461
462}
463catch(exception& e)
464{
465 cerr<<"Fatal: "<<e.what()<<endl;
466}
467
468#endif