xref: /netbsd-src/external/bsd/nsd/dist/rdata.c (revision 811a4a0195236f69295602fbee687a174d42af9b)
1d83a80eeSchristos /*
2d83a80eeSchristos  * rdata.c -- RDATA conversion functions.
3d83a80eeSchristos  *
4d83a80eeSchristos  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
5d83a80eeSchristos  *
6d83a80eeSchristos  * See LICENSE for the license.
7d83a80eeSchristos  *
8d83a80eeSchristos  */
9d83a80eeSchristos 
10d83a80eeSchristos #include "config.h"
11d83a80eeSchristos 
12d83a80eeSchristos #include <sys/types.h>
13d83a80eeSchristos #include <sys/socket.h>
14d83a80eeSchristos #include <netinet/in.h>
15d83a80eeSchristos #include <arpa/inet.h>
16d83a80eeSchristos #include <ctype.h>
17d83a80eeSchristos #include <netdb.h>
18d83a80eeSchristos #include <stdlib.h>
19d83a80eeSchristos #include <string.h>
20d83a80eeSchristos #ifdef HAVE_STRINGS_H
21d83a80eeSchristos #include <strings.h>
22d83a80eeSchristos #endif
23d83a80eeSchristos 
24d83a80eeSchristos #include "rdata.h"
25d83a80eeSchristos #include "zonec.h"
26d83a80eeSchristos 
27d83a80eeSchristos /* Taken from RFC 4398, section 2.1.  */
28d83a80eeSchristos lookup_table_type dns_certificate_types[] = {
29d83a80eeSchristos /*	0		Reserved */
30d83a80eeSchristos 	{ 1, "PKIX" },	/* X.509 as per PKIX */
31d83a80eeSchristos 	{ 2, "SPKI" },	/* SPKI cert */
32d83a80eeSchristos 	{ 3, "PGP" },	/* OpenPGP packet */
33d83a80eeSchristos 	{ 4, "IPKIX" },	/* The URL of an X.509 data object */
34d83a80eeSchristos 	{ 5, "ISPKI" },	/* The URL of an SPKI certificate */
35d83a80eeSchristos 	{ 6, "IPGP" },	/* The fingerprint and URL of an OpenPGP packet */
36d83a80eeSchristos 	{ 7, "ACPKIX" },	/* Attribute Certificate */
37d83a80eeSchristos 	{ 8, "IACPKIX" },	/* The URL of an Attribute Certificate */
38d83a80eeSchristos 	{ 253, "URI" },	/* URI private */
39d83a80eeSchristos 	{ 254, "OID" },	/* OID private */
40d83a80eeSchristos /*	255 		Reserved */
41d83a80eeSchristos /* 	256-65279	Available for IANA assignment */
42d83a80eeSchristos /*	65280-65534	Experimental */
43d83a80eeSchristos /*	65535		Reserved */
44d83a80eeSchristos 	{ 0, NULL }
45d83a80eeSchristos };
46d83a80eeSchristos 
47d83a80eeSchristos /* Taken from RFC 2535, section 7.  */
48d83a80eeSchristos lookup_table_type dns_algorithms[] = {
49d83a80eeSchristos 	{ 1, "RSAMD5" },	/* RFC 2537 */
50d83a80eeSchristos 	{ 2, "DH" },		/* RFC 2539 */
51d83a80eeSchristos 	{ 3, "DSA" },		/* RFC 2536 */
52d83a80eeSchristos 	{ 4, "ECC" },
53d83a80eeSchristos 	{ 5, "RSASHA1" },	/* RFC 3110 */
54d83a80eeSchristos 	{ 6, "DSA-NSEC3-SHA1" },	/* RFC 5155 */
55d83a80eeSchristos 	{ 7, "RSASHA1-NSEC3-SHA1" },	/* RFC 5155 */
56d83a80eeSchristos 	{ 8, "RSASHA256" },		/* RFC 5702 */
57d83a80eeSchristos 	{ 10, "RSASHA512" },		/* RFC 5702 */
58d83a80eeSchristos 	{ 12, "ECC-GOST" },		/* RFC 5933 */
59d83a80eeSchristos 	{ 13, "ECDSAP256SHA256" },	/* RFC 6605 */
60d83a80eeSchristos 	{ 14, "ECDSAP384SHA384" },	/* RFC 6605 */
613fb62404Schristos 	{ 15, "ED25519" },		/* RFC 8080 */
623fb62404Schristos 	{ 16, "ED448" },		/* RFC 8080 */
63d83a80eeSchristos 	{ 252, "INDIRECT" },
64d83a80eeSchristos 	{ 253, "PRIVATEDNS" },
65d83a80eeSchristos 	{ 254, "PRIVATEOID" },
66d83a80eeSchristos 	{ 0, NULL }
67d83a80eeSchristos };
68d83a80eeSchristos 
69ee758998Schristos const char *svcparamkey_strs[] = {
70ee758998Schristos 		"mandatory", "alpn", "no-default-alpn", "port",
71*811a4a01Schristos 		"ipv4hint", "ech", "ipv6hint", "dohpath"
72ee758998Schristos 	};
73ee758998Schristos 
74d83a80eeSchristos typedef int (*rdata_to_string_type)(buffer_type *output,
75d83a80eeSchristos 				    rdata_atom_type rdata,
76d83a80eeSchristos 				    rr_type *rr);
77d83a80eeSchristos 
78d83a80eeSchristos static int
rdata_dname_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))79d83a80eeSchristos rdata_dname_to_string(buffer_type *output, rdata_atom_type rdata,
80d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
81d83a80eeSchristos {
82d83a80eeSchristos 	buffer_printf(output,
83d83a80eeSchristos 		      "%s",
84d83a80eeSchristos 		      dname_to_string(domain_dname(rdata_atom_domain(rdata)),
85d83a80eeSchristos 				      NULL));
86d83a80eeSchristos 	return 1;
87d83a80eeSchristos }
88d83a80eeSchristos 
89d83a80eeSchristos static int
rdata_dns_name_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))90d83a80eeSchristos rdata_dns_name_to_string(buffer_type *output, rdata_atom_type rdata,
91d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
92d83a80eeSchristos {
93d83a80eeSchristos 	const uint8_t *data = rdata_atom_data(rdata);
94d83a80eeSchristos 	size_t offset = 0;
95d83a80eeSchristos 	uint8_t length = data[offset];
96d83a80eeSchristos 	size_t i;
97d83a80eeSchristos 
98d83a80eeSchristos 	while (length > 0)
99d83a80eeSchristos 	{
100d83a80eeSchristos 		if (offset) /* concat label */
101d83a80eeSchristos 			buffer_printf(output, ".");
102d83a80eeSchristos 
103d83a80eeSchristos 		for (i = 1; i <= length; ++i) {
104d83a80eeSchristos 			uint8_t ch = data[i+offset];
105d83a80eeSchristos 
106d83a80eeSchristos 			if (ch=='.' || ch==';' || ch=='(' || ch==')' || ch=='\\') {
107d83a80eeSchristos 				buffer_printf(output, "\\%c", (char) ch);
108d83a80eeSchristos 			} else if (!isgraph((unsigned char) ch)) {
109d83a80eeSchristos 				buffer_printf(output, "\\%03u", (unsigned int) ch);
110d83a80eeSchristos 			} else if (isprint((unsigned char) ch)) {
111d83a80eeSchristos 				buffer_printf(output, "%c", (char) ch);
112d83a80eeSchristos 			} else {
113d83a80eeSchristos 				buffer_printf(output, "\\%03u", (unsigned int) ch);
114d83a80eeSchristos 			}
115d83a80eeSchristos 		}
116d83a80eeSchristos 		/* next label */
117d83a80eeSchristos 		offset = offset+length+1;
118d83a80eeSchristos 		length = data[offset];
119d83a80eeSchristos 	}
120d83a80eeSchristos 
121d83a80eeSchristos 	/* root label */
122d83a80eeSchristos 	buffer_printf(output, ".");
123d83a80eeSchristos 	return 1;
124d83a80eeSchristos }
125d83a80eeSchristos 
126d83a80eeSchristos static int
rdata_text_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))127d83a80eeSchristos rdata_text_to_string(buffer_type *output, rdata_atom_type rdata,
128d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
129d83a80eeSchristos {
130d83a80eeSchristos 	const uint8_t *data = rdata_atom_data(rdata);
131d83a80eeSchristos 	uint8_t length = data[0];
132d83a80eeSchristos 	size_t i;
133d83a80eeSchristos 
134d83a80eeSchristos 	buffer_printf(output, "\"");
135d83a80eeSchristos 	for (i = 1; i <= length; ++i) {
136d83a80eeSchristos 		char ch = (char) data[i];
137d83a80eeSchristos 		if (isprint((unsigned char)ch)) {
138d83a80eeSchristos 			if (ch == '"' || ch == '\\') {
139d83a80eeSchristos 				buffer_printf(output, "\\");
140d83a80eeSchristos 			}
141d83a80eeSchristos 			buffer_printf(output, "%c", ch);
142d83a80eeSchristos 		} else {
143d83a80eeSchristos 			buffer_printf(output, "\\%03u", (unsigned) data[i]);
144d83a80eeSchristos 		}
145d83a80eeSchristos 	}
146d83a80eeSchristos 	buffer_printf(output, "\"");
147d83a80eeSchristos 	return 1;
148d83a80eeSchristos }
149d83a80eeSchristos 
150d83a80eeSchristos static int
rdata_texts_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))151d83a80eeSchristos rdata_texts_to_string(buffer_type *output, rdata_atom_type rdata,
152d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
153d83a80eeSchristos {
154d83a80eeSchristos 	uint16_t pos = 0;
155d83a80eeSchristos 	const uint8_t *data = rdata_atom_data(rdata);
156d83a80eeSchristos 	uint16_t length = rdata_atom_size(rdata);
157d83a80eeSchristos 	size_t i;
158d83a80eeSchristos 
159d83a80eeSchristos 	while (pos < length && pos + data[pos] < length) {
160d83a80eeSchristos 		buffer_printf(output, "\"");
161d83a80eeSchristos 		for (i = 1; i <= data[pos]; ++i) {
162d83a80eeSchristos 			char ch = (char) data[pos + i];
163d83a80eeSchristos 			if (isprint((unsigned char)ch)) {
164d83a80eeSchristos 				if (ch == '"' || ch == '\\') {
165d83a80eeSchristos 					buffer_printf(output, "\\");
166d83a80eeSchristos 				}
167d83a80eeSchristos 				buffer_printf(output, "%c", ch);
168d83a80eeSchristos 			} else {
169d83a80eeSchristos 				buffer_printf(output, "\\%03u", (unsigned) data[pos+i]);
170d83a80eeSchristos 			}
171d83a80eeSchristos 		}
172d83a80eeSchristos 		pos += data[pos]+1;
173d83a80eeSchristos 		buffer_printf(output, pos < length?"\" ":"\"");
174d83a80eeSchristos 	}
175d83a80eeSchristos 	return 1;
176d83a80eeSchristos }
177d83a80eeSchristos 
178d83a80eeSchristos static int
rdata_long_text_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))179d83a80eeSchristos rdata_long_text_to_string(buffer_type *output, rdata_atom_type rdata,
180d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
181d83a80eeSchristos {
182d83a80eeSchristos 	const uint8_t *data = rdata_atom_data(rdata);
183d83a80eeSchristos 	uint16_t length = rdata_atom_size(rdata);
184d83a80eeSchristos 	size_t i;
185d83a80eeSchristos 
186d83a80eeSchristos 	buffer_printf(output, "\"");
187d83a80eeSchristos 	for (i = 0; i < length; ++i) {
188d83a80eeSchristos 		char ch = (char) data[i];
189d83a80eeSchristos 		if (isprint((unsigned char)ch)) {
190d83a80eeSchristos 			if (ch == '"' || ch == '\\') {
191d83a80eeSchristos 				buffer_printf(output, "\\");
192d83a80eeSchristos 			}
193d83a80eeSchristos 			buffer_printf(output, "%c", ch);
194d83a80eeSchristos 		} else {
195d83a80eeSchristos 			buffer_printf(output, "\\%03u", (unsigned) data[i]);
196d83a80eeSchristos 		}
197d83a80eeSchristos 	}
198d83a80eeSchristos 	buffer_printf(output, "\"");
199d83a80eeSchristos 	return 1;
200d83a80eeSchristos }
201d83a80eeSchristos 
202d83a80eeSchristos static int
rdata_tag_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))203d83a80eeSchristos rdata_tag_to_string(buffer_type *output, rdata_atom_type rdata,
204d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
205d83a80eeSchristos {
206d83a80eeSchristos 	const uint8_t *data = rdata_atom_data(rdata);
207d83a80eeSchristos 	uint8_t length = data[0];
208d83a80eeSchristos 	size_t i;
209d83a80eeSchristos 	for (i = 1; i <= length; ++i) {
210d83a80eeSchristos 		char ch = (char) data[i];
211d83a80eeSchristos 		if (isdigit((unsigned char)ch) || islower((unsigned char)ch))
212d83a80eeSchristos 			buffer_printf(output, "%c", ch);
213d83a80eeSchristos 		else	return 0;
214d83a80eeSchristos 	}
215d83a80eeSchristos 	return 1;
216d83a80eeSchristos }
217d83a80eeSchristos 
218d83a80eeSchristos static int
rdata_byte_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))219d83a80eeSchristos rdata_byte_to_string(buffer_type *output, rdata_atom_type rdata,
220d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
221d83a80eeSchristos {
222d83a80eeSchristos 	uint8_t data = *rdata_atom_data(rdata);
223d83a80eeSchristos 	buffer_printf(output, "%lu", (unsigned long) data);
224d83a80eeSchristos 	return 1;
225d83a80eeSchristos }
226d83a80eeSchristos 
227d83a80eeSchristos static int
rdata_short_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))228d83a80eeSchristos rdata_short_to_string(buffer_type *output, rdata_atom_type rdata,
229d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
230d83a80eeSchristos {
231d83a80eeSchristos 	uint16_t data = read_uint16(rdata_atom_data(rdata));
232d83a80eeSchristos 	buffer_printf(output, "%lu", (unsigned long) data);
233d83a80eeSchristos 	return 1;
234d83a80eeSchristos }
235d83a80eeSchristos 
236d83a80eeSchristos static int
rdata_long_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))237d83a80eeSchristos rdata_long_to_string(buffer_type *output, rdata_atom_type rdata,
238d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
239d83a80eeSchristos {
240d83a80eeSchristos 	uint32_t data = read_uint32(rdata_atom_data(rdata));
241d83a80eeSchristos 	buffer_printf(output, "%lu", (unsigned long) data);
242d83a80eeSchristos 	return 1;
243d83a80eeSchristos }
244d83a80eeSchristos 
245d83a80eeSchristos static int
rdata_a_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))246d83a80eeSchristos rdata_a_to_string(buffer_type *output, rdata_atom_type rdata,
247d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
248d83a80eeSchristos {
249d83a80eeSchristos 	int result = 0;
250d83a80eeSchristos 	char str[200];
251d83a80eeSchristos 	if (inet_ntop(AF_INET, rdata_atom_data(rdata), str, sizeof(str))) {
252d83a80eeSchristos 		buffer_printf(output, "%s", str);
253d83a80eeSchristos 		result = 1;
254d83a80eeSchristos 	}
255d83a80eeSchristos 	return result;
256d83a80eeSchristos }
257d83a80eeSchristos 
258d83a80eeSchristos static int
rdata_aaaa_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))259d83a80eeSchristos rdata_aaaa_to_string(buffer_type *output, rdata_atom_type rdata,
260d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
261d83a80eeSchristos {
262d83a80eeSchristos 	int result = 0;
263d83a80eeSchristos 	char str[200];
264d83a80eeSchristos 	if (inet_ntop(AF_INET6, rdata_atom_data(rdata), str, sizeof(str))) {
265d83a80eeSchristos 		buffer_printf(output, "%s", str);
266d83a80eeSchristos 		result = 1;
267d83a80eeSchristos 	}
268d83a80eeSchristos 	return result;
269d83a80eeSchristos }
270d83a80eeSchristos 
271d83a80eeSchristos static int
rdata_ilnp64_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))272d83a80eeSchristos rdata_ilnp64_to_string(buffer_type *output, rdata_atom_type rdata,
273d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
274d83a80eeSchristos {
275d83a80eeSchristos 	uint8_t* data = rdata_atom_data(rdata);
276d83a80eeSchristos 	uint16_t a1 = read_uint16(data);
277d83a80eeSchristos 	uint16_t a2 = read_uint16(data+2);
278d83a80eeSchristos 	uint16_t a3 = read_uint16(data+4);
279d83a80eeSchristos 	uint16_t a4 = read_uint16(data+6);
280d83a80eeSchristos 
281d83a80eeSchristos 	buffer_printf(output, "%.4x:%.4x:%.4x:%.4x", a1, a2, a3, a4);
282d83a80eeSchristos 	return 1;
283d83a80eeSchristos }
284d83a80eeSchristos 
285d83a80eeSchristos static int
rdata_eui48_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))286d83a80eeSchristos rdata_eui48_to_string(buffer_type *output, rdata_atom_type rdata,
287d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
288d83a80eeSchristos {
289d83a80eeSchristos 	uint8_t* data = rdata_atom_data(rdata);
290d83a80eeSchristos 	uint8_t a1 = data[0];
291d83a80eeSchristos 	uint8_t a2 = data[1];
292d83a80eeSchristos 	uint8_t a3 = data[2];
293d83a80eeSchristos 	uint8_t a4 = data[3];
294d83a80eeSchristos 	uint8_t a5 = data[4];
295d83a80eeSchristos 	uint8_t a6 = data[5];
296d83a80eeSchristos 
297d83a80eeSchristos 	buffer_printf(output, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
298d83a80eeSchristos 		a1, a2, a3, a4, a5, a6);
299d83a80eeSchristos 	return 1;
300d83a80eeSchristos }
301d83a80eeSchristos 
302d83a80eeSchristos static int
rdata_eui64_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))303d83a80eeSchristos rdata_eui64_to_string(buffer_type *output, rdata_atom_type rdata,
304d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
305d83a80eeSchristos {
306d83a80eeSchristos 	uint8_t* data = rdata_atom_data(rdata);
307d83a80eeSchristos 	uint8_t a1 = data[0];
308d83a80eeSchristos 	uint8_t a2 = data[1];
309d83a80eeSchristos 	uint8_t a3 = data[2];
310d83a80eeSchristos 	uint8_t a4 = data[3];
311d83a80eeSchristos 	uint8_t a5 = data[4];
312d83a80eeSchristos 	uint8_t a6 = data[5];
313d83a80eeSchristos 	uint8_t a7 = data[6];
314d83a80eeSchristos 	uint8_t a8 = data[7];
315d83a80eeSchristos 
316d83a80eeSchristos 	buffer_printf(output, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
317d83a80eeSchristos 		a1, a2, a3, a4, a5, a6, a7, a8);
318d83a80eeSchristos 	return 1;
319d83a80eeSchristos }
320d83a80eeSchristos 
321d83a80eeSchristos static int
rdata_rrtype_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))322d83a80eeSchristos rdata_rrtype_to_string(buffer_type *output, rdata_atom_type rdata,
323d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
324d83a80eeSchristos {
325d83a80eeSchristos 	uint16_t type = read_uint16(rdata_atom_data(rdata));
326d83a80eeSchristos 	buffer_printf(output, "%s", rrtype_to_string(type));
327d83a80eeSchristos 	return 1;
328d83a80eeSchristos }
329d83a80eeSchristos 
330d83a80eeSchristos static int
rdata_algorithm_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))331d83a80eeSchristos rdata_algorithm_to_string(buffer_type *output, rdata_atom_type rdata,
332d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
333d83a80eeSchristos {
334d83a80eeSchristos 	uint8_t id = *rdata_atom_data(rdata);
335d83a80eeSchristos 	buffer_printf(output, "%u", (unsigned) id);
336d83a80eeSchristos 	return 1;
337d83a80eeSchristos }
338d83a80eeSchristos 
339d83a80eeSchristos static int
rdata_certificate_type_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))340d83a80eeSchristos rdata_certificate_type_to_string(buffer_type *output, rdata_atom_type rdata,
341d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
342d83a80eeSchristos {
343d83a80eeSchristos 	uint16_t id = read_uint16(rdata_atom_data(rdata));
344d83a80eeSchristos 	lookup_table_type *type
345d83a80eeSchristos 		= lookup_by_id(dns_certificate_types, id);
346d83a80eeSchristos 	if (type) {
347d83a80eeSchristos 		buffer_printf(output, "%s", type->name);
348d83a80eeSchristos 	} else {
349d83a80eeSchristos 		buffer_printf(output, "%u", (unsigned) id);
350d83a80eeSchristos 	}
351d83a80eeSchristos 	return 1;
352d83a80eeSchristos }
353d83a80eeSchristos 
354d83a80eeSchristos static int
rdata_period_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))355d83a80eeSchristos rdata_period_to_string(buffer_type *output, rdata_atom_type rdata,
356d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
357d83a80eeSchristos {
358d83a80eeSchristos 	uint32_t period = read_uint32(rdata_atom_data(rdata));
359d83a80eeSchristos 	buffer_printf(output, "%lu", (unsigned long) period);
360d83a80eeSchristos 	return 1;
361d83a80eeSchristos }
362d83a80eeSchristos 
363d83a80eeSchristos static int
rdata_time_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))364d83a80eeSchristos rdata_time_to_string(buffer_type *output, rdata_atom_type rdata,
365d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
366d83a80eeSchristos {
367d83a80eeSchristos 	int result = 0;
368d83a80eeSchristos 	time_t time = (time_t) read_uint32(rdata_atom_data(rdata));
369d83a80eeSchristos 	struct tm *tm = gmtime(&time);
370d83a80eeSchristos 	char buf[15];
371d83a80eeSchristos 	if (strftime(buf, sizeof(buf), "%Y%m%d%H%M%S", tm)) {
372d83a80eeSchristos 		buffer_printf(output, "%s", buf);
373d83a80eeSchristos 		result = 1;
374d83a80eeSchristos 	}
375d83a80eeSchristos 	return result;
376d83a80eeSchristos }
377d83a80eeSchristos 
378d83a80eeSchristos static int
rdata_base32_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))379d83a80eeSchristos rdata_base32_to_string(buffer_type *output, rdata_atom_type rdata,
380d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
381d83a80eeSchristos {
382d83a80eeSchristos 	int length;
383d83a80eeSchristos 	size_t size = rdata_atom_size(rdata);
384d83a80eeSchristos 	if(size == 0) {
385d83a80eeSchristos 		buffer_write(output, "-", 1);
386d83a80eeSchristos 		return 1;
387d83a80eeSchristos 	}
388d83a80eeSchristos 	size -= 1; /* remove length byte from count */
389d83a80eeSchristos 	buffer_reserve(output, size * 2 + 1);
390d83a80eeSchristos 	length = b32_ntop(rdata_atom_data(rdata)+1, size,
391d83a80eeSchristos 			  (char *) buffer_current(output), size * 2);
392d83a80eeSchristos 	if (length > 0) {
393d83a80eeSchristos 		buffer_skip(output, length);
394d83a80eeSchristos 	}
395d83a80eeSchristos 	return length != -1;
396d83a80eeSchristos }
397d83a80eeSchristos 
398d83a80eeSchristos static int
rdata_base64_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))399d83a80eeSchristos rdata_base64_to_string(buffer_type *output, rdata_atom_type rdata,
400d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
401d83a80eeSchristos {
402d83a80eeSchristos 	int length;
403d83a80eeSchristos 	size_t size = rdata_atom_size(rdata);
4043fb62404Schristos 	if(size == 0) {
4053fb62404Schristos 		/* single zero represents empty buffer */
4063fb62404Schristos 		buffer_write(output, "0", 1);
407d83a80eeSchristos 		return 1;
4083fb62404Schristos 	}
409d83a80eeSchristos 	buffer_reserve(output, size * 2 + 1);
410d83a80eeSchristos 	length = b64_ntop(rdata_atom_data(rdata), size,
411d83a80eeSchristos 			  (char *) buffer_current(output), size * 2);
412d83a80eeSchristos 	if (length > 0) {
413d83a80eeSchristos 		buffer_skip(output, length);
414d83a80eeSchristos 	}
415d83a80eeSchristos 	return length != -1;
416d83a80eeSchristos }
417d83a80eeSchristos 
418d83a80eeSchristos static void
hex_to_string(buffer_type * output,const uint8_t * data,size_t size)419d83a80eeSchristos hex_to_string(buffer_type *output, const uint8_t *data, size_t size)
420d83a80eeSchristos {
421d83a80eeSchristos 	static const char hexdigits[] = {
422d83a80eeSchristos 		'0', '1', '2', '3', '4', '5', '6', '7',
423d83a80eeSchristos 		'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
424d83a80eeSchristos 	};
425d83a80eeSchristos 	size_t i;
426d83a80eeSchristos 
427d83a80eeSchristos 	buffer_reserve(output, size * 2);
428d83a80eeSchristos 	for (i = 0; i < size; ++i) {
429d83a80eeSchristos 		uint8_t octet = *data++;
430d83a80eeSchristos 		buffer_write_u8(output, hexdigits[octet >> 4]);
431d83a80eeSchristos 		buffer_write_u8(output, hexdigits[octet & 0x0f]);
432d83a80eeSchristos 	}
433d83a80eeSchristos }
434d83a80eeSchristos 
435d83a80eeSchristos static int
rdata_hex_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))436d83a80eeSchristos rdata_hex_to_string(buffer_type *output, rdata_atom_type rdata,
437d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
438d83a80eeSchristos {
4393fb62404Schristos 	if(rdata_atom_size(rdata) == 0) {
4403fb62404Schristos 		/* single zero represents empty buffer, such as CDS deletes */
4413fb62404Schristos 		buffer_printf(output, "0");
4423fb62404Schristos 	} else {
443d83a80eeSchristos 		hex_to_string(output, rdata_atom_data(rdata), rdata_atom_size(rdata));
4443fb62404Schristos 	}
445d83a80eeSchristos 	return 1;
446d83a80eeSchristos }
447d83a80eeSchristos 
448d83a80eeSchristos static int
rdata_hexlen_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))449d83a80eeSchristos rdata_hexlen_to_string(buffer_type *output, rdata_atom_type rdata,
450d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
451d83a80eeSchristos {
452d83a80eeSchristos 	if(rdata_atom_size(rdata) <= 1) {
453d83a80eeSchristos 		/* NSEC3 salt hex can be empty */
454d83a80eeSchristos 		buffer_printf(output, "-");
455d83a80eeSchristos 		return 1;
456d83a80eeSchristos 	}
457d83a80eeSchristos 	hex_to_string(output, rdata_atom_data(rdata)+1, rdata_atom_size(rdata)-1);
458d83a80eeSchristos 	return 1;
459d83a80eeSchristos }
460d83a80eeSchristos 
461d83a80eeSchristos static int
rdata_nsap_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))462d83a80eeSchristos rdata_nsap_to_string(buffer_type *output, rdata_atom_type rdata,
463d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
464d83a80eeSchristos {
465d83a80eeSchristos 	buffer_printf(output, "0x");
466d83a80eeSchristos 	hex_to_string(output, rdata_atom_data(rdata), rdata_atom_size(rdata));
467d83a80eeSchristos 	return 1;
468d83a80eeSchristos }
469d83a80eeSchristos 
470d83a80eeSchristos static int
rdata_apl_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))471d83a80eeSchristos rdata_apl_to_string(buffer_type *output, rdata_atom_type rdata,
472d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
473d83a80eeSchristos {
474d83a80eeSchristos 	int result = 0;
475d83a80eeSchristos 	buffer_type packet;
476d83a80eeSchristos 
477d83a80eeSchristos 	buffer_create_from(
478d83a80eeSchristos 		&packet, rdata_atom_data(rdata), rdata_atom_size(rdata));
479d83a80eeSchristos 
480d83a80eeSchristos 	if (buffer_available(&packet, 4)) {
481d83a80eeSchristos 		uint16_t address_family = buffer_read_u16(&packet);
482d83a80eeSchristos 		uint8_t prefix = buffer_read_u8(&packet);
483d83a80eeSchristos 		uint8_t length = buffer_read_u8(&packet);
484d83a80eeSchristos 		int negated = length & APL_NEGATION_MASK;
485d83a80eeSchristos 		int af = -1;
486d83a80eeSchristos 
487d83a80eeSchristos 		length &= APL_LENGTH_MASK;
488d83a80eeSchristos 		switch (address_family) {
489d83a80eeSchristos 		case 1: af = AF_INET; break;
490d83a80eeSchristos 		case 2: af = AF_INET6; break;
491d83a80eeSchristos 		}
492d83a80eeSchristos 		if (af != -1 && buffer_available(&packet, length)) {
493d83a80eeSchristos 			char text_address[1000];
494d83a80eeSchristos 			uint8_t address[128];
495d83a80eeSchristos 			memset(address, 0, sizeof(address));
496d83a80eeSchristos 			buffer_read(&packet, address, length);
497d83a80eeSchristos 			if (inet_ntop(af, address, text_address, sizeof(text_address))) {
498d83a80eeSchristos 				buffer_printf(output, "%s%d:%s/%d",
499d83a80eeSchristos 					      negated ? "!" : "",
500d83a80eeSchristos 					      (int) address_family,
501d83a80eeSchristos 					      text_address,
502d83a80eeSchristos 					      (int) prefix);
503d83a80eeSchristos 				result = 1;
504d83a80eeSchristos 			}
505d83a80eeSchristos 		}
506d83a80eeSchristos 	}
507d83a80eeSchristos 	return result;
508d83a80eeSchristos }
509d83a80eeSchristos 
510d83a80eeSchristos static int
rdata_services_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))511d83a80eeSchristos rdata_services_to_string(buffer_type *output, rdata_atom_type rdata,
512d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
513d83a80eeSchristos {
514d83a80eeSchristos 	int result = 0;
515d83a80eeSchristos 	buffer_type packet;
516d83a80eeSchristos 
517d83a80eeSchristos 	buffer_create_from(
518d83a80eeSchristos 		&packet, rdata_atom_data(rdata), rdata_atom_size(rdata));
519d83a80eeSchristos 
520d83a80eeSchristos 	if (buffer_available(&packet, 1)) {
521d83a80eeSchristos 		uint8_t protocol_number = buffer_read_u8(&packet);
522d83a80eeSchristos 		ssize_t bitmap_size = buffer_remaining(&packet);
523d83a80eeSchristos 		uint8_t *bitmap = buffer_current(&packet);
524d83a80eeSchristos 		struct protoent *proto = getprotobynumber(protocol_number);
525d83a80eeSchristos 
526d83a80eeSchristos 		if (proto) {
527d83a80eeSchristos 			int i;
528d83a80eeSchristos 
529d83a80eeSchristos 			buffer_printf(output, "%s", proto->p_name);
530d83a80eeSchristos 
531d83a80eeSchristos 			for (i = 0; i < bitmap_size * 8; ++i) {
532d83a80eeSchristos 				if (get_bit(bitmap, i)) {
533d83a80eeSchristos 					struct servent *service = getservbyport((int)htons(i), proto->p_name);
534d83a80eeSchristos 					if (service) {
535d83a80eeSchristos 						buffer_printf(output, " %s", service->s_name);
536d83a80eeSchristos 					} else {
537d83a80eeSchristos 						buffer_printf(output, " %d", i);
538d83a80eeSchristos 					}
539d83a80eeSchristos 				}
540d83a80eeSchristos 			}
541d83a80eeSchristos 			buffer_skip(&packet, bitmap_size);
542d83a80eeSchristos 			result = 1;
543d83a80eeSchristos 		}
544d83a80eeSchristos 	}
545d83a80eeSchristos 	return result;
546d83a80eeSchristos }
547d83a80eeSchristos 
548d83a80eeSchristos static int
rdata_ipsecgateway_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * rr)549d83a80eeSchristos rdata_ipsecgateway_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* rr)
550d83a80eeSchristos {
551d83a80eeSchristos 	int gateway_type = rdata_atom_data(rr->rdatas[1])[0];
552d83a80eeSchristos 	switch(gateway_type) {
553d83a80eeSchristos 	case IPSECKEY_NOGATEWAY:
554d83a80eeSchristos 		buffer_printf(output, ".");
555d83a80eeSchristos 		break;
556d83a80eeSchristos 	case IPSECKEY_IP4:
557d83a80eeSchristos 		rdata_a_to_string(output, rdata, rr);
558d83a80eeSchristos 		break;
559d83a80eeSchristos 	case IPSECKEY_IP6:
560d83a80eeSchristos 		rdata_aaaa_to_string(output, rdata, rr);
561d83a80eeSchristos 		break;
562d83a80eeSchristos 	case IPSECKEY_DNAME:
563d83a80eeSchristos 		{
564d83a80eeSchristos 			region_type* temp = region_create(xalloc, free);
565d83a80eeSchristos 			const dname_type* d = dname_make(temp,
566d83a80eeSchristos 				rdata_atom_data(rdata), 0);
567d83a80eeSchristos 			if(!d) {
568d83a80eeSchristos 				region_destroy(temp);
569d83a80eeSchristos 				return 0;
570d83a80eeSchristos 			}
571d83a80eeSchristos 			buffer_printf(output, "%s", dname_to_string(d, NULL));
572d83a80eeSchristos 			region_destroy(temp);
573d83a80eeSchristos 		}
574d83a80eeSchristos 		break;
575d83a80eeSchristos 	default:
576d83a80eeSchristos 		return 0;
577d83a80eeSchristos 	}
578d83a80eeSchristos 	return 1;
579d83a80eeSchristos }
580d83a80eeSchristos 
581d83a80eeSchristos static int
rdata_nxt_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))582d83a80eeSchristos rdata_nxt_to_string(buffer_type *output, rdata_atom_type rdata,
583d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
584d83a80eeSchristos {
585d83a80eeSchristos 	size_t i;
586d83a80eeSchristos 	uint8_t *bitmap = rdata_atom_data(rdata);
587d83a80eeSchristos 	size_t bitmap_size = rdata_atom_size(rdata);
588d83a80eeSchristos 
589d83a80eeSchristos 	for (i = 0; i < bitmap_size * 8; ++i) {
590d83a80eeSchristos 		if (get_bit(bitmap, i)) {
591d83a80eeSchristos 			buffer_printf(output, "%s ", rrtype_to_string(i));
592d83a80eeSchristos 		}
593d83a80eeSchristos 	}
594d83a80eeSchristos 
595d83a80eeSchristos 	buffer_skip(output, -1);
596d83a80eeSchristos 
597d83a80eeSchristos 	return 1;
598d83a80eeSchristos }
599d83a80eeSchristos 
600d83a80eeSchristos static int
rdata_nsec_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))601d83a80eeSchristos rdata_nsec_to_string(buffer_type *output, rdata_atom_type rdata,
602d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
603d83a80eeSchristos {
604d83a80eeSchristos 	size_t saved_position = buffer_position(output);
605d83a80eeSchristos 	buffer_type packet;
606d83a80eeSchristos 	int insert_space = 0;
607d83a80eeSchristos 
608d83a80eeSchristos 	buffer_create_from(
609d83a80eeSchristos 		&packet, rdata_atom_data(rdata), rdata_atom_size(rdata));
610d83a80eeSchristos 
611d83a80eeSchristos 	while (buffer_available(&packet, 2)) {
612d83a80eeSchristos 		uint8_t window = buffer_read_u8(&packet);
613d83a80eeSchristos 		uint8_t bitmap_size = buffer_read_u8(&packet);
614d83a80eeSchristos 		uint8_t *bitmap = buffer_current(&packet);
615d83a80eeSchristos 		int i;
616d83a80eeSchristos 
617d83a80eeSchristos 		if (!buffer_available(&packet, bitmap_size)) {
618d83a80eeSchristos 			buffer_set_position(output, saved_position);
619d83a80eeSchristos 			return 0;
620d83a80eeSchristos 		}
621d83a80eeSchristos 
622d83a80eeSchristos 		for (i = 0; i < bitmap_size * 8; ++i) {
623d83a80eeSchristos 			if (get_bit(bitmap, i)) {
624d83a80eeSchristos 				buffer_printf(output,
625d83a80eeSchristos 					      "%s%s",
626d83a80eeSchristos 					      insert_space ? " " : "",
627d83a80eeSchristos 					      rrtype_to_string(
628d83a80eeSchristos 						      window * 256 + i));
629d83a80eeSchristos 				insert_space = 1;
630d83a80eeSchristos 			}
631d83a80eeSchristos 		}
632d83a80eeSchristos 		buffer_skip(&packet, bitmap_size);
633d83a80eeSchristos 	}
634d83a80eeSchristos 
635d83a80eeSchristos 	return 1;
636d83a80eeSchristos }
637d83a80eeSchristos 
638d83a80eeSchristos static int
rdata_loc_to_string(buffer_type * ATTR_UNUSED (output),rdata_atom_type ATTR_UNUSED (rdata),rr_type * ATTR_UNUSED (rr))639d83a80eeSchristos rdata_loc_to_string(buffer_type *ATTR_UNUSED(output),
640d83a80eeSchristos 		    rdata_atom_type ATTR_UNUSED(rdata),
641d83a80eeSchristos 		    rr_type* ATTR_UNUSED(rr))
642d83a80eeSchristos {
643d83a80eeSchristos 	/*
644d83a80eeSchristos 	 * Returning 0 forces the record to be printed in unknown
645d83a80eeSchristos 	 * format.
646d83a80eeSchristos 	 */
647d83a80eeSchristos 	return 0;
648d83a80eeSchristos }
649d83a80eeSchristos 
650ee758998Schristos static void
buffer_print_svcparamkey(buffer_type * output,uint16_t svcparamkey)651ee758998Schristos buffer_print_svcparamkey(buffer_type *output, uint16_t svcparamkey)
652ee758998Schristos {
653ee758998Schristos 	if (svcparamkey < SVCPARAMKEY_COUNT)
654ee758998Schristos 		buffer_printf(output, "%s", svcparamkey_strs[svcparamkey]);
655ee758998Schristos 	else
656ee758998Schristos 		buffer_printf(output, "key%d", (int)svcparamkey);
657ee758998Schristos }
658ee758998Schristos 
659ee758998Schristos static int
rdata_svcparam_port_to_string(buffer_type * output,uint16_t val_len,uint16_t * data)660ee758998Schristos rdata_svcparam_port_to_string(buffer_type *output, uint16_t val_len,
661ee758998Schristos 	uint16_t *data)
662ee758998Schristos {
663ee758998Schristos 	if (val_len != 2)
664ee758998Schristos 		return 0; /* wireformat error, a short is 2 bytes */
665ee758998Schristos 	buffer_printf(output, "=%d", (int)ntohs(data[0]));
666ee758998Schristos 	return 1;
667ee758998Schristos }
668ee758998Schristos 
669ee758998Schristos static int
rdata_svcparam_ipv4hint_to_string(buffer_type * output,uint16_t val_len,uint16_t * data)670ee758998Schristos rdata_svcparam_ipv4hint_to_string(buffer_type *output, uint16_t val_len,
671ee758998Schristos 	uint16_t *data)
672ee758998Schristos {
673ee758998Schristos 	char ip_str[INET_ADDRSTRLEN + 1];
674ee758998Schristos 
675ee758998Schristos 	assert(val_len > 0); /* Guaranteed by rdata_svcparam_to_string */
676ee758998Schristos 
677ee758998Schristos 	if ((val_len % IP4ADDRLEN) == 0) {
678ee758998Schristos 		if (inet_ntop(AF_INET, data, ip_str, sizeof(ip_str)) == NULL)
679ee758998Schristos 			return 0; /* wireformat error, incorrect size or inet family */
680ee758998Schristos 
681ee758998Schristos 		buffer_printf(output, "=%s", ip_str);
682ee758998Schristos 		data += IP4ADDRLEN / sizeof(uint16_t);
683ee758998Schristos 
684ee758998Schristos 		while ((val_len -= IP4ADDRLEN) > 0) {
685ee758998Schristos 			if (inet_ntop(AF_INET, data, ip_str, sizeof(ip_str)) == NULL)
686ee758998Schristos 				return 0; /* wireformat error, incorrect size or inet family */
687ee758998Schristos 
688ee758998Schristos 			buffer_printf(output, ",%s", ip_str);
689ee758998Schristos 			data += IP4ADDRLEN / sizeof(uint16_t);
690ee758998Schristos 		}
691ee758998Schristos 		return 1;
692ee758998Schristos 	} else
693ee758998Schristos 		return 0;
694ee758998Schristos }
695ee758998Schristos 
696ee758998Schristos static int
rdata_svcparam_ipv6hint_to_string(buffer_type * output,uint16_t val_len,uint16_t * data)697ee758998Schristos rdata_svcparam_ipv6hint_to_string(buffer_type *output, uint16_t val_len,
698ee758998Schristos 	uint16_t *data)
699ee758998Schristos {
700ee758998Schristos 	char ip_str[INET6_ADDRSTRLEN + 1];
701ee758998Schristos 
702ee758998Schristos 	assert(val_len > 0); /* Guaranteed by rdata_svcparam_to_string */
703ee758998Schristos 
704ee758998Schristos 	if ((val_len % IP6ADDRLEN) == 0) {
705ee758998Schristos 		if (inet_ntop(AF_INET6, data, ip_str, sizeof(ip_str)) == NULL)
706ee758998Schristos 			return 0; /* wireformat error, incorrect size or inet family */
707ee758998Schristos 
708ee758998Schristos 		buffer_printf(output, "=%s", ip_str);
709ee758998Schristos 		data += IP6ADDRLEN / sizeof(uint16_t);
710ee758998Schristos 
711ee758998Schristos 		while ((val_len -= IP6ADDRLEN) > 0) {
712ee758998Schristos 			if (inet_ntop(AF_INET6, data, ip_str, sizeof(ip_str)) == NULL)
713ee758998Schristos 				return 0; /* wireformat error, incorrect size or inet family */
714ee758998Schristos 
715ee758998Schristos 			buffer_printf(output, ",%s", ip_str);
716ee758998Schristos 			data += IP6ADDRLEN / sizeof(uint16_t);
717ee758998Schristos 		}
718ee758998Schristos 		return 1;
719ee758998Schristos 	} else
720ee758998Schristos 		return 0;
721ee758998Schristos }
722ee758998Schristos 
723ee758998Schristos static int
rdata_svcparam_mandatory_to_string(buffer_type * output,uint16_t val_len,uint16_t * data)724ee758998Schristos rdata_svcparam_mandatory_to_string(buffer_type *output, uint16_t val_len,
725ee758998Schristos 	uint16_t *data)
726ee758998Schristos {
727ee758998Schristos 	assert(val_len > 0); /* Guaranteed by rdata_svcparam_to_string */
728ee758998Schristos 
729ee758998Schristos 	if (val_len % sizeof(uint16_t))
730ee758998Schristos 		return 0; /* wireformat error, val_len must be multiple of shorts */
731ee758998Schristos 	buffer_write_u8(output, '=');
732ee758998Schristos 	buffer_print_svcparamkey(output, ntohs(*data));
733ee758998Schristos 	data += 1;
734ee758998Schristos 
735ee758998Schristos 	while ((val_len -= sizeof(uint16_t))) {
736ee758998Schristos 		buffer_write_u8(output, ',');
737ee758998Schristos 		buffer_print_svcparamkey(output, ntohs(*data));
738ee758998Schristos 		data += 1;
739ee758998Schristos 	}
740ee758998Schristos 
741ee758998Schristos 	return 1;
742ee758998Schristos }
743ee758998Schristos 
744ee758998Schristos static int
rdata_svcparam_ech_to_string(buffer_type * output,uint16_t val_len,uint16_t * data)745ee758998Schristos rdata_svcparam_ech_to_string(buffer_type *output, uint16_t val_len,
746ee758998Schristos 	uint16_t *data)
747ee758998Schristos {
748ee758998Schristos 	int length;
749ee758998Schristos 
750ee758998Schristos 	assert(val_len > 0); /* Guaranteed by rdata_svcparam_to_string */
751ee758998Schristos 
752ee758998Schristos 	buffer_write_u8(output, '=');
753ee758998Schristos 
754ee758998Schristos 	buffer_reserve(output, val_len * 2 + 1);
755ee758998Schristos 	length = b64_ntop((uint8_t*) data, val_len,
756ee758998Schristos 			  (char *) buffer_current(output), val_len * 2);
757ee758998Schristos 	if (length > 0) {
758ee758998Schristos 		buffer_skip(output, length);
759ee758998Schristos 	}
760ee758998Schristos 
761ee758998Schristos 	return length != -1;
762ee758998Schristos }
763ee758998Schristos 
764ee758998Schristos static int
rdata_svcparam_alpn_to_string(buffer_type * output,uint16_t val_len,uint16_t * data)765ee758998Schristos rdata_svcparam_alpn_to_string(buffer_type *output, uint16_t val_len,
766ee758998Schristos 	uint16_t *data)
767ee758998Schristos {
768ee758998Schristos 	uint8_t *dp = (void *)data;
769ee758998Schristos 
770ee758998Schristos 	assert(val_len > 0); /* Guaranteed by rdata_svcparam_to_string */
771ee758998Schristos 
772ee758998Schristos 	buffer_write_u8(output, '=');
773ee758998Schristos 	buffer_write_u8(output, '"');
774ee758998Schristos 	while (val_len) {
775ee758998Schristos 		uint8_t i, str_len = *dp++;
776ee758998Schristos 
777ee758998Schristos 		if (str_len > --val_len)
778ee758998Schristos 			return 0;
779ee758998Schristos 
780ee758998Schristos 		for (i = 0; i < str_len; i++) {
781ee758998Schristos 			if (dp[i] == '"' || dp[i] == '\\')
782ee758998Schristos 				buffer_printf(output, "\\\\\\%c", dp[i]);
783ee758998Schristos 
784ee758998Schristos 			else if (dp[i] == ',')
785ee758998Schristos 				buffer_printf(output, "\\\\%c", dp[i]);
786ee758998Schristos 
787ee758998Schristos 			else if (!isprint(dp[i]))
788ee758998Schristos 				buffer_printf(output, "\\%03u", (unsigned) dp[i]);
789ee758998Schristos 
790ee758998Schristos 			else
791ee758998Schristos 				buffer_write_u8(output, dp[i]);
792ee758998Schristos 		}
793ee758998Schristos 		dp += str_len;
794ee758998Schristos 		if ((val_len -= str_len))
795ee758998Schristos 			buffer_write_u8(output, ',');
796ee758998Schristos 	}
797ee758998Schristos 	buffer_write_u8(output, '"');
798ee758998Schristos 	return 1;
799ee758998Schristos }
800ee758998Schristos 
801ee758998Schristos static int
rdata_svcparam_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))802ee758998Schristos rdata_svcparam_to_string(buffer_type *output, rdata_atom_type rdata,
803ee758998Schristos 	rr_type* ATTR_UNUSED(rr))
804ee758998Schristos {
805ee758998Schristos 	uint16_t  size = rdata_atom_size(rdata);
806ee758998Schristos 	uint16_t* data = (uint16_t *)rdata_atom_data(rdata);
807ee758998Schristos 	uint16_t  svcparamkey, val_len;
808ee758998Schristos 	uint8_t*  dp;
809ee758998Schristos 	size_t i;
810ee758998Schristos 
811ee758998Schristos 	if (size < 4)
812ee758998Schristos 		return 0;
813ee758998Schristos 	svcparamkey = ntohs(data[0]);
814ee758998Schristos 
815ee758998Schristos 	buffer_print_svcparamkey(output, svcparamkey);
816ee758998Schristos 	val_len = ntohs(data[1]);
817ee758998Schristos 	if (size != val_len + 4)
818ee758998Schristos 		return 0; /* wireformat error */
819ee758998Schristos 	if (!val_len) {
820ee758998Schristos 		/* Some SvcParams MUST have values */
821ee758998Schristos 		switch (svcparamkey) {
822ee758998Schristos 		case SVCB_KEY_ALPN:
823ee758998Schristos 		case SVCB_KEY_PORT:
824ee758998Schristos 		case SVCB_KEY_IPV4HINT:
825ee758998Schristos 		case SVCB_KEY_IPV6HINT:
826ee758998Schristos 		case SVCB_KEY_MANDATORY:
827*811a4a01Schristos 		case SVCB_KEY_DOHPATH:
828ee758998Schristos 			return 0;
829ee758998Schristos 		default:
830ee758998Schristos 			return 1;
831ee758998Schristos 		}
832ee758998Schristos 	}
833ee758998Schristos 	switch (svcparamkey) {
834ee758998Schristos 	case SVCB_KEY_PORT:
835ee758998Schristos 		return rdata_svcparam_port_to_string(output, val_len, data+2);
836ee758998Schristos 	case SVCB_KEY_IPV4HINT:
837ee758998Schristos 		return rdata_svcparam_ipv4hint_to_string(output, val_len, data+2);
838ee758998Schristos 	case SVCB_KEY_IPV6HINT:
839ee758998Schristos 		return rdata_svcparam_ipv6hint_to_string(output, val_len, data+2);
840ee758998Schristos 	case SVCB_KEY_MANDATORY:
841ee758998Schristos 		return rdata_svcparam_mandatory_to_string(output, val_len, data+2);
842ee758998Schristos 	case SVCB_KEY_NO_DEFAULT_ALPN:
843ee758998Schristos 		return 0; /* wireformat error, should not have a value */
844ee758998Schristos 	case SVCB_KEY_ALPN:
845ee758998Schristos 		return rdata_svcparam_alpn_to_string(output, val_len, data+2);
846ee758998Schristos 	case SVCB_KEY_ECH:
847ee758998Schristos 		return rdata_svcparam_ech_to_string(output, val_len, data+2);
848*811a4a01Schristos 	case SVCB_KEY_DOHPATH:
849*811a4a01Schristos 		/* fallthrough */
850ee758998Schristos 	default:
851ee758998Schristos 		buffer_write(output, "=\"", 2);
852ee758998Schristos 		dp = (void*) (data + 2);
853ee758998Schristos 
854ee758998Schristos 		for (i = 0; i < val_len; i++) {
855ee758998Schristos 			if (dp[i] == '"' || dp[i] == '\\')
856ee758998Schristos 				buffer_printf(output, "\\%c", dp[i]);
857ee758998Schristos 
858ee758998Schristos 			else if (!isprint(dp[i]))
859ee758998Schristos 				buffer_printf(output, "\\%03u", (unsigned) dp[i]);
860ee758998Schristos 
861ee758998Schristos 			else
862ee758998Schristos 				buffer_write_u8(output, dp[i]);
863ee758998Schristos 		}
864ee758998Schristos 		buffer_write_u8(output, '"');
865ee758998Schristos 		break;
866ee758998Schristos 	}
867ee758998Schristos 	return 1;
868ee758998Schristos }
869ee758998Schristos 
870d83a80eeSchristos static int
rdata_unknown_to_string(buffer_type * output,rdata_atom_type rdata,rr_type * ATTR_UNUSED (rr))871d83a80eeSchristos rdata_unknown_to_string(buffer_type *output, rdata_atom_type rdata,
872d83a80eeSchristos 	rr_type* ATTR_UNUSED(rr))
873d83a80eeSchristos {
874d83a80eeSchristos  	uint16_t size = rdata_atom_size(rdata);
875d83a80eeSchristos  	buffer_printf(output, "\\# %lu ", (unsigned long) size);
876d83a80eeSchristos 	hex_to_string(output, rdata_atom_data(rdata), size);
877d83a80eeSchristos 	return 1;
878d83a80eeSchristos }
879d83a80eeSchristos 
880d83a80eeSchristos static rdata_to_string_type rdata_to_string_table[RDATA_ZF_UNKNOWN + 1] = {
881d83a80eeSchristos 	rdata_dname_to_string,
882d83a80eeSchristos 	rdata_dns_name_to_string,
883d83a80eeSchristos 	rdata_text_to_string,
884d83a80eeSchristos 	rdata_texts_to_string,
885d83a80eeSchristos 	rdata_byte_to_string,
886d83a80eeSchristos 	rdata_short_to_string,
887d83a80eeSchristos 	rdata_long_to_string,
888d83a80eeSchristos 	rdata_a_to_string,
889d83a80eeSchristos 	rdata_aaaa_to_string,
890d83a80eeSchristos 	rdata_rrtype_to_string,
891d83a80eeSchristos 	rdata_algorithm_to_string,
892d83a80eeSchristos 	rdata_certificate_type_to_string,
893d83a80eeSchristos 	rdata_period_to_string,
894d83a80eeSchristos 	rdata_time_to_string,
895d83a80eeSchristos 	rdata_base64_to_string,
896d83a80eeSchristos 	rdata_base32_to_string,
897d83a80eeSchristos 	rdata_hex_to_string,
898d83a80eeSchristos 	rdata_hexlen_to_string,
899d83a80eeSchristos 	rdata_nsap_to_string,
900d83a80eeSchristos 	rdata_apl_to_string,
901d83a80eeSchristos 	rdata_ipsecgateway_to_string,
902d83a80eeSchristos 	rdata_services_to_string,
903d83a80eeSchristos 	rdata_nxt_to_string,
904d83a80eeSchristos 	rdata_nsec_to_string,
905d83a80eeSchristos 	rdata_loc_to_string,
906d83a80eeSchristos 	rdata_ilnp64_to_string,
907d83a80eeSchristos 	rdata_eui48_to_string,
908d83a80eeSchristos 	rdata_eui64_to_string,
909d83a80eeSchristos 	rdata_long_text_to_string,
910d83a80eeSchristos 	rdata_tag_to_string,
911ee758998Schristos 	rdata_svcparam_to_string,
912d83a80eeSchristos 	rdata_unknown_to_string
913d83a80eeSchristos };
914d83a80eeSchristos 
915d83a80eeSchristos int
rdata_atom_to_string(buffer_type * output,rdata_zoneformat_type type,rdata_atom_type rdata,rr_type * record)916d83a80eeSchristos rdata_atom_to_string(buffer_type *output, rdata_zoneformat_type type,
917d83a80eeSchristos 		     rdata_atom_type rdata, rr_type* record)
918d83a80eeSchristos {
919d83a80eeSchristos 	return rdata_to_string_table[type](output, rdata, record);
920d83a80eeSchristos }
921d83a80eeSchristos 
922d83a80eeSchristos ssize_t
rdata_wireformat_to_rdata_atoms(region_type * region,domain_table_type * owners,uint16_t rrtype,uint16_t data_size,buffer_type * packet,rdata_atom_type ** rdatas)923d83a80eeSchristos rdata_wireformat_to_rdata_atoms(region_type *region,
924d83a80eeSchristos 				domain_table_type *owners,
925d83a80eeSchristos 				uint16_t rrtype,
926d83a80eeSchristos 				uint16_t data_size,
927d83a80eeSchristos 				buffer_type *packet,
928d83a80eeSchristos 				rdata_atom_type **rdatas)
929d83a80eeSchristos {
930d83a80eeSchristos 	size_t end = buffer_position(packet) + data_size;
931d83a80eeSchristos 	size_t i;
932d83a80eeSchristos 	rdata_atom_type temp_rdatas[MAXRDATALEN];
933d83a80eeSchristos 	rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(rrtype);
934d83a80eeSchristos 	region_type *temp_region;
935d83a80eeSchristos 
936d83a80eeSchristos 	assert(descriptor->maximum <= MAXRDATALEN);
937d83a80eeSchristos 
938d83a80eeSchristos 	if (!buffer_available(packet, data_size)) {
939d83a80eeSchristos 		return -1;
940d83a80eeSchristos 	}
941d83a80eeSchristos 
942d83a80eeSchristos 	temp_region = region_create(xalloc, free);
943d83a80eeSchristos 
944d83a80eeSchristos 	for (i = 0; i < descriptor->maximum; ++i) {
945d83a80eeSchristos 		int is_domain = 0;
946d83a80eeSchristos 		int is_normalized = 0;
947d83a80eeSchristos 		int is_wirestore = 0;
948d83a80eeSchristos 		size_t length = 0;
949d83a80eeSchristos 		int required = i < descriptor->minimum;
950d83a80eeSchristos 
951d83a80eeSchristos 		switch (rdata_atom_wireformat_type(rrtype, i)) {
952d83a80eeSchristos 		case RDATA_WF_COMPRESSED_DNAME:
953d83a80eeSchristos 		case RDATA_WF_UNCOMPRESSED_DNAME:
954d83a80eeSchristos 			is_domain = 1;
955d83a80eeSchristos 			is_normalized = 1;
956d83a80eeSchristos 			break;
957d83a80eeSchristos 		case RDATA_WF_LITERAL_DNAME:
958d83a80eeSchristos 			is_domain = 1;
959d83a80eeSchristos 			is_wirestore = 1;
960d83a80eeSchristos 			break;
961d83a80eeSchristos 		case RDATA_WF_BYTE:
962d83a80eeSchristos 			length = sizeof(uint8_t);
963d83a80eeSchristos 			break;
964d83a80eeSchristos 		case RDATA_WF_SHORT:
965d83a80eeSchristos 			length = sizeof(uint16_t);
966d83a80eeSchristos 			break;
967d83a80eeSchristos 		case RDATA_WF_LONG:
968d83a80eeSchristos 			length = sizeof(uint32_t);
969d83a80eeSchristos 			break;
970d83a80eeSchristos 		case RDATA_WF_TEXTS:
971d83a80eeSchristos 		case RDATA_WF_LONG_TEXT:
972d83a80eeSchristos 			length = end - buffer_position(packet);
973d83a80eeSchristos 			break;
974d83a80eeSchristos 		case RDATA_WF_TEXT:
975d83a80eeSchristos 		case RDATA_WF_BINARYWITHLENGTH:
976d83a80eeSchristos 			/* Length is stored in the first byte.  */
977d83a80eeSchristos 			length = 1;
978d83a80eeSchristos 			if (buffer_position(packet) + length <= end) {
979d83a80eeSchristos 				length += buffer_current(packet)[length - 1];
980d83a80eeSchristos 			}
981d83a80eeSchristos 			break;
982d83a80eeSchristos 		case RDATA_WF_A:
983d83a80eeSchristos 			length = sizeof(in_addr_t);
984d83a80eeSchristos 			break;
985d83a80eeSchristos 		case RDATA_WF_AAAA:
986d83a80eeSchristos 			length = IP6ADDRLEN;
987d83a80eeSchristos 			break;
988d83a80eeSchristos 		case RDATA_WF_ILNP64:
989d83a80eeSchristos 			length = IP6ADDRLEN/2;
990d83a80eeSchristos 			break;
991d83a80eeSchristos 		case RDATA_WF_EUI48:
992d83a80eeSchristos 			length = EUI48ADDRLEN;
993d83a80eeSchristos 			break;
994d83a80eeSchristos 		case RDATA_WF_EUI64:
995d83a80eeSchristos 			length = EUI64ADDRLEN;
996d83a80eeSchristos 			break;
997d83a80eeSchristos 		case RDATA_WF_BINARY:
998d83a80eeSchristos 			/* Remaining RDATA is binary.  */
999d83a80eeSchristos 			length = end - buffer_position(packet);
1000d83a80eeSchristos 			break;
1001d83a80eeSchristos 		case RDATA_WF_APL:
1002d83a80eeSchristos 			length = (sizeof(uint16_t)    /* address family */
1003d83a80eeSchristos 				  + sizeof(uint8_t)   /* prefix */
1004d83a80eeSchristos 				  + sizeof(uint8_t)); /* length */
1005d83a80eeSchristos 			if (buffer_position(packet) + length <= end) {
1006d83a80eeSchristos 				/* Mask out negation bit.  */
1007d83a80eeSchristos 				length += (buffer_current(packet)[length - 1]
1008d83a80eeSchristos 					   & APL_LENGTH_MASK);
1009d83a80eeSchristos 			}
1010d83a80eeSchristos 			break;
1011d83a80eeSchristos 		case RDATA_WF_IPSECGATEWAY:
1012ee758998Schristos 			assert(i>1); /* we are past the gateway type */
1013d83a80eeSchristos 			switch(rdata_atom_data(temp_rdatas[1])[0]) /* gateway type */ {
1014d83a80eeSchristos 			default:
1015d83a80eeSchristos 			case IPSECKEY_NOGATEWAY:
1016d83a80eeSchristos 				length = 0;
1017d83a80eeSchristos 				break;
1018d83a80eeSchristos 			case IPSECKEY_IP4:
1019d83a80eeSchristos 				length = IP4ADDRLEN;
1020d83a80eeSchristos 				break;
1021d83a80eeSchristos 			case IPSECKEY_IP6:
1022d83a80eeSchristos 				length = IP6ADDRLEN;
1023d83a80eeSchristos 				break;
1024d83a80eeSchristos 			case IPSECKEY_DNAME:
1025d83a80eeSchristos 				is_domain = 1;
1026d83a80eeSchristos 				is_normalized = 1;
1027d83a80eeSchristos 				is_wirestore = 1;
1028d83a80eeSchristos 				break;
1029d83a80eeSchristos 			}
1030d83a80eeSchristos 			break;
1031ee758998Schristos 		case RDATA_WF_SVCPARAM:
1032ee758998Schristos 			length = 4;
1033ee758998Schristos 			if (buffer_position(packet) + 4 <= end) {
1034ee758998Schristos 				length +=
1035ee758998Schristos 				    read_uint16(buffer_current(packet) + 2);
1036ee758998Schristos 			}
1037ee758998Schristos 			break;
1038d83a80eeSchristos 		}
1039d83a80eeSchristos 
1040d83a80eeSchristos 		if (is_domain) {
1041d83a80eeSchristos 			const dname_type *dname;
1042d83a80eeSchristos 
1043d83a80eeSchristos 			if (!required && buffer_position(packet) == end) {
1044d83a80eeSchristos 				break;
1045d83a80eeSchristos 			}
1046d83a80eeSchristos 
1047d83a80eeSchristos 			dname = dname_make_from_packet(
1048d83a80eeSchristos 				temp_region, packet, 1, is_normalized);
1049d83a80eeSchristos 			if (!dname || buffer_position(packet) > end) {
1050d83a80eeSchristos 				/* Error in domain name.  */
1051d83a80eeSchristos 				region_destroy(temp_region);
1052d83a80eeSchristos 				return -1;
1053d83a80eeSchristos 			}
1054d83a80eeSchristos 			if(is_wirestore) {
1055d83a80eeSchristos 				temp_rdatas[i].data = (uint16_t *) region_alloc(
1056d83a80eeSchristos                                 	region, sizeof(uint16_t) + ((size_t)dname->name_size));
1057d83a80eeSchristos 				temp_rdatas[i].data[0] = dname->name_size;
1058d83a80eeSchristos 				memcpy(temp_rdatas[i].data+1, dname_name(dname),
1059d83a80eeSchristos 					dname->name_size);
1060d83a80eeSchristos 			} else {
1061d83a80eeSchristos 				temp_rdatas[i].domain
1062d83a80eeSchristos 					= domain_table_insert(owners, dname);
1063d83a80eeSchristos 				temp_rdatas[i].domain->usage ++;
1064d83a80eeSchristos 			}
1065d83a80eeSchristos 		} else {
1066d83a80eeSchristos 			if (buffer_position(packet) + length > end) {
1067d83a80eeSchristos 				if (required) {
1068d83a80eeSchristos 					/* Truncated RDATA.  */
1069d83a80eeSchristos 					region_destroy(temp_region);
1070d83a80eeSchristos 					return -1;
1071d83a80eeSchristos 				} else {
1072d83a80eeSchristos 					break;
1073d83a80eeSchristos 				}
1074d83a80eeSchristos 			}
1075d83a80eeSchristos 			if (!required && buffer_position(packet) == end) {
1076d83a80eeSchristos 				break;
1077d83a80eeSchristos 			}
1078d83a80eeSchristos 
1079d83a80eeSchristos 			temp_rdatas[i].data = (uint16_t *) region_alloc(
1080d83a80eeSchristos 				region, sizeof(uint16_t) + length);
1081d83a80eeSchristos 			temp_rdatas[i].data[0] = length;
1082d83a80eeSchristos 			buffer_read(packet, temp_rdatas[i].data + 1, length);
1083d83a80eeSchristos 		}
1084d83a80eeSchristos 	}
1085d83a80eeSchristos 
1086d83a80eeSchristos 	if (buffer_position(packet) < end) {
1087d83a80eeSchristos 		/* Trailing garbage.  */
1088d83a80eeSchristos 		region_destroy(temp_region);
1089d83a80eeSchristos 		return -1;
1090d83a80eeSchristos 	}
1091d83a80eeSchristos 
1092d83a80eeSchristos 	*rdatas = (rdata_atom_type *) region_alloc_array_init(
1093d83a80eeSchristos 		region, temp_rdatas, i, sizeof(rdata_atom_type));
1094d83a80eeSchristos 	region_destroy(temp_region);
1095d83a80eeSchristos 	return (ssize_t)i;
1096d83a80eeSchristos }
1097d83a80eeSchristos 
1098d83a80eeSchristos size_t
rdata_maximum_wireformat_size(rrtype_descriptor_type * descriptor,size_t rdata_count,rdata_atom_type * rdatas)1099d83a80eeSchristos rdata_maximum_wireformat_size(rrtype_descriptor_type *descriptor,
1100d83a80eeSchristos 			      size_t rdata_count,
1101d83a80eeSchristos 			      rdata_atom_type *rdatas)
1102d83a80eeSchristos {
1103d83a80eeSchristos 	size_t result = 0;
1104d83a80eeSchristos 	size_t i;
1105d83a80eeSchristos 	for (i = 0; i < rdata_count; ++i) {
1106d83a80eeSchristos 		if (rdata_atom_is_domain(descriptor->type, i)) {
1107d83a80eeSchristos 			result += domain_dname(rdata_atom_domain(rdatas[i]))->name_size;
1108d83a80eeSchristos 		} else {
1109d83a80eeSchristos 			result += rdata_atom_size(rdatas[i]);
1110d83a80eeSchristos 		}
1111d83a80eeSchristos 	}
1112d83a80eeSchristos 	return result;
1113d83a80eeSchristos }
1114d83a80eeSchristos 
1115d83a80eeSchristos int
rdata_atoms_to_unknown_string(buffer_type * output,rrtype_descriptor_type * descriptor,size_t rdata_count,rdata_atom_type * rdatas)1116d83a80eeSchristos rdata_atoms_to_unknown_string(buffer_type *output,
1117d83a80eeSchristos 			      rrtype_descriptor_type *descriptor,
1118d83a80eeSchristos 			      size_t rdata_count,
1119d83a80eeSchristos 			      rdata_atom_type *rdatas)
1120d83a80eeSchristos {
1121d83a80eeSchristos 	size_t i;
1122d83a80eeSchristos 	size_t size =
1123d83a80eeSchristos 		rdata_maximum_wireformat_size(descriptor, rdata_count, rdatas);
1124d83a80eeSchristos 	buffer_printf(output, " \\# %lu ", (unsigned long) size);
1125d83a80eeSchristos 	for (i = 0; i < rdata_count; ++i) {
1126d83a80eeSchristos 		if (rdata_atom_is_domain(descriptor->type, i)) {
1127d83a80eeSchristos 			const dname_type *dname =
1128d83a80eeSchristos 				domain_dname(rdata_atom_domain(rdatas[i]));
1129d83a80eeSchristos 			hex_to_string(
1130d83a80eeSchristos 				output, dname_name(dname), dname->name_size);
1131d83a80eeSchristos 		} else {
1132d83a80eeSchristos 			hex_to_string(output, rdata_atom_data(rdatas[i]),
1133d83a80eeSchristos 				rdata_atom_size(rdatas[i]));
1134d83a80eeSchristos 		}
1135d83a80eeSchristos 	}
1136d83a80eeSchristos 	return 1;
1137d83a80eeSchristos }
1138d83a80eeSchristos 
1139d83a80eeSchristos int
print_rdata(buffer_type * output,rrtype_descriptor_type * descriptor,rr_type * record)1140d83a80eeSchristos print_rdata(buffer_type *output, rrtype_descriptor_type *descriptor,
1141d83a80eeSchristos 	    rr_type *record)
1142d83a80eeSchristos {
1143d83a80eeSchristos 	size_t i;
1144d83a80eeSchristos 	size_t saved_position = buffer_position(output);
1145d83a80eeSchristos 
1146d83a80eeSchristos 	for (i = 0; i < record->rdata_count; ++i) {
1147d83a80eeSchristos 		if (i == 0) {
1148d83a80eeSchristos 			buffer_printf(output, "\t");
1149d83a80eeSchristos 		} else if (descriptor->type == TYPE_SOA && i == 2) {
1150d83a80eeSchristos 			buffer_printf(output, " (\n\t\t");
1151d83a80eeSchristos 		} else {
1152d83a80eeSchristos 			buffer_printf(output, " ");
1153d83a80eeSchristos 		}
1154d83a80eeSchristos 		if (!rdata_atom_to_string(
1155d83a80eeSchristos 			    output,
1156d83a80eeSchristos 			    (rdata_zoneformat_type) descriptor->zoneformat[i],
1157d83a80eeSchristos 			    record->rdatas[i], record))
1158d83a80eeSchristos 		{
1159d83a80eeSchristos 			buffer_set_position(output, saved_position);
1160d83a80eeSchristos 			return 0;
1161d83a80eeSchristos 		}
1162d83a80eeSchristos 	}
1163d83a80eeSchristos 	if (descriptor->type == TYPE_SOA) {
1164d83a80eeSchristos 		buffer_printf(output, " )");
1165d83a80eeSchristos 	}
1166d83a80eeSchristos 
1167d83a80eeSchristos 	return 1;
1168d83a80eeSchristos }
1169d83a80eeSchristos 
1170