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