]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/rcpgenerator.cc
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "rcpgenerator.hh"
27 #include "dnsparser.hh"
30 #include <boost/algorithm/string.hpp>
31 #include <boost/algorithm/string/classification.hpp>
36 #include "namespaces.hh"
38 RecordTextReader::RecordTextReader(const string
& str
, const DNSName
& zone
) : d_string(str
), d_zone(zone
), d_pos(0)
40 /* remove whitespace */
41 if(!d_string
.empty() && ( dns_isspace(*d_string
.begin()) || dns_isspace(*d_string
.rbegin()) ))
42 boost::trim_if(d_string
, dns_isspace
);
43 d_end
= d_string
.size();
46 void RecordTextReader::xfr48BitInt(uint64_t &val
)
49 if (val
> 281474976710655LL)
50 throw RecordTextException("Overflow reading 48 bit integer from record content"); // fixme improve
53 void RecordTextReader::xfr64BitInt(uint64_t &val
)
57 if(!isdigit(d_string
.at(d_pos
)))
58 throw RecordTextException("expected digits at position "+std::to_string(d_pos
)+" in '"+d_string
+"'");
61 val
=std::stoull(d_string
.substr(d_pos
), &pos
);
67 void RecordTextReader::xfr32BitInt(uint32_t &val
)
71 if(!isdigit(d_string
.at(d_pos
)))
72 throw RecordTextException("expected digits at position "+std::to_string(d_pos
)+" in '"+d_string
+"'");
75 val
=pdns_stou(d_string
.c_str()+d_pos
, &pos
);
80 void RecordTextReader::xfrTime(uint32_t &val
)
83 memset(&tm
, 0, sizeof(tm
));
88 if (itmp
<= (uint32_t)~0) {
89 // formatted as seconds since epoch, not as YYYYMMDDHHmmSS:
90 val
= (uint32_t) itmp
;
98 sscanf(tmp
.str().c_str(), "%04d%02d%02d" "%02d%02d%02d",
99 &tm
.tm_year
, &tm
.tm_mon
, &tm
.tm_mday
,
100 &tm
.tm_hour
, &tm
.tm_min
, &tm
.tm_sec
);
104 val
=(uint32_t)Utility::timegm(&tm
);
107 void RecordTextReader::xfrIP(uint32_t &val
)
111 if(!isdigit(d_string
.at(d_pos
)))
112 throw RecordTextException("while parsing IP address, expected digits at position "+std::to_string(d_pos
)+" in '"+d_string
+"'");
117 bool last_was_digit
= false;
120 if(d_string
.at(d_pos
)=='.') {
122 throw RecordTextException(string("unable to parse IP address, dot without previous digit"));
123 last_was_digit
= false;
129 throw RecordTextException(string("unable to parse IP address, too many dots"));
131 else if(isdigit(d_string
.at(d_pos
))) {
132 last_was_digit
= true;
134 octet
+=d_string
.at(d_pos
) - '0';
136 throw RecordTextException("unable to parse IP address");
138 else if(dns_isspace(d_string
.at(d_pos
)))
141 throw RecordTextException(string("unable to parse IP address, strange character: ")+d_string
.at(d_pos
));
144 if(d_pos
== d_string
.length())
148 throw RecordTextException(string("unable to parse IP address, not enough dots"));
150 throw RecordTextException(string("unable to parse IP address, trailing dot"));
157 void RecordTextReader::xfrIP6(std::string
&val
)
159 struct in6_addr tmpbuf
;
164 // lookup end of value - think of ::ffff encoding too, has dots in it!
166 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
)=='.');
170 throw RecordTextException("while parsing IPv6 address, expected xdigits at position "+std::to_string(d_pos
)+" in '"+d_string
+"'");
172 // end of value is here, try parse as IPv6
173 string address
=d_string
.substr(d_pos
, len
);
175 if (inet_pton(AF_INET6
, address
.c_str(), &tmpbuf
) != 1) {
176 throw RecordTextException("while parsing IPv6 address: '" + address
+ "' is invalid");
179 val
= std::string((char*)tmpbuf
.s6_addr
, 16);
184 void RecordTextReader::xfrCAWithoutPort(uint8_t version
, ComboAddress
&val
)
189 val
= makeComboAddressFromRaw(4, string((const char*) &ip
, 4));
191 else if (version
== 6) {
194 val
= makeComboAddressFromRaw(6, ip
);
196 else throw RecordTextException("invalid address family");
199 void RecordTextReader::xfrCAPort(ComboAddress
&val
)
203 val
.sin4
.sin_port
= port
;
206 bool RecordTextReader::eof()
211 void RecordTextReader::xfr16BitInt(uint16_t &val
)
217 throw RecordTextException("Overflow reading 16 bit integer from record content"); // fixme improve
220 void RecordTextReader::xfr8BitInt(uint8_t &val
)
226 throw RecordTextException("Overflow reading 8 bit integer from record content"); // fixme improve
229 // this code should leave all the escapes around
230 void RecordTextReader::xfrName(DNSName
& val
, bool, bool)
235 const char* strptr
=d_string
.c_str();
236 string::size_type begin_pos
= d_pos
;
237 while(d_pos
< d_end
) {
238 if(strptr
[d_pos
]!='\r' && dns_isspace(strptr
[d_pos
]))
243 sval
= DNSName(std::string(strptr
+begin_pos
, strptr
+d_pos
));
247 else if(!d_zone
.empty())
252 static bool isbase64(char c
, bool acceptspace
)
256 if(c
>= '0' && c
<= '9')
258 if(c
>= 'a' && c
<= 'z')
260 if(c
>= 'A' && c
<= 'Z')
262 if(c
=='+' || c
=='/' || c
=='=')
267 void RecordTextReader::xfrBlobNoSpaces(string
& val
, int len
) {
270 const char* strptr
=d_string
.c_str();
271 while(d_pos
< d_end
&& isbase64(strptr
[d_pos
], false))
275 tmp
.assign(d_string
.c_str()+pos
, d_string
.c_str() + d_pos
);
276 boost::erase_all(tmp
," ");
280 if (len
>-1 && val
.size() != static_cast<size_t>(len
))
281 throw RecordTextException("Record length "+std::to_string(val
.size()) + " does not match expected length '"+std::to_string(len
));
284 void RecordTextReader::xfrBlob(string
& val
, int)
288 const char* strptr
=d_string
.c_str();
289 while(d_pos
< d_end
&& isbase64(strptr
[d_pos
], true))
293 tmp
.assign(d_string
.c_str()+pos
, d_string
.c_str() + d_pos
);
294 boost::erase_all(tmp
," ");
300 static inline uint8_t hextodec(uint8_t val
)
302 if(val
>= '0' && val
<='9')
304 else if(val
>= 'A' && val
<='F')
306 else if(val
>= 'a' && val
<='f')
309 throw RecordTextException("Unknown hexadecimal character '"+std::to_string(val
)+"'");
313 void HEXDecode(const char* begin
, const char* end
, string
& out
)
315 if(end
- begin
== 1 && *begin
=='-') {
320 out
.reserve((end
-begin
)/2);
321 uint8_t mode
=0, val
=0;
322 for(; begin
!= end
; ++begin
) {
326 val
= 16*hextodec(*begin
);
329 val
+= hextodec(*begin
);
330 out
.append(1, (char) val
);
336 out
.append(1, (char) val
);
340 void RecordTextReader::xfrHexBlob(string
& val
, bool keepReading
)
344 while(d_pos
< d_end
&& (keepReading
|| !dns_isspace(d_string
[d_pos
])))
347 HEXDecode(d_string
.c_str()+pos
, d_string
.c_str() + d_pos
, val
);
350 void RecordTextReader::xfrBase32HexBlob(string
& val
)
354 while(d_pos
< d_end
&& !dns_isspace(d_string
[d_pos
]))
357 val
=fromBase32Hex(string(d_string
.c_str()+pos
, d_pos
-pos
));
361 void RecordTextWriter::xfrBase32HexBlob(const string
& val
)
363 if(!d_string
.empty())
364 d_string
.append(1,' ');
366 d_string
.append(toUpper(toBase32Hex(val
)));
370 void RecordTextReader::xfrText(string
& val
, bool multi
, bool lenField
)
373 val
.reserve(d_end
- d_pos
);
375 while(d_pos
!= d_end
) {
380 if(d_string
[d_pos
]!='"') { // special case 'plenus' - without quotes
381 string::size_type pos
= d_pos
;
382 while(pos
!= d_end
&& isalnum(d_string
[pos
]))
386 val
.append(d_string
.c_str() + d_pos
, d_end
- d_pos
);
391 throw RecordTextException("Data field in DNS should start with quote (\") at position "+std::to_string(d_pos
)+" of '"+d_string
+"'");
394 while(++d_pos
< d_end
&& d_string
[d_pos
]!='"') {
395 if(d_string
[d_pos
]=='\\' && d_pos
+1!=d_end
) {
396 val
.append(1, d_string
[d_pos
++]);
398 val
.append(1, d_string
[d_pos
]);
402 throw RecordTextException("Data field in DNS should end on a quote (\") in '"+d_string
+"'");
409 void RecordTextReader::xfrUnquotedText(string
& val
, bool lenField
)
412 val
.reserve(d_end
- d_pos
);
418 val
.append(1, d_string
[d_pos
]);
419 while(++d_pos
< d_end
&& d_string
[d_pos
] != ' '){
420 val
.append(1, d_string
[d_pos
]);
424 void RecordTextReader::xfrType(uint16_t& val
)
428 while(d_pos
< d_end
&& !dns_isspace(d_string
[d_pos
]))
432 tmp
.assign(d_string
.c_str()+pos
, d_string
.c_str() + d_pos
);
434 val
=DNSRecordContent::TypeToNumber(tmp
);
438 void RecordTextReader::skipSpaces()
440 const char* strptr
= d_string
.c_str();
441 while(d_pos
< d_end
&& dns_isspace(strptr
[d_pos
]))
444 throw RecordTextException("missing field at the end of record content '"+d_string
+"'");
448 RecordTextWriter::RecordTextWriter(string
& str
, bool noDot
) : d_string(str
)
454 void RecordTextWriter::xfr48BitInt(const uint64_t& val
)
456 if(!d_string
.empty())
457 d_string
.append(1,' ');
458 d_string
+=std::to_string(val
);
462 void RecordTextWriter::xfr32BitInt(const uint32_t& val
)
464 if(!d_string
.empty())
465 d_string
.append(1,' ');
466 d_string
+=std::to_string(val
);
469 void RecordTextWriter::xfrType(const uint16_t& val
)
471 if(!d_string
.empty())
472 d_string
.append(1,' ');
473 d_string
+=DNSRecordContent::NumberToType(val
);
476 // this function is on the fast path for the pdns_recursor
477 void RecordTextWriter::xfrIP(const uint32_t& val
)
479 if(!d_string
.empty())
480 d_string
.append(1,' ');
486 memcpy(&vals
[0], &ip
, sizeof(ip
));
490 for(int n
=0; n
< 4; ++n
) {
492 *(pos
++)=vals
[n
]+'0';
493 } else if(vals
[n
] < 100) {
494 *(pos
++)=(vals
[n
]/10) +'0';
495 *(pos
++)=(vals
[n
]%10) +'0';
497 *(pos
++)=(vals
[n
]/100) +'0';
499 *(pos
++)=(vals
[n
]/10) +'0';
500 *(pos
++)=(vals
[n
]%10) +'0';
506 d_string
.append(tmp
, pos
);
509 void RecordTextWriter::xfrIP6(const std::string
& val
)
514 if(!d_string
.empty())
515 d_string
.append(1,' ');
519 if (inet_ntop(AF_INET6
, tmpbuf
, addrbuf
, sizeof addrbuf
) == NULL
)
520 throw RecordTextException("Unable to convert to ipv6 address");
522 d_string
+= std::string(addrbuf
);
525 void RecordTextWriter::xfrCAWithoutPort(uint8_t version
, ComboAddress
&val
)
527 string ip
= val
.toString();
529 if(!d_string
.empty())
530 d_string
.append(1,' ');
535 void RecordTextWriter::xfrCAPort(ComboAddress
&val
)
537 xfr16BitInt(val
.sin4
.sin_port
);
540 void RecordTextWriter::xfrTime(const uint32_t& val
)
542 if(!d_string
.empty())
543 d_string
.append(1,' ');
546 time_t time
=val
; // Y2038 bug!
547 gmtime_r(&time
, &tm
);
549 static const boost::format
fmt("%04d%02d%02d" "%02d%02d%02d");
550 d_string
+= boost::str(boost::format(fmt
) % (tm
.tm_year
+1900) % (tm
.tm_mon
+1) % tm
.tm_mday
% tm
.tm_hour
% tm
.tm_min
% tm
.tm_sec
);
554 void RecordTextWriter::xfr16BitInt(const uint16_t& val
)
559 void RecordTextWriter::xfr8BitInt(const uint8_t& val
)
564 // should not mess with the escapes
565 void RecordTextWriter::xfrName(const DNSName
& val
, bool, bool noDot
)
567 if(!d_string
.empty())
568 d_string
.append(1,' ');
571 d_string
+=val
.toStringRootDot();
575 d_string
+=val
.toString();
579 void RecordTextWriter::xfrBlobNoSpaces(const string
& val
, int size
)
584 void RecordTextWriter::xfrBlob(const string
& val
, int)
586 if(!d_string
.empty())
587 d_string
.append(1,' ');
589 d_string
+=Base64Encode(val
);
592 void RecordTextWriter::xfrHexBlob(const string
& val
, bool)
594 if(!d_string
.empty())
595 d_string
.append(1,' ');
598 d_string
.append(1,'-');
602 string::size_type limit
=val
.size();
604 for(string::size_type n
= 0; n
< limit
; ++n
) {
605 snprintf(tmp
, sizeof(tmp
), "%02x", (unsigned char)val
[n
]);
610 void RecordTextWriter::xfrText(const string
& val
, bool multi
, bool lenField
)
612 if(!d_string
.empty())
613 d_string
.append(1,' ');
615 d_string
.append(val
);
618 void RecordTextWriter::xfrUnquotedText(const string
& val
, bool lenField
)
620 if(!d_string
.empty())
621 d_string
.append(1,' ');
622 d_string
.append(val
);
627 int main(int argc
, char**argv
)
630 RecordTextReader
rtr(argv
[1], argv
[2]);
632 unsigned int order
, pref
;
633 string flags
, services
, regexp
, replacement
;
639 rtr
.xfrText(services
);
641 rtr
.xfrName(replacement
);
643 cout
<<"order: "<<order
<<", pref: "<<pref
<<"\n";
644 cout
<<"flags: \""<<flags
<<"\", services: \""<<services
<<"\", regexp: \""<<regexp
<<"\", replacement: "<<replacement
<<"\n";
647 RecordTextWriter
rtw(out
);
652 rtw
.xfrText(services
);
654 rtw
.xfrName(replacement
);
656 cout
<<"Regenerated: '"<<out
<<"'\n";
659 catch(std::exception
& e
)
661 cerr
<<"Fatal: "<<e
.what()<<endl
;