]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/helper-stubs.c
mDNSResponder-541.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / helper-stubs.c
1 /*
2 * Copyright (c) 2007-2012 Apple Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <mach/mach.h>
18 #include <mach/mach_error.h>
19 #include <mach/vm_map.h>
20 #include <servers/bootstrap.h>
21 #include <IOKit/IOReturn.h>
22 #include <CoreFoundation/CoreFoundation.h>
23 #include "mDNSDebug.h"
24 #include "helper.h"
25 #include "helpermsg.h"
26 #include <dispatch/dispatch.h>
27 #include <arpa/inet.h>
28
29 //
30 // Implementation Notes about the HelperQueue:
31 //
32 // To prevent blocking the main queue, all communications with mDNSResponderHelper should happen on
33 // HelperQueue. There are a few calls which are still synchronous and needs to be handled separately
34 // case by case.
35 //
36 // When spawning off the work to the HelperQueue, any arguments that are pointers need to be copied
37 // explicitly as they may cease to exist after the call returns. From within the block that is scheduled,
38 // arrays defined on the stack can't be referenced and hence it is enclosed them in a struct. If the array is
39 // an argument to the function, the blocks can reference them as they are passed in as pointers. But care should
40 // be taken to copy them locally as they may cease to exist when the function returns.
41 //
42 static dispatch_queue_t HelperQueue;
43
44 #define ERROR(x, y) y,
45 static const char *errorstring[] =
46 {
47 #include "helper-error.h"
48 NULL
49 };
50 #undef ERROR
51
52 mDNSexport mStatus mDNSHelperInit()
53 {
54 HelperQueue = dispatch_queue_create("com.apple.mDNSResponder.HelperQueue", NULL);
55 if (HelperQueue == NULL)
56 {
57 LogMsg("dispatch_queue_create: Helper queue NULL");
58 return mStatus_NoMemoryErr;
59 }
60 return mStatus_NoError;
61 }
62
63 static mach_port_t getHelperPort(int retry)
64 {
65 static mach_port_t port = MACH_PORT_NULL;
66 if (retry) port = MACH_PORT_NULL;
67 if (port == MACH_PORT_NULL && BOOTSTRAP_SUCCESS != bootstrap_look_up(bootstrap_port, kmDNSHelperServiceName, &port))
68 LogMsg("%s: cannot contact helper", __func__);
69 return port;
70 }
71
72 const char *mDNSHelperError(int err)
73 {
74 static const char *p = "<unknown error>";
75 if (mDNSHelperErrorBase < err && mDNSHelperErrorEnd > err)
76 p = errorstring[err - mDNSHelperErrorBase - 1];
77 return p;
78 }
79
80 /* Ugly but handy. */
81 // We don't bother reporting kIOReturnNotReady because that error code occurs in "normal" operation
82 // and doesn't indicate anything unexpected that needs to be investigated
83
84 #define MACHRETRYLOOP_BEGIN(kr, retry, err, fin) \
85 for (;;) \
86 {
87 #define MACHRETRYLOOP_END(kr, retry, err, fin) \
88 if (KERN_SUCCESS == (kr)) break; \
89 else if (MACH_SEND_INVALID_DEST == (kr) && 0 == (retry)++) continue; \
90 else \
91 { \
92 (err) = kmDNSHelperCommunicationFailed; \
93 LogMsg("%s: Mach communication failed: %d %X %s", __func__, kr, kr, mach_error_string(kr)); \
94 goto fin; \
95 } \
96 } \
97 if (0 != (err) && kIOReturnNotReady != (err)) \
98 { LogMsg("%s: %d 0x%X (%s)", __func__, (err), (err), mDNSHelperError(err)); goto fin; }
99
100 void mDNSPreferencesSetName(int key, domainlabel *old, domainlabel *new)
101 {
102 struct {
103 char oldname[MAX_DOMAIN_LABEL+1];
104 char newname[MAX_DOMAIN_LABEL+1];
105 } names;
106
107 mDNSPlatformMemZero(names.oldname, MAX_DOMAIN_LABEL + 1);
108 mDNSPlatformMemZero(names.newname, MAX_DOMAIN_LABEL + 1);
109
110 ConvertDomainLabelToCString_unescaped(old, names.oldname);
111 if (new) ConvertDomainLabelToCString_unescaped(new, names.newname);
112 dispatch_async(HelperQueue, ^{
113
114 kern_return_t kr = KERN_FAILURE;
115 int retry = 0;
116 int err = 0;
117
118 LogInfo("%s: oldname %s newname %s", __func__, names.oldname, names.newname);
119 MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
120 kr = proxy_mDNSPreferencesSetName(getHelperPort(retry), key, names.oldname, names.newname);
121 MACHRETRYLOOP_END(kr, retry, err, fin);
122
123 fin:
124 (void)err;
125 });
126 }
127
128 void mDNSRequestBPF(void)
129 {
130 dispatch_async(HelperQueue, ^{
131
132 kern_return_t kr = KERN_FAILURE;
133 int retry = 0, err = 0;
134 LogInfo("%s: BPF", __func__);
135 MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
136 kr = proxy_mDNSRequestBPF(getHelperPort(retry));
137 MACHRETRYLOOP_END(kr, retry, err, fin);
138 fin:
139 (void)err;
140 });
141 }
142
143 int mDNSPowerRequest(int key, int interval)
144 {
145 kern_return_t kr = KERN_FAILURE;
146 int retry = 0, err = 0;
147 MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
148 kr = proxy_mDNSPowerRequest(getHelperPort(retry), key, interval, &err);
149 MACHRETRYLOOP_END(kr, retry, err, fin);
150 fin:
151 return err;
152 }
153
154 int mDNSSetLocalAddressCacheEntry(int ifindex, int family, const v6addr_t ip, const ethaddr_t eth)
155 {
156 kern_return_t kr = KERN_FAILURE;
157 int retry = 0, err = 0;
158 MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
159 kr = proxy_mDNSSetLocalAddressCacheEntry(getHelperPort(retry), ifindex, family, (uint8_t*)ip, (uint8_t*)eth, &err);
160 MACHRETRYLOOP_END(kr, retry, err, fin);
161 fin:
162 return err;
163 }
164
165 void mDNSNotify(const char *title, const char *msg) // Both strings are UTF-8 text
166 {
167 char *titleCopy = NULL;
168 char *msgCopy = NULL;
169
170 if (title)
171 {
172 int len = strlen(title);
173 titleCopy = mDNSPlatformMemAllocate(len + 1);
174 if (!titleCopy)
175 {
176 LogMsg("mDNSNotify: titleCopy NULL for %s", msg);
177 return;
178 }
179 mDNSPlatformMemCopy(titleCopy, title, len);
180 titleCopy[len] = 0;
181 }
182 if (msg)
183 {
184 int len = strlen(msg);
185 msgCopy = mDNSPlatformMemAllocate(len + 1);
186 if (!msgCopy)
187 {
188 LogMsg("mDNSNotify: msgCopy NULL for %s", msg);
189 return;
190 }
191 mDNSPlatformMemCopy(msgCopy, msg, len);
192 msgCopy[len] = 0;
193 }
194
195 dispatch_async(HelperQueue, ^{
196
197 kern_return_t kr = KERN_FAILURE;
198 int retry = 0, err = 0;
199
200 LogInfo("%s: title %s, msg %s", __func__, titleCopy, msgCopy);
201
202 MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
203 kr = proxy_mDNSNotify(getHelperPort(retry), titleCopy, msgCopy);
204 MACHRETRYLOOP_END(kr, retry, err, fin);
205 fin:
206 if (titleCopy)
207 mDNSPlatformMemFree(titleCopy);
208 if (msgCopy)
209 mDNSPlatformMemFree(msgCopy);
210 (void)err;
211 });
212 }
213
214 int mDNSKeychainGetSecrets(CFArrayRef *result)
215 {
216 CFPropertyListRef plist = NULL;
217 CFDataRef bytes = NULL;
218 kern_return_t kr = KERN_FAILURE;
219 unsigned int numsecrets = 0;
220 vm_offset_t secrets = 0;
221 mach_msg_type_number_t secretsCnt = 0;
222 int retry = 0, err = 0;
223
224 MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
225 kr = proxy_mDNSKeychainGetSecrets(getHelperPort(retry), &numsecrets, &secrets, &secretsCnt, &err);
226 MACHRETRYLOOP_END(kr, retry, err, fin);
227
228 if (NULL == (bytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (void*)secrets, secretsCnt, kCFAllocatorNull)))
229 {
230 err = kmDNSHelperCreationFailed;
231 LogMsg("%s: CFDataCreateWithBytesNoCopy failed", __func__);
232 goto fin;
233 }
234 if (NULL == (plist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, bytes, kCFPropertyListImmutable, NULL)))
235 {
236 err = kmDNSHelperInvalidPList;
237 LogMsg("%s: CFPropertyListCreateFromXMLData failed", __func__);
238 goto fin;
239 }
240 if (CFArrayGetTypeID() != CFGetTypeID(plist))
241 {
242 err = kmDNSHelperTypeError;
243 LogMsg("%s: Unexpected result type", __func__);
244 CFRelease(plist);
245 plist = NULL;
246 goto fin;
247 }
248 *result = (CFArrayRef)plist;
249
250 fin:
251 if (bytes) CFRelease(bytes);
252 if (secrets) vm_deallocate(mach_task_self(), secrets, secretsCnt);
253 return err;
254 }
255
256 void mDNSConfigureServer(int updown, const char *const prefix, const domainname *const fqdn)
257 {
258 struct
259 {
260 // Assume the prefix is no larger than 10 chars
261 char fqdnStr[MAX_ESCAPED_DOMAIN_NAME + 10];
262 } name;
263
264 mDNSPlatformMemZero(name.fqdnStr, MAX_DOMAIN_LABEL + 10);
265
266 if (fqdn)
267 {
268 mDNSPlatformStrCopy(name.fqdnStr, prefix);
269 ConvertDomainNameToCString(fqdn, name.fqdnStr + mDNSPlatformStrLen(prefix));
270 }
271
272 dispatch_async(HelperQueue, ^{
273
274 kern_return_t kr = KERN_SUCCESS;
275 int retry = 0, err = 0;
276
277 LogInfo("%s: fqdnStr %s", __func__, name.fqdnStr);
278
279 MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
280 kr = proxy_mDNSConfigureServer(getHelperPort(retry), updown, name.fqdnStr);
281 MACHRETRYLOOP_END(kr, retry, err, fin);
282 fin:
283 (void)err;
284
285 });
286 }
287
288 int mDNSAutoTunnelSetKeys(int replacedelete, v6addr_t local_inner,
289 v6addr_t local_outer, short local_port, v6addr_t remote_inner,
290 v6addr_t remote_outer, short remote_port, const char* const prefix, const domainname *const fqdn)
291 {
292 kern_return_t kr = KERN_SUCCESS;
293 int retry = 0, err = 0;
294 char fqdnStr[MAX_ESCAPED_DOMAIN_NAME + 10] = { 0 }; // Assume the prefix is no larger than 10 chars
295 if (fqdn)
296 {
297 mDNSPlatformStrCopy(fqdnStr, prefix);
298 ConvertDomainNameToCString(fqdn, fqdnStr + mDNSPlatformStrLen(prefix));
299 }
300 MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
301 kr = proxy_mDNSAutoTunnelSetKeys(getHelperPort(retry), replacedelete, local_inner, local_outer, local_port, remote_inner, remote_outer, remote_port, fqdnStr, &err);
302 MACHRETRYLOOP_END(kr, retry, err, fin);
303 fin:
304 return err;
305 }
306
307 void mDNSSendWakeupPacket(unsigned ifid, char *eth_addr, char *ip_addr, int iteration)
308 {
309 char *ip_addr_copy = NULL;
310 char *eth_addr_copy = NULL;
311
312 if (eth_addr)
313 {
314 int len = strlen(eth_addr);
315 eth_addr_copy = mDNSPlatformMemAllocate(len + 1);
316 if (!eth_addr_copy)
317 {
318 LogMsg("mDNSSendWakeupPacket: eth_addr_copy NULL for %s", eth_addr);
319 return;
320 }
321 mDNSPlatformMemCopy(eth_addr_copy, eth_addr, len);
322 eth_addr_copy[len] = 0;
323 }
324 if (ip_addr)
325 {
326 int len = strlen(ip_addr);
327 ip_addr_copy = mDNSPlatformMemAllocate(len + 1);
328 if (!ip_addr_copy)
329 {
330 LogMsg("mDNSSendWakeupPacket: ip_addr_copy NULL for %s", ip_addr);
331 return;
332 }
333 mDNSPlatformMemCopy(ip_addr_copy, ip_addr, len);
334 ip_addr_copy[len] = 0;
335 }
336 dispatch_async(HelperQueue, ^{
337
338 kern_return_t kr = KERN_SUCCESS;
339 int retry = 0, err = 0;
340
341 LogInfo("%s: Entered ethernet address %s, ip address %s", __func__, eth_addr_copy, ip_addr_copy);
342
343 MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
344 kr = proxy_mDNSSendWakeupPacket(getHelperPort(retry), ifid, eth_addr_copy, ip_addr_copy, iteration);
345 MACHRETRYLOOP_END(kr, retry, err, fin);
346 fin:
347 if (eth_addr_copy)
348 mDNSPlatformMemFree(eth_addr_copy);
349 if (ip_addr_copy)
350 mDNSPlatformMemFree(ip_addr_copy);
351 (void) err;
352 });
353 }
354
355 void mDNSPacketFilterControl(uint32_t command, char * ifname, uint32_t count, pfArray_t portArray, pfArray_t protocolArray)
356 {
357 struct
358 {
359 pfArray_t portArray;
360 pfArray_t protocolArray;
361 } pfa;
362 char *ifnameCopy = NULL;
363
364 mDNSPlatformMemCopy(pfa.portArray, portArray, sizeof(pfArray_t));
365 mDNSPlatformMemCopy(pfa.protocolArray, protocolArray, sizeof(pfArray_t));
366 if (ifname)
367 {
368 int len = strlen(ifname);
369 ifnameCopy = mDNSPlatformMemAllocate(len + 1);
370 if (!ifnameCopy)
371 {
372 LogMsg("mDNSPacketFilterControl: ifnameCopy NULL");
373 return;
374 }
375 mDNSPlatformMemCopy(ifnameCopy, ifname, len);
376 ifnameCopy[len] = 0;
377 }
378 dispatch_async(HelperQueue, ^{
379
380 kern_return_t kr = KERN_SUCCESS;
381 int retry = 0, err = 0;
382
383 LogInfo("%s, ifname %s", __func__, ifnameCopy);
384
385 MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
386 kr = proxy_mDNSPacketFilterControl(getHelperPort(retry), command, ifnameCopy, count, (uint16_t *)pfa.portArray, (uint16_t *)pfa.protocolArray);
387 MACHRETRYLOOP_END(kr, retry, err, fin);
388 fin:
389 if (ifnameCopy)
390 mDNSPlatformMemFree(ifnameCopy);
391 (void) err;
392 });
393 }
394
395 void mDNSSendKeepalive(v6addr_t sadd, v6addr_t dadd, uint16_t lport, uint16_t rport, unsigned seq, unsigned ack, uint16_t win)
396 {
397 struct
398 {
399 v6addr_t sadd;
400 v6addr_t dadd;
401 } addr;
402
403 mDNSPlatformMemCopy(addr.sadd, sadd, sizeof(v6addr_t));
404 mDNSPlatformMemCopy(addr.dadd, dadd, sizeof(v6addr_t));
405
406 dispatch_async(HelperQueue, ^{
407
408 kern_return_t kr = KERN_FAILURE;
409 int retry = 0, err = 0;
410 char buf1[INET6_ADDRSTRLEN];
411 char buf2[INET6_ADDRSTRLEN];
412
413 buf1[0] = 0;
414 buf2[0] = 0;
415
416 inet_ntop(AF_INET6, addr.sadd, buf1, sizeof(buf1));
417 inet_ntop(AF_INET6, addr.dadd, buf2, sizeof(buf2));
418 LogInfo("%s: sadd is %s, dadd is %s", __func__, buf1, buf2);
419
420 MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
421 kr = proxy_mDNSSendKeepalive(getHelperPort(retry), (uint8_t *)addr.sadd, (uint8_t *)addr.dadd, lport, rport, seq, ack, win);
422 MACHRETRYLOOP_END(kr, retry, err, fin);
423 fin:
424 (void) err;
425 });
426 }
427
428 int mDNSRetrieveTCPInfo(int family, v6addr_t laddr, uint16_t lport, v6addr_t raddr, uint16_t rport, uint32_t *seq, uint32_t *ack, uint16_t *win, int32_t *intfid)
429 {
430 kern_return_t kr = KERN_FAILURE;
431 int retry = 0, err = 0;
432 MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
433 kr = proxy_mDNSRetrieveTCPInfo(getHelperPort(retry), family, (uint8_t *)laddr, lport, (uint8_t *)raddr, rport, seq, ack, win, intfid);
434 MACHRETRYLOOP_END(kr, retry, err, fin);
435 fin:
436 return err;
437 }
438
439 void mDNSGetRemoteMAC(mDNS *const m, int family, v6addr_t raddr)
440 {
441 struct {
442 v6addr_t addr;
443 } dst;
444
445 mDNSPlatformMemCopy(dst.addr, raddr, sizeof(v6addr_t));
446 dispatch_async(HelperQueue, ^{
447 kern_return_t kr = KERN_FAILURE;
448 int retry = 0, err = 0;
449 ethaddr_t eth;
450 IPAddressMACMapping *addrMapping;
451
452 MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
453 kr = proxy_mDNSGetRemoteMAC(getHelperPort(retry), family, (uint8_t *)dst.addr, eth);
454 MACHRETRYLOOP_END(kr, retry, err, fin);
455 // If the call to get the remote MAC address succeeds, allocate and copy
456 // the values and schedule a task to update the MAC address in the TCP Keepalive record.
457 if (kr == KERN_SUCCESS)
458 {
459 addrMapping = (IPAddressMACMapping *)malloc(sizeof(IPAddressMACMapping));
460 snprintf(addrMapping->ethaddr, sizeof(addrMapping->ethaddr), "%02x:%02x:%02x:%02x:%02x:%02x",
461 eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
462 if (family == AF_INET)
463 {
464 addrMapping->ipaddr.type = mDNSAddrType_IPv4;
465 mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v4.b, dst.addr, sizeof(v6addr_t));
466 }
467 else
468 {
469 addrMapping->ipaddr.type = mDNSAddrType_IPv6;
470 mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v6.b, dst.addr, sizeof(v6addr_t));
471 }
472 mDNSPlatformDispatchAsync(m, addrMapping, UpdateRMACCallback);
473 }
474 fin:
475 (void) err;
476 });
477
478 }
479
480 void mDNSStoreSPSMACAddress(int family, v6addr_t spsaddr, char *ifname)
481 {
482 struct {
483 v6addr_t saddr;
484 } addr;
485 mDNSPlatformMemCopy(addr.saddr, spsaddr, sizeof(v6addr_t));
486
487 dispatch_async(HelperQueue, ^{
488 kern_return_t kr = KERN_FAILURE;
489 int retry = 0, err = 0;
490 MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
491 kr = proxy_mDNSStoreSPSMACAddress(getHelperPort(retry), family, (uint8_t *)addr.saddr, ifname);
492 MACHRETRYLOOP_END(kr, retry, err, fin);
493 fin:
494 (void)err;
495 });
496 }