]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/rcpgenerator.cc
and the final bit of whitespace/tab cleanup
[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 22#include <boost/lexical_cast.hpp>
12b33ac2 23#include <boost/algorithm/string.hpp>
4192ca66 24#include <iostream>
8c1c9170 25#include "base64.hh"
d2d6cf61 26#include "namespaces.hh"
4192ca66
BH
27
28RecordTextReader::RecordTextReader(const string& str, const string& zone) : d_string(str), d_zone(zone), d_pos(0), d_end(str.size())
29{
30}
31
341930bb
BH
32void RecordTextReader::xfr48BitInt(uint64_t &val)
33{
34 xfr64BitInt(val);
35}
36
37void RecordTextReader::xfr64BitInt(uint64_t &val)
38{
39 skipSpaces();
40
41 if(!isdigit(d_string.at(d_pos)))
42 throw RecordTextException("expected digits at position "+lexical_cast<string>(d_pos)+" in '"+d_string+"'");
43
44 char *endptr;
45 unsigned long ret=strtoull(d_string.c_str() + d_pos, &endptr, 10);
46 val=ret;
47
48 d_pos = endptr - d_string.c_str();
49}
50
51
cbf0e7f3 52void RecordTextReader::xfr32BitInt(uint32_t &val)
4192ca66
BH
53{
54 skipSpaces();
55
56 if(!isdigit(d_string.at(d_pos)))
57 throw RecordTextException("expected digits at position "+lexical_cast<string>(d_pos)+" in '"+d_string+"'");
58
59 char *endptr;
60 unsigned long ret=strtoul(d_string.c_str() + d_pos, &endptr, 10);
61 val=ret;
62
63 d_pos = endptr - d_string.c_str();
64}
65
8bf26468
BH
66void RecordTextReader::xfrTime(uint32_t &val)
67{
68 struct tm tm;
69 memset(&tm, 0, sizeof(tm));
70
71 string tmp;
72 xfrLabel(tmp); // ends on number, so this works
73
74 sscanf(tmp.c_str(), "%04d%02d%02d" "%02d%02d%02d",
4957a608
BH
75 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
76 &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
8bf26468
BH
77
78 tm.tm_year-=1900;
12b33ac2 79 tm.tm_mon-=1;
12b33ac2 80 val=(uint32_t)timegm(&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)
4957a608 101 break;
1149fa0b
BH
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)
4957a608 107 throw RecordTextException("unable to parse IP address");
1149fa0b
BH
108 }
109 else if(dns_isspace(d_string.at(d_pos)))
110 break;
87c837a3
BH
111 else {
112 throw RecordTextException(string("unable to parse IP address, strange character: ")+d_string.at(d_pos));
113 }
1149fa0b
BH
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();
83b77f90 156 string::size_type begin_pos = d_pos;
29a14b24 157 while(d_pos < d_end) {
0a1825d6 158 if(strptr[d_pos]!='\r' && dns_isspace(strptr[d_pos]))
29a14b24
BH
159 break;
160
38e655b6 161 if(strptr[d_pos]=='\\' && d_pos < d_end - 1 && strptr[d_pos+1]!='.') // leave the \. escape around
29a14b24
BH
162 d_pos++;
163
4192ca66 164 d_pos++;
29a14b24 165 }
4192ca66 166
83b77f90
BH
167 val.append(strptr+begin_pos, strptr+d_pos);
168
4192ca66
BH
169 if(val.empty())
170 val=d_zone;
bca6643b 171 else if(!d_zone.empty()) {
cbf0e7f3
BH
172 char last=val[val.size()-1];
173
b0d4fb45
BH
174 if(last =='.')
175 val.resize(val.size()-1);
176 else if(last != '.' && !isdigit(last)) // don't add zone to IP address
cbf0e7f3
BH
177 val+="."+d_zone;
178 }
4192ca66
BH
179}
180
12b33ac2
BH
181static bool isbase64(char c)
182{
183 if(dns_isspace(c))
184 return true;
185 if(c >= '0' && c <= '9')
186 return true;
187 if(c >= 'a' && c <= 'z')
188 return true;
189 if(c >= 'A' && c <= 'Z')
190 return true;
191 if(c=='+' || c=='/' || c=='=')
192 return true;
193 return false;
194}
195
06ffdc52 196void RecordTextReader::xfrBlob(string& val, int)
8c1c9170
BH
197{
198 skipSpaces();
705f31ae 199 int pos=(int)d_pos;
d39704c0 200 const char* strptr=d_string.c_str();
12b33ac2 201 while(d_pos < d_end && isbase64(strptr[d_pos]))
8c1c9170 202 d_pos++;
12b33ac2 203
20133c59
BH
204 string tmp;
205 tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos);
12b33ac2 206 boost::erase_all(tmp," ");
20133c59
BH
207 val.clear();
208 B64Decode(tmp, val);
8c1c9170
BH
209}
210
59a0f653
BH
211
212static inline uint8_t hextodec(uint8_t val)
213{
214 if(val >= '0' && val<='9')
215 return val-'0';
216 else if(val >= 'A' && val<='F')
217 return 10+(val-'A');
218 else if(val >= 'a' && val<='f')
219 return 10+(val-'a');
220 else
221 throw RecordTextException("Unknown hexadecimal character '"+lexical_cast<string>(val)+"'");
222}
223
224
225void HEXDecode(const char* begin, const char* end, string& val)
226{
227 if((end - begin)%2)
228 throw RecordTextException("Hexadecimal blob with odd number of characters");
229
705f31ae 230 int limit=(int)(end-begin)/2;
59a0f653
BH
231 val.resize(limit);
232 for(int n=0; n < limit; ++n) {
233 val[n] = hextodec(begin[2*n])*16 + hextodec(begin[2*n+1]);
234 }
235}
236
237void RecordTextReader::xfrHexBlob(string& val)
238{
239 skipSpaces();
705f31ae 240 int pos=(int)d_pos;
59a0f653
BH
241 while(d_pos < d_end && !dns_isspace(d_string[d_pos]))
242 d_pos++;
243
244 HEXDecode(d_string.c_str()+pos, d_string.c_str() + d_pos, val);
245}
246
ef6a78d5 247void RecordTextReader::xfrText(string& val, bool multi)
4192ca66 248{
4192ca66
BH
249 val.clear();
250 val.reserve(d_end - d_pos);
ef6a78d5
BH
251
252 while(d_pos != d_end) {
253 if(!val.empty())
254 val.append(1, ' ');
255
256 skipSpaces();
257 if(d_string[d_pos]!='"')
258 throw RecordTextException("Data field in DNS should start with quote (\") at position "+lexical_cast<string>(d_pos)+" of '"+d_string+"'");
259
260 val.append(1, '"');
261 while(++d_pos < d_end && d_string[d_pos]!='"') {
262 if(d_string[d_pos]=='\\' && d_pos+1!=d_end) {
4957a608 263 val.append(1, d_string[d_pos++]);
ef6a78d5
BH
264 }
265 val.append(1, d_string[d_pos]);
4192ca66 266 }
ef6a78d5
BH
267 val.append(1,'"');
268 if(d_pos == d_end)
269 throw RecordTextException("Data field in DNS should end on a quote (\") in '"+d_string+"'");
270 d_pos++;
271 if(!multi)
272 break;
4192ca66 273 }
4192ca66
BH
274}
275
20133c59
BH
276void RecordTextReader::xfrType(uint16_t& val)
277{
278 skipSpaces();
705f31ae 279 int pos=(int)d_pos;
ec486449 280 while(d_pos < d_end && !dns_isspace(d_string[d_pos]))
20133c59
BH
281 d_pos++;
282
283 string tmp;
284 tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos);
285
286 val=DNSRecordContent::TypeToNumber(tmp);
287}
4192ca66 288
8c1c9170 289
4192ca66
BH
290void RecordTextReader::skipSpaces()
291{
d39704c0
BH
292 const char* strptr = d_string.c_str();
293 while(d_pos < d_end && dns_isspace(strptr[d_pos]))
4192ca66 294 d_pos++;
4192ca66
BH
295 if(d_pos == d_end)
296 throw RecordTextException("missing field at the end of record content '"+d_string+"'");
297}
298
299
300RecordTextWriter::RecordTextWriter(string& str) : d_string(str)
301{
302 d_string.clear();
303}
304
341930bb 305void RecordTextWriter::xfr48BitInt(const uint64_t& val)
4192ca66
BH
306{
307 if(!d_string.empty())
308 d_string.append(1,' ');
309 d_string+=lexical_cast<string>(val);
310}
311
20133c59 312
341930bb
BH
313void RecordTextWriter::xfr32BitInt(const uint32_t& val)
314{
315 if(!d_string.empty())
316 d_string.append(1,' ');
317 d_string+=lexical_cast<string>(val);
318}
20133c59
BH
319
320void RecordTextWriter::xfrType(const uint16_t& val)
321{
322 if(!d_string.empty())
323 d_string.append(1,' ');
324 d_string+=DNSRecordContent::NumberToType(val);
325}
326
ec486449 327// this function is on the fast path for the pdns_recursor
cbf0e7f3
BH
328void RecordTextWriter::xfrIP(const uint32_t& val)
329{
330 if(!d_string.empty())
331 d_string.append(1,' ');
332
ec486449 333 char tmp[17];
79a9e9ad 334 uint32_t ip=val;
1149fa0b
BH
335 uint8_t vals[4];
336
337 memcpy(&vals[0], &ip, sizeof(ip));
338
339 char *pos=tmp;
340
341 for(int n=0; n < 4; ++n) {
342 if(vals[n]<10) {
343 *(pos++)=vals[n]+'0';
344 } else if(vals[n] < 100) {
345 *(pos++)=(vals[n]/10) +'0';
346 *(pos++)=(vals[n]%10) +'0';
347 } else {
348 *(pos++)=(vals[n]/100) +'0';
349 vals[n]%=100;
350 *(pos++)=(vals[n]/10) +'0';
351 *(pos++)=(vals[n]%10) +'0';
352 }
353 if(n!=3)
354 *(pos++)='.';
355 }
356 *pos=0;
357 d_string.append(tmp, pos);
cbf0e7f3
BH
358}
359
360
8bf26468
BH
361void RecordTextWriter::xfrTime(const uint32_t& val)
362{
363 if(!d_string.empty())
364 d_string.append(1,' ');
365
366 struct tm tm;
367 time_t time=val; // Y2038 bug!
d3b729e8 368#ifndef WIN32
8bf26468 369 gmtime_r(&time, &tm);
d3b729e8
BH
370#else
371 struct tm* tmptr;
372 tmptr=gmtime(&time);
373 if(!tmptr)
374 throw RecordTextException("Unable to convert timestamp into pretty printable time");
375 tm=*tmptr;
376#endif
8bf26468
BH
377
378 char tmp[16];
379 snprintf(tmp,sizeof(tmp)-1, "%04d%02d%02d" "%02d%02d%02d",
4957a608
BH
380 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
381 tm.tm_hour, tm.tm_min, tm.tm_sec);
8bf26468
BH
382
383 d_string += tmp;
384}
385
386
cbf0e7f3
BH
387void RecordTextWriter::xfr16BitInt(const uint16_t& val)
388{
389 xfr32BitInt(val);
390}
391
8c1c9170
BH
392void RecordTextWriter::xfr8BitInt(const uint8_t& val)
393{
394 xfr32BitInt(val);
395}
396
cbf0e7f3 397
bca6643b 398void RecordTextWriter::xfrLabel(const string& val, bool)
4192ca66
BH
399{
400 if(!d_string.empty())
401 d_string.append(1,' ');
29a14b24
BH
402 if(val.find(' ')==string::npos)
403 d_string+=val;
404 else {
405 d_string.reserve(d_string.size()+val.size()+3);
406 for(string::size_type pos=0; pos < val.size() ; ++pos)
ec486449 407 if(dns_isspace(val[pos]))
4957a608 408 d_string+="\\ ";
29a14b24 409 else if(val[pos]=='\\')
4957a608 410 d_string.append(1,'\\');
29a14b24 411 else
4957a608 412 d_string.append(1,val[pos]);
29a14b24 413 }
7738a23f 414 // d_string.append(1,'.');
4192ca66
BH
415}
416
06ffdc52 417void RecordTextWriter::xfrBlob(const string& val, int)
8c1c9170
BH
418{
419 if(!d_string.empty())
420 d_string.append(1,' ');
421
422 d_string+=Base64Encode(val);
423}
424
59a0f653
BH
425void RecordTextWriter::xfrHexBlob(const string& val)
426{
427 if(!d_string.empty())
428 d_string.append(1,' ');
429
430 string::size_type limit=val.size();
431 char tmp[5];
432 for(string::size_type n = 0; n < limit; ++n) {
433 snprintf(tmp, sizeof(tmp)-1, "%02x", (unsigned char)val[n]);
434 d_string+=tmp;
435 }
436}
437
ef6a78d5 438void RecordTextWriter::xfrText(const string& val, bool multi)
4192ca66
BH
439{
440 if(!d_string.empty())
441 d_string.append(1,' ');
4192ca66 442
ef6a78d5 443 d_string.append(val);
4192ca66
BH
444}
445
446
447#ifdef TESTING
448
449int main(int argc, char**argv)
450try
451{
452 RecordTextReader rtr(argv[1], argv[2]);
453
454 unsigned int order, pref;
455 string flags, services, regexp, replacement;
456 string mx;
457
458 rtr.xfrInt(order);
459 rtr.xfrInt(pref);
cbf0e7f3
BH
460 rtr.xfrText(flags);
461 rtr.xfrText(services);
462 rtr.xfrText(regexp);
4192ca66
BH
463 rtr.xfrLabel(replacement);
464
465 cout<<"order: "<<order<<", pref: "<<pref<<"\n";
466 cout<<"flags: \""<<flags<<"\", services: \""<<services<<"\", regexp: \""<<regexp<<"\", replacement: "<<replacement<<"\n";
467
468 string out;
469 RecordTextWriter rtw(out);
470
471 rtw.xfrInt(order);
472 rtw.xfrInt(pref);
cbf0e7f3
BH
473 rtw.xfrText(flags);
474 rtw.xfrText(services);
475 rtw.xfrText(regexp);
4192ca66
BH
476 rtw.xfrLabel(replacement);
477
478 cout<<"Regenerated: '"<<out<<"'\n";
479
480}
adc10f99 481catch(std::exception& e)
4192ca66
BH
482{
483 cerr<<"Fatal: "<<e.what()<<endl;
484}
485
486#endif