wire2str.c revision 302408
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	if(*dlen != 0) {
701		goto failed;
702	}
703	return w;
704}
705
706int sldns_wire2str_rdata_unknown_scan(uint8_t** d, size_t* dlen, char** s,
707	size_t* slen)
708{
709	int w = 0;
710
711	/* print length */
712	w += sldns_str_print(s, slen, "\\# %u", (unsigned)*dlen);
713
714	/* print rdlen in hex */
715	if(*dlen != 0)
716		w += sldns_str_print(s, slen, " ");
717	w += print_hex_buf(s, slen, *d, *dlen);
718	(*d) += *dlen;
719	(*dlen) = 0;
720	return w;
721}
722
723/** print and escape one character for a domain dname */
724static int dname_char_print(char** s, size_t* slen, uint8_t c)
725{
726	if(c == '.' || c == ';' || c == '(' || c == ')' || c == '\\')
727		return sldns_str_print(s, slen, "\\%c", c);
728	else if(!(isascii((unsigned char)c) && isgraph((unsigned char)c)))
729		return sldns_str_print(s, slen, "\\%03u", (unsigned)c);
730	/* plain printout */
731	if(*slen) {
732		**s = (char)c;
733		(*s)++;
734		(*slen)--;
735	}
736	return 1;
737}
738
739int sldns_wire2str_dname_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
740	uint8_t* pkt, size_t pktlen)
741{
742	int w = 0;
743	/* spool labels onto the string, use compression if its there */
744	uint8_t* pos = *d;
745	unsigned i, counter=0;
746	const unsigned maxcompr = 1000; /* loop detection, max compr ptrs */
747	int in_buf = 1;
748	if(*dlen == 0) return sldns_str_print(s, slen, "ErrorMissingDname");
749	if(*pos == 0) {
750		(*d)++;
751		(*dlen)--;
752		return sldns_str_print(s, slen, ".");
753	}
754	while(*pos) {
755		/* read label length */
756		uint8_t labellen = *pos++;
757		if(in_buf) { (*d)++; (*dlen)--; }
758
759		/* find out what sort of label we have */
760		if((labellen&0xc0) == 0xc0) {
761			/* compressed */
762			uint16_t target = 0;
763			if(in_buf && *dlen == 0)
764				return w + sldns_str_print(s, slen,
765					"ErrorPartialDname");
766			else if(!in_buf && pos+1 > pkt+pktlen)
767				return w + sldns_str_print(s, slen,
768					"ErrorPartialDname");
769			target = ((labellen&0x3f)<<8) | *pos;
770			if(in_buf) { (*d)++; (*dlen)--; }
771			/* move to target, if possible */
772			if(!pkt || target >= pktlen)
773				return w + sldns_str_print(s, slen,
774					"ErrorComprPtrOutOfBounds");
775			if(counter++ > maxcompr)
776				return w + sldns_str_print(s, slen,
777					"ErrorComprPtrLooped");
778			in_buf = 0;
779			pos = pkt+target;
780			continue;
781		} else if((labellen&0xc0)) {
782			/* notimpl label type */
783			w += sldns_str_print(s, slen,
784				"ErrorLABELTYPE%xIsUnknown",
785				(int)(labellen&0xc0));
786			return w;
787		}
788
789		/* spool label characters, end with '.' */
790		if(in_buf && *dlen < labellen) labellen = *dlen;
791		else if(!in_buf && pos+labellen > pkt+pktlen)
792			labellen = (uint8_t)(pkt + pktlen - pos);
793		for(i=0; i<(unsigned)labellen; i++) {
794			w += dname_char_print(s, slen, *pos++);
795		}
796		if(in_buf) {
797			(*d) += labellen;
798			(*dlen) -= labellen;
799			if(*dlen == 0) break;
800		}
801		w += sldns_str_print(s, slen, ".");
802	}
803	/* skip over final root label */
804	if(in_buf && *dlen > 0) { (*d)++; (*dlen)--; }
805	/* in case we printed no labels, terminate dname */
806	if(w == 0) w += sldns_str_print(s, slen, ".");
807	return w;
808}
809
810int sldns_wire2str_opcode_print(char** s, size_t* slen, int opcode)
811{
812	sldns_lookup_table *lt = sldns_lookup_by_id(sldns_opcodes, opcode);
813	if (lt && lt->name) {
814		return sldns_str_print(s, slen, "%s", lt->name);
815	}
816	return sldns_str_print(s, slen, "OPCODE%u", (unsigned)opcode);
817}
818
819int sldns_wire2str_rcode_print(char** s, size_t* slen, int rcode)
820{
821	sldns_lookup_table *lt = sldns_lookup_by_id(sldns_rcodes, rcode);
822	if (lt && lt->name) {
823		return sldns_str_print(s, slen, "%s", lt->name);
824	}
825	return sldns_str_print(s, slen, "RCODE%u", (unsigned)rcode);
826}
827
828int sldns_wire2str_class_print(char** s, size_t* slen, uint16_t rrclass)
829{
830	sldns_lookup_table *lt = sldns_lookup_by_id(sldns_rr_classes,
831		(int)rrclass);
832	if (lt && lt->name) {
833		return sldns_str_print(s, slen, "%s", lt->name);
834	}
835	return sldns_str_print(s, slen, "CLASS%u", (unsigned)rrclass);
836}
837
838int sldns_wire2str_type_print(char** s, size_t* slen, uint16_t rrtype)
839{
840	const sldns_rr_descriptor *descriptor = sldns_rr_descript(rrtype);
841	if (descriptor && descriptor->_name) {
842		return sldns_str_print(s, slen, "%s", descriptor->_name);
843	}
844	return sldns_str_print(s, slen, "TYPE%u", (unsigned)rrtype);
845}
846
847int sldns_wire2str_edns_option_code_print(char** s, size_t* slen,
848	uint16_t opcode)
849{
850	sldns_lookup_table *lt = sldns_lookup_by_id(sldns_edns_options,
851		(int)opcode);
852	if (lt && lt->name) {
853		return sldns_str_print(s, slen, "%s", lt->name);
854	}
855	return sldns_str_print(s, slen, "OPT%u", (unsigned)opcode);
856}
857
858int sldns_wire2str_class_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen)
859{
860	uint16_t c;
861	if(*dlen == 0) return 0;
862	if(*dlen < 2) return print_remainder_hex("Error malformed 0x", d, dlen, s, slen);
863	c = sldns_read_uint16(*d);
864	(*d)+=2;
865	(*dlen)-=2;
866	return sldns_wire2str_class_print(s, slen, c);
867}
868
869int sldns_wire2str_type_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen)
870{
871	uint16_t t;
872	if(*dlen == 0) return 0;
873	if(*dlen < 2) return print_remainder_hex("Error malformed 0x", d, dlen, s, slen);
874	t = sldns_read_uint16(*d);
875	(*d)+=2;
876	(*dlen)-=2;
877	return sldns_wire2str_type_print(s, slen, t);
878}
879
880int sldns_wire2str_ttl_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen)
881{
882	uint32_t ttl;
883	if(*dlen == 0) return 0;
884	if(*dlen < 4) return print_remainder_hex("Error malformed 0x", d, dlen, s, slen);
885	ttl = sldns_read_uint32(*d);
886	(*d)+=4;
887	(*dlen)-=4;
888	return sldns_str_print(s, slen, "%u", (unsigned)ttl);
889}
890
891int sldns_wire2str_rdf_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
892	int rdftype, uint8_t* pkt, size_t pktlen)
893{
894	if(*dlen == 0) return 0;
895	switch(rdftype) {
896	case LDNS_RDF_TYPE_NONE:
897		return 0;
898	case LDNS_RDF_TYPE_DNAME:
899		return sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen);
900	case LDNS_RDF_TYPE_INT8:
901		return sldns_wire2str_int8_scan(d, dlen, s, slen);
902	case LDNS_RDF_TYPE_INT16:
903		return sldns_wire2str_int16_scan(d, dlen, s, slen);
904	case LDNS_RDF_TYPE_INT32:
905		return sldns_wire2str_int32_scan(d, dlen, s, slen);
906	case LDNS_RDF_TYPE_PERIOD:
907		return sldns_wire2str_period_scan(d, dlen, s, slen);
908	case LDNS_RDF_TYPE_TSIGTIME:
909		return sldns_wire2str_tsigtime_scan(d, dlen, s, slen);
910	case LDNS_RDF_TYPE_A:
911		return sldns_wire2str_a_scan(d, dlen, s, slen);
912	case LDNS_RDF_TYPE_AAAA:
913		return sldns_wire2str_aaaa_scan(d, dlen, s, slen);
914	case LDNS_RDF_TYPE_STR:
915		return sldns_wire2str_str_scan(d, dlen, s, slen);
916	case LDNS_RDF_TYPE_APL:
917		return sldns_wire2str_apl_scan(d, dlen, s, slen);
918	case LDNS_RDF_TYPE_B32_EXT:
919		return sldns_wire2str_b32_ext_scan(d, dlen, s, slen);
920	case LDNS_RDF_TYPE_B64:
921		return sldns_wire2str_b64_scan(d, dlen, s, slen);
922	case LDNS_RDF_TYPE_HEX:
923		return sldns_wire2str_hex_scan(d, dlen, s, slen);
924	case LDNS_RDF_TYPE_NSEC:
925		return sldns_wire2str_nsec_scan(d, dlen, s, slen);
926	case LDNS_RDF_TYPE_NSEC3_SALT:
927		return sldns_wire2str_nsec3_salt_scan(d, dlen, s, slen);
928	case LDNS_RDF_TYPE_TYPE:
929		return sldns_wire2str_type_scan(d, dlen, s, slen);
930	case LDNS_RDF_TYPE_CLASS:
931		return sldns_wire2str_class_scan(d, dlen, s, slen);
932	case LDNS_RDF_TYPE_CERT_ALG:
933		return sldns_wire2str_cert_alg_scan(d, dlen, s, slen);
934	case LDNS_RDF_TYPE_ALG:
935		return sldns_wire2str_alg_scan(d, dlen, s, slen);
936	case LDNS_RDF_TYPE_UNKNOWN:
937		return sldns_wire2str_unknown_scan(d, dlen, s, slen);
938	case LDNS_RDF_TYPE_TIME:
939		return sldns_wire2str_time_scan(d, dlen, s, slen);
940	case LDNS_RDF_TYPE_LOC:
941		return sldns_wire2str_loc_scan(d, dlen, s, slen);
942	case LDNS_RDF_TYPE_WKS:
943	case LDNS_RDF_TYPE_SERVICE:
944		return sldns_wire2str_wks_scan(d, dlen, s, slen);
945	case LDNS_RDF_TYPE_NSAP:
946		return sldns_wire2str_nsap_scan(d, dlen, s, slen);
947	case LDNS_RDF_TYPE_ATMA:
948		return sldns_wire2str_atma_scan(d, dlen, s, slen);
949	case LDNS_RDF_TYPE_IPSECKEY:
950		return sldns_wire2str_ipseckey_scan(d, dlen, s, slen, pkt,
951			pktlen);
952	case LDNS_RDF_TYPE_HIP:
953		return sldns_wire2str_hip_scan(d, dlen, s, slen);
954	case LDNS_RDF_TYPE_INT16_DATA:
955		return sldns_wire2str_int16_data_scan(d, dlen, s, slen);
956	case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER:
957		return sldns_wire2str_b32_ext_scan(d, dlen, s, slen);
958	case LDNS_RDF_TYPE_ILNP64:
959		return sldns_wire2str_ilnp64_scan(d, dlen, s, slen);
960	case LDNS_RDF_TYPE_EUI48:
961		return sldns_wire2str_eui48_scan(d, dlen, s, slen);
962	case LDNS_RDF_TYPE_EUI64:
963		return sldns_wire2str_eui64_scan(d, dlen, s, slen);
964	case LDNS_RDF_TYPE_TAG:
965		return sldns_wire2str_tag_scan(d, dlen, s, slen);
966	case LDNS_RDF_TYPE_LONG_STR:
967		return sldns_wire2str_long_str_scan(d, dlen, s, slen);
968	}
969	/* unknown rdf type */
970	return -1;
971}
972
973int sldns_wire2str_int8_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
974{
975	int w;
976	if(*dl < 1) return -1;
977	w = sldns_str_print(s, sl, "%u", (unsigned)**d);
978	(*d)++;
979	(*dl)--;
980	return w;
981}
982
983int sldns_wire2str_int16_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
984{
985	int w;
986	if(*dl < 2) return -1;
987	w = sldns_str_print(s, sl, "%lu", (unsigned long)sldns_read_uint16(*d));
988	(*d)+=2;
989	(*dl)-=2;
990	return w;
991}
992
993int sldns_wire2str_int32_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
994{
995	int w;
996	if(*dl < 4) return -1;
997	w = sldns_str_print(s, sl, "%lu", (unsigned long)sldns_read_uint32(*d));
998	(*d)+=4;
999	(*dl)-=4;
1000	return w;
1001}
1002
1003int sldns_wire2str_period_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1004{
1005	int w;
1006	if(*dl < 4) return -1;
1007	w = sldns_str_print(s, sl, "%u", (unsigned)sldns_read_uint32(*d));
1008	(*d)+=4;
1009	(*dl)-=4;
1010	return w;
1011}
1012
1013int sldns_wire2str_tsigtime_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1014{
1015	/* tsigtime is 48 bits network order unsigned integer */
1016	int w;
1017	uint64_t tsigtime = 0;
1018	uint64_t d0, d1, d2, d3, d4, d5;
1019	if(*dl < 6) return -1;
1020	d0 = (*d)[0]; /* cast to uint64 for shift operations */
1021	d1 = (*d)[1];
1022	d2 = (*d)[2];
1023	d3 = (*d)[3];
1024	d4 = (*d)[4];
1025	d5 = (*d)[5];
1026	tsigtime = (d0<<40) | (d1<<32) | (d2<<24) | (d3<<16) | (d4<<8) | d5;
1027#ifndef USE_WINSOCK
1028	w = sldns_str_print(s, sl, "%llu", (long long)tsigtime);
1029#else
1030	w = sldns_str_print(s, sl, "%I64u", (long long)tsigtime);
1031#endif
1032	(*d)+=6;
1033	(*dl)-=6;
1034	return w;
1035}
1036
1037int sldns_wire2str_a_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1038{
1039	char buf[32];
1040	int w;
1041	if(*dl < 4) return -1;
1042	if(!inet_ntop(AF_INET, *d, buf, (socklen_t)sizeof(buf)))
1043		return -1;
1044	w = sldns_str_print(s, sl, "%s", buf);
1045	(*d)+=4;
1046	(*dl)-=4;
1047	return w;
1048}
1049
1050int sldns_wire2str_aaaa_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1051{
1052#ifdef AF_INET6
1053	char buf[64];
1054	int w;
1055	if(*dl < 16) return -1;
1056	if(!inet_ntop(AF_INET6, *d, buf, (socklen_t)sizeof(buf)))
1057		return -1;
1058	w = sldns_str_print(s, sl, "%s", buf);
1059	(*d)+=16;
1060	(*dl)-=16;
1061	return w;
1062#else
1063	return -1;
1064#endif
1065}
1066
1067/** printout escaped TYPE_STR character */
1068static int str_char_print(char** s, size_t* sl, uint8_t c)
1069{
1070	if(isprint((unsigned char)c) || c == '\t') {
1071		if(c == '\"' || c == '\\')
1072			return sldns_str_print(s, sl, "\\%c", c);
1073		if(*sl) {
1074			**s = (char)c;
1075			(*s)++;
1076			(*sl)--;
1077		}
1078		return 1;
1079	}
1080	return sldns_str_print(s, sl, "\\%03u", (unsigned)c);
1081}
1082
1083int sldns_wire2str_str_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1084{
1085	int w = 0;
1086	size_t i, len;
1087	if(*dl < 1) return -1;
1088	len = **d;
1089	if(*dl < 1+len) return -1;
1090	(*d)++;
1091	(*dl)--;
1092	w += sldns_str_print(s, sl, "\"");
1093	for(i=0; i<len; i++)
1094		w += str_char_print(s, sl, (*d)[i]);
1095	w += sldns_str_print(s, sl, "\"");
1096	(*d)+=len;
1097	(*dl)-=len;
1098	return w;
1099}
1100
1101int sldns_wire2str_apl_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1102{
1103	int i, w = 0;
1104	uint16_t family;
1105	uint8_t negation, prefix, adflength;
1106	if(*dl < 4) return -1;
1107	family = sldns_read_uint16(*d);
1108	prefix = (*d)[2];
1109	negation = ((*d)[3] & LDNS_APL_NEGATION);
1110	adflength = ((*d)[3] & LDNS_APL_MASK);
1111	if(*dl < 4+(size_t)adflength) return -1;
1112	if(family != LDNS_APL_IP4 && family != LDNS_APL_IP6)
1113		return -1; /* unknown address family */
1114	if(negation)
1115		w += sldns_str_print(s, sl, "!");
1116	w += sldns_str_print(s, sl, "%u:", (unsigned)family);
1117	if(family == LDNS_APL_IP4) {
1118		/* check if prefix <32 ? */
1119		/* address is variable length 0 - 4 */
1120		for(i=0; i<4; i++) {
1121			if(i > 0)
1122				w += sldns_str_print(s, sl, ".");
1123			if(i < (int)adflength)
1124				w += sldns_str_print(s, sl, "%d", (*d)[4+i]);
1125			else	w += sldns_str_print(s, sl, "0");
1126		}
1127	} else if(family == LDNS_APL_IP6) {
1128		/* check if prefix <128 ? */
1129		/* address is variable length 0 - 16 */
1130		for(i=0; i<16; i++) {
1131			if(i%2 == 0 && i>0)
1132				w += sldns_str_print(s, sl, ":");
1133			if(i < (int)adflength)
1134				w += sldns_str_print(s, sl, "%02x", (*d)[4+i]);
1135			else	w += sldns_str_print(s, sl, "00");
1136		}
1137	}
1138	w += sldns_str_print(s, sl, "/%u", (unsigned)prefix);
1139	(*d) += 4+adflength;
1140	(*dl) -= 4+adflength;
1141	return w;
1142}
1143
1144int sldns_wire2str_b32_ext_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1145{
1146	size_t datalen;
1147	size_t sz;
1148	if(*dl < 1) return -1;
1149	datalen = (*d)[0];
1150	if(*dl < 1+datalen) return -1;
1151	sz = sldns_b32_ntop_calculate_size(datalen);
1152	if(*sl < sz+1) {
1153		(*d) += datalen+1;
1154		(*dl) -= (datalen+1);
1155		return (int)sz; /* out of space really, but would need buffer
1156			in order to truncate the output */
1157	}
1158	sldns_b32_ntop_extended_hex((*d)+1, datalen, *s, *sl);
1159	(*d) += datalen+1;
1160	(*dl) -= (datalen+1);
1161	(*s) += sz;
1162	(*sl) -= sz;
1163	return (int)sz;
1164}
1165
1166/** scan number of bytes from wire into b64 presentation format */
1167static int sldns_wire2str_b64_scan_num(uint8_t** d, size_t* dl, char** s,
1168	size_t* sl, size_t num)
1169{
1170	/* b64_ntop_calculate size includes null at the end */
1171	size_t sz = sldns_b64_ntop_calculate_size(num)-1;
1172	if(*sl < sz+1) {
1173		(*d) += num;
1174		(*dl) -= num;
1175		return (int)sz; /* out of space really, but would need buffer
1176			in order to truncate the output */
1177	}
1178	sldns_b64_ntop(*d, num, *s, *sl);
1179	(*d) += num;
1180	(*dl) -= num;
1181	(*s) += sz;
1182	(*sl) -= sz;
1183	return (int)sz;
1184}
1185
1186int sldns_wire2str_b64_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1187{
1188	return sldns_wire2str_b64_scan_num(d, dl, s, sl, *dl);
1189}
1190
1191int sldns_wire2str_hex_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1192{
1193	return print_remainder_hex("", d, dl, s, sl);
1194}
1195
1196int sldns_wire2str_nsec_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1197{
1198	uint8_t* p = *d;
1199	size_t pl = *dl;
1200	unsigned i, bit, window, block_len;
1201	uint16_t t;
1202	int w = 0;
1203
1204	/* check for errors */
1205	while(pl) {
1206		if(pl < 2) return -1;
1207		block_len = (unsigned)p[1];
1208		if(pl < 2+block_len) return -1;
1209		p += block_len+2;
1210		pl -= block_len+2;
1211	}
1212
1213	/* do it */
1214	p = *d;
1215	pl = *dl;
1216	while(pl) {
1217		if(pl < 2) return -1; /* cannot happen */
1218		window = (unsigned)p[0];
1219		block_len = (unsigned)p[1];
1220		if(pl < 2+block_len) return -1; /* cannot happen */
1221		p += 2;
1222		for(i=0; i<block_len; i++) {
1223			if(p[i] == 0) continue;
1224			/* base type number for this octet */
1225			t = ((window)<<8) | (i << 3);
1226			for(bit=0; bit<8; bit++) {
1227				if((p[i]&(0x80>>bit))) {
1228					if(w) w += sldns_str_print(s, sl, " ");
1229					w += sldns_wire2str_type_print(s, sl,
1230						t+bit);
1231				}
1232			}
1233		}
1234		p += block_len;
1235		pl -= block_len+2;
1236	}
1237	(*d) += *dl;
1238	(*dl) = 0;
1239	return w;
1240}
1241
1242int sldns_wire2str_nsec3_salt_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1243{
1244	size_t salt_len;
1245	int w;
1246	if(*dl < 1) return -1;
1247	salt_len = (size_t)(*d)[0];
1248	if(*dl < 1+salt_len) return -1;
1249	(*d)++;
1250	(*dl)--;
1251	if(salt_len == 0) {
1252		return sldns_str_print(s, sl, "-");
1253	}
1254	w = print_hex_buf(s, sl, *d, salt_len);
1255	(*dl)-=salt_len;
1256	(*d)+=salt_len;
1257	return w;
1258}
1259
1260int sldns_wire2str_cert_alg_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1261{
1262	sldns_lookup_table *lt;
1263	int data, w;
1264	if(*dl < 2) return -1;
1265	data = (int)sldns_read_uint16(*d);
1266	lt = sldns_lookup_by_id(sldns_cert_algorithms, data);
1267	if(lt && lt->name)
1268		w = sldns_str_print(s, sl, "%s", lt->name);
1269	else 	w = sldns_str_print(s, sl, "%d", data);
1270	(*dl)-=2;
1271	(*d)+=2;
1272	return w;
1273}
1274
1275int sldns_wire2str_alg_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1276{
1277	/* don't use algorithm mnemonics in the presentation format
1278	 * this kind of got sneaked into the rfc's */
1279	return sldns_wire2str_int8_scan(d, dl, s, sl);
1280}
1281
1282int sldns_wire2str_unknown_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1283{
1284	return sldns_wire2str_rdata_unknown_scan(d, dl, s, sl);
1285}
1286
1287int sldns_wire2str_time_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1288{
1289	/* create a YYYYMMDDHHMMSS string if possible */
1290	struct tm tm;
1291	char date_buf[16];
1292	uint32_t t;
1293	memset(&tm, 0, sizeof(tm));
1294	if(*dl < 4) return -1;
1295	t = sldns_read_uint32(*d);
1296	date_buf[15]=0;
1297	if(sldns_serial_arithmitics_gmtime_r(t, time(NULL), &tm) &&
1298		strftime(date_buf, 15, "%Y%m%d%H%M%S", &tm)) {
1299		(*d) += 4;
1300		(*dl) -= 4;
1301		return sldns_str_print(s, sl, "%s", date_buf);
1302	}
1303	return -1;
1304}
1305
1306static int
1307loc_cm_print(char** str, size_t* sl, uint8_t mantissa, uint8_t exponent)
1308{
1309	int w = 0;
1310	uint8_t i;
1311	/* is it 0.<two digits> ? */
1312	if(exponent < 2) {
1313		if(exponent == 1)
1314			mantissa *= 10;
1315		return sldns_str_print(str, sl, "0.%02ld", (long)mantissa);
1316	}
1317	/* always <digit><string of zeros> */
1318	w += sldns_str_print(str, sl, "%d", (int)mantissa);
1319	for(i=0; i<exponent-2; i++)
1320		w += sldns_str_print(str, sl, "0");
1321	return w;
1322}
1323
1324int sldns_wire2str_loc_scan(uint8_t** d, size_t* dl, char** str, size_t* sl)
1325{
1326	/* we could do checking (ie degrees < 90 etc)? */
1327	uint8_t version;
1328	uint8_t size;
1329	uint8_t horizontal_precision;
1330	uint8_t vertical_precision;
1331	uint32_t longitude;
1332	uint32_t latitude;
1333	uint32_t altitude;
1334	char northerness;
1335	char easterness;
1336	uint32_t h;
1337	uint32_t m;
1338	double s;
1339	uint32_t equator = (uint32_t)1 << 31; /* 2**31 */
1340	int w = 0;
1341
1342	if(*dl < 16) return -1;
1343	version = (*d)[0];
1344	if(version != 0)
1345		return sldns_wire2str_hex_scan(d, dl, str, sl);
1346	size = (*d)[1];
1347	horizontal_precision = (*d)[2];
1348	vertical_precision = (*d)[3];
1349
1350	latitude = sldns_read_uint32((*d)+4);
1351	longitude = sldns_read_uint32((*d)+8);
1352	altitude = sldns_read_uint32((*d)+12);
1353
1354	if (latitude > equator) {
1355		northerness = 'N';
1356		latitude = latitude - equator;
1357	} else {
1358		northerness = 'S';
1359		latitude = equator - latitude;
1360	}
1361	h = latitude / (1000 * 60 * 60);
1362	latitude = latitude % (1000 * 60 * 60);
1363	m = latitude / (1000 * 60);
1364	latitude = latitude % (1000 * 60);
1365	s = (double) latitude / 1000.0;
1366	w += sldns_str_print(str, sl, "%02u %02u %06.3f %c ",
1367		h, m, s, northerness);
1368
1369	if (longitude > equator) {
1370		easterness = 'E';
1371		longitude = longitude - equator;
1372	} else {
1373		easterness = 'W';
1374		longitude = equator - longitude;
1375	}
1376	h = longitude / (1000 * 60 * 60);
1377	longitude = longitude % (1000 * 60 * 60);
1378	m = longitude / (1000 * 60);
1379	longitude = longitude % (1000 * 60);
1380	s = (double) longitude / (1000.0);
1381	w += sldns_str_print(str, sl, "%02u %02u %06.3f %c ",
1382		h, m, s, easterness);
1383
1384	s = ((double) altitude) / 100;
1385	s -= 100000;
1386
1387	if(altitude%100 != 0)
1388		w += sldns_str_print(str, sl, "%.2f", s);
1389	else
1390		w += sldns_str_print(str, sl, "%.0f", s);
1391
1392	w += sldns_str_print(str, sl, "m ");
1393
1394	w += loc_cm_print(str, sl, (size & 0xf0) >> 4, size & 0x0f);
1395	w += sldns_str_print(str, sl, "m ");
1396
1397	w += loc_cm_print(str, sl, (horizontal_precision & 0xf0) >> 4,
1398		horizontal_precision & 0x0f);
1399	w += sldns_str_print(str, sl, "m ");
1400
1401	w += loc_cm_print(str, sl, (vertical_precision & 0xf0) >> 4,
1402		vertical_precision & 0x0f);
1403	w += sldns_str_print(str, sl, "m");
1404
1405	(*d)+=16;
1406	(*dl)-=16;
1407	return w;
1408}
1409
1410int sldns_wire2str_wks_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1411{
1412	/* protocol, followed by bitmap of services */
1413	const char* proto_name = NULL;
1414	struct protoent *protocol;
1415	struct servent *service;
1416	uint8_t protocol_nr;
1417	int bit, port, w = 0;
1418	size_t i;
1419	/* we cannot print with strings because they
1420	 * are not portable, the presentation format may
1421	 * not be able to be read in on another computer.  */
1422	int print_symbols = 0;
1423
1424	/* protocol */
1425	if(*dl < 1) return -1;
1426	protocol_nr = (*d)[0];
1427	(*d)++;
1428	(*dl)--;
1429	protocol = getprotobynumber((int)protocol_nr);
1430	if(protocol && (protocol->p_name != NULL)) {
1431		w += sldns_str_print(s, sl, "%s", protocol->p_name);
1432		proto_name = protocol->p_name;
1433	} else	{
1434		w += sldns_str_print(s, sl, "%u", (unsigned)protocol_nr);
1435	}
1436
1437	for(i=0; i<*dl; i++) {
1438		if((*d)[i] == 0)
1439			continue;
1440		for(bit=0; bit<8; bit++) {
1441			if(!(((*d)[i])&(0x80>>bit)))
1442				continue;
1443			port = (int)i*8 + bit;
1444
1445			if(!print_symbols)
1446				service = NULL;
1447			else
1448				service = getservbyport(
1449					(int)htons((uint16_t)port), proto_name);
1450			if(service && service->s_name)
1451				w += sldns_str_print(s, sl, " %s",
1452					service->s_name);
1453			else 	w += sldns_str_print(s, sl, " %u",
1454					(unsigned)port);
1455		}
1456	}
1457
1458#ifdef HAVE_ENDSERVENT
1459	endservent();
1460#endif
1461#ifdef HAVE_ENDPROTOENT
1462        endprotoent();
1463#endif
1464	(*d) += *dl;
1465	(*dl) = 0;
1466	return w;
1467}
1468
1469int sldns_wire2str_nsap_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1470{
1471	return print_remainder_hex("0x", d, dl, s, sl);
1472}
1473
1474int sldns_wire2str_atma_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1475{
1476	return print_remainder_hex("", d, dl, s, sl);
1477}
1478
1479/* internal scan routine that can modify arguments on failure */
1480static int sldns_wire2str_ipseckey_scan_internal(uint8_t** d, size_t* dl,
1481	char** s, size_t* sl, uint8_t* pkt, size_t pktlen)
1482{
1483	/* http://www.ietf.org/internet-drafts/draft-ietf-ipseckey-rr-12.txt*/
1484	uint8_t precedence, gateway_type, algorithm;
1485	int w = 0;
1486
1487	if(*dl < 3) return -1;
1488	precedence = (*d)[0];
1489	gateway_type = (*d)[1];
1490	algorithm = (*d)[2];
1491	if(gateway_type > 3)
1492		return -1; /* unknown */
1493	(*d)+=3;
1494	(*dl)-=3;
1495	w += sldns_str_print(s, sl, "%d %d %d ",
1496		(int)precedence, (int)gateway_type, (int)algorithm);
1497
1498	switch(gateway_type) {
1499	case 0: /* no gateway */
1500		w += sldns_str_print(s, sl, ".");
1501		break;
1502	case 1: /* ip4 */
1503		w += sldns_wire2str_a_scan(d, dl, s, sl);
1504		break;
1505	case 2: /* ip6 */
1506		w += sldns_wire2str_aaaa_scan(d, dl, s, sl);
1507		break;
1508	case 3: /* dname */
1509		w += sldns_wire2str_dname_scan(d, dl, s, sl, pkt, pktlen);
1510		break;
1511	default: /* unknown */
1512		return -1;
1513	}
1514
1515	if(*dl < 1)
1516		return -1;
1517	w += sldns_str_print(s, sl, " ");
1518	w += sldns_wire2str_b64_scan_num(d, dl, s, sl, *dl);
1519	return w;
1520}
1521
1522int sldns_wire2str_ipseckey_scan(uint8_t** d, size_t* dl, char** s, size_t* sl,
1523	uint8_t* pkt, size_t pktlen)
1524{
1525	uint8_t* od = *d;
1526	char* os = *s;
1527	size_t odl = *dl, osl = *sl;
1528	int w=sldns_wire2str_ipseckey_scan_internal(d, dl, s, sl, pkt, pktlen);
1529	if(w == -1) {
1530		*d = od;
1531		*s = os;
1532		*dl = odl;
1533		*sl = osl;
1534		return -1;
1535	}
1536	return w;
1537}
1538
1539int sldns_wire2str_hip_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1540{
1541	int w;
1542	uint8_t algo, hitlen;
1543	uint16_t pklen;
1544
1545	/* read lengths */
1546	if(*dl < 4)
1547		return -1;
1548	hitlen = (*d)[0];
1549	algo = (*d)[1];
1550	pklen = sldns_read_uint16((*d)+2);
1551	if(*dl < (size_t)4 + (size_t)hitlen + (size_t)pklen)
1552		return -1;
1553
1554	/* write: algo hit pubkey */
1555	w = sldns_str_print(s, sl, "%u ", (unsigned)algo);
1556	w += print_hex_buf(s, sl, (*d)+4, hitlen);
1557	w += sldns_str_print(s, sl, " ");
1558	(*d)+=4+hitlen;
1559	(*dl)-= (4+hitlen);
1560	w += sldns_wire2str_b64_scan_num(d, dl, s, sl, pklen);
1561	return w;
1562}
1563
1564int sldns_wire2str_int16_data_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1565{
1566	uint16_t n;
1567	if(*dl < 2)
1568		return -1;
1569	n = sldns_read_uint16(*d);
1570	if(*dl < 2+(size_t)n)
1571		return -1;
1572	(*d)+=2;
1573	(*dl)-=2;
1574	return sldns_wire2str_b64_scan_num(d, dl, s, sl, n);
1575}
1576
1577int sldns_wire2str_nsec3_next_owner_scan(uint8_t** d, size_t* dl, char** s,
1578	size_t* sl)
1579{
1580	return sldns_wire2str_b32_ext_scan(d, dl, s, sl);
1581}
1582
1583int sldns_wire2str_ilnp64_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1584{
1585	int w;
1586	if(*dl < 8)
1587		return -1;
1588	w = sldns_str_print(s, sl, "%.4x:%.4x:%.4x:%.4x",
1589		sldns_read_uint16(*d), sldns_read_uint16((*d)+2),
1590		sldns_read_uint16((*d)+4), sldns_read_uint16((*d)+6));
1591	(*d)+=8;
1592	(*dl)-=8;
1593	return w;
1594}
1595
1596int sldns_wire2str_eui48_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1597{
1598	int w;
1599	if(*dl < 6)
1600		return -1;
1601	w = sldns_str_print(s, sl, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
1602		(*d)[0], (*d)[1], (*d)[2], (*d)[3], (*d)[4], (*d)[5]);
1603	(*d)+=6;
1604	(*dl)-=6;
1605	return w;
1606}
1607
1608int sldns_wire2str_eui64_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1609{
1610	int w;
1611	if(*dl < 8)
1612		return -1;
1613	w = sldns_str_print(s, sl, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
1614		(*d)[0], (*d)[1], (*d)[2], (*d)[3], (*d)[4], (*d)[5],
1615		(*d)[6], (*d)[7]);
1616	(*d)+=8;
1617	(*dl)-=8;
1618	return w;
1619}
1620
1621int sldns_wire2str_tag_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1622{
1623	size_t i, n;
1624	int w = 0;
1625	if(*dl < 1)
1626		return -1;
1627	n = (size_t)((*d)[0]);
1628	if(*dl < 1+n)
1629		return -1;
1630	for(i=0; i<n; i++)
1631		if(!isalnum((unsigned char)(*d)[i]))
1632			return -1;
1633	for(i=0; i<n; i++)
1634		w += sldns_str_print(s, sl, "%c", (char)(*d)[i]);
1635	(*d)+=n+1;
1636	(*dl)-=(n+1);
1637	return w;
1638}
1639
1640int sldns_wire2str_long_str_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
1641{
1642	size_t i;
1643	int w = 0;
1644	w += sldns_str_print(s, sl, "\"");
1645	for(i=0; i<*dl; i++)
1646		w += str_char_print(s, sl, (*d)[i]);
1647	w += sldns_str_print(s, sl, "\"");
1648	(*d)+=*dl;
1649	(*dl)=0;
1650	return w;
1651}
1652
1653int sldns_wire2str_edns_llq_print(char** s, size_t* sl, uint8_t* data,
1654	size_t len)
1655{
1656	/* LLQ constants */
1657	const char* llq_errors[] = {"NO-ERROR", "SERV-FULL", "STATIC",
1658		"FORMAT-ERR", "NO-SUCH-LLQ", "BAD-VERS", "UNKNOWN_ERR"};
1659	const unsigned int llq_errors_num = 7;
1660	const char* llq_opcodes[] = {"LLQ-SETUP", "LLQ-REFRESH", "LLQ-EVENT"};
1661	const unsigned int llq_opcodes_num = 3;
1662	uint16_t version, llq_opcode, error_code;
1663	uint64_t llq_id;
1664	uint32_t lease_life; /* Requested or granted life of LLQ, in seconds */
1665	int w = 0;
1666
1667	/* read the record */
1668	if(len != 18) {
1669		w += sldns_str_print(s, sl, "malformed LLQ ");
1670		w += print_hex_buf(s, sl, data, len);
1671		return w;
1672	}
1673	version = sldns_read_uint16(data);
1674	llq_opcode = sldns_read_uint16(data+2);
1675	error_code = sldns_read_uint16(data+4);
1676	memmove(&llq_id, data+6, sizeof(llq_id));
1677	lease_life = sldns_read_uint32(data+14);
1678
1679	/* print it */
1680	w += sldns_str_print(s, sl, "v%d ", (int)version);
1681	if(llq_opcode < llq_opcodes_num)
1682		w += sldns_str_print(s, sl, "%s", llq_opcodes[llq_opcode]);
1683	else	w += sldns_str_print(s, sl, "opcode %d", (int)llq_opcode);
1684	if(error_code < llq_errors_num)
1685		w += sldns_str_print(s, sl, " %s", llq_errors[error_code]);
1686	else	w += sldns_str_print(s, sl, " error %d", (int)error_code);
1687#ifndef USE_WINSOCK
1688	w += sldns_str_print(s, sl, " id %llx lease-life %lu",
1689		(unsigned long long)llq_id, (unsigned long)lease_life);
1690#else
1691	w += sldns_str_print(s, sl, " id %I64x lease-life %lu",
1692		(unsigned long long)llq_id, (unsigned long)lease_life);
1693#endif
1694	return w;
1695}
1696
1697int sldns_wire2str_edns_ul_print(char** s, size_t* sl, uint8_t* data,
1698	size_t len)
1699{
1700	uint32_t lease;
1701	int w = 0;
1702	if(len != 4) {
1703		w += sldns_str_print(s, sl, "malformed UL ");
1704		w += print_hex_buf(s, sl, data, len);
1705		return w;
1706	}
1707	lease = sldns_read_uint32(data);
1708	w += sldns_str_print(s, sl, "lease %lu", (unsigned long)lease);
1709	return w;
1710}
1711
1712int sldns_wire2str_edns_nsid_print(char** s, size_t* sl, uint8_t* data,
1713	size_t len)
1714{
1715	int w = 0;
1716	size_t i, printed=0;
1717	w += print_hex_buf(s, sl, data, len);
1718	for(i=0; i<len; i++) {
1719		if(isprint((unsigned char)data[i]) || data[i] == '\t') {
1720			if(!printed) {
1721				w += sldns_str_print(s, sl, " (");
1722				printed = 1;
1723			}
1724			w += sldns_str_print(s, sl, "%c", (char)data[i]);
1725		}
1726	}
1727	if(printed)
1728		w += sldns_str_print(s, sl, ")");
1729	return w;
1730}
1731
1732int sldns_wire2str_edns_dau_print(char** s, size_t* sl, uint8_t* data,
1733	size_t len)
1734{
1735	sldns_lookup_table *lt;
1736	size_t i;
1737	int w = 0;
1738	for(i=0; i<len; i++) {
1739		lt = sldns_lookup_by_id(sldns_algorithms, (int)data[i]);
1740		if(lt && lt->name)
1741			w += sldns_str_print(s, sl, " %s", lt->name);
1742		else 	w += sldns_str_print(s, sl, " %d", (int)data[i]);
1743	}
1744	return w;
1745}
1746
1747int sldns_wire2str_edns_dhu_print(char** s, size_t* sl, uint8_t* data,
1748	size_t len)
1749{
1750	sldns_lookup_table *lt;
1751	size_t i;
1752	int w = 0;
1753	for(i=0; i<len; i++) {
1754		lt = sldns_lookup_by_id(sldns_hashes, (int)data[i]);
1755		if(lt && lt->name)
1756			w += sldns_str_print(s, sl, " %s", lt->name);
1757		else 	w += sldns_str_print(s, sl, " %d", (int)data[i]);
1758	}
1759	return w;
1760}
1761
1762int sldns_wire2str_edns_n3u_print(char** s, size_t* sl, uint8_t* data,
1763	size_t len)
1764{
1765	size_t i;
1766	int w = 0;
1767	for(i=0; i<len; i++) {
1768		if(data[i] == 1)
1769			w += sldns_str_print(s, sl, " SHA1");
1770		else 	w += sldns_str_print(s, sl, " %d", (int)data[i]);
1771	}
1772	return w;
1773}
1774
1775int sldns_wire2str_edns_subnet_print(char** s, size_t* sl, uint8_t* data,
1776	size_t len)
1777{
1778	int w = 0;
1779	uint16_t family;
1780	uint8_t source, scope;
1781	if(len < 4) {
1782		w += sldns_str_print(s, sl, "malformed subnet ");
1783		w += print_hex_buf(s, sl, data, len);
1784		return w;
1785	}
1786	family = sldns_read_uint16(data);
1787	source = data[2];
1788	scope = data[3];
1789	if(family == 1) {
1790		/* IP4 */
1791		char buf[64];
1792		uint8_t ip4[4];
1793		memset(ip4, 0, sizeof(ip4));
1794		if(len-4 > 4) {
1795			w += sldns_str_print(s, sl, "trailingdata:");
1796			w += print_hex_buf(s, sl, data+4+4, len-4-4);
1797			w += sldns_str_print(s, sl, " ");
1798			len = 4+4;
1799		}
1800		memmove(ip4, data+4, len-4);
1801		if(!inet_ntop(AF_INET, ip4, buf, (socklen_t)sizeof(buf))) {
1802			w += sldns_str_print(s, sl, "ip4ntoperror ");
1803			w += print_hex_buf(s, sl, data+4+4, len-4-4);
1804		} else {
1805			w += sldns_str_print(s, sl, "%s", buf);
1806		}
1807	} else if(family == 2) {
1808		/* IP6 */
1809		char buf[64];
1810		uint8_t ip6[16];
1811		memset(ip6, 0, sizeof(ip6));
1812		if(len-4 > 16) {
1813			w += sldns_str_print(s, sl, "trailingdata:");
1814			w += print_hex_buf(s, sl, data+4+16, len-4-16);
1815			w += sldns_str_print(s, sl, " ");
1816			len = 4+16;
1817		}
1818		memmove(ip6, data+4, len-4);
1819#ifdef AF_INET6
1820		if(!inet_ntop(AF_INET6, ip6, buf, (socklen_t)sizeof(buf))) {
1821			w += sldns_str_print(s, sl, "ip6ntoperror ");
1822			w += print_hex_buf(s, sl, data+4+4, len-4-4);
1823		} else {
1824			w += sldns_str_print(s, sl, "%s", buf);
1825		}
1826#else
1827		w += print_hex_buf(s, sl, data+4+4, len-4-4);
1828#endif
1829	} else {
1830		/* unknown */
1831		w += sldns_str_print(s, sl, "family %d ",
1832			(int)family);
1833		w += print_hex_buf(s, sl, data, len);
1834	}
1835	w += sldns_str_print(s, sl, "/%d scope /%d", (int)source, (int)scope);
1836	return w;
1837}
1838
1839int sldns_wire2str_edns_option_print(char** s, size_t* sl,
1840	uint16_t option_code, uint8_t* optdata, size_t optlen)
1841{
1842	int w = 0;
1843	w += sldns_wire2str_edns_option_code_print(s, sl, option_code);
1844	w += sldns_str_print(s, sl, ": ");
1845	switch(option_code) {
1846	case LDNS_EDNS_LLQ:
1847		w += sldns_wire2str_edns_llq_print(s, sl, optdata, optlen);
1848		break;
1849	case LDNS_EDNS_UL:
1850		w += sldns_wire2str_edns_ul_print(s, sl, optdata, optlen);
1851		break;
1852	case LDNS_EDNS_NSID:
1853		w += sldns_wire2str_edns_nsid_print(s, sl, optdata, optlen);
1854		break;
1855	case LDNS_EDNS_DAU:
1856		w += sldns_wire2str_edns_dau_print(s, sl, optdata, optlen);
1857		break;
1858	case LDNS_EDNS_DHU:
1859		w += sldns_wire2str_edns_dhu_print(s, sl, optdata, optlen);
1860		break;
1861	case LDNS_EDNS_N3U:
1862		w += sldns_wire2str_edns_n3u_print(s, sl, optdata, optlen);
1863		break;
1864	case LDNS_EDNS_CLIENT_SUBNET:
1865		w += sldns_wire2str_edns_subnet_print(s, sl, optdata, optlen);
1866		break;
1867	default:
1868		/* unknown option code */
1869		w += print_hex_buf(s, sl, optdata, optlen);
1870		break;
1871	}
1872	return w;
1873}
1874
1875/** print the edns options to string */
1876static int
1877print_edns_opts(char** s, size_t* sl, uint8_t* rdata, size_t rdatalen)
1878{
1879	uint16_t option_code, option_len;
1880	int w = 0;
1881	while(rdatalen > 0) {
1882		/* option name */
1883		if(rdatalen < 4) {
1884			w += sldns_str_print(s, sl, " ; malformed: ");
1885			w += print_hex_buf(s, sl, rdata, rdatalen);
1886			return w;
1887		}
1888		option_code = sldns_read_uint16(rdata);
1889		option_len = sldns_read_uint16(rdata+2);
1890		rdata += 4;
1891		rdatalen -= 4;
1892
1893		/* option value */
1894		if(rdatalen < (size_t)option_len) {
1895			w += sldns_str_print(s, sl, " ; malformed ");
1896			w += sldns_wire2str_edns_option_code_print(s, sl,
1897				option_code);
1898			w += sldns_str_print(s, sl, ": ");
1899			w += print_hex_buf(s, sl, rdata, rdatalen);
1900			return w;
1901		}
1902		w += sldns_str_print(s, sl, " ; ");
1903		w += sldns_wire2str_edns_option_print(s, sl, option_code,
1904			rdata, option_len);
1905		rdata += option_len;
1906		rdatalen -= option_len;
1907	}
1908	return w;
1909}
1910
1911int sldns_wire2str_edns_scan(uint8_t** data, size_t* data_len, char** str,
1912        size_t* str_len, uint8_t* pkt, size_t pktlen)
1913{
1914	int w = 0;
1915	uint8_t ext_rcode, edns_version;
1916	uint16_t udpsize, edns_bits, rdatalen;
1917	w += sldns_str_print(str, str_len, "; EDNS:");
1918
1919	/* some input checks, domain name */
1920	if(*data_len < 1+10)
1921		return w + print_remainder_hex("Error malformed 0x",
1922			data, data_len, str, str_len);
1923	if(*data[0] != 0) {
1924		return w + print_remainder_hex("Error nonrootdname 0x",
1925			data, data_len, str, str_len);
1926	}
1927	(*data)++;
1928	(*data_len)--;
1929
1930	/* check type and read fixed contents */
1931	if(sldns_read_uint16((*data)) != LDNS_RR_TYPE_OPT) {
1932		return w + print_remainder_hex("Error nottypeOPT 0x",
1933			data, data_len, str, str_len);
1934	}
1935	udpsize = sldns_read_uint16((*data)+2);
1936	ext_rcode = (*data)[4];
1937	edns_version = (*data)[5];
1938	edns_bits = sldns_read_uint16((*data)+6);
1939	rdatalen = sldns_read_uint16((*data)+8);
1940	(*data)+=10;
1941	(*data_len)-=10;
1942
1943	w += sldns_str_print(str, str_len, " version: %u;",
1944		(unsigned)edns_version);
1945	w += sldns_str_print(str, str_len, " flags:");
1946	if((edns_bits & LDNS_EDNS_MASK_DO_BIT))
1947		w += sldns_str_print(str, str_len, " do");
1948	/* the extended rcode is the value set, shifted four bits,
1949	 * and or'd with the original rcode */
1950	if(ext_rcode) {
1951		int rc = ((int)ext_rcode)<<4;
1952		if(pkt && pktlen >= LDNS_HEADER_SIZE)
1953			rc |= LDNS_RCODE_WIRE(pkt);
1954		w += sldns_str_print(str, str_len, " ; ext-rcode: %d", rc);
1955	}
1956	w += sldns_str_print(str, str_len, " ; udp: %u", (unsigned)udpsize);
1957
1958	if(rdatalen) {
1959		if(*data_len < rdatalen) {
1960			w += sldns_str_print(str, str_len,
1961				" ; Error EDNS rdata too short; ");
1962			rdatalen = *data_len;
1963		}
1964		w += print_edns_opts(str, str_len, *data, rdatalen);
1965		(*data) += rdatalen;
1966		(*data_len) -= rdatalen;
1967	}
1968	w += sldns_str_print(str, str_len, "\n");
1969	return w;
1970}
1971