]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/rcpgenerator.cc
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2005 - 2011 PowerDNS.COM BV
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
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.
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.
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
26 #include "rcpgenerator.hh"
27 #include "dnsparser.hh"
29 #include <boost/lexical_cast.hpp>
30 #include <boost/algorithm/string.hpp>
34 #include "namespaces.hh"
36 RecordTextReader::RecordTextReader(const string
& str
, const string
& zone
) : d_string(str
), d_zone(zone
), d_pos(0), d_end(str
.size())
40 void RecordTextReader::xfr48BitInt(uint64_t &val
)
45 void RecordTextReader::xfr64BitInt(uint64_t &val
)
49 if(!isdigit(d_string
.at(d_pos
)))
50 throw RecordTextException("expected digits at position "+lexical_cast
<string
>(d_pos
)+" in '"+d_string
+"'");
53 unsigned long ret
=strtoull(d_string
.c_str() + d_pos
, &endptr
, 10);
56 d_pos
= endptr
- d_string
.c_str();
60 void RecordTextReader::xfr32BitInt(uint32_t &val
)
64 if(!isdigit(d_string
.at(d_pos
)))
65 throw RecordTextException("expected digits at position "+lexical_cast
<string
>(d_pos
)+" in '"+d_string
+"'");
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
+"'");
72 d_pos
= endptr
- d_string
.c_str();
75 void RecordTextReader::xfrTime(uint32_t &val
)
78 memset(&tm
, 0, sizeof(tm
));
81 xfrLabel(tmp
); // ends on number, so this works
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
);
89 val
=(uint32_t)Utility::timegm(&tm
);
92 void RecordTextReader::xfrIP(uint32_t &val
)
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
+"'");
104 if(d_string
.at(d_pos
)=='.') {
112 else if(isdigit(d_string
.at(d_pos
))) {
114 octet
+=d_string
.at(d_pos
) - '0';
116 throw RecordTextException("unable to parse IP address");
118 else if(dns_isspace(d_string
.at(d_pos
)))
121 throw RecordTextException(string("unable to parse IP address, strange character: ")+d_string
.at(d_pos
));
124 if(d_pos
== d_string
.length())
135 void RecordTextReader::xfrIP6(std::string
&val
)
137 struct in6_addr tmpbuf
;
142 // lookup end of value - think of ::ffff encoding too, has dots in it!
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
)=='.');
148 throw RecordTextException("while parsing IPv6 address, expected xdigits at position "+lexical_cast
<string
>(d_pos
)+" in '"+d_string
+"'");
150 // end of value is here, try parse as IPv6
151 string address
=d_string
.substr(d_pos
, len
);
153 if (inet_pton(AF_INET6
, address
.c_str(), &tmpbuf
) != 1) {
154 throw RecordTextException("while parsing IPv6 address: '" + address
+ "' is invalid");
157 val
= std::string((char*)tmpbuf
.s6_addr
, 16);
162 bool RecordTextReader::eof()
167 void RecordTextReader::xfr16BitInt(uint16_t &val
)
173 throw RecordTextException("Overflow reading 16 bit integer from record content"); // fixme improve
176 void RecordTextReader::xfr8BitInt(uint8_t &val
)
182 throw RecordTextException("Overflow reading 8 bit integer from record content"); // fixme improve
185 // this code should leave all the escapes around
186 void RecordTextReader::xfrLabel(string
& val
, bool)
190 val
.reserve(d_end
- d_pos
);
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
]))
200 val
.append(strptr
+begin_pos
, strptr
+d_pos
);
204 else if(!d_zone
.empty()) {
205 char last
=val
[val
.size()-1];
208 val
.resize(val
.size()-1);
209 else if(last
!= '.' && !isdigit(last
)) // don't add zone to IP address
214 static bool isbase64(char c
, bool acceptspace
)
218 if(c
>= '0' && c
<= '9')
220 if(c
>= 'a' && c
<= 'z')
222 if(c
>= 'A' && c
<= 'Z')
224 if(c
=='+' || c
=='/' || c
=='=')
229 void RecordTextReader::xfrBlobNoSpaces(string
& val
, int len
) {
232 const char* strptr
=d_string
.c_str();
233 while(d_pos
< d_end
&& isbase64(strptr
[d_pos
], false))
237 tmp
.assign(d_string
.c_str()+pos
, d_string
.c_str() + d_pos
);
238 boost::erase_all(tmp
," ");
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
));
246 void RecordTextReader::xfrBlob(string
& val
, int)
250 const char* strptr
=d_string
.c_str();
251 while(d_pos
< d_end
&& isbase64(strptr
[d_pos
], true))
255 tmp
.assign(d_string
.c_str()+pos
, d_string
.c_str() + d_pos
);
256 boost::erase_all(tmp
," ");
262 static inline uint8_t hextodec(uint8_t val
)
264 if(val
>= '0' && val
<='9')
266 else if(val
>= 'A' && val
<='F')
268 else if(val
>= 'a' && val
<='f')
271 throw RecordTextException("Unknown hexadecimal character '"+lexical_cast
<string
>(val
)+"'");
275 void HEXDecode(const char* begin
, const char* end
, string
& out
)
277 if(end
- begin
== 1 && *begin
=='-') {
282 out
.reserve((end
-begin
)/2);
283 uint8_t mode
=0, val
=0;
284 for(; begin
!= end
; ++begin
) {
288 val
= 16*hextodec(*begin
);
291 val
+= hextodec(*begin
);
292 out
.append(1, (char) val
);
298 out
.append(1, (char) val
);
302 void RecordTextReader::xfrHexBlob(string
& val
, bool keepReading
)
306 while(d_pos
< d_end
&& (keepReading
|| !dns_isspace(d_string
[d_pos
])))
309 HEXDecode(d_string
.c_str()+pos
, d_string
.c_str() + d_pos
, val
);
312 void RecordTextReader::xfrBase32HexBlob(string
& val
)
316 while(d_pos
< d_end
&& !dns_isspace(d_string
[d_pos
]))
319 val
=fromBase32Hex(string(d_string
.c_str()+pos
, d_pos
-pos
));
323 void RecordTextWriter::xfrBase32HexBlob(const string
& val
)
325 if(!d_string
.empty())
326 d_string
.append(1,' ');
328 d_string
.append(toUpper(toBase32Hex(val
)));
332 void RecordTextReader::xfrText(string
& val
, bool multi
)
335 val
.reserve(d_end
- d_pos
);
337 while(d_pos
!= d_end
) {
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
]))
348 val
.append(d_string
.c_str() + d_pos
, d_end
- d_pos
);
353 throw RecordTextException("Data field in DNS should start with quote (\") at position "+lexical_cast
<string
>(d_pos
)+" of '"+d_string
+"'");
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
++]);
360 val
.append(1, d_string
[d_pos
]);
364 throw RecordTextException("Data field in DNS should end on a quote (\") in '"+d_string
+"'");
371 void RecordTextReader::xfrType(uint16_t& val
)
375 while(d_pos
< d_end
&& !dns_isspace(d_string
[d_pos
]))
379 tmp
.assign(d_string
.c_str()+pos
, d_string
.c_str() + d_pos
);
381 val
=DNSRecordContent::TypeToNumber(tmp
);
385 void RecordTextReader::skipSpaces()
387 const char* strptr
= d_string
.c_str();
388 while(d_pos
< d_end
&& dns_isspace(strptr
[d_pos
]))
391 throw RecordTextException("missing field at the end of record content '"+d_string
+"'");
395 RecordTextWriter::RecordTextWriter(string
& str
) : d_string(str
)
400 void RecordTextWriter::xfr48BitInt(const uint64_t& val
)
402 if(!d_string
.empty())
403 d_string
.append(1,' ');
404 d_string
+=lexical_cast
<string
>(val
);
408 void RecordTextWriter::xfr32BitInt(const uint32_t& val
)
410 if(!d_string
.empty())
411 d_string
.append(1,' ');
412 d_string
+=lexical_cast
<string
>(val
);
415 void RecordTextWriter::xfrType(const uint16_t& val
)
417 if(!d_string
.empty())
418 d_string
.append(1,' ');
419 d_string
+=DNSRecordContent::NumberToType(val
);
422 // this function is on the fast path for the pdns_recursor
423 void RecordTextWriter::xfrIP(const uint32_t& val
)
425 if(!d_string
.empty())
426 d_string
.append(1,' ');
432 memcpy(&vals
[0], &ip
, sizeof(ip
));
436 for(int n
=0; n
< 4; ++n
) {
438 *(pos
++)=vals
[n
]+'0';
439 } else if(vals
[n
] < 100) {
440 *(pos
++)=(vals
[n
]/10) +'0';
441 *(pos
++)=(vals
[n
]%10) +'0';
443 *(pos
++)=(vals
[n
]/100) +'0';
445 *(pos
++)=(vals
[n
]/10) +'0';
446 *(pos
++)=(vals
[n
]%10) +'0';
452 d_string
.append(tmp
, pos
);
455 void RecordTextWriter::xfrIP6(const std::string
& val
)
460 if(!d_string
.empty())
461 d_string
.append(1,' ');
465 if (inet_ntop(AF_INET6
, tmpbuf
, addrbuf
, sizeof addrbuf
) == NULL
)
466 throw RecordTextException("Unable to convert to ipv6 address");
468 d_string
+= std::string(addrbuf
);
471 void RecordTextWriter::xfrTime(const uint32_t& val
)
473 if(!d_string
.empty())
474 d_string
.append(1,' ');
477 time_t time
=val
; // Y2038 bug!
478 Utility::gmtime_r(&time
, &tm
);
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
);
489 void RecordTextWriter::xfr16BitInt(const uint16_t& val
)
494 void RecordTextWriter::xfr8BitInt(const uint8_t& val
)
499 // should not mess with the escapes
500 void RecordTextWriter::xfrLabel(const string
& val
, bool)
502 if(!d_string
.empty())
503 d_string
.append(1,' ');
508 void RecordTextWriter::xfrBlobNoSpaces(const string
& val
, int size
)
513 void RecordTextWriter::xfrBlob(const string
& val
, int)
515 if(!d_string
.empty())
516 d_string
.append(1,' ');
518 d_string
+=Base64Encode(val
);
521 void RecordTextWriter::xfrHexBlob(const string
& val
, bool)
523 if(!d_string
.empty())
524 d_string
.append(1,' ');
527 d_string
.append(1,'-');
531 string::size_type limit
=val
.size();
533 for(string::size_type n
= 0; n
< limit
; ++n
) {
534 snprintf(tmp
, sizeof(tmp
)-1, "%02x", (unsigned char)val
[n
]);
539 void RecordTextWriter::xfrText(const string
& val
, bool multi
)
541 if(!d_string
.empty())
542 d_string
.append(1,' ');
544 d_string
.append(val
);
550 int main(int argc
, char**argv
)
553 RecordTextReader
rtr(argv
[1], argv
[2]);
555 unsigned int order
, pref
;
556 string flags
, services
, regexp
, replacement
;
562 rtr
.xfrText(services
);
564 rtr
.xfrLabel(replacement
);
566 cout
<<"order: "<<order
<<", pref: "<<pref
<<"\n";
567 cout
<<"flags: \""<<flags
<<"\", services: \""<<services
<<"\", regexp: \""<<regexp
<<"\", replacement: "<<replacement
<<"\n";
570 RecordTextWriter
rtw(out
);
575 rtw
.xfrText(services
);
577 rtw
.xfrLabel(replacement
);
579 cout
<<"Regenerated: '"<<out
<<"'\n";
582 catch(std::exception
& e
)
584 cerr
<<"Fatal: "<<e
.what()<<endl
;