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