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