xref: /openbsd-src/usr.sbin/unbound/sldns/wire2str.c (revision ae3cb403620ab940fbaabb3055fac045a63d56b7)
1 /*
2  * wire2str.c
3  *
4  * conversion routines from the wire format
5  * to the presentation format (strings)
6  *
7  * (c) NLnet Labs, 2004-2006
8  *
9  * See the file LICENSE for the license
10  */
11 /**
12  * \file
13  *
14  * Contains functions to translate the wireformat to text
15  * representation, as well as functions to print them.
16  */
17 #include "config.h"
18 #include "sldns/wire2str.h"
19 #include "sldns/str2wire.h"
20 #include "sldns/rrdef.h"
21 #include "sldns/pkthdr.h"
22 #include "sldns/parseutil.h"
23 #include "sldns/sbuffer.h"
24 #include "sldns/keyraw.h"
25 #ifdef HAVE_TIME_H
26 #include <time.h>
27 #endif
28 #include <sys/time.h>
29 #include <stdarg.h>
30 #include <ctype.h>
31 #ifdef HAVE_NETDB_H
32 #include <netdb.h>
33 #endif
34 
35 /* lookup tables for standard DNS stuff  */
36 /* Taken from RFC 2535, section 7.  */
37 static sldns_lookup_table sldns_algorithms_data[] = {
38 	{ LDNS_RSAMD5, "RSAMD5" },
39 	{ LDNS_DH, "DH" },
40 	{ LDNS_DSA, "DSA" },
41 	{ LDNS_ECC, "ECC" },
42 	{ LDNS_RSASHA1, "RSASHA1" },
43 	{ LDNS_DSA_NSEC3, "DSA-NSEC3-SHA1" },
44 	{ LDNS_RSASHA1_NSEC3, "RSASHA1-NSEC3-SHA1" },
45 	{ LDNS_RSASHA256, "RSASHA256"},
46 	{ LDNS_RSASHA512, "RSASHA512"},
47 	{ LDNS_ECC_GOST, "ECC-GOST"},
48 	{ LDNS_ECDSAP256SHA256, "ECDSAP256SHA256"},
49 	{ LDNS_ECDSAP384SHA384, "ECDSAP384SHA384"},
50 	{ LDNS_ED25519, "ED25519"},
51 	{ LDNS_ED448, "ED448"},
52 	{ LDNS_INDIRECT, "INDIRECT" },
53 	{ LDNS_PRIVATEDNS, "PRIVATEDNS" },
54 	{ LDNS_PRIVATEOID, "PRIVATEOID" },
55 	{ 0, NULL }
56 };
57 sldns_lookup_table* sldns_algorithms = sldns_algorithms_data;
58 
59 /* hash algorithms in DS record */
60 static sldns_lookup_table sldns_hashes_data[] = {
61 	{ LDNS_SHA1, "SHA1" },
62 	{ LDNS_SHA256, "SHA256" },
63 	{ LDNS_HASH_GOST, "HASH-GOST" },
64 	{ LDNS_SHA384, "SHA384" },
65 	{ 0, NULL }
66 };
67 sldns_lookup_table* sldns_hashes = sldns_hashes_data;
68 
69 /* Taken from RFC 4398  */
70 static sldns_lookup_table sldns_cert_algorithms_data[] = {
71 	{ LDNS_CERT_PKIX, "PKIX" },
72 	{ LDNS_CERT_SPKI, "SPKI" },
73 	{ LDNS_CERT_PGP, "PGP" },
74 	{ LDNS_CERT_IPKIX, "IPKIX" },
75 	{ LDNS_CERT_ISPKI, "ISPKI" },
76 	{ LDNS_CERT_IPGP, "IPGP" },
77 	{ LDNS_CERT_ACPKIX, "ACPKIX" },
78 	{ LDNS_CERT_IACPKIX, "IACPKIX" },
79 	{ LDNS_CERT_URI, "URI" },
80 	{ LDNS_CERT_OID, "OID" },
81 	{ 0, NULL }
82 };
83 sldns_lookup_table* sldns_cert_algorithms = sldns_cert_algorithms_data;
84 
85 /* if these are used elsewhere */
86 static sldns_lookup_table sldns_rcodes_data[] = {
87 	{ LDNS_RCODE_NOERROR, "NOERROR" },
88 	{ LDNS_RCODE_FORMERR, "FORMERR" },
89 	{ LDNS_RCODE_SERVFAIL, "SERVFAIL" },
90 	{ LDNS_RCODE_NXDOMAIN, "NXDOMAIN" },
91 	{ LDNS_RCODE_NOTIMPL, "NOTIMPL" },
92 	{ LDNS_RCODE_REFUSED, "REFUSED" },
93 	{ LDNS_RCODE_YXDOMAIN, "YXDOMAIN" },
94 	{ LDNS_RCODE_YXRRSET, "YXRRSET" },
95 	{ LDNS_RCODE_NXRRSET, "NXRRSET" },
96 	{ LDNS_RCODE_NOTAUTH, "NOTAUTH" },
97 	{ LDNS_RCODE_NOTZONE, "NOTZONE" },
98 	{ 0, NULL }
99 };
100 sldns_lookup_table* sldns_rcodes = sldns_rcodes_data;
101 
102 static sldns_lookup_table sldns_opcodes_data[] = {
103 	{ LDNS_PACKET_QUERY, "QUERY" },
104 	{ LDNS_PACKET_IQUERY, "IQUERY" },
105 	{ LDNS_PACKET_STATUS, "STATUS" },
106 	{ LDNS_PACKET_NOTIFY, "NOTIFY" },
107 	{ LDNS_PACKET_UPDATE, "UPDATE" },
108 	{ 0, NULL }
109 };
110 sldns_lookup_table* sldns_opcodes = sldns_opcodes_data;
111 
112 static sldns_lookup_table sldns_wireparse_errors_data[] = {
113 	{ LDNS_WIREPARSE_ERR_OK, "no parse error" },
114 	{ LDNS_WIREPARSE_ERR_GENERAL, "parse error" },
115 	{ LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, "Domainname length overflow" },
116 	{ LDNS_WIREPARSE_ERR_DOMAINNAME_UNDERFLOW, "Domainname length underflow (zero length)" },
117 	{ LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, "buffer too small" },
118 	{ LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, "Label length overflow" },
119 	{ LDNS_WIREPARSE_ERR_EMPTY_LABEL, "Empty label" },
120 	{ LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE, "Syntax error, bad escape sequence" },
121 	{ LDNS_WIREPARSE_ERR_SYNTAX, "Syntax error, could not parse the RR" },
122 	{ LDNS_WIREPARSE_ERR_SYNTAX_TTL, "Syntax error, could not parse the RR's TTL" },
123 	{ LDNS_WIREPARSE_ERR_SYNTAX_TYPE, "Syntax error, could not parse the RR's type" },
124 	{ LDNS_WIREPARSE_ERR_SYNTAX_CLASS, "Syntax error, could not parse the RR's class" },
125 	{ LDNS_WIREPARSE_ERR_SYNTAX_RDATA, "Syntax error, could not parse the RR's rdata" },
126 	{ LDNS_WIREPARSE_ERR_SYNTAX_MISSING_VALUE, "Syntax error, value expected" },
127 	{ LDNS_WIREPARSE_ERR_INVALID_STR, "Conversion error, string expected" },
128 	{ LDNS_WIREPARSE_ERR_SYNTAX_B64, "Conversion error, b64 encoding expected" },
129 	{ LDNS_WIREPARSE_ERR_SYNTAX_B32_EXT, "Conversion error, b32 ext encoding expected" },
130 	{ LDNS_WIREPARSE_ERR_SYNTAX_HEX, "Conversion error, hex encoding expected" },
131 	{ LDNS_WIREPARSE_ERR_CERT_BAD_ALGORITHM, "Bad algorithm type for CERT record" },
132 	{ LDNS_WIREPARSE_ERR_SYNTAX_TIME, "Conversion error, time encoding expected" },
133 	{ LDNS_WIREPARSE_ERR_SYNTAX_PERIOD, "Conversion error, time period encoding expected" },
134 	{ LDNS_WIREPARSE_ERR_SYNTAX_ILNP64, "Conversion error, 4 colon separated hex numbers expected" },
135 	{ LDNS_WIREPARSE_ERR_SYNTAX_EUI48,
136 		"Conversion error, 6 two character hex numbers "
137 		"separated by dashes expected (i.e. xx-xx-xx-xx-xx-xx" },
138 	{ LDNS_WIREPARSE_ERR_SYNTAX_EUI64,
139 		"Conversion error, 8 two character hex numbers "
140 		"separated by dashes expected (i.e. xx-xx-xx-xx-xx-xx-xx-xx" },
141 	{ LDNS_WIREPARSE_ERR_SYNTAX_TAG,
142 		"Conversion error, a non-zero sequence of US-ASCII letters "
143 		"and numbers in lower case expected" },
144 	{ LDNS_WIREPARSE_ERR_NOT_IMPL, "not implemented" },
145 	{ LDNS_WIREPARSE_ERR_SYNTAX_INT, "Conversion error, integer expected" },
146 	{ LDNS_WIREPARSE_ERR_SYNTAX_IP4, "Conversion error, ip4 addr expected" },
147 	{ LDNS_WIREPARSE_ERR_SYNTAX_IP6, "Conversion error, ip6 addr expected" },
148 	{ LDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW, "Syntax error, integer overflow" },
149 	{ LDNS_WIREPARSE_ERR_INCLUDE, "$INCLUDE directive was seen in the zone" },
150 	{ LDNS_WIREPARSE_ERR_PARENTHESIS, "Parse error, parenthesis mismatch" },
151 	{ 0, NULL }
152 };
153 sldns_lookup_table* sldns_wireparse_errors = sldns_wireparse_errors_data;
154 
155 static sldns_lookup_table sldns_edns_flags_data[] = {
156 	{ 3600, "do"},
157 	{ 0, NULL}
158 };
159 sldns_lookup_table* sldns_edns_flags = sldns_edns_flags_data;
160 
161 static sldns_lookup_table sldns_edns_options_data[] = {
162 	{ 1, "LLQ" },
163 	{ 2, "UL" },
164 	{ 3, "NSID" },
165 	/* 4 draft-cheshire-edns0-owner-option */
166 	{ 5, "DAU" },
167 	{ 6, "DHU" },
168 	{ 7, "N3U" },
169 	{ 8, "edns-client-subnet" },
170 	{ 11, "edns-tcp-keepalive"},
171 	{ 12, "Padding" },
172 	{ 0, NULL}
173 };
174 sldns_lookup_table* sldns_edns_options = sldns_edns_options_data;
175 
176 static sldns_lookup_table sldns_tsig_errors_data[] = {
177 	{ LDNS_TSIG_ERROR_NOERROR, "NOERROR" },
178 	{ LDNS_RCODE_FORMERR, "FORMERR" },
179 	{ LDNS_RCODE_SERVFAIL, "SERVFAIL" },
180 	{ LDNS_RCODE_NXDOMAIN, "NXDOMAIN" },
181 	{ LDNS_RCODE_NOTIMPL, "NOTIMPL" },
182 	{ LDNS_RCODE_REFUSED, "REFUSED" },
183 	{ LDNS_RCODE_YXDOMAIN, "YXDOMAIN" },
184 	{ LDNS_RCODE_YXRRSET, "YXRRSET" },
185 	{ LDNS_RCODE_NXRRSET, "NXRRSET" },
186 	{ LDNS_RCODE_NOTAUTH, "NOTAUTH" },
187 	{ LDNS_RCODE_NOTZONE, "NOTZONE" },
188 	{ LDNS_TSIG_ERROR_BADSIG, "BADSIG" },
189 	{ LDNS_TSIG_ERROR_BADKEY, "BADKEY" },
190 	{ LDNS_TSIG_ERROR_BADTIME, "BADTIME" },
191 	{ LDNS_TSIG_ERROR_BADMODE, "BADMODE" },
192 	{ LDNS_TSIG_ERROR_BADNAME, "BADNAME" },
193 	{ LDNS_TSIG_ERROR_BADALG, "BADALG" },
194 	{ 0, NULL }
195 };
196 sldns_lookup_table* sldns_tsig_errors = sldns_tsig_errors_data;
197 
198 char* sldns_wire2str_pkt(uint8_t* data, size_t len)
199 {
200 	size_t slen = (size_t)sldns_wire2str_pkt_buf(data, len, NULL, 0);
201 	char* result = (char*)malloc(slen+1);
202 	if(!result) return NULL;
203 	sldns_wire2str_pkt_buf(data, len, result, slen+1);
204 	return result;
205 }
206 
207 char* sldns_wire2str_rr(uint8_t* rr, size_t len)
208 {
209 	size_t slen = (size_t)sldns_wire2str_rr_buf(rr, len, NULL, 0);
210 	char* result = (char*)malloc(slen+1);
211 	if(!result) return NULL;
212 	sldns_wire2str_rr_buf(rr, len, result, slen+1);
213 	return result;
214 }
215 
216 char* sldns_wire2str_type(uint16_t rrtype)
217 {
218 	char buf[16];
219 	sldns_wire2str_type_buf(rrtype, buf, sizeof(buf));
220 	return strdup(buf);
221 }
222 
223 char* sldns_wire2str_class(uint16_t rrclass)
224 {
225 	char buf[16];
226 	sldns_wire2str_class_buf(rrclass, buf, sizeof(buf));
227 	return strdup(buf);
228 }
229 
230 char* sldns_wire2str_dname(uint8_t* dname, size_t dname_len)
231 {
232 	size_t slen=(size_t)sldns_wire2str_dname_buf(dname, dname_len, NULL, 0);
233 	char* result = (char*)malloc(slen+1);
234 	if(!result) return NULL;
235 	sldns_wire2str_dname_buf(dname, dname_len, result, slen+1);
236 	return result;
237 }
238 
239 char* sldns_wire2str_rcode(int rcode)
240 {
241 	char buf[16];
242 	sldns_wire2str_rcode_buf(rcode, buf, sizeof(buf));
243 	return strdup(buf);
244 }
245 
246 int sldns_wire2str_pkt_buf(uint8_t* d, size_t dlen, char* s, size_t slen)
247 {
248 	/* use arguments as temporary variables */
249 	return sldns_wire2str_pkt_scan(&d, &dlen, &s, &slen);
250 }
251 
252 int sldns_wire2str_rr_buf(uint8_t* d, size_t dlen, char* s, size_t slen)
253 {
254 	/* use arguments as temporary variables */
255 	return sldns_wire2str_rr_scan(&d, &dlen, &s, &slen, NULL, 0);
256 }
257 
258 int sldns_wire2str_rdata_buf(uint8_t* rdata, size_t rdata_len, char* str,
259 	size_t str_len, uint16_t rrtype)
260 {
261 	/* use arguments as temporary variables */
262 	return sldns_wire2str_rdata_scan(&rdata, &rdata_len, &str, &str_len,
263 		rrtype, NULL, 0);
264 }
265 
266 int sldns_wire2str_rr_unknown_buf(uint8_t* d, size_t dlen, char* s, size_t slen)
267 {
268 	/* use arguments as temporary variables */
269 	return sldns_wire2str_rr_unknown_scan(&d, &dlen, &s, &slen, NULL, 0);
270 }
271 
272 int sldns_wire2str_rr_comment_buf(uint8_t* rr, size_t rrlen, size_t dname_len,
273 	char* s, size_t slen)
274 {
275 	uint16_t rrtype = sldns_wirerr_get_type(rr, rrlen, dname_len);
276 	return sldns_wire2str_rr_comment_print(&s, &slen, rr, rrlen, dname_len,
277 		rrtype);
278 }
279 
280 int sldns_wire2str_type_buf(uint16_t rrtype, char* s, size_t slen)
281 {
282 	/* use arguments as temporary variables */
283 	return sldns_wire2str_type_print(&s, &slen, rrtype);
284 }
285 
286 int sldns_wire2str_class_buf(uint16_t rrclass, char* s, size_t slen)
287 {
288 	/* use arguments as temporary variables */
289 	return sldns_wire2str_class_print(&s, &slen, rrclass);
290 }
291 
292 int sldns_wire2str_rcode_buf(int rcode, char* s, size_t slen)
293 {
294 	/* use arguments as temporary variables */
295 	return sldns_wire2str_rcode_print(&s, &slen, rcode);
296 }
297 
298 int sldns_wire2str_opcode_buf(int opcode, char* s, size_t slen)
299 {
300 	/* use arguments as temporary variables */
301 	return sldns_wire2str_opcode_print(&s, &slen, opcode);
302 }
303 
304 int sldns_wire2str_dname_buf(uint8_t* d, size_t dlen, char* s, size_t slen)
305 {
306 	/* use arguments as temporary variables */
307 	return sldns_wire2str_dname_scan(&d, &dlen, &s, &slen, NULL, 0);
308 }
309 
310 int sldns_str_vprint(char** str, size_t* slen, const char* format, va_list args)
311 {
312 	int w = vsnprintf(*str, *slen, format, args);
313 	if(w < 0) {
314 		/* error in printout */
315 		return 0;
316 	} else if((size_t)w >= *slen) {
317 		*str = NULL; /* we do not want str to point outside of buffer*/
318 		*slen = 0;
319 	} else {
320 		*str += w;
321 		*slen -= w;
322 	}
323 	return w;
324 }
325 
326 int sldns_str_print(char** str, size_t* slen, const char* format, ...)
327 {
328 	int w;
329 	va_list args;
330 	va_start(args, format);
331 	w = sldns_str_vprint(str, slen, format, args);
332 	va_end(args);
333 	return w;
334 }
335 
336 /** print hex format into text buffer for specified length */
337 static int print_hex_buf(char** s, size_t* slen, uint8_t* buf, size_t len)
338 {
339 	const char* hex = "0123456789ABCDEF";
340 	size_t i;
341 	for(i=0; i<len; i++) {
342 		(void)sldns_str_print(s, slen, "%c%c", hex[(buf[i]&0xf0)>>4],
343 			hex[buf[i]&0x0f]);
344 	}
345 	return (int)len*2;
346 }
347 
348 /** print remainder of buffer in hex format with prefixed text */
349 static int print_remainder_hex(const char* pref, uint8_t** d, size_t* dlen,
350 	char** s, size_t* slen)
351 {
352 	int w = 0;
353 	w += sldns_str_print(s, slen, "%s", pref);
354 	w += print_hex_buf(s, slen, *d, *dlen);
355 	*d += *dlen;
356 	*dlen = 0;
357 	return w;
358 }
359 
360 int sldns_wire2str_pkt_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen)
361 {
362 	int w = 0;
363 	unsigned qdcount, ancount, nscount, arcount, i;
364 	uint8_t* pkt = *d;
365 	size_t pktlen = *dlen;
366 	if(*dlen >= LDNS_HEADER_SIZE) {
367 		qdcount = (unsigned)LDNS_QDCOUNT(*d);
368 		ancount = (unsigned)LDNS_ANCOUNT(*d);
369 		nscount = (unsigned)LDNS_NSCOUNT(*d);
370 		arcount = (unsigned)LDNS_ARCOUNT(*d);
371 	} else {
372 		qdcount = ancount = nscount = arcount = 0;
373 	}
374 	w += sldns_wire2str_header_scan(d, dlen, s, slen);
375 	w += sldns_str_print(s, slen, "\n");
376 	w += sldns_str_print(s, slen, ";; QUESTION SECTION:\n");
377 	for(i=0; i<qdcount; i++) {
378 		w += sldns_wire2str_rrquestion_scan(d, dlen, s, slen,
379 			pkt, pktlen);
380 		if(!*dlen) break;
381 	}
382 	w += sldns_str_print(s, slen, "\n");
383 	w += sldns_str_print(s, slen, ";; ANSWER SECTION:\n");
384 	for(i=0; i<ancount; i++) {
385 		w += sldns_wire2str_rr_scan(d, dlen, s, slen, pkt, pktlen);
386 		if(!*dlen) break;
387 	}
388 	w += sldns_str_print(s, slen, "\n");
389 	w += sldns_str_print(s, slen, ";; AUTHORITY SECTION:\n");
390 	for(i=0; i<nscount; i++) {
391 		w += sldns_wire2str_rr_scan(d, dlen, s, slen, pkt, pktlen);
392 		if(!*dlen) break;
393 	}
394 	w += sldns_str_print(s, slen, "\n");
395 	w += sldns_str_print(s, slen, ";; ADDITIONAL SECTION:\n");
396 	for(i=0; i<arcount; i++) {
397 		w += sldns_wire2str_rr_scan(d, dlen, s, slen, pkt, pktlen);
398 		if(!*dlen) break;
399 	}
400 	/* other fields: WHEN(time), SERVER(IP) not available here. */
401 	w += sldns_str_print(s, slen, ";; MSG SIZE  rcvd: %d\n", (int)pktlen);
402 	if(*dlen > 0) {
403 		w += print_remainder_hex(";; trailing garbage 0x",
404 			d, dlen, s, slen);
405 		w += sldns_str_print(s, slen, "\n");
406 	}
407 	return w;
408 }
409 
410 /** scan type, class and ttl and printout, for rr */
411 static int sldns_rr_tcttl_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
412 {
413 	int w = 0;
414 	uint16_t t, c;
415 	uint32_t ttl;
416 	if(*dl < 8) {
417 		if(*dl < 4)
418 			return w + print_remainder_hex("; Error malformed 0x",
419 				d, dl, s, sl);
420 		/* these print values or 0x.. if none left */
421 		t = sldns_read_uint16(*d);
422 		c = sldns_read_uint16((*d)+2);
423 		(*d)+=4;
424 		(*dl)-=4;
425 		w += sldns_wire2str_class_print(s, sl, c);
426 		w += sldns_str_print(s, sl, "\t");
427 		w += sldns_wire2str_type_print(s, sl, t);
428 		if(*dl == 0)
429 			return w + sldns_str_print(s, sl, "; Error no ttl");
430 		return w + print_remainder_hex(
431 			"; Error malformed ttl 0x", d, dl, s, sl);
432 	}
433 	t = sldns_read_uint16(*d);
434 	c = sldns_read_uint16((*d)+2);
435 	ttl = sldns_read_uint32((*d)+4);
436 	(*d)+=8;
437 	(*dl)-=8;
438 	w += sldns_str_print(s, sl, "%lu\t", (unsigned long)ttl);
439 	w += sldns_wire2str_class_print(s, sl, c);
440 	w += sldns_str_print(s, sl, "\t");
441 	w += sldns_wire2str_type_print(s, sl, t);
442 	return w;
443 }
444 
445 int sldns_wire2str_rr_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
446 	uint8_t* pkt, size_t pktlen)
447 {
448 	int w = 0;
449 	uint8_t* rr = *d;
450 	size_t rrlen = *dlen, dname_off, rdlen, ordlen;
451 	uint16_t rrtype = 0;
452 
453 	if(*dlen >= 3 && (*d)[0]==0 &&
454 		sldns_read_uint16((*d)+1)==LDNS_RR_TYPE_OPT) {
455 		/* perform EDNS OPT processing */
456 		return sldns_wire2str_edns_scan(d, dlen, s, slen, pkt, pktlen);
457 	}
458 
459 	/* try to scan the rdata with pretty-printing, but if that fails, then
460 	 * scan the rdata as an unknown RR type */
461 	w += sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen);
462 	w += sldns_str_print(s, slen, "\t");
463 	dname_off = rrlen-(*dlen);
464 	if(*dlen == 4) {
465 		/* like a question-RR */
466 		uint16_t t = sldns_read_uint16(*d);
467 		uint16_t c = sldns_read_uint16((*d)+2);
468 		(*d)+=4;
469 		(*dlen)-=4;
470 		w += sldns_wire2str_class_print(s, slen, c);
471 		w += sldns_str_print(s, slen, "\t");
472 		w += sldns_wire2str_type_print(s, slen, t);
473 		w += sldns_str_print(s, slen, " ; Error no ttl,rdata\n");
474 		return w;
475 	}
476 	if(*dlen < 8) {
477 		if(*dlen == 0)
478 			return w + sldns_str_print(s, slen, ";Error missing RR\n");
479 		w += print_remainder_hex(";Error partial RR 0x", d, dlen, s, slen);
480 		return w + sldns_str_print(s, slen, "\n");
481 	}
482 	rrtype = sldns_read_uint16(*d);
483 	w += sldns_rr_tcttl_scan(d, dlen, s, slen);
484 	w += sldns_str_print(s, slen, "\t");
485 
486 	/* rdata */
487 	if(*dlen < 2) {
488 		if(*dlen == 0)
489 			return w + sldns_str_print(s, slen, ";Error missing rdatalen\n");
490 		w += print_remainder_hex(";Error missing rdatalen 0x",
491 			d, dlen, s, slen);
492 		return w + sldns_str_print(s, slen, "\n");
493 	}
494 	rdlen = sldns_read_uint16(*d);
495 	ordlen = rdlen;
496 	(*d)+=2;
497 	(*dlen)-=2;
498 	if(*dlen < rdlen) {
499 		w += sldns_str_print(s, slen, "\\# %u ", (unsigned)rdlen);
500 		if(*dlen == 0)
501 			return w + sldns_str_print(s, slen, ";Error missing rdata\n");
502 		w += print_remainder_hex(";Error partial rdata 0x", d, dlen, s, slen);
503 		return w + sldns_str_print(s, slen, "\n");
504 	}
505 	w += sldns_wire2str_rdata_scan(d, &rdlen, s, slen, rrtype, pkt, pktlen);
506 	(*dlen) -= (ordlen-rdlen);
507 
508 	/* default comment */
509 	w += sldns_wire2str_rr_comment_print(s, slen, rr, rrlen, dname_off,
510 		rrtype);
511 	w += sldns_str_print(s, slen, "\n");
512 	return w;
513 }
514 
515 int sldns_wire2str_rrquestion_scan(uint8_t** d, size_t* dlen, char** s,
516 	size_t* slen, uint8_t* pkt, size_t pktlen)
517 {
518 	int w = 0;
519 	uint16_t t, c;
520 	w += sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen);
521 	w += sldns_str_print(s, slen, "\t");
522 	if(*dlen < 4) {
523 		if(*dlen == 0)
524 			return w + sldns_str_print(s, slen, "Error malformed\n");
525 		w += print_remainder_hex("Error malformed 0x", d, dlen, s, slen);
526 		return w + sldns_str_print(s, slen, "\n");
527 	}
528 	t = sldns_read_uint16(*d);
529 	c = sldns_read_uint16((*d)+2);
530 	(*d)+=4;
531 	(*dlen)-=4;
532 	w += sldns_wire2str_class_print(s, slen, c);
533 	w += sldns_str_print(s, slen, "\t");
534 	w += sldns_wire2str_type_print(s, slen, t);
535 	w += sldns_str_print(s, slen, "\n");
536 	return w;
537 }
538 
539 int sldns_wire2str_rr_unknown_scan(uint8_t** d, size_t* dlen, char** s,
540 	size_t* slen, uint8_t* pkt, size_t pktlen)
541 {
542 	size_t rdlen, ordlen;
543 	int w = 0;
544 	w += sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen);
545 	w += sldns_str_print(s, slen, "\t");
546 	w += sldns_rr_tcttl_scan(d, dlen, s, slen);
547 	w += sldns_str_print(s, slen, "\t");
548 	if(*dlen < 2) {
549 		if(*dlen == 0)
550 			return w + sldns_str_print(s, slen, ";Error missing rdatalen\n");
551 		w += print_remainder_hex(";Error missing rdatalen 0x",
552 			d, dlen, s, slen);
553 		return w + sldns_str_print(s, slen, "\n");
554 	}
555 	rdlen = sldns_read_uint16(*d);
556 	ordlen = rdlen;
557 	(*d) += 2;
558 	(*dlen) -= 2;
559 	if(*dlen < rdlen) {
560 		w += sldns_str_print(s, slen, "\\# %u ", (unsigned)rdlen);
561 		if(*dlen == 0)
562 			return w + sldns_str_print(s, slen, ";Error missing rdata\n");
563 		w += print_remainder_hex(";Error partial rdata 0x", d, dlen, s, slen);
564 		return w + sldns_str_print(s, slen, "\n");
565 	}
566 	w += sldns_wire2str_rdata_unknown_scan(d, &rdlen, s, slen);
567 	(*dlen) -= (ordlen-rdlen);
568 	w += sldns_str_print(s, slen, "\n");
569 	return w;
570 }
571 
572 /** print rr comment for type DNSKEY */
573 static int rr_comment_dnskey(char** s, size_t* slen, uint8_t* rr,
574 	size_t rrlen, size_t dname_off)
575 {
576 	size_t rdlen;
577 	uint8_t* rdata;
578 	int flags, w = 0;
579 	if(rrlen < dname_off + 10) return 0;
580 	rdlen = sldns_read_uint16(rr+dname_off+8);
581 	if(rrlen < dname_off + 10 + rdlen) return 0;
582 	rdata = rr + dname_off + 10;
583 	flags = (int)sldns_read_uint16(rdata);
584 	w += sldns_str_print(s, slen, " ;{");
585 
586 	/* id */
587 	w += sldns_str_print(s, slen, "id = %u",
588 		sldns_calc_keytag_raw(rdata, rdlen));
589 
590 	/* flags */
591 	if((flags&LDNS_KEY_ZONE_KEY)) {
592 		if((flags&LDNS_KEY_SEP_KEY))
593 			w += sldns_str_print(s, slen, " (ksk)");
594 		else 	w += sldns_str_print(s, slen, " (zsk)");
595 	}
596 
597 	/* keysize */
598 	if(rdlen > 4) {
599 		w += sldns_str_print(s, slen, ", ");
600 		w += sldns_str_print(s, slen, "size = %db",
601 			(int)sldns_rr_dnskey_key_size_raw(
602 			(unsigned char*)rdata+4, rdlen-4, (int)(rdata[3])));
603 	}
604 
605 	w += sldns_str_print(s, slen, "}");
606 	return w;
607 }
608 
609 /** print rr comment for type RRSIG */
610 static int rr_comment_rrsig(char** s, size_t* slen, uint8_t* rr,
611 	size_t rrlen, size_t dname_off)
612 {
613 	size_t rdlen;
614 	uint8_t* rdata;
615 	if(rrlen < dname_off + 10) return 0;
616 	rdlen = sldns_read_uint16(rr+dname_off+8);
617 	if(rrlen < dname_off + 10 + rdlen) return 0;
618 	rdata = rr + dname_off + 10;
619 	if(rdlen < 18) return 0;
620 	return sldns_str_print(s, slen, " ;{id = %d}",
621 		(int)sldns_read_uint16(rdata+16));
622 }
623 
624 /** print rr comment for type NSEC3 */
625 static int rr_comment_nsec3(char** s, size_t* slen, uint8_t* rr,
626 	size_t rrlen, size_t dname_off)
627 {
628 	size_t rdlen;
629 	uint8_t* rdata;
630 	int w = 0;
631 	if(rrlen < dname_off + 10) return 0;
632 	rdlen = sldns_read_uint16(rr+dname_off+8);
633 	if(rrlen < dname_off + 10 + rdlen) return 0;
634 	rdata = rr + dname_off + 10;
635 	if(rdlen < 2) return 0;
636 	if((rdata[1] & LDNS_NSEC3_VARS_OPTOUT_MASK))
637 		w += sldns_str_print(s, slen, " ;{flags: optout}");
638 	return w;
639 }
640 
641 int sldns_wire2str_rr_comment_print(char** s, size_t* slen, uint8_t* rr,
642 	size_t rrlen, size_t dname_off, uint16_t rrtype)
643 {
644 	if(rrtype == LDNS_RR_TYPE_DNSKEY) {
645 		return rr_comment_dnskey(s, slen, rr, rrlen, dname_off);
646 	} else if(rrtype == LDNS_RR_TYPE_RRSIG) {
647 		return rr_comment_rrsig(s, slen, rr, rrlen, dname_off);
648 	} else if(rrtype == LDNS_RR_TYPE_NSEC3) {
649 		return rr_comment_nsec3(s, slen, rr, rrlen, dname_off);
650 	}
651 	return 0;
652 }
653 
654 int sldns_wire2str_header_scan(uint8_t** d, size_t* dlen, char** s,
655 	size_t* slen)
656 {
657 	int w = 0;
658 	int opcode, rcode;
659 	w += sldns_str_print(s, slen, ";; ->>HEADER<<- ");
660 	if(*dlen == 0)
661 		return w+sldns_str_print(s, slen, "Error empty packet");
662 	if(*dlen < 4)
663 		return w+print_remainder_hex("Error header too short 0x", d, dlen, s, slen);
664 	opcode = (int)LDNS_OPCODE_WIRE(*d);
665 	rcode = (int)LDNS_RCODE_WIRE(*d);
666 	w += sldns_str_print(s, slen, "opcode: ");
667 	w += sldns_wire2str_opcode_print(s, slen, opcode);
668 	w += sldns_str_print(s, slen, ", ");
669 	w += sldns_str_print(s, slen, "rcode: ");
670 	w += sldns_wire2str_rcode_print(s, slen, rcode);
671 	w += sldns_str_print(s, slen, ", ");
672 	w += sldns_str_print(s, slen, "id: %d\n", (int)LDNS_ID_WIRE(*d));
673 	w += sldns_str_print(s, slen, ";; flags:");
674 	if(LDNS_QR_WIRE(*d)) w += sldns_str_print(s, slen, " qr");
675 	if(LDNS_AA_WIRE(*d)) w += sldns_str_print(s, slen, " aa");
676 	if(LDNS_TC_WIRE(*d)) w += sldns_str_print(s, slen, " tc");
677 	if(LDNS_RD_WIRE(*d)) w += sldns_str_print(s, slen, " rd");
678 	if(LDNS_CD_WIRE(*d)) w += sldns_str_print(s, slen, " cd");
679 	if(LDNS_RA_WIRE(*d)) w += sldns_str_print(s, slen, " ra");
680 	if(LDNS_AD_WIRE(*d)) w += sldns_str_print(s, slen, " ad");
681 	if(LDNS_Z_WIRE(*d))  w += sldns_str_print(s, slen, " z");
682 	w += sldns_str_print(s, slen, " ; ");
683 	if(*dlen < LDNS_HEADER_SIZE)
684 		return w+print_remainder_hex("Error header too short 0x", d, dlen, s, slen);
685 	w += sldns_str_print(s, slen, "QUERY: %d, ", (int)LDNS_QDCOUNT(*d));
686 	w += sldns_str_print(s, slen, "ANSWER: %d, ", (int)LDNS_ANCOUNT(*d));
687 	w += sldns_str_print(s, slen, "AUTHORITY: %d, ", (int)LDNS_NSCOUNT(*d));
688 	w += sldns_str_print(s, slen, "ADDITIONAL: %d ", (int)LDNS_ARCOUNT(*d));
689 	*d += LDNS_HEADER_SIZE;
690 	*dlen -= LDNS_HEADER_SIZE;
691 	return w;
692 }
693 
694 int sldns_wire2str_rdata_scan(uint8_t** d, size_t* dlen, char** s,
695 	size_t* slen, uint16_t rrtype, uint8_t* pkt, size_t pktlen)
696 {
697 	/* try to prettyprint, but if that fails, use unknown format */
698 	uint8_t* origd = *d;
699 	char* origs = *s;
700 	size_t origdlen = *dlen, origslen = *slen;
701 	size_t r_cnt, r_max;
702 	sldns_rdf_type rdftype;
703 	int w = 0, n;
704 
705 	const sldns_rr_descriptor *desc = sldns_rr_descript(rrtype);
706 	if(!desc) /* unknown format */
707 		return sldns_wire2str_rdata_unknown_scan(d, dlen, s, slen);
708 	/* dlen equals the rdatalen for the rdata */
709 
710 	r_max = sldns_rr_descriptor_maximum(desc);
711 	for(r_cnt=0; r_cnt < r_max; r_cnt++) {
712 		if(*dlen == 0) {
713 			if(r_cnt < sldns_rr_descriptor_minimum(desc))
714 				goto failed;
715 			break; /* nothing more to print */
716 		}
717 		rdftype = sldns_rr_descriptor_field_type(desc, r_cnt);
718 		if(r_cnt != 0)
719 			w += sldns_str_print(s, slen, " ");
720 		n = sldns_wire2str_rdf_scan(d, dlen, s, slen, rdftype,
721 			pkt, pktlen);
722 		if(n == -1) {
723 		failed:
724 			/* failed, use unknown format */
725 			*d = origd; *s = origs;
726 			*dlen = origdlen; *slen = origslen;
727 			return sldns_wire2str_rdata_unknown_scan(d, dlen,
728 				s, slen);
729 		}
730 		w += n;
731 	}
732 	if(*dlen != 0) {
733 		goto failed;
734 	}
735 	return w;
736 }
737 
738 int sldns_wire2str_rdata_unknown_scan(uint8_t** d, size_t* dlen, char** s,
739 	size_t* slen)
740 {
741 	int w = 0;
742 
743 	/* print length */
744 	w += sldns_str_print(s, slen, "\\# %u", (unsigned)*dlen);
745 
746 	/* print rdlen in hex */
747 	if(*dlen != 0)
748 		w += sldns_str_print(s, slen, " ");
749 	w += print_hex_buf(s, slen, *d, *dlen);
750 	(*d) += *dlen;
751 	(*dlen) = 0;
752 	return w;
753 }
754 
755 /** print and escape one character for a domain dname */
756 static int dname_char_print(char** s, size_t* slen, uint8_t c)
757 {
758 	if(c == '.' || c == ';' || c == '(' || c == ')' || c == '\\')
759 		return sldns_str_print(s, slen, "\\%c", c);
760 	else if(!(isascii((unsigned char)c) && isgraph((unsigned char)c)))
761 		return sldns_str_print(s, slen, "\\%03u", (unsigned)c);
762 	/* plain printout */
763 	if(*slen) {
764 		**s = (char)c;
765 		(*s)++;
766 		(*slen)--;
767 	}
768 	return 1;
769 }
770 
771 int sldns_wire2str_dname_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
772 	uint8_t* pkt, size_t pktlen)
773 {
774 	int w = 0;
775 	/* spool labels onto the string, use compression if its there */
776 	uint8_t* pos = *d;
777 	unsigned i, counter=0;
778 	const unsigned maxcompr = 1000; /* loop detection, max compr ptrs */
779 	int in_buf = 1;
780 	if(*dlen == 0) return sldns_str_print(s, slen, "ErrorMissingDname");
781 	if(*pos == 0) {
782 		(*d)++;
783 		(*dlen)--;
784 		return sldns_str_print(s, slen, ".");
785 	}
786 	while(*pos) {
787 		/* read label length */
788 		uint8_t labellen = *pos++;
789 		if(in_buf) { (*d)++; (*dlen)--; }
790 
791 		/* find out what sort of label we have */
792 		if((labellen&0xc0) == 0xc0) {
793 			/* compressed */
794 			uint16_t target = 0;
795 			if(in_buf && *dlen == 0)
796 				return w + sldns_str_print(s, slen,
797 					"ErrorPartialDname");
798 			else if(!in_buf && pos+1 > pkt+pktlen)
799 				return w + sldns_str_print(s, slen,
800 					"ErrorPartialDname");
801 			target = ((labellen&0x3f)<<8) | *pos;
802 			if(in_buf) { (*d)++; (*dlen)--; }
803 			/* move to target, if possible */
804 			if(!pkt || target >= pktlen)
805 				return w + sldns_str_print(s, slen,
806 					"ErrorComprPtrOutOfBounds");
807 			if(counter++ > maxcompr)
808 				return w + sldns_str_print(s, slen,
809 					"ErrorComprPtrLooped");
810 			in_buf = 0;
811 			pos = pkt+target;
812 			continue;
813 		} else if((labellen&0xc0)) {
814 			/* notimpl label type */
815 			w += sldns_str_print(s, slen,
816 				"ErrorLABELTYPE%xIsUnknown",
817 				(int)(labellen&0xc0));
818 			return w;
819 		}
820 
821 		/* spool label characters, end with '.' */
822 		if(in_buf && *dlen < (size_t)labellen)
823 			labellen = (uint8_t)*dlen;
824 		else if(!in_buf && pos+(size_t)labellen > pkt+pktlen)
825 			labellen = (uint8_t)(pkt + pktlen - pos);
826 		for(i=0; i<(unsigned)labellen; i++) {
827 			w += dname_char_print(s, slen, *pos++);
828 		}
829 		if(in_buf) {
830 			(*d) += labellen;
831 			(*dlen) -= labellen;
832 			if(*dlen == 0) break;
833 		}
834 		w += sldns_str_print(s, slen, ".");
835 	}
836 	/* skip over final root label */
837 	if(in_buf && *dlen > 0) { (*d)++; (*dlen)--; }
838 	/* in case we printed no labels, terminate dname */
839 	if(w == 0) w += sldns_str_print(s, slen, ".");
840 	return w;
841 }
842 
843 int sldns_wire2str_opcode_print(char** s, size_t* slen, int opcode)
844 {
845 	sldns_lookup_table *lt = sldns_lookup_by_id(sldns_opcodes, opcode);
846 	if (lt && lt->name) {
847 		return sldns_str_print(s, slen, "%s", lt->name);
848 	}
849 	return sldns_str_print(s, slen, "OPCODE%u", (unsigned)opcode);
850 }
851 
852 int sldns_wire2str_rcode_print(char** s, size_t* slen, int rcode)
853 {
854 	sldns_lookup_table *lt = sldns_lookup_by_id(sldns_rcodes, rcode);
855 	if (lt && lt->name) {
856 		return sldns_str_print(s, slen, "%s", lt->name);
857 	}
858 	return sldns_str_print(s, slen, "RCODE%u", (unsigned)rcode);
859 }
860 
861 int sldns_wire2str_class_print(char** s, size_t* slen, uint16_t rrclass)
862 {
863 	sldns_lookup_table *lt = sldns_lookup_by_id(sldns_rr_classes,
864 		(int)rrclass);
865 	if (lt && lt->name) {
866 		return sldns_str_print(s, slen, "%s", lt->name);
867 	}
868 	return sldns_str_print(s, slen, "CLASS%u", (unsigned)rrclass);
869 }
870 
871 int sldns_wire2str_type_print(char** s, size_t* slen, uint16_t rrtype)
872 {
873 	const sldns_rr_descriptor *descriptor = sldns_rr_descript(rrtype);
874 	if (descriptor && descriptor->_name) {
875 		return sldns_str_print(s, slen, "%s", descriptor->_name);
876 	}
877 	return sldns_str_print(s, slen, "TYPE%u", (unsigned)rrtype);
878 }
879 
880 int sldns_wire2str_edns_option_code_print(char** s, size_t* slen,
881 	uint16_t opcode)
882 {
883 	sldns_lookup_table *lt = sldns_lookup_by_id(sldns_edns_options,
884 		(int)opcode);
885 	if (lt && lt->name) {
886 		return sldns_str_print(s, slen, "%s", lt->name);
887 	}
888 	return sldns_str_print(s, slen, "OPT%u", (unsigned)opcode);
889 }
890 
891 int sldns_wire2str_class_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen)
892 {
893 	uint16_t c;
894 	if(*dlen == 0) return 0;
895 	if(*dlen < 2) return print_remainder_hex("Error malformed 0x", d, dlen, s, slen);
896 	c = sldns_read_uint16(*d);
897 	(*d)+=2;
898 	(*dlen)-=2;
899 	return sldns_wire2str_class_print(s, slen, c);
900 }
901 
902 int sldns_wire2str_type_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen)
903 {
904 	uint16_t t;
905 	if(*dlen == 0) return 0;
906 	if(*dlen < 2) return print_remainder_hex("Error malformed 0x", d, dlen, s, slen);
907 	t = sldns_read_uint16(*d);
908 	(*d)+=2;
909 	(*dlen)-=2;
910 	return sldns_wire2str_type_print(s, slen, t);
911 }
912 
913 int sldns_wire2str_ttl_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen)
914 {
915 	uint32_t ttl;
916 	if(*dlen == 0) return 0;
917 	if(*dlen < 4) return print_remainder_hex("Error malformed 0x", d, dlen, s, slen);
918 	ttl = sldns_read_uint32(*d);
919 	(*d)+=4;
920 	(*dlen)-=4;
921 	return sldns_str_print(s, slen, "%u", (unsigned)ttl);
922 }
923 
924 int sldns_wire2str_rdf_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
925 	int rdftype, uint8_t* pkt, size_t pktlen)
926 {
927 	if(*dlen == 0) return 0;
928 	switch(rdftype) {
929 	case LDNS_RDF_TYPE_NONE:
930 		return 0;
931 	case LDNS_RDF_TYPE_DNAME:
932 		return sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen);
933 	case LDNS_RDF_TYPE_INT8:
934 		return sldns_wire2str_int8_scan(d, dlen, s, slen);
935 	case LDNS_RDF_TYPE_INT16:
936 		return sldns_wire2str_int16_scan(d, dlen, s, slen);
937 	case LDNS_RDF_TYPE_INT32:
938 		return sldns_wire2str_int32_scan(d, dlen, s, slen);
939 	case LDNS_RDF_TYPE_PERIOD:
940 		return sldns_wire2str_period_scan(d, dlen, s, slen);
941 	case LDNS_RDF_TYPE_TSIGTIME:
942 		return sldns_wire2str_tsigtime_scan(d, dlen, s, slen);
943 	case LDNS_RDF_TYPE_A:
944 		return sldns_wire2str_a_scan(d, dlen, s, slen);
945 	case LDNS_RDF_TYPE_AAAA:
946 		return sldns_wire2str_aaaa_scan(d, dlen, s, slen);
947 	case LDNS_RDF_TYPE_STR:
948 		return sldns_wire2str_str_scan(d, dlen, s, slen);
949 	case LDNS_RDF_TYPE_APL:
950 		return sldns_wire2str_apl_scan(d, dlen, s, slen);
951 	case LDNS_RDF_TYPE_B32_EXT:
952 		return sldns_wire2str_b32_ext_scan(d, dlen, s, slen);
953 	case LDNS_RDF_TYPE_B64:
954 		return sldns_wire2str_b64_scan(d, dlen, s, slen);
955 	case LDNS_RDF_TYPE_HEX:
956 		return sldns_wire2str_hex_scan(d, dlen, s, slen);
957 	case LDNS_RDF_TYPE_NSEC:
958 		return sldns_wire2str_nsec_scan(d, dlen, s, slen);
959 	case LDNS_RDF_TYPE_NSEC3_SALT:
960 		return sldns_wire2str_nsec3_salt_scan(d, dlen, s, slen);
961 	case LDNS_RDF_TYPE_TYPE:
962 		return sldns_wire2str_type_scan(d, dlen, s, slen);
963 	case LDNS_RDF_TYPE_CLASS:
964 		return sldns_wire2str_class_scan(d, dlen, s, slen);
965 	case LDNS_RDF_TYPE_CERT_ALG:
966 		return sldns_wire2str_cert_alg_scan(d, dlen, s, slen);
967 	case LDNS_RDF_TYPE_ALG:
968 		return sldns_wire2str_alg_scan(d, dlen, s, slen);
969 	case LDNS_RDF_TYPE_UNKNOWN:
970 		return sldns_wire2str_unknown_scan(d, dlen, s, slen);
971 	case LDNS_RDF_TYPE_TIME:
972 		return sldns_wire2str_time_scan(d, dlen, s, slen);
973 	case LDNS_RDF_TYPE_LOC:
974 		return sldns_wire2str_loc_scan(d, dlen, s, slen);
975 	case LDNS_RDF_TYPE_WKS:
976 	case LDNS_RDF_TYPE_SERVICE:
977 		return sldns_wire2str_wks_scan(d, dlen, s, slen);
978 	case LDNS_RDF_TYPE_NSAP:
979 		return sldns_wire2str_nsap_scan(d, dlen, s, slen);
980 	case LDNS_RDF_TYPE_ATMA:
981 		return sldns_wire2str_atma_scan(d, dlen, s, slen);
982 	case LDNS_RDF_TYPE_IPSECKEY:
983 		return sldns_wire2str_ipseckey_scan(d, dlen, s, slen, pkt,
984 			pktlen);
985 	case LDNS_RDF_TYPE_HIP:
986 		return sldns_wire2str_hip_scan(d, dlen, s, slen);
987 	case LDNS_RDF_TYPE_INT16_DATA:
988 		return sldns_wire2str_int16_data_scan(d, dlen, s, slen);
989 	case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER:
990 		return sldns_wire2str_b32_ext_scan(d, dlen, s, slen);
991 	case LDNS_RDF_TYPE_ILNP64:
992 		return sldns_wire2str_ilnp64_scan(d, dlen, s, slen);
993 	case LDNS_RDF_TYPE_EUI48:
994 		return sldns_wire2str_eui48_scan(d, dlen, s, slen);
995 	case LDNS_RDF_TYPE_EUI64:
996 		return sldns_wire2str_eui64_scan(d, dlen, s, slen);
997 	case LDNS_RDF_TYPE_TAG:
998 		return sldns_wire2str_tag_scan(d, dlen, s, slen);
999 	case LDNS_RDF_TYPE_LONG_STR:
1000 		return sldns_wire2str_long_str_scan(d, dlen, s, slen);
1001 	case LDNS_RDF_TYPE_TSIGERROR:
1002 		return sldns_wire2str_tsigerror_scan(d, dlen, s, slen);
1003 	}
1004 	/* unknown rdf type */
1005 	return -1;
1006 }
1007 
1008 int sldns_wire2str_int8_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1009 {
1010 	int w;
1011 	if(*dl < 1) return -1;
1012 	w = sldns_str_print(s, sl, "%u", (unsigned)**d);
1013 	(*d)++;
1014 	(*dl)--;
1015 	return w;
1016 }
1017 
1018 int sldns_wire2str_int16_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1019 {
1020 	int w;
1021 	if(*dl < 2) return -1;
1022 	w = sldns_str_print(s, sl, "%lu", (unsigned long)sldns_read_uint16(*d));
1023 	(*d)+=2;
1024 	(*dl)-=2;
1025 	return w;
1026 }
1027 
1028 int sldns_wire2str_int32_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1029 {
1030 	int w;
1031 	if(*dl < 4) return -1;
1032 	w = sldns_str_print(s, sl, "%lu", (unsigned long)sldns_read_uint32(*d));
1033 	(*d)+=4;
1034 	(*dl)-=4;
1035 	return w;
1036 }
1037 
1038 int sldns_wire2str_period_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1039 {
1040 	int w;
1041 	if(*dl < 4) return -1;
1042 	w = sldns_str_print(s, sl, "%u", (unsigned)sldns_read_uint32(*d));
1043 	(*d)+=4;
1044 	(*dl)-=4;
1045 	return w;
1046 }
1047 
1048 int sldns_wire2str_tsigtime_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1049 {
1050 	/* tsigtime is 48 bits network order unsigned integer */
1051 	int w;
1052 	uint64_t tsigtime = 0;
1053 	uint64_t d0, d1, d2, d3, d4, d5;
1054 	if(*dl < 6) return -1;
1055 	d0 = (*d)[0]; /* cast to uint64 for shift operations */
1056 	d1 = (*d)[1];
1057 	d2 = (*d)[2];
1058 	d3 = (*d)[3];
1059 	d4 = (*d)[4];
1060 	d5 = (*d)[5];
1061 	tsigtime = (d0<<40) | (d1<<32) | (d2<<24) | (d3<<16) | (d4<<8) | d5;
1062 #ifndef USE_WINSOCK
1063 	w = sldns_str_print(s, sl, "%llu", (long long)tsigtime);
1064 #else
1065 	w = sldns_str_print(s, sl, "%I64u", (long long)tsigtime);
1066 #endif
1067 	(*d)+=6;
1068 	(*dl)-=6;
1069 	return w;
1070 }
1071 
1072 int sldns_wire2str_a_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1073 {
1074 	char buf[32];
1075 	int w;
1076 	if(*dl < 4) return -1;
1077 	if(!inet_ntop(AF_INET, *d, buf, (socklen_t)sizeof(buf)))
1078 		return -1;
1079 	w = sldns_str_print(s, sl, "%s", buf);
1080 	(*d)+=4;
1081 	(*dl)-=4;
1082 	return w;
1083 }
1084 
1085 int sldns_wire2str_aaaa_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1086 {
1087 #ifdef AF_INET6
1088 	char buf[64];
1089 	int w;
1090 	if(*dl < 16) return -1;
1091 	if(!inet_ntop(AF_INET6, *d, buf, (socklen_t)sizeof(buf)))
1092 		return -1;
1093 	w = sldns_str_print(s, sl, "%s", buf);
1094 	(*d)+=16;
1095 	(*dl)-=16;
1096 	return w;
1097 #else
1098 	return -1;
1099 #endif
1100 }
1101 
1102 /** printout escaped TYPE_STR character */
1103 static int str_char_print(char** s, size_t* sl, uint8_t c)
1104 {
1105 	if(isprint((unsigned char)c) || c == '\t') {
1106 		if(c == '\"' || c == '\\')
1107 			return sldns_str_print(s, sl, "\\%c", c);
1108 		if(*sl) {
1109 			**s = (char)c;
1110 			(*s)++;
1111 			(*sl)--;
1112 		}
1113 		return 1;
1114 	}
1115 	return sldns_str_print(s, sl, "\\%03u", (unsigned)c);
1116 }
1117 
1118 int sldns_wire2str_str_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1119 {
1120 	int w = 0;
1121 	size_t i, len;
1122 	if(*dl < 1) return -1;
1123 	len = **d;
1124 	if(*dl < 1+len) return -1;
1125 	(*d)++;
1126 	(*dl)--;
1127 	w += sldns_str_print(s, sl, "\"");
1128 	for(i=0; i<len; i++)
1129 		w += str_char_print(s, sl, (*d)[i]);
1130 	w += sldns_str_print(s, sl, "\"");
1131 	(*d)+=len;
1132 	(*dl)-=len;
1133 	return w;
1134 }
1135 
1136 int sldns_wire2str_apl_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1137 {
1138 	int i, w = 0;
1139 	uint16_t family;
1140 	uint8_t negation, prefix, adflength;
1141 	if(*dl < 4) return -1;
1142 	family = sldns_read_uint16(*d);
1143 	prefix = (*d)[2];
1144 	negation = ((*d)[3] & LDNS_APL_NEGATION);
1145 	adflength = ((*d)[3] & LDNS_APL_MASK);
1146 	if(*dl < 4+(size_t)adflength) return -1;
1147 	if(family != LDNS_APL_IP4 && family != LDNS_APL_IP6)
1148 		return -1; /* unknown address family */
1149 	if(negation)
1150 		w += sldns_str_print(s, sl, "!");
1151 	w += sldns_str_print(s, sl, "%u:", (unsigned)family);
1152 	if(family == LDNS_APL_IP4) {
1153 		/* check if prefix <32 ? */
1154 		/* address is variable length 0 - 4 */
1155 		for(i=0; i<4; i++) {
1156 			if(i > 0)
1157 				w += sldns_str_print(s, sl, ".");
1158 			if(i < (int)adflength)
1159 				w += sldns_str_print(s, sl, "%d", (*d)[4+i]);
1160 			else	w += sldns_str_print(s, sl, "0");
1161 		}
1162 	} else if(family == LDNS_APL_IP6) {
1163 		/* check if prefix <128 ? */
1164 		/* address is variable length 0 - 16 */
1165 		for(i=0; i<16; i++) {
1166 			if(i%2 == 0 && i>0)
1167 				w += sldns_str_print(s, sl, ":");
1168 			if(i < (int)adflength)
1169 				w += sldns_str_print(s, sl, "%02x", (*d)[4+i]);
1170 			else	w += sldns_str_print(s, sl, "00");
1171 		}
1172 	}
1173 	w += sldns_str_print(s, sl, "/%u", (unsigned)prefix);
1174 	(*d) += 4+adflength;
1175 	(*dl) -= 4+adflength;
1176 	return w;
1177 }
1178 
1179 int sldns_wire2str_b32_ext_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1180 {
1181 	size_t datalen;
1182 	size_t sz;
1183 	if(*dl < 1) return -1;
1184 	datalen = (*d)[0];
1185 	if(*dl < 1+datalen) return -1;
1186 	sz = sldns_b32_ntop_calculate_size(datalen);
1187 	if(*sl < sz+1) {
1188 		(*d) += datalen+1;
1189 		(*dl) -= (datalen+1);
1190 		return (int)sz; /* out of space really, but would need buffer
1191 			in order to truncate the output */
1192 	}
1193 	sldns_b32_ntop_extended_hex((*d)+1, datalen, *s, *sl);
1194 	(*d) += datalen+1;
1195 	(*dl) -= (datalen+1);
1196 	(*s) += sz;
1197 	(*sl) -= sz;
1198 	return (int)sz;
1199 }
1200 
1201 /** scan number of bytes from wire into b64 presentation format */
1202 static int sldns_wire2str_b64_scan_num(uint8_t** d, size_t* dl, char** s,
1203 	size_t* sl, size_t num)
1204 {
1205 	/* b64_ntop_calculate size includes null at the end */
1206 	size_t sz = sldns_b64_ntop_calculate_size(num)-1;
1207 	if(*sl < sz+1) {
1208 		(*d) += num;
1209 		(*dl) -= num;
1210 		return (int)sz; /* out of space really, but would need buffer
1211 			in order to truncate the output */
1212 	}
1213 	sldns_b64_ntop(*d, num, *s, *sl);
1214 	(*d) += num;
1215 	(*dl) -= num;
1216 	(*s) += sz;
1217 	(*sl) -= sz;
1218 	return (int)sz;
1219 }
1220 
1221 int sldns_wire2str_b64_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1222 {
1223 	if(*dl == 0) {
1224 		return sldns_str_print(s, sl, "0");
1225 	}
1226 	return sldns_wire2str_b64_scan_num(d, dl, s, sl, *dl);
1227 }
1228 
1229 int sldns_wire2str_hex_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1230 {
1231 	if(*dl == 0) {
1232 		return sldns_str_print(s, sl, "0");
1233 	}
1234 	return print_remainder_hex("", d, dl, s, sl);
1235 }
1236 
1237 int sldns_wire2str_nsec_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1238 {
1239 	uint8_t* p = *d;
1240 	size_t pl = *dl;
1241 	unsigned i, bit, window, block_len;
1242 	uint16_t t;
1243 	int w = 0;
1244 
1245 	/* check for errors */
1246 	while(pl) {
1247 		if(pl < 2) return -1;
1248 		block_len = (unsigned)p[1];
1249 		if(pl < 2+block_len) return -1;
1250 		p += block_len+2;
1251 		pl -= block_len+2;
1252 	}
1253 
1254 	/* do it */
1255 	p = *d;
1256 	pl = *dl;
1257 	while(pl) {
1258 		if(pl < 2) return -1; /* cannot happen */
1259 		window = (unsigned)p[0];
1260 		block_len = (unsigned)p[1];
1261 		if(pl < 2+block_len) return -1; /* cannot happen */
1262 		p += 2;
1263 		for(i=0; i<block_len; i++) {
1264 			if(p[i] == 0) continue;
1265 			/* base type number for this octet */
1266 			t = ((window)<<8) | (i << 3);
1267 			for(bit=0; bit<8; bit++) {
1268 				if((p[i]&(0x80>>bit))) {
1269 					if(w) w += sldns_str_print(s, sl, " ");
1270 					w += sldns_wire2str_type_print(s, sl,
1271 						t+bit);
1272 				}
1273 			}
1274 		}
1275 		p += block_len;
1276 		pl -= block_len+2;
1277 	}
1278 	(*d) += *dl;
1279 	(*dl) = 0;
1280 	return w;
1281 }
1282 
1283 int sldns_wire2str_nsec3_salt_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1284 {
1285 	size_t salt_len;
1286 	int w;
1287 	if(*dl < 1) return -1;
1288 	salt_len = (size_t)(*d)[0];
1289 	if(*dl < 1+salt_len) return -1;
1290 	(*d)++;
1291 	(*dl)--;
1292 	if(salt_len == 0) {
1293 		return sldns_str_print(s, sl, "-");
1294 	}
1295 	w = print_hex_buf(s, sl, *d, salt_len);
1296 	(*dl)-=salt_len;
1297 	(*d)+=salt_len;
1298 	return w;
1299 }
1300 
1301 int sldns_wire2str_cert_alg_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1302 {
1303 	sldns_lookup_table *lt;
1304 	int data, w;
1305 	if(*dl < 2) return -1;
1306 	data = (int)sldns_read_uint16(*d);
1307 	lt = sldns_lookup_by_id(sldns_cert_algorithms, data);
1308 	if(lt && lt->name)
1309 		w = sldns_str_print(s, sl, "%s", lt->name);
1310 	else 	w = sldns_str_print(s, sl, "%d", data);
1311 	(*dl)-=2;
1312 	(*d)+=2;
1313 	return w;
1314 }
1315 
1316 int sldns_wire2str_alg_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1317 {
1318 	/* don't use algorithm mnemonics in the presentation format
1319 	 * this kind of got sneaked into the rfc's */
1320 	return sldns_wire2str_int8_scan(d, dl, s, sl);
1321 }
1322 
1323 int sldns_wire2str_unknown_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1324 {
1325 	return sldns_wire2str_rdata_unknown_scan(d, dl, s, sl);
1326 }
1327 
1328 int sldns_wire2str_time_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1329 {
1330 	/* create a YYYYMMDDHHMMSS string if possible */
1331 	struct tm tm;
1332 	char date_buf[16];
1333 	uint32_t t;
1334 	memset(&tm, 0, sizeof(tm));
1335 	if(*dl < 4) return -1;
1336 	t = sldns_read_uint32(*d);
1337 	date_buf[15]=0;
1338 	if(sldns_serial_arithmitics_gmtime_r(t, time(NULL), &tm) &&
1339 		strftime(date_buf, 15, "%Y%m%d%H%M%S", &tm)) {
1340 		(*d) += 4;
1341 		(*dl) -= 4;
1342 		return sldns_str_print(s, sl, "%s", date_buf);
1343 	}
1344 	return -1;
1345 }
1346 
1347 static int
1348 loc_cm_print(char** str, size_t* sl, uint8_t mantissa, uint8_t exponent)
1349 {
1350 	int w = 0;
1351 	uint8_t i;
1352 	/* is it 0.<two digits> ? */
1353 	if(exponent < 2) {
1354 		if(exponent == 1)
1355 			mantissa *= 10;
1356 		return sldns_str_print(str, sl, "0.%02ld", (long)mantissa);
1357 	}
1358 	/* always <digit><string of zeros> */
1359 	w += sldns_str_print(str, sl, "%d", (int)mantissa);
1360 	for(i=0; i<exponent-2; i++)
1361 		w += sldns_str_print(str, sl, "0");
1362 	return w;
1363 }
1364 
1365 int sldns_wire2str_loc_scan(uint8_t** d, size_t* dl, char** str, size_t* sl)
1366 {
1367 	/* we could do checking (ie degrees < 90 etc)? */
1368 	uint8_t version;
1369 	uint8_t size;
1370 	uint8_t horizontal_precision;
1371 	uint8_t vertical_precision;
1372 	uint32_t longitude;
1373 	uint32_t latitude;
1374 	uint32_t altitude;
1375 	char northerness;
1376 	char easterness;
1377 	uint32_t h;
1378 	uint32_t m;
1379 	double s;
1380 	uint32_t equator = (uint32_t)1 << 31; /* 2**31 */
1381 	int w = 0;
1382 
1383 	if(*dl < 16) return -1;
1384 	version = (*d)[0];
1385 	if(version != 0)
1386 		return sldns_wire2str_hex_scan(d, dl, str, sl);
1387 	size = (*d)[1];
1388 	horizontal_precision = (*d)[2];
1389 	vertical_precision = (*d)[3];
1390 
1391 	latitude = sldns_read_uint32((*d)+4);
1392 	longitude = sldns_read_uint32((*d)+8);
1393 	altitude = sldns_read_uint32((*d)+12);
1394 
1395 	if (latitude > equator) {
1396 		northerness = 'N';
1397 		latitude = latitude - equator;
1398 	} else {
1399 		northerness = 'S';
1400 		latitude = equator - latitude;
1401 	}
1402 	h = latitude / (1000 * 60 * 60);
1403 	latitude = latitude % (1000 * 60 * 60);
1404 	m = latitude / (1000 * 60);
1405 	latitude = latitude % (1000 * 60);
1406 	s = (double) latitude / 1000.0;
1407 	w += sldns_str_print(str, sl, "%02u %02u %06.3f %c ",
1408 		h, m, s, northerness);
1409 
1410 	if (longitude > equator) {
1411 		easterness = 'E';
1412 		longitude = longitude - equator;
1413 	} else {
1414 		easterness = 'W';
1415 		longitude = equator - longitude;
1416 	}
1417 	h = longitude / (1000 * 60 * 60);
1418 	longitude = longitude % (1000 * 60 * 60);
1419 	m = longitude / (1000 * 60);
1420 	longitude = longitude % (1000 * 60);
1421 	s = (double) longitude / (1000.0);
1422 	w += sldns_str_print(str, sl, "%02u %02u %06.3f %c ",
1423 		h, m, s, easterness);
1424 
1425 	s = ((double) altitude) / 100;
1426 	s -= 100000;
1427 
1428 	if(altitude%100 != 0)
1429 		w += sldns_str_print(str, sl, "%.2f", s);
1430 	else
1431 		w += sldns_str_print(str, sl, "%.0f", s);
1432 
1433 	w += sldns_str_print(str, sl, "m ");
1434 
1435 	w += loc_cm_print(str, sl, (size & 0xf0) >> 4, size & 0x0f);
1436 	w += sldns_str_print(str, sl, "m ");
1437 
1438 	w += loc_cm_print(str, sl, (horizontal_precision & 0xf0) >> 4,
1439 		horizontal_precision & 0x0f);
1440 	w += sldns_str_print(str, sl, "m ");
1441 
1442 	w += loc_cm_print(str, sl, (vertical_precision & 0xf0) >> 4,
1443 		vertical_precision & 0x0f);
1444 	w += sldns_str_print(str, sl, "m");
1445 
1446 	(*d)+=16;
1447 	(*dl)-=16;
1448 	return w;
1449 }
1450 
1451 int sldns_wire2str_wks_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1452 {
1453 	/* protocol, followed by bitmap of services */
1454 	const char* proto_name = NULL;
1455 	struct protoent *protocol;
1456 	struct servent *service;
1457 	uint8_t protocol_nr;
1458 	int bit, port, w = 0;
1459 	size_t i;
1460 	/* we cannot print with strings because they
1461 	 * are not portable, the presentation format may
1462 	 * not be able to be read in on another computer.  */
1463 	int print_symbols = 0;
1464 
1465 	/* protocol */
1466 	if(*dl < 1) return -1;
1467 	protocol_nr = (*d)[0];
1468 	(*d)++;
1469 	(*dl)--;
1470 	protocol = getprotobynumber((int)protocol_nr);
1471 	if(protocol && (protocol->p_name != NULL)) {
1472 		w += sldns_str_print(s, sl, "%s", protocol->p_name);
1473 		proto_name = protocol->p_name;
1474 	} else if(protocol_nr == 6) {
1475 		w += sldns_str_print(s, sl, "tcp");
1476 	} else if(protocol_nr == 17) {
1477 		w += sldns_str_print(s, sl, "udp");
1478 	} else	{
1479 		w += sldns_str_print(s, sl, "%u", (unsigned)protocol_nr);
1480 	}
1481 
1482 	for(i=0; i<*dl; i++) {
1483 		if((*d)[i] == 0)
1484 			continue;
1485 		for(bit=0; bit<8; bit++) {
1486 			if(!(((*d)[i])&(0x80>>bit)))
1487 				continue;
1488 			port = (int)i*8 + bit;
1489 
1490 			if(!print_symbols)
1491 				service = NULL;
1492 			else
1493 				service = getservbyport(
1494 					(int)htons((uint16_t)port), proto_name);
1495 			if(service && service->s_name)
1496 				w += sldns_str_print(s, sl, " %s",
1497 					service->s_name);
1498 			else 	w += sldns_str_print(s, sl, " %u",
1499 					(unsigned)port);
1500 		}
1501 	}
1502 
1503 #ifdef HAVE_ENDSERVENT
1504 	endservent();
1505 #endif
1506 #ifdef HAVE_ENDPROTOENT
1507         endprotoent();
1508 #endif
1509 	(*d) += *dl;
1510 	(*dl) = 0;
1511 	return w;
1512 }
1513 
1514 int sldns_wire2str_nsap_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1515 {
1516 	return print_remainder_hex("0x", d, dl, s, sl);
1517 }
1518 
1519 int sldns_wire2str_atma_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1520 {
1521 	return print_remainder_hex("", d, dl, s, sl);
1522 }
1523 
1524 /* internal scan routine that can modify arguments on failure */
1525 static int sldns_wire2str_ipseckey_scan_internal(uint8_t** d, size_t* dl,
1526 	char** s, size_t* sl, uint8_t* pkt, size_t pktlen)
1527 {
1528 	/* http://www.ietf.org/internet-drafts/draft-ietf-ipseckey-rr-12.txt*/
1529 	uint8_t precedence, gateway_type, algorithm;
1530 	int w = 0;
1531 
1532 	if(*dl < 3) return -1;
1533 	precedence = (*d)[0];
1534 	gateway_type = (*d)[1];
1535 	algorithm = (*d)[2];
1536 	if(gateway_type > 3)
1537 		return -1; /* unknown */
1538 	(*d)+=3;
1539 	(*dl)-=3;
1540 	w += sldns_str_print(s, sl, "%d %d %d ",
1541 		(int)precedence, (int)gateway_type, (int)algorithm);
1542 
1543 	switch(gateway_type) {
1544 	case 0: /* no gateway */
1545 		w += sldns_str_print(s, sl, ".");
1546 		break;
1547 	case 1: /* ip4 */
1548 		w += sldns_wire2str_a_scan(d, dl, s, sl);
1549 		break;
1550 	case 2: /* ip6 */
1551 		w += sldns_wire2str_aaaa_scan(d, dl, s, sl);
1552 		break;
1553 	case 3: /* dname */
1554 		w += sldns_wire2str_dname_scan(d, dl, s, sl, pkt, pktlen);
1555 		break;
1556 	default: /* unknown */
1557 		return -1;
1558 	}
1559 
1560 	if(*dl < 1)
1561 		return -1;
1562 	w += sldns_str_print(s, sl, " ");
1563 	w += sldns_wire2str_b64_scan_num(d, dl, s, sl, *dl);
1564 	return w;
1565 }
1566 
1567 int sldns_wire2str_ipseckey_scan(uint8_t** d, size_t* dl, char** s, size_t* sl,
1568 	uint8_t* pkt, size_t pktlen)
1569 {
1570 	uint8_t* od = *d;
1571 	char* os = *s;
1572 	size_t odl = *dl, osl = *sl;
1573 	int w=sldns_wire2str_ipseckey_scan_internal(d, dl, s, sl, pkt, pktlen);
1574 	if(w == -1) {
1575 		*d = od;
1576 		*s = os;
1577 		*dl = odl;
1578 		*sl = osl;
1579 		return -1;
1580 	}
1581 	return w;
1582 }
1583 
1584 int sldns_wire2str_hip_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1585 {
1586 	int w;
1587 	uint8_t algo, hitlen;
1588 	uint16_t pklen;
1589 
1590 	/* read lengths */
1591 	if(*dl < 4)
1592 		return -1;
1593 	hitlen = (*d)[0];
1594 	algo = (*d)[1];
1595 	pklen = sldns_read_uint16((*d)+2);
1596 	if(*dl < (size_t)4 + (size_t)hitlen + (size_t)pklen)
1597 		return -1;
1598 
1599 	/* write: algo hit pubkey */
1600 	w = sldns_str_print(s, sl, "%u ", (unsigned)algo);
1601 	w += print_hex_buf(s, sl, (*d)+4, hitlen);
1602 	w += sldns_str_print(s, sl, " ");
1603 	(*d)+=4+hitlen;
1604 	(*dl)-= (4+hitlen);
1605 	w += sldns_wire2str_b64_scan_num(d, dl, s, sl, pklen);
1606 	return w;
1607 }
1608 
1609 int sldns_wire2str_int16_data_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1610 {
1611 	int w;
1612 	uint16_t n;
1613 	if(*dl < 2)
1614 		return -1;
1615 	n = sldns_read_uint16(*d);
1616 	if(*dl < 2+(size_t)n)
1617 		return -1;
1618 	(*d)+=2;
1619 	(*dl)-=2;
1620 	if(n == 0) {
1621 		return sldns_str_print(s, sl, "0");
1622 	}
1623 	w = sldns_str_print(s, sl, "%u ", (unsigned)n);
1624 	w += sldns_wire2str_b64_scan_num(d, dl, s, sl, n);
1625 	return w;
1626 }
1627 
1628 int sldns_wire2str_nsec3_next_owner_scan(uint8_t** d, size_t* dl, char** s,
1629 	size_t* sl)
1630 {
1631 	return sldns_wire2str_b32_ext_scan(d, dl, s, sl);
1632 }
1633 
1634 int sldns_wire2str_ilnp64_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1635 {
1636 	int w;
1637 	if(*dl < 8)
1638 		return -1;
1639 	w = sldns_str_print(s, sl, "%.4x:%.4x:%.4x:%.4x",
1640 		sldns_read_uint16(*d), sldns_read_uint16((*d)+2),
1641 		sldns_read_uint16((*d)+4), sldns_read_uint16((*d)+6));
1642 	(*d)+=8;
1643 	(*dl)-=8;
1644 	return w;
1645 }
1646 
1647 int sldns_wire2str_eui48_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1648 {
1649 	int w;
1650 	if(*dl < 6)
1651 		return -1;
1652 	w = sldns_str_print(s, sl, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
1653 		(*d)[0], (*d)[1], (*d)[2], (*d)[3], (*d)[4], (*d)[5]);
1654 	(*d)+=6;
1655 	(*dl)-=6;
1656 	return w;
1657 }
1658 
1659 int sldns_wire2str_eui64_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1660 {
1661 	int w;
1662 	if(*dl < 8)
1663 		return -1;
1664 	w = sldns_str_print(s, sl, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
1665 		(*d)[0], (*d)[1], (*d)[2], (*d)[3], (*d)[4], (*d)[5],
1666 		(*d)[6], (*d)[7]);
1667 	(*d)+=8;
1668 	(*dl)-=8;
1669 	return w;
1670 }
1671 
1672 int sldns_wire2str_tag_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1673 {
1674 	size_t i, n;
1675 	int w = 0;
1676 	if(*dl < 1)
1677 		return -1;
1678 	n = (size_t)((*d)[0]);
1679 	if(*dl < 1+n)
1680 		return -1;
1681 	for(i=0; i<n; i++)
1682 		if(!isalnum((unsigned char)(*d)[i+1]))
1683 			return -1;
1684 	for(i=0; i<n; i++)
1685 		w += sldns_str_print(s, sl, "%c", (char)(*d)[i+1]);
1686 	(*d)+=n+1;
1687 	(*dl)-=(n+1);
1688 	return w;
1689 }
1690 
1691 int sldns_wire2str_long_str_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1692 {
1693 	size_t i;
1694 	int w = 0;
1695 	w += sldns_str_print(s, sl, "\"");
1696 	for(i=0; i<*dl; i++)
1697 		w += str_char_print(s, sl, (*d)[i]);
1698 	w += sldns_str_print(s, sl, "\"");
1699 	(*d)+=*dl;
1700 	(*dl)=0;
1701 	return w;
1702 }
1703 
1704 int sldns_wire2str_tsigerror_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1705 {
1706 	sldns_lookup_table *lt;
1707 	int data, w;
1708 	if(*dl < 2) return -1;
1709 	data = (int)sldns_read_uint16(*d);
1710 	lt = sldns_lookup_by_id(sldns_tsig_errors, data);
1711 	if(lt && lt->name)
1712 		w = sldns_str_print(s, sl, "%s", lt->name);
1713 	else 	w = sldns_str_print(s, sl, "%d", data);
1714 	(*dl)-=2;
1715 	(*d)+=2;
1716 	return w;
1717 }
1718 
1719 int sldns_wire2str_edns_llq_print(char** s, size_t* sl, uint8_t* data,
1720 	size_t len)
1721 {
1722 	/* LLQ constants */
1723 	const char* llq_errors[] = {"NO-ERROR", "SERV-FULL", "STATIC",
1724 		"FORMAT-ERR", "NO-SUCH-LLQ", "BAD-VERS", "UNKNOWN_ERR"};
1725 	const unsigned int llq_errors_num = 7;
1726 	const char* llq_opcodes[] = {"LLQ-SETUP", "LLQ-REFRESH", "LLQ-EVENT"};
1727 	const unsigned int llq_opcodes_num = 3;
1728 	uint16_t version, llq_opcode, error_code;
1729 	uint64_t llq_id;
1730 	uint32_t lease_life; /* Requested or granted life of LLQ, in seconds */
1731 	int w = 0;
1732 
1733 	/* read the record */
1734 	if(len != 18) {
1735 		w += sldns_str_print(s, sl, "malformed LLQ ");
1736 		w += print_hex_buf(s, sl, data, len);
1737 		return w;
1738 	}
1739 	version = sldns_read_uint16(data);
1740 	llq_opcode = sldns_read_uint16(data+2);
1741 	error_code = sldns_read_uint16(data+4);
1742 	memmove(&llq_id, data+6, sizeof(llq_id));
1743 	lease_life = sldns_read_uint32(data+14);
1744 
1745 	/* print it */
1746 	w += sldns_str_print(s, sl, "v%d ", (int)version);
1747 	if(llq_opcode < llq_opcodes_num)
1748 		w += sldns_str_print(s, sl, "%s", llq_opcodes[llq_opcode]);
1749 	else	w += sldns_str_print(s, sl, "opcode %d", (int)llq_opcode);
1750 	if(error_code < llq_errors_num)
1751 		w += sldns_str_print(s, sl, " %s", llq_errors[error_code]);
1752 	else	w += sldns_str_print(s, sl, " error %d", (int)error_code);
1753 #ifndef USE_WINSOCK
1754 	w += sldns_str_print(s, sl, " id %llx lease-life %lu",
1755 		(unsigned long long)llq_id, (unsigned long)lease_life);
1756 #else
1757 	w += sldns_str_print(s, sl, " id %I64x lease-life %lu",
1758 		(unsigned long long)llq_id, (unsigned long)lease_life);
1759 #endif
1760 	return w;
1761 }
1762 
1763 int sldns_wire2str_edns_ul_print(char** s, size_t* sl, uint8_t* data,
1764 	size_t len)
1765 {
1766 	uint32_t lease;
1767 	int w = 0;
1768 	if(len != 4) {
1769 		w += sldns_str_print(s, sl, "malformed UL ");
1770 		w += print_hex_buf(s, sl, data, len);
1771 		return w;
1772 	}
1773 	lease = sldns_read_uint32(data);
1774 	w += sldns_str_print(s, sl, "lease %lu", (unsigned long)lease);
1775 	return w;
1776 }
1777 
1778 int sldns_wire2str_edns_nsid_print(char** s, size_t* sl, uint8_t* data,
1779 	size_t len)
1780 {
1781 	int w = 0;
1782 	size_t i, printed=0;
1783 	w += print_hex_buf(s, sl, data, len);
1784 	for(i=0; i<len; i++) {
1785 		if(isprint((unsigned char)data[i]) || data[i] == '\t') {
1786 			if(!printed) {
1787 				w += sldns_str_print(s, sl, " (");
1788 				printed = 1;
1789 			}
1790 			w += sldns_str_print(s, sl, "%c", (char)data[i]);
1791 		}
1792 	}
1793 	if(printed)
1794 		w += sldns_str_print(s, sl, ")");
1795 	return w;
1796 }
1797 
1798 int sldns_wire2str_edns_dau_print(char** s, size_t* sl, uint8_t* data,
1799 	size_t len)
1800 {
1801 	sldns_lookup_table *lt;
1802 	size_t i;
1803 	int w = 0;
1804 	for(i=0; i<len; i++) {
1805 		lt = sldns_lookup_by_id(sldns_algorithms, (int)data[i]);
1806 		if(lt && lt->name)
1807 			w += sldns_str_print(s, sl, " %s", lt->name);
1808 		else 	w += sldns_str_print(s, sl, " %d", (int)data[i]);
1809 	}
1810 	return w;
1811 }
1812 
1813 int sldns_wire2str_edns_dhu_print(char** s, size_t* sl, uint8_t* data,
1814 	size_t len)
1815 {
1816 	sldns_lookup_table *lt;
1817 	size_t i;
1818 	int w = 0;
1819 	for(i=0; i<len; i++) {
1820 		lt = sldns_lookup_by_id(sldns_hashes, (int)data[i]);
1821 		if(lt && lt->name)
1822 			w += sldns_str_print(s, sl, " %s", lt->name);
1823 		else 	w += sldns_str_print(s, sl, " %d", (int)data[i]);
1824 	}
1825 	return w;
1826 }
1827 
1828 int sldns_wire2str_edns_n3u_print(char** s, size_t* sl, uint8_t* data,
1829 	size_t len)
1830 {
1831 	size_t i;
1832 	int w = 0;
1833 	for(i=0; i<len; i++) {
1834 		if(data[i] == 1)
1835 			w += sldns_str_print(s, sl, " SHA1");
1836 		else 	w += sldns_str_print(s, sl, " %d", (int)data[i]);
1837 	}
1838 	return w;
1839 }
1840 
1841 int sldns_wire2str_edns_subnet_print(char** s, size_t* sl, uint8_t* data,
1842 	size_t len)
1843 {
1844 	int w = 0;
1845 	uint16_t family;
1846 	uint8_t source, scope;
1847 	if(len < 4) {
1848 		w += sldns_str_print(s, sl, "malformed subnet ");
1849 		w += print_hex_buf(s, sl, data, len);
1850 		return w;
1851 	}
1852 	family = sldns_read_uint16(data);
1853 	source = data[2];
1854 	scope = data[3];
1855 	if(family == 1) {
1856 		/* IP4 */
1857 		char buf[64];
1858 		uint8_t ip4[4];
1859 		memset(ip4, 0, sizeof(ip4));
1860 		if(len-4 > 4) {
1861 			w += sldns_str_print(s, sl, "trailingdata:");
1862 			w += print_hex_buf(s, sl, data+4+4, len-4-4);
1863 			w += sldns_str_print(s, sl, " ");
1864 			len = 4+4;
1865 		}
1866 		memmove(ip4, data+4, len-4);
1867 		if(!inet_ntop(AF_INET, ip4, buf, (socklen_t)sizeof(buf))) {
1868 			w += sldns_str_print(s, sl, "ip4ntoperror ");
1869 			w += print_hex_buf(s, sl, data+4+4, len-4-4);
1870 		} else {
1871 			w += sldns_str_print(s, sl, "%s", buf);
1872 		}
1873 	} else if(family == 2) {
1874 		/* IP6 */
1875 		char buf[64];
1876 		uint8_t ip6[16];
1877 		memset(ip6, 0, sizeof(ip6));
1878 		if(len-4 > 16) {
1879 			w += sldns_str_print(s, sl, "trailingdata:");
1880 			w += print_hex_buf(s, sl, data+4+16, len-4-16);
1881 			w += sldns_str_print(s, sl, " ");
1882 			len = 4+16;
1883 		}
1884 		memmove(ip6, data+4, len-4);
1885 #ifdef AF_INET6
1886 		if(!inet_ntop(AF_INET6, ip6, buf, (socklen_t)sizeof(buf))) {
1887 			w += sldns_str_print(s, sl, "ip6ntoperror ");
1888 			w += print_hex_buf(s, sl, data+4+4, len-4-4);
1889 		} else {
1890 			w += sldns_str_print(s, sl, "%s", buf);
1891 		}
1892 #else
1893 		w += print_hex_buf(s, sl, data+4+4, len-4-4);
1894 #endif
1895 	} else {
1896 		/* unknown */
1897 		w += sldns_str_print(s, sl, "family %d ",
1898 			(int)family);
1899 		w += print_hex_buf(s, sl, data, len);
1900 	}
1901 	w += sldns_str_print(s, sl, "/%d scope /%d", (int)source, (int)scope);
1902 	return w;
1903 }
1904 
1905 int sldns_wire2str_edns_keepalive_print(char** s, size_t* sl, uint8_t* data,
1906 	size_t len)
1907 {
1908 	int w = 0;
1909 	uint16_t timeout;
1910 	if(!(len == 0 || len == 2)) {
1911 		w += sldns_str_print(s, sl, "malformed keepalive ");
1912 		w += print_hex_buf(s, sl, data, len);
1913 		return w;
1914 	}
1915 	if(len == 0 ) {
1916 		w += sldns_str_print(s, sl, "no timeout value (only valid for client option) ");
1917 	} else {
1918 		timeout = sldns_read_uint16(data);
1919 		w += sldns_str_print(s, sl, "timeout value in units of 100ms %u", (int)timeout);
1920 	}
1921 	return w;
1922 }
1923 
1924 int sldns_wire2str_edns_option_print(char** s, size_t* sl,
1925 	uint16_t option_code, uint8_t* optdata, size_t optlen)
1926 {
1927 	int w = 0;
1928 	w += sldns_wire2str_edns_option_code_print(s, sl, option_code);
1929 	w += sldns_str_print(s, sl, ": ");
1930 	switch(option_code) {
1931 	case LDNS_EDNS_LLQ:
1932 		w += sldns_wire2str_edns_llq_print(s, sl, optdata, optlen);
1933 		break;
1934 	case LDNS_EDNS_UL:
1935 		w += sldns_wire2str_edns_ul_print(s, sl, optdata, optlen);
1936 		break;
1937 	case LDNS_EDNS_NSID:
1938 		w += sldns_wire2str_edns_nsid_print(s, sl, optdata, optlen);
1939 		break;
1940 	case LDNS_EDNS_DAU:
1941 		w += sldns_wire2str_edns_dau_print(s, sl, optdata, optlen);
1942 		break;
1943 	case LDNS_EDNS_DHU:
1944 		w += sldns_wire2str_edns_dhu_print(s, sl, optdata, optlen);
1945 		break;
1946 	case LDNS_EDNS_N3U:
1947 		w += sldns_wire2str_edns_n3u_print(s, sl, optdata, optlen);
1948 		break;
1949 	case LDNS_EDNS_CLIENT_SUBNET:
1950 		w += sldns_wire2str_edns_subnet_print(s, sl, optdata, optlen);
1951 		break;
1952 	 case LDNS_EDNS_KEEPALIVE:
1953 		w += sldns_wire2str_edns_keepalive_print(s, sl, optdata, optlen);
1954 		break;
1955 	case LDNS_EDNS_PADDING:
1956 		w += print_hex_buf(s, sl, optdata, optlen);
1957 		break;
1958 	default:
1959 		/* unknown option code */
1960 		w += print_hex_buf(s, sl, optdata, optlen);
1961 		break;
1962 	}
1963 	return w;
1964 }
1965 
1966 /** print the edns options to string */
1967 static int
1968 print_edns_opts(char** s, size_t* sl, uint8_t* rdata, size_t rdatalen)
1969 {
1970 	uint16_t option_code, option_len;
1971 	int w = 0;
1972 	while(rdatalen > 0) {
1973 		/* option name */
1974 		if(rdatalen < 4) {
1975 			w += sldns_str_print(s, sl, " ; malformed: ");
1976 			w += print_hex_buf(s, sl, rdata, rdatalen);
1977 			return w;
1978 		}
1979 		option_code = sldns_read_uint16(rdata);
1980 		option_len = sldns_read_uint16(rdata+2);
1981 		rdata += 4;
1982 		rdatalen -= 4;
1983 
1984 		/* option value */
1985 		if(rdatalen < (size_t)option_len) {
1986 			w += sldns_str_print(s, sl, " ; malformed ");
1987 			w += sldns_wire2str_edns_option_code_print(s, sl,
1988 				option_code);
1989 			w += sldns_str_print(s, sl, ": ");
1990 			w += print_hex_buf(s, sl, rdata, rdatalen);
1991 			return w;
1992 		}
1993 		w += sldns_str_print(s, sl, " ; ");
1994 		w += sldns_wire2str_edns_option_print(s, sl, option_code,
1995 			rdata, option_len);
1996 		rdata += option_len;
1997 		rdatalen -= option_len;
1998 	}
1999 	return w;
2000 }
2001 
2002 int sldns_wire2str_edns_scan(uint8_t** data, size_t* data_len, char** str,
2003         size_t* str_len, uint8_t* pkt, size_t pktlen)
2004 {
2005 	int w = 0;
2006 	uint8_t ext_rcode, edns_version;
2007 	uint16_t udpsize, edns_bits, rdatalen;
2008 	w += sldns_str_print(str, str_len, "; EDNS:");
2009 
2010 	/* some input checks, domain name */
2011 	if(*data_len < 1+10)
2012 		return w + print_remainder_hex("Error malformed 0x",
2013 			data, data_len, str, str_len);
2014 	if(*data[0] != 0) {
2015 		return w + print_remainder_hex("Error nonrootdname 0x",
2016 			data, data_len, str, str_len);
2017 	}
2018 	(*data)++;
2019 	(*data_len)--;
2020 
2021 	/* check type and read fixed contents */
2022 	if(sldns_read_uint16((*data)) != LDNS_RR_TYPE_OPT) {
2023 		return w + print_remainder_hex("Error nottypeOPT 0x",
2024 			data, data_len, str, str_len);
2025 	}
2026 	udpsize = sldns_read_uint16((*data)+2);
2027 	ext_rcode = (*data)[4];
2028 	edns_version = (*data)[5];
2029 	edns_bits = sldns_read_uint16((*data)+6);
2030 	rdatalen = sldns_read_uint16((*data)+8);
2031 	(*data)+=10;
2032 	(*data_len)-=10;
2033 
2034 	w += sldns_str_print(str, str_len, " version: %u;",
2035 		(unsigned)edns_version);
2036 	w += sldns_str_print(str, str_len, " flags:");
2037 	if((edns_bits & LDNS_EDNS_MASK_DO_BIT))
2038 		w += sldns_str_print(str, str_len, " do");
2039 	/* the extended rcode is the value set, shifted four bits,
2040 	 * and or'd with the original rcode */
2041 	if(ext_rcode) {
2042 		int rc = ((int)ext_rcode)<<4;
2043 		if(pkt && pktlen >= LDNS_HEADER_SIZE)
2044 			rc |= LDNS_RCODE_WIRE(pkt);
2045 		w += sldns_str_print(str, str_len, " ; ext-rcode: %d", rc);
2046 	}
2047 	w += sldns_str_print(str, str_len, " ; udp: %u", (unsigned)udpsize);
2048 
2049 	if(rdatalen) {
2050 		if((size_t)*data_len < rdatalen) {
2051 			w += sldns_str_print(str, str_len,
2052 				" ; Error EDNS rdata too short; ");
2053 			rdatalen = (uint16_t)*data_len;
2054 		}
2055 		w += print_edns_opts(str, str_len, *data, rdatalen);
2056 		(*data) += rdatalen;
2057 		(*data_len) -= rdatalen;
2058 	}
2059 	w += sldns_str_print(str, str_len, "\n");
2060 	return w;
2061 }
2062