1/*
2 * Copyright (c) 1999-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <ctype.h>
27#include <string.h>
28#include <unistd.h>
29#include <netdb.h>
30#include <stdarg.h>
31#include <sys/stat.h>
32#include <sys/dir.h>
33#include <errno.h>
34#include <sys/types.h>
35#include <sys/socket.h>
36#include <ifaddrs.h>
37#include <net/if.h>
38#include <pthread.h>
39#include <netinet/in.h>
40#include <arpa/nameser.h>
41#include <resolv.h>
42#include "dns.h"
43#include "dns_util.h"
44#include "dns_private.h"
45#include "res_private.h"
46
47#define DNS_RESOLVER_DIR "/etc/resolver"
48
49#define DNS_PRIVATE_HANDLE_TYPE_SUPER 0
50#define DNS_PRIVATE_HANDLE_TYPE_PLAIN 1
51#define DNS_DEFAULT_RECEIVE_SIZE 8192
52#define DNS_MAX_RECEIVE_SIZE 65536
53
54#define SDNS_DEFAULT_STAT_LATENCY 10
55
56#define DNS_FLAGS_QR_MASK  0x8000
57#define DNS_FLAGS_QR_QUERY 0x0000
58
59#define DNS_FLAGS_OPCODE_MASK    0x7800
60
61#define DNS_FLAGS_RCODE_MASK 0x000f
62
63#define DNS_FLAGS_AA 0x0400
64#define DNS_FLAGS_TC 0x0200
65#define DNS_FLAGS_RD 0x0100
66#define DNS_FLAGS_RA 0x0080
67
68#define DNS_SOCK_UDP 0
69#define DNS_SOCK_TCP_UNCONNECTED 1
70#define DNS_SOCK_TCP_CONNECTED 2
71
72#define INET_NTOP_AF_INET_OFFSET 4
73#define INET_NTOP_AF_INET6_OFFSET 8
74
75#define MAXPACKET 1024
76
77extern void res_client_close(res_state res);
78extern int __res_nquery(res_state statp, const char *name, int class, int type, u_char *answer, int anslen);
79extern int dns_res_send(res_state statp, const u_char *buf, int buflen, u_char *ans, int *anssiz, struct sockaddr *from, int *fromlen);
80extern void _check_cache(sdns_handle_t *sdns);
81extern int _sdns_search(sdns_handle_t *sdns, const char *name, uint32_t class, uint32_t type, uint32_t fqdn, uint32_t recurse, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen, int *min);
82extern int _pdns_search(sdns_handle_t *sdns, pdns_handle_t *pdns, const char *name, uint32_t class, uint32_t type, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen);
83static pthread_mutex_t _dnsPrintLock = PTHREAD_MUTEX_INITIALIZER;
84
85static void
86_dns_print_lock(void)
87{
88	pthread_mutex_lock(&_dnsPrintLock);
89}
90
91static void
92_dns_print_unlock(void)
93{
94	pthread_mutex_unlock(&_dnsPrintLock);
95}
96
97
98static uint8_t
99_dns_parse_uint8(char **p)
100{
101	uint8_t v;
102
103	v = (uint8_t)**p;
104	*p += 1;
105	return v;
106}
107
108static uint16_t
109_dns_parse_uint16(char **p)
110{
111	uint16_t *x, v;
112
113	x = (uint16_t *)*p;
114	v = ntohs(*x);
115	*p += 2;
116	return v;
117}
118
119static uint32_t
120_dns_parse_uint32(char **p)
121{
122	uint32_t *x, v;
123
124	x = (uint32_t *)*p;
125	v = ntohl(*x);
126	*p += 4;
127	return v;
128}
129
130static uint8_t
131_dns_cname_length(char *s)
132{
133	uint8_t l;
134
135	if (s == NULL) return 1;
136	l = strlen(s);
137	while ((s[l - 1] == '.') && (l > 1)) l--;
138	return l;
139}
140
141static void
142_dns_insert_cname(char *s, char *p)
143{
144	int i;
145	uint8_t len, dlen;
146
147	if (s == NULL)
148	{
149		*p = 0;
150		return;
151	}
152
153	if (!strcmp(s, "."))
154	{
155		p[0] = 1;
156		p[1] = '.';
157		p[2] = 0;
158		return;
159	}
160
161	len = _dns_cname_length(s);
162
163	p[0] = '.';
164	memmove(p + 1, s, len);
165	p[len + 1] = '.';
166
167	dlen = 0;
168
169	for (i = len + 1; i >= 0; i--)
170	{
171		if (p[i] == '.')
172		{
173			p[i] = dlen;
174			dlen = 0;
175		}
176		else dlen++;
177	}
178}
179
180static char *
181_dns_parse_string(const char *p, char **x, int32_t *remaining)
182{
183	char *str;
184	uint8_t len;
185
186	if (*remaining < 1) return NULL;
187	*remaining -= 1;
188
189	len = (uint8_t)**x;
190	*x += 1;
191
192	if (*remaining < len) return NULL;
193	*remaining -= len;
194
195	str = malloc(len + 1);
196	memmove(str, *x, len);
197	str[len] = '\0';
198	*x += len;
199
200	return str;
201}
202
203static char *
204_dns_parse_domain_name(const char *p, char **x, int32_t *remaining)
205{
206	uint8_t *v8;
207	uint16_t *v16, skip;
208	uint16_t i, j, dlen, len;
209	int more, compressed;
210	char *name, *start, *y, *z;
211
212	if (*remaining < 1) return NULL;
213
214	z = *x + *remaining;
215	start = *x;
216	compressed = 0;
217	more = 1;
218	name = malloc(1);
219	name[0] = '\0';
220	len = 1;
221	j = 0;
222	skip = 0;
223
224	while (more == 1)
225	{
226		if ((*x + 1) > z)
227		{
228			free(name);
229			return NULL;
230		}
231
232		v8 = (uint8_t *)*x;
233		dlen = *v8;
234
235		if ((dlen & 0xc0) == 0xc0)
236		{
237			if ((*x + 2) > z)
238			{
239				free(name);
240				return NULL;
241			}
242
243			v16 = (uint16_t *)*x;
244
245			y = (char *)p + (ntohs(*v16) & 0x3fff);
246			if ((*x == y) || (y > z))
247			{
248				free(name);
249				return NULL;
250			}
251
252			*x = y;
253			if (compressed == 0) skip += 2;
254			compressed = 1;
255			continue;
256		}
257
258		if ((*x + 1) > z)
259		{
260			free(name);
261			return NULL;
262		}
263
264		*x += 1;
265
266		if (dlen > 0)
267		{
268			len += dlen;
269			name = realloc(name, len);
270		}
271
272		if ((*x + dlen) > z)
273		{
274			free(name);
275			return NULL;
276		}
277
278		for (i = 0; i < dlen; i++)
279		{
280			name[j++] = **x;
281			*x += 1;
282		}
283
284		name[j] = '\0';
285		if (compressed == 0) skip += (dlen + 1);
286
287		if (dlen == 0) more = 0;
288		else
289		{
290			if ((*x + 1) > z)
291			{
292				free(name);
293				return NULL;
294			}
295
296			v8 = (uint8_t *)*x;
297			if (*v8 != 0)
298			{
299				len += 1;
300				name = realloc(name, len);
301				name[j++] = '.';
302				name[j] = '\0';
303			}
304		}
305	}
306
307	if ((start + skip) > z)
308	{
309		free(name);
310		return NULL;
311	}
312
313	*x = start + skip;
314	*remaining -= skip;
315
316	return name;
317}
318
319dns_resource_record_t *
320_dns_parse_resource_record_internal(const char *p, char **x, int32_t *remaining)
321{
322	uint32_t size, bx, mi;
323	uint16_t rdlen;
324	uint8_t byte, i;
325	dns_resource_record_t *r;
326	char *eor;
327
328	if (*remaining < 1) return NULL;
329
330	r = (dns_resource_record_t *)calloc(1, sizeof(dns_resource_record_t));
331
332	r->name = _dns_parse_domain_name(p, x, remaining);
333	if (r->name == NULL)
334	{
335		dns_free_resource_record(r);
336		return NULL;
337	}
338
339	if (*remaining < 10)
340	{
341		dns_free_resource_record(r);
342		return NULL;
343	}
344
345	r->dnstype = _dns_parse_uint16(x);
346	r->dnsclass = _dns_parse_uint16(x);
347	r->ttl = _dns_parse_uint32(x);
348	rdlen = _dns_parse_uint16(x);
349
350	*remaining -= 10;
351
352	if (*remaining < rdlen)
353	{
354		dns_free_resource_record(r);
355		return NULL;
356	}
357
358	eor = *x;
359	r->data.A = NULL;
360
361	switch (r->dnstype)
362	{
363		case ns_t_a:
364			if (*remaining < 4)
365			{
366				dns_free_resource_record(r);
367				return NULL;
368			}
369
370			*remaining -= 4;
371
372			size = sizeof(dns_address_record_t);
373			r->data.A = (dns_address_record_t *)calloc(1, size);
374			r->data.A->addr.s_addr = htonl(_dns_parse_uint32(x));
375			break;
376
377		case ns_t_aaaa:
378			if (*remaining < 16)
379			{
380				dns_free_resource_record(r);
381				return NULL;
382			}
383
384			*remaining -= 16;
385
386			size = sizeof(dns_in6_address_record_t);
387			r->data.AAAA = (dns_in6_address_record_t *)calloc(1, size);
388			r->data.AAAA->addr.__u6_addr.__u6_addr32[0] = htonl(_dns_parse_uint32(x));
389			r->data.AAAA->addr.__u6_addr.__u6_addr32[1] = htonl(_dns_parse_uint32(x));
390			r->data.AAAA->addr.__u6_addr.__u6_addr32[2] = htonl(_dns_parse_uint32(x));
391			r->data.AAAA->addr.__u6_addr.__u6_addr32[3] = htonl(_dns_parse_uint32(x));
392			break;
393
394		case ns_t_ns:
395		case ns_t_md:
396		case ns_t_mf:
397		case ns_t_cname:
398		case ns_t_mb:
399		case ns_t_mg:
400		case ns_t_mr:
401		case ns_t_ptr:
402			size = sizeof(dns_domain_name_record_t);
403			r->data.CNAME = (dns_domain_name_record_t *)calloc(1,size);
404			r->data.CNAME->name = _dns_parse_domain_name(p, x, remaining);
405			if (r->data.CNAME->name == NULL)
406			{
407				dns_free_resource_record(r);
408				return NULL;
409			}
410			break;
411
412		case ns_t_soa:
413			size = sizeof(dns_SOA_record_t);
414			r->data.SOA = (dns_SOA_record_t *)calloc(1, size);
415
416			r->data.SOA->mname = _dns_parse_domain_name(p, x, remaining);
417			if (r->data.SOA->mname == NULL)
418			{
419				dns_free_resource_record(r);
420				return NULL;
421			}
422
423			r->data.SOA->rname = _dns_parse_domain_name(p, x, remaining);
424			if (r->data.SOA->rname == NULL)
425			{
426				dns_free_resource_record(r);
427				return NULL;
428			}
429
430			if (*remaining < 20)
431			{
432				dns_free_resource_record(r);
433				return NULL;
434			}
435
436			*remaining -= 20;
437
438			r->data.SOA->serial = _dns_parse_uint32(x);
439			r->data.SOA->refresh = _dns_parse_uint32(x);
440			r->data.SOA->retry = _dns_parse_uint32(x);
441			r->data.SOA->expire = _dns_parse_uint32(x);
442			r->data.SOA->minimum = _dns_parse_uint32(x);
443			break;
444
445		case ns_t_wks:
446			if (*remaining < 5)
447			{
448				dns_free_resource_record(r);
449				return NULL;
450			}
451
452			*remaining -= rdlen;
453
454			size = sizeof(dns_WKS_record_t);
455			r->data.WKS = (dns_WKS_record_t *)calloc(1, size);
456
457			r->data.WKS->addr.s_addr = htonl(_dns_parse_uint32(x));
458			r->data.WKS->protocol = _dns_parse_uint8(x);
459			size = rdlen - 5;
460			r->data.WKS->maplength = size * 8;
461			r->data.WKS->map = NULL;
462			if (size == 0) break;
463
464			r->data.WKS->map = (uint8_t *)calloc(1, r->data.WKS->maplength);
465			mi = 0;
466			for (bx = 0; bx < size; bx++)
467			{
468				byte = _dns_parse_uint8(x);
469				for (i = 128; i >= 1; i = i/2)
470				{
471					if (byte & i) r->data.WKS->map[mi] = 0xff;
472					else r->data.WKS->map[mi] = 0;
473					mi++;
474				}
475			}
476			break;
477
478		case ns_t_hinfo:
479			size = sizeof(dns_HINFO_record_t);
480			r->data.HINFO = (dns_HINFO_record_t *)calloc(1, size);
481
482			r->data.HINFO->cpu = _dns_parse_string(p, x, remaining);
483			if (r->data.HINFO->cpu == NULL)
484			{
485				dns_free_resource_record(r);
486				return NULL;
487			}
488
489			r->data.HINFO->os = _dns_parse_string(p, x, remaining);
490			if (r->data.HINFO->os == NULL)
491			{
492				dns_free_resource_record(r);
493				return NULL;
494			}
495
496			break;
497
498		case ns_t_minfo:
499			size = sizeof(dns_MINFO_record_t);
500			r->data.MINFO = (dns_MINFO_record_t *)calloc(1, size);
501
502			r->data.MINFO->rmailbx = _dns_parse_domain_name(p, x, remaining);
503			if (r->data.MINFO->rmailbx == NULL)
504			{
505				dns_free_resource_record(r);
506				return NULL;
507			}
508
509			r->data.MINFO->emailbx = _dns_parse_domain_name(p, x, remaining);
510			if (r->data.MINFO->emailbx == NULL)
511			{
512				dns_free_resource_record(r);
513				return NULL;
514			}
515
516			break;
517
518		case ns_t_mx:
519			if (*remaining < 2)
520			{
521				dns_free_resource_record(r);
522				return NULL;
523			}
524
525			*remaining -= 2;
526
527			size = sizeof(dns_MX_record_t);
528			r->data.MX = (dns_MX_record_t *)calloc(1, size);
529
530			r->data.MX->preference = _dns_parse_uint16(x);
531			r->data.MX->name = _dns_parse_domain_name(p, x, remaining);
532			if (r->data.MX->name == NULL)
533			{
534				dns_free_resource_record(r);
535				return NULL;
536			}
537
538			break;
539
540		case ns_t_txt:
541			size = sizeof(dns_TXT_record_t);
542			r->data.TXT = (dns_TXT_record_t *)malloc(size);
543			r->data.TXT->string_count = 0;
544			r->data.TXT->strings = NULL;
545
546			while (*x < (eor + rdlen))
547			{
548				if (r->data.TXT->string_count == 0)
549				{
550					r->data.TXT->strings = (char **)calloc(1, sizeof(char *));
551				}
552				else
553				{
554					r->data.TXT->strings = (char **)realloc(r->data.TXT->strings, (r->data.TXT->string_count + 1) * sizeof(char *));
555				}
556
557				r->data.TXT->strings[r->data.TXT->string_count] = _dns_parse_string(p, x, remaining);
558				if (r->data.TXT->strings[r->data.TXT->string_count] == NULL)
559				{
560					dns_free_resource_record(r);
561					return NULL;
562				}
563				r->data.TXT->string_count++;
564			}
565
566			break;
567
568		case ns_t_rp:
569			size = sizeof(dns_RP_record_t);
570			r->data.RP = (dns_RP_record_t *)calloc(1, size);
571
572			r->data.RP->mailbox = _dns_parse_domain_name(p, x, remaining);
573			if (r->data.RP->mailbox == NULL)
574			{
575				dns_free_resource_record(r);
576				return NULL;
577			}
578
579			r->data.RP->txtdname = _dns_parse_domain_name(p, x, remaining);
580			if (r->data.RP->txtdname == NULL)
581			{
582				dns_free_resource_record(r);
583				return NULL;
584			}
585
586			break;
587
588		case ns_t_afsdb:
589			if (*remaining < 4)
590			{
591				dns_free_resource_record(r);
592				return NULL;
593			}
594
595			*remaining -= 4;
596			size = sizeof(dns_AFSDB_record_t);
597			r->data.AFSDB = (dns_AFSDB_record_t *)calloc(1, size);
598
599			r->data.AFSDB->subtype = _dns_parse_uint32(x);
600			r->data.AFSDB->hostname = _dns_parse_domain_name(p, x, remaining);
601			if (r->data.AFSDB->hostname == NULL)
602			{
603				dns_free_resource_record(r);
604				return NULL;
605			}
606
607			break;
608
609		case ns_t_x25:
610			size = sizeof(dns_X25_record_t);
611			r->data.X25 = (dns_X25_record_t *)calloc(1, size);
612
613			r->data.X25->psdn_address = _dns_parse_string(p, x, remaining);
614			if (r->data.X25->psdn_address == NULL)
615			{
616				dns_free_resource_record(r);
617				return NULL;
618			}
619
620			break;
621
622		case ns_t_isdn:
623			size = sizeof(dns_ISDN_record_t);
624			r->data.ISDN = (dns_ISDN_record_t *)calloc(1, size);
625
626			r->data.ISDN->isdn_address = _dns_parse_string(p, x, remaining);
627			if (r->data.ISDN->isdn_address == NULL)
628			{
629				dns_free_resource_record(r);
630				return NULL;
631			}
632
633			if (*x < (eor + rdlen))
634			{
635				r->data.ISDN->subaddress = _dns_parse_string(p, x, remaining);
636				if (r->data.ISDN->subaddress == NULL)
637				{
638					dns_free_resource_record(r);
639					return NULL;
640				}
641			}
642			else
643			{
644				r->data.ISDN->subaddress = NULL;
645			}
646
647			break;
648
649		case ns_t_rt:
650			if (*remaining < 2)
651			{
652				dns_free_resource_record(r);
653				return NULL;
654			}
655
656			*remaining -= 2;
657
658			size = sizeof(dns_RT_record_t);
659			r->data.RT = (dns_RT_record_t *)calloc(1, size);
660
661			r->data.RT->preference = _dns_parse_uint16(x);
662			r->data.RT->intermediate = _dns_parse_domain_name(p, x, remaining);
663			if (r->data.RT->intermediate == NULL)
664			{
665				dns_free_resource_record(r);
666				return NULL;
667			}
668
669			break;
670
671		case ns_t_loc:
672			if (*remaining < 16)
673			{
674				dns_free_resource_record(r);
675				return NULL;
676			}
677
678			*remaining -= 16;
679
680			size = sizeof(dns_LOC_record_t);
681			r->data.LOC = (dns_LOC_record_t *)calloc(1, size);
682
683			r->data.LOC->version = _dns_parse_uint8(x);
684			r->data.LOC->size = _dns_parse_uint8(x);
685			r->data.LOC->horizontal_precision = _dns_parse_uint8(x);
686			r->data.LOC->vertical_precision = _dns_parse_uint8(x);
687			r->data.LOC->latitude = _dns_parse_uint32(x);
688			r->data.LOC->longitude = _dns_parse_uint32(x);
689			r->data.LOC->altitude = _dns_parse_uint32(x);
690			break;
691
692		case ns_t_srv:
693			if (*remaining < 6)
694			{
695				dns_free_resource_record(r);
696				return NULL;
697			}
698
699			*remaining -= 6;
700
701			size = sizeof(dns_SRV_record_t);
702			r->data.SRV = (dns_SRV_record_t *)calloc(1, size);
703
704			r->data.SRV->priority = _dns_parse_uint16(x);
705			r->data.SRV->weight = _dns_parse_uint16(x);
706			r->data.SRV->port = _dns_parse_uint16(x);
707			r->data.SRV->target = _dns_parse_domain_name(p, x, remaining);
708			if (r->data.SRV->target == NULL)
709			{
710				dns_free_resource_record(r);
711				return NULL;
712			}
713
714			break;
715
716		case ns_t_null:
717		default:
718			*remaining -= rdlen;
719
720			size = sizeof(dns_raw_resource_record_t);
721			r->data.DNSNULL = (dns_raw_resource_record_t *)calloc(1, size);
722
723			r->data.DNSNULL->length = rdlen;
724			r->data.DNSNULL->data = calloc(1, rdlen);
725			memmove(r->data.DNSNULL->data, *x, rdlen);
726			*x += rdlen;
727			break;
728	}
729
730	*x = eor + rdlen;
731	return r;
732}
733
734dns_resource_record_t *
735dns_parse_resource_record(const char *buf, uint32_t len)
736{
737	char *x;
738	int32_t remaining;
739
740	remaining = len;
741	x = (char *)buf;
742	return _dns_parse_resource_record_internal(buf, &x, &remaining);
743}
744
745dns_question_t *
746_dns_parse_question_internal(const char *p, char **x, int32_t *remaining)
747{
748	dns_question_t *q;
749
750	if (x == NULL) return NULL;
751	if (*x == NULL) return NULL;
752	if (*remaining < 1) return NULL;
753
754	q = (dns_question_t *)calloc(1, sizeof(dns_question_t));
755
756	q->name = _dns_parse_domain_name(p, x, remaining);
757	if (q->name == NULL)
758	{
759		free(q);
760		return NULL;
761	}
762
763	if (*remaining < 4)
764	{
765		free(q->name);
766		free(q);
767		return NULL;
768	}
769
770	*remaining = *remaining - 4;
771
772	q->dnstype = _dns_parse_uint16(x);
773	q->dnsclass = _dns_parse_uint16(x);
774
775	return q;
776}
777
778dns_question_t *
779dns_parse_question(const char *buf, uint32_t len)
780{
781	char *x;
782	int32_t remaining;
783
784	remaining = len;
785	x = (char *)buf;
786	return _dns_parse_question_internal(buf, &x, &remaining);
787}
788
789
790dns_reply_t *
791dns_parse_packet(const char *p, uint32_t len)
792{
793	dns_reply_t *r;
794	dns_header_t *h;
795	char *x;
796	uint32_t i, size;
797    int32_t remaining;
798
799	if (p == NULL) return NULL;
800	if (len < NS_HFIXEDSZ) return NULL;
801
802	x = (char *)p;
803
804	r = (dns_reply_t *)calloc(1, sizeof(dns_reply_t));
805
806	r->header = (dns_header_t *)calloc(1, sizeof(dns_header_t));
807	h = r->header;
808
809	h->xid = _dns_parse_uint16(&x);
810	h->flags = _dns_parse_uint16(&x);
811	h->qdcount = _dns_parse_uint16(&x);
812	h->ancount = _dns_parse_uint16(&x);
813	h->nscount = _dns_parse_uint16(&x);
814	h->arcount = _dns_parse_uint16(&x);
815
816	remaining = len - NS_HFIXEDSZ;
817
818	size = sizeof(dns_question_t *);
819	r->question = (dns_question_t **)calloc(h->qdcount, size);
820	for (i = 0; i < h->qdcount; i++)
821	{
822		r->question[i] = _dns_parse_question_internal(p, &x, &remaining);
823		if (r->question[i] ==NULL)
824		{
825			h->qdcount = 0;
826			if (i > 0) h->qdcount = i - 1;
827			h->ancount = 0;
828			h->nscount = 0;
829			h->arcount = 0;
830			dns_free_reply(r);
831			return NULL;
832		}
833	}
834
835	size = sizeof(dns_resource_record_t *);
836
837	r->answer = (dns_resource_record_t **)calloc(h->ancount, size);
838	for (i = 0; i < h->ancount; i++)
839	{
840		r->answer[i] = _dns_parse_resource_record_internal(p, &x, &remaining);
841		if (r->answer[i] == NULL)
842		{
843			h->ancount = 0;
844			if (i > 0) h->ancount = i - 1;
845			h->nscount = 0;
846			h->arcount = 0;
847			dns_free_reply(r);
848			return NULL;
849		}
850	}
851
852	r->authority = (dns_resource_record_t **)calloc(h->nscount, size);
853	for (i = 0; i < h->nscount; i++)
854	{
855		r->authority[i] = _dns_parse_resource_record_internal(p, &x, &remaining);
856		if (r->authority[i] == NULL)
857		{
858			h->nscount = 0;
859			if (i > 0) h->nscount = i - 1;
860			h->arcount = 0;
861			dns_free_reply(r);
862			return NULL;
863		}
864	}
865
866	r->additional = (dns_resource_record_t **)calloc(h->arcount, size);
867	for (i = 0; i < h->arcount; i++)
868	{
869		r->additional[i] = _dns_parse_resource_record_internal(p, &x, &remaining);
870		if (r->additional[i] == NULL)
871		{
872			h->arcount = 0;
873			if (i > 0) h->arcount = i - 1;
874			dns_free_reply(r);
875			return NULL;
876		}
877	}
878
879	return r;
880}
881
882void
883dns_free_resource_record(dns_resource_record_t *r)
884{
885	int i;
886
887	free(r->name);
888
889	switch (r->dnstype)
890	{
891		case ns_t_a:
892			if (r->data.A != NULL) free(r->data.A);
893			break;
894
895		case ns_t_aaaa:
896			if (r->data.AAAA != NULL) free(r->data.AAAA);
897			break;
898
899		case ns_t_ns:
900		case ns_t_md:
901		case ns_t_mf:
902		case ns_t_cname:
903		case ns_t_mb:
904		case ns_t_mg:
905		case ns_t_mr:
906		case ns_t_ptr:
907			if (r->data.CNAME != NULL)
908			{
909				if (r->data.CNAME->name != NULL) free(r->data.CNAME->name);
910				free(r->data.CNAME);
911			}
912			break;
913
914		case ns_t_soa:
915			if (r->data.SOA != NULL)
916			{
917				if (r->data.SOA->mname != NULL) free(r->data.SOA->mname);
918				if (r->data.SOA->rname != NULL) free(r->data.SOA->rname);
919				free(r->data.SOA);
920			}
921			break;
922
923		case ns_t_wks:
924			if (r->data.WKS != NULL)
925			{
926				if (r->data.WKS->map != NULL) free(r->data.WKS->map);
927				free(r->data.WKS);
928			}
929			break;
930
931		case ns_t_hinfo:
932			if (r->data.HINFO != NULL)
933			{
934				if (r->data.HINFO->cpu != NULL) free(r->data.HINFO->cpu);
935				if (r->data.HINFO->os != NULL) free(r->data.HINFO->os);
936				free(r->data.HINFO);
937			}
938			break;
939
940		case ns_t_minfo:
941			if (r->data.MINFO != NULL)
942			{
943				if (r->data.MINFO->rmailbx != NULL) free(r->data.MINFO->rmailbx);
944				if (r->data.MINFO->emailbx != NULL) free(r->data.MINFO->emailbx);
945				free(r->data.MINFO);
946			}
947			break;
948
949		case ns_t_mx:
950			if (r->data.MX != NULL)
951			{
952				if (r->data.MX->name != NULL) free(r->data.MX->name);
953				free(r->data.MX);
954			}
955			break;
956
957
958		case ns_t_txt:
959			if (r->data.TXT != NULL)
960			{
961				for (i = 0; i < r->data.TXT->string_count; i++) free(r->data.TXT->strings[i]);
962				if (r->data.TXT->strings != NULL) free(r->data.TXT->strings);
963				free(r->data.TXT);
964			}
965			break;
966
967		case ns_t_rp:
968			if (r->data.RP != NULL)
969			{
970				if (r->data.RP->mailbox != NULL) free(r->data.RP->mailbox);
971				if (r->data.RP->txtdname != NULL) free(r->data.RP->txtdname);
972				free(r->data.RP);
973			}
974			break;
975
976		case ns_t_afsdb:
977			if (r->data.AFSDB != NULL)
978			{
979				if (r->data.AFSDB->hostname != NULL) free(r->data.AFSDB->hostname);
980				free(r->data.AFSDB);
981			}
982			break;
983
984		case ns_t_x25:
985			if (r->data.X25 != NULL)
986			{
987				if (r->data.X25->psdn_address != NULL) free(r->data.X25->psdn_address);
988				free(r->data.X25);
989			}
990			break;
991
992		case ns_t_isdn:
993			if (r->data.ISDN != NULL)
994			{
995				if (r->data.ISDN->isdn_address != NULL) free(r->data.ISDN->isdn_address);
996				if (r->data.ISDN->subaddress != NULL) free(r->data.ISDN->subaddress);
997				free(r->data.ISDN);
998			}
999			break;
1000
1001		case ns_t_rt:
1002			if (r->data.RT != NULL)
1003			{
1004				if (r->data.RT->intermediate != NULL) free(r->data.RT->intermediate);
1005				free(r->data.RT);
1006			}
1007			break;
1008
1009		case ns_t_loc:
1010			if (r->data.LOC != NULL) free(r->data.LOC);
1011			break;
1012
1013		case ns_t_srv:
1014			if (r->data.SRV != NULL)
1015			{
1016				if (r->data.SRV->target != NULL) free(r->data.SRV->target);
1017				free(r->data.SRV);
1018			}
1019			break;
1020
1021		case ns_t_invalid:
1022			break;
1023
1024		case ns_t_null:
1025		default:
1026			if (r->data.DNSNULL != NULL)
1027			{
1028				if (r->data.DNSNULL->data != NULL) free(r->data.DNSNULL->data);
1029				free(r->data.DNSNULL);
1030			}
1031			break;
1032	}
1033
1034	free(r);
1035}
1036
1037void
1038dns_free_reply(dns_reply_t *r)
1039{
1040	uint32_t i;
1041
1042	if (r == NULL) return;
1043	if (r->header != NULL)
1044	{
1045		for (i = 0; i < r->header->qdcount; i++)
1046		{
1047			free(r->question[i]->name);
1048			free(r->question[i]);
1049		}
1050
1051		for (i = 0; i < r->header->ancount; i++) dns_free_resource_record(r->answer[i]);
1052		for (i = 0; i < r->header->nscount; i++) dns_free_resource_record(r->authority[i]);
1053		for (i = 0; i < r->header->arcount; i++) dns_free_resource_record(r->additional[i]);
1054
1055		free(r->header);
1056	}
1057
1058	if (r->question != NULL) free(r->question);
1059	if (r->answer != NULL) free(r->answer);
1060	if (r->authority != NULL) free(r->authority);
1061	if (r->additional != NULL) free(r->additional);
1062
1063	if (r->server != NULL) free(r->server);
1064
1065	free(r);
1066}
1067
1068static void
1069_dns_append_question(dns_question_t *q, char **s, uint16_t *l)
1070{
1071	uint16_t len, *p;
1072	char *x;
1073
1074	if (q == NULL) return;
1075
1076	len = *l + _dns_cname_length(q->name) + 2 + 4;
1077	*s = realloc(*s, len);
1078
1079	_dns_insert_cname(q->name, (char *)*s + *l);
1080	*l = len;
1081
1082	x = *s + (len - 4);
1083
1084	p = (uint16_t *)x;
1085	*p = htons(q->dnstype);
1086	x += 2;
1087
1088	p = (uint16_t *)x;
1089	*p = htons(q->dnsclass);
1090
1091}
1092
1093static void
1094_dns_append_resource_record(dns_resource_record_t *r, char **s, uint16_t *l)
1095{
1096	uint16_t clen, len, *p, extra, rdlen;
1097	uint32_t *p2;
1098	char *x;
1099
1100	if (r == NULL) return;
1101
1102	extra = 10;
1103	switch (r->dnstype)
1104	{
1105		case ns_t_a:
1106			extra += 4;
1107			break;
1108		case ns_t_ptr:
1109			extra += 2;
1110			clen = _dns_cname_length(r->data.PTR->name);
1111			extra += clen;
1112			break;
1113		default: break;
1114	}
1115
1116	len = *l + _dns_cname_length(r->name) + 2 + extra;
1117	*s = realloc(*s, len);
1118
1119	_dns_insert_cname(r->name, (char *)*s + *l);
1120	*l = len;
1121
1122	x = *s + (len - extra);
1123
1124	p = (uint16_t *)x;
1125	*p = htons(r->dnstype);
1126	x += 2;
1127
1128	p = (uint16_t *)x;
1129	*p = htons(r->dnsclass);
1130	x += 2;
1131
1132	p2 = (uint32_t *)x;
1133	*p2 = htonl(r->ttl);
1134	x += 4;
1135
1136	switch (r->dnstype)
1137	{
1138		case ns_t_a:
1139			rdlen = 4;
1140			p = (uint16_t *)x;
1141			*p = htons(rdlen);
1142			x += 2;
1143
1144			p2 = (uint32_t *)x;
1145			*p2 = htons(r->data.A->addr.s_addr);
1146			x += 4;
1147			return;
1148
1149		case ns_t_ptr:
1150			clen = _dns_cname_length(r->data.PTR->name) + 2;
1151			p = (uint16_t *)x;
1152			*p = htons(clen);
1153			x += 2;
1154			_dns_insert_cname(r->data.PTR->name, x);
1155			x += clen;
1156			return;
1157
1158		default: return;
1159	}
1160}
1161
1162char *
1163dns_build_reply(dns_reply_t *dnsr, uint16_t *rl)
1164{
1165	uint16_t i, len;
1166	dns_header_t *h;
1167	char *s, *x;
1168
1169	if (dnsr == NULL) return NULL;
1170
1171	len = NS_HFIXEDSZ;
1172
1173	s = malloc(len);
1174	x = s + len;
1175
1176	memset(s, 0, len);
1177	*rl = len;
1178
1179	h = (dns_header_t *)s;
1180
1181	h->xid = htons(dnsr->header->xid);
1182	h->flags = htons(dnsr->header->flags);
1183	h->qdcount = htons(dnsr->header->qdcount);
1184	h->ancount = htons(dnsr->header->ancount);
1185	h->nscount = htons(dnsr->header->nscount);
1186	h->arcount = htons(dnsr->header->arcount);
1187
1188	for (i = 0; i < dnsr->header->qdcount; i++)
1189	{
1190		_dns_append_question(dnsr->question[i], &s, rl);
1191	}
1192
1193	for (i = 0; i < dnsr->header->ancount; i++)
1194	{
1195		_dns_append_resource_record(dnsr->answer[i], &s, rl);
1196	}
1197
1198	for (i = 0; i < dnsr->header->nscount; i++)
1199	{
1200		_dns_append_resource_record(dnsr->authority[i], &s, rl);
1201	}
1202
1203	for (i = 0; i < dnsr->header->arcount; i++)
1204	{
1205		_dns_append_resource_record(dnsr->additional[i], &s, rl);
1206	}
1207
1208	return s;
1209}
1210
1211void
1212dns_free_question(dns_question_t *q)
1213{
1214	if (q == NULL) return;
1215	if (q->name != NULL) free(q->name);
1216	free(q);
1217}
1218
1219void
1220dns_set_buffer_size(dns_handle_t d, uint32_t len)
1221{
1222	dns_private_handle_t *dns;
1223	if (d == NULL) return;
1224
1225	dns = (dns_private_handle_t *)d;
1226	if (dns->recvsize == len) return;
1227
1228	if (dns->recvbuf != NULL)
1229	{
1230		free(dns->recvbuf);
1231		dns->recvbuf = NULL;
1232	}
1233
1234	dns->recvsize = len;
1235	if (dns->recvsize > DNS_MAX_RECEIVE_SIZE) dns->recvsize = DNS_MAX_RECEIVE_SIZE;
1236
1237	if (dns->recvsize > 0) dns->recvbuf = malloc(dns->recvsize);
1238}
1239
1240uint32_t
1241dns_get_buffer_size(dns_handle_t d)
1242{
1243	dns_private_handle_t *dns;
1244	if (d == NULL) return 0;
1245
1246	dns = (dns_private_handle_t *)d;
1247	return dns->recvsize;
1248}
1249
1250dns_reply_t *
1251dns_lookup_soa_min(dns_handle_t d, const char *name, uint32_t class, uint32_t type, int *min)
1252{
1253	dns_private_handle_t *dns;
1254	dns_reply_t *r;
1255	int len;
1256	struct sockaddr_storage *from;
1257	uint32_t fromlen;
1258
1259	if (d == NULL) return NULL;
1260	if (name == NULL) return NULL;
1261
1262	dns = (dns_private_handle_t *)d;
1263	if (min != NULL) *min = -1;
1264
1265	if (dns->recvbuf == NULL)
1266	{
1267		if (dns->recvsize == 0) dns->recvsize = DNS_DEFAULT_RECEIVE_SIZE;
1268
1269		dns->recvbuf = malloc(dns->recvsize);
1270		if (dns->recvbuf == NULL) return NULL;
1271	}
1272
1273	fromlen = sizeof(struct sockaddr_storage);
1274	from = (struct sockaddr_storage *)calloc(1, sizeof(struct sockaddr_storage));
1275	len = -1;
1276
1277	if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER)
1278	{
1279		_check_cache(dns->sdns);
1280		len = _sdns_search(dns->sdns, name, class, type, 0, 1,  dns->recvbuf, dns->recvsize, (struct sockaddr *)from, &fromlen, min);
1281	}
1282	else
1283	{
1284		/* NB.  Minumium SOA TTL values are NOT provided when the caller passes a DNS_PRIVATE_HANDLE_TYPE_PLAIN handle */
1285		len = _pdns_search(dns->sdns, dns->pdns, name, class, type,  dns->recvbuf, dns->recvsize, (struct sockaddr *)from, &fromlen);
1286	}
1287
1288	if (len <= 0)
1289	{
1290		free(from);
1291		return NULL;
1292	}
1293
1294	r = dns_parse_packet(dns->recvbuf, len);
1295
1296	if (r == NULL) free(from);
1297	else r->server = (struct sockaddr *)from;
1298
1299	return r;
1300}
1301
1302dns_reply_t *
1303dns_lookup(dns_handle_t d, const char *name, uint32_t class, uint32_t type)
1304{
1305	int unused = 0;
1306
1307	return dns_lookup_soa_min(d, name, class, type, &unused);
1308}
1309
1310/*
1311 * DNS printing utilities
1312 */
1313
1314static char *
1315coord_ntoa(int32_t coord, uint32_t islat)
1316{
1317	int32_t deg, min, sec, secfrac;
1318	static char buf[64];
1319	char dir;
1320
1321	coord = coord - 0x80000000;
1322	dir = 'N';
1323
1324	if ((islat == 1) && (coord < 0))
1325	{
1326		dir = 'S';
1327		coord = -coord;
1328	}
1329
1330	if (islat == 0)
1331	{
1332		dir = 'E';
1333		if (coord < 0)
1334		{
1335			dir = 'W';
1336			coord = -coord;
1337		}
1338	}
1339
1340	secfrac = coord % 1000;
1341	coord = coord / 1000;
1342	sec = coord % 60;
1343	coord = coord / 60;
1344	min = coord % 60;
1345	coord = coord / 60;
1346	deg = coord;
1347
1348	sprintf(buf, "%d %.2d %.2d.%.3d %c", deg, min, sec, secfrac, dir);
1349	return buf;
1350}
1351
1352static char *
1353alt_ntoa(int32_t alt)
1354{
1355	int32_t ref, m, frac, sign;
1356	static char buf[128];
1357
1358	ref = 100000 * 100;
1359	sign = 1;
1360
1361	if (alt < ref)
1362	{
1363		alt = ref - alt;
1364		sign = -1;
1365	}
1366	else
1367	{
1368		alt = alt - ref;
1369	}
1370
1371	frac = alt % 100;
1372	m = (alt / 100) * sign;
1373
1374	sprintf(buf, "%d.%.2d", m, frac);
1375	return buf;
1376}
1377
1378static unsigned int
1379poweroften[10] =
1380{	1,
1381	10,
1382	100,
1383	1000,
1384	10000,
1385	100000,
1386	1000000,
1387	10000000,
1388	100000000,
1389	1000000000
1390};
1391
1392static char *
1393precsize_ntoa(uint8_t prec)
1394{
1395	static char buf[19];
1396	unsigned long val;
1397	int mantissa, exponent;
1398
1399	mantissa = (int)((prec >> 4) & 0x0f) % 10;
1400	exponent = (int)((prec >> 0) & 0x0f) % 10;
1401
1402	val = mantissa * poweroften[exponent];
1403
1404	sprintf(buf, "%ld.%.2ld", val/100, val%100);
1405	return buf;
1406}
1407
1408const char *
1409dns_type_string(uint16_t t)
1410{
1411	switch (t)
1412	{
1413		case ns_t_a:     return "A    ";
1414		case ns_t_ns:    return "NS   ";
1415		case ns_t_md:    return "MD   ";
1416		case ns_t_mf:    return "MF   ";
1417		case ns_t_cname: return "CNAME";
1418		case ns_t_soa:   return "SOA  ";
1419		case ns_t_mb:    return "MB  ";
1420		case ns_t_mg:    return "MG   ";
1421		case ns_t_mr:    return "MR   ";
1422		case ns_t_null:  return "NULL ";
1423		case ns_t_wks:   return "WKS  ";
1424		case ns_t_ptr:   return "PTR  ";
1425		case ns_t_hinfo: return "HINFO";
1426		case ns_t_minfo: return "MINFO";
1427		case ns_t_mx:    return "MX   ";
1428		case ns_t_txt:   return "TXT  ";
1429		case ns_t_rp:    return "PR   ";
1430		case ns_t_afsdb: return "AFSDB";
1431		case ns_t_x25:   return "X25  ";
1432		case ns_t_isdn:  return "ISDN ";
1433		case ns_t_rt:    return "RT   ";
1434		case ns_t_nsap:  return "NSAP ";
1435		case ns_t_nsap_ptr: return "NSPTR";
1436		case ns_t_sig:   return "SIG  ";
1437		case ns_t_key:   return "KEY  ";
1438		case ns_t_px:    return "PX   ";
1439		case ns_t_gpos:  return "GPOS ";
1440		case ns_t_aaaa:  return "AAAA ";
1441		case ns_t_loc:   return "LOC  ";
1442		case ns_t_nxt:   return "NXT  ";
1443		case ns_t_eid:   return "EID  ";
1444		case ns_t_nimloc: return "NIMLC";
1445		case ns_t_srv:   return "SRV  ";
1446		case ns_t_atma:  return "ATMA ";
1447		case ns_t_naptr: return "NAPTR";
1448		case ns_t_kx:    return "KX   ";
1449		case ns_t_cert:  return "CERT ";
1450		case ns_t_a6:    return "A6   ";
1451		case ns_t_dname: return "DNAME";
1452		case ns_t_sink:  return "SINK ";
1453		case ns_t_opt:   return "OPT  ";
1454		case ns_t_tkey:  return "TKEY ";
1455		case ns_t_tsig:  return "TSIG ";
1456		case ns_t_ixfr:  return "IXFR ";
1457		case ns_t_axfr:  return "AXFR ";
1458		case ns_t_mailb: return "MAILB";
1459		case ns_t_maila: return "MAILA";
1460		case ns_t_any:   return "ANY  ";
1461		case ns_t_zxfr:  return "ZXFR ";
1462		default:         return "?????";
1463	}
1464
1465	return "?????";
1466}
1467
1468int32_t
1469dns_type_number(const char *t, uint16_t *n)
1470{
1471	if (t == NULL) return -1;
1472
1473	if (!strcasecmp(t, "A"))       { *n = ns_t_a;        return 0; }
1474	if (!strcasecmp(t, "NS"))      { *n = ns_t_ns;       return 0; }
1475	if (!strcasecmp(t, "MD"))      { *n = ns_t_md;       return 0; }
1476	if (!strcasecmp(t, "MF"))      { *n = ns_t_mf;       return 0; }
1477	if (!strcasecmp(t, "CNAME"))   { *n = ns_t_cname;    return 0; }
1478	if (!strcasecmp(t, "SOA"))     { *n = ns_t_soa;      return 0; }
1479	if (!strcasecmp(t, "MB"))      { *n = ns_t_mb;       return 0; }
1480	if (!strcasecmp(t, "MG"))      { *n = ns_t_mg;       return 0; }
1481	if (!strcasecmp(t, "MR"))      { *n = ns_t_mr;       return 0; }
1482	if (!strcasecmp(t, "NULL"))    { *n = ns_t_null;     return 0; }
1483	if (!strcasecmp(t, "WKS"))     { *n = ns_t_wks;      return 0; }
1484	if (!strcasecmp(t, "PTR"))     { *n = ns_t_ptr;      return 0; }
1485	if (!strcasecmp(t, "HINFO"))   { *n = ns_t_hinfo;    return 0; }
1486	if (!strcasecmp(t, "MINFO"))   { *n = ns_t_minfo;    return 0; }
1487	if (!strcasecmp(t, "MX"))      { *n = ns_t_mx;       return 0; }
1488	if (!strcasecmp(t, "TXT"))     { *n = ns_t_txt;      return 0; }
1489	if (!strcasecmp(t, "RP"))      { *n = ns_t_rp;       return 0; }
1490	if (!strcasecmp(t, "AFSDB"))   { *n = ns_t_afsdb;    return 0; }
1491	if (!strcasecmp(t, "X25"))     { *n = ns_t_x25;      return 0; }
1492	if (!strcasecmp(t, "ISDN"))    { *n = ns_t_isdn;     return 0; }
1493	if (!strcasecmp(t, "RT"))      { *n = ns_t_rt;       return 0; }
1494	if (!strcasecmp(t, "NSAP"))    { *n = ns_t_nsap;     return 0; }
1495	if (!strcasecmp(t, "NSPTR"))   { *n = ns_t_nsap_ptr; return 0; }
1496	if (!strcasecmp(t, "NSAP_PTR")){ *n = ns_t_nsap_ptr; return 0; }
1497	if (!strcasecmp(t, "SIG"))     { *n = ns_t_sig;      return 0; }
1498	if (!strcasecmp(t, "KEY"))     { *n = ns_t_key;      return 0; }
1499	if (!strcasecmp(t, "PX"))      { *n = ns_t_px;       return 0; }
1500	if (!strcasecmp(t, "GPOS"))    { *n = ns_t_gpos;     return 0; }
1501	if (!strcasecmp(t, "AAAA"))    { *n = ns_t_aaaa;     return 0; }
1502	if (!strcasecmp(t, "LOC"))     { *n = ns_t_loc;      return 0; }
1503	if (!strcasecmp(t, "NXT"))     { *n = ns_t_nxt;      return 0; }
1504	if (!strcasecmp(t, "EID"))     { *n = ns_t_eid;      return 0; }
1505	if (!strcasecmp(t, "NIMLOC"))  { *n = ns_t_nimloc;   return 0; }
1506	if (!strcasecmp(t, "SRV"))     { *n = ns_t_srv;      return 0; }
1507	if (!strcasecmp(t, "ATMA"))    { *n = ns_t_atma;     return 0; }
1508	if (!strcasecmp(t, "NAPTR"))   { *n = ns_t_naptr;    return 0; }
1509	if (!strcasecmp(t, "KX"))      { *n = ns_t_kx;       return 0; }
1510	if (!strcasecmp(t, "CERT"))    { *n = ns_t_cert;     return 0; }
1511	if (!strcasecmp(t, "A6"))      { *n = ns_t_a6;       return 0; }
1512	if (!strcasecmp(t, "DNAME"))   { *n = ns_t_dname;    return 0; }
1513	if (!strcasecmp(t, "SINK"))    { *n = ns_t_sink;     return 0; }
1514	if (!strcasecmp(t, "OPT"))     { *n = ns_t_opt;      return 0; }
1515	if (!strcasecmp(t, "TKEY"))    { *n = ns_t_tkey;     return 0; }
1516	if (!strcasecmp(t, "TSIG"))    { *n = ns_t_tsig;     return 0; }
1517	if (!strcasecmp(t, "IXFR"))    { *n = ns_t_ixfr;     return 0; }
1518	if (!strcasecmp(t, "AXFR"))    { *n = ns_t_axfr;     return 0; }
1519	if (!strcasecmp(t, "MAILB"))   { *n = ns_t_mailb;    return 0; }
1520	if (!strcasecmp(t, "MAILA"))   { *n = ns_t_maila;    return 0; }
1521	if (!strcasecmp(t, "ANY"))     { *n = ns_t_any;      return 0; }
1522	if (!strcasecmp(t, "ZXFR"))    { *n = ns_t_zxfr;     return 0; }
1523
1524	return -1;
1525}
1526
1527const char *
1528dns_class_string(uint16_t c)
1529{
1530	switch (c)
1531	{
1532		case ns_c_in: return "IN";
1533		case ns_c_2: return "CS";
1534		case ns_c_chaos: return "CH";
1535		case ns_c_hs: return "HS";
1536		case ns_c_none: return "NONE";
1537		case ns_c_any: return "ANY";
1538		default: return "??";
1539	}
1540
1541	return "??";
1542}
1543
1544int32_t
1545dns_class_number(const char *c, uint16_t *n)
1546{
1547	if (c == NULL) return -1;
1548
1549	if (!strcasecmp(c, "IN"))   { *n = ns_c_in;    return 0; }
1550	if (!strcasecmp(c, "CS"))   { *n = ns_c_2;     return 0; }
1551	if (!strcasecmp(c, "CH"))   { *n = ns_c_chaos; return 0; }
1552	if (!strcasecmp(c, "HS"))   { *n = ns_c_hs;    return 0; }
1553	if (!strcasecmp(c, "NONE")) { *n = ns_c_none;  return 0; }
1554	if (!strcasecmp(c, "ANY"))  { *n = ns_c_any;   return 0; }
1555
1556	return -1;
1557}
1558
1559static void
1560_dns_print_question_lock(const dns_question_t *q, FILE *f, int lockit)
1561{
1562	if (lockit != 0) _dns_print_lock();
1563	fprintf(f, "%s %s %s\n", q->name, dns_class_string(q->dnsclass), dns_type_string(q->dnstype));
1564	if (lockit != 0) _dns_print_unlock();
1565}
1566
1567void
1568dns_print_question(const dns_question_t *q, FILE *f)
1569{
1570	_dns_print_question_lock(q, f, 1);
1571}
1572
1573static void
1574_dns_print_resource_record_lock(const dns_resource_record_t *r, FILE *f, int lockit)
1575{
1576	struct protoent *p;
1577	struct servent *s;
1578	uint32_t i, len;
1579	uint8_t x;
1580	struct sockaddr_in6 s6;
1581	char pbuf[64];
1582
1583	if (lockit != 0) _dns_print_lock();
1584
1585	fprintf(f, "%s %s %s ", r->name, dns_class_string(r->dnsclass), dns_type_string(r->dnstype));
1586	fprintf(f, "%u", r->ttl);
1587
1588	switch (r->dnstype)
1589	{
1590		case ns_t_a:
1591			fprintf(f, " %s", inet_ntoa(r->data.A->addr));
1592			break;
1593
1594		case ns_t_aaaa:
1595			memset(&s6, 0, sizeof(struct sockaddr_in6));
1596			s6.sin6_len = sizeof(struct sockaddr_in6);
1597			s6.sin6_family = AF_INET6;
1598			s6.sin6_addr = r->data.AAAA->addr;
1599			fprintf(f, " %s", inet_ntop(AF_INET6, (char *)(&s6) + INET_NTOP_AF_INET6_OFFSET, pbuf, 64));
1600			break;
1601
1602		case ns_t_md:
1603		case ns_t_mf:
1604		case ns_t_cname:
1605		case ns_t_mb:
1606		case ns_t_mg:
1607		case ns_t_mr:
1608		case ns_t_ptr:
1609		case ns_t_ns:
1610			fprintf(f, " %s", r->data.CNAME->name);
1611			break;
1612
1613		case ns_t_soa:
1614			fprintf(f, " %s %s %u %u %u %u %u",
1615				r->data.SOA->mname, r->data.SOA->rname,
1616				r->data.SOA->serial, r->data.SOA->refresh, r->data.SOA->retry,
1617				r->data.SOA->expire, r->data.SOA->minimum);
1618			break;
1619
1620		case ns_t_wks:
1621			fprintf(f, " %s", inet_ntoa(r->data.WKS->addr));
1622			p = getprotobynumber(r->data.WKS->protocol);
1623			if (p != NULL)
1624			{
1625				fprintf(f, " %s", p->p_name);
1626
1627				for (i = 0; i < r->data.WKS->maplength; i++)
1628				{
1629					if (r->data.WKS->map[i])
1630					{
1631						s = getservbyport(i, p->p_name);
1632						if (s == NULL) fprintf(f, " %u", i);
1633						else fprintf(f, " %s", s->s_name);
1634					}
1635				}
1636			}
1637			else fprintf(f, " UNKNOWN PROTOCOL %u", r->data.WKS->protocol);
1638			break;
1639
1640		case ns_t_hinfo:
1641			fprintf(f, " %s %s", r->data.HINFO->cpu, r->data.HINFO->os);
1642			break;
1643
1644		case ns_t_minfo:
1645			fprintf(f, " %s %s", r->data.MINFO->rmailbx, r->data.MINFO->emailbx);
1646			break;
1647
1648		case ns_t_mx:
1649			fprintf(f, " %u %s", r->data.MX->preference, r->data.MX->name);
1650			break;
1651
1652		case ns_t_txt:
1653			for (i = 0; i < r->data.TXT->string_count; i++)
1654			{
1655				fprintf(f, " \"%s\"", r->data.TXT->strings[i]);
1656			}
1657			break;
1658
1659		case ns_t_rp:
1660			fprintf(f, " %s %s", r->data.RP->mailbox, r->data.RP->txtdname);
1661			break;
1662
1663		case ns_t_afsdb:
1664			fprintf(f, " %u %s", r->data.AFSDB->subtype,
1665				r->data.AFSDB->hostname);
1666			break;
1667
1668		case ns_t_x25:
1669			fprintf(f, " %s", r->data.X25->psdn_address);
1670			break;
1671
1672		case ns_t_isdn:
1673			fprintf(f, " %s", r->data.ISDN->isdn_address);
1674			if (r->data.ISDN->subaddress != NULL)
1675				fprintf(f, " %s", r->data.ISDN->subaddress);
1676			break;
1677
1678		case ns_t_rt:
1679			fprintf(f, " %hu %s", r->data.RT->preference,
1680				r->data.RT->intermediate);
1681			break;
1682
1683		case ns_t_loc:
1684			fprintf(f, " %s", coord_ntoa(r->data.LOC->latitude, 1));
1685			fprintf(f, " %s", coord_ntoa(r->data.LOC->longitude, 0));
1686			fprintf(f, " %sm", alt_ntoa(r->data.LOC->altitude));
1687			fprintf(f, " %sm", precsize_ntoa(r->data.LOC->size));
1688			fprintf(f, " %sm", precsize_ntoa(r->data.LOC->horizontal_precision));
1689			fprintf(f, " %sm", precsize_ntoa(r->data.LOC->vertical_precision));
1690			break;
1691
1692		case ns_t_srv:
1693			fprintf(f, " %hu %hu %hu %s",
1694				r->data.SRV->priority, r->data.SRV->weight,
1695				r->data.SRV->port, r->data.SRV->target);
1696			break;
1697
1698		case ns_t_null:
1699		default:
1700			len = r->data.DNSNULL->length;
1701			fprintf(f, " %u ", len);
1702			for (i = 0; i < len; i++)
1703			{
1704				x = r->data.DNSNULL->data[i];
1705				fprintf(f, "%x", x);
1706			}
1707
1708			fprintf(f, " (");
1709
1710			len = r->data.DNSNULL->length;
1711			for (i = 0; i < len; i++)
1712			{
1713				x = r->data.DNSNULL->data[i];
1714				if (isascii(x)) fprintf(f, "%c", x);
1715				else fprintf(f, " ");
1716			}
1717			fprintf(f, ")\n");
1718
1719	}
1720
1721	fprintf(f, "\n");
1722
1723	if (lockit != 0) _dns_print_unlock();
1724}
1725
1726void
1727dns_print_resource_record(const dns_resource_record_t *r, FILE *f)
1728{
1729	_dns_print_resource_record_lock(r, f, 1);
1730}
1731
1732void
1733dns_print_reply(const dns_reply_t *r, FILE *f, uint16_t mask)
1734{
1735	uint16_t i;
1736	dns_header_t *h;
1737	char scratch[1024];
1738	uint32_t offset, iface;
1739
1740	_dns_print_lock();
1741
1742	if (r == NULL)
1743	{
1744		fprintf(f, "-nil-\n");
1745		_dns_print_unlock();
1746		return;
1747	}
1748
1749	if (r->status != DNS_STATUS_OK)
1750	{
1751		if (r->status == DNS_STATUS_TIMEOUT)
1752			fprintf(f, "Timeout\n");
1753		else if (r->status == DNS_STATUS_SEND_FAILED)
1754			fprintf(f, "Send failed\n");
1755		else if (r->status == DNS_STATUS_RECEIVE_FAILED)
1756			fprintf(f, "Receive failed\n");
1757		else fprintf(f, "status %u\n", r->status);
1758
1759		_dns_print_unlock();
1760		return;
1761	}
1762
1763	h = r->header;
1764
1765	if (mask & DNS_PRINT_XID)
1766	{
1767		fprintf(f, "Xid: %u\n", h->xid);
1768	}
1769
1770	if (mask & DNS_PRINT_QR)
1771	{
1772		if ((h->flags & DNS_FLAGS_QR_MASK) == DNS_FLAGS_QR_QUERY)
1773			fprintf(f, "QR: Query\n");
1774		else
1775			fprintf(f, "QR: Reply\n");
1776	}
1777
1778	if (mask & DNS_PRINT_SERVER)
1779	{
1780		if (r->server == NULL)
1781		{
1782			fprintf(f, "Server: -nil-\n");
1783		}
1784		else
1785		{
1786			offset = INET_NTOP_AF_INET_OFFSET;
1787			if (r->server->sa_family == AF_INET6) offset = INET_NTOP_AF_INET6_OFFSET;
1788
1789			fprintf(f, "Server: %s", inet_ntop(r->server->sa_family, (char *)(r->server) + offset, scratch, 1024));
1790			if (r->server->sa_family == AF_INET)
1791			{
1792				memcpy(&iface, (((struct sockaddr_in *)(r->server))->sin_zero), 4);
1793				if (iface > 0) fprintf(f, "%%%s", if_indextoname(iface, scratch));
1794			}
1795			else if (r->server->sa_family == AF_INET6)
1796			{
1797				iface = ((struct sockaddr_in6 *)(r->server))->sin6_scope_id;
1798				if (iface > 0) fprintf(f, "%%%s", if_indextoname(iface, scratch));
1799			}
1800			fprintf(f, "\n");
1801		}
1802	}
1803
1804	if (mask & DNS_PRINT_OPCODE)
1805	{
1806		fprintf(f, "Opcode: ");
1807		switch (h->flags & DNS_FLAGS_OPCODE_MASK)
1808		{
1809			case ns_o_query:  fprintf(f, "Standard\n"); break;
1810			case ns_o_iquery: fprintf(f, "Inverse\n"); break;
1811			case ns_o_status: fprintf(f, "Status\n"); break;
1812			case ns_o_notify: fprintf(f, "Notify\n"); break;
1813			case ns_o_update: fprintf(f, "Update\n"); break;
1814			default:
1815				fprintf(f, "Reserved (%hu)\n",
1816					(uint16_t)((h->flags & DNS_FLAGS_OPCODE_MASK) >> 11));
1817		}
1818	}
1819
1820	if (mask & DNS_PRINT_AA)
1821	{
1822		if (h->flags & DNS_FLAGS_AA) fprintf(f, "AA: Authoritative\n");
1823		else fprintf(f, "AA: Non-Authoritative\n");
1824	}
1825
1826	if (mask & DNS_PRINT_TC)
1827	{
1828		if (h->flags & DNS_FLAGS_TC) fprintf(f, "TC: Truncated\n");
1829		else fprintf(f, "TC: Non-Truncated\n");
1830	}
1831
1832	if (mask & DNS_PRINT_RD)
1833	{
1834		if (h->flags & DNS_FLAGS_RD) fprintf(f, "RD: Recursion desired\n");
1835		else fprintf(f, "RD: No recursion desired\n");
1836	}
1837
1838	if (mask & DNS_PRINT_RA)
1839	{
1840		if (h->flags & DNS_FLAGS_RA) fprintf(f, "RA: Recursion available\n");
1841		else fprintf(f, "RA: No recursion available \n");
1842	}
1843
1844	if (mask & DNS_PRINT_RCODE)
1845	{
1846		fprintf(f, "Rcode: ");
1847		switch (h->flags & DNS_FLAGS_RCODE_MASK)
1848		{
1849			case ns_r_noerror:
1850				fprintf(f, "No error\n");
1851				break;
1852			case ns_r_formerr:
1853				fprintf(f, "Format error \n");
1854				break;
1855			case ns_r_servfail:
1856				fprintf(f, "Server failure\n");
1857				break;
1858			case ns_r_nxdomain:
1859				fprintf(f, "Name error \n");
1860				break;
1861			case ns_r_notimpl:
1862				fprintf(f, "Not implemented\n");
1863				break;
1864			case ns_r_refused:
1865				fprintf(f, "Refused\n");
1866				break;
1867			case ns_r_yxdomain:
1868				fprintf(f, "Name exists\n");
1869				break;
1870			case ns_r_yxrrset:
1871				fprintf(f, "RR Set exists\n");
1872				break;
1873			case ns_r_nxrrset:
1874				fprintf(f, "RR Set does not exist\n");
1875				break;
1876			case ns_r_notauth:
1877				fprintf(f, "Not authoritative\n");
1878				break;
1879			case ns_r_notzone:
1880				fprintf(f, "Record zone does not match section zone\n");
1881				break;
1882			case ns_r_badvers:
1883				fprintf(f, "Invalid EDNS version or TSIG signature\n");
1884				break;
1885			case ns_r_badkey:
1886				fprintf(f, "Invalid key\n");
1887				break;
1888			case ns_r_badtime:
1889				fprintf(f, "Invalid time\n");
1890				break;
1891			default:
1892				fprintf(f, "Reserved (%hu)\n",(uint16_t)(h->flags & DNS_FLAGS_RCODE_MASK));
1893		}
1894	}
1895
1896	if (mask & DNS_PRINT_QUESTION)
1897	{
1898		fprintf(f, "Question (%hu):\n", h->qdcount);
1899		for (i = 0; i < h->qdcount; i++)
1900			_dns_print_question_lock(r->question[i], f, 0);
1901	}
1902
1903	if (mask & DNS_PRINT_ANSWER)
1904	{
1905		fprintf(f, "Answer (%hu):\n", h->ancount);
1906		for (i = 0; i < h->ancount; i++)
1907			_dns_print_resource_record_lock(r->answer[i], f, 0);
1908	}
1909
1910	if (mask & DNS_PRINT_AUTHORITY)
1911	{
1912		fprintf(f, "Authority (%hu):\n", h->nscount);
1913		for (i = 0; i < h->nscount; i++)
1914			_dns_print_resource_record_lock(r->authority[i], f, 0);
1915	}
1916
1917	if (mask & DNS_PRINT_ADDITIONAL)
1918	{
1919		fprintf(f, "Additional records (%hu):\n", h->arcount);
1920		for (i = 0; i < h->arcount; i++)
1921			_dns_print_resource_record_lock(r->additional[i], f, 0);
1922	}
1923
1924	_dns_print_unlock();
1925}
1926
1927static void
1928_pdns_print_handle(pdns_handle_t *pdns, FILE *f)
1929{
1930	uint32_t i, offset;
1931	struct in_addr a;
1932	char scratch[1024];
1933	struct sockaddr *sa;
1934	res_state r;
1935
1936	if (pdns == NULL)
1937	{
1938		fprintf(f, "-nil-\n");
1939		return;
1940	}
1941
1942	if (pdns->name == NULL) fprintf(f, "Name: -nil-\n");
1943	else fprintf(f, "Name: %s\n", pdns->name);
1944
1945	fprintf(f, "Flags:");
1946	if (pdns->flags == 0) fprintf(f, " None\n");
1947	else
1948	{
1949		if (pdns->flags & DNS_FLAG_DEBUG) fprintf(f, " Debug");
1950		if (pdns->flags & DNS_FLAG_CHECK_RESOLVER_DIR) fprintf(f, " DirCheck");
1951		if (pdns->flags & DNS_FLAG_HAVE_IPV6_SERVER) fprintf(f, " IPv6");
1952		if (pdns->flags & DNS_FLAG_OK_TO_SKIP_AAAA) fprintf(f, " SkipAAAA");
1953		if (pdns->flags & DNS_FLAG_DEFAULT_RESOLVER) fprintf(f, " Default");
1954		fprintf(f, "\n");
1955	}
1956
1957	r = pdns->res;
1958	if (r == NULL) return;
1959
1960	if (r->defdname[0] != '\0') fprintf(f, "Domain: %s\n", r->defdname);
1961	fprintf(f, "Search Order: %d\n", pdns->search_order);
1962	fprintf(f, "Total Timeout: %d\n", pdns->total_timeout);
1963	fprintf(f, "Retry Timeout: %d\n", pdns->res->retrans);
1964	fprintf(f, "Retry Attempts: %d\n", pdns->res->retry);
1965
1966	fprintf(f, "Server%s:\n", (r->nscount == 1) ? "" : "s");
1967	for (i = 0; i < r->nscount; i++)
1968	{
1969		sa = get_nsaddr(r, i);
1970		offset = INET_NTOP_AF_INET_OFFSET;
1971		if (sa->sa_family == AF_INET6) offset = INET_NTOP_AF_INET6_OFFSET;
1972		fprintf(f, "  %u: %s", i, inet_ntop(sa->sa_family, (char *)sa + offset, scratch, 1024));
1973		fprintf(f, "\n");
1974	}
1975
1976	if (pdns->search_count > 0)
1977	{
1978		fprintf(f, "Search List:\n");
1979		for (i = 0; i < pdns->search_count; i++)
1980			fprintf(f, "  %u: %s\n", i, pdns->search_list[i]);
1981	}
1982
1983	if (r->sort_list[0].addr.s_addr != 0)
1984	{
1985		fprintf(f, "Sortlist:\n");
1986		for (i = 0; (r->sort_list[i].addr.s_addr != 0); i++)
1987		{
1988			fprintf(f, "  %u: ", i);
1989			a.s_addr = r->sort_list[i].addr.s_addr;
1990			fprintf(f, "%s/", inet_ntoa(a));
1991			a.s_addr = r->sort_list[i].mask;
1992			fprintf(f, "%s\n", inet_ntoa(a));
1993		}
1994	}
1995}
1996
1997static void
1998_sdns_print_handle(sdns_handle_t *sdns, FILE *f)
1999{
2000	int i;
2001
2002	if (sdns == NULL)
2003	{
2004		fprintf(f, "-nil-\n");
2005		return;
2006	}
2007
2008	for (i = 0; i < sdns->client_count; i++)
2009	{
2010		fprintf(f, "DNS client %d\n", i);
2011		_pdns_print_handle(sdns->client[i], f);
2012		fprintf(f, "\n");
2013	}
2014
2015	fprintf(f, "resolver dir mod time = %u\n", sdns->modtime);
2016	fprintf(f, "resolver dir stat time = %u\n", sdns->stattime);
2017	fprintf(f, "resolver dir stat latency = %u\n", sdns->stat_latency);
2018}
2019
2020void
2021dns_print_handle(dns_handle_t d, FILE *f)
2022{
2023	dns_private_handle_t *dns;
2024
2025	_dns_print_lock();
2026
2027	if (d == NULL)
2028	{
2029		fprintf(f, "-nil-\n");
2030		_dns_print_unlock();
2031		return;
2032	}
2033
2034	dns = (dns_private_handle_t *)d;
2035
2036	if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER)
2037	{
2038		_sdns_print_handle(dns->sdns, f);
2039	}
2040	else
2041	{
2042		_pdns_print_handle(dns->pdns, f);
2043	}
2044
2045	_dns_print_unlock();
2046}
2047
2048void
2049dns_all_server_addrs(dns_handle_t d, struct sockaddr ***addrs, uint32_t *count)
2050{
2051	int i, j, k, n, found;
2052	dns_private_handle_t *dns;
2053	pdns_handle_t *pdns;
2054	struct sockaddr *sa;
2055	struct sockaddr_storage **l;
2056	res_state r;
2057
2058	*addrs = NULL;
2059	*count = 0;
2060	l = NULL;
2061	n = 0;
2062
2063	if (d == NULL) return;
2064
2065	dns = (dns_private_handle_t *)d;
2066
2067	if (dns->handle_type != DNS_PRIVATE_HANDLE_TYPE_SUPER) return;
2068
2069	if (dns->sdns == NULL) return;
2070
2071	/* Just to initialize / validate clients */
2072	i = dns_search_list_count(d);
2073
2074	for (i = 0; i < dns->sdns->client_count; i++)
2075	{
2076		pdns = dns->sdns->client[i];
2077		if (pdns == NULL) continue;
2078
2079		r = pdns->res;
2080		if (r == NULL) continue;
2081
2082		for (j = 0; j < r->nscount; j++)
2083		{
2084			sa = get_nsaddr(r, j);
2085			found = 0;
2086			for (k = 0; (found == 0) && (k < n); k++)
2087			{
2088				if (memcmp(l[k], sa, sa->sa_len) == 0) found = 1;
2089			}
2090			if (found == 1) continue;
2091
2092			if (n == 0)
2093			{
2094				l = (struct sockaddr_storage **)calloc(1, sizeof(struct sockaddr_storage *));
2095			}
2096			else
2097			{
2098				l = (struct sockaddr_storage **)reallocf(l, (n + 1) * sizeof(struct sockaddr_storage *));
2099			}
2100
2101			if (l == NULL) return;
2102
2103			l[n] = (struct sockaddr_storage *)calloc(1, sizeof(struct sockaddr_storage));
2104			if (l[n] == NULL) return;
2105
2106			memset(l[n], 0, sizeof(struct sockaddr_storage));
2107			memcpy(l[n], sa, sa->sa_len);
2108			n++;
2109		}
2110	}
2111
2112	*addrs = (struct sockaddr **)l;
2113	*count = n;
2114}
2115
2116int
2117dns_res_once(struct sockaddr *server, struct timeval *timeout, int options, const char *name, int class, int type, u_char *res, int *reslen)
2118{
2119	res_state statp;
2120	int n, fromlen, status;
2121	struct sockaddr_storage from;
2122	u_char buf[MAXPACKET];
2123
2124	if (server == NULL) return DNS_RES_STATUS_INVALID_ARGUMENT;
2125	if (name == NULL) return DNS_RES_STATUS_INVALID_ARGUMENT;
2126	if (res == NULL) return DNS_RES_STATUS_INVALID_ARGUMENT;
2127	if (reslen == NULL) return DNS_RES_STATUS_INVALID_ARGUMENT;
2128
2129	fromlen = sizeof(struct sockaddr_storage);
2130
2131	statp = res_state_new();
2132	statp->retry = 1;
2133	statp->options = options;
2134	statp->id = res_randomid();
2135	if (timeout == NULL) statp->retrans = 5;
2136	else statp->retrans = timeout->tv_sec;
2137
2138	statp->ndots = 1;
2139	statp->_vcsock = -1;
2140	statp->nscount = 1;
2141
2142	strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa");
2143	strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int");
2144	strcpy(statp->_u._ext.ext->bsuffix, "ip6.arpa");
2145
2146	if (server->sa_family == AF_INET6)
2147	{
2148		memcpy(&(statp->_u._ext.ext->nsaddrs[0]), server, sizeof(struct sockaddr_in6));
2149		statp->nsaddr_list[0].sin_family = 0;
2150	}
2151	else
2152	{
2153		memcpy(&(statp->_u._ext.ext->nsaddrs[0]), server, sizeof(struct sockaddr_in));
2154		memcpy(&(statp->nsaddr_list[0]), server, sizeof(struct sockaddr_in));
2155	}
2156
2157	n = res_nmkquery(statp, ns_o_query, name, class, type, NULL, 0, NULL, buf, sizeof(buf));
2158
2159	status = dns_res_send(statp, buf, n, res, reslen, (struct sockaddr *)&from, &fromlen);
2160
2161	res_client_close(statp);
2162
2163	return status;
2164}
2165