1 /**
2  *
3  * /brief getdns support functions for DNS Resource Records
4  *
5  * This file contains the tables with the information needed by getdns about
6  * individual RRs, such as their name and rdata fields and types.
7  * This information is provided via the response dict.
8  *
9  */
10 /*
11  * Copyright (c) 2013, NLnet Labs, Verisign, Inc.
12  * All rights reserved.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions are met:
16  * * Redistributions of source code must retain the above copyright
17  *   notice, this list of conditions and the following disclaimer.
18  * * Redistributions in binary form must reproduce the above copyright
19  *   notice, this list of conditions and the following disclaimer in the
20  *   documentation and/or other materials provided with the distribution.
21  * * Neither the names of the copyright holders nor the
22  *   names of its contributors may be used to endorse or promote products
23  *   derived from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28  * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
29  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
32  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36 
37 #include "rr-dict.h"
38 #include "gldns/gbuffer.h"
39 #include "util-internal.h"
40 #include "types-internal.h"
41 #include "context.h"
42 #include "dict.h"
43 
44 #define ALEN(a) (sizeof(a)/sizeof(a[0]))
45 #define UNKNOWN_RDATA NULL
46 
47 static const uint8_t *
apl_n_rdf_end(const uint8_t * pkt,const uint8_t * pkt_end,const uint8_t * rdf)48 apl_n_rdf_end(const uint8_t *pkt, const uint8_t *pkt_end, const uint8_t *rdf)
49 {
50 	(void)pkt;
51 	return rdf < pkt_end ? rdf + 1 : NULL;
52 }
53 static getdns_return_t
apl_n_wire2dict(getdns_dict * dict,const uint8_t * rdf)54 apl_n_wire2dict(getdns_dict *dict, const uint8_t *rdf)
55 {
56 	return getdns_dict_set_int(dict, "n", (*rdf  >> 7));
57 }
58 static getdns_return_t
apl_n_2wire(uint32_t value,uint8_t * rdata,uint8_t * rdf,size_t * rdf_len)59 apl_n_2wire(uint32_t value, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len)
60 {
61 	(void)rdata; /* unused parameter */
62 
63 	if (*rdf_len < 1) {
64 		*rdf_len = 1;
65 		return GETDNS_RETURN_NEED_MORE_SPACE;
66 	}
67 	*rdf_len = 1;
68 	*rdf = value ? 0x80 : 0x00;
69 	return GETDNS_RETURN_GOOD;
70 }
71 static getdns_return_t
apl_n_dict2wire(const getdns_dict * dict,uint8_t * rdata,uint8_t * rdf,size_t * rdf_len)72 apl_n_dict2wire(const getdns_dict *dict,
73     uint8_t *rdata, uint8_t *rdf, size_t *rdf_len)
74 {
75 	getdns_return_t r;
76 	uint32_t        value;
77 
78 	if ((r = getdns_dict_get_int(dict, "n", &value)))
79 		return r;
80 	else
81 		return apl_n_2wire(value, rdata, rdf, rdf_len);
82 }
83 static _getdns_rdf_special apl_n = {
84     apl_n_rdf_end,
85     apl_n_wire2dict, NULL,
86     apl_n_dict2wire, NULL
87 };
88 
89 static const uint8_t *
apl_afdpart_rdf_end(const uint8_t * pkt,const uint8_t * pkt_end,const uint8_t * rdf)90 apl_afdpart_rdf_end(
91     const uint8_t *pkt, const uint8_t *pkt_end, const uint8_t *rdf)
92 {
93 	const uint8_t *end = rdf + (rdf[-1] & 0x7F);
94 	(void)(pkt);
95 	return end <= pkt_end ? end : NULL;
96 }
97 static getdns_return_t
apl_afdpart_wire2dict(getdns_dict * dict,const uint8_t * rdf)98 apl_afdpart_wire2dict(getdns_dict *dict, const uint8_t *rdf)
99 {
100 	return _getdns_dict_set_const_bindata(
101 	    dict, "afdpart", (rdf[-1] & 0x7F), rdf);
102 }
103 static getdns_return_t
apl_afdpart_2wire(const getdns_bindata * value,uint8_t * rdata,uint8_t * rdf,size_t * rdf_len)104 apl_afdpart_2wire(
105     const getdns_bindata *value, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len)
106 {
107 	if (value->size > 0x7F)
108 		return GETDNS_RETURN_INVALID_PARAMETER;
109 
110 	if (rdf - 1 < rdata)
111 		return GETDNS_RETURN_GENERIC_ERROR;
112 
113 	if (*rdf_len < value->size) {
114 		*rdf_len = value->size;
115 		return GETDNS_RETURN_NEED_MORE_SPACE;
116 	}
117 	*rdf_len = value->size;
118 
119 	/* Keeping first bit is safe because value->size <= 0x7F */
120 	rdf[-1] |= value->size;
121 
122 	(void) memcpy(rdf, value->data, value->size);
123 	return GETDNS_RETURN_GOOD;
124 }
125 static getdns_return_t
apl_afdpart_dict2wire(const getdns_dict * dict,uint8_t * rdata,uint8_t * rdf,size_t * rdf_len)126 apl_afdpart_dict2wire(
127     const getdns_dict *dict, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len)
128 {
129 	getdns_return_t r;
130 	getdns_bindata *value;
131 
132 	if ((r = getdns_dict_get_bindata(dict, "afdpart", &value)))
133 		return r;
134 	else
135 		return apl_afdpart_2wire(value, rdata, rdf, rdf_len);
136 }
137 static _getdns_rdf_special apl_afdpart = {
138     apl_afdpart_rdf_end,
139     apl_afdpart_wire2dict, NULL,
140     apl_afdpart_dict2wire, NULL
141 };
142 
143 static const uint8_t *
ipseckey_gateway_rdf_end(const uint8_t * pkt,const uint8_t * pkt_end,const uint8_t * rdf)144 ipseckey_gateway_rdf_end(
145     const uint8_t *pkt, const uint8_t *pkt_end, const uint8_t *rdf)
146 {
147 	const uint8_t *end;
148 
149 	if (rdf - 5 < pkt)
150 		return NULL;
151 	switch (rdf[-2]) {
152 	case 0:	end = rdf;
153 		break;
154 	case 1: end = rdf + 4;
155 		break;
156 	case 2: end = rdf + 16;
157 		break;
158 	case 3: for (end = rdf; end < pkt_end; end += *end + 1)
159 			if ((*end & 0xC0) == 0xC0)
160 				end  += 2;
161 			else if (*end & 0xC0)
162 				return NULL;
163 			else if (!*end) {
164 				end += 1;
165 				break;
166 			}
167 		break;
168 	default:
169 		return NULL;
170 	}
171 	return end <= pkt_end ? end : NULL;
172 }
173 static getdns_return_t
ipseckey_gateway_equip_const_bindata(const uint8_t * rdf,size_t * size,const uint8_t ** data)174 ipseckey_gateway_equip_const_bindata(
175     const uint8_t *rdf, size_t *size, const uint8_t **data)
176 {
177 	*data = rdf;
178 	switch (rdf[-2]) {
179 	case 0:	*size = 0;
180 		break;
181 	case 1: *size = 4;
182 		break;
183 	case 2: *size = 16;
184 		break;
185 	case 3: while (*rdf)
186 			if ((*rdf & 0xC0) == 0xC0)
187 				rdf += 2;
188 			else if (*rdf & 0xC0)
189 				return GETDNS_RETURN_GENERIC_ERROR;
190 			else
191 				rdf += *rdf + 1;
192 		*size = rdf + 1 - *data;
193 		break;
194 	default:
195 		return GETDNS_RETURN_GENERIC_ERROR;
196 	}
197 	return GETDNS_RETURN_GOOD;
198 }
199 
200 static getdns_return_t
ipseckey_gateway_wire2dict(getdns_dict * dict,const uint8_t * rdf)201 ipseckey_gateway_wire2dict(getdns_dict *dict, const uint8_t *rdf)
202 {
203 	size_t size;
204 	const uint8_t *data;
205 
206 	if (ipseckey_gateway_equip_const_bindata(rdf, &size, &data))
207 		return GETDNS_RETURN_GENERIC_ERROR;
208 
209 	else if (! size)
210 		return GETDNS_RETURN_GOOD;
211 	else
212 		return _getdns_dict_set_const_bindata(dict, "gateway", size, data);
213 }
214 static getdns_return_t
ipseckey_gateway_2wire(const getdns_bindata * value,uint8_t * rdata,uint8_t * rdf,size_t * rdf_len)215 ipseckey_gateway_2wire(
216     const getdns_bindata *value, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len)
217 {
218 	assert(rdf - 2 >= rdata && rdf[-2] > 0);
219 
220 	switch (rdf[-2]) {
221 	case 1: if (!value || value->size != 4)
222 			return GETDNS_RETURN_INVALID_PARAMETER;
223 		if (*rdf_len < 4) {
224 			*rdf_len = 4;
225 			return GETDNS_RETURN_NEED_MORE_SPACE;
226 		}
227 		*rdf_len = 4;
228 		(void)memcpy(rdf, value->data, 4);
229 		return GETDNS_RETURN_GOOD;
230 	case 2: if (!value || value->size != 16)
231 			return GETDNS_RETURN_INVALID_PARAMETER;
232 		if (*rdf_len < 16) {
233 			*rdf_len = 16;
234 			return GETDNS_RETURN_NEED_MORE_SPACE;
235 		}
236 		*rdf_len = 16;
237 		(void)memcpy(rdf, value->data, 16);
238 		return GETDNS_RETURN_GOOD;
239 	case 3: if (!value || value->size == 0)
240 			return GETDNS_RETURN_INVALID_PARAMETER;
241 		/* Assume bindata is a valid dname; garbage in, garbage out */
242 		if (*rdf_len < value->size) {
243 			*rdf_len = value->size;
244 			return GETDNS_RETURN_NEED_MORE_SPACE;
245 		}
246 		*rdf_len = value->size;
247 		(void)memcpy(rdf, value->data, value->size);
248 		return GETDNS_RETURN_GOOD;
249 	default:
250 		return GETDNS_RETURN_GENERIC_ERROR;
251 	}
252 	return GETDNS_RETURN_GOOD;
253 }
254 static getdns_return_t
ipseckey_gateway_dict2wire(const getdns_dict * dict,uint8_t * rdata,uint8_t * rdf,size_t * rdf_len)255 ipseckey_gateway_dict2wire(
256     const getdns_dict *dict, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len)
257 {
258 	getdns_return_t r;
259 	getdns_bindata *value;
260 
261 	if (rdf - 2 < rdata)
262 		return GETDNS_RETURN_GENERIC_ERROR;
263 
264 	else if (rdf[-2] == 0) {
265 		*rdf_len = 0;
266 		return GETDNS_RETURN_GOOD;
267 	}
268 	else if ((r = getdns_dict_get_bindata(dict, "gateway", &value)))
269 		return r;
270 	else
271 		return ipseckey_gateway_2wire(value, rdata, rdf, rdf_len);
272 }
273 static _getdns_rdf_special ipseckey_gateway = {
274     ipseckey_gateway_rdf_end,
275     ipseckey_gateway_wire2dict, NULL,
276     ipseckey_gateway_dict2wire, NULL
277 };
278 
279 static const uint8_t *
hip_pk_algorithm_rdf_end(const uint8_t * pkt,const uint8_t * pkt_end,const uint8_t * rdf)280 hip_pk_algorithm_rdf_end(
281     const uint8_t *pkt, const uint8_t *pkt_end, const uint8_t *rdf)
282 {
283 	(void)(pkt);
284 	return rdf + 4 > pkt_end ? NULL
285 	     : rdf + 4 + *rdf + gldns_read_uint16(rdf + 2) > pkt_end ? NULL
286 	     : rdf + 1;
287 }
288 static getdns_return_t
hip_pk_algorithm_wire2dict(getdns_dict * dict,const uint8_t * rdf)289 hip_pk_algorithm_wire2dict(getdns_dict *dict, const uint8_t *rdf)
290 {
291 	return getdns_dict_set_int(dict, "pk_algorithm", rdf[1]);
292 }
293 static getdns_return_t
hip_pk_algorithm_2wire(uint32_t value,uint8_t * rdata,uint8_t * rdf,size_t * rdf_len)294 hip_pk_algorithm_2wire(uint32_t value, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len)
295 {
296 	if (rdata != rdf)
297 		return GETDNS_RETURN_GENERIC_ERROR;
298 	if (value > 0xFF)
299 		return GETDNS_RETURN_INVALID_PARAMETER;
300 	if (*rdf_len < 4) {
301 		*rdf_len = 4;
302 		return GETDNS_RETURN_NEED_MORE_SPACE;
303 	}
304 	*rdf_len = 4;
305 	rdata[1] = value;
306 	return GETDNS_RETURN_GOOD;
307 }
308 static getdns_return_t
hip_pk_algorithm_dict2wire(const getdns_dict * dict,uint8_t * rdata,uint8_t * rdf,size_t * rdf_len)309 hip_pk_algorithm_dict2wire(
310     const getdns_dict *dict,uint8_t *rdata, uint8_t *rdf, size_t *rdf_len)
311 {
312 	getdns_return_t r;
313 	uint32_t        value;
314 
315 	if ((r = getdns_dict_get_int(dict, "pk_algorithm", &value)))
316 		return r;
317 	else
318 		return hip_pk_algorithm_2wire(value, rdata, rdf, rdf_len);
319 }
320 static _getdns_rdf_special hip_pk_algorithm = {
321     hip_pk_algorithm_rdf_end,
322     hip_pk_algorithm_wire2dict, NULL,
323     hip_pk_algorithm_dict2wire, NULL
324 };
325 
326 static const uint8_t *
hip_hit_rdf_end(const uint8_t * pkt,const uint8_t * pkt_end,const uint8_t * rdf)327 hip_hit_rdf_end(const uint8_t *pkt, const uint8_t *pkt_end, const uint8_t *rdf)
328 {
329 	(void)(pkt);
330 	return rdf + 3 > pkt_end ? NULL
331 	     : rdf + 3 + rdf[-1] + gldns_read_uint16(rdf + 1) > pkt_end ? NULL
332 	     : rdf + 1;
333 }
334 static getdns_return_t
hip_hit_wire2dict(getdns_dict * dict,const uint8_t * rdf)335 hip_hit_wire2dict(getdns_dict *dict, const uint8_t *rdf)
336 {
337 	return _getdns_dict_set_const_bindata(dict, "hit", rdf[-1], rdf + 3);
338 }
339 static getdns_return_t
hip_hit_2wire(const getdns_bindata * value,uint8_t * rdata,uint8_t * rdf,size_t * rdf_len)340 hip_hit_2wire(
341     const getdns_bindata *value, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len)
342 {
343 	if (rdata != rdf - 4)
344 		return GETDNS_RETURN_GENERIC_ERROR;
345 	if (value && value->size > 0xFF)
346 		return GETDNS_RETURN_INVALID_PARAMETER;
347 	if (!value || value->size == 0) {
348 		rdata[0] = 0;
349 		*rdf_len = 0;
350 		return GETDNS_RETURN_GOOD;
351 	}
352 	if (value->size > *rdf_len) {
353 		*rdf_len = value->size;
354 		return GETDNS_RETURN_NEED_MORE_SPACE;
355 	}
356 	*rdf_len = value->size;
357 	rdata[0] = (uint8_t) value->size;
358 	(void)memcpy(rdf, value->data, value->size);
359 	return GETDNS_RETURN_GOOD;
360 }
361 static getdns_return_t
hip_hit_dict2wire(const getdns_dict * dict,uint8_t * rdata,uint8_t * rdf,size_t * rdf_len)362 hip_hit_dict2wire(
363     const getdns_dict *dict, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len)
364 {
365 	getdns_return_t r;
366 	getdns_bindata *value;
367 
368 	if ((r = getdns_dict_get_bindata(dict, "hit", &value)))
369 		return r;
370 	else
371 		return hip_hit_2wire(value, rdata, rdf, rdf_len);
372 }
373 static _getdns_rdf_special hip_hit = {
374     hip_hit_rdf_end,
375     hip_hit_wire2dict, NULL,
376     hip_hit_dict2wire, NULL
377 };
378 
379 static const uint8_t *
hip_public_key_rdf_end(const uint8_t * pkt,const uint8_t * pkt_end,const uint8_t * rdf)380 hip_public_key_rdf_end(
381     const uint8_t *pkt, const uint8_t *pkt_end, const uint8_t *rdf)
382 {
383 	(void)(pkt);
384 	return rdf + 2 > pkt_end ? NULL
385 	     : rdf + 2 + rdf[-2] + gldns_read_uint16(rdf) > pkt_end ? NULL
386 	     : rdf + 2 + rdf[-2] + gldns_read_uint16(rdf);
387 }
388 static getdns_return_t
hip_public_key_wire2dict(getdns_dict * dict,const uint8_t * rdf)389 hip_public_key_wire2dict(getdns_dict *dict, const uint8_t *rdf)
390 {
391 	return _getdns_dict_set_const_bindata(
392 	    dict, "public_key", gldns_read_uint16(rdf), rdf + 2 + rdf[-2]);
393 }
394 static getdns_return_t
hip_public_key_2wire(const getdns_bindata * value,uint8_t * rdata,uint8_t * rdf,size_t * rdf_len)395 hip_public_key_2wire(
396     const getdns_bindata *value, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len)
397 {
398 	if (rdata > rdf - 4 || rdata + 4 + rdata[0] != rdf)
399 		return GETDNS_RETURN_GENERIC_ERROR;
400 	if (value && value->size > 0xFFFF)
401 		return GETDNS_RETURN_INVALID_PARAMETER;
402 	if (!value || value->size == 0) {
403 		rdata[2] = rdata[3] = 0;
404 		*rdf_len = 0;
405 		return GETDNS_RETURN_GOOD;
406 	}
407 	if (value->size > *rdf_len) {
408 		*rdf_len = value->size;
409 		return GETDNS_RETURN_NEED_MORE_SPACE;
410 	}
411 	*rdf_len = value->size;
412 	gldns_write_uint16(rdata + 2, (uint16_t) value->size);
413 	(void)memcpy(rdf, value->data, value->size);
414 	return GETDNS_RETURN_GOOD;
415 }
416 static getdns_return_t
hip_public_key_dict2wire(const getdns_dict * dict,uint8_t * rdata,uint8_t * rdf,size_t * rdf_len)417 hip_public_key_dict2wire(
418     const getdns_dict *dict, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len)
419 {
420 	getdns_return_t r;
421 	getdns_bindata *value;
422 
423 	if ((r = getdns_dict_get_bindata(dict, "public_key", &value)))
424 		return r;
425 	else
426 		return hip_public_key_2wire(value, rdata, rdf, rdf_len);
427 }
428 static _getdns_rdf_special hip_public_key = {
429     hip_public_key_rdf_end,
430     hip_public_key_wire2dict, NULL,
431     hip_public_key_dict2wire, NULL
432 };
433 
434 static const uint8_t *
amtrelay_D_rdf_end(const uint8_t * pkt,const uint8_t * pkt_end,const uint8_t * rdf)435 amtrelay_D_rdf_end(const uint8_t *pkt, const uint8_t *pkt_end, const uint8_t *rdf)
436 {
437 	(void)pkt;
438 	return rdf < pkt_end ? rdf + 1 : NULL;
439 }
440 static getdns_return_t
amtrelay_D_wire2dict(getdns_dict * dict,const uint8_t * rdf)441 amtrelay_D_wire2dict(getdns_dict *dict, const uint8_t *rdf)
442 {
443 	return getdns_dict_set_int(dict, "discovery_optional", (*rdf  >> 7));
444 }
445 static getdns_return_t
amtrelay_D_dict2wire(const getdns_dict * dict,uint8_t * rdata,uint8_t * rdf,size_t * rdf_len)446 amtrelay_D_dict2wire(const getdns_dict *dict,
447     uint8_t *rdata, uint8_t *rdf, size_t *rdf_len)
448 {
449 	getdns_return_t r;
450 	uint32_t        value;
451 	(void)rdata; /* unused parameter */
452 
453 	if ((r = getdns_dict_get_int(dict, "discovery_optional", &value)))
454 		return r;
455 
456 	*rdf_len = 1;
457 	if (*rdf_len < 1)
458 		return GETDNS_RETURN_NEED_MORE_SPACE;
459 
460 	*rdf_len = 1;
461 	*rdf = value ? 0x80 : 0x00;
462 	return GETDNS_RETURN_GOOD;
463 }
464 static _getdns_rdf_special amtrelay_D = {
465     amtrelay_D_rdf_end,
466     amtrelay_D_wire2dict, NULL,
467     amtrelay_D_dict2wire, NULL
468 };
469 
470 static const uint8_t *
amtrelay_rtype_rdf_end(const uint8_t * pkt,const uint8_t * pkt_end,const uint8_t * rdf)471 amtrelay_rtype_rdf_end(
472     const uint8_t *pkt, const uint8_t *pkt_end, const uint8_t *rdf)
473 {
474 	(void)pkt; (void)pkt_end;
475 	return rdf;
476 }
477 static getdns_return_t
amtrelay_rtype_wire2dict(getdns_dict * dict,const uint8_t * rdf)478 amtrelay_rtype_wire2dict(getdns_dict *dict, const uint8_t *rdf)
479 {
480 	return getdns_dict_set_int(
481 	    dict, "replay_type", (rdf[-1] & 0x7F));
482 }
483 static getdns_return_t
amtrelay_rtype_dict2wire(const getdns_dict * dict,uint8_t * rdata,uint8_t * rdf,size_t * rdf_len)484 amtrelay_rtype_dict2wire(
485     const getdns_dict *dict, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len)
486 {
487 	getdns_return_t r;
488 	uint32_t value;
489 
490 	if ((r = getdns_dict_get_int(dict, "relay_type", &value)))
491 		return r;
492 
493 	if (rdf - 1 < rdata)
494 		return GETDNS_RETURN_GENERIC_ERROR;
495 
496 	*rdf_len = 0;
497 	rdf[-1] |= (value & 0x7F);
498 
499 	return GETDNS_RETURN_GOOD;
500 }
501 static _getdns_rdf_special amtrelay_rtype = {
502     amtrelay_rtype_rdf_end,
503     amtrelay_rtype_wire2dict, NULL,
504     amtrelay_rtype_dict2wire, NULL
505 };
506 
507 static const uint8_t *
amtrelay_relay_rdf_end(const uint8_t * pkt,const uint8_t * pkt_end,const uint8_t * rdf)508 amtrelay_relay_rdf_end(
509     const uint8_t *pkt, const uint8_t *pkt_end, const uint8_t *rdf)
510 {
511 	const uint8_t *end;
512 
513 	if (rdf - 4 < pkt)
514 		return NULL;
515 	switch (rdf[-1] & 0x7F) {
516 	case 0:	end = rdf;
517 		break;
518 	case 1: end = rdf + 4;
519 		break;
520 	case 2: end = rdf + 16;
521 		break;
522 	case 3: for (end = rdf; end < pkt_end; end += *end + 1)
523 			if ((*end & 0xC0) == 0xC0)
524 				end  += 2;
525 			else if (*end & 0xC0)
526 				return NULL;
527 			else if (!*end) {
528 				end += 1;
529 				break;
530 			}
531 		break;
532 	default:
533 		return NULL;
534 	}
535 	return end <= pkt_end ? end : NULL;
536 }
537 static getdns_return_t
amtrelay_relay_equip_const_bindata(const uint8_t * rdf,size_t * size,const uint8_t ** data)538 amtrelay_relay_equip_const_bindata(
539     const uint8_t *rdf, size_t *size, const uint8_t **data)
540 {
541 	*data = rdf;
542 	switch (rdf[-1] & 0x7F) {
543 	case 0:	*size = 0;
544 		break;
545 	case 1: *size = 4;
546 		break;
547 	case 2: *size = 16;
548 		break;
549 	case 3: while (*rdf)
550 			if ((*rdf & 0xC0) == 0xC0)
551 				rdf += 2;
552 			else if (*rdf & 0xC0)
553 				return GETDNS_RETURN_GENERIC_ERROR;
554 			else
555 				rdf += *rdf + 1;
556 		*size = rdf + 1 - *data;
557 		break;
558 	default:
559 		return GETDNS_RETURN_GENERIC_ERROR;
560 	}
561 	return GETDNS_RETURN_GOOD;
562 }
563 
564 static getdns_return_t
amtrelay_relay_wire2dict(getdns_dict * dict,const uint8_t * rdf)565 amtrelay_relay_wire2dict(getdns_dict *dict, const uint8_t *rdf)
566 {
567 	size_t size;
568 	const uint8_t *data;
569 
570 	if (amtrelay_relay_equip_const_bindata(rdf, &size, &data))
571 		return GETDNS_RETURN_GENERIC_ERROR;
572 
573 	else if (! size)
574 		return GETDNS_RETURN_GOOD;
575 	else
576 		return _getdns_dict_set_const_bindata(dict, "relay", size, data);
577 }
578 static getdns_return_t
amtrelay_relay_2wire(const getdns_bindata * value,uint8_t * rdata,uint8_t * rdf,size_t * rdf_len)579 amtrelay_relay_2wire(
580     const getdns_bindata *value, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len)
581 {
582 	assert(rdf - 1 >= rdata && (rdf[-1] & 0x7F) > 0);
583 
584 	switch (rdf[-1] & 0x7F) {
585 	case 1: if (!value || value->size != 4)
586 			return GETDNS_RETURN_INVALID_PARAMETER;
587 		if (*rdf_len < 4) {
588 			*rdf_len = 4;
589 			return GETDNS_RETURN_NEED_MORE_SPACE;
590 		}
591 		*rdf_len = 4;
592 		(void)memcpy(rdf, value->data, 4);
593 		return GETDNS_RETURN_GOOD;
594 	case 2: if (!value || value->size != 16)
595 			return GETDNS_RETURN_INVALID_PARAMETER;
596 		if (*rdf_len < 16) {
597 			*rdf_len = 16;
598 			return GETDNS_RETURN_NEED_MORE_SPACE;
599 		}
600 		*rdf_len = 16;
601 		(void)memcpy(rdf, value->data, 16);
602 		return GETDNS_RETURN_GOOD;
603 	case 3: if (!value || value->size == 0)
604 			return GETDNS_RETURN_INVALID_PARAMETER;
605 		/* Assume bindata is a valid dname; garbage in, garbage out */
606 		if (*rdf_len < value->size) {
607 			*rdf_len = value->size;
608 			return GETDNS_RETURN_NEED_MORE_SPACE;
609 		}
610 		*rdf_len = value->size;
611 		(void)memcpy(rdf, value->data, value->size);
612 		return GETDNS_RETURN_GOOD;
613 	default:
614 		return GETDNS_RETURN_GENERIC_ERROR;
615 	}
616 	return GETDNS_RETURN_GOOD;
617 }
618 static getdns_return_t
amtrelay_relay_dict2wire(const getdns_dict * dict,uint8_t * rdata,uint8_t * rdf,size_t * rdf_len)619 amtrelay_relay_dict2wire(
620     const getdns_dict *dict, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len)
621 {
622 	getdns_return_t r;
623 	getdns_bindata *value;
624 
625 	if (rdf - 1 < rdata)
626 		return GETDNS_RETURN_GENERIC_ERROR;
627 
628 	else if ((rdf[-1] & 0x7F) == 0) {
629 		*rdf_len = 0;
630 		return GETDNS_RETURN_GOOD;
631 	}
632 	else if ((r = getdns_dict_get_bindata(dict, "relay", &value)))
633 		return r;
634 	else
635 		return amtrelay_relay_2wire(value, rdata, rdf, rdf_len);
636 }
637 static _getdns_rdf_special amtrelay_relay = {
638     amtrelay_relay_rdf_end,
639     amtrelay_relay_wire2dict, NULL,
640     amtrelay_relay_dict2wire, NULL
641 };
642 
643 
644 static _getdns_rdata_def          a_rdata[] = {
645 	{ "ipv4_address"                , GETDNS_RDF_A      , NULL }};
646 static _getdns_rdata_def         ns_rdata[] = {
647 	{ "nsdname"                     , GETDNS_RDF_N_C    , NULL }};
648 static _getdns_rdata_def         md_rdata[] = {
649 	{ "madname"                     , GETDNS_RDF_N_C    , NULL }};
650 static _getdns_rdata_def      cname_rdata[] = {
651 	{ "cname"                       , GETDNS_RDF_N_C    , NULL }};
652 static _getdns_rdata_def        soa_rdata[] = {
653 	{ "mname"                       , GETDNS_RDF_N_C    , NULL },
654 	{ "rname"                       , GETDNS_RDF_N_C    , NULL },
655 	{ "serial"                      , GETDNS_RDF_I4     , NULL },
656 	{ "refresh"                     , GETDNS_RDF_I4     , NULL },
657 	{ "retry"                       , GETDNS_RDF_I4     , NULL },
658 	{ "expire"                      , GETDNS_RDF_I4     , NULL },
659 	{ "minimum"                     , GETDNS_RDF_I4     , NULL }};
660 static _getdns_rdata_def         mg_rdata[] = {
661 	{ "mgmname"                     , GETDNS_RDF_N_C    , NULL }};
662 static _getdns_rdata_def         mr_rdata[] = {
663 	{ "newname"                     , GETDNS_RDF_N_C    , NULL }};
664 static _getdns_rdata_def       null_rdata[] = {
665 	{ "anything"                    , GETDNS_RDF_X      , NULL }};
666 static _getdns_rdata_def        wks_rdata[] = {
667 	{ "address"                     , GETDNS_RDF_A      , NULL },
668 	{ "protocol"                    , GETDNS_RDF_I1     , NULL },
669 	{ "bitmap"                      , GETDNS_RDF_X      , NULL }};
670 static _getdns_rdata_def        ptr_rdata[] = {
671 	{ "ptrdname"                    , GETDNS_RDF_N_C    , NULL }};
672 static _getdns_rdata_def      hinfo_rdata[] = {
673 	{ "cpu"                         , GETDNS_RDF_S      , NULL },
674 	{ "os"                          , GETDNS_RDF_S      , NULL }};
675 static _getdns_rdata_def      minfo_rdata[] = {
676 	{ "rmailbx"                     , GETDNS_RDF_N_C    , NULL },
677 	{ "emailbx"                     , GETDNS_RDF_N_C    , NULL }};
678 static _getdns_rdata_def         mx_rdata[] = {
679 	{ "preference"                  , GETDNS_RDF_I2     , NULL },
680 	{ "exchange"                    , GETDNS_RDF_N_C    , NULL }};
681 static _getdns_rdata_def        txt_rdata[] = {
682 	{ "txt_strings"                 , GETDNS_RDF_S_M    , NULL }};
683 static _getdns_rdata_def         rp_rdata[] = {
684 	{ "mbox_dname"                  , GETDNS_RDF_N      , NULL },
685 	{ "txt_dname"                   , GETDNS_RDF_N      , NULL }};
686 static _getdns_rdata_def      afsdb_rdata[] = {
687 	{ "subtype"                     , GETDNS_RDF_I2     , NULL },
688 	{ "hostname"                    , GETDNS_RDF_N      , NULL }};
689 static _getdns_rdata_def        x25_rdata[] = {
690 	{ "psdn_address"                , GETDNS_RDF_S      , NULL }};
691 static _getdns_rdata_def       isdn_rdata[] = {
692 	{ "isdn_address"                , GETDNS_RDF_S      , NULL },
693 	{ "sa"                          , GETDNS_RDF_S      , NULL }};
694 static _getdns_rdata_def         rt_rdata[] = {
695 	{ "preference"                  , GETDNS_RDF_I2     , NULL },
696 	{ "intermediate_host"           , GETDNS_RDF_N      , NULL }};
697 static _getdns_rdata_def       nsap_rdata[] = {
698 	{ "nsap"                        , GETDNS_RDF_X      , NULL }};
699 static _getdns_rdata_def   nsap_ptr_rdata[] = {
700 	{ "owner"                       , GETDNS_RDF_S      , NULL }};
701 static _getdns_rdata_def        sig_rdata[] = {
702 	{ "sig_obsolete"                , GETDNS_RDF_X      , NULL }};
703 static _getdns_rdata_def        key_rdata[] = {
704 	{ "key_obsolete"                , GETDNS_RDF_X      , NULL }};
705 static _getdns_rdata_def         px_rdata[] = {
706 	{ "preference"                  , GETDNS_RDF_I2     , NULL },
707 	{ "map822"                      , GETDNS_RDF_N      , NULL },
708 	{ "mapx400"                     , GETDNS_RDF_N      , NULL }};
709 static _getdns_rdata_def       gpos_rdata[] = {
710 	{ "longitude"                   , GETDNS_RDF_S      , NULL },
711 	{ "latitude"                    , GETDNS_RDF_S      , NULL },
712 	{ "altitude"                    , GETDNS_RDF_S      , NULL }};
713 static _getdns_rdata_def       aaaa_rdata[] = {
714 	{ "ipv6_address"                , GETDNS_RDF_AAAA   , NULL }};
715 static _getdns_rdata_def        loc_rdata[] = {
716 	{ "loc_obsolete"                , GETDNS_RDF_X      , NULL }};
717 static _getdns_rdata_def        nxt_rdata[] = {
718 	{ "nxt_obsolete"                , GETDNS_RDF_X      , NULL }};
719 static _getdns_rdata_def        eid_rdata[] = {
720 	{ "endpoint_identifier"         , GETDNS_RDF_X      , NULL }};
721 static _getdns_rdata_def     nimloc_rdata[] = {
722 	{ "nimrod_locator"              , GETDNS_RDF_X      , NULL }};
723 static _getdns_rdata_def        srv_rdata[] = {
724 	{ "priority"                    , GETDNS_RDF_I2     , NULL },
725 	{ "weight"                      , GETDNS_RDF_I2     , NULL },
726 	{ "port"                        , GETDNS_RDF_I2     , NULL },
727 	{ "target"                      , GETDNS_RDF_N      , NULL }};
728 static _getdns_rdata_def       atma_rdata[] = {
729 	{ "format"                      , GETDNS_RDF_X      , NULL }};
730 static _getdns_rdata_def      naptr_rdata[] = {
731 	{ "order"                       , GETDNS_RDF_I2     , NULL },
732 	{ "preference"                  , GETDNS_RDF_I2     , NULL },
733 	{ "flags"                       , GETDNS_RDF_S      , NULL },
734 	{ "service"                     , GETDNS_RDF_S      , NULL },
735 	{ "regexp"                      , GETDNS_RDF_S      , NULL },
736 	{ "replacement"                 , GETDNS_RDF_N      , NULL }};
737 static _getdns_rdata_def         kx_rdata[] = {
738 	{ "preference"                  , GETDNS_RDF_I2     , NULL },
739 	{ "exchanger"                   , GETDNS_RDF_N      , NULL }};
740 static _getdns_rdata_def       cert_rdata[] = {
741 	{ "type"                        , GETDNS_RDF_I2     , NULL },
742 	{ "key_tag"                     , GETDNS_RDF_I2     , NULL },
743 	{ "algorithm"                   , GETDNS_RDF_I1     , NULL },
744 	{ "certificate_or_crl"          , GETDNS_RDF_B      , NULL }};
745 static _getdns_rdata_def         a6_rdata[] = {
746 	{ "a6_obsolete"                 , GETDNS_RDF_X      , NULL }};
747 static _getdns_rdata_def      dname_rdata[] = {
748 	{ "target"                      , GETDNS_RDF_N      , NULL }};
749 static _getdns_rdata_def        opt_rdata[] = {
750 	{ "options"                     , GETDNS_RDF_R      , NULL },
751 	{ "option_code"                 , GETDNS_RDF_I2     , NULL },
752 	{ "option_data"                 , GETDNS_RDF_X_S    , NULL }};
753 static _getdns_rdata_def        apl_rdata[] = {
754 	{ "apitems"                     , GETDNS_RDF_R      , NULL },
755 	{ "address_family"              , GETDNS_RDF_I2     , NULL },
756 	{ "prefix"                      , GETDNS_RDF_I1     , NULL },
757 	{ "n"                           , GETDNS_RDF_SPECIAL, &apl_n },
758 	{ "afdpart"                     , GETDNS_RDF_SPECIAL, &apl_afdpart }};
759 static _getdns_rdata_def         ds_rdata[] = {
760 	{ "key_tag"                     , GETDNS_RDF_I2     , NULL },
761 	{ "algorithm"                   , GETDNS_RDF_I1     , NULL },
762 	{ "digest_type"                 , GETDNS_RDF_I1     , NULL },
763 	{ "digest"                      , GETDNS_RDF_X      , NULL }};
764 static _getdns_rdata_def      sshfp_rdata[] = {
765 	{ "algorithm"                   , GETDNS_RDF_I1     , NULL },
766 	{ "fp_type"                     , GETDNS_RDF_I1     , NULL },
767 	{ "fingerprint"                 , GETDNS_RDF_X      , NULL }};
768 static _getdns_rdata_def   ipseckey_rdata[] = {
769 	{ "algorithm"                   , GETDNS_RDF_I1     , NULL },
770 	{ "gateway_type"                , GETDNS_RDF_I1     , NULL },
771 	{ "precedence"                  , GETDNS_RDF_I1     , NULL },
772 	{ "gateway"                     , GETDNS_RDF_SPECIAL, &ipseckey_gateway },
773 	{ "public_key"                  , GETDNS_RDF_B      , NULL }};
774 static _getdns_rdata_def      rrsig_rdata[] = {
775 	{ "type_covered"                , GETDNS_RDF_I2     , NULL },
776 	{ "algorithm"                   , GETDNS_RDF_I1     , NULL },
777 	{ "labels"                      , GETDNS_RDF_I1     , NULL },
778 	{ "original_ttl"                , GETDNS_RDF_I4     , NULL },
779 	{ "signature_expiration"        , GETDNS_RDF_T      , NULL },
780 	{ "signature_inception"         , GETDNS_RDF_T      , NULL },
781 	{ "key_tag"                     , GETDNS_RDF_I2     , NULL },
782 	{ "signers_name"                , GETDNS_RDF_N      , NULL },
783 	{ "signature"                   , GETDNS_RDF_B      , NULL }};
784 static _getdns_rdata_def       nsec_rdata[] = {
785 	{ "next_domain_name"            , GETDNS_RDF_N      , NULL },
786 	{ "type_bit_maps"               , GETDNS_RDF_X      , NULL }};
787 static _getdns_rdata_def     dnskey_rdata[] = {
788 	{ "flags"                       , GETDNS_RDF_I2     , NULL },
789 	{ "protocol"                    , GETDNS_RDF_I1     , NULL },
790 	{ "algorithm"                   , GETDNS_RDF_I1     , NULL },
791 	{ "public_key"                  , GETDNS_RDF_B      , NULL }};
792 static _getdns_rdata_def      dhcid_rdata[] = {
793 	{ "dhcid_opaque"                , GETDNS_RDF_B      , NULL }};
794 static _getdns_rdata_def      nsec3_rdata[] = {
795 	{ "hash_algorithm"              , GETDNS_RDF_I1     , NULL },
796 	{ "flags"                       , GETDNS_RDF_I1     , NULL },
797 	{ "iterations"                  , GETDNS_RDF_I2     , NULL },
798 	{ "salt"                        , GETDNS_RDF_X_C    , NULL },
799 	{ "next_hashed_owner_name"      , GETDNS_RDF_B32_C  , NULL },
800 	{ "type_bit_maps"               , GETDNS_RDF_X      , NULL }};
801 static _getdns_rdata_def nsec3param_rdata[] = {
802 	{ "hash_algorithm"              , GETDNS_RDF_I1     , NULL },
803 	{ "flags"                       , GETDNS_RDF_I1     , NULL },
804 	{ "iterations"                  , GETDNS_RDF_I2     , NULL },
805 	{ "salt"                        , GETDNS_RDF_X_C    , NULL }};
806 static _getdns_rdata_def       tlsa_rdata[] = {
807 	{ "certificate_usage"           , GETDNS_RDF_I1     , NULL },
808 	{ "selector"                    , GETDNS_RDF_I1     , NULL },
809 	{ "matching_type"               , GETDNS_RDF_I1     , NULL },
810 	{ "certificate_association_data", GETDNS_RDF_X      , NULL }};
811 static _getdns_rdata_def        hip_rdata[] = {
812 	{ "pk_algorithm"                , GETDNS_RDF_SPECIAL, &hip_pk_algorithm },
813 	{ "hit"                         , GETDNS_RDF_SPECIAL, &hip_hit },
814 	{ "public_key"                  , GETDNS_RDF_SPECIAL, &hip_public_key },
815 	{ "rendezvous_servers"          , GETDNS_RDF_N_M    , NULL }};
816 static _getdns_rdata_def     talink_rdata[] = {
817 	{ "previous"                    , GETDNS_RDF_N      , NULL },
818 	{ "next"                        , GETDNS_RDF_N      , NULL }};
819 static _getdns_rdata_def   openpgpkey_rdata[] = {
820 	{ "transferable_public_key"     , GETDNS_RDF_B      , NULL }};
821 static _getdns_rdata_def        csync_rdata[] = {
822 	{ "serial"                      , GETDNS_RDF_I4     , NULL },
823 	{ "flags"                       , GETDNS_RDF_I2     , NULL },
824 	{ "type_bit_maps"               , GETDNS_RDF_X      , NULL }};
825 static _getdns_rdata_def     zonemd_rdata[] = {
826 	{ "serial"                      , GETDNS_RDF_I4     , NULL },
827 	{ "digest_type"                 , GETDNS_RDF_I1     , NULL },
828 	{ "reserved"                    , GETDNS_RDF_I1     , NULL },
829 	{ "digest"                      , GETDNS_RDF_X      , NULL }};
830 static _getdns_rdata_def        spf_rdata[] = {
831 	{ "text"                        , GETDNS_RDF_S_M    , NULL }};
832 static _getdns_rdata_def        nid_rdata[] = {
833 	{ "preference"                  , GETDNS_RDF_I2     , NULL },
834 	{ "node_id"                     , GETDNS_RDF_AA     , NULL }};
835 static _getdns_rdata_def        l32_rdata[] = {
836 	{ "preference"                  , GETDNS_RDF_I2     , NULL },
837 	{ "locator32"                   , GETDNS_RDF_A      , NULL }};
838 static _getdns_rdata_def        l64_rdata[] = {
839 	{ "preference"                  , GETDNS_RDF_I2     , NULL },
840 	{ "locator64"                   , GETDNS_RDF_AA     , NULL }};
841 static _getdns_rdata_def         lp_rdata[] = {
842 	{ "preference"                  , GETDNS_RDF_I2     , NULL },
843 	{ "fqdn"                        , GETDNS_RDF_N      , NULL }};
844 static _getdns_rdata_def      eui48_rdata[] = {
845 	{ "eui48_address"               , GETDNS_RDF_X6     , NULL }};
846 static _getdns_rdata_def      eui64_rdata[] = {
847 	{ "eui64_address"               , GETDNS_RDF_X8     , NULL }};
848 static _getdns_rdata_def       tkey_rdata[] = {
849 	{ "algorithm"                   , GETDNS_RDF_N      , NULL },
850 	{ "inception"                   , GETDNS_RDF_T      , NULL },
851 	{ "expiration"                  , GETDNS_RDF_T      , NULL },
852 	{ "mode"                        , GETDNS_RDF_I2     , NULL },
853 	{ "error"                       , GETDNS_RDF_I2     , NULL },
854 	{ "key_data"                    , GETDNS_RDF_X_S    , NULL },
855 	{ "other_data"                  , GETDNS_RDF_X_S    , NULL }};
856 static _getdns_rdata_def       tsig_rdata[] = {
857 	{ "algorithm"                   , GETDNS_RDF_N      , NULL },
858 	{ "time_signed"                 , GETDNS_RDF_T6     , NULL },
859 	{ "fudge"                       , GETDNS_RDF_I2     , NULL },
860 	{ "mac"                         , GETDNS_RDF_X_S    , NULL },
861 	{ "original_id"                 , GETDNS_RDF_I2     , NULL },
862 	{ "error"                       , GETDNS_RDF_I2     , NULL },
863 	{ "other_data"                  , GETDNS_RDF_X_S    , NULL }};
864 static _getdns_rdata_def        uri_rdata[] = {
865 	{ "priority"                    , GETDNS_RDF_I2     , NULL },
866 	{ "weight"                      , GETDNS_RDF_I2     , NULL },
867 	{ "target"                      , GETDNS_RDF_S_L    , NULL }};
868 static _getdns_rdata_def        caa_rdata[] = {
869 	{ "flags"                       , GETDNS_RDF_I1     , NULL },
870 	{ "tag"                         , GETDNS_RDF_S      , NULL },
871 	{ "value"                       , GETDNS_RDF_S_L    , NULL }};
872 static _getdns_rdata_def        dlv_rdata[] = {
873 	{ "key_tag"                     , GETDNS_RDF_I2     , NULL },
874 	{ "algorithm"                   , GETDNS_RDF_I1     , NULL },
875 	{ "digest_type"                 , GETDNS_RDF_I1     , NULL },
876 	{ "digest"                      , GETDNS_RDF_X      , NULL }};
877 static _getdns_rdata_def        doa_rdata[] = {
878 	{ "enterprise"                  , GETDNS_RDF_I4     , NULL },
879 	{ "type"                        , GETDNS_RDF_I4     , NULL },
880 	{ "location"                    , GETDNS_RDF_I1     , NULL },
881 	{ "media_type"                  , GETDNS_RDF_S      , NULL },
882 	{ "data"                        , GETDNS_RDF_B      , NULL }};
883 static _getdns_rdata_def   amtrelay_rdata[] = {
884 	{ "precedence"                  , GETDNS_RDF_I1     , NULL },
885 	{ "discovery_optional"          , GETDNS_RDF_SPECIAL, &amtrelay_D},
886 	{ "relay_type"                  , GETDNS_RDF_SPECIAL, &amtrelay_rtype },
887 	{ "relay"                       , GETDNS_RDF_SPECIAL, &amtrelay_relay }};
888 
889 static _getdns_rr_def _getdns_rr_defs[] = {
890 	{         NULL,             NULL, 0                      },
891 	{          "A",          a_rdata, ALEN(         a_rdata) }, /* 1 - */
892 	{         "NS",         ns_rdata, ALEN(        ns_rdata) },
893 	{         "MD",         md_rdata, ALEN(        md_rdata) },
894 	{         "MF",         md_rdata, ALEN(        md_rdata) },
895 	{      "CNAME",      cname_rdata, ALEN(     cname_rdata) },
896 	{        "SOA",        soa_rdata, ALEN(       soa_rdata) },
897 	{         "MB",         md_rdata, ALEN(        md_rdata) },
898 	{         "MG",         mg_rdata, ALEN(        mg_rdata) },
899 	{         "MR",         mr_rdata, ALEN(        mr_rdata) },
900 	{       "NULL",       null_rdata, ALEN(      null_rdata) },
901 	{        "WKS",        wks_rdata, ALEN(       wks_rdata) },
902 	{        "PTR",        ptr_rdata, ALEN(       ptr_rdata) },
903 	{      "HINFO",      hinfo_rdata, ALEN(     hinfo_rdata) },
904 	{      "MINFO",      minfo_rdata, ALEN(     minfo_rdata) },
905 	{         "MX",         mx_rdata, ALEN(        mx_rdata) },
906 	{        "TXT",        txt_rdata, ALEN(       txt_rdata) },
907 	{         "RP",         rp_rdata, ALEN(        rp_rdata) },
908 	{      "AFSDB",      afsdb_rdata, ALEN(     afsdb_rdata) },
909 	{        "X25",        x25_rdata, ALEN(       x25_rdata) },
910 	{       "ISDN",       isdn_rdata, ALEN(      isdn_rdata) },
911 	{         "RT",         rt_rdata, ALEN(        rt_rdata) },
912 	{       "NSAP",       nsap_rdata, ALEN(      nsap_rdata) },
913 	{   "NSAP_PTR",   nsap_ptr_rdata, ALEN(  nsap_ptr_rdata) },
914 	{        "SIG",        sig_rdata, ALEN(       sig_rdata) },
915 	{        "KEY",        key_rdata, ALEN(       key_rdata) },
916 	{         "PX",         px_rdata, ALEN(        px_rdata) },
917 	{       "GPOS",       gpos_rdata, ALEN(      gpos_rdata) },
918 	{       "AAAA",       aaaa_rdata, ALEN(      aaaa_rdata) },
919 	{        "LOC",        loc_rdata, ALEN(       loc_rdata) },
920 	{        "NXT",        nxt_rdata, ALEN(       nxt_rdata) },
921 	{        "EID",        eid_rdata, ALEN(       eid_rdata) },
922 	{     "NIMLOC",     nimloc_rdata, ALEN(    nimloc_rdata) },
923 	{        "SRV",        srv_rdata, ALEN(       srv_rdata) },
924 	{       "ATMA",       atma_rdata, ALEN(      atma_rdata) },
925 	{      "NAPTR",      naptr_rdata, ALEN(     naptr_rdata) },
926 	{         "KX",         kx_rdata, ALEN(        kx_rdata) },
927 	{       "CERT",       cert_rdata, ALEN(      cert_rdata) },
928 	{         "A6",         a6_rdata, ALEN(        a6_rdata) },
929 	{      "DNAME",      dname_rdata, ALEN(     dname_rdata) },
930 	{       "SINK",    UNKNOWN_RDATA, 0                      },
931 	{        "OPT",        opt_rdata, ALEN(       opt_rdata) },
932 	{        "APL",        apl_rdata, ALEN(       apl_rdata) },
933 	{         "DS",         ds_rdata, ALEN(        ds_rdata) },
934 	{      "SSHFP",      sshfp_rdata, ALEN(     sshfp_rdata) },
935 	{   "IPSECKEY",   ipseckey_rdata, ALEN(  ipseckey_rdata) },
936 	{      "RRSIG",      rrsig_rdata, ALEN(     rrsig_rdata) },
937 	{       "NSEC",       nsec_rdata, ALEN(      nsec_rdata) },
938 	{     "DNSKEY",     dnskey_rdata, ALEN(    dnskey_rdata) },
939 	{      "DHCID",      dhcid_rdata, ALEN(     dhcid_rdata) },
940 	{      "NSEC3",      nsec3_rdata, ALEN(     nsec3_rdata) },
941 	{ "NSEC3PARAM", nsec3param_rdata, ALEN(nsec3param_rdata) },
942 	{       "TLSA",       tlsa_rdata, ALEN(      tlsa_rdata) },
943 	{     "SMIMEA",       tlsa_rdata, ALEN(      tlsa_rdata) }, /* - 53 */
944 	{         NULL,             NULL, 0                      },
945 	{        "HIP",        hip_rdata, ALEN(       hip_rdata) }, /* 55 - */
946 	{      "NINFO",    UNKNOWN_RDATA, 0                      },
947 	{       "RKEY",    UNKNOWN_RDATA, 0                      },
948 	{     "TALINK",     talink_rdata, ALEN(    talink_rdata) },
949 	{        "CDS",         ds_rdata, ALEN(        ds_rdata) },
950 	{    "CDNSKEY",     dnskey_rdata, ALEN(    dnskey_rdata) },
951 	{ "OPENPGPKEY", openpgpkey_rdata, ALEN(openpgpkey_rdata) },
952 	{      "CSYNC",      csync_rdata, ALEN(     csync_rdata) },
953 	{     "ZONEMD",     zonemd_rdata, ALEN(    zonemd_rdata) }, /* - 63 */
954 	{         NULL,             NULL, 0                      },
955 	{         NULL,             NULL, 0                      },
956 	{         NULL,             NULL, 0                      },
957 	{         NULL,             NULL, 0                      },
958 	{         NULL,             NULL, 0                      },
959 	{         NULL,             NULL, 0                      },
960 	{         NULL,             NULL, 0                      },
961 	{         NULL,             NULL, 0                      },
962 	{         NULL,             NULL, 0                      },
963 	{         NULL,             NULL, 0                      },
964 	{         NULL,             NULL, 0                      },
965 	{         NULL,             NULL, 0                      },
966 	{         NULL,             NULL, 0                      },
967 	{         NULL,             NULL, 0                      },
968 	{         NULL,             NULL, 0                      },
969 	{         NULL,             NULL, 0                      },
970 	{         NULL,             NULL, 0                      },
971 	{         NULL,             NULL, 0                      },
972 	{         NULL,             NULL, 0                      },
973 	{         NULL,             NULL, 0                      },
974 	{         NULL,             NULL, 0                      },
975 	{         NULL,             NULL, 0                      },
976 	{         NULL,             NULL, 0                      },
977 	{         NULL,             NULL, 0                      },
978 	{         NULL,             NULL, 0                      },
979 	{         NULL,             NULL, 0                      },
980 	{         NULL,             NULL, 0                      },
981 	{         NULL,             NULL, 0                      },
982 	{         NULL,             NULL, 0                      },
983 	{         NULL,             NULL, 0                      },
984 	{         NULL,             NULL, 0                      },
985 	{         NULL,             NULL, 0                      },
986 	{         NULL,             NULL, 0                      },
987 	{         NULL,             NULL, 0                      },
988 	{         NULL,             NULL, 0                      },
989 	{        "SPF",        spf_rdata, ALEN(       spf_rdata) }, /* 99 - */
990 	{      "UINFO",    UNKNOWN_RDATA, 0                      },
991 	{        "UID",    UNKNOWN_RDATA, 0                      },
992 	{        "GID",    UNKNOWN_RDATA, 0                      },
993 	{     "UNSPEC",    UNKNOWN_RDATA, 0                      },
994 	{        "NID",        nid_rdata, ALEN(       nid_rdata) },
995 	{        "L32",        l32_rdata, ALEN(       l32_rdata) },
996 	{        "L64",        l64_rdata, ALEN(       l64_rdata) },
997 	{         "LP",         lp_rdata, ALEN(        lp_rdata) },
998 	{      "EUI48",      eui48_rdata, ALEN(     eui48_rdata) },
999 	{      "EUI64",      eui64_rdata, ALEN(     eui64_rdata) }, /* - 109 */
1000 	{         NULL,             NULL, 0                      },
1001 	{         NULL,             NULL, 0                      },
1002 	{         NULL,             NULL, 0                      },
1003 	{         NULL,             NULL, 0                      },
1004 	{         NULL,             NULL, 0                      },
1005 	{         NULL,             NULL, 0                      },
1006 	{         NULL,             NULL, 0                      },
1007 	{         NULL,             NULL, 0                      },
1008 	{         NULL,             NULL, 0                      },
1009 	{         NULL,             NULL, 0                      },
1010 	{         NULL,             NULL, 0                      },
1011 	{         NULL,             NULL, 0                      },
1012 	{         NULL,             NULL, 0                      },
1013 	{         NULL,             NULL, 0                      },
1014 	{         NULL,             NULL, 0                      },
1015 	{         NULL,             NULL, 0                      },
1016 	{         NULL,             NULL, 0                      },
1017 	{         NULL,             NULL, 0                      },
1018 	{         NULL,             NULL, 0                      },
1019 	{         NULL,             NULL, 0                      },
1020 	{         NULL,             NULL, 0                      },
1021 	{         NULL,             NULL, 0                      },
1022 	{         NULL,             NULL, 0                      },
1023 	{         NULL,             NULL, 0                      },
1024 	{         NULL,             NULL, 0                      },
1025 	{         NULL,             NULL, 0                      },
1026 	{         NULL,             NULL, 0                      },
1027 	{         NULL,             NULL, 0                      },
1028 	{         NULL,             NULL, 0                      },
1029 	{         NULL,             NULL, 0                      },
1030 	{         NULL,             NULL, 0                      },
1031 	{         NULL,             NULL, 0                      },
1032 	{         NULL,             NULL, 0                      },
1033 	{         NULL,             NULL, 0                      },
1034 	{         NULL,             NULL, 0                      },
1035 	{         NULL,             NULL, 0                      },
1036 	{         NULL,             NULL, 0                      },
1037 	{         NULL,             NULL, 0                      },
1038 	{         NULL,             NULL, 0                      },
1039 	{         NULL,             NULL, 0                      },
1040 	{         NULL,             NULL, 0                      },
1041 	{         NULL,             NULL, 0                      },
1042 	{         NULL,             NULL, 0                      },
1043 	{         NULL,             NULL, 0                      },
1044 	{         NULL,             NULL, 0                      },
1045 	{         NULL,             NULL, 0                      },
1046 	{         NULL,             NULL, 0                      },
1047 	{         NULL,             NULL, 0                      },
1048 	{         NULL,             NULL, 0                      },
1049 	{         NULL,             NULL, 0                      },
1050 	{         NULL,             NULL, 0                      },
1051 	{         NULL,             NULL, 0                      },
1052 	{         NULL,             NULL, 0                      },
1053 	{         NULL,             NULL, 0                      },
1054 	{         NULL,             NULL, 0                      },
1055 	{         NULL,             NULL, 0                      },
1056 	{         NULL,             NULL, 0                      },
1057 	{         NULL,             NULL, 0                      },
1058 	{         NULL,             NULL, 0                      },
1059 	{         NULL,             NULL, 0                      },
1060 	{         NULL,             NULL, 0                      },
1061 	{         NULL,             NULL, 0                      },
1062 	{         NULL,             NULL, 0                      },
1063 	{         NULL,             NULL, 0                      },
1064 	{         NULL,             NULL, 0                      },
1065 	{         NULL,             NULL, 0                      },
1066 	{         NULL,             NULL, 0                      },
1067 	{         NULL,             NULL, 0                      },
1068 	{         NULL,             NULL, 0                      },
1069 	{         NULL,             NULL, 0                      },
1070 	{         NULL,             NULL, 0                      },
1071 	{         NULL,             NULL, 0                      },
1072 	{         NULL,             NULL, 0                      },
1073 	{         NULL,             NULL, 0                      },
1074 	{         NULL,             NULL, 0                      },
1075 	{         NULL,             NULL, 0                      },
1076 	{         NULL,             NULL, 0                      },
1077 	{         NULL,             NULL, 0                      },
1078 	{         NULL,             NULL, 0                      },
1079 	{         NULL,             NULL, 0                      },
1080 	{         NULL,             NULL, 0                      },
1081 	{         NULL,             NULL, 0                      },
1082 	{         NULL,             NULL, 0                      },
1083 	{         NULL,             NULL, 0                      },
1084 	{         NULL,             NULL, 0                      },
1085 	{         NULL,             NULL, 0                      },
1086 	{         NULL,             NULL, 0                      },
1087 	{         NULL,             NULL, 0                      },
1088 	{         NULL,             NULL, 0                      },
1089 	{         NULL,             NULL, 0                      },
1090 	{         NULL,             NULL, 0                      },
1091 	{         NULL,             NULL, 0                      },
1092 	{         NULL,             NULL, 0                      },
1093 	{         NULL,             NULL, 0                      },
1094 	{         NULL,             NULL, 0                      },
1095 	{         NULL,             NULL, 0                      },
1096 	{         NULL,             NULL, 0                      },
1097 	{         NULL,             NULL, 0                      },
1098 	{         NULL,             NULL, 0                      },
1099 	{         NULL,             NULL, 0                      },
1100 	{         NULL,             NULL, 0                      },
1101 	{         NULL,             NULL, 0                      },
1102 	{         NULL,             NULL, 0                      },
1103 	{         NULL,             NULL, 0                      },
1104 	{         NULL,             NULL, 0                      },
1105 	{         NULL,             NULL, 0                      },
1106 	{         NULL,             NULL, 0                      },
1107 	{         NULL,             NULL, 0                      },
1108 	{         NULL,             NULL, 0                      },
1109 	{         NULL,             NULL, 0                      },
1110 	{         NULL,             NULL, 0                      },
1111 	{         NULL,             NULL, 0                      },
1112 	{         NULL,             NULL, 0                      },
1113 	{         NULL,             NULL, 0                      },
1114 	{         NULL,             NULL, 0                      },
1115 	{         NULL,             NULL, 0                      },
1116 	{         NULL,             NULL, 0                      },
1117 	{         NULL,             NULL, 0                      },
1118 	{         NULL,             NULL, 0                      },
1119 	{         NULL,             NULL, 0                      },
1120 	{         NULL,             NULL, 0                      },
1121 	{         NULL,             NULL, 0                      },
1122 	{         NULL,             NULL, 0                      },
1123 	{         NULL,             NULL, 0                      },
1124 	{         NULL,             NULL, 0                      },
1125 	{         NULL,             NULL, 0                      },
1126 	{         NULL,             NULL, 0                      },
1127 	{         NULL,             NULL, 0                      },
1128 	{         NULL,             NULL, 0                      },
1129 	{         NULL,             NULL, 0                      },
1130 	{         NULL,             NULL, 0                      },
1131 	{         NULL,             NULL, 0                      },
1132 	{         NULL,             NULL, 0                      },
1133 	{         NULL,             NULL, 0                      },
1134 	{         NULL,             NULL, 0                      },
1135 	{         NULL,             NULL, 0                      },
1136 	{         NULL,             NULL, 0                      },
1137 	{         NULL,             NULL, 0                      },
1138 	{         NULL,             NULL, 0                      },
1139 	{       "TKEY",       tkey_rdata, ALEN(      tkey_rdata) }, /* 249 - */
1140 	{       "TSIG",       tsig_rdata, ALEN(      tsig_rdata) }, /* - 250 */
1141 	{         NULL,             NULL, 0                      },
1142 	{         NULL,             NULL, 0                      },
1143 	{      "MAILB",    UNKNOWN_RDATA, 0                      }, /* 253 - */
1144 	{      "MAILA",    UNKNOWN_RDATA, 0                      }, /* - 254 */
1145 	{         NULL,             NULL, 0                      },
1146 	{        "URI",        uri_rdata, ALEN(       uri_rdata) }, /* 256 - */
1147 	{        "CAA",        caa_rdata, ALEN(       caa_rdata) },
1148 	{        "AVC",        txt_rdata, ALEN(       txt_rdata) },
1149 	{        "DOA",        doa_rdata, ALEN(       doa_rdata) },
1150 	{   "AMTRELAY",   amtrelay_rdata, ALEN(  amtrelay_rdata) }, /* - 260 */
1151 	{         "TA",         ds_rdata, ALEN(        ds_rdata) }, /* 32768 */
1152 	{        "DLV",        dlv_rdata, ALEN(       dlv_rdata) }  /* 32769 */
1153 };
1154 
1155 const _getdns_rr_def *
_getdns_rr_def_lookup(uint16_t rr_type)1156 _getdns_rr_def_lookup(uint16_t rr_type)
1157 {
1158 	if (rr_type <= 260)
1159 		return &_getdns_rr_defs[rr_type];
1160 	else if (rr_type == 32768)
1161 		return &_getdns_rr_defs[261];
1162 	else if (rr_type == 32769)
1163 		return &_getdns_rr_defs[262];
1164 	return _getdns_rr_defs;
1165 }
1166 
1167 const char *
_getdns_rr_type_name(int rr_type)1168 _getdns_rr_type_name(int rr_type)
1169 {
1170 	return _getdns_rr_def_lookup(rr_type)->name;
1171 }
1172 
1173 static void
write_int_rdata(gldns_buffer * buf,_getdns_rdf_type type,uint32_t value)1174 write_int_rdata(gldns_buffer *buf, _getdns_rdf_type type, uint32_t value)
1175 {
1176 	size_t j;
1177 
1178 	for (j = type & GETDNS_RDF_FIXEDSZ; j; j--)
1179 		gldns_buffer_write_u8(buf,
1180 		    (uint8_t)(value >> (8 * (j - 1))) & 0xff);
1181 }
1182 
1183 static void
write_bindata_rdata(gldns_buffer * buf,_getdns_rdf_type type,getdns_bindata * bindata)1184 write_bindata_rdata(gldns_buffer *buf,
1185     _getdns_rdf_type type, getdns_bindata *bindata)
1186 {
1187 	if (type & GETDNS_RDF_LEN_VAL)
1188 		write_int_rdata(buf, type >> 8, bindata->size);
1189 
1190 	gldns_buffer_write(buf, bindata->data, bindata->size);
1191 }
1192 
1193 
1194 static getdns_return_t
write_rdata_field(gldns_buffer * buf,uint8_t * rdata_start,const _getdns_rdata_def * rd_def,getdns_dict * rdata)1195 write_rdata_field(gldns_buffer *buf, uint8_t *rdata_start,
1196     const _getdns_rdata_def *rd_def, getdns_dict *rdata)
1197 {
1198 	getdns_return_t  r;
1199 	getdns_list     *list;
1200 	uint32_t         value;
1201 	getdns_bindata  *bindata;
1202 	size_t           i, rdf_len;
1203 
1204 	if (rd_def->type & GETDNS_RDF_INTEGER) {
1205 		if (!(rd_def->type & GETDNS_RDF_REPEAT)) {
1206 			if ((r = getdns_dict_get_int(
1207 			    rdata, rd_def->name, &value)))
1208 				return r;
1209 			else
1210 				write_int_rdata(buf, rd_def->type, value);
1211 
1212 		} else if ((r = getdns_dict_get_list(
1213 		    rdata, rd_def->name, &list)))
1214 
1215 			return r == GETDNS_RETURN_NO_SUCH_DICT_NAME
1216 			          ? GETDNS_RETURN_GOOD : r;
1217 
1218 		else for ( i = 0
1219 			 ; GETDNS_RETURN_GOOD ==
1220 			       (r = getdns_list_get_int(list, i, &value))
1221 			 ; i++)
1222 			write_int_rdata(buf, rd_def->type, value);
1223 
1224 
1225 	} else if (rd_def->type & GETDNS_RDF_BINDATA) {
1226 
1227 
1228 		if (!(rd_def->type & GETDNS_RDF_REPEAT)) {
1229 			if ((r = getdns_dict_get_bindata(
1230 			    rdata, rd_def->name, &bindata)))
1231 				return r;
1232 			else
1233 				write_bindata_rdata(buf, rd_def->type, bindata);
1234 
1235 		} else if ((r = getdns_dict_get_list(
1236 		    rdata, rd_def->name, &list)))
1237 
1238 			return r == GETDNS_RETURN_NO_SUCH_DICT_NAME
1239 			          ? GETDNS_RETURN_GOOD : r;
1240 
1241 		else for ( i = 0
1242 			 ; GETDNS_RETURN_GOOD ==
1243 			       (r = getdns_list_get_bindata(list, i, &bindata))
1244 			 ; i++)
1245 			write_bindata_rdata(buf, rd_def->type, bindata);
1246 
1247 
1248 	} else if (!(rd_def->type & GETDNS_RDF_SPECIAL)) {
1249 		/* Unknown rdata type */
1250 		return GETDNS_RETURN_GENERIC_ERROR;
1251 
1252 	} else if (!(rd_def->type & GETDNS_RDF_REPEAT)) {
1253 		/*
1254 		 * Non repetitive special rdatafield,
1255 		 * We must have a dict2wire function
1256 		 */
1257 		assert(rd_def->special->dict2wire);
1258 
1259 		rdf_len = gldns_buffer_remaining(buf);
1260 		r = rd_def->special->dict2wire(rdata, rdata_start,
1261 		    gldns_buffer_current(buf), &rdf_len);
1262 		if (r == GETDNS_RETURN_GOOD ||
1263 		    r == GETDNS_RETURN_NEED_MORE_SPACE)
1264 			gldns_buffer_skip(buf, rdf_len);
1265 		if (r)
1266 			return r;
1267 
1268 	/* We do not have repetitive special rdata fields (yet)
1269 	 *
1270 	 * LCOV_EXCL_START
1271 	 */
1272 	} else if ((r = getdns_dict_get_list(rdata, rd_def->name, &list))) {
1273 
1274 		return r == GETDNS_RETURN_NO_SUCH_DICT_NAME
1275 			  ? GETDNS_RETURN_GOOD : r;
1276 
1277 	} else for ( i = 0; r == GETDNS_RETURN_GOOD; i++ ) {
1278 		/*
1279 		 * A repetitive special rdata field must have the list2wire
1280 		 * function.
1281 		 */
1282 		assert(rd_def->special->list2wire);
1283 
1284 		rdf_len = gldns_buffer_remaining(buf);
1285 		r = rd_def->special->list2wire(list, i, rdata_start,
1286 		    gldns_buffer_current(buf), &rdf_len);
1287 		if (r == GETDNS_RETURN_GOOD ||
1288 		    r == GETDNS_RETURN_NEED_MORE_SPACE)
1289 			gldns_buffer_skip(buf, rdf_len);
1290 	}
1291 	/* LCOV_EXCL_STOP */
1292 
1293 	return r != GETDNS_RETURN_NO_SUCH_LIST_ITEM ? r : GETDNS_RETURN_GOOD;
1294 }
1295 
1296 getdns_return_t
_getdns_rr_dict2wire(const getdns_dict * rr_dict,gldns_buffer * buf)1297 _getdns_rr_dict2wire(const getdns_dict *rr_dict, gldns_buffer *buf)
1298 {
1299 	getdns_return_t r = GETDNS_RETURN_GOOD;
1300 	getdns_bindata root = { 1, (void *)"" };
1301 	getdns_bindata *name;
1302 	getdns_bindata *rdata_raw;
1303 	getdns_dict *rdata;
1304 	uint32_t rr_type;
1305 	uint32_t rr_class = GETDNS_RRCLASS_IN;
1306 	uint32_t rr_ttl = 0;
1307 	uint32_t value;
1308 	const _getdns_rr_def *rr_def;
1309 	const _getdns_rdata_def *rd_def, *rep_rd_def;
1310 	int n_rdata_fields, rep_n_rdata_fields;
1311 	size_t rdata_size_mark;
1312 	uint8_t *rdata_start;
1313 	getdns_list *list;
1314 	size_t i;
1315 
1316 	assert(rr_dict);
1317 	assert(buf);
1318 
1319 	if ((r = getdns_dict_get_int(rr_dict, "type", &rr_type)))
1320 		return r;
1321 	if ((r = getdns_dict_get_bindata(rr_dict, "name", &name))) {
1322 		if (r == GETDNS_RETURN_NO_SUCH_DICT_NAME &&
1323 		    rr_type == GETDNS_RRTYPE_OPT) {
1324 			name = &root;
1325 		} else
1326 			return r;
1327 	}
1328 	gldns_buffer_write(buf, name->data, name->size);
1329 	gldns_buffer_write_u16(buf, (uint16_t)rr_type);
1330 
1331 	(void) getdns_dict_get_int(rr_dict, "class", &rr_class);
1332 	if (rr_type == GETDNS_RRTYPE_OPT)
1333 		(void) getdns_dict_get_int(
1334 		    rr_dict, "udp_payload_size", &rr_class);
1335 	gldns_buffer_write_u16(buf, (uint16_t)rr_class);
1336 
1337 	(void) getdns_dict_get_int(rr_dict, "ttl", &rr_ttl);
1338 	if (rr_type == GETDNS_RRTYPE_OPT) {
1339 		if (!getdns_dict_get_int(rr_dict, "extended_rcode", &value))
1340 			rr_ttl = (rr_ttl & 0x00FFFFFF)|((value & 0xFF) << 24);
1341 		if (!getdns_dict_get_int(rr_dict, "version", &value))
1342 			rr_ttl = (rr_ttl & 0xFF00FFFF)|((value & 0xFF) << 16);
1343 		if (!getdns_dict_get_int(rr_dict, "z", &value))
1344 			rr_ttl = (rr_ttl & 0xFFFF0000)| (value & 0xFFFF);
1345 		if (!getdns_dict_get_int(rr_dict, "do", &value))
1346 			rr_ttl = (rr_ttl & 0xFFFF7FFF)| (value ? 0x8000 : 0);
1347 	}
1348 	gldns_buffer_write_u32(buf, rr_ttl);
1349 
1350 	/* Does rdata contain compressed names?
1351 	 * Because rdata_raw is unusable then.
1352 	 */
1353 	rr_def = _getdns_rr_def_lookup(rr_type);
1354 	for ( rd_def = rr_def->rdata
1355 	    , n_rdata_fields = rr_def->n_rdata_fields
1356 	    ; n_rdata_fields ; n_rdata_fields-- , rd_def++ ) {
1357 
1358 		if (rd_def->type & GETDNS_RDF_COMPRESSED)
1359 			break;
1360 	}
1361 
1362 	if ((r = getdns_dict_get_dict(rr_dict, "rdata", &rdata))) {
1363 		if (r == GETDNS_RETURN_NO_SUCH_DICT_NAME) {
1364 			gldns_buffer_write_u16(buf, 0);
1365 			r = GETDNS_RETURN_GOOD;
1366 		}
1367 
1368 	} else if (n_rdata_fields == 0 && GETDNS_RETURN_GOOD ==
1369 	    (r = getdns_dict_get_bindata(rdata, "rdata_raw", &rdata_raw))) {
1370 
1371 		gldns_buffer_write_u16(buf, (uint16_t)rdata_raw->size);
1372 		gldns_buffer_write(buf, rdata_raw->data, rdata_raw->size);
1373 
1374 	} else if (n_rdata_fields || r == GETDNS_RETURN_NO_SUCH_DICT_NAME) {
1375 
1376 		r = GETDNS_RETURN_GOOD;
1377 		rdata_size_mark = gldns_buffer_position(buf);
1378 		gldns_buffer_skip(buf, 2);
1379 		rdata_start = gldns_buffer_current(buf);
1380 
1381 		for ( rd_def = rr_def->rdata
1382 		    , n_rdata_fields = rr_def->n_rdata_fields
1383 		    ; n_rdata_fields ; n_rdata_fields-- , rd_def++ ) {
1384 
1385 			if (rd_def->type == GETDNS_RDF_REPEAT)
1386 				break;
1387 
1388 			if ((r = write_rdata_field(buf,
1389 			    rdata_start, rd_def, rdata)))
1390 				break;
1391 		}
1392 		if (n_rdata_fields == 0 || r) {
1393 			/* pass */;
1394 
1395 		} else if ((r = getdns_dict_get_list(
1396 		    rdata, rd_def->name, &list))) {
1397 			/* pass */;
1398 
1399 		} else for ( i = 0
1400 		           ; r == GETDNS_RETURN_GOOD
1401 		           ; i++) {
1402 
1403 			if ((r = getdns_list_get_dict(list, i, &rdata))) {
1404 				if (r == GETDNS_RETURN_NO_SUCH_LIST_ITEM)
1405 					r = GETDNS_RETURN_GOOD;
1406 				break;
1407 			}
1408 			for ( rep_rd_def = rd_def + 1
1409 			    , rep_n_rdata_fields = n_rdata_fields - 1
1410 			    ; rep_n_rdata_fields
1411 			    ; rep_n_rdata_fields--, rep_rd_def++ ) {
1412 
1413 				if ((r = write_rdata_field(buf,
1414 				    rdata_start, rep_rd_def, rdata)))
1415 					break;
1416 			}
1417 		}
1418 		gldns_buffer_write_u16_at(buf, rdata_size_mark,
1419 		    (uint16_t)(gldns_buffer_position(buf)-rdata_size_mark-2));
1420 	}
1421 	return r;
1422 }
1423 
1424