Libinfo-517.200.9.tar.gz
[apple/libinfo.git] / dns.subproj / res_query.c
1 /*
2 * Copyright (c) 1999, 2012-2018 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 "libinfo_common.h"
26
27 #include <dns_sd.h>
28 #include <errno.h>
29
30 #include <arpa/nameser_compat.h>
31 #include <nameser.h>
32
33 #include "si_module.h"
34
35 extern int h_errno;
36
37 // Storage for the global struct __res_9_state.
38 // The BIND9 libresolv.dylib shares the same storage for this structure as the
39 // legacy BIND8 libsystem_info.dylib. This implementation does not require the
40 // _res structure but libresolv.dylib does and many 3rd-party applications
41 // access this global symbol directly so we preserve it here.
42 #ifdef __LP64__
43 #define RES_9_STATE_SIZE 552
44 #else
45 #define RES_9_STATE_SIZE 512
46 #endif
47 LIBINFO_EXPORT
48 char _res[RES_9_STATE_SIZE] = {0};
49
50 LIBINFO_EXPORT
51 int
52 res_init(void)
53 {
54 // For compatibility only.
55 return 0;
56 }
57
58 // Perform a DNS query. Returned DNS response is placed in the answer buffer.
59 // A preliminary check of the answer is performed and success is returned only
60 // if no error is indicated in the answer and the answer count is nonzero.
61 // Returns the size of the response on success, or -1 with h_errno set.
62 static int
63 _mdns_query(int call, const char *name, int class, int type, u_char *answer, int anslen)
64 {
65 int res = -1;
66 si_item_t *item;
67 uint32_t err;
68 int cpylen = 0;
69
70 si_mod_t *dns = si_module_with_name("mdns");
71 if (dns == NULL) {
72 h_errno = NO_RECOVERY;
73 return -1;
74 }
75
76 item = dns->vtable->sim_item_call(dns, call, name, NULL, NULL, class, type, &err);
77
78 if (item != NULL) {
79 si_dnspacket_t *p;
80
81 p = (si_dnspacket_t *)((uintptr_t)item + sizeof(si_item_t));
82
83 res = p->dns_packet_len;
84
85 if (res >= 0 && anslen >= 0) {
86 // Truncate destination buffer size.
87 memcpy(answer, p->dns_packet, (cpylen = MIN(res, anslen)));
88 }
89 else {
90 h_errno = NO_RECOVERY;
91 res = -1;
92 }
93
94 si_item_release(item);
95 } else {
96 h_errno = HOST_NOT_FOUND;
97 res = -1;
98 }
99
100 if (cpylen >= sizeof(HEADER)) {
101 HEADER *hp = (HEADER *)answer;
102 switch (hp->rcode) {
103 case NXDOMAIN:
104 h_errno = HOST_NOT_FOUND;
105 res = -1;
106 break;
107 case SERVFAIL:
108 h_errno = TRY_AGAIN;
109 res = -1;
110 break;
111 case NOERROR:
112 if (ntohs(hp->ancount) == 0) {
113 h_errno = NO_DATA;
114 res = -1;
115 }
116 break;
117 case FORMERR:
118 case NOTIMP:
119 case REFUSED:
120 default:
121 h_errno = NO_RECOVERY;
122 res = -1;
123 break;
124 }
125 }
126
127 si_module_release(dns);
128 return res;
129 }
130
131 LIBINFO_EXPORT
132 int
133 res_query(const char *name, int class, int type, u_char *answer, int anslen)
134 {
135 return _mdns_query(SI_CALL_DNS_QUERY, name, class, type, answer, anslen);
136 }
137
138 LIBINFO_EXPORT
139 int
140 res_search(const char *name, int class, int type, u_char *answer, int anslen)
141 {
142 return _mdns_query(SI_CALL_DNS_SEARCH, name, class, type, answer, anslen);
143 }