]>
Commit | Line | Data |
---|---|---|
4192ca66 | 1 | /* |
6edbf68a PL |
2 | * This file is part of PowerDNS or dnsdist. |
3 | * Copyright -- PowerDNS.COM B.V. and its contributors | |
4 | * | |
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. | |
8 | * | |
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. | |
12 | * | |
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. | |
17 | * | |
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. | |
21 | */ | |
870a0fe4 AT |
22 | #ifdef HAVE_CONFIG_H |
23 | #include "config.h" | |
24 | #endif | |
4192ca66 | 25 | #include "rcpgenerator.hh" |
a416d398 | 26 | #include "ascii.hh" |
20133c59 | 27 | #include "dnsparser.hh" |
cbf0e7f3 | 28 | #include "misc.hh" |
3897b9e1 | 29 | #include "utility.hh" |
12b33ac2 | 30 | #include <boost/algorithm/string.hpp> |
ff7ac440 AT |
31 | #include <boost/algorithm/string/classification.hpp> |
32 | ||
4192ca66 | 33 | #include <iostream> |
1c4d88c5 | 34 | #include "base32.hh" |
8c1c9170 | 35 | #include "base64.hh" |
d2d6cf61 | 36 | #include "namespaces.hh" |
4192ca66 | 37 | |
3716f081 | 38 | RecordTextReader::RecordTextReader(const string& str, const DNSName& zone) : d_string(str), d_zone(zone), d_pos(0) |
4192ca66 | 39 | { |
ff7ac440 | 40 | /* remove whitespace */ |
13653a1a | 41 | if(!d_string.empty() && ( dns_isspace(*d_string.begin()) || dns_isspace(*d_string.rbegin()) )) |
5ead94ed | 42 | boost::trim_if(d_string, dns_isspace); |
ff7ac440 | 43 | d_end = d_string.size(); |
4192ca66 BH |
44 | } |
45 | ||
341930bb BH |
46 | void RecordTextReader::xfr48BitInt(uint64_t &val) |
47 | { | |
48 | xfr64BitInt(val); | |
335da0ba AT |
49 | if (val > 281474976710655LL) |
50 | throw RecordTextException("Overflow reading 48 bit integer from record content"); // fixme improve | |
341930bb BH |
51 | } |
52 | ||
53 | void RecordTextReader::xfr64BitInt(uint64_t &val) | |
54 | { | |
55 | skipSpaces(); | |
56 | ||
57 | if(!isdigit(d_string.at(d_pos))) | |
335da0ba | 58 | throw RecordTextException("expected digits at position "+std::to_string(d_pos)+" in '"+d_string+"'"); |
341930bb | 59 | |
335da0ba AT |
60 | size_t pos; |
61 | val=std::stoull(d_string.substr(d_pos), &pos); | |
341930bb | 62 | |
335da0ba | 63 | d_pos += pos; |
341930bb BH |
64 | } |
65 | ||
66 | ||
cbf0e7f3 | 67 | void RecordTextReader::xfr32BitInt(uint32_t &val) |
4192ca66 BH |
68 | { |
69 | skipSpaces(); | |
70 | ||
71 | if(!isdigit(d_string.at(d_pos))) | |
335da0ba | 72 | throw RecordTextException("expected digits at position "+std::to_string(d_pos)+" in '"+d_string+"'"); |
4192ca66 | 73 | |
335da0ba | 74 | size_t pos; |
aa7b2405 | 75 | val=pdns_stou(d_string.c_str()+d_pos, &pos); |
335da0ba AT |
76 | |
77 | d_pos += pos; | |
4192ca66 BH |
78 | } |
79 | ||
8bf26468 BH |
80 | void RecordTextReader::xfrTime(uint32_t &val) |
81 | { | |
82 | struct tm tm; | |
83 | memset(&tm, 0, sizeof(tm)); | |
84 | ||
4a51ff72 | 85 | uint64_t itmp; |
7c06b0d7 | 86 | xfr64BitInt(itmp); |
4a51ff72 | 87 | |
ed07d647 SB |
88 | if (itmp <= (uint32_t)~0) { |
89 | // formatted as seconds since epoch, not as YYYYMMDDHHmmSS: | |
90 | val = (uint32_t) itmp; | |
91 | return; | |
92 | } | |
93 | ||
4a51ff72 PD |
94 | ostringstream tmp; |
95 | ||
96 | tmp<<itmp; | |
8bf26468 | 97 | |
4a51ff72 | 98 | sscanf(tmp.str().c_str(), "%04d%02d%02d" "%02d%02d%02d", |
4957a608 BH |
99 | &tm.tm_year, &tm.tm_mon, &tm.tm_mday, |
100 | &tm.tm_hour, &tm.tm_min, &tm.tm_sec); | |
8bf26468 BH |
101 | |
102 | tm.tm_year-=1900; | |
12b33ac2 | 103 | tm.tm_mon-=1; |
49f72da1 | 104 | val=(uint32_t)Utility::timegm(&tm); |
8bf26468 BH |
105 | } |
106 | ||
cbf0e7f3 BH |
107 | void RecordTextReader::xfrIP(uint32_t &val) |
108 | { | |
109 | skipSpaces(); | |
110 | ||
111 | if(!isdigit(d_string.at(d_pos))) | |
335da0ba | 112 | throw RecordTextException("while parsing IP address, expected digits at position "+std::to_string(d_pos)+" in '"+d_string+"'"); |
1149fa0b BH |
113 | |
114 | uint32_t octet=0; | |
115 | val=0; | |
116 | char count=0; | |
267951e6 SB |
117 | bool last_was_digit = false; |
118 | ||
1149fa0b BH |
119 | for(;;) { |
120 | if(d_string.at(d_pos)=='.') { | |
267951e6 SB |
121 | if (!last_was_digit) |
122 | throw RecordTextException(string("unable to parse IP address, dot without previous digit")); | |
123 | last_was_digit = false; | |
1149fa0b BH |
124 | val<<=8; |
125 | val+=octet; | |
126 | octet=0; | |
127 | count++; | |
128 | if(count > 3) | |
267951e6 | 129 | throw RecordTextException(string("unable to parse IP address, too many dots")); |
1149fa0b BH |
130 | } |
131 | else if(isdigit(d_string.at(d_pos))) { | |
267951e6 | 132 | last_was_digit = true; |
1149fa0b BH |
133 | octet*=10; |
134 | octet+=d_string.at(d_pos) - '0'; | |
135 | if(octet > 255) | |
4957a608 | 136 | throw RecordTextException("unable to parse IP address"); |
1149fa0b BH |
137 | } |
138 | else if(dns_isspace(d_string.at(d_pos))) | |
139 | break; | |
87c837a3 BH |
140 | else { |
141 | throw RecordTextException(string("unable to parse IP address, strange character: ")+d_string.at(d_pos)); | |
142 | } | |
1149fa0b BH |
143 | d_pos++; |
144 | if(d_pos == d_string.length()) | |
145 | break; | |
146 | } | |
267951e6 SB |
147 | if (count != 3) |
148 | throw RecordTextException(string("unable to parse IP address, not enough dots")); | |
149 | if (!last_was_digit) | |
150 | throw RecordTextException(string("unable to parse IP address, trailing dot")); | |
151 | val<<=8; | |
152 | val+=octet; | |
1149fa0b | 153 | val=ntohl(val); |
cbf0e7f3 BH |
154 | } |
155 | ||
156 | ||
b9b28916 AT |
157 | void RecordTextReader::xfrIP6(std::string &val) |
158 | { | |
b9b28916 AT |
159 | struct in6_addr tmpbuf; |
160 | ||
161 | skipSpaces(); | |
b9b28916 AT |
162 | |
163 | size_t len; | |
cf90f8e1 | 164 | // lookup end of value - think of ::ffff encoding too, has dots in it! |
8d388c48 | 165 | for(len=0; |
cf90f8e1 | 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)=='.'); |
8d388c48 | 167 | len++); |
b9b28916 | 168 | |
8d388c48 | 169 | if(!len) |
335da0ba | 170 | throw RecordTextException("while parsing IPv6 address, expected xdigits at position "+std::to_string(d_pos)+" in '"+d_string+"'"); |
b9b28916 | 171 | |
8d388c48 | 172 | // end of value is here, try parse as IPv6 |
173 | string address=d_string.substr(d_pos, len); | |
174 | ||
175 | if (inet_pton(AF_INET6, address.c_str(), &tmpbuf) != 1) { | |
176 | throw RecordTextException("while parsing IPv6 address: '" + address + "' is invalid"); | |
b9b28916 AT |
177 | } |
178 | ||
179 | val = std::string((char*)tmpbuf.s6_addr, 16); | |
180 | ||
181 | d_pos += len; | |
182 | } | |
183 | ||
f4352636 PD |
184 | void RecordTextReader::xfrCAWithoutPort(uint8_t version, ComboAddress &val) |
185 | { | |
186 | if (version == 4) { | |
187 | uint32_t ip; | |
188 | xfrIP(ip); | |
189 | val = makeComboAddressFromRaw(4, string((const char*) &ip, 4)); | |
190 | } | |
191 | else if (version == 6) { | |
192 | string ip; | |
193 | xfrIP6(ip); | |
194 | val = makeComboAddressFromRaw(6, ip); | |
195 | } | |
196 | else throw RecordTextException("invalid address family"); | |
197 | } | |
198 | ||
199 | void RecordTextReader::xfrCAPort(ComboAddress &val) | |
200 | { | |
201 | uint16_t port; | |
202 | xfr16BitInt(port); | |
203 | val.sin4.sin_port = port; | |
204 | } | |
205 | ||
20133c59 BH |
206 | bool RecordTextReader::eof() |
207 | { | |
208 | return d_pos==d_end; | |
209 | } | |
210 | ||
cbf0e7f3 BH |
211 | void RecordTextReader::xfr16BitInt(uint16_t &val) |
212 | { | |
213 | uint32_t tmp; | |
214 | xfr32BitInt(tmp); | |
215 | val=tmp; | |
216 | if(val!=tmp) | |
217 | throw RecordTextException("Overflow reading 16 bit integer from record content"); // fixme improve | |
218 | } | |
219 | ||
8c1c9170 BH |
220 | void RecordTextReader::xfr8BitInt(uint8_t &val) |
221 | { | |
222 | uint32_t tmp; | |
223 | xfr32BitInt(tmp); | |
224 | val=tmp; | |
225 | if(val!=tmp) | |
226 | throw RecordTextException("Overflow reading 8 bit integer from record content"); // fixme improve | |
227 | } | |
228 | ||
7ecd3576 | 229 | // this code should leave all the escapes around |
f21fc0aa | 230 | void RecordTextReader::xfrName(DNSName& val, bool, bool) |
4192ca66 BH |
231 | { |
232 | skipSpaces(); | |
3716f081 | 233 | DNSName sval; |
29a14b24 | 234 | |
d39704c0 | 235 | const char* strptr=d_string.c_str(); |
83b77f90 | 236 | string::size_type begin_pos = d_pos; |
29a14b24 | 237 | while(d_pos < d_end) { |
0a1825d6 | 238 | if(strptr[d_pos]!='\r' && dns_isspace(strptr[d_pos])) |
29a14b24 | 239 | break; |
7ecd3576 | 240 | |
4192ca66 | 241 | d_pos++; |
29a14b24 | 242 | } |
3716f081 | 243 | sval = DNSName(std::string(strptr+begin_pos, strptr+d_pos)); |
83b77f90 | 244 | |
4a51ff72 PD |
245 | if(sval.empty()) |
246 | sval=d_zone; | |
3716f081 AT |
247 | else if(!d_zone.empty()) |
248 | sval+=d_zone; | |
249 | val = sval; | |
4192ca66 BH |
250 | } |
251 | ||
2fe9d6f7 | 252 | static bool isbase64(char c, bool acceptspace) |
12b33ac2 BH |
253 | { |
254 | if(dns_isspace(c)) | |
2fe9d6f7 | 255 | return acceptspace; |
12b33ac2 BH |
256 | if(c >= '0' && c <= '9') |
257 | return true; | |
258 | if(c >= 'a' && c <= 'z') | |
259 | return true; | |
260 | if(c >= 'A' && c <= 'Z') | |
261 | return true; | |
262 | if(c=='+' || c=='/' || c=='=') | |
263 | return true; | |
264 | return false; | |
265 | } | |
266 | ||
2fe9d6f7 AT |
267 | void RecordTextReader::xfrBlobNoSpaces(string& val, int len) { |
268 | skipSpaces(); | |
269 | int pos=(int)d_pos; | |
270 | const char* strptr=d_string.c_str(); | |
271 | while(d_pos < d_end && isbase64(strptr[d_pos], false)) | |
272 | d_pos++; | |
273 | ||
274 | string tmp; | |
275 | tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos); | |
276 | boost::erase_all(tmp," "); | |
277 | val.clear(); | |
278 | B64Decode(tmp, val); | |
279 | ||
280 | if (len>-1 && val.size() != static_cast<size_t>(len)) | |
335da0ba | 281 | throw RecordTextException("Record length "+std::to_string(val.size()) + " does not match expected length '"+std::to_string(len)); |
2fe9d6f7 AT |
282 | } |
283 | ||
06ffdc52 | 284 | void RecordTextReader::xfrBlob(string& val, int) |
8c1c9170 BH |
285 | { |
286 | skipSpaces(); | |
705f31ae | 287 | int pos=(int)d_pos; |
d39704c0 | 288 | const char* strptr=d_string.c_str(); |
2fe9d6f7 | 289 | while(d_pos < d_end && isbase64(strptr[d_pos], true)) |
8c1c9170 | 290 | d_pos++; |
12b33ac2 | 291 | |
20133c59 BH |
292 | string tmp; |
293 | tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos); | |
12b33ac2 | 294 | boost::erase_all(tmp," "); |
20133c59 BH |
295 | val.clear(); |
296 | B64Decode(tmp, val); | |
8c1c9170 BH |
297 | } |
298 | ||
59a0f653 BH |
299 | |
300 | static inline uint8_t hextodec(uint8_t val) | |
301 | { | |
302 | if(val >= '0' && val<='9') | |
303 | return val-'0'; | |
304 | else if(val >= 'A' && val<='F') | |
305 | return 10+(val-'A'); | |
306 | else if(val >= 'a' && val<='f') | |
307 | return 10+(val-'a'); | |
308 | else | |
335da0ba | 309 | throw RecordTextException("Unknown hexadecimal character '"+std::to_string(val)+"'"); |
59a0f653 BH |
310 | } |
311 | ||
312 | ||
4e75f84a | 313 | void HEXDecode(const char* begin, const char* end, string& out) |
59a0f653 | 314 | { |
3c873e66 | 315 | if(end - begin == 1 && *begin=='-') { |
4e75f84a | 316 | out.clear(); |
3c873e66 BH |
317 | return; |
318 | } | |
4e75f84a BH |
319 | out.clear(); |
320 | out.reserve((end-begin)/2); | |
321 | uint8_t mode=0, val=0; | |
322 | for(; begin != end; ++begin) { | |
323 | if(!isalnum(*begin)) | |
324 | continue; | |
325 | if(mode==0) { | |
326 | val = 16*hextodec(*begin); | |
327 | mode=1; | |
328 | } else { | |
329 | val += hextodec(*begin); | |
330 | out.append(1, (char) val); | |
331 | mode = 0; | |
332 | val = 0; | |
333 | } | |
59a0f653 | 334 | } |
4e75f84a BH |
335 | if(mode) |
336 | out.append(1, (char) val); | |
337 | ||
59a0f653 BH |
338 | } |
339 | ||
e4090157 | 340 | void RecordTextReader::xfrHexBlob(string& val, bool keepReading) |
59a0f653 BH |
341 | { |
342 | skipSpaces(); | |
705f31ae | 343 | int pos=(int)d_pos; |
e4090157 | 344 | while(d_pos < d_end && (keepReading || !dns_isspace(d_string[d_pos]))) |
59a0f653 BH |
345 | d_pos++; |
346 | ||
347 | HEXDecode(d_string.c_str()+pos, d_string.c_str() + d_pos, val); | |
348 | } | |
349 | ||
8b606f6e BH |
350 | void RecordTextReader::xfrBase32HexBlob(string& val) |
351 | { | |
352 | skipSpaces(); | |
353 | int pos=(int)d_pos; | |
354 | while(d_pos < d_end && !dns_isspace(d_string[d_pos])) | |
355 | d_pos++; | |
356 | ||
357 | val=fromBase32Hex(string(d_string.c_str()+pos, d_pos-pos)); | |
358 | } | |
359 | ||
360 | ||
1c4d88c5 BH |
361 | void RecordTextWriter::xfrBase32HexBlob(const string& val) |
362 | { | |
363 | if(!d_string.empty()) | |
364 | d_string.append(1,' '); | |
365 | ||
1bad4190 | 366 | d_string.append(toUpper(toBase32Hex(val))); |
1c4d88c5 BH |
367 | } |
368 | ||
369 | ||
84e1142d | 370 | void RecordTextReader::xfrText(string& val, bool multi, bool lenField) |
4192ca66 | 371 | { |
4192ca66 BH |
372 | val.clear(); |
373 | val.reserve(d_end - d_pos); | |
ef6a78d5 BH |
374 | |
375 | while(d_pos != d_end) { | |
376 | if(!val.empty()) | |
377 | val.append(1, ' '); | |
378 | ||
379 | skipSpaces(); | |
2220e01f BH |
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])) | |
383 | pos++; | |
384 | if(pos == d_end) { | |
385 | val.append(1, '"'); | |
386 | val.append(d_string.c_str() + d_pos, d_end - d_pos); | |
387 | val.append(1, '"'); | |
388 | d_pos = d_end; | |
389 | break; | |
390 | } | |
335da0ba | 391 | throw RecordTextException("Data field in DNS should start with quote (\") at position "+std::to_string(d_pos)+" of '"+d_string+"'"); |
2220e01f | 392 | } |
ef6a78d5 BH |
393 | val.append(1, '"'); |
394 | while(++d_pos < d_end && d_string[d_pos]!='"') { | |
395 | if(d_string[d_pos]=='\\' && d_pos+1!=d_end) { | |
4957a608 | 396 | val.append(1, d_string[d_pos++]); |
ef6a78d5 BH |
397 | } |
398 | val.append(1, d_string[d_pos]); | |
4192ca66 | 399 | } |
ef6a78d5 BH |
400 | val.append(1,'"'); |
401 | if(d_pos == d_end) | |
402 | throw RecordTextException("Data field in DNS should end on a quote (\") in '"+d_string+"'"); | |
403 | d_pos++; | |
404 | if(!multi) | |
405 | break; | |
4192ca66 | 406 | } |
4192ca66 BH |
407 | } |
408 | ||
948a927f PL |
409 | void RecordTextReader::xfrUnquotedText(string& val, bool lenField) |
410 | { | |
411 | val.clear(); | |
412 | val.reserve(d_end - d_pos); | |
413 | ||
414 | if(!val.empty()) | |
415 | val.append(1, ' '); | |
416 | ||
417 | skipSpaces(); | |
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]); | |
421 | } | |
422 | } | |
423 | ||
20133c59 BH |
424 | void RecordTextReader::xfrType(uint16_t& val) |
425 | { | |
426 | skipSpaces(); | |
705f31ae | 427 | int pos=(int)d_pos; |
ec486449 | 428 | while(d_pos < d_end && !dns_isspace(d_string[d_pos])) |
20133c59 BH |
429 | d_pos++; |
430 | ||
431 | string tmp; | |
432 | tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos); | |
433 | ||
434 | val=DNSRecordContent::TypeToNumber(tmp); | |
435 | } | |
4192ca66 | 436 | |
8c1c9170 | 437 | |
4192ca66 BH |
438 | void RecordTextReader::skipSpaces() |
439 | { | |
d39704c0 BH |
440 | const char* strptr = d_string.c_str(); |
441 | while(d_pos < d_end && dns_isspace(strptr[d_pos])) | |
4192ca66 | 442 | d_pos++; |
4192ca66 BH |
443 | if(d_pos == d_end) |
444 | throw RecordTextException("missing field at the end of record content '"+d_string+"'"); | |
445 | } | |
446 | ||
447 | ||
f21fc0aa | 448 | RecordTextWriter::RecordTextWriter(string& str, bool noDot) : d_string(str) |
4192ca66 BH |
449 | { |
450 | d_string.clear(); | |
f21fc0aa | 451 | d_nodot=noDot; |
4192ca66 BH |
452 | } |
453 | ||
341930bb | 454 | void RecordTextWriter::xfr48BitInt(const uint64_t& val) |
4192ca66 BH |
455 | { |
456 | if(!d_string.empty()) | |
457 | d_string.append(1,' '); | |
335da0ba | 458 | d_string+=std::to_string(val); |
4192ca66 BH |
459 | } |
460 | ||
20133c59 | 461 | |
341930bb BH |
462 | void RecordTextWriter::xfr32BitInt(const uint32_t& val) |
463 | { | |
464 | if(!d_string.empty()) | |
465 | d_string.append(1,' '); | |
335da0ba | 466 | d_string+=std::to_string(val); |
341930bb | 467 | } |
20133c59 BH |
468 | |
469 | void RecordTextWriter::xfrType(const uint16_t& val) | |
470 | { | |
471 | if(!d_string.empty()) | |
472 | d_string.append(1,' '); | |
473 | d_string+=DNSRecordContent::NumberToType(val); | |
474 | } | |
475 | ||
ec486449 | 476 | // this function is on the fast path for the pdns_recursor |
cbf0e7f3 BH |
477 | void RecordTextWriter::xfrIP(const uint32_t& val) |
478 | { | |
479 | if(!d_string.empty()) | |
480 | d_string.append(1,' '); | |
481 | ||
ec486449 | 482 | char tmp[17]; |
79a9e9ad | 483 | uint32_t ip=val; |
1149fa0b BH |
484 | uint8_t vals[4]; |
485 | ||
486 | memcpy(&vals[0], &ip, sizeof(ip)); | |
487 | ||
488 | char *pos=tmp; | |
489 | ||
490 | for(int n=0; n < 4; ++n) { | |
491 | if(vals[n]<10) { | |
492 | *(pos++)=vals[n]+'0'; | |
493 | } else if(vals[n] < 100) { | |
494 | *(pos++)=(vals[n]/10) +'0'; | |
495 | *(pos++)=(vals[n]%10) +'0'; | |
496 | } else { | |
497 | *(pos++)=(vals[n]/100) +'0'; | |
498 | vals[n]%=100; | |
499 | *(pos++)=(vals[n]/10) +'0'; | |
500 | *(pos++)=(vals[n]%10) +'0'; | |
501 | } | |
502 | if(n!=3) | |
503 | *(pos++)='.'; | |
504 | } | |
505 | *pos=0; | |
506 | d_string.append(tmp, pos); | |
cbf0e7f3 BH |
507 | } |
508 | ||
b9b28916 AT |
509 | void RecordTextWriter::xfrIP6(const std::string& val) |
510 | { | |
511 | char tmpbuf[16]; | |
512 | char addrbuf[40]; | |
513 | ||
514 | if(!d_string.empty()) | |
515 | d_string.append(1,' '); | |
516 | ||
517 | val.copy(tmpbuf,16); | |
518 | ||
519 | if (inet_ntop(AF_INET6, tmpbuf, addrbuf, sizeof addrbuf) == NULL) | |
520 | throw RecordTextException("Unable to convert to ipv6 address"); | |
521 | ||
522 | d_string += std::string(addrbuf); | |
523 | } | |
cbf0e7f3 | 524 | |
f4352636 PD |
525 | void RecordTextWriter::xfrCAWithoutPort(uint8_t version, ComboAddress &val) |
526 | { | |
527 | string ip = val.toString(); | |
528 | ||
529 | if(!d_string.empty()) | |
530 | d_string.append(1,' '); | |
531 | ||
532 | d_string += ip; | |
533 | } | |
534 | ||
535 | void RecordTextWriter::xfrCAPort(ComboAddress &val) | |
536 | { | |
537 | xfr16BitInt(val.sin4.sin_port); | |
538 | } | |
539 | ||
8bf26468 BH |
540 | void RecordTextWriter::xfrTime(const uint32_t& val) |
541 | { | |
542 | if(!d_string.empty()) | |
543 | d_string.append(1,' '); | |
544 | ||
545 | struct tm tm; | |
546 | time_t time=val; // Y2038 bug! | |
c96765da | 547 | gmtime_r(&time, &tm); |
76473b92 | 548 | |
3cbe2773 CHB |
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); | |
8bf26468 BH |
551 | } |
552 | ||
553 | ||
cbf0e7f3 BH |
554 | void RecordTextWriter::xfr16BitInt(const uint16_t& val) |
555 | { | |
556 | xfr32BitInt(val); | |
557 | } | |
558 | ||
8c1c9170 BH |
559 | void RecordTextWriter::xfr8BitInt(const uint8_t& val) |
560 | { | |
561 | xfr32BitInt(val); | |
562 | } | |
563 | ||
7ecd3576 | 564 | // should not mess with the escapes |
f21fc0aa | 565 | void RecordTextWriter::xfrName(const DNSName& val, bool, bool noDot) |
4192ca66 BH |
566 | { |
567 | if(!d_string.empty()) | |
568 | d_string.append(1,' '); | |
7ecd3576 | 569 | |
f21fc0aa | 570 | if(d_nodot) { |
3b295666 | 571 | d_string+=val.toStringRootDot(); |
f21fc0aa PD |
572 | } |
573 | else | |
574 | { | |
575 | d_string+=val.toString(); | |
576 | } | |
4192ca66 BH |
577 | } |
578 | ||
2fe9d6f7 AT |
579 | void RecordTextWriter::xfrBlobNoSpaces(const string& val, int size) |
580 | { | |
581 | xfrBlob(val, size); | |
582 | } | |
583 | ||
06ffdc52 | 584 | void RecordTextWriter::xfrBlob(const string& val, int) |
8c1c9170 BH |
585 | { |
586 | if(!d_string.empty()) | |
587 | d_string.append(1,' '); | |
588 | ||
589 | d_string+=Base64Encode(val); | |
590 | } | |
591 | ||
e4090157 | 592 | void RecordTextWriter::xfrHexBlob(const string& val, bool) |
59a0f653 BH |
593 | { |
594 | if(!d_string.empty()) | |
595 | d_string.append(1,' '); | |
596 | ||
3c873e66 BH |
597 | if(val.empty()) { |
598 | d_string.append(1,'-'); | |
599 | return; | |
600 | } | |
601 | ||
59a0f653 BH |
602 | string::size_type limit=val.size(); |
603 | char tmp[5]; | |
604 | for(string::size_type n = 0; n < limit; ++n) { | |
9b2244e1 | 605 | snprintf(tmp, sizeof(tmp), "%02x", (unsigned char)val[n]); |
59a0f653 BH |
606 | d_string+=tmp; |
607 | } | |
608 | } | |
609 | ||
84e1142d | 610 | void RecordTextWriter::xfrText(const string& val, bool multi, bool lenField) |
4192ca66 BH |
611 | { |
612 | if(!d_string.empty()) | |
613 | d_string.append(1,' '); | |
4192ca66 | 614 | |
ef6a78d5 | 615 | d_string.append(val); |
4192ca66 BH |
616 | } |
617 | ||
948a927f PL |
618 | void RecordTextWriter::xfrUnquotedText(const string& val, bool lenField) |
619 | { | |
620 | if(!d_string.empty()) | |
621 | d_string.append(1,' '); | |
622 | d_string.append(val); | |
623 | } | |
4192ca66 BH |
624 | |
625 | #ifdef TESTING | |
626 | ||
627 | int main(int argc, char**argv) | |
628 | try | |
629 | { | |
630 | RecordTextReader rtr(argv[1], argv[2]); | |
631 | ||
632 | unsigned int order, pref; | |
633 | string flags, services, regexp, replacement; | |
634 | string mx; | |
635 | ||
636 | rtr.xfrInt(order); | |
637 | rtr.xfrInt(pref); | |
cbf0e7f3 BH |
638 | rtr.xfrText(flags); |
639 | rtr.xfrText(services); | |
640 | rtr.xfrText(regexp); | |
ad8fa726 | 641 | rtr.xfrName(replacement); |
4192ca66 BH |
642 | |
643 | cout<<"order: "<<order<<", pref: "<<pref<<"\n"; | |
644 | cout<<"flags: \""<<flags<<"\", services: \""<<services<<"\", regexp: \""<<regexp<<"\", replacement: "<<replacement<<"\n"; | |
645 | ||
646 | string out; | |
647 | RecordTextWriter rtw(out); | |
648 | ||
649 | rtw.xfrInt(order); | |
650 | rtw.xfrInt(pref); | |
cbf0e7f3 BH |
651 | rtw.xfrText(flags); |
652 | rtw.xfrText(services); | |
653 | rtw.xfrText(regexp); | |
ad8fa726 | 654 | rtw.xfrName(replacement); |
4192ca66 BH |
655 | |
656 | cout<<"Regenerated: '"<<out<<"'\n"; | |
657 | ||
658 | } | |
adc10f99 | 659 | catch(std::exception& e) |
4192ca66 BH |
660 | { |
661 | cerr<<"Fatal: "<<e.what()<<endl; | |
662 | } | |
663 | ||
664 | #endif |