]> git.saurik.com Git - apple/libresolv.git/blob - dns_async.c
9aa367ac807b32abc0023bab5795e95f12b9f4fd
[apple/libresolv.git] / dns_async.c
1 /*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_headER_START@
5 *
6 * Portions Copyright (c) 2003 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 <stdlib.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <mach/mach.h>
29 #include <pthread.h>
30 #include <netdb.h>
31 #include <netdb_async.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #include <dns.h>
35 #include <dns_util.h>
36
37 typedef struct
38 {
39 uint32_t datalen;
40 char *databuf;
41 uint32_t _size;
42 uint32_t _dict;
43 uint32_t _key;
44 uint32_t _vlist;
45 uint32_t _val;
46 } kvbuf_t;
47
48 typedef struct
49 {
50 uint32_t kcount;
51 const char **key;
52 uint32_t *vcount;
53 const char ***val;
54 } kvdict_t;
55
56 typedef struct
57 {
58 uint32_t count;
59 uint32_t curr;
60 kvdict_t *dict;
61 kvbuf_t *kv;
62 } kvarray_t;
63
64 extern kvbuf_t *kvbuf_new(void);
65 extern void kvbuf_add_dict(kvbuf_t *kv);
66 extern void kvbuf_add_key(kvbuf_t *kv, const char *key);
67 extern void kvbuf_add_val(kvbuf_t *kv, const char *val);
68 extern void kvbuf_free(kvbuf_t *kv);
69 extern void kvarray_free(kvarray_t *kva);
70 extern uint32_t kvbuf_get_val_len(const char *val);
71 extern kern_return_t LI_DSLookupGetProcedureNumber(const char *name, int *procno);
72 extern kern_return_t LI_async_start(mach_port_t *p, uint32_t proc, kvbuf_t *query, void *callback, void *context);
73 extern kern_return_t LI_async_handle_reply(void *msg, kvarray_t **reply, void **callback, void **context);
74 extern kern_return_t LI_async_receive(mach_port_t p, kvarray_t **reply);
75 extern void LI_async_call_cancel(mach_port_t p, void **context);
76 extern uint32_t kvbuf_get_len(const char *p);
77
78 static kvbuf_t *
79 dns_make_query(const char *name, uint16_t dnsclass, uint16_t dnstype, uint32_t do_search)
80 {
81 kvbuf_t *request;
82 char str[128];
83
84 if (name == NULL) return NULL;
85
86 request = kvbuf_new();
87 if (request == NULL) return NULL;
88
89 kvbuf_add_dict(request);
90
91 /* Encode name */
92 kvbuf_add_key(request, "domain");
93 kvbuf_add_val(request, name);
94
95 /* Encode class */
96 snprintf(str, 128, "%hu", dnsclass);
97 kvbuf_add_key(request, "class");
98 kvbuf_add_val(request, str);
99
100 /* Encode type */
101 snprintf(str, 128, "%hu", dnstype);
102 kvbuf_add_key(request, "type");
103 kvbuf_add_val(request, str);
104
105 /* Encode do_search */
106 snprintf(str, 128, "%hu", do_search);
107 kvbuf_add_key(request, "search");
108 kvbuf_add_val(request, str);
109
110 return request;
111 }
112
113 int32_t
114 dns_async_start(mach_port_t *p, const char *name, uint16_t dnsclass, uint16_t dnstype, uint32_t do_search, dns_async_callback callback, void *context)
115 {
116 int32_t status;
117 kvbuf_t *request;
118 static int proc = -1;
119
120 *p = MACH_PORT_NULL;
121
122 if (name == NULL) return NO_RECOVERY;
123
124 if (proc < 0)
125 {
126 status = LI_DSLookupGetProcedureNumber("dns_proxy", &proc);
127 if (status != KERN_SUCCESS) return NO_RECOVERY;
128 }
129
130 request = dns_make_query(name, dnsclass, dnstype, do_search);
131 if (request == NULL) return NO_RECOVERY;
132
133 status = LI_async_start(p, proc, request, (void *)callback, context);
134
135 kvbuf_free(request);
136 if (status != 0) return NO_RECOVERY;
137 return 0;
138 }
139
140 void
141 dns_async_cancel(mach_port_t p)
142 {
143 LI_async_call_cancel(p, NULL);
144 }
145
146 int32_t
147 dns_async_send(mach_port_t *p, const char *name, uint16_t dnsclass, uint16_t dnstype, uint32_t do_search)
148 {
149 return dns_async_start(p, name, dnsclass, dnstype, do_search, NULL, NULL);
150 }
151
152 static int
153 dns_extract_data(kvarray_t *in, char **buf, uint32_t *len, struct sockaddr **from, uint32_t *fromlen)
154 {
155 int32_t status;
156 struct in_addr addr4;
157 struct sockaddr_in sin4;
158 struct in6_addr addr6;
159 struct sockaddr_in6 sin6;
160 uint32_t d, k, kcount;
161
162 if (in == NULL) return -1;
163 if (buf == NULL) return -1;
164 if (len == NULL) return -1;
165 if (from == NULL) return -1;
166 if (fromlen == NULL) return -1;
167
168 *buf = NULL;
169 *len = 0;
170 *from = NULL;
171 *fromlen = 0;
172
173 d = in->curr;
174 in->curr++;
175
176 if (d >= in->count) return -1;
177
178 kcount = in->dict[d].kcount;
179
180 for (k = 0; k < kcount; k++)
181 {
182 if (!strcmp(in->dict[d].key[k], "data"))
183 {
184 if (in->dict[d].vcount[k] == 0) continue;
185 if (*buf != NULL) continue;
186
187 /*
188 * dns_proxy contains binary data, possibly with embedded nuls,
189 * so we extract the string length from the kvbuf_t reply that
190 * Libinfo got from directory services, rather than calling strlen().
191 */
192 *len = kvbuf_get_len(in->dict[d].val[k][0]);
193 if (*len == 0) continue;
194
195 *buf = malloc(*len);
196 if (*buf == NULL) return -1;
197
198 memcpy(*buf, in->dict[d].val[k][0], *len);
199 }
200 else if (!strcmp(in->dict[d].key[k], "server"))
201 {
202 if (in->dict[d].vcount[k] == 0) continue;
203 if (*from != NULL) continue;
204
205 memset(&addr4, 0, sizeof(struct in_addr));
206 memset(&sin4, 0, sizeof(struct sockaddr_in));
207
208 memset(&addr6, 0, sizeof(struct in6_addr));
209 memset(&sin6, 0, sizeof(struct sockaddr_in6));
210
211 status = inet_pton(AF_INET6, in->dict[d].val[k][0], &addr6);
212 if (status == 1)
213 {
214 sin6.sin6_addr = addr6;
215 sin6.sin6_family = AF_INET6;
216 sin6.sin6_len = sizeof(struct sockaddr_in6);
217 *from = (struct sockaddr *)calloc(1, sin6.sin6_len);
218 memcpy(*from, &sin6, sin6.sin6_len);
219 *fromlen = sin6.sin6_len;
220 }
221
222 status = inet_pton(AF_INET, in->dict[d].val[k][0], &addr4);
223 if (status == 1)
224 {
225 sin4.sin_addr = addr4;
226 sin4.sin_family = AF_INET;
227 sin4.sin_len = sizeof(struct sockaddr_in);
228 *from = (struct sockaddr *)calloc(1, sin4.sin_len);
229 memcpy(*from, &sin4, sin4.sin_len);
230 *fromlen = sin4.sin_len;
231 }
232 }
233 }
234
235 return 0;
236 }
237
238 int32_t
239 dns_async_receive(mach_port_t p, char **buf, uint32_t *len, struct sockaddr **from, uint32_t *fromlen)
240 {
241 kern_return_t status;
242 kvarray_t *reply;
243
244 reply = NULL;
245
246 status = LI_async_receive(p, &reply);
247 if (status != 0) return NO_RECOVERY;
248 if (reply == NULL) return HOST_NOT_FOUND;
249
250 status = dns_extract_data(reply, buf, len, from, fromlen);
251 kvarray_free(reply);
252 if (status != 0) return NO_RECOVERY;
253
254 if (*buf == NULL) return NO_DATA;
255
256 return 0;
257 }
258
259 int32_t
260 dns_async_handle_reply(void *msg)
261 {
262 dns_async_callback callback;
263 void *context;
264 char *buf;
265 kvarray_t *reply;
266 kern_return_t status;
267 struct sockaddr *from;
268 uint32_t len, fromlen;
269
270 callback = (dns_async_callback)NULL;
271 context = NULL;
272 reply = NULL;
273 buf = NULL;
274 len = 0;
275 from = NULL;
276 fromlen = 0;
277
278 status = LI_async_handle_reply(msg, &reply, (void **)&callback, &context);
279 if (status != KERN_SUCCESS)
280 {
281 if (status == MIG_REPLY_MISMATCH) return 0;
282 callback(NO_RECOVERY, NULL, 0, NULL, 0, context);
283 return NO_RECOVERY;
284 }
285
286 status = dns_extract_data(reply, &buf, &len, &from, &fromlen);
287 kvarray_free(reply);
288 if (status != 0)
289 {
290 callback(NO_RECOVERY, NULL, 0, NULL, 0, context);
291 return 0;
292 }
293
294 if (buf == NULL)
295 {
296 callback(NO_DATA, NULL, 0, NULL, 0, context);
297 return NO_DATA;
298 }
299
300 callback(0, buf, len, from, fromlen, context);
301
302 return 0;
303 }
304