2 * Copyright (c) 2007-2012 Apple Inc. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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"
25 #include "helpermsg.h"
26 #include <dispatch/dispatch.h>
27 #include <arpa/inet.h>
30 // Implementation Notes about the HelperQueue:
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
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.
42 static dispatch_queue_t HelperQueue
;
44 #define ERROR(x, y) y,
45 static const char *errorstring
[] =
47 #include "helper-error.h"
52 mDNSexport mStatus
mDNSHelperInit()
54 HelperQueue
= dispatch_queue_create("com.apple.mDNSResponder.HelperQueue", NULL
);
55 if (HelperQueue
== NULL
)
57 LogMsg("dispatch_queue_create: Helper queue NULL");
58 return mStatus_NoMemoryErr
;
60 return mStatus_NoError
;
63 static mach_port_t
getHelperPort(int retry
)
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__
);
72 const char *mDNSHelperError(int err
)
74 static const char *p
= "<unknown error>";
75 if (mDNSHelperErrorBase
< err
&& mDNSHelperErrorEnd
> err
)
76 p
= errorstring
[err
- mDNSHelperErrorBase
- 1];
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
84 #define MACHRETRYLOOP_BEGIN(kr, retry, err, fin) \
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; \
92 (err) = kmDNSHelperCommunicationFailed; \
93 LogMsg("%s: Mach communication failed: %d %X %s", __func__, kr, kr, mach_error_string(kr)); \
97 if (0 != (err) && kIOReturnNotReady != (err)) \
98 { LogMsg("%s: %d 0x%X (%s)", __func__, (err), (err), mDNSHelperError(err)); goto fin; }
100 void mDNSPreferencesSetName(int key
, domainlabel
*old
, domainlabel
*new)
103 char oldname
[MAX_DOMAIN_LABEL
+1];
104 char newname
[MAX_DOMAIN_LABEL
+1];
107 mDNSPlatformMemZero(names
.oldname
, MAX_DOMAIN_LABEL
+ 1);
108 mDNSPlatformMemZero(names
.newname
, MAX_DOMAIN_LABEL
+ 1);
110 ConvertDomainLabelToCString_unescaped(old
, names
.oldname
);
111 if (new) ConvertDomainLabelToCString_unescaped(new, names
.newname
);
112 dispatch_async(HelperQueue
, ^{
114 kern_return_t kr
= KERN_FAILURE
;
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
);
128 void mDNSRequestBPF(void)
130 dispatch_async(HelperQueue
, ^{
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
);
143 int mDNSPowerRequest(int key
, int interval
)
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
);
154 int mDNSSetLocalAddressCacheEntry(int ifindex
, int family
, const v6addr_t ip
, const ethaddr_t eth
)
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
);
165 void mDNSNotify(const char *title
, const char *msg
) // Both strings are UTF-8 text
167 char *titleCopy
= NULL
;
168 char *msgCopy
= NULL
;
172 int len
= strlen(title
);
173 titleCopy
= mDNSPlatformMemAllocate(len
+ 1);
176 LogMsg("mDNSNotify: titleCopy NULL for %s", msg
);
179 mDNSPlatformMemCopy(titleCopy
, title
, len
);
184 int len
= strlen(msg
);
185 msgCopy
= mDNSPlatformMemAllocate(len
+ 1);
188 LogMsg("mDNSNotify: msgCopy NULL for %s", msg
);
191 mDNSPlatformMemCopy(msgCopy
, msg
, len
);
195 dispatch_async(HelperQueue
, ^{
197 kern_return_t kr
= KERN_FAILURE
;
198 int retry
= 0, err
= 0;
200 LogInfo("%s: title %s, msg %s", __func__
, titleCopy
, msgCopy
);
202 MACHRETRYLOOP_BEGIN(kr
, retry
, err
, fin
);
203 kr
= proxy_mDNSNotify(getHelperPort(retry
), titleCopy
, msgCopy
);
204 MACHRETRYLOOP_END(kr
, retry
, err
, fin
);
207 mDNSPlatformMemFree(titleCopy
);
209 mDNSPlatformMemFree(msgCopy
);
214 int mDNSKeychainGetSecrets(CFArrayRef
*result
)
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;
224 MACHRETRYLOOP_BEGIN(kr
, retry
, err
, fin
);
225 kr
= proxy_mDNSKeychainGetSecrets(getHelperPort(retry
), &numsecrets
, &secrets
, &secretsCnt
, &err
);
226 MACHRETRYLOOP_END(kr
, retry
, err
, fin
);
228 if (NULL
== (bytes
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, (void*)secrets
, secretsCnt
, kCFAllocatorNull
)))
230 err
= kmDNSHelperCreationFailed
;
231 LogMsg("%s: CFDataCreateWithBytesNoCopy failed", __func__
);
234 if (NULL
== (plist
= CFPropertyListCreateFromXMLData(kCFAllocatorDefault
, bytes
, kCFPropertyListImmutable
, NULL
)))
236 err
= kmDNSHelperInvalidPList
;
237 LogMsg("%s: CFPropertyListCreateFromXMLData failed", __func__
);
240 if (CFArrayGetTypeID() != CFGetTypeID(plist
))
242 err
= kmDNSHelperTypeError
;
243 LogMsg("%s: Unexpected result type", __func__
);
248 *result
= (CFArrayRef
)plist
;
251 if (bytes
) CFRelease(bytes
);
252 if (secrets
) vm_deallocate(mach_task_self(), secrets
, secretsCnt
);
256 void mDNSConfigureServer(int updown
, const char *const prefix
, const domainname
*const fqdn
)
260 // Assume the prefix is no larger than 10 chars
261 char fqdnStr
[MAX_ESCAPED_DOMAIN_NAME
+ 10];
264 mDNSPlatformMemZero(name
.fqdnStr
, MAX_DOMAIN_LABEL
+ 10);
268 mDNSPlatformStrCopy(name
.fqdnStr
, prefix
);
269 ConvertDomainNameToCString(fqdn
, name
.fqdnStr
+ mDNSPlatformStrLen(prefix
));
272 dispatch_async(HelperQueue
, ^{
274 kern_return_t kr
= KERN_SUCCESS
;
275 int retry
= 0, err
= 0;
277 LogInfo("%s: fqdnStr %s", __func__
, name
.fqdnStr
);
279 MACHRETRYLOOP_BEGIN(kr
, retry
, err
, fin
);
280 kr
= proxy_mDNSConfigureServer(getHelperPort(retry
), updown
, name
.fqdnStr
);
281 MACHRETRYLOOP_END(kr
, retry
, err
, fin
);
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
)
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
297 mDNSPlatformStrCopy(fqdnStr
, prefix
);
298 ConvertDomainNameToCString(fqdn
, fqdnStr
+ mDNSPlatformStrLen(prefix
));
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
);
307 void mDNSSendWakeupPacket(unsigned ifid
, char *eth_addr
, char *ip_addr
, int iteration
)
309 char *ip_addr_copy
= NULL
;
310 char *eth_addr_copy
= NULL
;
314 int len
= strlen(eth_addr
);
315 eth_addr_copy
= mDNSPlatformMemAllocate(len
+ 1);
318 LogMsg("mDNSSendWakeupPacket: eth_addr_copy NULL for %s", eth_addr
);
321 mDNSPlatformMemCopy(eth_addr_copy
, eth_addr
, len
);
322 eth_addr_copy
[len
] = 0;
326 int len
= strlen(ip_addr
);
327 ip_addr_copy
= mDNSPlatformMemAllocate(len
+ 1);
330 LogMsg("mDNSSendWakeupPacket: ip_addr_copy NULL for %s", ip_addr
);
333 mDNSPlatformMemCopy(ip_addr_copy
, ip_addr
, len
);
334 ip_addr_copy
[len
] = 0;
336 dispatch_async(HelperQueue
, ^{
338 kern_return_t kr
= KERN_SUCCESS
;
339 int retry
= 0, err
= 0;
341 LogInfo("%s: Entered ethernet address %s, ip address %s", __func__
, eth_addr_copy
, ip_addr_copy
);
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
);
348 mDNSPlatformMemFree(eth_addr_copy
);
350 mDNSPlatformMemFree(ip_addr_copy
);
355 void mDNSPacketFilterControl(uint32_t command
, char * ifname
, uint32_t count
, pfArray_t portArray
, pfArray_t protocolArray
)
360 pfArray_t protocolArray
;
362 char *ifnameCopy
= NULL
;
364 mDNSPlatformMemCopy(pfa
.portArray
, portArray
, sizeof(pfArray_t
));
365 mDNSPlatformMemCopy(pfa
.protocolArray
, protocolArray
, sizeof(pfArray_t
));
368 int len
= strlen(ifname
);
369 ifnameCopy
= mDNSPlatformMemAllocate(len
+ 1);
372 LogMsg("mDNSPacketFilterControl: ifnameCopy NULL");
375 mDNSPlatformMemCopy(ifnameCopy
, ifname
, len
);
378 dispatch_async(HelperQueue
, ^{
380 kern_return_t kr
= KERN_SUCCESS
;
381 int retry
= 0, err
= 0;
383 LogInfo("%s, ifname %s", __func__
, ifnameCopy
);
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
);
390 mDNSPlatformMemFree(ifnameCopy
);
395 void mDNSSendKeepalive(v6addr_t sadd
, v6addr_t dadd
, uint16_t lport
, uint16_t rport
, unsigned seq
, unsigned ack
, uint16_t win
)
403 mDNSPlatformMemCopy(addr
.sadd
, sadd
, sizeof(v6addr_t
));
404 mDNSPlatformMemCopy(addr
.dadd
, dadd
, sizeof(v6addr_t
));
406 dispatch_async(HelperQueue
, ^{
408 kern_return_t kr
= KERN_FAILURE
;
409 int retry
= 0, err
= 0;
410 char buf1
[INET6_ADDRSTRLEN
];
411 char buf2
[INET6_ADDRSTRLEN
];
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
);
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
);
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
)
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
);
439 void mDNSGetRemoteMAC(mDNS
*const m
, int family
, v6addr_t raddr
)
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;
450 IPAddressMACMapping
*addrMapping
;
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
)
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
)
464 addrMapping
->ipaddr
.type
= mDNSAddrType_IPv4
;
465 mDNSPlatformMemCopy(addrMapping
->ipaddr
.ip
.v4
.b
, dst
.addr
, sizeof(v6addr_t
));
469 addrMapping
->ipaddr
.type
= mDNSAddrType_IPv6
;
470 mDNSPlatformMemCopy(addrMapping
->ipaddr
.ip
.v6
.b
, dst
.addr
, sizeof(v6addr_t
));
472 mDNSPlatformDispatchAsync(m
, addrMapping
, UpdateRMACCallback
);
480 void mDNSStoreSPSMACAddress(int family
, v6addr_t spsaddr
, char *ifname
)
485 mDNSPlatformMemCopy(addr
.saddr
, spsaddr
, sizeof(v6addr_t
));
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
);