Libinfo-517.tar.gz
[apple/libinfo.git] / dns.subproj / res_query.c
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
33 extern 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
45 char _res[RES_9_STATE_SIZE] = {0};
46
47 int
48 res_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.
58 static 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 int cpylen = 0;
65
66 si_mod_t *dns = si_module_with_name("mdns");
67 if (dns == NULL) {
68 h_errno = NO_RECOVERY;
69 return -1;
70 }
71
72 item = dns->vtable->sim_item_call(dns, call, name, NULL, NULL, class, type, &err);
73
74 if (item != NULL) {
75 si_dnspacket_t *p;
76
77 p = (si_dnspacket_t *)((uintptr_t)item + sizeof(si_item_t));
78
79 res = p->dns_packet_len;
80
81 if (res >= 0 && anslen >= 0) {
82 // Truncate destination buffer size.
83 memcpy(answer, p->dns_packet, (cpylen = MIN(res, anslen)));
84 }
85 else {
86 h_errno = NO_RECOVERY;
87 res = -1;
88 }
89
90 si_item_release(item);
91 } else {
92 h_errno = HOST_NOT_FOUND;
93 res = -1;
94 }
95
96 if (cpylen >= sizeof(HEADER)) {
97 HEADER *hp = (HEADER *)answer;
98 switch (hp->rcode) {
99 case NXDOMAIN:
100 h_errno = HOST_NOT_FOUND;
101 res = -1;
102 break;
103 case SERVFAIL:
104 h_errno = TRY_AGAIN;
105 res = -1;
106 break;
107 case NOERROR:
108 if (ntohs(hp->ancount) == 0) {
109 h_errno = NO_DATA;
110 res = -1;
111 }
112 break;
113 case FORMERR:
114 case NOTIMP:
115 case REFUSED:
116 default:
117 h_errno = NO_RECOVERY;
118 res = -1;
119 break;
120 }
121 }
122
123 si_module_release(dns);
124 return res;
125 }
126
127 int
128 res_query(const char *name, int class, int type, u_char *answer, int anslen)
129 {
130 return _mdns_query(SI_CALL_DNS_QUERY, name, class, type, answer, anslen);
131 }
132
133 int
134 res_search(const char *name, int class, int type, u_char *answer, int anslen)
135 {
136 return _mdns_query(SI_CALL_DNS_SEARCH, name, class, type, answer, anslen);
137 }