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