2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_headER_START@
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
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
22 * @APPLE_LICENSE_headER_END@
28 #include <mach/mach.h>
31 #include <netdb_async.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
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
);
79 dns_make_query(const char *name
, uint16_t dnsclass
, uint16_t dnstype
, uint32_t do_search
)
84 if (name
== NULL
) return NULL
;
86 request
= kvbuf_new();
87 if (request
== NULL
) return NULL
;
89 kvbuf_add_dict(request
);
92 kvbuf_add_key(request
, "domain");
93 kvbuf_add_val(request
, name
);
96 snprintf(str
, 128, "%hu", dnsclass
);
97 kvbuf_add_key(request
, "class");
98 kvbuf_add_val(request
, str
);
101 snprintf(str
, 128, "%hu", dnstype
);
102 kvbuf_add_key(request
, "type");
103 kvbuf_add_val(request
, str
);
105 /* Encode do_search */
106 snprintf(str
, 128, "%hu", do_search
);
107 kvbuf_add_key(request
, "search");
108 kvbuf_add_val(request
, str
);
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
)
118 static int proc
= -1;
122 if (name
== NULL
) return NO_RECOVERY
;
126 status
= LI_DSLookupGetProcedureNumber("dns_proxy", &proc
);
127 if (status
!= KERN_SUCCESS
) return NO_RECOVERY
;
130 request
= dns_make_query(name
, dnsclass
, dnstype
, do_search
);
131 if (request
== NULL
) return NO_RECOVERY
;
133 status
= LI_async_start(p
, proc
, request
, (void *)callback
, context
);
136 if (status
!= 0) return NO_RECOVERY
;
141 dns_async_cancel(mach_port_t p
)
143 LI_async_call_cancel(p
, NULL
);
147 dns_async_send(mach_port_t
*p
, const char *name
, uint16_t dnsclass
, uint16_t dnstype
, uint32_t do_search
)
149 return dns_async_start(p
, name
, dnsclass
, dnstype
, do_search
, NULL
, NULL
);
153 dns_extract_data(kvarray_t
*in
, char **buf
, uint32_t *len
, struct sockaddr
**from
, uint32_t *fromlen
)
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
;
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;
176 if (d
>= in
->count
) return -1;
178 kcount
= in
->dict
[d
].kcount
;
180 for (k
= 0; k
< kcount
; k
++)
182 if (!strcmp(in
->dict
[d
].key
[k
], "data"))
184 if (in
->dict
[d
].vcount
[k
] == 0) continue;
185 if (*buf
!= NULL
) continue;
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().
192 *len
= kvbuf_get_len(in
->dict
[d
].val
[k
][0]);
193 if (*len
== 0) continue;
196 if (*buf
== NULL
) return -1;
198 memcpy(*buf
, in
->dict
[d
].val
[k
][0], *len
);
200 else if (!strcmp(in
->dict
[d
].key
[k
], "server"))
202 if (in
->dict
[d
].vcount
[k
] == 0) continue;
203 if (*from
!= NULL
) continue;
205 memset(&addr4
, 0, sizeof(struct in_addr
));
206 memset(&sin4
, 0, sizeof(struct sockaddr_in
));
208 memset(&addr6
, 0, sizeof(struct in6_addr
));
209 memset(&sin6
, 0, sizeof(struct sockaddr_in6
));
211 status
= inet_pton(AF_INET6
, in
->dict
[d
].val
[k
][0], &addr6
);
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
;
222 status
= inet_pton(AF_INET
, in
->dict
[d
].val
[k
][0], &addr4
);
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
;
239 dns_async_receive(mach_port_t p
, char **buf
, uint32_t *len
, struct sockaddr
**from
, uint32_t *fromlen
)
241 kern_return_t status
;
246 status
= LI_async_receive(p
, &reply
);
247 if (status
!= 0) return NO_RECOVERY
;
248 if (reply
== NULL
) return HOST_NOT_FOUND
;
250 status
= dns_extract_data(reply
, buf
, len
, from
, fromlen
);
252 if (status
!= 0) return NO_RECOVERY
;
254 if (*buf
== NULL
) return NO_DATA
;
260 dns_async_handle_reply(void *msg
)
262 dns_async_callback callback
;
266 kern_return_t status
;
267 struct sockaddr
*from
;
268 uint32_t len
, fromlen
;
270 callback
= (dns_async_callback
)NULL
;
278 status
= LI_async_handle_reply(msg
, &reply
, (void **)&callback
, &context
);
279 if (status
!= KERN_SUCCESS
)
281 if (status
== MIG_REPLY_MISMATCH
) return 0;
282 callback(NO_RECOVERY
, NULL
, 0, NULL
, 0, context
);
286 status
= dns_extract_data(reply
, &buf
, &len
, &from
, &fromlen
);
290 callback(NO_RECOVERY
, NULL
, 0, NULL
, 0, context
);
296 callback(NO_DATA
, NULL
, 0, NULL
, 0, context
);
300 callback(0, buf
, len
, from
, fromlen
, context
);