1/*
2 * Copyright (c) 1999, 2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
7 * Reserved.  This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License").  You may not use this file
10 * except in compliance with the License.  Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT.  Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25#include <dns_sd.h>
26#include <errno.h>
27
28#include <arpa/nameser_compat.h>
29#include <nameser.h>
30
31#include "si_module.h"
32
33extern int h_errno;
34
35// Storage for the global struct __res_9_state.
36// The BIND9 libresolv.dylib shares the same storage for this structure as the
37// legacy BIND8 libsystem_info.dylib. This implementation does not require the
38// _res structure but libresolv.dylib does and many 3rd-party applications
39// access this global symbol directly so we preserve it here.
40#ifdef __LP64__
41#define RES_9_STATE_SIZE 552
42#else
43#define RES_9_STATE_SIZE 512
44#endif
45char _res[RES_9_STATE_SIZE] = {0};
46
47int
48res_init(void)
49{
50	// For compatibility only.
51	return 0;
52}
53
54// Perform a DNS query. Returned DNS response is placed in the answer buffer.
55// A preliminary check of the answer is performed and success is returned only
56// if no error is indicated in the answer and the answer count is nonzero.
57// Returns the size of the response on success, or -1 with h_errno set.
58static int
59_mdns_query(int call, const char *name, int class, int type, u_char *answer, int anslen)
60{
61	int res = -1;
62	si_item_t *item;
63	uint32_t err;
64
65	si_mod_t *dns = si_module_with_name("mdns");
66	if (dns == NULL) {
67		h_errno = NO_RECOVERY;
68		return -1;
69	}
70
71	item = dns->vtable->sim_item_call(dns, call, name, NULL, NULL, class, type, &err);
72
73	if (item != NULL) {
74		si_dnspacket_t *p;
75
76		p = (si_dnspacket_t *)((uintptr_t)item + sizeof(si_item_t));
77
78		res = p->dns_packet_len;
79
80		// Truncate to destination buffer size.
81		memcpy(answer, p->dns_packet, MIN(res, anslen));
82
83		si_item_release(item);
84	} else {
85		h_errno = HOST_NOT_FOUND;
86		res = -1;
87	}
88
89	if (MIN(res, anslen) >= sizeof(HEADER)) {
90		HEADER *hp = (HEADER *)answer;
91		switch (hp->rcode) {
92			case NXDOMAIN:
93				h_errno = HOST_NOT_FOUND;
94				res = -1;
95				break;
96			case SERVFAIL:
97				h_errno = TRY_AGAIN;
98				res = -1;
99				break;
100			case NOERROR:
101				if (ntohs(hp->ancount) == 0) {
102					h_errno = NO_DATA;
103					res = -1;
104				}
105				break;
106			case FORMERR:
107			case NOTIMP:
108			case REFUSED:
109			default:
110				h_errno = NO_RECOVERY;
111				res = -1;
112				break;
113		}
114	}
115
116	si_module_release(dns);
117	return res;
118}
119
120int
121res_query(const char *name, int class, int type, u_char *answer, int anslen)
122{
123	return _mdns_query(SI_CALL_DNS_QUERY, name, class, type, answer, anslen);
124}
125
126int
127res_search(const char *name, int class, int type, u_char *answer, int anslen)
128{
129	return _mdns_query(SI_CALL_DNS_SEARCH, name, class, type, answer, anslen);
130}
131