/* * Copyright (c) 2007 Apple Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include "mDNSDebug.h" #include "helper.h" #include "helpermsg.h" #define ERROR(x, y) y, static const char *errorstring[] = { #include "helper-error.h" NULL }; #undef ERROR static mach_port_t getHelperPort(int retry) { static mach_port_t port = MACH_PORT_NULL; if (retry) port = MACH_PORT_NULL; if (port == MACH_PORT_NULL && BOOTSTRAP_SUCCESS != bootstrap_look_up(bootstrap_port, kmDNSHelperServiceName, &port)) LogMsg("%s: cannot contact helper", __func__); return port; } const char *mDNSHelperError(int err) { static const char *p = ""; if (mDNSHelperErrorBase < err && mDNSHelperErrorEnd > err) p = errorstring[err - mDNSHelperErrorBase - 1]; return p; } /* Ugly but handy. */ // We don't bother reporting kIOReturnNotReady because that error code occurs in "normal" operation // and doesn't indicate anything unexpected that needs to be investigated #define MACHRETRYLOOP_BEGIN(kr, retry, err, fin) \ for (;;) \ { #define MACHRETRYLOOP_END(kr, retry, err, fin) \ if (KERN_SUCCESS == (kr)) break; \ else if (MACH_SEND_INVALID_DEST == (kr) && 0 == (retry)++) continue; \ else \ { \ (err) = kmDNSHelperCommunicationFailed; \ LogMsg("%s: Mach communication failed: %d %X %s", __func__, kr, kr, mach_error_string(kr)); \ goto fin; \ } \ } \ if (0 != (err) && kIOReturnNotReady != (err)) \ { LogMsg("%s: %d 0x%X (%s)", __func__, (err), (err), mDNSHelperError(err)); goto fin; } void mDNSPreferencesSetName(int key, domainlabel *old, domainlabel *new) { kern_return_t kr = KERN_FAILURE; int retry = 0; int err = 0; char oldname[MAX_DOMAIN_LABEL+1] = {0}; char newname[MAX_DOMAIN_LABEL+1] = {0}; ConvertDomainLabelToCString_unescaped(old, oldname); if (new) ConvertDomainLabelToCString_unescaped(new, newname); MACHRETRYLOOP_BEGIN(kr, retry, err, fin); kr = proxy_mDNSPreferencesSetName(getHelperPort(retry), key, oldname, newname); MACHRETRYLOOP_END(kr, retry, err, fin); fin: (void)err; } void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropertyListRef value) { CFWriteStreamRef stream = NULL; CFDataRef bytes = NULL; kern_return_t kr = KERN_FAILURE; int retry = 0; int err = 0; if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL, NULL))) { err = kmDNSHelperCreationFailed; LogMsg("%s: CFWriteStreamCreateWithAllocatedBuffers failed", __func__); goto fin; } CFWriteStreamOpen(stream); if (0 == CFPropertyListWriteToStream(value, stream, kCFPropertyListBinaryFormat_v1_0, NULL)) { err = kmDNSHelperPListWriteFailed; LogMsg("%s: CFPropertyListWriteToStream failed", __func__); goto fin; } if (NULL == (bytes = CFWriteStreamCopyProperty(stream, kCFStreamPropertyDataWritten))) { err = kmDNSHelperCreationFailed; LogMsg("%s: CFWriteStreamCopyProperty failed", __func__); goto fin; } CFWriteStreamClose(stream); CFRelease(stream); stream = NULL; MACHRETRYLOOP_BEGIN(kr, retry, err, fin); kr = proxy_mDNSDynamicStoreSetConfig(getHelperPort(retry), key, subkey ? subkey : "", (vm_offset_t)CFDataGetBytePtr(bytes), CFDataGetLength(bytes)); MACHRETRYLOOP_END(kr, retry, err, fin); fin: if (NULL != stream) { CFWriteStreamClose(stream); CFRelease(stream); } if (NULL != bytes) CFRelease(bytes); (void)err; } void mDNSRequestBPF(void) { kern_return_t kr = KERN_FAILURE; int retry = 0, err = 0; MACHRETRYLOOP_BEGIN(kr, retry, err, fin); kr = proxy_mDNSRequestBPF(getHelperPort(retry)); MACHRETRYLOOP_END(kr, retry, err, fin); fin: (void)err; } int mDNSPowerRequest(int key, int interval) { kern_return_t kr = KERN_FAILURE; int retry = 0, err = 0; MACHRETRYLOOP_BEGIN(kr, retry, err, fin); kr = proxy_mDNSPowerRequest(getHelperPort(retry), key, interval, &err); MACHRETRYLOOP_END(kr, retry, err, fin); fin: return err; } int mDNSSetLocalAddressCacheEntry(int ifindex, int family, const v6addr_t ip, const ethaddr_t eth) { kern_return_t kr = KERN_FAILURE; int retry = 0, err = 0; MACHRETRYLOOP_BEGIN(kr, retry, err, fin); kr = proxy_mDNSSetLocalAddressCacheEntry(getHelperPort(retry), ifindex, family, (uint8_t*)ip, (uint8_t*)eth, &err); MACHRETRYLOOP_END(kr, retry, err, fin); fin: return err; } void mDNSNotify(const char *title, const char *msg) // Both strings are UTF-8 text { kern_return_t kr = KERN_FAILURE; int retry = 0, err = 0; MACHRETRYLOOP_BEGIN(kr, retry, err, fin); kr = proxy_mDNSNotify(getHelperPort(retry), title, msg); MACHRETRYLOOP_END(kr, retry, err, fin); fin: (void)err; } int mDNSKeychainGetSecrets(CFArrayRef *result) { CFPropertyListRef plist = NULL; CFDataRef bytes = NULL; kern_return_t kr = KERN_FAILURE; unsigned int numsecrets = 0; vm_offset_t secrets = 0; mach_msg_type_number_t secretsCnt = 0; int retry = 0, err = 0; MACHRETRYLOOP_BEGIN(kr, retry, err, fin); kr = proxy_mDNSKeychainGetSecrets(getHelperPort(retry), &numsecrets, &secrets, &secretsCnt, &err); MACHRETRYLOOP_END(kr, retry, err, fin); if (NULL == (bytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (void*)secrets, secretsCnt, kCFAllocatorNull))) { err = kmDNSHelperCreationFailed; LogMsg("%s: CFDataCreateWithBytesNoCopy failed", __func__); goto fin; } if (NULL == (plist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, bytes, kCFPropertyListImmutable, NULL))) { err = kmDNSHelperInvalidPList; LogMsg("%s: CFPropertyListCreateFromXMLData failed", __func__); goto fin; } if (CFArrayGetTypeID() != CFGetTypeID(plist)) { err = kmDNSHelperTypeError; LogMsg("%s: Unexpected result type", __func__); CFRelease(plist); plist = NULL; goto fin; } *result = (CFArrayRef)plist; fin: if (bytes) CFRelease(bytes); if (secrets) vm_deallocate(mach_task_self(), secrets, secretsCnt); return err; } void mDNSAutoTunnelInterfaceUpDown(int updown, v6addr_t address) { kern_return_t kr = KERN_SUCCESS; int retry = 0, err = 0; MACHRETRYLOOP_BEGIN(kr, retry, err, fin); kr = proxy_mDNSAutoTunnelInterfaceUpDown(getHelperPort(retry), updown, address); MACHRETRYLOOP_END(kr, retry, err, fin); fin: (void)err; } void mDNSConfigureServer(int updown, const domainname *const fqdn) { kern_return_t kr = KERN_SUCCESS; int retry = 0, err = 0; char fqdnStr[MAX_ESCAPED_DOMAIN_NAME] = { 0 }; if (fqdn && ConvertDomainNameToCString(fqdn, fqdnStr)) { // remove the trailing dot, as that is not used in the keychain entry racoon will lookup mDNSu32 fqdnEnd = mDNSPlatformStrLen(fqdnStr); if (fqdnEnd) fqdnStr[fqdnEnd - 1] = 0; } MACHRETRYLOOP_BEGIN(kr, retry, err, fin); kr = proxy_mDNSConfigureServer(getHelperPort(retry), updown, fqdnStr); MACHRETRYLOOP_END(kr, retry, err, fin); fin: (void)err; } int mDNSAutoTunnelSetKeys(int replacedelete, v6addr_t local_inner, v6addr_t local_outer, short local_port, v6addr_t remote_inner, v6addr_t remote_outer, short remote_port, const domainname *const fqdn) { kern_return_t kr = KERN_SUCCESS; int retry = 0, err = 0; char fqdnStr[MAX_ESCAPED_DOMAIN_NAME] = { 0 }; if (fqdn && ConvertDomainNameToCString(fqdn, fqdnStr)) { // remove the trailing dot, as that is not used in the keychain entry racoon will lookup mDNSu32 fqdnEnd = mDNSPlatformStrLen(fqdnStr); if (fqdnEnd) fqdnStr[fqdnEnd - 1] = 0; } MACHRETRYLOOP_BEGIN(kr, retry, err, fin); kr = proxy_mDNSAutoTunnelSetKeys(getHelperPort(retry), replacedelete, local_inner, local_outer, local_port, remote_inner, remote_outer, remote_port, fqdnStr, &err); MACHRETRYLOOP_END(kr, retry, err, fin); fin: return err; }