1 /**
2  *
3  * getdns dict management functions, note that the internal storage is
4  * accomplished via an _getdns_rbtree_t
5  *
6  * Interfaces originally taken from the getdns API description pseudo implementation.
7  *
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 "config.h"
38 #include <ctype.h>
39 #ifndef USE_WINSOCK
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #endif
45 
46 #include "types-internal.h"
47 #include "util-internal.h"
48 #include "dict.h"
49 #include "list.h"
50 #include "rr-dict.h"
51 #include "const-info.h"
52 #include "gldns/gbuffer.h"
53 #include "gldns/wire2str.h"
54 #include "gldns/parseutil.h"
55 
56 
_json_ptr_first(const struct mem_funcs * mf,const char * jptr,char * first,ssize_t first_sz)57 static char *_json_ptr_first(const struct mem_funcs *mf,
58     const char *jptr, char *first, ssize_t first_sz)
59 {
60 	const char *next_ref, *k;
61 	char *j;
62 
63 	if (*jptr != '/')
64 		return (char *)jptr;
65 	jptr++;
66 	if (!(next_ref = strchr(jptr, '/')))
67 		next_ref = strchr(jptr, '\0');
68 
69 	if ((ssize_t)(next_ref - jptr + 1) > first_sz || !first)
70 		first = GETDNS_XMALLOC(*mf, char, next_ref - jptr + 1);
71 
72 	for (j = first, k = jptr; k < next_ref; j++, k++)
73 		*j = k[0] == '~' && k[1] == '1' ? (k++, '/') : *k;
74 	*j = '\0';
75 	for (j = first, k = first; *k; j++, k++)
76 		*j = k[0] == '~' && k[1] == '0' ? (k++, '~') : *k;
77 	*j = '\0';
78 
79 	return first;
80 }
81 
82 
83 static struct getdns_dict_item *
_find_dict_item(const getdns_dict * dict,const char * jptr)84 _find_dict_item(const getdns_dict *dict, const char *jptr)
85 {
86 	char first_spc[1024], *first;
87 	struct getdns_dict_item *d;
88 
89 	first = _json_ptr_first(&dict->mf, jptr,
90 	    first_spc, sizeof(first_spc));
91 
92 	d = (struct getdns_dict_item *) _getdns_rbtree_search(
93 	    (_getdns_rbtree_t *)&(dict->root), first);
94 
95 	if (first && first != jptr && first != first_spc)
96 		GETDNS_FREE(dict->mf, first);
97 
98 	return d;
99 }
100 
101 
102 static struct getdns_dict_item *
_delete_dict_item(const getdns_dict * dict,const char * jptr)103 _delete_dict_item(const getdns_dict *dict, const char *jptr)
104 {
105 	char first_spc[1024], *first;
106 	struct getdns_dict_item *d;
107 
108 	first = _json_ptr_first(&dict->mf, jptr,
109 	    first_spc, sizeof(first_spc));
110 
111 	d = (struct getdns_dict_item *) _getdns_rbtree_delete(
112 	    (_getdns_rbtree_t *)&(dict->root), first);
113 
114 	if (first && first != jptr && first != first_spc)
115 		GETDNS_FREE(dict->mf, first);
116 
117 	return d;
118 }
119 
120 
121 static char *
_json_ptr_keydup(const struct mem_funcs * mf,const char * jptr)122 _json_ptr_keydup(const struct mem_funcs *mf, const char *jptr)
123 {
124 	char *first = _json_ptr_first(mf, jptr, NULL, 0);
125 
126 	if (first == jptr || first == jptr + 1) {
127 		size_t sz = strlen(jptr) + 1;
128 
129 		if ((first = GETDNS_XMALLOC(*mf, char, sz)))
130 			memcpy(first, jptr, sz);
131 	}
132 	return first;
133 }
134 
135 
136 getdns_return_t
_getdns_dict_find(const getdns_dict * dict,const char * key,getdns_item ** item)137 _getdns_dict_find(const getdns_dict *dict, const char *key, getdns_item **item)
138 {
139 	const char *next;
140 	struct getdns_dict_item *d;
141 
142 	if (!(d = _find_dict_item(dict, key)))
143 		return GETDNS_RETURN_NO_SUCH_DICT_NAME;
144 
145 	if (*key != '/' || !(next = strchr(key + 1, '/'))) {
146 		*item = &d->i;
147 		return GETDNS_RETURN_GOOD;
148 
149 	} else switch (d->i.dtype) { /* Key was nested reference */
150 	case t_dict: return _getdns_dict_find(d->i.data.dict, next, item);
151 	case t_list: return _getdns_list_find(d->i.data.list, next, item);
152 	default    : /* Trying to dereference a non list or dict */
153 	             return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
154 	}
155 }
156 
157 
158 /*---------------------------------------- getdns_dict_item_free */
159 /**
160  * private function used to release storage associated with a dictionary item
161  * @param node all memory in this structure and its children will be freed
162  * @param arg is a dict who's custom memory function will be used
163  *            to free the items
164  * @return void
165  */
166 static void
getdns_dict_item_free(_getdns_rbnode_t * node,void * arg)167 getdns_dict_item_free(_getdns_rbnode_t *node, void *arg)
168 {
169 	struct getdns_dict_item *d = (struct getdns_dict_item *)node;
170 	struct getdns_dict *dict = (struct getdns_dict *)arg;
171 
172 	assert(node);
173 	assert(arg);
174 
175 	switch (d->i.dtype) {
176 	case t_dict   : getdns_dict_destroy(d->i.data.dict); break;
177 	case t_list   : getdns_list_destroy(d->i.data.list); break;
178 	case t_bindata: _getdns_bindata_destroy(&dict->mf, d->i.data.bindata);
179 	default       : break;
180 	}
181 	if (node->key)
182 		GETDNS_FREE(dict->mf, (void *)node->key);
183 	GETDNS_FREE(dict->mf, node);
184 }				/* getdns_dict_item_free */
185 
186 
187 getdns_return_t
getdns_dict_remove_name(getdns_dict * dict,const char * name)188 getdns_dict_remove_name(getdns_dict *dict, const char *name)
189 {
190 	const char *next;
191 	struct getdns_dict_item *d;
192 
193 	if (!dict || !name)
194 		return GETDNS_RETURN_INVALID_PARAMETER;
195 
196 	if (!(d = _find_dict_item(dict, name)))
197 		return GETDNS_RETURN_NO_SUCH_DICT_NAME;
198 
199 	if (*name != '/' || !(next = strchr(name + 1, '/'))) {
200 		d = _delete_dict_item(dict, name);
201 		getdns_dict_item_free(&d->node, dict);
202 		return GETDNS_RETURN_GOOD;
203 
204 	} else switch (d->i.dtype) {
205 	case t_dict: return getdns_dict_remove_name(d->i.data.dict, next);
206 	case t_list: return _getdns_list_remove_name(d->i.data.list, next);
207 	default    : /* Trying to dereference a non list or dict */
208 	             return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
209 	}
210 }
211 
212 
213 getdns_return_t
_getdns_dict_find_and_add(getdns_dict * dict,const char * key,getdns_item ** item)214 _getdns_dict_find_and_add(
215     getdns_dict *dict, const char *key, getdns_item **item)
216 {
217 	const char *next;
218 	struct getdns_dict_item *d;
219 
220 	if (!(d = _find_dict_item(dict, key))) {
221 		/* add a node */
222 		d = GETDNS_MALLOC(dict->mf, struct getdns_dict_item);
223 		d->node.key = _json_ptr_keydup(&dict->mf, key);
224 		_getdns_rbtree_insert(&(dict->root), (_getdns_rbnode_t *) d);
225 		if (*key != '/' || !(next = strchr(key + 1, '/'))) {
226 			(void) memset(&d->i.data, 0, sizeof(d->i.data));
227 			d->i.dtype = t_int;
228 			d->i.data.n = 55555333;
229 			*item = &d->i;
230 			return GETDNS_RETURN_GOOD;
231 		}
232 		if ((next[1] == '0' || next[1] == '-') &&
233 		    (next[2] == '/' || next[2] == '\0')) {
234 
235 			d->i.dtype = t_list;
236 			d->i.data.list =_getdns_list_create_with_mf(&dict->mf);
237 			return _getdns_list_find_and_add(
238 			    d->i.data.list, next, item);
239 		}
240 		d->i.dtype = t_dict;
241 		d->i.data.dict = _getdns_dict_create_with_mf(&dict->mf);
242 		return _getdns_dict_find_and_add(d->i.data.dict, next, item);
243 	}
244 	if (*key != '/' || !(next = strchr(key + 1, '/'))) {
245 		switch (d->i.dtype) {
246 		case t_dict   : getdns_dict_destroy(d->i.data.dict); break;
247 		case t_list   : getdns_list_destroy(d->i.data.list); break;
248 		case t_bindata: _getdns_bindata_destroy(
249 				      &dict->mf, d->i.data.bindata); break;
250 		default       : break;
251 		}
252 		d->i.dtype = t_int;
253 		d->i.data.n = 33355555;
254 		*item = &d->i;
255 		return GETDNS_RETURN_GOOD;
256 
257 	} else switch (d->i.dtype) {  /* Key was nested reference */
258 	case t_dict:return _getdns_dict_find_and_add(d->i.data.dict,next,item);
259 	case t_list:return _getdns_list_find_and_add(d->i.data.list,next,item);
260 	default    :/* Trying to dereference a non list or dict */
261 	            return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
262 	}
263 }				/* getdns_dict_find_and_add */
264 
265 
266 /*---------------------------------------- getdns_dict_get_names
267 */
268 getdns_return_t
getdns_dict_get_names(const getdns_dict * dict,getdns_list ** answer)269 getdns_dict_get_names(const getdns_dict *dict, getdns_list **answer)
270 {
271 	struct getdns_dict_item *item;
272 
273 	if (!dict || !answer)
274 		return GETDNS_RETURN_INVALID_PARAMETER;
275 
276 	*answer = getdns_list_create_with_extended_memory_functions(
277 		dict->mf.mf_arg, dict->mf.mf.ext.malloc,
278 		dict->mf.mf.ext.realloc, dict->mf.mf.ext.free);
279 	if (!*answer)
280 		return GETDNS_RETURN_NO_SUCH_DICT_NAME;
281 
282 	RBTREE_FOR(item, struct getdns_dict_item *,
283 		(_getdns_rbtree_t *)&(dict->root)) {
284 		_getdns_list_append_string(*answer, item->node.key);
285 	}
286 	return GETDNS_RETURN_GOOD;
287 }				/* getdns_dict_get_names */
288 
289 /*---------------------------------------- getdns_dict_get_data_type */
290 getdns_return_t
getdns_dict_get_data_type(const getdns_dict * dict,const char * name,getdns_data_type * answer)291 getdns_dict_get_data_type(
292     const getdns_dict *dict, const char *name, getdns_data_type *answer)
293 {
294 	getdns_return_t r;
295 	getdns_item *item;
296 
297 	if (!dict || !name || !answer)
298 		return GETDNS_RETURN_INVALID_PARAMETER;
299 
300 	if ((r = _getdns_dict_find(dict, name, &item)))
301 		return r;
302 
303 	*answer = item->dtype;
304 	return GETDNS_RETURN_GOOD;
305 }				/* getdns_dict_get_data_type */
306 
307 /*---------------------------------------- getdns_dict_get_dict */
308 getdns_return_t
getdns_dict_get_dict(const getdns_dict * dict,const char * name,getdns_dict ** answer)309 getdns_dict_get_dict(
310     const getdns_dict *dict, const char *name, getdns_dict **answer)
311 {
312 	getdns_return_t r;
313 	getdns_item *item;
314 
315 	if (!dict || !name || !answer)
316 		return GETDNS_RETURN_INVALID_PARAMETER;
317 
318 	if ((r = _getdns_dict_find(dict, name, &item)))
319 		return r;
320 
321 	if (item->dtype != t_dict)
322 		return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
323 
324 	*answer = item->data.dict;
325 	return GETDNS_RETURN_GOOD;
326 }				/* getdns_dict_get_dict */
327 
328 /*---------------------------------------- getdns_dict_get_list */
329 getdns_return_t
getdns_dict_get_list(const getdns_dict * dict,const char * name,getdns_list ** answer)330 getdns_dict_get_list(
331     const getdns_dict *dict, const char *name, getdns_list **answer)
332 {
333 	getdns_return_t r;
334 	getdns_item *item;
335 
336 	if (!dict || !name || !answer)
337 		return GETDNS_RETURN_INVALID_PARAMETER;
338 
339 	if ((r = _getdns_dict_find(dict, name, &item)))
340 		return r;
341 
342 	if (item->dtype != t_list)
343 		return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
344 
345 	*answer = item->data.list;
346 	return GETDNS_RETURN_GOOD;
347 }				/* getdns_dict_get_list */
348 
349 /*---------------------------------------- getdns_dict_get_bindata */
350 getdns_return_t
getdns_dict_get_bindata(const getdns_dict * dict,const char * name,getdns_bindata ** answer)351 getdns_dict_get_bindata(
352     const getdns_dict *dict, const char *name, getdns_bindata **answer)
353 {
354 	getdns_return_t r;
355 	getdns_item *item;
356 
357 	if (!dict || !name || !answer)
358 		return GETDNS_RETURN_INVALID_PARAMETER;
359 
360 	if ((r = _getdns_dict_find(dict, name, &item)))
361 		return GETDNS_RETURN_NO_SUCH_DICT_NAME;
362 
363 	if (item->dtype != t_bindata)
364 		return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
365 
366 	*answer = item->data.bindata;
367 	return GETDNS_RETURN_GOOD;
368 }				/* getdns_dict_get_bindata */
369 
370 /*---------------------------------------- getdns_dict_get_int */
371 getdns_return_t
getdns_dict_get_int(const getdns_dict * dict,const char * name,uint32_t * answer)372 getdns_dict_get_int(
373     const getdns_dict *dict, const char *name, uint32_t *answer)
374 {
375 	getdns_return_t r;
376 	getdns_item *item;
377 
378 	if (!dict || !name || !answer)
379 		return GETDNS_RETURN_INVALID_PARAMETER;
380 
381 	if ((r = _getdns_dict_find(dict, name, &item)))
382 		return r;
383 
384 	if (item->dtype != t_int)
385 		return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
386 
387 	*answer = item->data.n;
388 	return GETDNS_RETURN_GOOD;
389 }				/* getdns_dict_get_int */
390 
391 struct getdns_dict *
getdns_dict_create_with_extended_memory_functions(void * userarg,void * (* malloc)(void * userarg,size_t),void * (* realloc)(void * userarg,void *,size_t),void (* free)(void * userarg,void *))392 getdns_dict_create_with_extended_memory_functions(
393 	void *userarg,
394 	void *(*malloc)(void *userarg, size_t),
395 	void *(*realloc)(void *userarg, void *, size_t),
396 	void (*free)(void *userarg, void *))
397 {
398 	struct getdns_dict *dict;
399 	mf_union mf;
400 
401 	if (!malloc || !realloc || !free)
402 		return NULL;
403 
404 	mf.ext.malloc = malloc;
405 	dict = userarg == MF_PLAIN
406 		 ? (struct getdns_dict*)(*mf.pln.malloc)(
407 			   sizeof(struct getdns_dict))
408 		 : (struct getdns_dict*)(*mf.ext.malloc)(userarg,
409 			   sizeof(struct getdns_dict));
410 	if (!dict)
411 		return NULL;
412 
413 	dict->mf.mf_arg         = userarg;
414 	dict->mf.mf.ext.malloc  = malloc;
415 	dict->mf.mf.ext.realloc = realloc;
416 	dict->mf.mf.ext.free    = free;
417 
418 	_getdns_rbtree_init(&(dict->root),
419 		(int (*)(const void *, const void *)) strcmp);
420 	return dict;
421 }
422 
423 struct getdns_dict *
getdns_dict_create_with_memory_functions(void * (* malloc)(size_t),void * (* realloc)(void *,size_t),void (* free)(void *))424 getdns_dict_create_with_memory_functions(void *(*malloc)(size_t),
425 	void *(*realloc)(void *, size_t), void (*free)(void *))
426 {
427 	mf_union mf;
428 	mf.pln.malloc = malloc;
429 	mf.pln.realloc = realloc;
430 	mf.pln.free = free;
431 	return getdns_dict_create_with_extended_memory_functions(
432 		MF_PLAIN, mf.ext.malloc, mf.ext.realloc, mf.ext.free);
433 }
434 
435 /*-------------------------- getdns_dict_create_with_context */
436 struct getdns_dict *
getdns_dict_create_with_context(const getdns_context * context)437 getdns_dict_create_with_context(const getdns_context *context)
438 {
439 	if (context)
440 		return getdns_dict_create_with_extended_memory_functions(
441 			context->mf.mf_arg, context->mf.mf.ext.malloc,
442 			context->mf.mf.ext.realloc, context->mf.mf.ext.free);
443 	else
444 		return getdns_dict_create_with_memory_functions(&malloc,
445 			&realloc, &free);
446 }			/* getdns_dict_create_with_context */
447 
448 /*---------------------------------------- getdns_dict_create */
449 struct getdns_dict *
getdns_dict_create()450 getdns_dict_create()
451 {
452 	return getdns_dict_create_with_context(NULL);
453 }					/* getdns_dict_create */
454 
455 /*---------------------------------------- _getdns_dict_copy */
456 /**
457  * private function used to make a copy of a dict structure,
458  * the caller is responsible * for freeing storage allocated to returned value
459  * @param srcdict the dictionary structure to copy
460  * @param dstdict the copy destination
461  * @return the address of the copy of the dictionary structure on success
462  * @return NULL on error (out of memory, invalid srcdict)
463  */
464 getdns_return_t
_getdns_dict_copy(const struct getdns_dict * srcdict,struct getdns_dict ** dstdict)465 _getdns_dict_copy(const struct getdns_dict * srcdict,
466 	struct getdns_dict ** dstdict)
467 {
468 	struct getdns_dict_item *item;
469 	char *key;
470 	getdns_return_t retval;
471 
472 	if (!dstdict)
473 		return GETDNS_RETURN_INVALID_PARAMETER;
474 
475 	if (!srcdict) {
476 		*dstdict = NULL;
477 		return GETDNS_RETURN_GOOD;
478 	}
479 	*dstdict = getdns_dict_create_with_extended_memory_functions(
480 		srcdict->mf.mf_arg,
481 		srcdict->mf.mf.ext.malloc,
482 		srcdict->mf.mf.ext.realloc,
483 		srcdict->mf.mf.ext.free);
484 	if (!*dstdict)
485 		return GETDNS_RETURN_GENERIC_ERROR;
486 
487 	RBTREE_FOR(item, struct getdns_dict_item *,
488 		(struct _getdns_rbtree_t *)&(srcdict->root)) {
489 		key = (char *) item->node.key;
490 		switch (item->i.dtype) {
491 		case t_bindata:
492 			retval = getdns_dict_set_bindata(*dstdict, key,
493 				item->i.data.bindata);
494 			break;
495 
496 		case t_dict:
497 			retval = getdns_dict_set_dict(*dstdict, key,
498 				item->i.data.dict);
499 			break;
500 
501 		case t_int:
502 			retval = getdns_dict_set_int(*dstdict, key,
503 				item->i.data.n);
504 			break;
505 
506 		case t_list:
507 			retval = getdns_dict_set_list(*dstdict, key,
508 				item->i.data.list);
509 			break;
510 		default:
511 			retval = GETDNS_RETURN_WRONG_TYPE_REQUESTED;
512 			break;
513 		}
514 		if (retval != GETDNS_RETURN_GOOD) {
515 			getdns_dict_destroy(*dstdict);;
516 			*dstdict = NULL;
517 			return retval;
518 		}
519 	}
520 	return GETDNS_RETURN_GOOD;
521 }				/* _getdns_dict_copy */
522 
523 
524 /*---------------------------------------- getdns_dict_destroy */
525 void
getdns_dict_destroy(struct getdns_dict * dict)526 getdns_dict_destroy(struct getdns_dict *dict)
527 {
528 	if (!dict) return;
529 	_getdns_traverse_postorder(&(dict->root), getdns_dict_item_free, dict);
530 	GETDNS_FREE(dict->mf, dict);
531 }				/* getdns_dict_destroy */
532 
533 /*---------------------------------------- getdns_dict_set_dict */
534 getdns_return_t
_getdns_dict_set_this_dict(getdns_dict * dict,const char * name,getdns_dict * child_dict)535 _getdns_dict_set_this_dict(
536     getdns_dict *dict, const char *name, getdns_dict *child_dict)
537 {
538 	getdns_item    *item;
539 	getdns_return_t r;
540 
541 	if (!dict || !name || !child_dict)
542 		return GETDNS_RETURN_INVALID_PARAMETER;
543 
544 	if ((r = _getdns_dict_find_and_add(dict, name, &item)))
545 		return r;
546 
547 	item->dtype = t_dict;
548 	item->data.dict = child_dict;
549 	return GETDNS_RETURN_GOOD;
550 }				/* getdns_dict_set_dict */
551 
552 getdns_return_t
getdns_dict_set_dict(getdns_dict * dict,const char * name,const getdns_dict * child_dict)553 getdns_dict_set_dict(
554     getdns_dict *dict, const char *name, const getdns_dict *child_dict)
555 {
556 	getdns_dict    *newdict;
557 	getdns_return_t r;
558 
559 	if ((r = _getdns_dict_copy(child_dict, &newdict)))
560 		return r;
561 
562 	if ((r = _getdns_dict_set_this_dict(dict, name, newdict)))
563 		getdns_dict_destroy(newdict);
564 
565 	return r;
566 }
567 
568 
569 /*---------------------------------------- getdns_dict_set_list */
570 getdns_return_t
_getdns_dict_set_this_list(getdns_dict * dict,const char * name,getdns_list * child_list)571 _getdns_dict_set_this_list(
572     getdns_dict *dict, const char *name, getdns_list *child_list)
573 {
574 	getdns_item    *item;
575 	getdns_return_t r;
576 
577 	if (!dict || !name || !child_list)
578 		return GETDNS_RETURN_INVALID_PARAMETER;
579 
580 	if ((r = _getdns_dict_find_and_add(dict, name, &item)))
581 		return r;
582 
583 	item->dtype = t_list;
584 	item->data.list = child_list;
585 	return GETDNS_RETURN_GOOD;
586 }				/* getdns_dict_set_list */
587 
588 getdns_return_t
getdns_dict_set_list(getdns_dict * dict,const char * name,const getdns_list * child_list)589 getdns_dict_set_list(
590     getdns_dict *dict, const char *name, const getdns_list *child_list)
591 {
592 	getdns_list    *newlist;
593 	getdns_return_t r;
594 
595 	if ((r = _getdns_list_copy(child_list, &newlist)))
596 		return r;
597 
598 	if ((r = _getdns_dict_set_this_list(dict, name, newlist)))
599 		getdns_list_destroy(newlist);
600 
601 	return r;
602 }
603 
604 
605 /*---------------------------------------- getdns_dict_set_bindata */
606 getdns_return_t
_getdns_dict_set_this_bindata(getdns_dict * dict,const char * name,getdns_bindata * bindata)607 _getdns_dict_set_this_bindata(
608     getdns_dict *dict, const char *name, getdns_bindata *bindata)
609 {
610 	getdns_item    *item;
611 	getdns_return_t r;
612 
613 	if (!dict || !name || !bindata)
614 		return GETDNS_RETURN_INVALID_PARAMETER;
615 
616 	if ((r = _getdns_dict_find_and_add(dict, name, &item)))
617 		return r;
618 
619 	item->dtype = t_bindata;
620 	item->data.bindata = bindata;
621 	return GETDNS_RETURN_GOOD;
622 }
623 
624 getdns_return_t
_getdns_dict_set_const_bindata(getdns_dict * dict,const char * name,size_t size,const void * data)625 _getdns_dict_set_const_bindata(
626     getdns_dict *dict, const char *name, size_t size, const void *data)
627 {
628 	getdns_item    *item;
629 	getdns_bindata *newbindata;
630 	getdns_return_t r;
631 
632 	if (!dict || !name)
633 		return GETDNS_RETURN_INVALID_PARAMETER;
634 
635 	if (!(newbindata = _getdns_bindata_copy(&dict->mf, size, data)))
636 		return GETDNS_RETURN_MEMORY_ERROR;
637 
638 	if ((r = _getdns_dict_find_and_add(dict, name, &item))) {
639 		_getdns_bindata_destroy(&dict->mf, newbindata);
640 		return r;
641 	}
642 	item->dtype = t_bindata;
643 	item->data.bindata = newbindata;
644 	return GETDNS_RETURN_GOOD;
645 }
646 
647 getdns_return_t
getdns_dict_set_bindata(getdns_dict * dict,const char * name,const getdns_bindata * child_bindata)648 getdns_dict_set_bindata(
649     getdns_dict *dict, const char *name, const getdns_bindata *child_bindata)
650 {
651 	return !child_bindata ? GETDNS_RETURN_INVALID_PARAMETER
652 	    : _getdns_dict_set_const_bindata(
653 	    dict, name, child_bindata->size, child_bindata->data);
654 }
655 
656 /*---------------------------------------- getdns_dict_set_bindata */
657 getdns_return_t
getdns_dict_util_set_string(getdns_dict * dict,const char * name,const char * value)658 getdns_dict_util_set_string(getdns_dict *dict,
659     const char *name, const char *value)
660 {
661 	getdns_item    *item;
662 	getdns_bindata *newbindata;
663 	getdns_return_t r;
664 
665 	if (!dict || !name || !value)
666 		return GETDNS_RETURN_INVALID_PARAMETER;
667 
668 	if (!(newbindata = _getdns_bindata_copy(
669 	    &dict->mf, strlen(value) + 1, (uint8_t *)value)))
670 		return GETDNS_RETURN_MEMORY_ERROR;
671 
672 	newbindata->size -= 1;
673 
674 	if ((r = _getdns_dict_find_and_add(dict, name, &item))) {
675 		_getdns_bindata_destroy(&dict->mf, newbindata);
676 		return r;
677 	}
678 	item->dtype = t_bindata;
679 	item->data.bindata = newbindata;
680 	return GETDNS_RETURN_GOOD;
681 }				/* getdns_dict_util_set_dict */
682 
683 /*---------------------------------------- getdns_dict_set_int */
684 getdns_return_t
getdns_dict_set_int(getdns_dict * dict,const char * name,uint32_t child_uint32)685 getdns_dict_set_int(getdns_dict *dict, const char *name, uint32_t child_uint32)
686 {
687 	getdns_item    *item;
688 	getdns_return_t r;
689 
690 	if (!dict || !name)
691 		return GETDNS_RETURN_INVALID_PARAMETER;
692 
693 	if ((r = _getdns_dict_find_and_add(dict, name, &item)))
694 		return r;
695 
696 	item->dtype = t_int;
697 	item->data.n = child_uint32;
698 	return  GETDNS_RETURN_GOOD;
699 }				/* getdns_dict_set_int */
700 
701 /*---------------------------------------- getdns_pp_dict */
702 /**
703  * private function to help with indenting.
704  * @param indent number of spaces to return
705  * @return       a character string containing min(80, indent) spaces
706  */
707 static const char *
getdns_indent(size_t indent)708 getdns_indent(size_t indent)
709 {
710 	static const char *spaces = "                                        "
711 		"                                        ";
712 	return spaces + 80 - (indent < 80 ? indent : 0);
713 }				/* getdns_indent */
714 
715 int
_getdns_bindata_is_dname(getdns_bindata * bindata)716 _getdns_bindata_is_dname(getdns_bindata *bindata)
717 {
718 	size_t i = 0, n_labels = 0;
719 
720 	while (i < bindata->size && bindata->data[i]) {
721 		if (bindata->data[i] & 0xC0) /* Compression pointer! */
722 			return 0;
723 
724 		i += ((size_t)bindata->data[i]) + 1;
725 		n_labels++;
726 	}
727 	if (i < bindata->size && !bindata->data[i]) {
728 		n_labels++;
729 		i++;
730 	}
731 
732 	return i == bindata->size && n_labels > 1 &&
733 		bindata->data[bindata->size - 1] == 0;
734 }
735 
736 static int
getdns_pp_base64(gldns_buffer * buf,getdns_bindata * bindata)737 getdns_pp_base64(gldns_buffer *buf, getdns_bindata *bindata)
738 {
739 	size_t p = gldns_buffer_position(buf);
740 	size_t base64str_sz;
741 
742 	if (gldns_buffer_printf(buf, " <bindata of ") < 0)
743 		return -1;
744 
745 	base64str_sz = gldns_b64_ntop_calculate_size(bindata->size);
746 	if (!gldns_buffer_reserve(buf, base64str_sz))
747 		return -1;
748 
749 	gldns_buffer_skip(buf, gldns_b64_ntop(bindata->data, bindata->size,
750 	    (char *)gldns_buffer_current(buf), base64str_sz));
751 
752 	if (gldns_buffer_printf(buf, ">") < 0)
753 		return -1;
754 
755 	return gldns_buffer_position(buf) - p;
756 }
757 
758 /*---------------------------------------- getdns_pp_bindata */
759 /**
760  * private function to pretty print bindata to a gldns_buffer
761  * @param buf     buffer to write to
762  * @param bindata the bindata to print
763  * @return        on success the number of written characters
764  *                if an output error is encountered, a negative value
765  */
766 static int
getdns_pp_bindata(gldns_buffer * buf,getdns_bindata * bindata,int rdata_raw,int json)767 getdns_pp_bindata(gldns_buffer *buf, getdns_bindata *bindata,
768     int rdata_raw, int json)
769 {
770 	size_t i, p = gldns_buffer_position(buf);
771 	uint8_t *dptr;
772 	char spc[1024];
773 
774 	if (!json && gldns_buffer_printf(buf, " <bindata ") < 0)
775 		return -1;
776 
777 	/* Walk through all printable characters */
778 	i = 0;
779 	if (!rdata_raw)
780 		while (i < bindata->size && isprint(bindata->data[i]))
781 			i++;
782 
783 	if (bindata->size > 0 && i == bindata->size) {     /* all printable? */
784 
785 		if (json) {
786 			const uint8_t *s = bindata->data;
787 			const uint8_t *e = s + bindata->size;
788 			const uint8_t *b;
789 
790 			if (!gldns_buffer_reserve(buf, (e - s) + 2))
791 				return -1;
792 			gldns_buffer_write_u8(buf, '"');
793 			for (;;) {
794 				for ( b = s
795 				    ; b < e && *b != '\\' && *b != '"'
796 				    ; b++)
797 					; /* pass */
798 				if (b == e)
799 					break;
800 				if (!gldns_buffer_reserve(buf, (b - s) + 3))
801 					return -1;
802 				gldns_buffer_write(buf, s, b - s);
803 				gldns_buffer_write_u8(buf, '\\');
804 				gldns_buffer_write_u8(buf, *b);
805 				s = b + 1;
806 			}
807 			if (s < e)
808 			       	gldns_buffer_write(buf, s, e - s);
809 			gldns_buffer_write_u8(buf, '"');
810 		} else {
811 			(void)snprintf(spc, sizeof(spc), "of \"%%.%ds\"%s>",
812 			    (int)(i > 32 ? 32 : i), (i > 32 ? "..." : ""));
813 			if (gldns_buffer_printf(buf, spc, bindata->data) < 0)
814 				return -1;
815 		}
816 
817 	} else if (bindata->size > 1 &&         /* null terminated printable */
818 	    i == bindata->size - 1 && bindata->data[i] == 0) {
819 
820 		if (gldns_buffer_printf(
821 		    buf, (json ? "\"%s\"" : "of \"%s\">"), bindata->data) < 0)
822 			return -1;
823 
824 	} else if (bindata->size == 1 && *bindata->data == 0) {
825 		if (gldns_buffer_printf(buf, json ? "\".\"" : "for .>") < 0)
826 			return -1;
827 
828 	} else if (_getdns_bindata_is_dname(bindata)) {
829 		(void)gldns_wire2str_dname_buf(
830 		    bindata->data, bindata->size, spc, sizeof(spc));
831 		if (gldns_buffer_printf(
832 		    buf, (json ? "\"%s\"" : "for %s>"), spc) < 0)
833 			return -1;
834 	} else if (json) {
835 		if (gldns_buffer_printf(buf, "[") < 0)
836 			return -1;
837 		for (dptr = bindata->data;
838 			dptr < bindata->data + bindata->size; dptr++) {
839 			if (dptr > bindata->data) {
840 				if (gldns_buffer_printf(buf, ",") < 0)
841 					return -1;
842 			}
843 			if (gldns_buffer_printf(buf, "%d", (int)*dptr) < 0)
844 				return -1;
845 		}
846 		if (gldns_buffer_printf(buf, "]") < 0)
847 			return -1;
848 	} else {
849 		if (gldns_buffer_printf(buf, "of 0x") < 0)
850 			return -1;
851 		for (dptr = bindata->data;
852 			dptr < bindata->data + bindata->size; dptr++) {
853 			if (dptr - bindata->data >= 16) {
854 				if (gldns_buffer_printf(buf, "...") < 0)
855 					return -1;
856 				break;
857 			}
858 			if (gldns_buffer_printf(buf, "%.2x", *dptr) < 0)
859 				return -1;
860 		}
861 		if (gldns_buffer_printf(buf, ">") < 0)
862 			return -1;
863 	}
864 	return gldns_buffer_position(buf) - p;
865 }				/* getdns_pp_bindata */
866 
867 static int
868 getdns_pp_dict(gldns_buffer * buf, size_t indent,
869 	const getdns_dict *dict, int json);
870 
871 static const char *unknown_str_l[] = {" <unknown>", " null", "null"};
872 
873 /*---------------------------------------- getdns_pp_list */
874 /**
875  * private function to pretty print list to a gldns_buffer
876  * @param buf    buffer to write to
877  * @param indent number of spaces to append after newline
878  * @param list   the to list print
879  * @param for_literals The list is a list of literals.
880  *               Show the literal instead of the value.
881  * @return       on success the number of written characters
882  *               if an output error is encountered, a negative value
883  */
884 static int
getdns_pp_list(gldns_buffer * buf,size_t indent,const getdns_list * list,int for_literals,int json)885 getdns_pp_list(gldns_buffer *buf, size_t indent, const getdns_list *list,
886     int for_literals, int json)
887 {
888 	size_t i, length, p = gldns_buffer_position(buf);
889 	getdns_data_type dtype;
890 	struct getdns_dict *dict_item;
891 	struct getdns_list *list_item;
892 	struct getdns_bindata *bindata_item;
893 	uint32_t int_item;
894 	const char *strval;
895 
896 	if (list == NULL)
897 		return 0;
898 
899 	if (gldns_buffer_printf(buf, "[") < 0)
900 		return -1;
901 
902 	if (getdns_list_get_length(list, &length) != GETDNS_RETURN_GOOD)
903 		return -1;
904 
905 	indent += 2;
906 	for (i = 0; i < length; i++) {
907 		if (i && gldns_buffer_printf(buf, ",") < 0)
908 			return -1;
909 		if (json < 2 && gldns_buffer_printf(buf, "\n%s",
910 		    getdns_indent(indent)) < 0)
911 			return -1;
912 
913 		if (getdns_list_get_data_type(list, i, &dtype) !=
914 		    GETDNS_RETURN_GOOD)
915 			return -1;
916 
917 		switch (dtype) {
918 		case t_int:
919 
920 			if (getdns_list_get_int(list, i, &int_item))
921 				return -1;
922 			if (!json && for_literals &&
923 			    (strval =
924 			     _getdns_get_const_info(int_item)->name)) {
925 				if (gldns_buffer_printf(buf, "%s", strval) < 0)
926 					return -1;
927 			} else if (0 >
928 			    gldns_buffer_printf(buf, "%d", (int)int_item))
929 				return -1;
930 			break;
931 
932 		case t_bindata:
933 			if (getdns_list_get_bindata(list, i, &bindata_item) !=
934 			    GETDNS_RETURN_GOOD)
935 				return -1;
936 			if (getdns_pp_bindata(
937 			    buf, bindata_item, 0, json) < 0)
938 				return -1;
939 			break;
940 
941 		case t_list:
942 			if (getdns_list_get_list(list, i, &list_item) !=
943 			    GETDNS_RETURN_GOOD)
944 				return -1;
945 			if (getdns_pp_list(
946 			    buf, indent, list_item, 0, json) < 0)
947 				return -1;
948 			break;
949 
950 		case t_dict:
951 			if (getdns_list_get_dict(list, i, &dict_item) !=
952 				GETDNS_RETURN_GOOD)
953 				return -1;
954 			if (getdns_pp_dict(buf, indent, dict_item, json) < 0)
955 				return -1;
956 			break;
957 
958 		default:
959 			if (gldns_buffer_printf(
960 			    buf, "%s", unknown_str_l[json]) < 0)
961 				return -1;
962 		}
963 	}
964 	indent -= 2;
965 	if (json < 2 && i && gldns_buffer_printf(
966 	    buf, "\n%s", getdns_indent(indent)) < 0)
967 		return -1;
968 	if (gldns_buffer_printf(buf, "]") < 0)
969 		return -1;
970 
971 	return gldns_buffer_position(buf) - p;
972 }				/* getdns_pp_list */
973 
974 static int
_getdns_print_class(gldns_buffer * buf,uint32_t klass)975 _getdns_print_class(gldns_buffer *buf, uint32_t klass)
976 {
977 	switch (klass) {
978 	case GETDNS_RRCLASS_IN:
979 		(void) gldns_buffer_printf(buf, " GETDNS_RRCLASS_IN");
980 		return 1;
981 	case GETDNS_RRCLASS_CH:
982 		(void) gldns_buffer_printf(buf, " GETDNS_RRCLASS_CH");
983 		return 1;
984 	case GETDNS_RRCLASS_HS:
985 		(void) gldns_buffer_printf(buf, " GETDNS_RRCLASS_HS");
986 		return 1;
987 	case GETDNS_RRCLASS_NONE:
988 		(void) gldns_buffer_printf(buf, " GETDNS_RRCLASS_NONE");
989 		return 1;
990 	case GETDNS_RRCLASS_ANY:
991 		(void) gldns_buffer_printf(buf, " GETDNS_RRCLASS_ANY");
992 		return 1;
993 	}
994 	return 0;
995 }
996 
997 static int
_getdns_print_opcode(gldns_buffer * buf,uint32_t opcode)998 _getdns_print_opcode(gldns_buffer *buf, uint32_t opcode)
999 {
1000 	switch (opcode) {
1001 	case GETDNS_OPCODE_QUERY:
1002 		(void) gldns_buffer_printf(buf, " GETDNS_OPCODE_QUERY");
1003 		return 1;
1004 	case GETDNS_OPCODE_IQUERY:
1005 		(void) gldns_buffer_printf(buf, " GETDNS_OPCODE_IQUERY");
1006 		return 1;
1007 	case GETDNS_OPCODE_STATUS:
1008 		(void) gldns_buffer_printf(buf, " GETDNS_OPCODE_STATUS");
1009 		return 1;
1010 	case GETDNS_OPCODE_NOTIFY:
1011 		(void) gldns_buffer_printf(buf, " GETDNS_OPCODE_NOTIFY");
1012 		return 1;
1013 	case GETDNS_OPCODE_UPDATE:
1014 		(void) gldns_buffer_printf(buf, " GETDNS_OPCODE_UPDATE");
1015 		return 1;
1016 	}
1017 	return 0;
1018 }
1019 
1020 static int
_getdns_print_rcode(gldns_buffer * buf,uint32_t rcode)1021 _getdns_print_rcode(gldns_buffer *buf, uint32_t rcode)
1022 {
1023 	static const char *rcodes[] = {
1024 		" GETDNS_RCODE_NOERROR" , " GETDNS_RCODE_FORMERR" ,
1025 		" GETDNS_RCODE_SERVFAIL", " GETDNS_RCODE_NXDOMAIN",
1026 		" GETDNS_RCODE_NOTIMP"  , " GETDNS_RCODE_REFUSED" ,
1027 		" GETDNS_RCODE_YXDOMAIN", " GETDNS_RCODE_YXRRSET" ,
1028 		" GETDNS_RCODE_NXRRSET" , " GETDNS_RCODE_NOTAUTH" ,
1029 		" GETDNS_RCODE_NOTZONE" ,
1030 		" GETDNS_RCODE_BADSIG"  , " GETDNS_RCODE_BADKEY"  ,
1031 		" GETDNS_RCODE_BADTIME" , " GETDNS_RCODE_BADMODE" ,
1032 		" GETDNS_RCODE_BADNAME" , " GETDNS_RCODE_BADALG"  ,
1033 		" GETDNS_RCODE_BADTRUNC"
1034 	};
1035 	if (rcode <= 10)
1036 		(void) gldns_buffer_printf(buf, "%s", rcodes[rcode]);
1037 	else if (rcode >= 16 && rcode <= 22)
1038 		(void) gldns_buffer_printf(buf, "%s", rcodes[rcode-6]);
1039 	else
1040 		return 0;
1041 	return 1;
1042 }
1043 
1044 /*---------------------------------------- getdns_pp_dict */
1045 /**
1046  * private function to pretty print dict to a gldns_buffer
1047  * @param buf    buffer to write to
1048  * @param indent number of spaces to append after newline
1049  * @param dict   the dict to print
1050  * @return       on success the number of written characters
1051  *               if an output error is encountered, a negative value
1052  */
1053 static int
getdns_pp_dict(gldns_buffer * buf,size_t indent,const getdns_dict * dict,int json)1054 getdns_pp_dict(gldns_buffer * buf, size_t indent,
1055 	const getdns_dict *dict, int json)
1056 {
1057 	size_t i, length, p = gldns_buffer_position(buf);
1058 	struct getdns_dict_item *item;
1059 	const char *strval;
1060 
1061 	char abuf[80];
1062 
1063 	if (dict == NULL)
1064 		return 0;
1065 
1066 	if (gldns_buffer_printf(buf, "{") < 0)
1067 		return -1;
1068 
1069 	i = 0;
1070 	indent += 2;
1071 	RBTREE_FOR(item, struct getdns_dict_item *,
1072 		(_getdns_rbtree_t *)&(dict->root)) {
1073 
1074 		if (i && gldns_buffer_printf(buf, ",") < 0)
1075 			return -1;
1076 		if (json < 2 && gldns_buffer_printf(
1077 		    buf, "\n%s", getdns_indent(indent)) < 0)
1078 			return -1;
1079 		if (gldns_buffer_printf(
1080 		    buf, "\"%s\":",(const char *)item->node.key) < 0)
1081 			return -1;
1082 
1083 		switch (item->i.dtype) {
1084 		case t_int:
1085 			if (!json &&
1086 			    (strcmp(item->node.key, "type") == 0  ||
1087 			     strcmp(item->node.key, "type_covered") == 0 ||
1088 				 strcmp(item->node.key, "query_type") == 0 ||
1089 			     strcmp(item->node.key, "qtype") == 0) &&
1090 			    (strval = _getdns_rr_type_name(item->i.data.n))) {
1091 				if (gldns_buffer_printf(
1092 					buf, " GETDNS_RRTYPE_%s", strval) < 0)
1093 					return -1;
1094 				break;
1095 			}
1096 			if (!json &&
1097 			    (strcmp(item->node.key, "answer_type") == 0  ||
1098 			     strcmp(item->node.key, "dnssec_status") == 0 ||
1099 			     strcmp(item->node.key, "tsig_status") == 0 ||
1100 			     strcmp(item->node.key, "status") == 0 ||
1101 			     strcmp(item->node.key, "append_name") == 0 ||
1102 			     strcmp(item->node.key, "follow_redirects") == 0 ||
1103 			     strcmp(item->node.key, "transport") == 0 ||
1104 			     strcmp(item->node.key, "resolution_type") == 0 ||
1105 			     strcmp(item->node.key, "tls_authentication") == 0 ||
1106 			     strcmp(item->node.key, "tls_min_version") == 0 ||
1107 			     strcmp(item->node.key, "tls_max_version") == 0 ||
1108 
1109 			     /* extensions */
1110 			     strcmp(item->node.key, "add_warning_for_bad_dns") == 0 ||
1111 			     strcmp(item->node.key, "dnssec") == 0 ||
1112 			     strcmp(item->node.key, "dnssec_return_all_statuses") == 0 ||
1113 			     strcmp(item->node.key, "dnssec_return_full_validation_chain") == 0 ||
1114 			     strcmp(item->node.key, "dnssec_return_only_secure") == 0 ||
1115 			     strcmp(item->node.key, "dnssec_return_status") == 0 ||
1116 			     strcmp(item->node.key, "dnssec_return_validation_chain") == 0 ||
1117 #if defined(DNSSEC_ROADBLOCK_AVOIDANCE) && defined(HAVE_LIBUNBOUND)
1118 			     strcmp(item->node.key, "dnssec_roadblock_avoidance") == 0 ||
1119 #endif
1120 #ifdef EDNS_COOKIES
1121 			     strcmp(item->node.key, "edns_cookies") == 0 ||
1122 #endif
1123 			     strcmp(item->node.key, "return_api_information") == 0 ||
1124 			     strcmp(item->node.key, "return_both_v4_and_v6") == 0 ||
1125 			     strcmp(item->node.key, "return_call_reporting") == 0
1126 			     ) &&
1127 			    (strval =
1128 			     _getdns_get_const_info(item->i.data.n)->name)) {
1129 				if (gldns_buffer_printf(buf, " %s", strval) < 0)
1130 					return -1;
1131 				break;
1132 			}
1133 			if (!json &&
1134 			    (strcmp(item->node.key, "class")  == 0  ||
1135 			     strcmp(item->node.key, "qclass") == 0) &&
1136 			    _getdns_print_class(buf, item->i.data.n))
1137 				break;
1138 			if (!json && strcmp(item->node.key, "opcode") == 0 &&
1139 			    _getdns_print_opcode(buf, item->i.data.n))
1140 				break;
1141 			if (!json && strcmp(item->node.key, "rcode") == 0 &&
1142 			    _getdns_print_rcode(buf, item->i.data.n))
1143 				break;
1144 			if (gldns_buffer_printf(
1145 			    buf,(json < 2 ? " %d" : "%d"), item->i.data.n) < 0)
1146 				return -1;
1147 			break;
1148 
1149 		case t_bindata:
1150 			if ((strcmp(item->node.key, "address_data") == 0 ||
1151 			     strcmp(item->node.key, "ipv4_address") == 0 ||
1152 			     strcmp(item->node.key, "ipv6_address") == 0 ) &&
1153 			    (item->i.data.bindata->size == 4  ||
1154 			     item->i.data.bindata->size == 16 )) {
1155 
1156 				if (gldns_buffer_printf(buf,
1157 				    (json ? "\"%s\"" : " <bindata for %s>"),
1158 				    inet_ntop(( item->i.data.bindata->size == 4
1159 				              ? AF_INET : AF_INET6)
1160 				              , item->i.data.bindata->data
1161 				              , abuf
1162 				              , 40
1163 				              )) < 0)
1164 					return -1;
1165 
1166 			} else if (!json &&
1167 			    (strcmp(item->node.key, "pin-sha256") == 0 ||
1168 			     strcmp(item->node.key, "value") == 0) &&
1169 			     item->i.data.bindata->size > 0 &&
1170 			     item->i.data.bindata->size % 4 == 0) {
1171 
1172 				if (getdns_pp_base64(buf,
1173 				    item->i.data.bindata) < 0)
1174 					return -1;
1175 
1176 			} else if (getdns_pp_bindata(
1177 			    buf, item->i.data.bindata,
1178 			    (strcmp(item->node.key, "rdata_raw") == 0),
1179 			    json) < 0)
1180 				return -1;
1181 			break;
1182 
1183 		case t_list:	/* Don't put empty lists on a new line */
1184 
1185 			if (getdns_list_get_length(item->i.data.list, &length) !=
1186 			    GETDNS_RETURN_GOOD)
1187 				return -1;
1188 			if (length == 0) {
1189 				if (gldns_buffer_printf(
1190 				    buf, (json < 2 ? " []" : "[]")) < 0)
1191 					return -1;
1192 				break;
1193 			}
1194 			if (json < 2 && gldns_buffer_printf(buf, "\n%s",
1195 			    getdns_indent(indent)) < 0)
1196 				return -1;
1197 			if (getdns_pp_list(buf, indent, item->i.data.list,
1198 			    (strcmp(item->node.key, "namespaces") == 0 ||
1199 			     strcmp(item->node.key, "dns_transport_list") == 0
1200 			     || strcmp(item->node.key, "bad_dns") == 0),
1201 			    json) < 0)
1202 				return -1;
1203 			break;
1204 
1205 		case t_dict:
1206 			if (json < 2 && gldns_buffer_printf(buf, "\n%s",
1207 			    getdns_indent(indent)) < 0)
1208 				return -1;
1209 			if (getdns_pp_dict(
1210 			    buf, indent, item->i.data.dict, json) < 0)
1211 				return -1;
1212 			break;
1213 
1214 		default:
1215 			if (gldns_buffer_printf(
1216 			    buf, "%s", unknown_str_l[json]) < 0)
1217 				return -1;
1218 		}
1219 		i++;
1220 	}
1221 	indent -= 2;
1222 	if (json < 2 && i  && gldns_buffer_printf(
1223 	    buf, "\n%s", getdns_indent(indent)) < 0)
1224 		return -1;
1225 	if (gldns_buffer_printf(buf, "}") < 0)
1226 		return -1;
1227 
1228 	return gldns_buffer_position(buf) - p;
1229 }				/* getdns_pp_dict */
1230 
1231 /*---------------------------------------- getdns_pretty_print_dict */
1232 /**
1233  * Return a character string containing a "human readable" representation
1234  * of dict.
1235  * @param dict   the dict to pretty print
1236  * @return       the "human readable" representation of dict
1237  *               or NULL on error
1238  */
1239 char *
getdns_pretty_print_dict(const struct getdns_dict * dict)1240 getdns_pretty_print_dict(const struct getdns_dict *dict)
1241 {
1242 	gldns_buffer *buf;
1243 	char *ret;
1244 
1245 	if (!dict)
1246 		return NULL;
1247 
1248 	buf = gldns_buffer_new(8192);
1249 	if (!buf)
1250 		return NULL;
1251 
1252 	if (getdns_pp_dict(buf, 0, dict, 0) < 0) {
1253 		gldns_buffer_free(buf);
1254 		return NULL;
1255 	}
1256 	ret = (char *) gldns_buffer_export(buf);
1257 	gldns_buffer_free(buf);
1258 	return ret;
1259 }				/* getdns_pretty_print_dict */
1260 
1261 int
getdns_pretty_snprint_dict(char * str,size_t size,const getdns_dict * dict)1262 getdns_pretty_snprint_dict(char *str, size_t size, const getdns_dict *dict)
1263 {
1264 	gldns_buffer buf;
1265 
1266 	if (!dict) return -1;
1267 
1268 	gldns_buffer_init_vfixed_frm_data(&buf, str, size);
1269 	return getdns_pp_dict(&buf, 0, dict, 0) < 0
1270 	     ? -1 : (int)gldns_buffer_position(&buf);
1271 }
1272 
1273 char *
getdns_pretty_print_list(const getdns_list * list)1274 getdns_pretty_print_list(const getdns_list *list)
1275 {
1276 	gldns_buffer *buf;
1277 	char *ret;
1278 
1279 	if (!list)
1280 		return NULL;
1281 
1282 	buf = gldns_buffer_new(4096);
1283 	if (!buf)
1284 		return NULL;
1285 
1286 	if (getdns_pp_list(buf, 0, list, 0, 0) < 0) {
1287 		gldns_buffer_free(buf);
1288 		return NULL;
1289 	}
1290 	ret = (char *) gldns_buffer_export(buf);
1291 	gldns_buffer_free(buf);
1292 	return ret;
1293 }
1294 
1295 int
getdns_pretty_snprint_list(char * str,size_t size,const getdns_list * list)1296 getdns_pretty_snprint_list(char *str, size_t size, const getdns_list *list)
1297 {
1298 	gldns_buffer buf;
1299 
1300 	if (!list) return -1;
1301 
1302 	gldns_buffer_init_vfixed_frm_data(&buf, str, size);
1303 	return getdns_pp_list(&buf, 0, list, 0, 0) < 0
1304 	     ? -1 : (int)gldns_buffer_position(&buf);
1305 }
1306 
1307 char *
getdns_print_json_dict(const getdns_dict * dict,int pretty)1308 getdns_print_json_dict(const getdns_dict *dict, int pretty)
1309 {
1310 	gldns_buffer *buf;
1311 	char *ret;
1312 
1313 	if (!dict)
1314 		return NULL;
1315 
1316 	buf = gldns_buffer_new(8192);
1317 	if (!buf)
1318 		return NULL;
1319 
1320 	if (getdns_pp_dict(buf, 0, dict, pretty ? 1 : 2) < 0) {
1321 		gldns_buffer_free(buf);
1322 		return NULL;
1323 	}
1324 	ret = (char *) gldns_buffer_export(buf);
1325 	gldns_buffer_free(buf);
1326 	return ret;
1327 }				/* getdns_print_json_dict */
1328 
1329 int
getdns_snprint_json_dict(char * str,size_t size,const getdns_dict * dict,int pretty)1330 getdns_snprint_json_dict(
1331     char *str, size_t size, const getdns_dict *dict, int pretty)
1332 {
1333 	gldns_buffer buf;
1334 
1335 	if (!dict) return -1;
1336 
1337 	gldns_buffer_init_vfixed_frm_data(&buf, str, size);
1338 	return getdns_pp_dict(&buf, 0, dict, pretty ? 1 : 2) < 0
1339 	     ? -1 : (int)gldns_buffer_position(&buf);
1340 }
1341 
1342 char *
getdns_print_json_list(const getdns_list * list,int pretty)1343 getdns_print_json_list(const getdns_list *list, int pretty)
1344 {
1345 	gldns_buffer *buf;
1346 	char *ret;
1347 
1348 	if (!list)
1349 		return NULL;
1350 
1351 	buf = gldns_buffer_new(4096);
1352 	if (!buf)
1353 		return NULL;
1354 
1355 	if (getdns_pp_list(buf, 0, list, 0, pretty ? 1 : 2) < 0) {
1356 		gldns_buffer_free(buf);
1357 		return NULL;
1358 	}
1359 	ret = (char *) gldns_buffer_export(buf);
1360 	gldns_buffer_free(buf);
1361 	return ret;
1362 }
1363 
1364 int
getdns_snprint_json_list(char * str,size_t size,const getdns_list * list,int pretty)1365 getdns_snprint_json_list(
1366     char *str, size_t size, const getdns_list *list, int pretty)
1367 {
1368 	gldns_buffer buf;
1369 
1370 	if (!list) return -1;
1371 
1372 	gldns_buffer_init_vfixed_frm_data(&buf, str, size);
1373 	return getdns_pp_list(&buf, 0, list, 0, pretty ? 1 : 2) < 0
1374 	     ? -1 : (int)gldns_buffer_position(&buf);
1375 }
1376 
1377 /* dict.c */
1378