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