root/trunk/pdns/pdns/rcpgenerator.cc @ 1681

Revision 1681, 11.6 KB (checked in by ahu, 3 years ago)

gratefully copied timegm replacement code from dietlibc! (GPL)

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