From f01edf10244ccd53e098abdc1773c1aa0e4c5f8d Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 19 Sep 2018 08:53:26 +0200 Subject: mDNSResponder: Update to v765.1.2 The sources can be obtained via: https://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-765.1.2.tar.gz Move mDNS_StartResolveService() and mDNS_StopResolveService() to an RTEMS-specific file (rtemsbsd/mdns/mDNSResolveService.c) using the v576.30.4 implementation. Apple removed these functions without explanation. Update #3522. --- mDNSResponder/Clients/ClientCommon.c | 3 +- mDNSResponder/Clients/Java/nmakefile | 2 +- mDNSResponder/Clients/dns-sd.c | 606 +++- mDNSResponder/Clients/dnsctl.c | 227 +- .../52D711AF-4055-4867-A494-7E31552BB9E1.png | Bin 0 -> 153759 bytes .../Screen Shot 2015-09-16 at 3.36.23 PM.png | Bin 0 -> 6231 bytes .../Screen Shot 2015-09-16 at 3.46.14 PM.png | Bin 0 -> 6910 bytes .../Attach mDNSResponder to Xcode.rtfd/TXT.rtf | 75 + .../Attach mDNSResponder to Xcode.rtfd/unknown.png | Bin 0 -> 55910 bytes .../A944EB40-AEFD-4CA1-BF10-E8F52835CA8C.png | Bin 0 -> 90282 bytes .../Screen Shot 2015-09-16 at 4.22.37 PM.png | Bin 0 -> 8498 bytes .../Start mDNSResponder in Xcode.rtfd/TXT.rtf | 57 + mDNSResponder/Makefile | 3 +- mDNSResponder/mDNSCore/DNSCommon.c | 59 +- mDNSResponder/mDNSCore/DNSCommon.h | 25 +- mDNSResponder/mDNSCore/anonymous.c | 7 +- mDNSResponder/mDNSCore/dnsproxy.c | 28 +- mDNSResponder/mDNSCore/dnssec.c | 7 +- mDNSResponder/mDNSCore/mDNS.c | 1826 ++++++----- mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h | 247 +- mDNSResponder/mDNSCore/nsec3.c | 4 +- mDNSResponder/mDNSCore/uDNS.c | 801 +++-- mDNSResponder/mDNSCore/uDNS.h | 14 +- mDNSResponder/mDNSMacOSX/BLE.c | 853 +++++ mDNSResponder/mDNSMacOSX/BLE.h | 54 + mDNSResponder/mDNSMacOSX/DNSProxySupport.c | 22 +- mDNSResponder/mDNSMacOSX/DNSSECSupport.c | 8 +- mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.c | 595 +--- mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.h | 180 +- .../mDNSMacOSX/DNSServiceDiscoveryDefines.h | 2 - .../mDNSMacOSX/DNSServiceDiscoveryReply.defs | 60 - .../mDNSMacOSX/DNSServiceDiscoveryRequest.defs | 80 - mDNSResponder/mDNSMacOSX/Metrics.h | 7 +- mDNSResponder/mDNSMacOSX/Metrics.m | 2051 ++++++++++-- mDNSResponder/mDNSMacOSX/P2PPacketFilter.c | 6 +- mDNSResponder/mDNSMacOSX/P2PPacketFilter.h | 3 +- .../PreferencePane/ConfigurationAuthority.c | 4 +- .../PreferencePane/DNSServiceDiscoveryPref.m | 4 +- .../PreferencePane/PrivilegedOperations.c | 10 +- .../Private/com.apple.mDNSResponder.plist | 19 + mDNSResponder/mDNSMacOSX/Private/dns_sd_private.h | 27 +- mDNSResponder/mDNSMacOSX/Private/dns_services.c | 49 +- mDNSResponder/mDNSMacOSX/Private/dns_services.h | 3 +- mDNSResponder/mDNSMacOSX/Private/dns_xpc.h | 30 +- mDNSResponder/mDNSMacOSX/Private/dnsctl_server.c | 224 ++ mDNSResponder/mDNSMacOSX/Private/xpc_services.c | 13 +- mDNSResponder/mDNSMacOSX/Private/xpc_services.h | 6 + mDNSResponder/mDNSMacOSX/SymptomReporter.c | 59 +- mDNSResponder/mDNSMacOSX/com.apple.dnsextd.plist | 2 - .../mDNSMacOSX/com.apple.mDNSResponder.plist | 10 +- .../mDNSMacOSX/com.apple.mDNSResponderHelper.plist | 2 +- .../mDNSMacOSX/com.apple.networking.mDNSResponder | 1 - mDNSResponder/mDNSMacOSX/coreBLE.h | 32 + mDNSResponder/mDNSMacOSX/coreBLE.m | 371 +++ mDNSResponder/mDNSMacOSX/daemon.c | 1972 ++---------- mDNSResponder/mDNSMacOSX/dnsctl-entitlements.plist | 2 + mDNSResponder/mDNSMacOSX/helper-error.h | 49 - mDNSResponder/mDNSMacOSX/helper-main.c | 586 +++- mDNSResponder/mDNSMacOSX/helper-server.h | 3 - mDNSResponder/mDNSMacOSX/helper-stubs.c | 823 +++-- mDNSResponder/mDNSMacOSX/helper.c | 3386 +++++++++----------- mDNSResponder/mDNSMacOSX/helper.h | 97 +- mDNSResponder/mDNSMacOSX/helpermsg-types.h | 2 +- mDNSResponder/mDNSMacOSX/helpermsg.defs | 143 - mDNSResponder/mDNSMacOSX/mDNSMacOSX.c | 1448 ++++++--- mDNSResponder/mDNSMacOSX/mDNSMacOSX.h | 8 +- .../mDNSMacOSX/mDNSResponder-entitlements.plist | 8 + mDNSResponder/mDNSMacOSX/mDNSResponder.sb | 14 +- .../mDNSResponder.xcodeproj/project.pbxproj | 1258 ++++++-- .../xcshareddata/xcschemes/Build All.xcscheme | 80 + .../xcshareddata/xcschemes/mDNSResponder.xcscheme | 101 + .../mDNSMacOSX/mDNSResponderLogging.mobileconfig | 57 - mDNSResponder/mDNSMacOSX/uDNSPathEvalulation.c | 10 +- mDNSResponder/mDNSPosix/._ReadMe.txt | Bin 171 -> 0 bytes mDNSResponder/mDNSPosix/Makefile | 11 +- mDNSResponder/mDNSPosix/ReadMe.txt | 14 - mDNSResponder/mDNSPosix/mDNSPosix.c | 72 +- mDNSResponder/mDNSPosix/mdnsd.sh | 2 +- mDNSResponder/mDNSPosix/nss_mdns.c | 4 + mDNSResponder/mDNSShared/PlatformCommon.c | 13 + mDNSResponder/mDNSShared/dns_sd.h | 154 +- mDNSResponder/mDNSShared/dnssd_clientshim.c | 2 +- mDNSResponder/mDNSShared/dnssd_clientstub.c | 98 +- mDNSResponder/mDNSShared/dnssd_ipc.h | 2 - mDNSResponder/mDNSShared/uds_daemon.c | 683 ++-- mDNSResponder/mDNSShared/uds_daemon.h | 19 +- .../ControlPanel/ConfigPropertySheet.cpp | 4 +- .../mDNSWindows/ControlPanel/ControlPanelExe.cpp | 9 +- .../mDNSWindows/ControlPanel/FourthPage.cpp | 2 +- mDNSResponder/mDNSWindows/DLLStub/DLLStub.cpp | 4 +- mDNSResponder/mDNSWindows/DLLX/DNSSD.cpp | 2 +- .../Windows/Sources/ChooserDialog.cpp | 12 +- .../WindowsCE/Sources/BrowserDialog.cpp | 2 +- mDNSResponder/mDNSWindows/Java/makefile | 2 +- mDNSResponder/mDNSWindows/Java/makefile64 | 2 +- mDNSResponder/mDNSWindows/NSPTool/NSPTool.c | 8 +- mDNSResponder/mDNSWindows/SystemService/Service.c | 2 +- mDNSResponder/mDNSWindows/mDNSWin32.c | 195 +- mDNSResponder/mDNSWindows/mdnsNSP/mdnsNSP.c | 13 +- mDNSResponder/unittests/DNSMessageTest.c | 50 + mDNSResponder/unittests/DNSMessageTest.h | 8 + mDNSResponder/unittests/DomainNameTest.c | 28 + mDNSResponder/unittests/DomainNameTest.h | 7 + mDNSResponder/unittests/InterfaceTest.c | 19 + mDNSResponder/unittests/InterfaceTest.h | 9 + mDNSResponder/unittests/ResourceRecordTest.c | 60 + mDNSResponder/unittests/ResourceRecordTest.h | 10 + mDNSResponder/unittests/main.c | 33 + mDNSResponder/unittests/unittest.c | 105 + mDNSResponder/unittests/unittest.h | 84 + 110 files changed, 12109 insertions(+), 8460 deletions(-) create mode 100644 mDNSResponder/Documents/Attach mDNSResponder to Xcode.rtfd/52D711AF-4055-4867-A494-7E31552BB9E1.png create mode 100644 mDNSResponder/Documents/Attach mDNSResponder to Xcode.rtfd/Screen Shot 2015-09-16 at 3.36.23 PM.png create mode 100644 mDNSResponder/Documents/Attach mDNSResponder to Xcode.rtfd/Screen Shot 2015-09-16 at 3.46.14 PM.png create mode 100644 mDNSResponder/Documents/Attach mDNSResponder to Xcode.rtfd/TXT.rtf create mode 100644 mDNSResponder/Documents/Attach mDNSResponder to Xcode.rtfd/unknown.png create mode 100644 mDNSResponder/Documents/Start mDNSResponder in Xcode.rtfd/A944EB40-AEFD-4CA1-BF10-E8F52835CA8C.png create mode 100644 mDNSResponder/Documents/Start mDNSResponder in Xcode.rtfd/Screen Shot 2015-09-16 at 4.22.37 PM.png create mode 100644 mDNSResponder/Documents/Start mDNSResponder in Xcode.rtfd/TXT.rtf create mode 100644 mDNSResponder/mDNSMacOSX/BLE.c create mode 100644 mDNSResponder/mDNSMacOSX/BLE.h delete mode 100644 mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryReply.defs delete mode 100644 mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryRequest.defs create mode 100644 mDNSResponder/mDNSMacOSX/Private/com.apple.mDNSResponder.plist create mode 100644 mDNSResponder/mDNSMacOSX/Private/dnsctl_server.c delete mode 100644 mDNSResponder/mDNSMacOSX/com.apple.networking.mDNSResponder create mode 100644 mDNSResponder/mDNSMacOSX/coreBLE.h create mode 100644 mDNSResponder/mDNSMacOSX/coreBLE.m delete mode 100644 mDNSResponder/mDNSMacOSX/helper-error.h delete mode 100644 mDNSResponder/mDNSMacOSX/helpermsg.defs create mode 100644 mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/xcshareddata/xcschemes/Build All.xcscheme create mode 100644 mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/xcshareddata/xcschemes/mDNSResponder.xcscheme delete mode 100644 mDNSResponder/mDNSMacOSX/mDNSResponderLogging.mobileconfig delete mode 100755 mDNSResponder/mDNSPosix/._ReadMe.txt create mode 100644 mDNSResponder/unittests/DNSMessageTest.c create mode 100644 mDNSResponder/unittests/DNSMessageTest.h create mode 100644 mDNSResponder/unittests/DomainNameTest.c create mode 100644 mDNSResponder/unittests/DomainNameTest.h create mode 100644 mDNSResponder/unittests/InterfaceTest.c create mode 100644 mDNSResponder/unittests/InterfaceTest.h create mode 100644 mDNSResponder/unittests/ResourceRecordTest.c create mode 100644 mDNSResponder/unittests/ResourceRecordTest.h create mode 100644 mDNSResponder/unittests/main.c create mode 100644 mDNSResponder/unittests/unittest.c create mode 100644 mDNSResponder/unittests/unittest.h (limited to 'mDNSResponder') diff --git a/mDNSResponder/Clients/ClientCommon.c b/mDNSResponder/Clients/ClientCommon.c index cb59e7b9..f96319ce 100644 --- a/mDNSResponder/Clients/ClientCommon.c +++ b/mDNSResponder/Clients/ClientCommon.c @@ -49,8 +49,9 @@ const char *GetNextLabel(const char *cstr, char label[64]) while (*cstr && *cstr != '.') // While we have characters in the label... { char c = *cstr++; - if (c == '\\' && *cstr) // If we have a backslash, and it's not the last character of the string + if (c == '\\') // If escape character, check next character { + if (*cstr == '\0') break; // If this is the end of the string, then break c = *cstr++; if (isdigit(cstr[-1]) && isdigit(cstr[0]) && isdigit(cstr[1])) { diff --git a/mDNSResponder/Clients/Java/nmakefile b/mDNSResponder/Clients/Java/nmakefile index 89168e0b..1758f7a4 100644 --- a/mDNSResponder/Clients/Java/nmakefile +++ b/mDNSResponder/Clients/Java/nmakefile @@ -29,7 +29,7 @@ ############################################################################ -JDK = $(JAVA_HOME) +JDK = "$(JAVA_HOME)" CP = copy RM = del /Q diff --git a/mDNSResponder/Clients/dns-sd.c b/mDNSResponder/Clients/dns-sd.c index 9469d24d..f36211e5 100644 --- a/mDNSResponder/Clients/dns-sd.c +++ b/mDNSResponder/Clients/dns-sd.c @@ -320,18 +320,70 @@ static char *DNSTypeName(unsigned short rr_type) { switch (rr_type) { - case kDNSServiceType_A: return("Addr"); - case kDNSServiceType_NS: return("NS"); - case kDNSServiceType_MX: return("MX"); - case kDNSServiceType_CNAME: return("CNAME"); - case kDNSServiceType_SOA: return("SOA"); - case kDNSServiceType_PTR: return("PTR"); - case kDNSServiceType_AAAA: return("AAAA"); - case kDNSServiceType_NSEC: return("NSEC"); - case kDNSServiceType_TSIG: return("TSIG"); - case kDNSServiceType_RRSIG: return("RRSIG"); - case kDNSServiceType_DNSKEY: return("DNSKEY"); - case kDNSServiceType_DS: return("DS"); + case kDNSServiceType_A: return("Addr"); + case kDNSServiceType_NS: return("NS"); + case kDNSServiceType_MD: return("MD"); + case kDNSServiceType_MF: return("MF"); + case kDNSServiceType_CNAME: return("CNAME"); + case kDNSServiceType_SOA: return("SOA"); + case kDNSServiceType_MB: return("MB"); + case kDNSServiceType_MG: return("MG"); + case kDNSServiceType_MR: return("MR"); + case kDNSServiceType_NULL: return("NULL"); + case kDNSServiceType_WKS: return("WKS"); + case kDNSServiceType_PTR: return("PTR"); + case kDNSServiceType_HINFO: return("HINFO"); + case kDNSServiceType_MINFO: return("MINFO"); + case kDNSServiceType_MX: return("MX"); + case kDNSServiceType_TXT: return("TXT"); + case kDNSServiceType_RP: return("RP"); + case kDNSServiceType_AFSDB: return("AFSDB"); + case kDNSServiceType_X25: return("X25"); + case kDNSServiceType_ISDN: return("ISDN"); + case kDNSServiceType_RT: return("RT"); + case kDNSServiceType_NSAP: return("NSAP"); + case kDNSServiceType_NSAP_PTR: return("NSAP_PTR"); + case kDNSServiceType_SIG: return("SIG"); + case kDNSServiceType_KEY: return("KEY"); + case kDNSServiceType_PX: return("PX"); + case kDNSServiceType_GPOS: return("GPOS"); + case kDNSServiceType_AAAA: return("AAAA"); + case kDNSServiceType_LOC: return("LOC"); + case kDNSServiceType_NXT: return("NXT"); + case kDNSServiceType_EID: return("EID"); + case kDNSServiceType_NIMLOC: return("NIMLOC"); + case kDNSServiceType_SRV: return("SRV"); + case kDNSServiceType_ATMA: return("ATMA"); + case kDNSServiceType_NAPTR: return("NAPTR"); + case kDNSServiceType_KX: return("KX"); + case kDNSServiceType_CERT: return("CERT"); + case kDNSServiceType_A6: return("A6"); + case kDNSServiceType_DNAME: return("DNAME"); + case kDNSServiceType_SINK: return("SINK"); + case kDNSServiceType_OPT: return("OPT"); + case kDNSServiceType_APL: return("APL"); + case kDNSServiceType_DS: return("DS"); + case kDNSServiceType_SSHFP: return("SSHFP"); + case kDNSServiceType_IPSECKEY: return("IPSECKEY"); + case kDNSServiceType_RRSIG: return("RRSIG"); + case kDNSServiceType_NSEC: return("NSEC"); + case kDNSServiceType_DNSKEY: return("DNSKEY"); + case kDNSServiceType_DHCID: return("DHCID"); + case kDNSServiceType_NSEC3: return("NSEC3"); + case kDNSServiceType_NSEC3PARAM: return("NSEC3PARAM"); + case kDNSServiceType_HIP: return("HIP"); + case kDNSServiceType_SPF: return("SPF"); + case kDNSServiceType_UINFO: return("UINFO"); + case kDNSServiceType_UID: return("UID"); + case kDNSServiceType_GID: return("GID"); + case kDNSServiceType_UNSPEC: return("UNSPEC"); + case kDNSServiceType_TKEY: return("TKEY"); + case kDNSServiceType_TSIG: return("TSIG"); + case kDNSServiceType_IXFR: return("IXFR"); + case kDNSServiceType_AXFR: return("AXFR"); + case kDNSServiceType_MAILB: return("MAILB"); + case kDNSServiceType_MAILA: return("MAILA"); + case kDNSServiceType_ANY: return("ANY"); default: { static char buffer[RR_TYPE_SIZE]; @@ -422,7 +474,9 @@ static DNSServiceProtocol GetProtocol(const char *s) //************************************************************************************************************* // Sample callback functions for each of the operation types -static void printtimestamp(void) +#define printtimestamp() printtimestamp_F(stdout) + +static void printtimestamp_F(FILE *outstream) { struct tm tm; int ms; @@ -443,10 +497,10 @@ static void printtimestamp(void) strftime(new_date, sizeof(new_date), "%a %d %b %Y", &tm); if (strncmp(date, new_date, sizeof(new_date))) { - printf("DATE: ---%s---\n", new_date); //display date only if it has changed + fprintf(outstream, "DATE: ---%s---\n", new_date); //display date only if it has changed strncpy(date, new_date, sizeof(date)); } - printf("%2d:%02d:%02d.%03d ", tm.tm_hour, tm.tm_min, tm.tm_sec, ms); + fprintf(outstream, "%2d:%02d:%02d.%03d ", tm.tm_hour, tm.tm_min, tm.tm_sec, ms); } // formating time to RFC 4034 format @@ -467,41 +521,50 @@ static void FormatTime(unsigned long te, unsigned char *buf, int bufsize) static void print_usage(const char *arg0, int print_all) { + // Print the commonly used command line options. These are listed in "the order they have been in historically". fprintf(stderr, "%s -E (Enumerate recommended registration domains)\n", arg0); fprintf(stderr, "%s -F (Enumerate recommended browsing domains)\n", arg0); fprintf(stderr, "%s -R [...] (Register a service)\n", arg0); - fprintf(stderr, "%s -B (Browse for services instances)\n", arg0); - fprintf(stderr, "%s -L (Look up a service instance)\n", arg0); - fprintf(stderr, "%s -P [...] (Proxy)\n", arg0); - fprintf(stderr, "%s -q (Generic query for any record type)\n", arg0); - fprintf(stderr, "%s -D (Validate query for any record type with DNSSEC)\n", arg0); + fprintf(stderr, "%s -B (Browse for service instances)\n", arg0); + fprintf(stderr, "%s -L (Resolve a service instance)\n", arg0); + fprintf(stderr, "%s -Q (Generic query for any record type)\n", arg0); fprintf(stderr, "%s -Z (Output results in Zone File format)\n", arg0); fprintf(stderr, "%s -G v4/v6/v4v6 (Get address information for hostname)\n", arg0); - fprintf(stderr, "%s -g v4/v6/v4v6 (Validate address info for hostname with DNSSEC)\n", arg0); + fprintf(stderr, "%s -H (Print usage for complete command list)\n", arg0); fprintf(stderr, "%s -V (Get version of currently running daemon / system service)\n", arg0); - if (print_all) //Print all available options for dns-sd tool + if (print_all) // Print all available options for dns-sd tool. Keep these in alphabetical order for easier maintenance. { - fprintf(stderr, "%s -C (Query; reconfirming each result)\n", arg0); - fprintf(stderr, "%s -X udp/tcp/udptcp (NAT Port Mapping)\n", arg0); + fprintf(stderr, "\n"); fprintf(stderr, "%s -A (Test Adding/Updating/Deleting a record)\n", arg0); - fprintf(stderr, "%s -U (Test updating a TXT record)\n", arg0); + fprintf(stderr, "%s -C (Query; reconfirming each result)\n", arg0); + fprintf(stderr, "%s -D (Validate query for any record type with DNSSEC)\n", arg0); + fprintf(stderr, "%s -I (Test registering and then immediately updating TXT record)\n", arg0); fprintf(stderr, "%s -N (Test adding a large NULL record)\n", arg0); - fprintf(stderr, "%s -T (Test creating a large TXT record)\n", arg0); fprintf(stderr, "%s -M (Test creating a registration with multiple TXT records)\n", arg0); - fprintf(stderr, "%s -I (Test registering and then immediately updating TXT record)\n", arg0); + fprintf(stderr, "%s -P [...] (Proxy)\n", arg0); fprintf(stderr, "%s -S (Test multiple operations on a shared socket)\n", arg0); + fprintf(stderr, "%s -T (Test creating a large TXT record)\n", arg0); + fprintf(stderr, "%s -U (Test updating a TXT record)\n", arg0); + fprintf(stderr, "%s -X udp/tcp/udptcp (NAT Port Mapping)\n", arg0); + fprintf(stderr, "%s -ble (Use kDNSServiceInterfaceIndexBLE)\n", arg0); + fprintf(stderr, "%s -g v4/v6/v4v6 (Validate address info for hostname with DNSSEC)\n", arg0); fprintf(stderr, "%s -i (Run dns-sd cmd on a specific interface (en0/en1)\n", arg0); - fprintf(stderr, "%s -lo (Run dns-sd cmd using local only interface)\n", arg0); - fprintf(stderr, "%s -p2p (Use kDNSServiceInterfaceIndexP2P)\n", arg0); fprintf(stderr, "%s -includep2p (Set kDNSServiceFlagsIncludeP2P flag)\n", arg0); fprintf(stderr, "%s -includeAWDL (Set kDNSServiceFlagsIncludeAWDL flag)\n", arg0); + fprintf(stderr, "%s -intermediates (Set kDNSServiceFlagsReturnIntermediates flag)\n", arg0); + fprintf(stderr, "%s -ku (Set kDNSServiceFlagsKnownUnique flag)\n", arg0); + fprintf(stderr, "%s -lo (Run dns-sd cmd using local only interface)\n", arg0); fprintf(stderr, "%s -optional (Set kDNSServiceFlagsValidateOptional flag)\n", arg0); + fprintf(stderr, "%s -p2p (Use kDNSServiceInterfaceIndexP2P)\n", arg0); + fprintf(stderr, "%s -q (Equivalent to -Q with kDNSServiceFlagsSuppressUnusable set)\n", arg0); fprintf(stderr, "%s -tc (Set kDNSServiceFlagsBackgroundTrafficClass flag)\n", arg0); - fprintf(stderr, "%s -unicastResponse (Set kDNSServiceFlagsUnicastResponse flag)\n", arg0); + fprintf(stderr, "%s -test (Run basic API input range tests)\n", arg0); fprintf(stderr, "%s -t1 (Set kDNSServiceFlagsThresholdOne flag)\n", arg0); fprintf(stderr, "%s -tFinder (Set kDNSServiceFlagsThresholdFinder flag)\n", arg0); fprintf(stderr, "%s -timeout (Set kDNSServiceFlagsTimeout flag)\n", arg0); + fprintf(stderr, "%s -unicastResponse (Set kDNSServiceFlagsUnicastResponse flag)\n", arg0); + fprintf(stderr, "%s -autoTrigger (Set kDNSServiceFlagsAutoTrigger flag)\n", arg0); } } @@ -731,17 +794,20 @@ static void DNSSD_API resolve_reply(DNSServiceRef sdref, const DNSServiceFlags f (void)context; // Unused EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode); - if (errorCode) - printf("Error code %d\n", errorCode); - else - { - printtimestamp(); - printf("%s can be reached at %s:%u (interface %d)", fullname, hosttarget, PortAsNumber, ifIndex); - if (flags) printf(" Flags: %X", flags); - // Don't show degenerate TXT records containing nothing but a single empty string - if (txtLen > 1) { printf("\n"); ShowTXTRecord(txtLen, txtRecord); } - printf("\n"); - } + printtimestamp(); + + printf("%s ", fullname); + + if (errorCode == kDNSServiceErr_NoSuchRecord) printf("No Such Record"); + else if (errorCode) printf("error code %d\n", errorCode); + else printf("can be reached at %s:%u (interface %d)", hosttarget, PortAsNumber, ifIndex); + + if (flags) printf(" Flags: %X", flags); + + // Don't show degenerate TXT records containing nothing but a single empty string + if (!errorCode && txtLen > 1) { printf("\n"); ShowTXTRecord(txtLen, txtRecord); } + + printf("\n"); if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout); } @@ -776,6 +842,7 @@ static void myTimerCallBack(void) { if (updatetest[1] != 'Z') updatetest[1]++; else updatetest[1] = 'A'; + // The following line toggles the string length between 1 and 2 characters. updatetest[0] = 3 - updatetest[0]; updatetest[2] = updatetest[1]; printtimestamp(); @@ -1249,7 +1316,7 @@ static void HandleEvents(void) DNSServiceErrorType err = kDNSServiceErr_NoError; if (client && FD_ISSET(dns_sd_fd, &readfds)) err = DNSServiceProcessResult(client ); else if (client_pa && FD_ISSET(dns_sd_fd2, &readfds)) err = DNSServiceProcessResult(client_pa); - if (err) { fprintf(stderr, "DNSServiceProcessResult returned %d\n", err); stopNow = 1; } + if (err) { printtimestamp_F(stderr); fprintf(stderr, "DNSServiceProcessResult returned %d\n", err); stopNow = 1; } } else if (result == 0) myTimerCallBack(); @@ -1306,18 +1373,6 @@ static void DNSSD_API MyRegisterRecordCallback(DNSServiceRef service, DNSRecordR default: printf("Error %d\n", errorCode); break; } if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout); - // DNSServiceRemoveRecord(service, rec, 0); to test record removal - -#if 0 // To test updating of individual records registered via DNSServiceRegisterRecord - if (!errorCode) - { - int x = 0x11111111; - printf("Updating\n"); - DNSServiceUpdateRecord(service, rec, 0, sizeof(x), &x, 0); - } -#endif - - if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout); } static void getip(const char *const name, struct sockaddr_storage *result) @@ -1403,6 +1458,215 @@ static char *gettype(char *buffer, char *typ) return(typ); } +// Do some basic tests to verify API handles > 63 byte strings gracefully with +// a returned error code. + +#define STRING_64_BYTES "_123456789012345678901234567890123456789012345678901234567890123" + +static int API_string_limit_test() +{ + const char * regtype; + DNSServiceRef sdRef = NULL; + const char * longHost = STRING_64_BYTES ".local"; + const char * longDomain = "hostname." STRING_64_BYTES; + + printf("Testing for error returns when various strings are > 63 bytes.\n"); + + printf("DNSServiceGetAddrInfo(), hostname = %s\n", longHost); + if (DNSServiceGetAddrInfo(&sdRef, 0, 0, 0, longHost, addrinfo_reply, 0) == 0) + { + printf("DNSServiceGetAddrInfo(): expected error return\n"); + return 1; + }; + + printf("DNSServiceGetAddrInfo(), hostname = %s\n", longDomain); + if (DNSServiceGetAddrInfo(&sdRef, 0, 0, 0, longDomain, addrinfo_reply, 0) == 0) + { + printf("DNSServiceGetAddrInfo(): expected error return\n"); + return 1; + }; + + printf("DNSServiceResolve(), name = %s\n", STRING_64_BYTES); + if (DNSServiceResolve(&sdRef, 0, 0, STRING_64_BYTES, "_test._tcp", "local", resolve_reply, NULL) == 0) + { + printf("DNSServiceResolve(): expected error return\n"); + return 1; + }; + + regtype = STRING_64_BYTES "._tcp"; + printf("DNSServiceResolve(), regtype = %s\n", regtype); + if (DNSServiceResolve(&sdRef, 0, 0, "instanceName", regtype, "local", resolve_reply, NULL) == 0) + { + printf("DNSServiceResolve(): expected error return\n"); + return 1; + }; + + printf("DNSServiceResolve(), domain = %s\n", STRING_64_BYTES); + if (DNSServiceResolve(&sdRef, 0, 0, "instanceName", "_test._tcp", STRING_64_BYTES, resolve_reply, NULL) == 0) + { + printf("DNSServiceResolve(): expected error return\n"); + return 1; + }; + + printf("Testing for error returns when various strings are > 63 bytes: PASSED\n"); + return 0; +} + +// local prototypes for routines that don't have prototypes in dns_sd.h +#if APPLE_OSX_mDNSResponder +DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain); +DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid); +#endif + +static int API_NULL_input_test() +{ + printf("Running basic API input range tests with all parameters set to 0:\n"); + + // Test that API's handle NULL pointers by returning an error when appropriate. + printf("DNSServiceRefSockFD()\n"); + if (DNSServiceRefSockFD(0) != -1) + { + printf("DNSServiceRefSockFD(): expected dnssd_InvalidSocket return\n"); + return 1; + }; + + printf("DNSServiceProcessResult()\n"); + if (DNSServiceProcessResult(0) == 0) + { + printf("DNSServiceProcessResult(): expected error return\n"); + return 1; + }; + + // no return value, just verify it doesn't crash + printf("DNSServiceRefDeallocate()\n"); + DNSServiceRefDeallocate(0); + + printf("DNSServiceGetProperty()\n"); + if (DNSServiceGetProperty(0, 0, 0) == 0) + { + printf("DNSServiceGetProperty(): expected error return\n"); + return 1; + }; + + printf("DNSServiceResolve()\n"); + if (DNSServiceResolve(0, 0, 0, 0, 0, 0, 0, 0) == 0) + { + printf("DNSServiceResolve(): expected error return\n"); + return 1; + }; + + printf("DNSServiceQueryRecord()\n"); + if (DNSServiceQueryRecord(0, 0, 0, 0, 0, 0, 0, 0) == 0) + { + printf("DNSServiceQueryRecord(): expected error return\n"); + return 1; + }; + + printf("DNSServiceGetAddrInfo()\n"); + if (DNSServiceGetAddrInfo(0, 0, 0, 0, 0, 0, 0) == 0) + { + printf("DNSServiceGetAddrInfo(): expected error return\n"); + return 1; + }; + + printf("DNSServiceBrowse()\n"); + if (DNSServiceBrowse(0, 0, 0, 0, 0, 0, 0) == 0) + { + printf("DNSServiceBrowse(): expected error return\n"); + return 1; + }; + +#if APPLE_OSX_mDNSResponder + printf("DNSServiceSetDefaultDomainForUser()\n"); + if (DNSServiceSetDefaultDomainForUser(0, 0) == 0) + { + printf("DNSServiceSetDefaultDomainForUser(): expected error return\n"); + return 1; + }; +#endif + + printf("DNSServiceRegister()\n"); + if (DNSServiceRegister(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) == 0) + { + printf("DNSServiceRegister(): expected error return\n"); + return 1; + }; + + printf("DNSServiceEnumerateDomains()\n"); + if (DNSServiceEnumerateDomains(0, 0, 0, 0, 0) == 0) + { + printf("DNSServiceEnumerateDomains(): expected error return\n"); + return 1; + }; + + printf("DNSServiceCreateConnection()\n"); + if (DNSServiceCreateConnection(0) == 0) + { + printf("DNSServiceCreateConnection(): expected error return\n"); + return 1; + }; + +#if APPLE_OSX_mDNSResponder + printf("DNSServiceCreateDelegateConnection()\n"); + if (DNSServiceCreateDelegateConnection(0, 0, 0) == 0) + { + printf("DNSServiceCreateDelegateConnection(): expected error return\n"); + return 1; + }; +#endif + + printf("DNSServiceRegisterRecord()\n"); + if (DNSServiceRegisterRecord(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) == 0) + { + printf("DNSServiceRegisterRecord(): expected error return\n"); + return 1; + }; + + printf("DNSServiceAddRecord()\n"); + if (DNSServiceAddRecord(0, 0, 0, 0, 0, 0, 0) == 0) + { + printf("DNSServiceAddRecord(): expected error return\n"); + return 1; + }; + + printf("DNSServiceUpdateRecord()\n"); + if (DNSServiceUpdateRecord(0, 0, 0, 0, 0, 0) == 0) + { + printf("DNSServiceUpdateRecord(): expected error return\n"); + return 1; + }; + + printf("DNSServiceRemoveRecord()\n"); + if (DNSServiceRemoveRecord(0, 0, 0) == 0) + { + printf("DNSServiceRemoveRecord(): expected error return\n"); + return 1; + }; + + printf("DNSServiceReconfirmRecord()\n"); + if (DNSServiceReconfirmRecord(0, 0, 0, 0, 0, 0, 0) == 0) + { + printf("DNSServiceReconfirmRecord(): expected error return\n"); + return 1; + }; + + + printf("Basic API input range tests with all parameters set to 0: PASSED\n"); + return 0; +} + +static int API_input_range_test() +{ + + if (API_string_limit_test()) + return 1; + + if (API_NULL_input_test()) + return 1; + + return 0; +} + int main(int argc, char **argv) { DNSServiceErrorType err; @@ -1432,102 +1696,154 @@ int main(int argc, char **argv) //TXTRecordSetValue(&txtRecord, "aaa", 1, "b"); //printf("%d\n", TXTRecordContainsKey(TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord), "Aaa")); - if (argc > 1 && !strcmp(argv[1], "-lo")) - { - argc--; - argv++; - opinterface = kDNSServiceInterfaceIndexLocalOnly; - printf("Using LocalOnly\n"); - } - - if (argc > 1 && (!strcmp(argv[1], "-p2p") || !strcmp(argv[1], "-P2P"))) - { - argc--; - argv++; - opinterface = kDNSServiceInterfaceIndexP2P; - } - - if (argc > 1 && !strcasecmp(argv[1], "-includep2p")) - { - argc--; - argv++; - flags |= kDNSServiceFlagsIncludeP2P; - printf("Setting kDNSServiceFlagsIncludeP2P\n"); - } - - if (argc > 1 && !strcasecmp(argv[1], "-includeAWDL")) - { - argc--; - argv++; - flags |= kDNSServiceFlagsIncludeAWDL; - printf("Setting kDNSServiceFlagsIncludeAWDL\n"); - } - - if (argc > 1 && !strcasecmp(argv[1], "-tc")) + while (argc > 1) { - argc--; - argv++; - flags |= kDNSServiceFlagsBackgroundTrafficClass; - printf("Setting kDNSServiceFlagsBackgroundTrafficClass\n"); - } - - if (argc > 1 && !strcasecmp(argv[1], "-t1")) - { - argc--; - argv++; - flags |= kDNSServiceFlagsThresholdOne; - printf("Setting kDNSServiceFlagsThresholdOne\n"); - } - - if (argc > 1 && !strcasecmp(argv[1], "-tFinder")) - { - argc--; - argv++; - flags |= kDNSServiceFlagsThresholdFinder; - printf("Setting kDNSServiceFlagsThresholdFinder\n"); - } - - if (argc > 1 && !strcasecmp(argv[1], "-wo")) - { - argc--; - argv++; - flags |= kDNSServiceFlagsWakeOnlyService; - printf("Setting kDNSServiceFlagsWakeOnlyService\n"); - } - - if (argc > 1 && !strcasecmp(argv[1], "-unicastResponse")) - { - argc--; - argv++; - flags |= kDNSServiceFlagsUnicastResponse; - printf("Setting kDNSServiceFlagsUnicastResponse\n"); - } - if (argc > 1 && !strcasecmp(argv[1], "-timeout")) - { - argc--; - argv++; - flags |= kDNSServiceFlagsTimeout; - printf("Setting kDNSServiceFlagsTimeout\n"); - } - if (argc > 1 && !strcasecmp(argv[1], "-optional")) - { - argc--; - argv++; - optional = 1; - printf("Setting DNSSEC optional flag\n"); - } + int entryCount; + + // record current argc to see if we process an argument in this pass + entryCount = argc; + + if (argc > 1 && !strcmp(argv[1], "-test")) + { + argc--; + argv++; + return API_input_range_test(); + } + + if (argc > 1 && !strcmp(argv[1], "-lo")) + { + argc--; + argv++; + opinterface = kDNSServiceInterfaceIndexLocalOnly; + printf("Using LocalOnly\n"); + } + + if (argc > 1 && (!strcasecmp(argv[1], "-p2p"))) + { + argc--; + argv++; + opinterface = kDNSServiceInterfaceIndexP2P; + } + + if (argc > 1 && (!strcasecmp(argv[1], "-ble"))) + { + argc--; + argv++; + opinterface = kDNSServiceInterfaceIndexBLE; + } + + if (argc > 1 && !strcasecmp(argv[1], "-includep2p")) + { + argc--; + argv++; + flags |= kDNSServiceFlagsIncludeP2P; + printf("Setting kDNSServiceFlagsIncludeP2P\n"); + } + + if (argc > 1 && !strcasecmp(argv[1], "-includeAWDL")) + { + argc--; + argv++; + flags |= kDNSServiceFlagsIncludeAWDL; + printf("Setting kDNSServiceFlagsIncludeAWDL\n"); + } + + if (argc > 1 && !strcasecmp(argv[1], "-intermediates")) + { + argc--; + argv++; + flags |= kDNSServiceFlagsReturnIntermediates; + printf("Setting kDNSServiceFlagsReturnIntermediates\n"); + } - if (argc > 2 && !strcmp(argv[1], "-i")) - { - opinterface = if_nametoindex(argv[2]); - if (!opinterface) opinterface = atoi(argv[2]); - if (!opinterface) { fprintf(stderr, "Unknown interface %s\n", argv[2]); goto Fail; } - argc -= 2; - argv += 2; + if (argc > 1 && !strcasecmp(argv[1], "-tc")) + { + argc--; + argv++; + flags |= kDNSServiceFlagsBackgroundTrafficClass; + printf("Setting kDNSServiceFlagsBackgroundTrafficClass\n"); + } + + if (argc > 1 && !strcasecmp(argv[1], "-t1")) + { + argc--; + argv++; + flags |= kDNSServiceFlagsThresholdOne; + printf("Setting kDNSServiceFlagsThresholdOne\n"); + } + + if (argc > 1 && !strcasecmp(argv[1], "-tFinder")) + { + argc--; + argv++; + flags |= kDNSServiceFlagsThresholdFinder; + printf("Setting kDNSServiceFlagsThresholdFinder\n"); + } + + if (argc > 1 && !strcasecmp(argv[1], "-wo")) + { + argc--; + argv++; + flags |= kDNSServiceFlagsWakeOnlyService; + printf("Setting kDNSServiceFlagsWakeOnlyService\n"); + } + + if (argc > 1 && !strcasecmp(argv[1], "-ku")) + { + argc--; + argv++; + flags |= kDNSServiceFlagsKnownUnique; + printf("Setting kDNSServiceFlagsKnownUnique\n"); + } + + if (argc > 1 && !strcasecmp(argv[1], "-unicastResponse")) + { + argc--; + argv++; + flags |= kDNSServiceFlagsUnicastResponse; + printf("Setting kDNSServiceFlagsUnicastResponse\n"); + } + + if (argc > 1 && !strcasecmp(argv[1], "-timeout")) + { + argc--; + argv++; + flags |= kDNSServiceFlagsTimeout; + printf("Setting kDNSServiceFlagsTimeout\n"); + } + + if (argc > 1 && !strcasecmp(argv[1], "-autoTrigger")) + { + argc--; + argv++; + flags |= kDNSServiceFlagsAutoTrigger; + printf("Setting kDNSServiceFlagsAutoTrigger\n"); + } + + if (argc > 1 && !strcasecmp(argv[1], "-optional")) + { + argc--; + argv++; + optional = 1; + printf("Setting DNSSEC optional flag\n"); + } + + if (argc > 2 && !strcmp(argv[1], "-i")) + { + opinterface = if_nametoindex(argv[2]); + if (!opinterface) opinterface = atoi(argv[2]); + if (!opinterface) { fprintf(stderr, "Unknown interface %s\n", argv[2]); goto Fail; } + argc -= 2; + argv += 2; + } + + // Exit loop if if we didn't match one of the multi character options. + if (argc == entryCount) + break; } if (argc < 2) goto Fail; // Minimum command line is the command name and one argument - operation = getfirstoption(argc, argv, "EFBZLlRPQqCAUNTMISVHhD" + operation = getfirstoption(argc, argv, "ABCDEFHILMNPQRSTUVZhlq" "X" "Gg" , &opi); diff --git a/mDNSResponder/Clients/dnsctl.c b/mDNSResponder/Clients/dnsctl.c index f10f2259..e01c8fec 100644 --- a/mDNSResponder/Clients/dnsctl.c +++ b/mDNSResponder/Clients/dnsctl.c @@ -17,16 +17,20 @@ #include #include // if_nametoindex() -#include #include "dns_services.h" +#include +#include "dns_xpc.h" //************************************************************************************************************* // Globals: //************************************************************************************************************* static const char kFilePathSep = '/'; + static DNSXConnRef ClientRef = NULL; +static xpc_connection_t dnsctl_conn = NULL; + //************************************************************************************************************* // Utility Funcs: //************************************************************************************************************* @@ -56,12 +60,31 @@ static void print_usage(const char *arg0) fprintf(stderr, "%s USAGE: \n", arg0); fprintf(stderr, "%s -DP Enable DNS Proxy with Default Parameters \n", arg0); fprintf(stderr, "%s -DP [-o ] [-i ] Enable DNS Proxy \n", arg0); + fprintf(stderr, "%s -L [1/2/3/4] Change mDNSResponder Logging Level \n", arg0); + fprintf(stderr, "%s -I Print mDNSResponder STATE INFO \n", arg0); +} + + +static bool DebugEnabled() +{ + return true; // keep this true to debug the XPC msgs +} + +static void DebugLog(const char *prefix, xpc_object_t o) +{ + if (!DebugEnabled()) + return; + + char *desc = xpc_copy_description(o); + printf("%s: %s \n", prefix, desc); + free(desc); } //************************************************************************************************************* // CallBack Funcs: //************************************************************************************************************* + // DNSXEnableProxy Callback from the Daemon static void dnsproxy_reply(DNSXConnRef connRef, DNSXErrorType errCode) { @@ -75,6 +98,8 @@ static void dnsproxy_reply(DNSXConnRef connRef, DNSXErrorType errCode) DNSXRefDeAlloc(ClientRef); break; case kDNSX_BadParam : printf(" BAD PARAMETER \n"); DNSXRefDeAlloc(ClientRef); break; + case kDNSX_Busy : printf(" BUSY \n"); + DNSXRefDeAlloc(ClientRef); break; case kDNSX_UnknownErr : default : printf(" UNKNOWN ERR \n"); DNSXRefDeAlloc(ClientRef); break; @@ -83,16 +108,57 @@ static void dnsproxy_reply(DNSXConnRef connRef, DNSXErrorType errCode) } +//************************************************************************************************************* +// XPC Funcs: //************************************************************************************************************* -int main(int argc, char **argv) +static void Init_Connection(const char *servname) +{ + dnsctl_conn = xpc_connection_create_mach_service(servname, dispatch_get_main_queue(), XPC_CONNECTION_MACH_SERVICE_PRIVILEGED); + + xpc_connection_set_event_handler(dnsctl_conn, ^(xpc_object_t event) + { + printf("InitConnection: [%s] \n", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION)); + }); + + xpc_connection_resume(dnsctl_conn); +} + +static void SendDictToServer(xpc_object_t msg) { - DNSXErrorType err; - // Default i/p intf is lo0 and o/p intf is primary interface - IfIndex Ipintfs[MaxInputIf] = {1, 0, 0, 0, 0}; - IfIndex Opintf = kDNSIfindexAny; + DebugLog("SendDictToServer Sending msg to Daemon", msg); + xpc_connection_send_message_with_reply(dnsctl_conn, msg, dispatch_get_main_queue(), ^(xpc_object_t recv_msg) + { + xpc_type_t type = xpc_get_type(recv_msg); + + if (type == XPC_TYPE_DICTIONARY) + { + DebugLog("SendDictToServer Received reply msg from Daemon", recv_msg); + /* + // If we ever want to do something based on the reply of the daemon + switch (daemon_status) + { + default: + break; + } + */ + } + else + { + printf("SendDictToServer Received unexpected reply from daemon [%s]", + xpc_dictionary_get_string(recv_msg, XPC_ERROR_KEY_DESCRIPTION)); + DebugLog("SendDictToServer Unexpected Reply contents", recv_msg); + } + exit(1); + }); +} + +//************************************************************************************************************* + +int main(int argc, char **argv) +{ // Extract program name from argv[0], which by convention contains the path to this executable const char *a0 = strrchr(argv[0], kFilePathSep) + 1; if (a0 == (const char *)1) @@ -113,15 +179,20 @@ int main(int argc, char **argv) if (argc < 2) goto Usage; - if ( !strcmp(argv[1], "-DP") || !strcmp(argv[1], "-dp") ) + printtimestamp(); + if (!strcasecmp(argv[1], "-DP")) { + DNSXErrorType err; + // Default i/p intf is lo0 and o/p intf is primary interface + IfIndex Ipintfs[MaxInputIf] = {1, 0, 0, 0, 0}; + IfIndex Opintf = kDNSIfindexAny; + if (argc == 2) { - printtimestamp(); - printf("Enabling DNSProxy on mDNSResponder with Default Parameters\n"); dispatch_queue_t my_Q = dispatch_queue_create("com.apple.dnsctl.callback_queue", NULL); err = DNSXEnableProxy(&ClientRef, kDNSProxyEnable, Ipintfs, Opintf, my_Q, dnsproxy_reply); - if (err) fprintf(stderr, "DNSXEnableProxy returned %d\n", err); + if (err) + fprintf(stderr, "DNSXEnableProxy returned %d\n", err); } else if (argc > 2) { @@ -159,13 +230,96 @@ int main(int argc, char **argv) argv++; } } - printtimestamp(); printf("Enabling DNSProxy on mDNSResponder \n"); dispatch_queue_t my_Q = dispatch_queue_create("com.apple.dnsctl.callback_queue", NULL); err = DNSXEnableProxy(&ClientRef, kDNSProxyEnable, Ipintfs, Opintf, my_Q, dnsproxy_reply); - if (err) fprintf(stderr, "DNSXEnableProxy returned %d\n", err); + if (err) + fprintf(stderr, "DNSXEnableProxy returned %d\n", err); + } + } + else if (!strcasecmp(argv[1], "-l")) + { + printf("Changing loglevel of mDNSResponder \n"); + Init_Connection(kDNSCTLService); + + // Create Dictionary To Send + xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); + + if (argc == 2) + { + xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level1); + + SendDictToServer(dict); + xpc_release(dict); + dict = NULL; + } + else if (argc > 2) + { + argc--; + argv++; + switch (atoi(argv[1])) + { + case log_level1: + xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level1); + break; + + case log_level2: + xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level2); + break; + + case log_level3: + xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level3); + break; + + case log_level4: + xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level4); + break; + + default: + xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level1); + break; + } + SendDictToServer(dict); + xpc_release(dict); + dict = NULL; } } + else if(!strcasecmp(argv[1], "-i")) + { + printf("Get STATE INFO of mDNSResponder \n"); + Init_Connection(kDNSCTLService); + + // Create Dictionary To Send + xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_uint64(dict, kDNSStateInfo, full_state); + SendDictToServer(dict); + xpc_release(dict); + dict = NULL; + } + else if(!strcasecmp(argv[1], "-th")) + { + printf("Sending Test message to mDNSResponder to forward to mDNSResponderHelper\n"); + Init_Connection(kDNSCTLService); + + // Create Dictionary To Send + xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_uint64(dict, kmDNSResponderTests, test_helper_ipc); + SendDictToServer(dict); + xpc_release(dict); + dict = NULL; + } + else if(!strcasecmp(argv[1], "-tl")) + { + printf("Testing mDNSResponder Logging\n"); + Init_Connection(kDNSCTLService); + + // Create Dictionary To Send + xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_uint64(dict, kmDNSResponderTests, test_mDNS_log); + SendDictToServer(dict); + xpc_release(dict); + dict = NULL; + } else { goto Usage; @@ -178,3 +332,52 @@ Usage: return 0; } +/* + +#include + +static int operation; + +static int getfirstoption(int argc, char **argv, const char *optstr, int *pOptInd) +{ + // Return the recognized option in optstr and the option index of the next arg. + int o = getopt(argc, (char *const *)argv, optstr); + *pOptInd = optind; + return o; +} + +int opindex; +operation = getfirstoption(argc, argv, "lLDdPp", &opindex); +if (operation == -1) + goto Usage; + + + +switch (operation) +{ + case 'L': + case 'l': + { + printtimestamp(); + printf("Change Verbosity Level of mDNSResponder\n"); + + Init_Connection(kDNSCTLService); + + // Create Dictionary To Send + xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); + if (dict == NULL) + printf("could not create the Msg Dict To Send! \n"); + xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level2); + + SendDictToServer(dict); + + xpc_release(dict); + dict = NULL; + break; + } + // exit(1); + +} + +*/ + diff --git a/mDNSResponder/Documents/Attach mDNSResponder to Xcode.rtfd/52D711AF-4055-4867-A494-7E31552BB9E1.png b/mDNSResponder/Documents/Attach mDNSResponder to Xcode.rtfd/52D711AF-4055-4867-A494-7E31552BB9E1.png new file mode 100644 index 00000000..38eef124 Binary files /dev/null and b/mDNSResponder/Documents/Attach mDNSResponder to Xcode.rtfd/52D711AF-4055-4867-A494-7E31552BB9E1.png differ diff --git a/mDNSResponder/Documents/Attach mDNSResponder to Xcode.rtfd/Screen Shot 2015-09-16 at 3.36.23 PM.png b/mDNSResponder/Documents/Attach mDNSResponder to Xcode.rtfd/Screen Shot 2015-09-16 at 3.36.23 PM.png new file mode 100644 index 00000000..40426447 Binary files /dev/null and b/mDNSResponder/Documents/Attach mDNSResponder to Xcode.rtfd/Screen Shot 2015-09-16 at 3.36.23 PM.png differ diff --git a/mDNSResponder/Documents/Attach mDNSResponder to Xcode.rtfd/Screen Shot 2015-09-16 at 3.46.14 PM.png b/mDNSResponder/Documents/Attach mDNSResponder to Xcode.rtfd/Screen Shot 2015-09-16 at 3.46.14 PM.png new file mode 100644 index 00000000..31cd8070 Binary files /dev/null and b/mDNSResponder/Documents/Attach mDNSResponder to Xcode.rtfd/Screen Shot 2015-09-16 at 3.46.14 PM.png differ diff --git a/mDNSResponder/Documents/Attach mDNSResponder to Xcode.rtfd/TXT.rtf b/mDNSResponder/Documents/Attach mDNSResponder to Xcode.rtfd/TXT.rtf new file mode 100644 index 00000000..ddcccfdc --- /dev/null +++ b/mDNSResponder/Documents/Attach mDNSResponder to Xcode.rtfd/TXT.rtf @@ -0,0 +1,75 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf120 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fnil\fcharset0 Menlo-Regular;} +{\colortbl;\red255\green255\blue255;} +\margl1440\margr1440\vieww25580\viewh24980\viewkind0 +\deftab720 +\pard\pardeftab720\partightenfactor0 + +\f0\fs24 \cf0 \expnd0\expndtw0\kerning0 +Three steps to attach, and debug in Xcode, a /usr/sbin/mDNSResponder that is already running. One caveat, mDNSResponder has to be built and deployed (using step 1 and 2 below) before it can be attached to Xcode.\ +\ +1.) First you have to build the Xcode project with symbols included and optimizations off.\ +\ + a.) From Terminal shell, open mDNSResponder Xcode project from top of tree: \'a0\ +\ + $ open mDNSMacOSX/mDNSResponder.xcodeproj/\ +\ +\pard\pardeftab720\partightenfactor0 +\cf0 You can also just double click on the project from Finder.\ +\ + b.) Add your diffs to mDNSResponder project. +\f1\fs22 \ +\pard\pardeftab720\partightenfactor0 + +\f0\fs24 \cf0 \ + c.) Set Strip Linked Product to No and compiler Optimization Level to None. Below shows changed settings.\ +\ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 +\cf0 \kerning1\expnd0\expndtw0 {{\NeXTGraphic Screen Shot 2015-09-16 at 3.36.23 PM.png \width7680 \height460 +}¬}\ +\ + {{\NeXTGraphic Screen Shot 2015-09-16 at 3.46.14 PM.png \width8700 \height460 +}¬}\expnd0\expndtw0\kerning0 +\ +\pard\pardeftab720\partightenfactor0 +\cf0 \ + d. ) Build mDNSResponder by setting the target to mDNSResponder.\ +\ + {{\NeXTGraphic unknown.png \width4300 \height800 \noorient +}¬}\ +\ + Then execute\'a0Command-B to build.\ +\ +\ +2.) Next, deploy newly-created Xcode version.\ +\ + a.) Go to Terminal shell and type the following: sudo mv \ +\ + b.) Then drag mDNSResponder from Products list on left side panel (shown below using red arrow) to Terminal shell.\ +\ +\pard\pardeftab720\partightenfactor0 +\cf0 {{\NeXTGraphic 52D711AF-4055-4867-A494-7E31552BB9E1.png \width4420 \height9700 +}¬}\pard\pardeftab720\partightenfactor0 +\cf0 \ +\ + c.) Execute command.\ +\ + For example:\ + \ + $ sudo mv\'a0/Volumes/iMac\\ HD/Users/llaier/Library/Developer/Xcode/DerivedData/mDNSResponder-fktewmdupxbxrrdlsdljyhmihboz/Build/Products/mDNSResponder\'a0/usr/sbin/mDNSResponder\ +\ + d.) Restart mDNSResponder by executing the following:\ +\ + $ sudo killall mDNSResponder\ +\pard\pardeftab720\partightenfactor0 + +\f1\fs22 \cf0 \ +\ +\pard\pardeftab720\partightenfactor0 + +\f0\fs24 \cf0 3.) In Xcode, select Debug > Attach to Process > mDNSResponder. +\f1\fs22 \ + +\f0\fs24 \ + Now set a breakpoint and try to trigger it.\ +} \ No newline at end of file diff --git a/mDNSResponder/Documents/Attach mDNSResponder to Xcode.rtfd/unknown.png b/mDNSResponder/Documents/Attach mDNSResponder to Xcode.rtfd/unknown.png new file mode 100644 index 00000000..7e2364e0 Binary files /dev/null and b/mDNSResponder/Documents/Attach mDNSResponder to Xcode.rtfd/unknown.png differ diff --git a/mDNSResponder/Documents/Start mDNSResponder in Xcode.rtfd/A944EB40-AEFD-4CA1-BF10-E8F52835CA8C.png b/mDNSResponder/Documents/Start mDNSResponder in Xcode.rtfd/A944EB40-AEFD-4CA1-BF10-E8F52835CA8C.png new file mode 100644 index 00000000..a5410efe Binary files /dev/null and b/mDNSResponder/Documents/Start mDNSResponder in Xcode.rtfd/A944EB40-AEFD-4CA1-BF10-E8F52835CA8C.png differ diff --git a/mDNSResponder/Documents/Start mDNSResponder in Xcode.rtfd/Screen Shot 2015-09-16 at 4.22.37 PM.png b/mDNSResponder/Documents/Start mDNSResponder in Xcode.rtfd/Screen Shot 2015-09-16 at 4.22.37 PM.png new file mode 100644 index 00000000..1341df46 Binary files /dev/null and b/mDNSResponder/Documents/Start mDNSResponder in Xcode.rtfd/Screen Shot 2015-09-16 at 4.22.37 PM.png differ diff --git a/mDNSResponder/Documents/Start mDNSResponder in Xcode.rtfd/TXT.rtf b/mDNSResponder/Documents/Start mDNSResponder in Xcode.rtfd/TXT.rtf new file mode 100644 index 00000000..13e14d4a --- /dev/null +++ b/mDNSResponder/Documents/Start mDNSResponder in Xcode.rtfd/TXT.rtf @@ -0,0 +1,57 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf460 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\margl1440\margr1440\vieww51000\viewh25780\viewkind0 +\deftab720 +\pard\pardeftab720\partightenfactor0 + +\f0\fs24 \cf0 \expnd0\expndtw0\kerning0 +Instructions on how to run a secondary mDNSResponder in the Xcode debugger. (Two known issues, the secondary mDNSResponder will not send unicast mDNS packets and it does not support BTMM.)\ +\ +1.) From Terminal shell, open mDNSResponder Xcode project. \'a0\ +\ + $ open mDNSMacOSX/mDNSResponder.xcodeproj/\ +\ +You can also just double click on the project from Finder.\ +\ +2.) Configure Xcode Project Scheme by adding the following three arguments, -d -NoSandbox -UseDebugSocket.\ +\ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardeftab720\pardirnatural\partightenfactor0 +\cf0 \kerning1\expnd0\expndtw0 {{\NeXTGraphic A944EB40-AEFD-4CA1-BF10-E8F52835CA8C.png \width18360 \height4420 +}¬}\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardeftab720\pardirnatural\partightenfactor0 +\cf0 \expnd0\expndtw0\kerning0 +\ +\pard\pardeftab720\partightenfactor0 +\cf0 \ +3.) Build and run mDNSResponder by setting the target to mDNSResponder.\ +\ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardeftab720\pardirnatural\partightenfactor0 +\cf0 \kerning1\expnd0\expndtw0 {{\NeXTGraphic Screen Shot 2015-09-16 at 4.22.37 PM.png \width5980 \height660 +}¬}\expnd0\expndtw0\kerning0 +\ +\pard\pardeftab720\partightenfactor0 +\cf0 \ + Then execute\'a0Command-R to build and run your code with the active scheme.\ +\ +\pard\pardeftab720\pardirnatural\partightenfactor0 +\cf0 \kerning1\expnd0\expndtw0 \CocoaLigature0 4.) Before using dns-sd with Xcode-version of mDNSResponder, make sure to export the socket UDS path by executing one of the following commands:\ +\ + From a Borne, bash or zsh, execute this command:\ +\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardeftab720\pardirnatural\partightenfactor0 +\cf0 export DNSSD_UDS_PATH=/var/tmp/mDNSResponder\ +\ +\pard\tx729\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardeftab720\pardirnatural\partightenfactor0 +\cf0 From csh or tcsh, execute this command:\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardeftab720\pardirnatural\partightenfactor0 +\cf0 \ + \expnd0\expndtw0\kerning0 +\CocoaLigature1 setenv DNSSD_UDS_PATH /var/tmp/mDNSResponder\ +\ + There may be other variants to setting the environment variable as well for other shells.\kerning1\expnd0\expndtw0 \CocoaLigature0 \ +\ + Now running dns-sd will interoperate with the secondary Xcode-version of mDNSResponder as long as you run dns-sd from this terminal shell.\ +\ +5.) \expnd0\expndtw0\kerning0 +\CocoaLigature1 Now set a breakpoint in Xcode and try to trigger it using dns-sd.\ +} \ No newline at end of file diff --git a/mDNSResponder/Makefile b/mDNSResponder/Makefile index ba79b293..ab610a7c 100644 --- a/mDNSResponder/Makefile +++ b/mDNSResponder/Makefile @@ -16,7 +16,7 @@ include $(MAKEFILEPATH)/pb_makefiles/platform.make -MVERS = "mDNSResponder-625.41.2" +MVERS = "mDNSResponder-765.1.2" DDNSWRITECONFIG = "$(DSTROOT)/Library/Application Support/Bonjour/ddnswriteconfig" VER = @@ -41,6 +41,7 @@ installsrc: installhdrs:: cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild installhdrs OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target SystemLibraries $(VER) + cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild installhdrs OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target dns_services $(VER) java: cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target libjdns_sd.jnilib $(VER) diff --git a/mDNSResponder/mDNSCore/DNSCommon.c b/mDNSResponder/mDNSCore/DNSCommon.c index d364ee02..a2b703f7 100644 --- a/mDNSResponder/mDNSCore/DNSCommon.c +++ b/mDNSResponder/mDNSCore/DNSCommon.c @@ -43,6 +43,7 @@ mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)-2; mDNSexport const mDNSInterfaceID mDNSInterface_Unicast = (mDNSInterfaceID)-3; mDNSexport const mDNSInterfaceID mDNSInterface_P2P = (mDNSInterfaceID)-4; mDNSexport const mDNSInterfaceID uDNSInterfaceMark = (mDNSInterfaceID)-5; +mDNSexport const mDNSInterfaceID mDNSInterface_BLE = (mDNSInterfaceID)-6; // Note: Microsoft's proposed "Link Local Multicast Name Resolution Protocol" (LLMNR) is essentially a limited version of // Multicast DNS, using the same packet formats, naming syntax, and record types as Multicast DNS, but on a different UDP @@ -107,6 +108,8 @@ mDNSexport const mDNSOpaque16 DNSSecQFlags = { { kDNSFlag0_QR_Query | kDNS mDNSexport const mDNSOpaque16 ResponseFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } }; mDNSexport const mDNSOpaque16 UpdateReqFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_Update, 0 } }; mDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, 0 } }; +mDNSexport const mDNSOpaque16 SubscribeFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_Subscribe, 0 } }; +mDNSexport const mDNSOpaque16 UnSubscribeFlags= { { kDNSFlag0_QR_Query | kDNSFlag0_OP_UnSubscribe, 0 } }; mDNSexport const mDNSOpaque64 zeroOpaque64 = { { 0 } }; @@ -541,7 +544,7 @@ mDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *const rr, const RD } break; - default: mDNS_snprintf(buffer+length, RemSpc, "RDLen %d: %s", rr->rdlength, rd->data); + default: mDNS_snprintf(buffer+length, RemSpc, "RDLen %d: %.*s", rr->rdlength, rr->rdlength, rd->data); // Really should scan buffer to check if text is valid UTF-8 and only replace with dots if not for (ptr = buffer; *ptr; ptr++) if (*ptr < ' ') *ptr = '.'; break; @@ -803,6 +806,7 @@ mDNSexport mDNSu8 *AppendDNSNameString(domainname *const name, const char *cstri mDNSu8 c = (mDNSu8)*cstr++; // Read the character if (c == '\\') // If escape character, check next character { + if (*cstr == '\0') break; // If this is the end of the string, then break c = (mDNSu8)*cstr++; // Assume we'll just take the next character if (mDNSIsDigit(cstr[-1]) && mDNSIsDigit(cstr[0]) && mDNSIsDigit(cstr[1])) { // If three decimal digits, @@ -815,7 +819,7 @@ mDNSexport mDNSu8 *AppendDNSNameString(domainname *const name, const char *cstri } *ptr++ = c; // Write the character } - if (*cstr) cstr++; // Skip over the trailing dot (if present) + if (*cstr == '.') cstr++; // Skip over the trailing dot (if present) if (ptr - lengthbyte - 1 > MAX_DOMAIN_LABEL) // If illegal label, abort return(mDNSNULL); *lengthbyte = (mDNSu8)(ptr - lengthbyte - 1); // Fill in the length byte @@ -1165,7 +1169,8 @@ mDNSexport const mDNSu8 *NSEC3HashName(const domainname *name, rdataNSEC3 *nsec3 const mDNSu8 hash[NSEC3_MAX_HASH_LEN], int *dlen) { AlgContext *ctx; - int i; + unsigned int i; + unsigned int iterations; domainname lname; mDNSu8 *p = (mDNSu8 *)&nsec3->salt; const mDNSu8 *digest; @@ -1183,7 +1188,8 @@ mDNSexport const mDNSu8 *NSEC3HashName(const domainname *name, rdataNSEC3 *nsec3 // Note that it is "i <=". The first iteration is for digesting the name and salt. // The iteration count does not include that. - for (i = 0; i <= swap16(nsec3->iterations); i++) + iterations = swap16(nsec3->iterations); + for (i = 0; i <= iterations; i++) { ctx = AlgCreate(DIGEST_ALG, nsec3->alg); if (!ctx) @@ -1367,17 +1373,14 @@ mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mD if (InterfaceID == mDNSInterface_LocalOnly && artype != AuthRecordLocalOnly) { LogMsg("mDNS_SetupResourceRecord: ERROR!! Mismatch LocalOnly record InterfaceID %p called with artype %d", InterfaceID, artype); - return; } else if (InterfaceID == mDNSInterface_P2P && artype != AuthRecordP2P) { LogMsg("mDNS_SetupResourceRecord: ERROR!! Mismatch P2P record InterfaceID %p called with artype %d", InterfaceID, artype); - return; } else if (!InterfaceID && (artype == AuthRecordP2P || artype == AuthRecordLocalOnly)) { LogMsg("mDNS_SetupResourceRecord: ERROR!! Mismatch InterfaceAny record InterfaceID %p called with artype %d", InterfaceID, artype); - return; } // Don't try to store a TTL bigger than we can represent in platform time units @@ -1467,8 +1470,6 @@ mDNSexport void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID I q->ForceMCast = mDNSfalse; q->ReturnIntermed = mDNSfalse; q->SuppressUnusable = mDNSfalse; - q->DenyOnCellInterface = mDNSfalse; - q->DenyOnExpInterface = mDNSfalse; q->SearchListIndex = 0; q->AppendSearchDomains = 0; q->RetryWithSearchDomains = mDNSfalse; @@ -1779,7 +1780,7 @@ mDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr // LocalOnly/P2P questions can be answered with AuthRecordAny in this function. LocalOnly/P2P records // are handled in LocalOnlyRecordAnswersQuestion - if ((rr->InterfaceID == mDNSInterface_LocalOnly) || (rr->InterfaceID == mDNSInterface_P2P)) + if (LocalOnlyOrP2PInterface(rr->InterfaceID)) { LogMsg("SameNameRecordAnswersQuestion: ERROR!! called with LocalOnly ResourceRecord %p, Question %p", rr->InterfaceID, q->InterfaceID); return mDNSfalse; @@ -1914,7 +1915,7 @@ mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const ResourceRecord *const rr, { // LocalOnly/P2P questions can be answered with AuthRecordAny in this function. LocalOnly/P2P records // are handled in LocalOnlyRecordAnswersQuestion - if ((rr->InterfaceID == mDNSInterface_LocalOnly) || (rr->InterfaceID == mDNSInterface_P2P)) + if (LocalOnlyOrP2PInterface(rr->InterfaceID)) { LogMsg("AnyTypeRecordAnswersQuestion: ERROR!! called with LocalOnly ResourceRecord %p, Question %p", rr->InterfaceID, q->InterfaceID); return mDNSfalse; @@ -2142,7 +2143,6 @@ mDNSexport const mDNSu8 *FindCompressionPointer(const mDNSu8 *const base, const return(mDNSNULL); } -// Put a string of dot-separated labels as length-prefixed labels // domainname is a fully-qualified name (i.e. assumed to be ending in a dot, even if it doesn't) // msg points to the message we're building (pass mDNSNULL if we don't want to use compression pointers) // end points to the end of the message so far @@ -2843,7 +2843,7 @@ mDNSlocal mDNSu8 *SanityCheckBitMap(const mDNSu8 *bmap, const mDNSu8 *end, int l // (domainnames are expanded to 255 bytes) when stored in memory. // // This function can also be called with "NULL" msg to parse a single resource record pointed to by ptr. -// The caller can do this only if the names in the resource records are compressed and validity of the +// The caller can do this only if the names in the resource records are not compressed and validity of the // resource record has already been done before. DNSSEC currently uses it this way. mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *end, LargeCacheRecord *const largecr, mDNSu16 rdlength) @@ -3348,6 +3348,12 @@ mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, con dlen = DomainNameLength(&name); rlen = end - ptr; rr->resrec.rdlength = dlen + rlen; + if (rr->resrec.rdlength > MaximumRDSize) + { + LogInfo("SetRData: Malformed TSIG/TKEY rdlength %d, rr->resrec.rdlength %d, " + "bmaplen %d, name %##s", rdlength, rr->resrec.rdlength, name.c); + goto fail; + } AssignDomainName((domainname *)rdb->data, &name); mDNSPlatformMemCopy(rdb->data + dlen, ptr, rlen); break; @@ -3626,7 +3632,7 @@ mDNSexport mDNSu32 GetPktLease(mDNS *m, DNSMessage *msg, const mDNSu8 *end) mDNSlocal const mDNSu8 *DumpRecords(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end, int count, char *label) { int i; - LogMsg("%2d %s", count, label); + LogInfo("%2d %s", count, label); for (i = 0; i < count && ptr; i++) { // This puts a LargeCacheRecord on the stack instead of using the shared m->rec storage, @@ -3634,9 +3640,11 @@ mDNSlocal const mDNSu8 *DumpRecords(mDNS *const m, const DNSMessage *const msg, // embedded systems) putting a 9kB object on the stack isn't a big problem. LargeCacheRecord largecr; ptr = GetLargeResourceRecord(m, msg, ptr, end, mDNSInterface_Any, kDNSRecordTypePacketAns, &largecr); - if (ptr) LogMsg("%2d TTL%8d %s", i, largecr.r.resrec.rroriginalttl, CRDisplayString(m, &largecr.r)); + if (ptr) + LogInfo("%2d TTL%8d %s", i, largecr.r.resrec.rroriginalttl, CRDisplayString(m, &largecr.r)); } - if (!ptr) LogMsg("DumpRecords: ERROR: Premature end of packet data"); + if (!ptr) + LogInfo("DumpRecords: ERROR: Premature end of packet data"); return(ptr); } @@ -3646,7 +3654,9 @@ mDNSlocal const mDNSu8 *DumpRecords(mDNS *const m, const DNSMessage *const msg, (X) == kDNSFlag0_OP_Status ? "Status " : \ (X) == kDNSFlag0_OP_Unused3 ? "Unused3 " : \ (X) == kDNSFlag0_OP_Notify ? "Notify " : \ - (X) == kDNSFlag0_OP_Update ? "Update " : "?? " ) + (X) == kDNSFlag0_OP_Update ? "Update " : \ + (X) == kDNSFlag0_OP_Subscribe? "Subscribe": \ + (X) == kDNSFlag0_OP_UnSubscribe? "UnSubscribe" : "?? " ) #define DNS_RC_Name(X) ( \ (X) == kDNSFlag1_RC_NoErr ? "NoErr" : \ @@ -3678,7 +3688,7 @@ mDNSexport void DumpPacket(mDNS *const m, mStatus status, mDNSBool sent, char *t if (dstaddr || !mDNSIPPortIsZero(dstport)) dbuffer[mDNS_snprintf(dbuffer, sizeof(dbuffer), " to %#a:%d", dstaddr, mDNSVal16(dstport))] = 0; - LogMsg("-- %s %s DNS %s%s (flags %02X%02X) RCODE: %s (%d) %s%s%s%s%s%sID: %d %d bytes from %s%d%s%s --", + LogInfo("-- %s %s DNS %s%s (flags %02X%02X) RCODE: %s (%d) %s%s%s%s%s%sID: %d %d bytes from %s%d%s%s --", tbuffer, transport, DNS_OP_Name(msg->h.flags.b[0] & kDNSFlag0_OP_Mask), msg->h.flags.b[0] & kDNSFlag0_QR_Response ? "Response" : "Query", @@ -3697,16 +3707,16 @@ mDNSexport void DumpPacket(mDNS *const m, mStatus status, mDNSBool sent, char *t (msg->h.flags.b[0] & kDNSFlag0_TC) ? " (truncated)" : "" ); - LogMsg("%2d %s", msg->h.numQuestions, IsUpdate ? "Zone" : "Questions"); + LogInfo("%2d %s", msg->h.numQuestions, IsUpdate ? "Zone" : "Questions"); for (i = 0; i < msg->h.numQuestions && ptr; i++) { ptr = getQuestion(msg, ptr, end, mDNSInterface_Any, &q); - if (ptr) LogMsg("%2d %##s %s", i, q.qname.c, DNSTypeName(q.qtype)); + if (ptr) LogInfo("%2d %##s %s", i, q.qname.c, DNSTypeName(q.qtype)); } ptr = DumpRecords(m, msg, ptr, end, msg->h.numAnswers, IsUpdate ? "Prerequisites" : "Answers"); ptr = DumpRecords(m, msg, ptr, end, msg->h.numAuthorities, IsUpdate ? "Updates" : "Authorities"); DumpRecords(m, msg, ptr, end, msg->h.numAdditionals, "Additionals"); - LogMsg("--------------"); + LogInfo("--------------"); } // *************************************************************************** @@ -3896,6 +3906,10 @@ mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m) if (e - m->NextScheduledSPS > 0) e = m->NextScheduledSPS; if (e - m->NextScheduledKA > 0) e = m->NextScheduledKA; +#if BONJOUR_ON_DEMAND + if (m->NextBonjourDisableTime && (e - m->NextBonjourDisableTime > 0)) e = m->NextBonjourDisableTime; +#endif // BONJOUR_ON_DEMAND + // NextScheduledSPRetry only valid when DelaySleep not set if (!m->DelaySleep && m->SleepLimit && e - m->NextScheduledSPRetry > 0) e = m->NextScheduledSPRetry; if (m->DelaySleep && e - m->DelaySleep > 0) e = m->DelaySleep; @@ -3911,6 +3925,9 @@ mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m) if (e - m->NextScheduledResponse > 0) e = m->NextScheduledResponse; } if (e - m->NextScheduledStopTime > 0) e = m->NextScheduledStopTime; + + if (m->NextBLEServiceTime && (e - m->NextBLEServiceTime > 0)) e = m->NextBLEServiceTime; + return(e); } diff --git a/mDNSResponder/mDNSCore/DNSCommon.h b/mDNSResponder/mDNSCore/DNSCommon.h index e51b06dd..2da19700 100644 --- a/mDNSResponder/mDNSCore/DNSCommon.h +++ b/mDNSResponder/mDNSCore/DNSCommon.h @@ -40,17 +40,19 @@ extern "C" { typedef enum { - kDNSFlag0_QR_Mask = 0x80, // Query or response? - kDNSFlag0_QR_Query = 0x00, - kDNSFlag0_QR_Response = 0x80, - - kDNSFlag0_OP_Mask = 0x78, // Operation type - kDNSFlag0_OP_StdQuery = 0x00, - kDNSFlag0_OP_Iquery = 0x08, - kDNSFlag0_OP_Status = 0x10, - kDNSFlag0_OP_Unused3 = 0x18, - kDNSFlag0_OP_Notify = 0x20, - kDNSFlag0_OP_Update = 0x28, + kDNSFlag0_QR_Mask = 0x80, // Query or response? + kDNSFlag0_QR_Query = 0x00, + kDNSFlag0_QR_Response = 0x80, + + kDNSFlag0_OP_Mask = 0x78, // Operation type + kDNSFlag0_OP_StdQuery = 0x00, + kDNSFlag0_OP_Subscribe = 0x06, + kDNSFlag0_OP_UnSubscribe = 0x07, + kDNSFlag0_OP_Iquery = 0x08, + kDNSFlag0_OP_Status = 0x10, + kDNSFlag0_OP_Unused3 = 0x18, + kDNSFlag0_OP_Notify = 0x20, + kDNSFlag0_OP_Update = 0x28, kDNSFlag0_QROP_Mask = kDNSFlag0_QR_Mask | kDNSFlag0_OP_Mask, @@ -84,6 +86,7 @@ typedef enum TSIG_ErrBadTime = 18 } TSIG_ErrorCode; + // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - diff --git a/mDNSResponder/mDNSCore/anonymous.c b/mDNSResponder/mDNSCore/anonymous.c index 779e4ea6..aaaebc27 100644 --- a/mDNSResponder/mDNSCore/anonymous.c +++ b/mDNSResponder/mDNSCore/anonymous.c @@ -71,7 +71,7 @@ mDNSlocal mDNSBool InitializeNSEC3Record(ResourceRecord *rr, const mDNSu8 *AnonD // Hash the base service name + salt + AnonData if (!NSEC3HashName(rr->name, nsec3, AnonData, len, hashName, &hlen)) { - LogMsg("InitializeNSEC3Record: NSEC3HashName failed for ##s", rr->name->c); + LogMsg("InitializeNSEC3Record: NSEC3HashName failed for %##s", rr->name->c); return mDNSfalse; } if (hlen != SHA1_HASH_LENGTH) @@ -280,9 +280,10 @@ mDNSexport int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNS int AnonDataLen; rdataNSEC3 *nsec3; int hlen; - const mDNSu8 hashName[NSEC3_MAX_HASH_LEN]; int nxtLength; mDNSu8 *nxtName; + mDNSu8 hashName[NSEC3_MAX_HASH_LEN]; + mDNSPlatformMemZero(hashName, sizeof(hashName)); debugf("AnonInfoAnswersQuestion: question qname %##s", q->qname.c); @@ -403,7 +404,7 @@ mDNSexport int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNS if (!NSEC3HashName(nsec3RR->name, nsec3, AnonData, AnonDataLen, hashName, &hlen)) { - LogMsg("AnonInfoAnswersQuestion: NSEC3HashName failed for ##s", nsec3RR->name->c); + LogMsg("AnonInfoAnswersQuestion: NSEC3HashName failed for %##s", nsec3RR->name->c); return mDNSfalse; } if (hlen != SHA1_HASH_LENGTH) diff --git a/mDNSResponder/mDNSCore/dnsproxy.c b/mDNSResponder/mDNSCore/dnsproxy.c index 5b358864..05b70dd9 100644 --- a/mDNSResponder/mDNSCore/dnsproxy.c +++ b/mDNSResponder/mDNSCore/dnsproxy.c @@ -553,14 +553,21 @@ mDNSlocal mDNSBool CheckDNSProxyIpIntf(const mDNS *const m, mDNSInterfaceID Inte int i; mDNSu32 ip_ifindex = (mDNSu32)(unsigned long)InterfaceID; - LogInfo("CheckDNSProxyIpIntf: Stored Input Interface List: [%d] [%d] [%d] [%d] [%d]", m->dp_ipintf[0], m->dp_ipintf[1], m->dp_ipintf[2], - m->dp_ipintf[3], m->dp_ipintf[4]); + LogInfo("CheckDNSProxyIpIntf: Check for ifindex[%d] in stored input interface list: [%d] [%d] [%d] [%d] [%d]", + ip_ifindex, m->dp_ipintf[0], m->dp_ipintf[1], m->dp_ipintf[2], m->dp_ipintf[3], m->dp_ipintf[4]); - for (i = 0; i < MaxIp; i++) + if (ip_ifindex > 0) { - if (ip_ifindex == m->dp_ipintf[i]) - return mDNStrue; + for (i = 0; i < MaxIp; i++) + { + if (ip_ifindex == m->dp_ipintf[i]) + return mDNStrue; + } } + + LogMsg("CheckDNSProxyIpIntf: ifindex[%d] not in stored input interface list: [%d] [%d] [%d] [%d] [%d]", + ip_ifindex, m->dp_ipintf[0], m->dp_ipintf[1], m->dp_ipintf[2], m->dp_ipintf[3], m->dp_ipintf[4]); + return mDNSfalse; } @@ -583,7 +590,10 @@ mDNSlocal void ProxyCallbackCommon(mDNS *const m, void *socket, void *const pkt, debugf("ProxyCallbackCommon: DNS Query coming from InterfaceID %p", InterfaceID); // Ignore if the DNS Query is not from a Valid Input InterfaceID if (!CheckDNSProxyIpIntf(m, InterfaceID)) + { + LogMsg("ProxyCallbackCommon: Rejecting DNS Query coming from InterfaceID %p", InterfaceID); return; + } if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader)) { @@ -691,8 +701,7 @@ mDNSlocal void ProxyCallbackCommon(mDNS *const m, void *socket, void *const pkt, debugf("ProxyCallbackCommon: DNS Query forwarding to interface index %d", m->dp_opintf); mDNS_SetupQuestion(&pc->q, (mDNSInterfaceID)(unsigned long)m->dp_opintf, &q.qname, q.qtype, ProxyClientCallback, pc); pc->q.TimeoutQuestion = 1; - // Even though we don't care about intermediate responses, set ReturnIntermed so that - // we get the negative responses + // Set ReturnIntermed so that we get the negative responses pc->q.ReturnIntermed = mDNStrue; pc->q.ProxyQuestion = mDNStrue; pc->q.ProxyDNSSECOK = pc->DNSSECOK; @@ -735,9 +744,10 @@ mDNSexport void ProxyTCPCallback(mDNS *const m, void *socket, void *const pkt, c const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context) { LogInfo("ProxyTCPCallback: DNS Message from %#a:%d to %#a:%d length %d", srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), end - (mDNSu8 *)pkt); - // If the connection was closed from the other side, locate the client + + // If the connection was closed from the other side or incoming packet does not match stored input interface list, locate the client // state and free it. - if ((end - (mDNSu8 *)pkt) == 0) + if (((end - (mDNSu8 *)pkt) == 0) || (!CheckDNSProxyIpIntf(m, InterfaceID))) { DNSProxyClient **ppc = &DNSProxyClients; DNSProxyClient **prevpc; diff --git a/mDNSResponder/mDNSCore/dnssec.c b/mDNSResponder/mDNSCore/dnssec.c index bf9acfe8..514a488c 100644 --- a/mDNSResponder/mDNSCore/dnssec.c +++ b/mDNSResponder/mDNSCore/dnssec.c @@ -87,6 +87,7 @@ mDNSlocal mDNSBool TrustedKeyPresent(mDNS *const m, DNSSECVerifier *dv); mDNSlocal mStatus ValidateDS(DNSSECVerifier *dv); mDNSlocal void DNSSECNegativeValidationCB(mDNS *const m, DNSSECVerifier *dv, CacheGroup *cg, ResourceRecord *answer, DNSSECStatus status); mDNSlocal RRVerifier* CopyRRVerifier(RRVerifier *from); +mDNSlocal void FreeDNSSECAuthChainInfo(AuthChain *ac); // Currently we use this to convert a RRVerifier to resource record so that we can // use the standard DNS utility functions @@ -300,6 +301,8 @@ mDNSlocal AuthChain *AuthChainCopy(AuthChain *ae) if (!ac) { LogMsg("AuthChainCopy: AuthChain alloc failure"); + if (retac) + FreeDNSSECAuthChainInfo(retac); return mDNSfalse; } @@ -2523,7 +2526,9 @@ mDNSlocal void FinishDNSSECVerification(mDNS *const m, DNSSECVerifier *dv) LogDNSSEC("FinishDNSSECVerification: all rdata sets available for sig verification for %##s (%s)", dv->origName.c, DNSTypeName(dv->origType)); - mDNS_StopQuery(m, &dv->q); + // Stop outstanding query if one exists + if (dv->q.ThisQInterval != -1) + mDNS_StopQuery(m, &dv->q); if (ValidateSignature(dv, &resultKey, &resultRRSig) == mStatus_NoError) { rdataDNSKey *key; diff --git a/mDNSResponder/mDNSCore/mDNS.c b/mDNSResponder/mDNSCore/mDNS.c index 6b02be46..d1841a5e 100755 --- a/mDNSResponder/mDNSCore/mDNS.c +++ b/mDNSResponder/mDNSCore/mDNS.c @@ -49,6 +49,9 @@ #if APPLE_OSX_mDNSResponder #include +// Delay in seconds before disabling multicast after there are no active queries or registrations. +#define BONJOUR_DISABLE_DELAY 60 + #if !NO_WCF WCFConnection *WCFConnectionNew(void) __attribute__((weak_import)); void WCFConnectionDealloc(WCFConnection* c) __attribute__((weak_import)); @@ -69,7 +72,7 @@ void WCFConnectionDealloc(WCFConnection* c) __attribute__((weak_import)); // Forward declarations mDNSlocal void BeginSleepProcessing(mDNS *const m); mDNSlocal void RetrySPSRegistrations(mDNS *const m); -mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password); +mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password, mDNSBool unicastOnly); mDNSlocal mDNSBool CacheRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q); mDNSlocal mDNSBool LocalRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q); mDNSlocal void mDNS_PurgeForQuestion(mDNS *const m, DNSQuestion *q); @@ -106,16 +109,39 @@ mDNSlocal mDNSu8 *GetValueForMACAddr(mDNSu8 *ptr, mDNSu8 *limit, mDNSEthAddr *et #define NR_AnswerMulticast (mDNSu8*)~0 #define NR_AnswerUnicast (mDNSu8*)~1 -// Defined to set the kDNSQClass_UnicastResponse bit in the first four query packets. -// else, it's just set it the first query. -#define mDNS_REQUEST_UNICAST_RESPONSE 0 - // The code (see SendQueries() and BuildQuestion()) needs to have the // RequestUnicast value set to a value one greater than the number of times you want the query // sent with the "request unicast response" (QU) bit set. #define SET_QU_IN_FIRST_QUERY 2 -#define SET_QU_IN_FIRST_FOUR_QUERIES 5 +#define kDefaultRequestUnicastCount SET_QU_IN_FIRST_QUERY + +// The time needed to offload records to a sleep proxy after powerd sends the kIOMessageSystemWillSleep notification +#define DARK_WAKE_DELAY_SLEEP 5 +#define kDarkWakeDelaySleep (mDNSPlatformOneSecond * DARK_WAKE_DELAY_SLEEP) + +// The maximum number of times we delay probing to prevent spurious conflicts due to stale packets +#define MAX_CONFLICT_PROCESSING_DELAYS 3 + +// RFC 6762 defines Passive Observation Of Failures (POOF) +// +// A host observes the multicast queries issued by the other hosts on +// the network. One of the major benefits of also sending responses +// using multicast is that it allows all hosts to see the responses +// (or lack thereof) to those queries. +// +// If a host sees queries, for which a record in its cache would be +// expected to be given as an answer in a multicast response, but no +// such answer is seen, then the host may take this as an indication +// that the record may no longer be valid. +// +// After seeing two or more of these queries, and seeing no multicast +// response containing the expected answer within ten seconds, then even +// though its TTL may indicate that it is not yet due to expire, that +// record SHOULD be flushed from the cache. +// +// +#define POOF_ENABLED 1 mDNSexport const char *const mDNS_DomainTypeNames[] = { @@ -294,13 +320,13 @@ mDNSlocal AuthGroup *GetAuthGroup(AuthHash *r, const mDNSu32 slot, const Resourc // Returns the AuthGroup in which the AuthRecord was inserted mDNSexport AuthGroup *InsertAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr) { + (void)m; AuthGroup *ag; const mDNSu32 slot = AuthHashSlot(rr->resrec.name); ag = AuthGroupForRecord(r, slot, &rr->resrec); if (!ag) ag = GetAuthGroup(r, slot, &rr->resrec); // If we don't have a AuthGroup for this name, make one now if (ag) { - LogInfo("InsertAuthRecord: inserting auth record %s from table", ARDisplayString(m, rr)); *(ag->rrauth_tail) = rr; // Append this record to tail of cache slot list ag->rrauth_tail = &(rr->next); // Advance tail pointer } @@ -310,13 +336,12 @@ mDNSexport AuthGroup *InsertAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *r mDNSexport AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr) { AuthGroup *a; - AuthGroup **ag = &a; AuthRecord **rp; const mDNSu32 slot = AuthHashSlot(rr->resrec.name); a = AuthGroupForRecord(r, slot, &rr->resrec); if (!a) { LogMsg("RemoveAuthRecord: ERROR!! AuthGroup not found for %s", ARDisplayString(m, rr)); return mDNSNULL; } - rp = &(*ag)->members; + rp = &a->members; while (*rp) { if (*rp != rr) @@ -330,7 +355,7 @@ mDNSexport AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *r } } // TBD: If there are no more members, release authgroup ? - (*ag)->rrauth_tail = rp; + a->rrauth_tail = rp; return a; } @@ -412,14 +437,15 @@ mDNSexport char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID Interfa } // Caller should hold the lock -mDNSlocal void GenerateNegativeResponse(mDNS *const m, QC_result qc) +mDNSlocal void GenerateNegativeResponse(mDNS *const m, mDNSInterfaceID InterfaceID, QC_result qc) { DNSQuestion *q; if (!m->CurrentQuestion) { LogMsg("GenerateNegativeResponse: ERROR!! CurrentQuestion not set"); return; } q = m->CurrentQuestion; LogInfo("GenerateNegativeResponse: Generating negative response for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); - MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any, mDNSNULL); + MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, InterfaceID, mDNSNULL); + // We need to force the response through in the following cases // // a) SuppressUnusable questions that are suppressed @@ -447,28 +473,10 @@ mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, Re UDPSocket *sock = q->LocalSocket; mDNSOpaque16 id = q->TargetQID; #if TARGET_OS_EMBEDDED - domainname *originalQName; + uDNSMetrics metrics; #endif - // if there is a message waiting at the socket, we want to process that instead - // of throwing it away. If we have a CNAME response that answers - // both A and AAAA question and while answering it we don't want to throw - // away the response where the actual addresses are present. - // This is a stupid hack and we should get rid of it. - // The chance of there being a second unicast UDP packet already waiting in the kernel before we’ve - // finished processing the previous one is virtually nil, and will only happen by luck on very rare - // occasions when running on a machine with a fast network connection and a slow or busy processor. - // The idea that we’d rely for correctness on this random chance event occurring is ridiculous. - // -- SC - if (mDNSPlatformPeekUDP(m, q->LocalSocket)) - { - LogInfo("AnswerQuestionByFollowingCNAME: Preserving UDP socket for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); - q->LocalSocket = mDNSNULL; - } - else - { - sock = mDNSNULL; - } + q->LocalSocket = mDNSNULL; // The SameDomainName check above is to ignore bogus CNAME records that point right back at // themselves. Without that check we can get into a case where we have two duplicate questions, @@ -489,29 +497,24 @@ mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, Re q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, RRDisplayString(m, rr)); #if TARGET_OS_EMBEDDED - if (q->metrics.originalQName) - { - originalQName = q->metrics.originalQName; - q->metrics.originalQName = mDNSNULL; - } - else + if ((q->CNAMEReferrals == 0) && !q->metrics.originalQName) { - mDNSu16 qNameLen; + domainname * qName; + mDNSu16 qNameLen; qNameLen = DomainNameLength(&q->qname); if ((qNameLen > 0) && (qNameLen <= MAX_DOMAIN_NAME)) { - originalQName = mDNSPlatformMemAllocate(qNameLen); - if (originalQName) + qName = mDNSPlatformMemAllocate(qNameLen); + if (qName) { - mDNSPlatformMemCopy(originalQName->c, q->qname.c, qNameLen); + mDNSPlatformMemCopy(qName->c, q->qname.c, qNameLen); + q->metrics.originalQName = qName; } } - else - { - originalQName = mDNSNULL; - } } + metrics = q->metrics; + mDNSPlatformMemZero(&q->metrics, sizeof(q->metrics)); #endif mDNS_StopQuery_internal(m, q); // Stop old query AssignDomainName(&q->qname, &rr->rdata->u.name); // Update qname @@ -530,19 +533,96 @@ mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, Re // because mDNS_StartQuery_internal re-initializes CNAMEReferrals to zero q->CNAMEReferrals = c; #if TARGET_OS_EMBEDDED - q->metrics.originalQName = originalQName; + q->metrics = metrics; #endif if (sock) { - // We have a message waiting and that should answer this question. - if (q->LocalSocket) - mDNSPlatformUDPClose(q->LocalSocket); - q->LocalSocket = sock; - q->TargetQID = id; + // If our new query is a duplicate, then it can't have a socket of its own, so we have to close the one we saved. + if (q->DuplicateOf) mDNSPlatformUDPClose(sock); + else + { + // Transplant the old socket into the new question, and copy the query ID across too. + // No need to close the old q->LocalSocket value because it won't have been created yet (they're made lazily on-demand). + q->LocalSocket = sock; + q->TargetQID = id; + } } } } +#ifdef USE_LIBIDN + +#include + +// #define DEBUG_PUNYCODE 1 + +mDNSlocal mDNSu8 *PunycodeConvert(const mDNSu8 *const src, mDNSu8 *const dst, const mDNSu8 *const end) +{ + UErrorCode errorCode = U_ZERO_ERROR; + UIDNAInfo info = UIDNA_INFO_INITIALIZER; + UIDNA *uts46 = uidna_openUTS46(UIDNA_USE_STD3_RULES|UIDNA_NONTRANSITIONAL_TO_UNICODE, &errorCode); + int32_t len = uidna_nameToASCII_UTF8(uts46, (const char *)src+1, src[0], (char *)dst+1, end-(dst+1), &info, &errorCode); + uidna_close(uts46); + #if DEBUG_PUNYCODE + if (errorCode) LogMsg("uidna_nameToASCII_UTF8(%##s) failed errorCode %d", src, errorCode); + if (info.errors) LogMsg("uidna_nameToASCII_UTF8(%##s) failed info.errors 0x%08X", src, info.errors); + if (len > MAX_DOMAIN_LABEL) LogMsg("uidna_nameToASCII_UTF8(%##s) result too long %d", src, len); + #endif + if (errorCode || info.errors || len > MAX_DOMAIN_LABEL) return mDNSNULL; + *dst = len; + return(dst + 1 + len); +} + +mDNSlocal mDNSBool IsHighASCIILabel(const mDNSu8 *d) +{ + int i; + for (i=1; i<=d[0]; i++) if (d[i] & 0x80) return mDNStrue; + return mDNSfalse; +} + +mDNSlocal const mDNSu8 *FindLastHighASCIILabel(const domainname *const d) +{ + const mDNSu8 *ptr = d->c; + const mDNSu8 *ans = mDNSNULL; + while (ptr[0]) + { + const mDNSu8 *const next = ptr + 1 + ptr[0]; + if (ptr[0] > MAX_DOMAIN_LABEL || next >= d->c + MAX_DOMAIN_NAME) return mDNSNULL; + if (IsHighASCIILabel(ptr)) ans = ptr; + ptr = next; + } + return ans; +} + +mDNSlocal mDNSBool PerformNextPunycodeConversion(const DNSQuestion *const q, domainname *const newname) +{ + const mDNSu8 *h = FindLastHighASCIILabel(&q->qname); + #if DEBUG_PUNYCODE + LogMsg("PerformNextPunycodeConversion: %##s (%s) Last High-ASCII Label %##s", q->qname.c, DNSTypeName(q->qtype), h); + #endif + if (!h) return mDNSfalse; // There are no high-ascii labels to convert + + mDNSu8 *const dst = PunycodeConvert(h, newname->c + (h - q->qname.c), newname->c + MAX_DOMAIN_NAME); + if (!dst) + return mDNSfalse; // The label was not convertible to Punycode + else + { + // If Punycode conversion of final eligible label was successful, copy the rest of the domainname + const mDNSu8 *const src = h + 1 + h[0]; + const mDNSu8 remainder = DomainNameLength((domainname*)src); + if (dst + remainder > newname->c + MAX_DOMAIN_NAME) return mDNSfalse; // Name too long -- cannot be converted to Punycode + + mDNSPlatformMemCopy(newname->c, q->qname.c, h - q->qname.c); // Fill in the leading part + mDNSPlatformMemCopy(dst, src, remainder); // Fill in the trailing part + #if DEBUG_PUNYCODE + LogMsg("PerformNextPunycodeConversion: %##s converted to %##s", q->qname.c, newname->c); + #endif + return mDNStrue; + } +} + +#endif // USE_LIBIDN + // For a single given DNSQuestion pointed to by CurrentQuestion, deliver an add/remove result for the single given AuthRecord // Note: All the callers should use the m->CurrentQuestion to see if the question is still valid or not mDNSlocal void AnswerLocalQuestionWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord) @@ -766,6 +846,8 @@ mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, cons pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse); if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) || authrr->WakeUp.HMAC.l[0]) if (pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse); + if ((authrr->resrec.InterfaceID == mDNSInterface_Any) && + !mDNSPlatformValidRecordForInterface(authrr, pktrr->resrec.InterfaceID)) return(mDNSfalse); return (mDNSBool)( pktrr->resrec.rrclass == authrr->resrec.rrclass && pktrr->resrec.namehash == authrr->resrec.namehash && @@ -843,11 +925,12 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr) if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0) { // To allow us to aggregate probes when a group of services are registered together, - // the first probe is delayed 1/4 second. This means the common-case behaviour is: - // 1/4 second wait; probe + // the first probe is delayed by a random delay in the range 1/8 to 1/4 second. + // This means the common-case behaviour is: + // randomized wait; probe // 1/4 second wait; probe // 1/4 second wait; probe - // 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered) + // 1/4 second wait; announce (i.e. service is normally announced 7/8 to 1 second after being registered) m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique/2 + mDNSRandom(DefaultProbeIntervalForTypeUnique/2)); // If we already have a *probe* scheduled to go out sooner, then use that time to get better aggregation @@ -879,7 +962,9 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr) } rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval; } - else if (m->SuppressProbes && m->SuppressProbes - m->timenow >= 0) + // Skip kDNSRecordTypeKnownUnique records here and set their LastAPTime in the "else" block below so that they get announced immediately, + // otherwise, their announcement would be delayed until all other record probes complete. + else if ((rr->resrec.RecordType != kDNSRecordTypeKnownUnique) && m->SuppressProbes && m->SuppressProbes - m->timenow >= 0) rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval + DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2; else rr->LastAPTime = m->timenow - rr->ThisAPInterval; @@ -890,7 +975,7 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr) // and we can begin broadcasting our announcements to take over ownership of that IP address. // If we don't wait for the client to go to sleep, then when the client sees our ARP Announcements there's a risk // (depending on the OS and networking stack it's using) that it might interpret it as a conflict and change its IP address. - if (rr->AddressProxy.type) + if (rr->AddressProxy.type) rr->LastAPTime = m->timenow; // Set LastMCTime to now, to inhibit multicast responses @@ -1068,26 +1153,25 @@ mDNSexport void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr) mDNSlocal AuthRecord *CheckAuthIdenticalRecord(AuthHash *r, AuthRecord *rr) { - AuthGroup *a; - AuthGroup **ag = &a; - AuthRecord **rp; + const AuthGroup *a; + AuthRecord *rp; const mDNSu32 slot = AuthHashSlot(rr->resrec.name); a = AuthGroupForRecord(r, slot, &rr->resrec); if (!a) return mDNSNULL; - rp = &(*ag)->members; - while (*rp) + rp = a->members; + while (rp) { - if (!RecordIsLocalDuplicate(*rp, rr)) - rp=&(*rp)->next; + if (!RecordIsLocalDuplicate(rp, rr)) + rp = rp->next; else { - if ((*rp)->resrec.RecordType == kDNSRecordTypeDeregistering) + if (rp->resrec.RecordType == kDNSRecordTypeDeregistering) { - (*rp)->AnnounceCount = 0; - rp=&(*rp)->next; + rp->AnnounceCount = 0; + rp = rp->next; } - else return *rp; + else return rp; } } return (mDNSNULL); @@ -1095,22 +1179,21 @@ mDNSlocal AuthRecord *CheckAuthIdenticalRecord(AuthHash *r, AuthRecord *rr) mDNSlocal mDNSBool CheckAuthRecordConflict(AuthHash *r, AuthRecord *rr) { - AuthGroup *a; - AuthGroup **ag = &a; - AuthRecord **rp; + const AuthGroup *a; + const AuthRecord *rp; const mDNSu32 slot = AuthHashSlot(rr->resrec.name); a = AuthGroupForRecord(r, slot, &rr->resrec); if (!a) return mDNSfalse; - rp = &(*ag)->members; - while (*rp) + rp = a->members; + while (rp) { const AuthRecord *s1 = rr->RRSet ? rr->RRSet : rr; - const AuthRecord *s2 = (*rp)->RRSet ? (*rp)->RRSet : *rp; - if (s1 != s2 && SameResourceRecordSignature((*rp), rr) && !IdenticalSameNameRecord(&(*rp)->resrec, &rr->resrec)) + const AuthRecord *s2 = rp->RRSet ? rp->RRSet : rp; + if (s1 != s2 && SameResourceRecordSignature(rp, rr) && !IdenticalSameNameRecord(&rp->resrec, &rr->resrec)) return mDNStrue; else - rp=&(*rp)->next; + rp = rp->next; } return (mDNSfalse); } @@ -1118,21 +1201,20 @@ mDNSlocal mDNSBool CheckAuthRecordConflict(AuthHash *r, AuthRecord *rr) // checks to see if "rr" is already present mDNSlocal AuthRecord *CheckAuthSameRecord(AuthHash *r, AuthRecord *rr) { - AuthGroup *a; - AuthGroup **ag = &a; - AuthRecord **rp; + const AuthGroup *a; + AuthRecord *rp; const mDNSu32 slot = AuthHashSlot(rr->resrec.name); a = AuthGroupForRecord(r, slot, &rr->resrec); if (!a) return mDNSNULL; - rp = &(*ag)->members; - while (*rp) + rp = a->members; + while (rp) { - if (*rp != rr) - rp=&(*rp)->next; + if (rp != rr) + rp = rp->next; else { - return *rp; + return rp; } } return (mDNSNULL); @@ -1158,20 +1240,22 @@ mDNSlocal void DecrementAutoTargetServices(mDNS *const m, AuthRecord *const rr) LogInfo("DecrementAutoTargetServices: AutoTargetServices %d Record %s", m->AutoTargetServices, ARDisplayString(m, rr)); } -#if TARGET_OS_WATCH +#if BONJOUR_ON_DEMAND if (!AuthRecord_uDNS(rr)) { if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1) - m->NetworkChanged = m->timenow; + m->NextBonjourDisableTime = NonZeroTime(m->timenow + (BONJOUR_DISABLE_DELAY * mDNSPlatformOneSecond)); m->NumAllInterfaceRecords--; LogInfo("DecrementAutoTargetServices: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %s", m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, ARDisplayString(m, rr)); } -#endif +#endif // BONJOUR_ON_DEMAND } mDNSlocal void IncrementAutoTargetServices(mDNS *const m, AuthRecord *const rr) { + mDNSBool enablingBonjour = 0; + if (RRLocalOnly(rr)) { // A sanity check, this should be prevented in calling code. @@ -1179,34 +1263,51 @@ mDNSlocal void IncrementAutoTargetServices(mDNS *const m, AuthRecord *const rr) return; } -#if TARGET_OS_WATCH +#if BONJOUR_ON_DEMAND if (!AuthRecord_uDNS(rr)) { m->NumAllInterfaceRecords++; LogInfo("IncrementAutoTargetServices: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %s", m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, ARDisplayString(m, rr)); if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1) - m->NetworkChanged = m->timenow; + { + m->NextBonjourDisableTime = 0; + if (m->BonjourEnabled == 0) + { + // Enable Bonjour immediately by scheduling network changed processing where + // we will join the multicast group on each active interface. + m->BonjourEnabled = 1; + enablingBonjour = 1; + m->NetworkChanged = m->timenow; + } + } } -#endif +#endif // BONJOUR_ON_DEMAND if (!AuthRecord_uDNS(rr) && rr->resrec.rrtype == kDNSType_SRV && rr->AutoTarget == Target_AutoHost) { m->AutoTargetServices++; LogInfo("IncrementAutoTargetServices: AutoTargetServices %d Record %s", m->AutoTargetServices, ARDisplayString(m, rr)); - // If this is the first advertised service - if (m->AutoTargetServices == 1) + + // If this is the first advertised service and we did not just enable Bonjour above, then + // advertise all the interface records. If we did enable Bonjour above, the interface records will + // be advertised during the network changed processing scheduled above, so no need + // to do it here. + if ((m->AutoTargetServices == 1) && (enablingBonjour == 0)) AdvertiseAllInterfaceRecords(m); } } mDNSlocal void getKeepaliveRaddr(mDNS *const m, AuthRecord *rr, mDNSAddr *raddr) { - mDNSAddr laddr; - mDNSEthAddr eth; - mDNSIPPort lport, rport; - mDNSu32 timeout, seq, ack; - mDNSu16 win; + mDNSAddr laddr = zeroAddr; + mDNSEthAddr eth = zeroEthAddr; + mDNSIPPort lport = zeroIPPort; + mDNSIPPort rport = zeroIPPort; + mDNSu32 timeout = 0; + mDNSu32 seq = 0; + mDNSu32 ack = 0; + mDNSu16 win = 0; if (mDNS_KeepaliveRecord(&rr->resrec)) { @@ -1305,15 +1406,15 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) // Set up by client prior to call // Field Group 2: Persistent metadata for Authoritative Records -// rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client -// rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client -// rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client -// rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client -// rr->Callback = already set in mDNS_SetupResourceRecord -// rr->Context = already set in mDNS_SetupResourceRecord -// rr->RecordType = already set in mDNS_SetupResourceRecord -// rr->HostTarget = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client -// rr->AllowRemoteQuery = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client +// rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client +// rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client +// rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client +// rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client +// rr->Callback = already set in mDNS_SetupResourceRecord +// rr->Context = already set in mDNS_SetupResourceRecord +// rr->RecordType = already set in mDNS_SetupResourceRecord +// rr->HostTarget = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client +// rr->AllowRemoteQuery = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client // Make sure target is not uninitialized data, or we may crash writing debugging log messages if (rr->AutoTarget && target) target->c[0] = 0; @@ -1336,9 +1437,9 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; if (!rr->AutoTarget) InitializeLastAPTime(m, rr); -// rr->LastAPTime = Set for us in InitializeLastAPTime() -// rr->LastMCTime = Set for us in InitializeLastAPTime() -// rr->LastMCInterface = Set for us in InitializeLastAPTime() +// rr->LastAPTime = Set for us in InitializeLastAPTime() +// rr->LastMCTime = Set for us in InitializeLastAPTime() +// rr->LastMCInterface = Set for us in InitializeLastAPTime() rr->NewRData = mDNSNULL; rr->newrdlength = 0; rr->UpdateCallback = mDNSNULL; @@ -1371,12 +1472,12 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) // times with different values if the external NAT port changes during the lifetime of the service registration. //if (rr->resrec.rrtype == kDNSType_SRV) rr->NATinfo.IntPort = rr->resrec.rdata->u.srv.port; -// rr->resrec.interface = already set in mDNS_SetupResourceRecord -// rr->resrec.name->c = MUST be set by client -// rr->resrec.rrtype = already set in mDNS_SetupResourceRecord -// rr->resrec.rrclass = already set in mDNS_SetupResourceRecord -// rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord -// rr->resrec.rdata = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set +// rr->resrec.interface = already set in mDNS_SetupResourceRecord +// rr->resrec.name->c = MUST be set by client +// rr->resrec.rrtype = already set in mDNS_SetupResourceRecord +// rr->resrec.rrclass = already set in mDNS_SetupResourceRecord +// rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord +// rr->resrec.rdata = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct, // since RFC 1035 specifies a TXT record as "One or more s", not "Zero or more s". @@ -1471,7 +1572,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) if (r) { - debugf("mDNS_Register_internal:Adding to duplicate list %s", ARDisplayString(m,rr)); + LogInfo("mDNS_Register_internal: Adding to duplicate list %s", ARDisplayString(m,rr)); *d = rr; // If the previous copy of this record is already verified unique, // then indicate that we should move this record promptly to kDNSRecordTypeUnique state. @@ -1482,7 +1583,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) } else { - debugf("mDNS_Register_internal: Adding to active record list %s", ARDisplayString(m,rr)); + LogInfo("mDNS_Register_internal: Adding to active record list %s", ARDisplayString(m,rr)); if (RRLocalOnly(rr)) { AuthGroup *ag; @@ -1504,6 +1605,19 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) } } + if (!AuthRecord_uDNS(rr)) // This check is superfluous, given that for unicast records we (currently) bail out above + { + // We have inserted the record in the list. See if we have to advertise the A/AAAA, HINFO, PTR records. + IncrementAutoTargetServices(m, rr); + + // For records that are not going to probe, acknowledge them right away + if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering) + AcknowledgeRecord(m, rr); + + // Adding a record may affect whether or not we should sleep + mDNS_UpdateAllowSleep(m); + } + // If this is a non-sleep proxy keepalive record, fetch the MAC address of the remote host. // This is used by the in-NIC proxy to send the keepalive packets. if (!rr->WakeUp.HMAC.l[0] && mDNS_KeepaliveRecord(&rr->resrec)) @@ -1519,19 +1633,6 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) mDNSPlatformGetRemoteMacAddr(m, &raddr); } - if (!AuthRecord_uDNS(rr)) // This check is superfluous, given that for unicast records we (currently) bail out above - { - // We have inserted the record in the list. See if we have to advertise the A/AAAA, HINFO, PTR records. - IncrementAutoTargetServices(m, rr); - - // For records that are not going to probe, acknowledge them right away - if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering) - AcknowledgeRecord(m, rr); - - // Adding a record may affect whether or not we should sleep - mDNS_UpdateAllowSleep(m); - } - return(mStatus_NoError); } @@ -1577,13 +1678,12 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, if (RRLocalOnly(rr)) { AuthGroup *a; - AuthGroup **ag = &a; AuthRecord **rp; const mDNSu32 slot = AuthHashSlot(rr->resrec.name); a = AuthGroupForRecord(&m->rrauth, slot, &rr->resrec); if (!a) return mDNSfalse; - rp = &(*ag)->members; + rp = &a->members; while (*rp && *rp != rr) rp=&(*rp)->next; p = rp; } @@ -1793,7 +1893,7 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, if (drt != mDNS_Dereg_conflict) { mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback - LogInfo("mDNS_Deregister_internal: mStatus_MemFree for %s", ARDisplayString(m, rr)); + LogInfo("mDNS_Deregister_internal: callback with mStatus_MemFree for %s", ARDisplayString(m, rr)); if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_MemFree); // MUST NOT touch rr after this mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again @@ -1817,6 +1917,10 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, } else { +#if APPLE_OSX_mDNSResponder + // See if this record was also registered with any D2D plugins. + D2D_stop_advertising_record(r2); +#endif mDNS_Deregister_internal(m, r2, mDNS_Dereg_conflict); // As this is a duplicate record, it will be unlinked from the list // immediately @@ -1927,9 +2031,8 @@ mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const d rr->v6Requester = zerov6Addr; // Only sent records registered for P2P over P2P interfaces - if (intf && !mDNSPlatformValidRecordForInterface(rr, intf)) + if (intf && !mDNSPlatformValidRecordForInterface(rr, intf->InterfaceID)) { - LogInfo("SendDelayedUnicastResponse: Not sending %s, on %s", ARDisplayString(m, rr), InterfaceNameForID(m, InterfaceID)); continue; } @@ -2343,6 +2446,22 @@ mDNSlocal mDNSBool ShouldSendGoodbyesBeforeSleep(mDNS *const m, const NetworkInt } } +mDNSlocal mDNSBool IsInterfaceValidForAuthRecord(const AuthRecord *ar, mDNSInterfaceID InterfaceID) +{ + mDNSBool result; + + if (ar->resrec.InterfaceID == mDNSInterface_Any) + { + result = mDNSPlatformValidRecordForInterface(ar, InterfaceID); + } + else + { + result = (ar->resrec.InterfaceID == InterfaceID); + } + + return(result); +} + // Note about acceleration of announcements to facilitate automatic coalescing of // multiple independent threads of announcements into a single synchronized thread: // The announcements in the packet may be at different stages of maturity; @@ -2404,8 +2523,10 @@ mDNSlocal void SendResponses(mDNS *const m) } else { + mDNSBool unicastOnly; LogSPS("SendResponses: Sending wakeup %2d for %.6a %s", rr->AnnounceCount-3, &rr->WakeUp.IMAC, ARDisplayString(m, rr)); - SendWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.IMAC, &rr->WakeUp.password); + unicastOnly = ((rr->AnnounceCount == WakeupCount) || (rr->AnnounceCount == WakeupCount - 1)) ? mDNStrue : mDNSfalse; + SendWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.IMAC, &rr->WakeUp.password, unicastOnly); for (r2 = rr; r2; r2=r2->next) if ((r2->resrec.RecordType == kDNSRecordTypeDeregistering) && r2->AnnounceCount && (r2->resrec.InterfaceID == rr->resrec.InterfaceID) && mDNSSameEthAddress(&r2->WakeUp.IMAC, &rr->WakeUp.IMAC) && !mDNSSameEthAddress(&zeroEthAddr, &r2->WakeUp.HMAC)) @@ -2506,17 +2627,28 @@ mDNSlocal void SendResponses(mDNS *const m) if (rr->ImmedAnswer) // If we're sending this as answer, see that its whole RRSet is similarly marked { for (r2 = m->ResourceRecords; r2; r2=r2->next) - if (ResourceRecordIsValidAnswer(r2)) - if (r2->ImmedAnswer != mDNSInterfaceMark && - r2->ImmedAnswer != rr->ImmedAnswer && SameResourceRecordSignature(r2, rr)) - r2->ImmedAnswer = !r2->ImmedAnswer ? rr->ImmedAnswer : mDNSInterfaceMark; + { + if ((r2->resrec.RecordType & kDNSRecordTypeUniqueMask) && ResourceRecordIsValidAnswer(r2) && + (r2->ImmedAnswer != mDNSInterfaceMark) && (r2->ImmedAnswer != rr->ImmedAnswer) && + SameResourceRecordSignature(r2, rr) && + ((rr->ImmedAnswer == mDNSInterfaceMark) || IsInterfaceValidForAuthRecord(r2, rr->ImmedAnswer))) + { + r2->ImmedAnswer = !r2->ImmedAnswer ? rr->ImmedAnswer : mDNSInterfaceMark; + } + } } else if (rr->ImmedAdditional) // If we're sending this as additional, see that its whole RRSet is similarly marked { for (r2 = m->ResourceRecords; r2; r2=r2->next) - if (ResourceRecordIsValidAnswer(r2)) - if (r2->ImmedAdditional != rr->ImmedAdditional && SameResourceRecordSignature(r2, rr)) - r2->ImmedAdditional = rr->ImmedAdditional; + { + if ((r2->resrec.RecordType & kDNSRecordTypeUniqueMask) && ResourceRecordIsValidAnswer(r2) && + (r2->ImmedAdditional != rr->ImmedAdditional) && + SameResourceRecordSignature(r2, rr) && + IsInterfaceValidForAuthRecord(r2, rr->ImmedAdditional)) + { + r2->ImmedAdditional = rr->ImmedAdditional; + } + } } } @@ -2529,6 +2661,7 @@ mDNSlocal void SendResponses(mDNS *const m) rr->ImmedAdditional = mDNSNULL; // No need to send as additional if sending as answer rr->LastMCTime = m->timenow; rr->LastMCInterface = rr->ImmedAnswer; + rr->ProbeRestartCount = 0; // Reset the probe restart count // If we're announcing this record, and it's at least half-way to its ordained time, then consider this announcement done if (TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2)) { @@ -2576,9 +2709,8 @@ mDNSlocal void SendResponses(mDNS *const m) // Skip this interface if the record InterfaceID is *Any and the record is not // appropriate for the interface type. if ((rr->SendRNow == intf->InterfaceID) && - ((rr->resrec.InterfaceID == mDNSInterface_Any) && !mDNSPlatformValidRecordForInterface(rr, intf))) + ((rr->resrec.InterfaceID == mDNSInterface_Any) && !mDNSPlatformValidRecordForInterface(rr, intf->InterfaceID))) { - // LogInfo("SendResponses: Not sending %s, on %s", ARDisplayString(m, rr), InterfaceNameForID(m, rr->SendRNow)); rr->SendRNow = GetNextActiveInterfaceID(intf); } else if (rr->SendRNow == intf->InterfaceID) @@ -2651,7 +2783,7 @@ mDNSlocal void SendResponses(mDNS *const m) // Get the reserved space back OwnerRecordSpace -= AnoninfoSpace; - TraceRecordSpace -= AnoninfoSpace; + TraceRecordSpace -= AnoninfoSpace; newptr = responseptr; for (rr = m->ResourceRecords; rr; rr=rr->next) { @@ -2800,10 +2932,9 @@ mDNSlocal void SendResponses(mDNS *const m) SetupTracerOpt(m, &opt.resrec.rdata->u.opt[0]); } newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &opt.resrec); - if (newptr) - { - responseptr = newptr; - LogInfo("SendResponses put %s %s: %s %s", OwnerRecordSpace ? "OWNER" : "", TraceRecordSpace ? "TRACER" : "", intf->ifname, ARDisplayString(m, &opt)); + if (newptr) + { + responseptr = newptr; } else if (m->omsg.h.numAnswers + m->omsg.h.numAuthorities + m->omsg.h.numAdditionals == 1) { @@ -2816,7 +2947,7 @@ mDNSlocal void SendResponses(mDNS *const m) m->omsg.h.numQuestions, m->omsg.h.numAnswers, m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt)); } } - + debugf("SendResponses: Sending %d Deregistration%s, %d Announcement%s, %d Answer%s, %d Additional%s on %p", numDereg, numDereg == 1 ? "" : "s", numAnnounce, numAnnounce == 1 ? "" : "s", @@ -3097,11 +3228,11 @@ mDNSlocal const CacheRecord *FindSPSInCache1(mDNS *const m, const DNSQuestion *c } return(bestcr); #else // SPC_DISABLED - (void) m; - (void) q; - (void) c0; - (void) c1; - (void) c1; + (void) m; + (void) q; + (void) c0; + (void) c1; + (void) c1; return mDNSNULL; #endif // SPC_DISABLED } @@ -3199,7 +3330,7 @@ mDNSlocal void mDNSSendWakeOnResolve(mDNS *const m, DNSQuestion *q) domainname *d = &q->qname; // We can't send magic packets without knowing which interface to send it on. - if (InterfaceID == mDNSInterface_Any || InterfaceID == mDNSInterface_LocalOnly || InterfaceID == mDNSInterface_P2P) + if (InterfaceID == mDNSInterface_Any || LocalOnlyOrP2PInterface(InterfaceID)) { LogMsg("mDNSSendWakeOnResolve: ERROR!! Invalid InterfaceID %p for question %##s", InterfaceID, q->qname.c); return; @@ -3415,7 +3546,7 @@ mDNSlocal void SendQueries(mDNS *const m) // don't send it again until MaxQuestionInterval unless: // one of its cached answers needs to be refreshed, // or it's the initial query for a kDNSServiceFlagsThresholdFinder mode browse. - if (q->BrowseThreshold + if (q->BrowseThreshold && (q->CurrentAnswers >= q->BrowseThreshold) && (q->CachedAnswerNeedsUpdate == mDNSfalse) && !((q->flags & kDNSServiceFlagsThresholdFinder) && (q->ThisQInterval == InitialQuestionInterval))) @@ -3437,7 +3568,7 @@ mDNSlocal void SendQueries(mDNS *const m) debugf("SendQueries: %##s (%s) next interval %d seconds RequestUnicast = %d", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval / InitialQuestionInterval, q->RequestUnicast); - if (q->ThisQInterval >= QuestionIntervalThreshold) + if (q->ThisQInterval > MaxQuestionInterval) { q->ThisQInterval = MaxQuestionInterval; } @@ -3500,11 +3631,11 @@ mDNSlocal void SendQueries(mDNS *const m) { if (ar->AddressProxy.type == mDNSAddrType_IPv4) { - // There's a problem here. If a host is waking up, and we probe to see if it responds, then - // it will see those ARP probes as signalling intent to use the address, so it picks a different one. - // A more benign way to find out if a host is responding to ARPs might be send a standard ARP *request* - // (using our sender IP address) instead of an ARP *probe* (using all-zero sender IP address). - // A similar concern may apply to the NDP Probe too. -- SC + // There's a problem here. If a host is waking up, and we probe to see if it responds, then + // it will see those ARP probes as signalling intent to use the address, so it picks a different one. + // A more benign way to find out if a host is responding to ARPs might be send a standard ARP *request* + // (using our sender IP address) instead of an ARP *probe* (using all-zero sender IP address). + // A similar concern may apply to the NDP Probe too. -- SC LogSPS("SendQueries ARP Probe %d %s %s", ar->ProbeCount, InterfaceNameForID(m, ar->resrec.InterfaceID), ARDisplayString(m,ar)); SendARP(m, 1, ar, &zerov4Addr, &zeroEthAddr, &ar->AddressProxy.ip.v4, &ar->WakeUp.IMAC); } @@ -3596,7 +3727,6 @@ mDNSlocal void SendQueries(mDNS *const m) // If interface is P2P type, verify that query should be sent over it. if (!mDNSPlatformValidQuestionForInterface(q, intf)) { - LogInfo("SendQueries: Not sending (%s) %##s on %s", DNSTypeName(q->qtype), q->qname.c, InterfaceNameForID(m, intf->InterfaceID)); q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf); } // If we're suppressing this question, or we successfully put it, update its SendQNow state @@ -3636,24 +3766,62 @@ mDNSlocal void SendQueries(mDNS *const m) // Put probe questions in this packet for (ar = m->ResourceRecords; ar; ar=ar->next) - if (ar->SendRNow == intf->InterfaceID) + { + if (ar->SendRNow != intf->InterfaceID) + continue; + + // If interface is a P2P variant, verify that the probe should be sent over it. + if (!mDNSPlatformValidRecordForInterface(ar, intf->InterfaceID)) + { + ar->SendRNow = (ar->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf); + ar->IncludeInProbe = mDNSfalse; + } + else { mDNSBool ucast = (ar->ProbeCount >= DefaultProbeCountForTypeUnique-1) && m->CanReceiveUnicastOn5353 && intf->SupportsUnicastMDNSResponse; mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0); const mDNSu8 *const limit = m->omsg.data + (m->omsg.h.numQuestions ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData); // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n) mDNSu32 forecast = answerforecast + 12 + ar->resrec.rdestimate; - mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit - forecast, ar->resrec.name, kDNSQType_ANY, (mDNSu16)(ar->resrec.rrclass | ucbit)); - if (newptr) + mDNSBool putProbe = mDNStrue; + mDNSu16 qclass = ar->resrec.rrclass | ucbit; + + {// Determine if this probe question is already in packet's dns message + const mDNSu8 *questionptr = m->omsg.data; + DNSQuestion question; + mDNSu16 n; + for (n = 0; n < m->omsg.h.numQuestions && questionptr; n++) + { + questionptr = getQuestion(&m->omsg, questionptr, limit, mDNSInterface_Any, &question); + if (questionptr && (question.qtype == kDNSQType_ANY) && (question.qclass == qclass) && + (question.qnamehash == ar->resrec.namehash) && SameDomainName(&question.qname, ar->resrec.name)) + { + putProbe = mDNSfalse; // set to false if already in message + break; + } + } + } + + if (putProbe) + { + mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit - forecast, ar->resrec.name, kDNSQType_ANY, qclass); + if (newptr) + { + queryptr = newptr; + answerforecast = forecast; + ar->SendRNow = (ar->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf); + ar->IncludeInProbe = mDNStrue; + verbosedebugf("SendQueries: Put Question %##s (%s) probecount %d InterfaceID= %d %d %d", + ar->resrec.name->c, DNSTypeName(ar->resrec.rrtype), ar->ProbeCount, ar->resrec.InterfaceID, ar->resrec.rdestimate, answerforecast); + } + } + else { - queryptr = newptr; - answerforecast = forecast; ar->SendRNow = (ar->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf); ar->IncludeInProbe = mDNStrue; - verbosedebugf("SendQueries: Put Question %##s (%s) probecount %d", - ar->resrec.name->c, DNSTypeName(ar->resrec.rrtype), ar->ProbeCount); } } + } } // Put our known answer list (either new one from this question or questions, or remainder of old one from last time) @@ -3719,7 +3887,7 @@ mDNSlocal void SendQueries(mDNS *const m) AuthRecord opt; mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL); opt.resrec.rrclass = NormalMaxDNSMessageData; - opt.resrec.rdlength = sizeof(rdataOPT); + opt.resrec.rdlength = sizeof(rdataOPT); opt.resrec.rdestimate = sizeof(rdataOPT); if (OwnerRecordSpace && TraceRecordSpace) { @@ -3736,19 +3904,18 @@ mDNSlocal void SendQueries(mDNS *const m) { SetupTracerOpt(m, &opt.resrec.rdata->u.opt[0]); } - LogInfo("SendQueries putting %s %s: %s %s", OwnerRecordSpace ? "OWNER" : "", TraceRecordSpace ? "TRACER" : "", intf->ifname, ARDisplayString(m, &opt)); queryptr = PutResourceRecordTTLWithLimit(&m->omsg, queryptr, &m->omsg.h.numAdditionals, &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData); if (!queryptr) - { + { LogMsg("SendQueries: How did we fail to have space for %s %s OPT record (%d/%d/%d/%d) %s", OwnerRecordSpace ? "OWNER" : "", TraceRecordSpace ? "TRACER" : "", m->omsg.h.numQuestions, m->omsg.h.numAnswers, m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt)); } if (queryptr > m->omsg.data + NormalMaxDNSMessageData) { if (m->omsg.h.numQuestions != 1 || m->omsg.h.numAnswers != 0 || m->omsg.h.numAuthorities != 1 || m->omsg.h.numAdditionals != 1) - LogMsg("SendQueries: Why did we generate oversized packet with %s %s OPT record %p %p %p (%d/%d/%d/%d) %s", OwnerRecordSpace ? "OWNER" : "", - TraceRecordSpace ? "TRACER" : "", m->omsg.data, m->omsg.data + NormalMaxDNSMessageData, queryptr, m->omsg.h.numQuestions, m->omsg.h.numAnswers, + LogMsg("SendQueries: Why did we generate oversized packet with %s %s OPT record %p %p %p (%d/%d/%d/%d) %s", OwnerRecordSpace ? "OWNER" : "", + TraceRecordSpace ? "TRACER" : "", m->omsg.data, m->omsg.data + NormalMaxDNSMessageData, queryptr, m->omsg.h.numQuestions, m->omsg.h.numAnswers, m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt)); } } @@ -3817,17 +3984,21 @@ mDNSlocal void SendQueries(mDNS *const m) { DNSQuestion *x; for (x = m->NewQuestions; x; x=x->next) if (x == q) break; // Check if this question is a NewQuestion - LogInfo("SendQueries: No active interface %d to send %s question: %d %##s (%s)", - (uint32_t)q->SendQNow, x ? "new" : "old", (uint32_t)q->InterfaceID, q->qname.c, DNSTypeName(q->qtype)); + // There will not be an active interface for questions applied to mDNSInterface_BLE + // so don't log the warning in that case. + if (q->InterfaceID != mDNSInterface_BLE) + LogInfo("SendQueries: No active interface %d to send %s question: %d %##s (%s)", + (uint32_t)q->SendQNow, x ? "new" : "old", (uint32_t)q->InterfaceID, q->qname.c, DNSTypeName(q->qtype)); q->SendQNow = mDNSNULL; } q->CachedAnswerNeedsUpdate = mDNSfalse; } } -mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password) +mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password, mDNSBool unicastOnly) { int i, j; + mDNSu8 *ptr = m->omsg.data; NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID); if (!intf) { LogMsg("SendARP: No interface with InterfaceID %p found", InterfaceID); return; } @@ -3853,13 +4024,16 @@ mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAdd mDNSPlatformSendRawPacket(m->omsg.data, ptr, InterfaceID); - // For Ethernet switches that don't flood-foward packets with unknown unicast destination MAC addresses, - // broadcast is the only reliable way to get a wakeup packet to the intended target machine. - // For 802.11 WPA networks, where a sleeping target machine may have missed a broadcast/multicast - // key rotation, unicast is the only way to get a wakeup packet to the intended target machine. - // So, we send one of each, unicast first, then broadcast second. - for (i=0; i<6; i++) m->omsg.data[i] = 0xFF; - mDNSPlatformSendRawPacket(m->omsg.data, ptr, InterfaceID); + if (!unicastOnly) + { + // For Ethernet switches that don't flood-foward packets with unknown unicast destination MAC addresses, + // broadcast is the only reliable way to get a wakeup packet to the intended target machine. + // For 802.11 WPA networks, where a sleeping target machine may have missed a broadcast/multicast + // key rotation, unicast is the only way to get a wakeup packet to the intended target machine. + // So, we send one of each, unicast first, then broadcast second. + for (i=0; i<6; i++) m->omsg.data[i] = 0xFF; + mDNSPlatformSendRawPacket(m->omsg.data, ptr, InterfaceID); + } } // *************************************************************************** @@ -3891,7 +4065,7 @@ mDNSlocal void ResetQuestionState(mDNS *const m, DNSQuestion *q) mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheRecord *const rr, const QC_result AddRecord) { DNSQuestion *const q = m->CurrentQuestion; - mDNSBool followcname = FollowCNAME(q, &rr->resrec, AddRecord); + const mDNSBool followcname = FollowCNAME(q, &rr->resrec, AddRecord); verbosedebugf("AnswerCurrentQuestionWithResourceRecord:%4lu %s TTL %d %s", q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, CRDisplayString(m, rr)); @@ -3937,28 +4111,32 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco } #if TARGET_OS_EMBEDDED - if ((AddRecord == QC_add) && Question_uDNS(q) && (!q->metrics.answered || (q->metrics.querySendCount > 0))) + if ((AddRecord == QC_add) && Question_uDNS(q) && !followcname) { - uDNSMetrics * metrics; const domainname * queryName; mDNSu32 responseLatencyMs; mDNSBool isForCellular; - metrics = &q->metrics; - queryName = metrics->originalQName ? metrics->originalQName : &q->qname; - if (metrics->querySendCount > 0) + queryName = q->metrics.originalQName ? q->metrics.originalQName : &q->qname; + isForCellular = (q->qDNSServer && q->qDNSServer->cellIntf); + if (!q->metrics.answered) { - responseLatencyMs = ((m->timenow - metrics->firstQueryTime) * 1000) / mDNSPlatformOneSecond; + if (q->metrics.querySendCount > 0) + { + responseLatencyMs = ((m->timenow - q->metrics.firstQueryTime) * 1000) / mDNSPlatformOneSecond; + } + else + { + responseLatencyMs = 0; + } + + MetricsUpdateUDNSQueryStats(queryName, q->qtype, &rr->resrec, q->metrics.querySendCount, responseLatencyMs, isForCellular); + q->metrics.answered = mDNStrue; } - else + if (q->metrics.querySendCount > 0) { - responseLatencyMs = 0; + MetricsUpdateUDNSResolveStats(queryName, &rr->resrec, isForCellular); } - isForCellular = (q->qDNSServer && q->qDNSServer->cellIntf); - - MetricsUpdateUDNSStats(queryName, mDNStrue, metrics->querySendCount, responseLatencyMs, isForCellular); - metrics->answered = mDNStrue; - metrics->querySendCount = 0; } #endif // Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerCurrentQuestionWithResourceRecord(... mDNStrue) @@ -3991,6 +4169,30 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco if (rr->DelayDelivery) return; // We'll come back later when CacheRecordDeferredAdd() calls us +#ifdef USE_LIBIDN + if (rr->resrec.RecordType == kDNSRecordTypePacketNegative) // If negative answer, check if we need to try Punycode conversion + { + domainname newname; + if (PerformNextPunycodeConversion(q, &newname)) // Itertative Punycode conversion succeeded, so reissue question with new name + { + UDPSocket *const sock = q->LocalSocket; // Save old socket and transaction ID + const mDNSOpaque16 id = q->TargetQID; + q->LocalSocket = mDNSNULL; + mDNS_StopQuery_internal(m, q); // Stop old query + AssignDomainName(&q->qname, &newname); // Update qname + q->qnamehash = DomainNameHashValue(&q->qname); // and namehash + mDNS_StartQuery_internal(m, q); // Start new query + + if (sock) // Transplant saved socket, if appropriate + { + if (q->DuplicateOf) mDNSPlatformUDPClose(sock); + else { q->LocalSocket = sock; q->TargetQID = id; } + } + return; // All done for now; wait until we get the next answer + } + } +#endif // USE_LIBIDN + // Only deliver negative answers if client has explicitly requested them except when we are forcing a negative response // for the purpose of retrying search domains/timeout OR the question is suppressed if (rr->resrec.RecordType == kDNSRecordTypePacketNegative || (q->qtype != kDNSType_NSEC && RRAssertsNonexistence(&rr->resrec, q->qtype))) @@ -4041,7 +4243,7 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco // If we get a CNAME back while we are validating the response (i.e., CNAME for DS, DNSKEY, RRSIG), // don't follow them. If it is a ValidationRequired question, wait for the CNAME to be validated // first before following it - if (!ValidatingQuestion(q) && followcname && m->CurrentQuestion == q) + if ((m->CurrentQuestion == q) && followcname && !ValidatingQuestion(q)) AnswerQuestionByFollowingCNAME(m, q, &rr->resrec); } @@ -4082,7 +4284,7 @@ mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *c // deliver a RMV (for the current old entry) followed by ADD (for the new entry). // It needs to schedule the timer for the next cache expiry (ScheduleNextCacheCheckTime), // so that the cache entry can be purged (purging causes the RMV followed by ADD) - // + // // 2) A new question is about to be answered and the caller needs to know whether it's // scheduling should be delayed so that the question is not answered with this record. // Instead of delivering an ADD (old entry) followed by RMV (old entry) and another ADD @@ -4317,7 +4519,7 @@ mDNSlocal void ReleaseCacheGroup(mDNS *const m, CacheGroup **cp) if ((*cp)->rrcache_tail != &(*cp)->members) LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)"); //if ((*cp)->name != (domainname*)((*cp)->namestorage)) - // LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage)); + // LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage)); if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name); (*cp)->name = mDNSNULL; *cp = (*cp)->next; // Cut record from list @@ -4364,7 +4566,7 @@ mDNSexport void ReleaseCacheRecord(mDNS *const m, CacheRecord *r) r->resrec.rdata = mDNSNULL; cg = CacheGroupForRecord(m, slot, &r->resrec); - + if (!cg) { // It is okay to have this printed for NSEC/NSEC3s @@ -4417,7 +4619,7 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot, CacheGrou if (m->timenow - event >= 0) // If expired, delete it { *rp = rr->next; // Cut it from the list - + verbosedebugf("CheckCacheExpiration: Deleting%7d %7d %p %s", m->timenow - rr->TimeRcvd, rr->resrec.rroriginalttl, rr->CRActiveQuestion, CRDisplayString(m, rr)); if (rr->CRActiveQuestion) // If this record has one or more active questions, tell them it's going away @@ -4509,7 +4711,7 @@ mDNSlocal mDNSBool AnswerQuestionWithLORecord(mDNS *const m, DNSQuestion *q, mDN // details on how we handle this case. For P2P we just handle "Interface_Any" questions. For LocalOnly // we handle both mDNSInterface_Any and scoped questions. - if (rr->ARType == AuthRecordLocalOnly || (rr->ARType == AuthRecordP2P && q->InterfaceID == mDNSInterface_Any)) + if (rr->ARType == AuthRecordLocalOnly || (rr->ARType == AuthRecordP2P && (q->InterfaceID == mDNSInterface_Any || q->InterfaceID == mDNSInterface_BLE))) if (LocalOnlyRecordAnswersQuestion(rr, q)) { if (checkOnly) @@ -4577,7 +4779,7 @@ mDNSlocal void AnswerSuppressedQuestion(mDNS *const m, DNSQuestion *q) q->SuppressQuery = mDNSfalse; q->DisallowPID = mDNSfalse; - GenerateNegativeResponse(m, QC_suppressed); + GenerateNegativeResponse(m, mDNSInterface_Any, QC_suppressed); q->SuppressQuery = SuppressQuery; q->DisallowPID = DisallowPID; @@ -4682,7 +4884,7 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m) AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add); if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here } - else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype)) + else if (mDNSOpaque16IsZero(q->TargetQID) && RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype)) ShouldQueryImmediately = mDNSfalse; } // We don't use LogInfo for this "Question deleted" message because it happens so routinely that @@ -4696,7 +4898,7 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m) if (!QuerySuppressed(q) && !AnsweredFromCache && q->RetryWithSearchDomains) { LogInfo("AnswerNewQuestion: Generating response for retrying with search domains %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); - GenerateNegativeResponse(m, QC_forceresponse); + GenerateNegativeResponse(m, mDNSInterface_Any, QC_forceresponse); } if (m->CurrentQuestion != q) { debugf("AnswerNewQuestion: Question deleted while giving negative answer"); goto exit; } @@ -4737,6 +4939,7 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m) AuthGroup *ag; DNSQuestion *q = m->NewLocalOnlyQuestions; // Grab the question we're going to answer m->NewLocalOnlyQuestions = q->next; // Advance NewLocalOnlyQuestions to the next (if any) + mDNSBool retEv = mDNSfalse; debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); @@ -4762,6 +4965,7 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m) m->CurrentRecord = rr->next; if (LocalOnlyRecordAnswersQuestion(rr, q)) { + retEv = mDNStrue; AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue); if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here } @@ -4778,12 +4982,18 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m) m->CurrentRecord = rr->next; if (ResourceRecordAnswersQuestion(&rr->resrec, q)) { + retEv = mDNStrue; AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue); if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here } } } + // The local host is the authoritative source for LocalOnly questions + // so if no records exist and client requested intermediates, then generate a negative response + if (!retEv && (m->CurrentQuestion == q) && q->ReturnIntermed) + GenerateNegativeResponse(m, mDNSInterface_LocalOnly, QC_forceresponse); + m->CurrentQuestion = mDNSNULL; m->CurrentRecord = mDNSNULL; } @@ -4898,7 +5108,7 @@ mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const Res cg->namehash = rr->namehash; cg->members = mDNSNULL; cg->rrcache_tail = &cg->members; - if (namelen > sizeof(cg->namestorage)) + if (namelen > sizeof(cg->namestorage)) cg->name = mDNSPlatformMemAllocate(namelen); else cg->name = (domainname*)cg->namestorage; @@ -5029,7 +5239,7 @@ mDNSlocal void TimeoutQuestions(mDNS *const m) if (m->timenow - q->StopTime >= 0) { LogInfo("TimeoutQuestions: question %p %##s timed out, time %d", q, q->qname.c, m->timenow - q->StopTime); - GenerateNegativeResponse(m, QC_forceresponse); + GenerateNegativeResponse(m, mDNSInterface_Any, QC_forceresponse); if (m->CurrentQuestion == q) q->StopTime = 0; } else @@ -5135,10 +5345,26 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m) mDNS_SendKeepalives(m); } +#if BONJOUR_ON_DEMAND + if (m->NextBonjourDisableTime && (m->timenow - m->NextBonjourDisableTime >= 0)) + { + // Schedule immediate network change processing to leave the multicast group + // since the delay time has expired since the previous active registration or query. + m->NetworkChanged = m->timenow; + m->NextBonjourDisableTime = 0; + m->BonjourEnabled = 0; + + LogInfo("mDNS_Execute: Scheduled network changed processing to leave multicast group."); + } +#endif // BONJOUR_ON_DEMAND + // Clear AnnounceOwner if necessary. (Do this *before* SendQueries() and SendResponses().) if (m->AnnounceOwner && m->timenow - m->AnnounceOwner >= 0) { m->AnnounceOwner = 0; + + // This is a good time to reset the delay counter used to prevent spurious conflicts + m->DelayConflictProcessing = 0; } if (m->DelaySleep && m->timenow - m->DelaySleep >= 0) @@ -5305,6 +5531,10 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m) if (m->timenow - m->NextScheduledNATOp >= 0) CheckNATMappings(m); if (m->timenow - m->NextuDNSEvent >= 0) uDNS_Tasks(m); #endif +#if APPLE_OSX_mDNSResponder + extern void serviceBLE(); + if (m->NextBLEServiceTime && (m->timenow - m->NextBLEServiceTime >= 0)) serviceBLE(); +#endif // APPLE_OSX_mDNSResponder } // Note about multi-threaded systems: @@ -5550,11 +5780,7 @@ mDNSexport void mDNSCoreRestartQuestion(mDNS *const m, DNSQuestion *q) if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q)) { q->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question -#if mDNS_REQUEST_UNICAST_RESPONSE - q->RequestUnicast = SET_QU_IN_FIRST_FOUR_QUERIES; -#else // mDNS_REQUEST_UNICAST_RESPONSE - q->RequestUnicast = SET_QU_IN_FIRST_QUERY; -#endif // mDNS_REQUEST_UNICAST_RESPONSE + q->RequestUnicast = kDefaultRequestUnicastCount; q->LastQTime = m->timenow - q->ThisQInterval; q->RecentAnswerPkts = 0; ExpireDupSuppressInfo(q->DupSuppress, m->timenow); @@ -5563,23 +5789,26 @@ mDNSexport void mDNSCoreRestartQuestion(mDNS *const m, DNSQuestion *q) } // restart the probe/announce cycle for multicast record -mDNSexport void mDNSCoreRestartRegistration(mDNS *const m, AuthRecord *rr, int announceCount) +mDNSexport void mDNSCoreRestartRegistration(mDNS *const m, AuthRecord *rr, int announceCount) { if (!AuthRecord_uDNS(rr)) { if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique; rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); - // announceCount < 0 indicates default announce count should be used - if (announceCount < 0) - announceCount = InitialAnnounceCount; - if (rr->AnnounceCount < announceCount) - rr->AnnounceCount = announceCount; - if (mDNS_KeepaliveRecord(&rr->resrec)) - rr->AnnounceCount = 0; // Do not announce keepalive records + { + rr->AnnounceCount = 0; // Do not announce keepalive records + } else - rr->AnnounceCount = InitialAnnounceCount; + { + // announceCount < 0 indicates default announce count should be used + if (announceCount < 0) + announceCount = InitialAnnounceCount; + if (rr->AnnounceCount < (mDNSu8)announceCount) + rr->AnnounceCount = (mDNSu8)announceCount; + } + rr->SendNSECNow = mDNSNULL; InitializeLastAPTime(m, rr); } @@ -5672,7 +5901,7 @@ mDNSlocal mDNSBool mDNSUpdateOkToSend(mDNS *const m, AuthRecord *rr, NetworkInte // If it is not a uDNS record, check to see if the updateid is zero. "updateid" is cleared when we have // sent the resource record on all the interfaces. If the update id is not zero, check to see if it is time // to send. - if (AuthRecord_uDNS(rr) || (rr->AuthFlags & AuthFlagsWakeOnly) || mDNSOpaque16IsZero(rr->updateid) || + if (AuthRecord_uDNS(rr) || (rr->AuthFlags & AuthFlagsWakeOnly) || mDNSOpaque16IsZero(rr->updateid) || m->timenow - (rr->LastAPTime + rr->ThisAPInterval) < 0) { return mDNSfalse; @@ -5693,53 +5922,56 @@ mDNSlocal mDNSBool mDNSUpdateOkToSend(mDNS *const m, AuthRecord *rr, NetworkInte return mDNSfalse; } -mDNSexport void UpdateRMACCallback(mDNS *const m, void *context) -{ - IPAddressMACMapping *addrmap = (IPAddressMACMapping *)context ; - m->CurrentRecord = m->ResourceRecords; - - if (!addrmap) - { - LogMsg("UpdateRMACCallback: Address mapping is NULL"); - return; - } - - while (m->CurrentRecord) - { - AuthRecord *rr = m->CurrentRecord; - // If this is a non-sleep proxy keepalive record and the remote IP address matches, update the RData - if (!rr->WakeUp.HMAC.l[0] && mDNS_KeepaliveRecord(&rr->resrec)) - { - mDNSAddr raddr; - getKeepaliveRaddr(m, rr, &raddr); - if (mDNSSameAddress(&raddr, &addrmap->ipaddr)) - { - // Update the MAC address only if it is not a zero MAC address - mDNSEthAddr macAddr; - mDNSu8 *ptr = GetValueForMACAddr((mDNSu8 *)(addrmap->ethaddr), (mDNSu8 *) (addrmap->ethaddr + sizeof(addrmap->ethaddr)), &macAddr); - if (ptr != mDNSNULL && !mDNSEthAddressIsZero(macAddr)) - { - UpdateKeepaliveRData(m, rr, mDNSNULL, mDNStrue, (char *)(addrmap->ethaddr)); - } - } - } - m->CurrentRecord = rr->next; - } - - if (addrmap) - { - mDNSPlatformMemFree(addrmap); - } +mDNSexport void UpdateRMAC(mDNS *const m, void *context) +{ + IPAddressMACMapping *addrmap = (IPAddressMACMapping *)context ; + m->CurrentRecord = m->ResourceRecords; + + if (!addrmap) + { + LogMsg("UpdateRMAC: Address mapping is NULL"); + return; + } + + while (m->CurrentRecord) + { + AuthRecord *rr = m->CurrentRecord; + // If this is a non-sleep proxy keepalive record and the remote IP address matches, update the RData + if (!rr->WakeUp.HMAC.l[0] && mDNS_KeepaliveRecord(&rr->resrec)) + { + mDNSAddr raddr; + getKeepaliveRaddr(m, rr, &raddr); + if (mDNSSameAddress(&raddr, &addrmap->ipaddr)) + { + // Update the MAC address only if it is not a zero MAC address + mDNSEthAddr macAddr; + mDNSu8 *ptr = GetValueForMACAddr((mDNSu8 *)(addrmap->ethaddr), (mDNSu8 *) (addrmap->ethaddr + sizeof(addrmap->ethaddr)), &macAddr); + if (ptr != mDNSNULL && !mDNSEthAddressIsZero(macAddr)) + { + UpdateKeepaliveRData(m, rr, mDNSNULL, mDNStrue, (char *)(addrmap->ethaddr)); + } + } + } + m->CurrentRecord = rr->next; + } + + if (addrmap) + mDNSPlatformMemFree(addrmap); + } mDNSexport mStatus UpdateKeepaliveRData(mDNS *const m, AuthRecord *rr, NetworkInterfaceInfo *const intf, mDNSBool updateMac, char *ethAddr) { mDNSu16 newrdlength; - mDNSAddr laddr, raddr; - mDNSEthAddr eth; - mDNSIPPort lport, rport; - mDNSu32 timeout, seq, ack; - mDNSu16 win; + mDNSAddr laddr = zeroAddr; + mDNSAddr raddr = zeroAddr; + mDNSEthAddr eth = zeroEthAddr; + mDNSIPPort lport = zeroIPPort; + mDNSIPPort rport = zeroIPPort; + mDNSu32 timeout = 0; + mDNSu32 seq = 0; + mDNSu32 ack = 0; + mDNSu16 win = 0; UTF8str255 txt; int rdsize; RData *newrd; @@ -5749,8 +5981,7 @@ mDNSexport mStatus UpdateKeepaliveRData(mDNS *const m, AuthRecord *rr, NetworkIn // Note: If we fail to update the DNS NULL record with additional information in this function, it will be registered // with the SPS like any other record. SPS will not send keepalives if it does not have additional information. mDNS_ExtractKeepaliveInfo(rr, &timeout, &laddr, &raddr, ð, &seq, &ack, &lport, &rport, &win); - if (!timeout || mDNSAddressIsZero(&laddr) || mDNSAddressIsZero(&raddr) || mDNSIPPortIsZero(lport) || - mDNSIPPortIsZero(rport)) + if (!timeout || mDNSAddressIsZero(&laddr) || mDNSAddressIsZero(&raddr) || mDNSIPPortIsZero(lport) || mDNSIPPortIsZero(rport)) { LogMsg("UpdateKeepaliveRData: not a valid record %s for keepalive %#a:%d %#a:%d", ARDisplayString(m, rr), &laddr, lport.NotAnInteger, &raddr, rport.NotAnInteger); return mStatus_UnknownErr; @@ -5813,8 +6044,8 @@ mDNSexport mStatus UpdateKeepaliveRData(mDNS *const m, AuthRecord *rr, NetworkIn // free that memory here before copying in the new data. if ( rr->resrec.rdata != &rr->rdatastorage) { - mDNSPlatformMemFree(rr->resrec.rdata); LogSPS("UpdateKeepaliveRData: Freed allocated memory for keep alive packet: %s ", ARDisplayString(m, rr)); + mDNSPlatformMemFree(rr->resrec.rdata); } SetNewRData(&rr->resrec, newrd, newrdlength); // Update our rdata @@ -5954,7 +6185,7 @@ mDNSlocal void SendSPSRegistrationForOwner(mDNS *const m, NetworkInterfaceInfo * LogSPS("SendSPSRegistration: Sending Update %s %d (%d) id %5d with %d records %d bytes to %#a:%d", intf->ifname, intf->NextSPSAttempt, sps, mDNSVal16(m->omsg.h.id), m->omsg.h.mDNS_numUpdates, p - m->omsg.data, &intf->SPSAddr[sps], mDNSVal16(intf->SPSPort[sps])); - // if (intf->NextSPSAttempt < 5) m->omsg.h.flags = zeroID; // For simulating packet loss + // if (intf->NextSPSAttempt < 5) m->omsg.h.flags = zeroID; // For simulating packet loss err = mDNSSendDNSMessage(m, &m->omsg, p, intf->InterfaceID, mDNSNULL, &intf->SPSAddr[sps], intf->SPSPort[sps], mDNSNULL, mDNSNULL, mDNSfalse); if (err) LogSPS("SendSPSRegistration: mDNSSendDNSMessage err %d", err); if (err && intf->SPSAddr[sps].type == mDNSAddrType_IPv4 && intf->NetWakeResolve[sps].ThisQInterval == -1) @@ -6027,7 +6258,7 @@ mDNSlocal void SPSInitRecordsBeforeUpdate(mDNS *const m, mDNSOpaque64 updateIntI { AuthRecord *ar; LogSPS("SPSInitRecordsBeforeUpdate: UpdateIntID 0x%x 0x%x", updateIntID.l[1], updateIntID.l[0]); - + *WakeOnlyService = mDNSfalse; // Before we store the A and AAAA records that we are going to register with the sleep proxy, @@ -6144,7 +6375,7 @@ mDNSlocal void NetWakeResolve(mDNS *const m, DNSQuestion *question, const Resour if (!AddRecord) return; // Don't care about REMOVE events if (answer->rrtype != question->qtype) return; // Don't care about CNAMEs - // if (answer->rrtype == kDNSType_AAAA && sps == 0) return; // To test failing to resolve sleep proxy's address + // if (answer->rrtype == kDNSType_AAAA && sps == 0) return; // To test failing to resolve sleep proxy's address if (answer->rrtype == kDNSType_SRV) { @@ -6230,14 +6461,8 @@ mDNSlocal void SendGoodbyesForWakeOnlyService(mDNS *const m, mDNSBool *WakeOnlyS { return SendGoodbyesForSelectServices(m, WakeOnlyService, WAKE_ONLY_SERVICE); } -#endif // APPLE_OSx_mDNSResponder +#endif // APPLE_OSX_mDNSResponder -#ifdef APPLE_OSX_mDNSResponder -mDNSlocal void SendGoodbyesForACOnlyServices(mDNS *const m, mDNSBool *acOnlyService) -{ - return SendGoodbyesForSelectServices(m, acOnlyService, AC_ONLY_SERVICE); -} -#endif mDNSlocal void SendSleepGoodbyes(mDNS *const m, mDNSBool AllInterfaces, mDNSBool unicast) { @@ -6334,11 +6559,10 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m) { mDNSBool SendGoodbyes = mDNStrue; mDNSBool WakeOnlyService = mDNSfalse; - mDNSBool ACOnlyService = mDNSfalse; mDNSBool invokeKACallback = mDNStrue; const CacheRecord *sps[3] = { mDNSNULL }; mDNSOpaque64 updateIntID = zeroOpaque64; - mDNSInterfaceID registeredIntfIDS[128]; + mDNSInterfaceID registeredIntfIDS[128] = { 0 }; mDNSu32 registeredCount = 0; int skippedRegistrations = 0; @@ -6351,7 +6575,7 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m) NetworkInterfaceInfo *intf; // Clear out the SCDynamic entry that stores the external SPS information - mDNSPlatformClearSPSMACAddr(); + mDNSPlatformClearSPSData(); for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) { @@ -6395,10 +6619,10 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m) if (ActivateLocalProxy(m, intf, &keepaliveOnly) == mStatus_NoError) { SendGoodbyesForWakeOnlyService(m, &WakeOnlyService); - if (keepaliveOnly) - SendGoodbyesForACOnlyServices(m, &ACOnlyService); - SendGoodbyes = mDNSfalse; - invokeKACallback = mDNSfalse; + + // Send goodbyes for all advertised services if the only record offloaded was the keepalive record. + SendGoodbyes = (keepaliveOnly) ? mDNStrue: mDNSfalse; + invokeKACallback = mDNSfalse; LogSPS("BeginSleepProcessing: %-6s using local proxy", intf->ifname); // This will leave m->SleepState set to SleepState_Transferring, // which is okay because with no outstanding resolves, or updates in flight, @@ -6482,7 +6706,7 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m) // // - If there are no sleep proxy servers, then send goodbyes on all interfaces // for both multicast and unicast. - // + // // - If we skipped registrations on some interfaces, then we have already marked // them appropriately above. We don't need to send goodbyes for unicast as // we have registered with at least one sleep proxy. @@ -6502,10 +6726,10 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m) LogSPS("BeginSleepProcessing: Not registering with Sleep Proxy Server on all interfaces"); SendSleepGoodbyes(m, mDNSfalse, mDNSfalse); } - else if (WakeOnlyService || ACOnlyService) + else if (WakeOnlyService) { // If we saw WakeOnly service above, send the goodbyes now. - LogSPS("BeginSleepProcessing: Sending goodbyes for %s", WakeOnlyService? "WakeOnlyService" : "AC Only Service"); + LogSPS("BeginSleepProcessing: Sending goodbyes for WakeOnlyService"); SendResponses(m); } } @@ -6531,7 +6755,7 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep) #ifndef SPC_DISABLED if (oldstate == 1) mDNS_DeregisterService(m, &m->SPSRecords); #else - (void)oldstate; + (void)oldstate; #endif mDNS_ReclaimLockAfterCallback(); } @@ -6579,7 +6803,11 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep) { m->SleepState = SleepState_Awake; m->SleepSeqNum++; - m->DelaySleep = 0; + // If the machine wakes and then immediately tries to sleep again (e.g. a maintenance wake) + // then we enforce a minimum delay of five seconds before we begin sleep processing. + // This is to allow time for the Ethernet link to come up, DHCP to get an address, mDNS to issue queries, etc., + // before we make our determination of whether there's a Sleep Proxy out there we should register with. + m->DelaySleep = NonZeroTime(m->timenow + kDarkWakeDelaySleep); } if (m->SPSState == 3) @@ -6588,7 +6816,7 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep) mDNSCoreBeSleepProxyServer_internal(m, m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower, m->SPSFeatureFlags); } m->mDNSStats.Wakes++; - + m->DelayConflictProcessing = MAX_CONFLICT_PROCESSING_DELAYS; // ... and the same for NextSPSAttempt for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) intf->NextSPSAttempt = -1; @@ -6629,7 +6857,7 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep) mDNSu32 uTTL = RRUnadjustedTTL(cr->resrec.rroriginalttl); const mDNSs32 remain = uTTL - (m->timenow - cr->TimeRcvd) / mDNSPlatformOneSecond; - // -if we have slept longer than the remaining TTL, purge and start fresh. + // -if we have slept longer than the remaining TTL, purge and start fresh. // -if we have been sleeping for a long time, we could reduce TimeRcvd below by // a sufficiently big value which could cause the value to go into the future // because of the signed comparison of time. For this to happen, we should have been @@ -7113,7 +7341,7 @@ mDNSlocal void DeregisterProxyRecord(mDNS *const m, AuthRecord *const rr) mDNSlocal void ClearKeepaliveProxyRecords(mDNS *const m, const OwnerOptData *const owner, AuthRecord *const thelist, const mDNSInterfaceID InterfaceID) { if (m->CurrentRecord) - LogMsg("ClearIdenticalProxyRecords ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); + LogMsg("ClearKeepaliveProxyRecords ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); m->CurrentRecord = thelist; // Normally, the RDATA of the keepalive record will be different each time and hence we always @@ -7247,9 +7475,9 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it } - // + // // Look in Authority Section for NSEC3 record - // + // mDNSParseNSEC3Records(m, query, end, InterfaceID, &McastNSEC3Records); @@ -7583,7 +7811,6 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con { SendLegacyResponse = mDNStrue; } - if (SendMulticastResponse || SendUnicastResponse) { @@ -7690,15 +7917,17 @@ exit: // For non-truncated queries, we can definitively say that we should expect // to be seeing a response for any records still left in the ExpectedAnswers list if (!(query->h.flags.b[0] & kDNSFlag0_TC)) - if (cr->UnansweredQueries == 0 || m->timenow - cr->LastUnansweredTime >= mDNSPlatformOneSecond) + if (cr->UnansweredQueries == 0 || m->timenow - cr->LastUnansweredTime >= mDNSPlatformOneSecond * 3/4) { cr->UnansweredQueries++; cr->LastUnansweredTime = m->timenow; -#if ENABLE_MULTI_PACKET_QUERY_SNOOPING if (cr->UnansweredQueries > 1) - debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s", + #if ENABLE_MULTI_PACKET_QUERY_SNOOPING + debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s", cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr)); -#endif // ENABLE_MULTI_PACKET_QUERY_SNOOPING + #else + debugf("ProcessQuery: UnansweredQueries %lu %s", cr->UnansweredQueries, CRDisplayString(m, cr)); + #endif // ENABLE_MULTI_PACKET_QUERY_SNOOPING SetNextCacheCheckTimeForRecord(m, cr); } @@ -7706,12 +7935,16 @@ exit: // then mark it to expire in five seconds if we don't get a response by then. if (cr->UnansweredQueries >= MaxUnansweredQueries) { -#if ENABLE_MULTI_PACKET_QUERY_SNOOPING // Only show debugging message if this record was not about to expire anyway - if (RRExpireTime(cr) - m->timenow > 4 * mDNSPlatformOneSecond) - debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s", + if (RRExpireTime(cr) - m->timenow > (mDNSs32) kDefaultReconfirmTimeForNoAnswer * 4 / 3 + mDNSPlatformOneSecond) + #if ENABLE_MULTI_PACKET_QUERY_SNOOPING + debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s", cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr)); -#endif // ENABLE_MULTI_PACKET_QUERY_SNOOPING + #else + LogInfo("ProcessQuery: UnansweredQueries %lu TTL %lu mDNS_Reconfirm() for %s", + cr->UnansweredQueries, (RRExpireTime(cr) - m->timenow + mDNSPlatformOneSecond-1) / mDNSPlatformOneSecond, CRDisplayString(m, cr)); + #endif // ENABLE_MULTI_PACKET_QUERY_SNOOPING + m->mDNSStats.PoofCacheDeletions++; mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); } @@ -7777,15 +8010,16 @@ mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg, mDNSBool QueryWasLocalUnicast = srcaddr && dstaddr && !mDNSAddrIsDNSMulticast(dstaddr) && mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr); - if (!InterfaceID && dstaddr && mDNSAddrIsDNSMulticast(dstaddr)) + if (!dstaddr || (!InterfaceID && mDNSAddrIsDNSMulticast(dstaddr))) { + const char *const reason = !dstaddr ? "Received over TCP connection" : "Multicast, but no InterfaceID"; LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with " - "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s %d bytes (Multicast, but no InterfaceID)", + "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s %d bytes (%s)", srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID, msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,", msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,", msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,", - msg->h.numAdditionals, msg->h.numAdditionals == 1 ? " " : "s", end - msg->data); + msg->h.numAdditionals, msg->h.numAdditionals == 1 ? " " : "s", end - msg->data, reason); return; } @@ -7875,9 +8109,9 @@ mDNSlocal DNSQuestion *ExpectingUnicastResponseForRecord(mDNS *const m, } if (mDNSSameIPPort(srcp, port)) return(q); - // if (mDNSSameAddress(srcaddr, &q->Target)) return(mDNStrue); - // if (q->LongLived && mDNSSameAddress(srcaddr, &q->servAddr)) return(mDNStrue); Shouldn't need this now that we have LLQType checking - // if (TrustedSource(m, srcaddr)) return(mDNStrue); + // if (mDNSSameAddress(srcaddr, &q->Target)) return(mDNStrue); + // if (q->LongLived && mDNSSameAddress(srcaddr, &q->servAddr)) return(mDNStrue); Shouldn't need this now that we have LLQType checking + // if (TrustedSource(m, srcaddr)) return(mDNStrue); LogInfo("WARNING: Ignoring suspect uDNS response for %##s (%s) [q->Target %#a:%d] from %#a:%d %s", q->qname.c, DNSTypeName(q->qtype), &q->Target, mDNSVal16(srcp), srcaddr, mDNSVal16(port), CRDisplayString(m, rr)); return(mDNSNULL); @@ -7915,7 +8149,7 @@ mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, C if (!m->rec.r.resrec.InterfaceID) debugf("CreateNewCacheEntry %s", CRDisplayString(m, &m->rec.r)); //if (RDLength > InlineCacheRDSize) - // LogInfo("Rdata len %4d > InlineCacheRDSize %d %s", RDLength, InlineCacheRDSize, CRDisplayString(m, &m->rec.r)); + // LogInfo("Rdata len %4d > InlineCacheRDSize %d %s", RDLength, InlineCacheRDSize, CRDisplayString(m, &m->rec.r)); if (!cg) cg = GetCacheGroup(m, slot, &m->rec.r.resrec); // If we don't have a CacheGroup for this name, make one now if (cg) rr = GetCacheRecord(m, cg, RDLength); // Make a cache record, being careful not to recycle cg @@ -8254,7 +8488,7 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage * // the application if (qptr->ProxyQuestion) qptr->responseFlags = response->h.flags; - GenerateNegativeResponse(m, QC_forceresponse); + GenerateNegativeResponse(m, mDNSInterface_Any, QC_forceresponse); m->CurrentQuestion = mDNSNULL; } else @@ -8438,7 +8672,7 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage * name = (const domainname *)(name->c + 1 + name->c[0]); hash = DomainNameHashValue(name); slot = HashSlot(name); - // For now, we don't need to update cg here, because we'll do it again immediately, back up at the start of this loop + // For now, we don't need to update cg here, because we'll do it again immediately, back up at the start of this loop //cg = CacheGroupForName(m, slot, hash, name); } } @@ -8614,7 +8848,6 @@ mDNSlocal CacheRecord* mDNSCoreReceiveCacheCheck(mDNS *const m, const DNSMessage } else { - // If the packet TTL is zero, that means we're deleting this record. // To give other hosts on the network a chance to protest, we push the deletion // out one second into the future. Also, we set UnansweredQueries to MaxUnansweredQueries. @@ -8685,7 +8918,7 @@ mDNSlocal void mDNSCoreResetRecord(mDNS *const m) m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it if (m->rec.r.resrec.AnonInfo) { - FreeAnonInfo(m->rec.r.resrec.AnonInfo); + FreeAnonInfo(m->rec.r.resrec.AnonInfo); m->rec.r.resrec.AnonInfo = mDNSNULL; } } @@ -8722,6 +8955,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, mDNSBool rrsigsCreated = mDNSfalse; mDNSBool DNSSECQuestion = mDNSfalse; NetworkInterfaceInfo *llintf = FirstIPv4LLInterfaceForID(m, InterfaceID); + mDNSBool recordAcceptedInResponse = mDNSfalse; // Set if a record is accepted from a unicast mDNS response that answers an existing question. // All records in a DNS response packet are treated as equally valid statements of truth. If we want // to guard against spoof responses, then the only credible protection against that is cryptographic @@ -8832,14 +9066,14 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, // and hence retransmit without the EDNS0/DOK option. if (DNSSECOptionalQuestion(qptr) && qptr->qDNSServer && !qptr->qDNSServer->DNSSECAware) { - LogInfo("mDNSCoreReceiveResponse: Server %p responded with code %d to DNSSEC Query %##s (%s), clear DO flag", + LogInfo("mDNSCoreReceiveResponse: Server %p responded with code %d to DNSSEC Query %##s (%s), clear DO flag", qptr->qDNSServer, rcode, q.qname.c, DNSTypeName(q.qtype)); - qptr->qDNSServer->req_DO = mDNSfalse; + qptr->qDNSServer->req_DO = mDNSfalse; } // For Unicast DNS Queries, penalize the DNSServer else { - LogInfo("mDNSCoreReceiveResponse: Server %p responded with code %d to query %##s (%s)", + LogInfo("mDNSCoreReceiveResponse: Server %p responded with code %d to query %##s (%s)", qptr->qDNSServer, rcode, q.qname.c, DNSTypeName(q.qtype)); PenalizeDNSServer(m, qptr, response->h.flags); } @@ -8874,7 +9108,9 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, { // All responses sent via LL multicast are acceptable for caching // All responses received over our outbound TCP connections are acceptable for caching - mDNSBool AcceptableResponse = ResponseMCast || !dstaddr || LLQType; + // We accept all records in a unicast response to a multicast query once we find one that + // answers an active question. + mDNSBool AcceptableResponse = ResponseMCast || !dstaddr || LLQType || recordAcceptedInResponse; // (Note that just because we are willing to cache something, that doesn't necessarily make it a trustworthy answer // to any specific question -- any code reading records from the cache needs to make that determination for itself.) @@ -8961,38 +9197,42 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, // Even though it is AcceptableResponse, we still need a DNSServer pointer for the resource records that // we create. - DNSQuestion *q = ExpectingUnicastResponseForRecord(m, srcaddr, ResponseSrcLocal, dstport, response->h.id, &m->rec.r, !dstaddr); - - // Initialize the DNS server on the resource record which will now filter what questions we answer with - // this record. - // - // We could potentially lookup the DNS server based on the source address, but that may not work always - // and that's why ExpectingUnicastResponseForRecord does not try to verify whether the response came - // from the DNS server that queried. We follow the same logic here. If we can find a matching quetion based - // on the "id" and "source port", then this response answers the question and assume the response - // came from the same DNS server that we sent the query to. - - if (q != mDNSNULL) - { - AcceptableResponse = mDNStrue; - if (!InterfaceID) - { - debugf("mDNSCoreReceiveResponse: InterfaceID %p %##s (%s)", q->InterfaceID, q->qname.c, DNSTypeName(q->qtype)); - m->rec.r.resrec.rDNSServer = uDNSServer = q->qDNSServer; - } - else - LogInfo("mDNSCoreReceiveResponse: InterfaceID %p %##s (%s)", q->InterfaceID, q->qname.c, DNSTypeName(q->qtype)); - } - else - { - // If we can't find a matching question, we need to see whether we have seen records earlier that matched - // the question. The code below does that. So, make this record unacceptable for now - if (!InterfaceID) - { - debugf("mDNSCoreReceiveResponse: Can't find question for record name %##s", m->rec.r.resrec.name->c); - AcceptableResponse = mDNSfalse; - } - } + DNSQuestion *q = ExpectingUnicastResponseForRecord(m, srcaddr, ResponseSrcLocal, dstport, response->h.id, &m->rec.r, !dstaddr); + + // Initialize the DNS server on the resource record which will now filter what questions we answer with + // this record. + // + // We could potentially lookup the DNS server based on the source address, but that may not work always + // and that's why ExpectingUnicastResponseForRecord does not try to verify whether the response came + // from the DNS server that queried. We follow the same logic here. If we can find a matching quetion based + // on the "id" and "source port", then this response answers the question and assume the response + // came from the same DNS server that we sent the query to. + + if (q != mDNSNULL) + { + AcceptableResponse = mDNStrue; + if (!InterfaceID) + { + debugf("mDNSCoreReceiveResponse: InterfaceID %p %##s (%s)", q->InterfaceID, q->qname.c, DNSTypeName(q->qtype)); + m->rec.r.resrec.rDNSServer = uDNSServer = q->qDNSServer; + } + else + { + // Accept all remaining records in this unicast response to an mDNS query. + recordAcceptedInResponse = mDNStrue; + LogInfo("mDNSCoreReceiveResponse: Accepting response for query: %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + } + } + else + { + // If we can't find a matching question, we need to see whether we have seen records earlier that matched + // the question. The code below does that. So, make this record unacceptable for now + if (!InterfaceID) + { + debugf("mDNSCoreReceiveResponse: Can't find question for record name %##s", m->rec.r.resrec.name->c); + AcceptableResponse = mDNSfalse; + } + } } } else if (llintf && llintf->IgnoreIPv4LL && m->rec.r.resrec.rrtype == kDNSType_A) @@ -9016,7 +9256,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, // This can cause some badly written applications to freeze for a long time if they // attempt to connect to an IPv4 link-local destination address and then wait for // that connection attempt to time out before trying other candidate addresses. - + // To mask this client bug, we suppress acceptance of IPv4 link-local address // records on interfaces where we know the OS will be unwilling even to attempt // communication with those IPv4 link-local destination addresses. @@ -9103,13 +9343,36 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, // If we're probing for this record, we just failed else if (rr->resrec.RecordType == kDNSRecordTypeUnique) { + // At this point in the code, we're probing for uniqueness. + // We've sent at least one probe (rr->ProbeCount < DefaultProbeCountForTypeUnique) + // but we haven't completed probing yet (rr->resrec.RecordType == kDNSRecordTypeUnique). // Before we call deregister, check if this is a packet we registered with the sleep proxy. if (!mDNSCoreRegisteredProxyRecord(m, rr)) { - LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; will deregister %s", rr->ProbeCount, ARDisplayString(m, rr)); - - m->mDNSStats.NameConflicts++; - mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict); + // This may be a conflict due to stale packets on the network. Delay probing by a second. + // If there are conflicts after 3 such attempts, then it is a true conflict. + if (m->DelayConflictProcessing) + { + m->DelayConflictProcessing--; + LogMsg("Possible spurious conflict for %s. Attempt %d at suppressing probes for one second", + ARDisplayString(m, rr), (MAX_CONFLICT_PROCESSING_DELAYS - m->DelayConflictProcessing)); + rr->ProbeCount = DefaultProbeCountForTypeUnique + 1; + rr->AnnounceCount = InitialAnnounceCount; + m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond); + InitializeLastAPTime(m, rr); + RecordProbeFailure(m, rr); // Repeated late conflicts also cause us to back off to the slower probing rate + } + else + { + LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; will deregister %s", rr->ProbeCount, ARDisplayString(m, rr)); + m->mDNSStats.NameConflicts++; +#if APPLE_OSX_mDNSResponder + // See if this record was also registered with any D2D plugins. + D2D_stop_advertising_record(rr); +#endif + mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict); + } + } } // We assumed this record must be unique, but we were wrong. (e.g. There are two mDNSResponders on the @@ -9121,6 +9384,9 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, { LogMsg("mDNSCoreReceiveResponse: Unexpected conflict discarding %s", ARDisplayString(m, rr)); m->mDNSStats.KnownUniqueNameConflicts++; +#if APPLE_OSX_mDNSResponder + D2D_stop_advertising_record(rr); +#endif mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict); } else @@ -9289,7 +9555,7 @@ exit: continue; } } - + // For Unicast (null InterfaceID) the resolver IDs should also match if ((r1->resrec.InterfaceID == r2->resrec.InterfaceID) && (r1->resrec.InterfaceID || (id1 == id2)) && @@ -9313,7 +9579,7 @@ exit: // to give us an aged TTL to correct for how long it has held the record, // so our received TTLs are expected to vary in that case - // We also suppress log message in the case of SRV records that are recieved + // We also suppress log message in the case of SRV records that are received // with a TTL of 4500 that are already cached with a TTL of 120 seconds, since // this behavior was observed for a number of discoveryd based AppleTV's in iOS 8 // GM builds. @@ -9388,7 +9654,7 @@ exit: // Note: We need to do this before we call CacheRecordDeferredAdd as this // might start the verification process which needs these NSEC records if (!AddNSECSForCacheRecord(m, NSECRecords, NSECCachePtr, rcode)) - { + { LogInfo("mDNSCoreReceiveResponse: AddNSECSForCacheRecord failed to add NSEC for %s", CRDisplayString(m, NSECCachePtr)); FreeNSECRecords(m, NSECRecords); } @@ -9408,7 +9674,7 @@ exit: { LogInfo("mDNSCoreReceieveResponse: Updating NSEC records in %s", CRDisplayString(m, NSECCachePtr)); if (!AddNSECSForCacheRecord(m, NSECRecords, NSECCachePtr, rcode)) - { + { LogInfo("mDNSCoreReceiveResponse: AddNSECSForCacheRecord failed to add NSEC for %s", CRDisplayString(m, NSECCachePtr)); FreeNSECRecords(m, NSECRecords); } @@ -9488,8 +9754,8 @@ mDNSlocal void SPSRecordCallback(mDNS *const m, AuthRecord *const ar, mStatus re LogMsg("%-7s Conflicting mDNS -- waking %.6a %s", InterfaceNameForID(m, ar->resrec.InterfaceID), &ar->WakeUp.HMAC, ARDisplayString(m, ar)); if (ar->WakeUp.HMAC.l[0]) { - SendWakeup(m, ar->resrec.InterfaceID, &ar->WakeUp.IMAC, &ar->WakeUp.password); // Send one wakeup magic packet - ScheduleWakeup(m, ar->resrec.InterfaceID, &ar->WakeUp.HMAC); // Schedule all other records with the same owner to be woken + SendWakeup(m, ar->resrec.InterfaceID, &ar->WakeUp.IMAC, &ar->WakeUp.password, mDNSfalse); // Send one wakeup magic packet + ScheduleWakeup(m, ar->resrec.InterfaceID, &ar->WakeUp.HMAC); // Schedule all other records with the same owner to be woken } mDNS_Unlock(m); } @@ -9519,7 +9785,7 @@ mDNSlocal mDNSu8 *GetValueForMACAddr(mDNSu8 *ptr, mDNSu8 *limit, mDNSEthAddr *et } else if (*ptr == ':') { - if (colons >=5 || val > 255) + if (colons >=5) { LogMsg("GetValueForMACAddr: Address malformed colons %d val %d", colons, val); return mDNSNULL; @@ -9704,32 +9970,33 @@ mDNSlocal mDNSu8 *GetValueForKeepalive(mDNSu8 *ptr, mDNSu8 *limit, mDNSu32 *valu mDNSexport mDNSBool mDNSValidKeepAliveRecord(AuthRecord *rr) { - mDNSAddr laddr, raddr; - mDNSEthAddr eth; - mDNSIPPort lport, rport; - mDNSu32 timeout, seq, ack; - mDNSu16 win; + mDNSAddr laddr, raddr; + mDNSEthAddr eth; + mDNSIPPort lport, rport; + mDNSu32 timeout, seq, ack; + mDNSu16 win; - if (!mDNS_KeepaliveRecord(&rr->resrec)) - { - return mDNSfalse; - } + if (!mDNS_KeepaliveRecord(&rr->resrec)) + { + return mDNSfalse; + } - timeout = seq = ack = 0; - win = 0; - laddr = raddr = zeroAddr; - lport = rport = zeroIPPort; + timeout = seq = ack = 0; + win = 0; + laddr = raddr = zeroAddr; + lport = rport = zeroIPPort; + eth = zeroEthAddr; - mDNS_ExtractKeepaliveInfo(rr, &timeout, &laddr, &raddr, ð, &seq, &ack, &lport, &rport, &win); + mDNS_ExtractKeepaliveInfo(rr, &timeout, &laddr, &raddr, ð, &seq, &ack, &lport, &rport, &win); - if (mDNSAddressIsZero(&laddr) || mDNSIPPortIsZero(lport) || - mDNSAddressIsZero(&raddr) || mDNSIPPortIsZero(rport) || - mDNSEthAddressIsZero(eth)) - { - return mDNSfalse; - } + if (mDNSAddressIsZero(&laddr) || mDNSIPPortIsZero(lport) || + mDNSAddressIsZero(&raddr) || mDNSIPPortIsZero(rport) || + mDNSEthAddressIsZero(eth)) + { + return mDNSfalse; + } - return mDNStrue; + return mDNStrue; } @@ -9760,7 +10027,7 @@ mDNSlocal void mDNS_ExtractKeepaliveInfo(AuthRecord *ar, mDNSu32 *timeout, mDNSA raddr->type = mDNSAddrType_IPv4; ptr = GetValueForIPv4Addr(ptr, limit, &raddr->ip.v4); } - if (param == 'H') + else if (param == 'H') { laddr->type = mDNSAddrType_IPv6; ptr = GetValueForIPv6Addr(ptr, limit, &laddr->ip.v6); @@ -10106,6 +10373,35 @@ mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m, mDNS_SendKeepalives(m); } +mDNSlocal mDNSu32 mDNSGenerateOwnerOptForInterface(mDNS *const m, const mDNSInterfaceID InterfaceID, DNSMessage *msg) +{ + mDNSu8 *ptr = msg->data; + mDNSu8 *end = mDNSNULL; + mDNSu32 length = 0; + AuthRecord opt; + + mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL); + opt.resrec.rrclass = NormalMaxDNSMessageData; + opt.resrec.rdlength = sizeof(rdataOPT); + opt.resrec.rdestimate = sizeof(rdataOPT); + + NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID); + SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[0]); + + LogSPS("Generated OPT record : %s", ARDisplayString(m, &opt)); + end = PutResourceRecord(msg, ptr, &msg->h.numAdditionals, &opt.resrec); + if (end != mDNSNULL) + { + // Put all the integer values in IETF byte-order (MSB first, LSB second) + SwapDNSHeaderBytes(msg); + length = (end - msg->data); + } + else + LogSPS("mDNSGenerateOwnerOptForInterface: Failed to generate owner OPT record"); + + return length; +} + mDNSlocal void mDNSCoreReceiveUpdateR(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *end, const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID) { if (InterfaceID) @@ -10166,6 +10462,18 @@ mDNSlocal void mDNSCoreReceiveUpdateR(mDNS *const m, const DNSMessage *const msg ifname = InterfaceNameForID(m, InterfaceID); mDNSPlatformMemCopy(&spsaddr, srcaddr, sizeof (mDNSAddr)); mDNSPlatformStoreSPSMACAddr(&spsaddr, ifname); + + // Store the Owner OPT record for this interface. + // Configd may use the OPT record if it detects a conflict with the BSP when the system wakes up + DNSMessage optMsg; + int length = 0; + InitializeDNSMessage(&optMsg.h, zeroID, ResponseFlags); + length = mDNSGenerateOwnerOptForInterface(m, InterfaceID, &optMsg); + if (length != 0) + { + length += sizeof(DNSMessageHeader); + mDNSPlatformStoreOwnerOptRecord(ifname, &optMsg, length); + } } // If we were waiting to go to sleep, then this SPS registration or wide-area record deletion // may have been the thing we were waiting for, so schedule another check to see if we can sleep now. @@ -10309,17 +10617,21 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *co else if (QR_OP == UpdR) mDNSCoreReceiveUpdateR (m, msg, end, srcaddr, InterfaceID); else { - LogMsg("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d length %d on %p (ignored)", - msg->h.flags.b[0], msg->h.flags.b[1], srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), end - (mDNSu8 *)pkt, InterfaceID); if (mDNS_LoggingEnabled) { - int i = 0; - while (ih.flags.b[0], msg->h.flags.b[1], srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), end - (mDNSu8 *)pkt, InterfaceID); + while (itriedAllServersOnce = question->triedAllServersOnce; q->TargetQID = question->TargetQID; - if (q->LocalSocket) - { - mDNSPlatformUDPClose(q->LocalSocket); - } - q->LocalSocket = question->LocalSocket; + // No need to close old q->LocalSocket first -- duplicate questions can't have their own sockets q->state = question->state; - // q->tcp = question->tcp; + // q->tcp = question->tcp; q->ReqLease = question->ReqLease; q->expire = question->expire; q->ntries = question->ntries; @@ -10451,7 +10759,7 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const questi question->LocalSocket = mDNSNULL; question->nta = mDNSNULL; // If we've got a GetZoneData in progress, transfer it to the newly active question - // question->tcp = mDNSNULL; + // question->tcp = mDNSNULL; if (q->LocalSocket) debugf("UpdateQuestionDuplicates transferred LocalSocket pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); @@ -10657,7 +10965,7 @@ mDNSlocal mDNSBool DNSServerMatch(DNSServer *d, mDNSInterfaceID InterfaceID, mDN // // 3) Scoped questions (non-zero ServiceID) should consider *only* scoped DNSServers (DNSServer // with "scoped" set to kScopeServiceID) and their ServiceIDs should match. - // + // // The first condition in the "if" statement checks to see if both the question and the DNSServer are // unscoped. The question is unscoped only if InterfaceID is zero and ServiceID is -1. // @@ -10715,7 +11023,7 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question) // match the scoped entries by mistake. // // Note: DNS configuration change will help pick the new dns servers but currently it does not affect the timeout - + // Skip DNSServers that are InterfaceID Scoped but have no valid interfaceid set OR DNSServers that are ServiceID Scoped but have no valid serviceid set if ((curr->scoped == kScopeInterfaceID && curr->interface == mDNSInterface_Any) || (curr->scoped == kScopeServiceID && curr->serviceID <= 0)) { @@ -10724,7 +11032,8 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question) } currcount = CountLabels(&curr->domain); - if ((!DEQuery || !curr->cellIntf) && DNSServerMatch(curr, question->InterfaceID, question->ServiceID)) + if ((!curr->cellIntf || (!DEQuery && !(question->flags & kDNSServiceFlagsDenyCellular))) && + DNSServerMatch(curr, question->InterfaceID, question->ServiceID)) { bettermatch = BetterMatchForName(&question->qname, namecount, &curr->domain, currcount, bestmatchlen); @@ -10963,7 +11272,7 @@ mDNSlocal mDNSBool ShouldSuppressUnicastQuery(mDNS *const m, DNSQuestion *q, DNS LogInfo("ShouldSuppressUnicastQuery: Query suppressed for %##s, qtype %s, as the DNS server is NULL", q->qname.c, DNSTypeName(q->qtype)); return mDNStrue; } - + // Check if the DNS Configuration allows A/AAAA queries to be sent if ((q->qtype == kDNSType_A) && (d->req_A)) { @@ -11037,6 +11346,12 @@ mDNSlocal mDNSBool ShouldSuppressDotLocalQuery(mDNS *const m, DNSQuestion *q) mDNSlocal mDNSBool ShouldSuppressQuery(mDNS *const m, DNSQuestion *q) { + if (q->InterfaceID == mDNSInterface_LocalOnly) + { + LogInfo("ShouldSuppressQuery: LocalOnly query not suppressed for %##s, qtype %s", q->qname.c, DNSTypeName(q->qtype)); + return mDNSfalse; + } + if (q->qtype != kDNSType_A && q->qtype != kDNSType_AAAA) { LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, not A/AAAA type", q->qname.c, DNSTypeName(q->qtype)); @@ -11310,7 +11625,7 @@ mDNSlocal void RestartUnicastQuestions(mDNS *const m) { if (mDNSOpaque16IsZero(q->TargetQID)) LogMsg("RestartUnicastQuestions: ERROR!! Restart set for multicast question %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); - + q->Restart = 0; SuppressStatusChanged(m, q, &restart); } @@ -11339,7 +11654,7 @@ mDNSlocal mStatus ValidateParameters(mDNS *const m, DNSQuestion *const question) } // If no question->Target specified, clear TargetPort - if (!question->Target.type) + if (!question->Target.type) question->TargetPort = zeroIPPort; if (!ValidateDomainName(&question->qname)) @@ -11349,14 +11664,14 @@ mDNSlocal mStatus ValidateParameters(mDNS *const m, DNSQuestion *const question) } // If this question is referencing a specific interface, verify it exists - if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly && question->InterfaceID != mDNSInterface_Unicast && question->InterfaceID != mDNSInterface_P2P) + if (question->InterfaceID && !LocalOnlyOrP2PInterface(question->InterfaceID) && question->InterfaceID != mDNSInterface_Unicast) { NetworkInterfaceInfo *intf = FirstInterfaceForID(m, question->InterfaceID); if (!intf) LogInfo("ValidateParameters: Note: InterfaceID %d for question %##s (%s) not currently found in active interface list", (uint32_t)question->InterfaceID, question->qname.c, DNSTypeName(question->qtype)); } - + return(mStatus_NoError); } @@ -11367,19 +11682,19 @@ mDNSlocal void InitDNSConfig(mDNS *const m, DNSQuestion *const question) // First reset all DNS Configuration question->qDNSServer = mDNSNULL; question->validDNSServers = zeroOpaque64; - question->triedAllServersOnce = 0; - question->noServerResponse = 0; + question->triedAllServersOnce = 0; + question->noServerResponse = 0; question->StopTime = 0; #if TARGET_OS_EMBEDDED mDNSPlatformMemZero(&question->metrics, sizeof(question->metrics)); #endif // Need not initialize the DNS Configuration for Local Only OR P2P Questions - if (question->InterfaceID == mDNSInterface_LocalOnly || question->InterfaceID == mDNSInterface_P2P) + if (LocalOnlyOrP2PInterface(question->InterfaceID)) return; // Proceed to initialize DNS Configuration (some are set in SetValidDNSServers()) if (!mDNSOpaque16IsZero(question->TargetQID)) - { + { mDNSu32 timeout = SetValidDNSServers(m, question); // We set the timeout whenever mDNS_StartQuery_internal is called. This means if we have // a networking change/search domain change that calls this function again we keep @@ -11402,7 +11717,7 @@ mDNSlocal void InitDNSConfig(mDNS *const m, DNSQuestion *const question) mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort)); } else - { + { if (question->TimeoutQuestion) question->StopTime = NonZeroTime(m->timenow + GetTimeoutForMcastQuestion(m, question) * mDNSPlatformOneSecond); } @@ -11411,7 +11726,7 @@ mDNSlocal void InitDNSConfig(mDNS *const m, DNSQuestion *const question) SetNextQueryStopTime(m, question); // SetNextQueryTime() need not be initialized for LocalOnly OR P2P Questions since those questions // will never be transmitted on the wire. Hence we call SetNextQueryTime() here. - SetNextQueryTime(m,question); + SetNextQueryTime(m,question); } // InitCommonState() is called by mDNS_StartQuery_internal() to initialize the common(uDNS/mDNS) internal @@ -11420,7 +11735,7 @@ mDNSlocal mDNSBool InitCommonState(mDNS *const m, DNSQuestion *const question) { mDNSBool purge; int i; - mDNSBool isCellBlocked = mDNSfalse; + mDNSBool isBlocked = mDNSfalse; // Note: In the case where we already have the answer to this question in our cache, that may be all the client // wanted, and they may immediately cancel their question. In this case, sending an actual query on the wire would @@ -11468,15 +11783,21 @@ mDNSlocal mDNSBool InitCommonState(mDNS *const m, DNSQuestion *const question) question->LOAddressAnswers = 0; question->FlappingInterface1 = mDNSNULL; question->FlappingInterface2 = mDNSNULL; - - // if kDNSServiceFlagsServiceIndex flag is SET by the client, then do NOT call mDNSPlatformGetDNSRoutePolicy() - // since we would already have the question->ServiceID in that case. - if (!(question->flags & kDNSServiceFlagsServiceIndex)) - mDNSPlatformGetDNSRoutePolicy(m, question, &isCellBlocked); - else - LogInfo("InitCommonState: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] is already set by client", question->qname.c, + + // if kDNSServiceFlagsServiceIndex flag is SET by the client, then do NOT call mDNSPlatformGetDNSRoutePolicy() + // since we would already have the question->ServiceID in that case. + if (!(question->flags & kDNSServiceFlagsServiceIndex)) + { +#if APPLE_OSX_mDNSResponder + mDNSPlatformGetDNSRoutePolicy(m, question, &isBlocked); +#else + question->ServiceID = -1; +#endif + } + else + LogInfo("InitCommonState: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] is already set by client", question->qname.c, DNSTypeName(question->qtype), question->pid, question->euid, question->ServiceID); - + InitDNSConfig(m, question); question->AuthInfo = GetAuthInfoForQuestion(m, question); @@ -11486,7 +11807,7 @@ mDNSlocal mDNSBool InitCommonState(mDNS *const m, DNSQuestion *const question) // If ServiceID is 0 or the policy disallows making DNS requests, // set DisallowPID - question->DisallowPID = (question->ServiceID == 0 || (isCellBlocked && question->qDNSServer && question->qDNSServer->cellIntf)); + question->DisallowPID = (question->ServiceID == 0 || isBlocked); if (question->DisallowPID) LogInfo("InitCommonState: Query suppressed for %##s (%s), PID %d/ServiceID %d not allowed", question->qname.c, DNSTypeName(question->qtype), question->pid, question->ServiceID); @@ -11494,47 +11815,27 @@ mDNSlocal mDNSBool InitCommonState(mDNS *const m, DNSQuestion *const question) question->NextInDQList = mDNSNULL; question->SendQNow = mDNSNULL; question->SendOnAll = mDNSfalse; - -#if mDNS_REQUEST_UNICAST_RESPONSE - question->RequestUnicast = SET_QU_IN_FIRST_FOUR_QUERIES; -#else // mDNS_REQUEST_UNICAST_RESPONSE - question->RequestUnicast = SET_QU_IN_FIRST_QUERY; -#endif // mDNS_REQUEST_UNICAST_RESPONSE + question->RequestUnicast = kDefaultRequestUnicastCount; #if APPLE_OSX_mDNSResponder - // Request unicast response for first 4 queries to increase - // reliability in an environment with high multicast packet loss. - // Must set to one more than the number of unicast queries you want, since SendQueries() - // decrements it before calling BuildQuestion() which acts on it. - if (question->flags & kDNSServiceFlagsUnicastResponse) + // Set the QU bit in the first query for the following options. + if ((question->flags & kDNSServiceFlagsUnicastResponse) || (question->flags & kDNSServiceFlagsThresholdFinder)) { - question->RequestUnicast = SET_QU_IN_FIRST_FOUR_QUERIES; + question->RequestUnicast = SET_QU_IN_FIRST_QUERY; LogInfo("InitCommonState: setting RequestUnicast = %d for %##s (%s)", question->RequestUnicast, question->qname.c, DNSTypeName(question->qtype)); - } - else if (question->flags & kDNSServiceFlagsThresholdFinder) - { - // always send one request with QU bit set when kDNSServiceFlagsThresholdFinder is set -#if mDNS_REQUEST_UNICAST_RESPONSE - question->RequestUnicast = SET_QU_IN_FIRST_FOUR_QUERIES; -#else // mDNS_REQUEST_UNICAST_RESPONSE - question->RequestUnicast = SET_QU_IN_FIRST_QUERY; -#endif // mDNS_REQUEST_UNICAST_RESPONSE - - LogInfo("InitCommonState: kDNSServiceFlagsThresholdFinder set, setting RequestUnicast = %d for %##s (%s)", - question->RequestUnicast, question->qname.c, DNSTypeName(question->qtype)); } #endif // APPLE_OSX_mDNSResponder question->LastQTxTime = m->timenow; - question->CNAMEReferrals = 0; + question->CNAMEReferrals = 0; question->WakeOnResolveCount = 0; if (question->WakeOnResolve) - { + { question->WakeOnResolveCount = InitialWakeOnResolveCount; purge = mDNStrue; - } + } for (i=0; iDupSuppress[i].InterfaceID = mDNSNULL; @@ -11561,7 +11862,7 @@ mDNSlocal void InitWABState(DNSQuestion *const question) // We won't need one for duplicate questions, or from questions answered immediately out of the cache. // We also don't need one for LLQs because (when we're using NAT) we want them all to share a single // NAT mapping for receiving inbound add/remove events. - question->LocalSocket = mDNSNULL; + question->LocalSocket = mDNSNULL; question->unansweredQueries = 0; question->nta = mDNSNULL; question->servAddr = zeroAddr; @@ -11593,6 +11894,11 @@ mDNSlocal void InitLLQState(DNSQuestion *const question) question->id = zeroOpaque64; } +mDNSlocal void InitDNSPNState(DNSQuestion *const question) +{ + question->dnsPushState = DNSPUSH_INIT; +} + // InitDNSSECProxyState() is called by mDNS_StartQuery_internal() to initialize // DNSSEC & DNS Proxy fields of the DNS Question. mDNSlocal void InitDNSSECProxyState(mDNS *const m, DNSQuestion *const question) @@ -11680,19 +11986,30 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu vStatus = ValidateParameters(m, question); if (vStatus) return(vStatus); - + +#ifdef USE_LIBIDN + // If the TLD includes high-ascii bytes, assume it will need to be converted to Punycode. + // (In the future the root name servers may answer UTF-8 queries directly, but for now they do not.) + if (IsHighASCIILabel(LastLabel(&question->qname))) + { + domainname newname; + if (PerformNextPunycodeConversion(question, &newname)) + AssignDomainName(&question->qname, &newname); + } +#endif // USE_LIBIDN + question->TargetQID = #ifndef UNICAST_DISABLED (question->Target.type || Question_uDNS(question)) ? mDNS_NewMessageID(m) : #endif // UNICAST_DISABLED zeroID; - debugf("mDNS_StartQuery_internal: %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); - + debugf("mDNS_StartQuery_internal: %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); + // Note: It important that new questions are appended at the *end* of the list, not prepended at the start q = &m->Questions; - if (question->InterfaceID == mDNSInterface_LocalOnly || question->InterfaceID == mDNSInterface_P2P) + if (LocalOnlyOrP2PInterface(question->InterfaceID)) q = &m->LocalOnlyQuestions; - while (*q && *q != question) + while (*q && *q != question) q=&(*q)->next; if (*q) @@ -11702,7 +12019,6 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu return(mStatus_AlreadyRegistered); } *q = question; - // Intialize the question. The only ordering constraint we have today is that // InitDNSSECProxyState should be called after the DNS server is selected (in @@ -11712,23 +12028,24 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu purge = InitCommonState(m, question); InitWABState(question); InitLLQState(question); + InitDNSPNState(question); InitDNSSECProxyState(m, question); // FindDuplicateQuestion should be called last after all the intialization // as the duplicate logic could be potentially based on any field in the // question. question->DuplicateOf = FindDuplicateQuestion(m, question); - if (question->DuplicateOf) - question->AuthInfo = question->DuplicateOf->AuthInfo; + if (question->DuplicateOf) + question->AuthInfo = question->DuplicateOf->AuthInfo; - if (question->InterfaceID == mDNSInterface_LocalOnly || question->InterfaceID == mDNSInterface_P2P) + if (LocalOnlyOrP2PInterface(question->InterfaceID)) { - if (!m->NewLocalOnlyQuestions) + if (!m->NewLocalOnlyQuestions) m->NewLocalOnlyQuestions = question; } else { - if (!m->NewQuestions) + if (!m->NewQuestions) m->NewQuestions = question; // If the question's id is non-zero, then it's Wide Area @@ -11743,13 +12060,22 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu } else { -#if TARGET_OS_WATCH - m->NumAllInterfaceQuestions++; - LogInfo("mDNS_StartQuery_internal: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %##s (%s)", - m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, question->qname.c, DNSTypeName(question->qtype)); - if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1) - m->NetworkChanged = m->timenow; -#endif +#if BONJOUR_ON_DEMAND + m->NumAllInterfaceQuestions++; + LogInfo("mDNS_StartQuery_internal: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %##s (%s)", + m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, question->qname.c, DNSTypeName(question->qtype)); + if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1) + { + m->NextBonjourDisableTime = 0; + if (m->BonjourEnabled == 0) + { + // Enable Bonjour immediately by scheduling network changed processing where + // we will join the multicast group on each active interface. + m->BonjourEnabled = 1; + m->NetworkChanged = m->timenow; + } + } +#endif // BONJOUR_ON_DEMAND if (purge) { LogInfo("mDNS_StartQuery_internal: Purging for %##s", question->qname.c); @@ -11786,7 +12112,8 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que //LogInfo("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); - if (question->InterfaceID == mDNSInterface_LocalOnly || question->InterfaceID == mDNSInterface_P2P) qp = &m->LocalOnlyQuestions; + if (LocalOnlyOrP2PInterface(question->InterfaceID)) + qp = &m->LocalOnlyQuestions; while (*qp && *qp != question) qp=&(*qp)->next; if (*qp) *qp = (*qp)->next; else @@ -11798,29 +12125,36 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que return(mStatus_BadReferenceErr); } -#if TARGET_OS_WATCH - if (question->InterfaceID != mDNSInterface_LocalOnly && question->InterfaceID != mDNSInterface_P2P && mDNSOpaque16IsZero(question->TargetQID)) +#if BONJOUR_ON_DEMAND + if (!LocalOnlyOrP2PInterface(question->InterfaceID) && mDNSOpaque16IsZero(question->TargetQID)) { - if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1) - m->NetworkChanged = m->timenow; - m->NumAllInterfaceQuestions--; - LogInfo("mDNS_StopQuery_internal: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %##s (%s)", - m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, question->qname.c, DNSTypeName(question->qtype)); + if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1) + m->NextBonjourDisableTime = NonZeroTime(m->timenow + (BONJOUR_DISABLE_DELAY * mDNSPlatformOneSecond)); + m->NumAllInterfaceQuestions--; + LogInfo("mDNS_StopQuery_internal: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %##s (%s)", + m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, question->qname.c, DNSTypeName(question->qtype)); } -#endif +#endif // BONJOUR_ON_DEMAND #if TARGET_OS_EMBEDDED - if (Question_uDNS(question) && !question->metrics.answered) + if (Question_uDNS(question) && !question->metrics.answered && (question->metrics.querySendCount > 0)) { - uDNSMetrics * metrics; const domainname * queryName; - mDNSBool isForCellular; + mDNSBool isForCell; + mDNSu32 durationMs; - metrics = &question->metrics; - queryName = metrics->originalQName ? metrics->originalQName : &question->qname; - isForCellular = (question->qDNSServer && question->qDNSServer->cellIntf); + queryName = question->metrics.originalQName ? question->metrics.originalQName : &question->qname; + isForCell = (question->qDNSServer && question->qDNSServer->cellIntf); - MetricsUpdateUDNSStats(queryName, mDNSfalse, metrics->querySendCount, 0, isForCellular); + if (question->metrics.querySendCount > 0) + { + durationMs = ((m->timenow - question->metrics.firstQueryTime) * 1000) / mDNSPlatformOneSecond; + } + else + { + durationMs = 0; + } + MetricsUpdateUDNSQueryStats(queryName, question->qtype, mDNSNULL, question->metrics.querySendCount, durationMs, isForCell); } #endif // Take care to cut question from list *before* calling UpdateQuestionDuplicates @@ -11835,16 +12169,31 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que if (rr->CRActiveQuestion == question) { DNSQuestion *q; - // Checking for ActiveQuestion filters questions that are suppressed also - // as suppressed questions are not active - for (q = m->Questions; q; q=q->next) // Scan our list of questions - if (ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q)) - break; - if (q) + DNSQuestion *replacement = mDNSNULL; + // If we find an active question that is answered by this cached record, use it as the cache record's + // CRActiveQuestion replacement. If there are no such questions, but there's at least one unsuppressed inactive + // question that is answered by this cache record, then use an inactive one to not forgo generating RMV events + // via CacheRecordRmv() when the cache record expires. + for (q = m->Questions; q && (q != m->NewQuestions); q = q->next) + { + if (!q->DuplicateOf && !QuerySuppressed(q) && ResourceRecordAnswersQuestion(&rr->resrec, q)) + { + if (q->ThisQInterval > 0) + { + replacement = q; + break; + } + else if (!replacement) + { + replacement = q; + } + } + } + if (replacement) debugf("mDNS_StopQuery_internal: Updating CRActiveQuestion to %p for cache record %s, Original question CurrentAnswers %d, new question " - "CurrentAnswers %d, SuppressQuery %d", q, CRDisplayString(m,rr), question->CurrentAnswers, q->CurrentAnswers, q->SuppressQuery); - rr->CRActiveQuestion = q; // Question used to be active; new value may or may not be null - if (!q) m->rrcache_active--; // If no longer active, decrement rrcache_active count + "CurrentAnswers %d, SuppressQuery %d", replacement, CRDisplayString(m,rr), question->CurrentAnswers, replacement->CurrentAnswers, replacement->SuppressQuery); + rr->CRActiveQuestion = replacement; // Question used to be active; new value may or may not be null + if (!replacement) m->rrcache_active--; // If no longer active, decrement rrcache_active count } } @@ -11927,6 +12276,15 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que question->tcp = mDNSNULL; } } + else if (question->dnsPushState == DNSPUSH_ESTABLISHED) + { + if (question->tcp) + { + UnSubscribeToDNSPushNotificationServer(m, q); + question->tcp->question = mDNSNULL; + question->tcp = mDNSNULL; + } + } #if APPLE_OSX_mDNSResponder UpdateAutoTunnelDomainStatuses(m); #endif @@ -12043,10 +12401,8 @@ mDNSlocal mStatus mDNS_StartBrowse_internal(mDNS *const m, DNSQuestion *const qu question->LongLived = mDNStrue; question->ExpectUnique = mDNSfalse; question->ForceMCast = ForceMCast; - question->ReturnIntermed = mDNSfalse; + question->ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0; question->SuppressUnusable = mDNSfalse; - question->DenyOnCellInterface = mDNSfalse; - question->DenyOnExpInterface = mDNSfalse; question->SearchListIndex = 0; question->AppendSearchDomains = 0; question->RetryWithSearchDomains = mDNSfalse; @@ -12087,295 +12443,6 @@ mDNSexport mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question, return(status); } -mDNSlocal mDNSBool MachineHasActiveIPv6(mDNS *const m) -{ - NetworkInterfaceInfo *intf; - for (intf = m->HostInterfaces; intf; intf = intf->next) - if (intf->ip.type == mDNSAddrType_IPv6) return(mDNStrue); - return(mDNSfalse); -} - -mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) -{ - ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext; - mDNSBool PortChanged = !mDNSSameIPPort(query->info->port, answer->rdata->u.srv.port); - if (!AddRecord) return; - if (answer->rrtype != kDNSType_SRV) return; - - query->info->port = answer->rdata->u.srv.port; - - // If this is our first answer, then set the GotSRV flag and start the address query - if (!query->GotSRV) - { - query->GotSRV = mDNStrue; - query->qAv4.InterfaceID = answer->InterfaceID; - AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target); - query->qAv6.InterfaceID = answer->InterfaceID; - AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target); - mDNS_StartQuery(m, &query->qAv4); - // Only do the AAAA query if this machine actually has IPv6 active - if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6); - } - // If this is not our first answer, only re-issue the address query if the target host name has changed - else if ((query->qAv4.InterfaceID != query->qSRV.InterfaceID && query->qAv4.InterfaceID != answer->InterfaceID) || - !SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target)) - { - mDNS_StopQuery(m, &query->qAv4); - if (query->qAv6.ThisQInterval >= 0) mDNS_StopQuery(m, &query->qAv6); - if (SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target) && !PortChanged) - { - // If we get here, it means: - // 1. This is not our first SRV answer - // 2. The interface ID is different, but the target host and port are the same - // This implies that we're seeing the exact same SRV record on more than one interface, so we should - // make our address queries at least as broad as the original SRV query so that we catch all the answers. - query->qAv4.InterfaceID = query->qSRV.InterfaceID; // Will be mDNSInterface_Any, or a specific interface - query->qAv6.InterfaceID = query->qSRV.InterfaceID; - } - else - { - query->qAv4.InterfaceID = answer->InterfaceID; - AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target); - query->qAv6.InterfaceID = answer->InterfaceID; - AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target); - } - debugf("FoundServiceInfoSRV: Restarting address queries for %##s (%s)", query->qAv4.qname.c, DNSTypeName(query->qAv4.qtype)); - mDNS_StartQuery(m, &query->qAv4); - // Only do the AAAA query if this machine actually has IPv6 active - if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6); - } - else if (query->ServiceInfoQueryCallback && query->GotADD && query->GotTXT && PortChanged) - { - if (++query->Answers >= 100) - debugf("**** WARNING **** Have given %lu answers for %##s (SRV) %##s %u", - query->Answers, query->qSRV.qname.c, answer->rdata->u.srv.target.c, - mDNSVal16(answer->rdata->u.srv.port)); - query->ServiceInfoQueryCallback(m, query); - } - // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's - // callback function is allowed to do anything, including deleting this query and freeing its memory. -} - -mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) -{ - ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext; - if (!AddRecord) return; - if (answer->rrtype != kDNSType_TXT) return; - if (answer->rdlength > sizeof(query->info->TXTinfo)) return; - - query->GotTXT = mDNStrue; - query->info->TXTlen = answer->rdlength; - query->info->TXTinfo[0] = 0; // In case answer->rdlength is zero - mDNSPlatformMemCopy(query->info->TXTinfo, answer->rdata->u.txt.c, answer->rdlength); - - verbosedebugf("FoundServiceInfoTXT: %##s GotADD=%d", query->info->name.c, query->GotADD); - - // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's - // callback function is allowed to do anything, including deleting this query and freeing its memory. - if (query->ServiceInfoQueryCallback && query->GotADD) - { - if (++query->Answers >= 100) - debugf("**** WARNING **** have given %lu answers for %##s (TXT) %#s...", - query->Answers, query->qSRV.qname.c, answer->rdata->u.txt.c); - query->ServiceInfoQueryCallback(m, query); - } -} - -mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) -{ - ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext; - //LogInfo("FoundServiceInfo %d %s", AddRecord, RRDisplayString(m, answer)); - if (!AddRecord) return; - - if (answer->rrtype == kDNSType_A) - { - query->info->ip.type = mDNSAddrType_IPv4; - query->info->ip.ip.v4 = answer->rdata->u.ipv4; - } - else if (answer->rrtype == kDNSType_AAAA) - { - query->info->ip.type = mDNSAddrType_IPv6; - query->info->ip.ip.v6 = answer->rdata->u.ipv6; - } - else - { - debugf("FoundServiceInfo: answer %##s type %d (%s) unexpected", answer->name->c, answer->rrtype, DNSTypeName(answer->rrtype)); - return; - } - - query->GotADD = mDNStrue; - query->info->InterfaceID = answer->InterfaceID; - - verbosedebugf("FoundServiceInfo v%ld: %##s GotTXT=%d", query->info->ip.type, query->info->name.c, query->GotTXT); - - // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's - // callback function is allowed to do anything, including deleting this query and freeing its memory. - if (query->ServiceInfoQueryCallback && query->GotTXT) - { - if (++query->Answers >= 100) - debugf(answer->rrtype == kDNSType_A ? - "**** WARNING **** have given %lu answers for %##s (A) %.4a" : - "**** WARNING **** have given %lu answers for %##s (AAAA) %.16a", - query->Answers, query->qSRV.qname.c, &answer->rdata->u.data); - query->ServiceInfoQueryCallback(m, query); - } -} - -// On entry, the client must have set the name and InterfaceID fields of the ServiceInfo structure -// If the query is not interface-specific, then InterfaceID may be zero -// Each time the Callback is invoked, the remainder of the fields will have been filled in -// In addition, InterfaceID will be updated to give the interface identifier corresponding to that response -mDNSexport mStatus mDNS_StartResolveService(mDNS *const m, - ServiceInfoQuery *query, ServiceInfo *info, mDNSServiceInfoQueryCallback *Callback, void *Context) -{ - mStatus status; - mDNS_Lock(m); - - query->qSRV.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question - query->qSRV.InterfaceID = info->InterfaceID; - query->qSRV.flags = 0; - query->qSRV.Target = zeroAddr; - AssignDomainName(&query->qSRV.qname, &info->name); - query->qSRV.qtype = kDNSType_SRV; - query->qSRV.qclass = kDNSClass_IN; - query->qSRV.LongLived = mDNSfalse; - query->qSRV.ExpectUnique = mDNStrue; - query->qSRV.ForceMCast = mDNSfalse; - query->qSRV.ReturnIntermed = mDNSfalse; - query->qSRV.SuppressUnusable = mDNSfalse; - query->qSRV.DenyOnCellInterface = mDNSfalse; - query->qSRV.DenyOnExpInterface = mDNSfalse; - query->qSRV.SearchListIndex = 0; - query->qSRV.AppendSearchDomains = 0; - query->qSRV.RetryWithSearchDomains = mDNSfalse; - query->qSRV.TimeoutQuestion = 0; - query->qSRV.WakeOnResolve = 0; - query->qSRV.UseBackgroundTrafficClass = mDNSfalse; - query->qSRV.ValidationRequired = 0; - query->qSRV.ValidatingResponse = 0; - query->qSRV.ProxyQuestion = 0; - query->qSRV.qnameOrig = mDNSNULL; - query->qSRV.AnonInfo = mDNSNULL; - query->qSRV.QuestionCallback = FoundServiceInfoSRV; - query->qSRV.QuestionContext = query; - - query->qTXT.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question - query->qTXT.InterfaceID = info->InterfaceID; - query->qTXT.flags = 0; - query->qTXT.Target = zeroAddr; - AssignDomainName(&query->qTXT.qname, &info->name); - query->qTXT.qtype = kDNSType_TXT; - query->qTXT.qclass = kDNSClass_IN; - query->qTXT.LongLived = mDNSfalse; - query->qTXT.ExpectUnique = mDNStrue; - query->qTXT.ForceMCast = mDNSfalse; - query->qTXT.ReturnIntermed = mDNSfalse; - query->qTXT.SuppressUnusable = mDNSfalse; - query->qTXT.DenyOnCellInterface = mDNSfalse; - query->qTXT.DenyOnExpInterface = mDNSfalse; - query->qTXT.SearchListIndex = 0; - query->qTXT.AppendSearchDomains = 0; - query->qTXT.RetryWithSearchDomains = mDNSfalse; - query->qTXT.TimeoutQuestion = 0; - query->qTXT.WakeOnResolve = 0; - query->qTXT.UseBackgroundTrafficClass = mDNSfalse; - query->qTXT.ValidationRequired = 0; - query->qTXT.ValidatingResponse = 0; - query->qTXT.ProxyQuestion = 0; - query->qTXT.qnameOrig = mDNSNULL; - query->qTXT.AnonInfo = mDNSNULL; - query->qTXT.QuestionCallback = FoundServiceInfoTXT; - query->qTXT.QuestionContext = query; - - query->qAv4.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question - query->qAv4.InterfaceID = info->InterfaceID; - query->qAv4.flags = 0; - query->qAv4.Target = zeroAddr; - query->qAv4.qname.c[0] = 0; - query->qAv4.qtype = kDNSType_A; - query->qAv4.qclass = kDNSClass_IN; - query->qAv4.LongLived = mDNSfalse; - query->qAv4.ExpectUnique = mDNStrue; - query->qAv4.ForceMCast = mDNSfalse; - query->qAv4.ReturnIntermed = mDNSfalse; - query->qAv4.SuppressUnusable = mDNSfalse; - query->qAv4.DenyOnCellInterface = mDNSfalse; - query->qAv4.DenyOnExpInterface = mDNSfalse; - query->qAv4.SearchListIndex = 0; - query->qAv4.AppendSearchDomains = 0; - query->qAv4.RetryWithSearchDomains = mDNSfalse; - query->qAv4.TimeoutQuestion = 0; - query->qAv4.WakeOnResolve = 0; - query->qAv4.UseBackgroundTrafficClass = mDNSfalse; - query->qAv4.ValidationRequired = 0; - query->qAv4.ValidatingResponse = 0; - query->qAv4.ProxyQuestion = 0; - query->qAv4.qnameOrig = mDNSNULL; - query->qAv4.AnonInfo = mDNSNULL; - query->qAv4.QuestionCallback = FoundServiceInfo; - query->qAv4.QuestionContext = query; - - query->qAv6.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question - query->qAv6.InterfaceID = info->InterfaceID; - query->qAv6.flags = 0; - query->qAv6.Target = zeroAddr; - query->qAv6.qname.c[0] = 0; - query->qAv6.qtype = kDNSType_AAAA; - query->qAv6.qclass = kDNSClass_IN; - query->qAv6.LongLived = mDNSfalse; - query->qAv6.ExpectUnique = mDNStrue; - query->qAv6.ForceMCast = mDNSfalse; - query->qAv6.ReturnIntermed = mDNSfalse; - query->qAv6.SuppressUnusable = mDNSfalse; - query->qAv6.DenyOnCellInterface = mDNSfalse; - query->qAv6.DenyOnExpInterface = mDNSfalse; - query->qAv6.SearchListIndex = 0; - query->qAv6.AppendSearchDomains = 0; - query->qAv6.RetryWithSearchDomains = mDNSfalse; - query->qAv6.TimeoutQuestion = 0; - query->qAv6.UseBackgroundTrafficClass = mDNSfalse; - query->qAv6.ValidationRequired = 0; - query->qAv6.ValidatingResponse = 0; - query->qAv6.ProxyQuestion = 0; - query->qAv6.qnameOrig = mDNSNULL; - query->qAv6.AnonInfo = mDNSNULL; - query->qAv6.QuestionCallback = FoundServiceInfo; - query->qAv6.QuestionContext = query; - - query->GotSRV = mDNSfalse; - query->GotTXT = mDNSfalse; - query->GotADD = mDNSfalse; - query->Answers = 0; - - query->info = info; - query->ServiceInfoQueryCallback = Callback; - query->ServiceInfoQueryContext = Context; - -// info->name = Must already be set up by client -// info->interface = Must already be set up by client - info->ip = zeroAddr; - info->port = zeroIPPort; - info->TXTlen = 0; - - // We use mDNS_StartQuery_internal here because we're already holding the lock - status = mDNS_StartQuery_internal(m, &query->qSRV); - if (status == mStatus_NoError) status = mDNS_StartQuery_internal(m, &query->qTXT); - if (status != mStatus_NoError) mDNS_StopResolveService(m, query); - - mDNS_Unlock(m); - return(status); -} - -mDNSexport void mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *q) -{ - mDNS_Lock(m); - // We use mDNS_StopQuery_internal here because we're already holding the lock - if (q->qSRV.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qSRV); - if (q->qTXT.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qTXT); - if (q->qAv4.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qAv4); - if (q->qAv6.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qAv6); - mDNS_Unlock(m); -} mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom, const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context) @@ -12390,8 +12457,6 @@ mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, m question->ForceMCast = mDNSfalse; question->ReturnIntermed = mDNSfalse; question->SuppressUnusable = mDNSfalse; - question->DenyOnCellInterface = mDNSfalse; - question->DenyOnExpInterface = mDNSfalse; question->SearchListIndex = 0; question->AppendSearchDomains = 0; question->RetryWithSearchDomains = mDNSfalse; @@ -12404,7 +12469,7 @@ mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, m question->qnameOrig = mDNSNULL; question->AnonInfo = mDNSNULL; question->pid = mDNSPlatformGetPID(); - question->euid = 0; + question->euid = 0; question->QuestionCallback = Callback; question->QuestionContext = Context; if (DomainType > mDNS_DomainTypeMax) return(mStatus_BadParamErr); @@ -12615,6 +12680,10 @@ mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set) return; } +#if APPLE_OSX_mDNSResponder + D2D_stop_advertising_interface(set); +#endif // APPLE_OSX_mDNSResponder + // Unregister these records. // When doing the mDNS_Exit processing, we first call DeadvertiseInterface for each interface, so by the time the platform // support layer gets to call mDNS_DeregisterInterface, the address and PTR records have already been deregistered for it. @@ -12623,11 +12692,6 @@ mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set) if (set->RR_A .resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_A, mDNS_Dereg_normal); if (set->RR_PTR .resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_PTR, mDNS_Dereg_normal); if (set->RR_HINFO.resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_HINFO, mDNS_Dereg_normal); - -#if APPLE_OSX_mDNSResponder - D2D_stop_advertising_interface(set); -#endif // APPLE_OSX_mDNSResponder - } mDNSlocal void AdvertiseAllInterfaceRecords(mDNS *const m) @@ -12656,6 +12720,23 @@ mDNSlocal void DeadvertiseAllInterfaceRecords(mDNS *const m) } } +// Change target host name for record. +mDNSlocal void UpdateTargetHostName(mDNS *const m, AuthRecord *const rr) +{ +#if APPLE_OSX_mDNSResponder + // If this record was also registered with any D2D plugins, stop advertising + // the version with the old host name. + D2D_stop_advertising_record(rr); +#endif + + SetTargetToHostName(m, rr); + +#if APPLE_OSX_mDNSResponder + // Advertise the record with the updated host name with the D2D plugins if appropriate. + D2D_start_advertising_record(rr); +#endif +} + mDNSexport void mDNS_SetFQDN(mDNS *const m) { domainname newmname; @@ -12676,8 +12757,8 @@ mDNSexport void mDNS_SetFQDN(mDNS *const m) } // 3. Make sure that any AutoTarget SRV records (and the like) get updated - for (rr = m->ResourceRecords; rr; rr=rr->next) if (rr->AutoTarget) SetTargetToHostName(m, rr); - for (rr = m->DuplicateRecords; rr; rr=rr->next) if (rr->AutoTarget) SetTargetToHostName(m, rr); + for (rr = m->ResourceRecords; rr; rr=rr->next) if (rr->AutoTarget) UpdateTargetHostName(m, rr); + for (rr = m->DuplicateRecords; rr; rr=rr->next) if (rr->AutoTarget) UpdateTargetHostName(m, rr); mDNS_Unlock(m); } @@ -12766,7 +12847,7 @@ mDNSlocal void InitializeNetWakeState(mDNS *const m, NetworkInterfaceInfo *set) // be stopped during interface deregistration. We can't sanity check to see if the // question has been stopped or not before initializing it to -1 because we need to // initialize it to -1 the very first time. - + set->NetWakeBrowse.ThisQInterval = -1; for (i=0; i<3; i++) { @@ -12916,6 +12997,7 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s } LogInfo("mDNS_RegisterInterface: %s (%#a) probedelay %d", set->ifname, &set->ip, probedelay); + if (m->SuppressProbes == 0 || m->SuppressProbes - NonZeroTime(m->timenow + probedelay) < 0) m->SuppressProbes = NonZeroTime(m->timenow + probedelay); @@ -12942,14 +13024,8 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s if (!q->ThisQInterval || q->ThisQInterval > initial) { - q->ThisQInterval = initial; - -#if mDNS_REQUEST_UNICAST_RESPONSE - q->RequestUnicast = SET_QU_IN_FIRST_FOUR_QUERIES; -#else // mDNS_REQUEST_UNICAST_RESPONSE - q->RequestUnicast = SET_QU_IN_FIRST_QUERY; -#endif // mDNS_REQUEST_UNICAST_RESPONSE - + q->ThisQInterval = initial; + q->RequestUnicast = kDefaultRequestUnicastCount; } q->LastQTime = m->timenow - q->ThisQInterval + qdelay; q->RecentAnswerPkts = 0; @@ -13235,13 +13311,17 @@ mDNSlocal void NSSCallback(mDNS *const m, AuthRecord *const rr, mStatus result) } +// Derive AuthRecType from the coreFlag* values. +// Note, this is not using the external flags values, kDNSServiceFlags*, defined in dns_sd.h. +// It should be changed to do so once the use of coreFlag* is completely replaced with +// the use the kDNSServiceFlags* definitions within mDNSResponder. mDNSlocal AuthRecType setAuthRecType(mDNSInterfaceID InterfaceID, mDNSu32 flags) { AuthRecType artype; if (InterfaceID == mDNSInterface_LocalOnly) artype = AuthRecordLocalOnly; - else if (InterfaceID == mDNSInterface_P2P) + else if (InterfaceID == mDNSInterface_P2P || InterfaceID == mDNSInterface_BLE) artype = AuthRecordP2P; else if ((InterfaceID == mDNSInterface_Any) && (flags & coreFlagIncludeP2P) && (flags & coreFlagIncludeAWDL)) @@ -13256,6 +13336,18 @@ mDNSlocal AuthRecType setAuthRecType(mDNSInterfaceID InterfaceID, mDNSu32 flags) return artype; } +// Used to derive the original D2D specific flags specified by the client in the registration +// when we don't have access to the original flag (kDNSServiceFlags*) values. +mDNSexport mDNSu32 deriveD2DFlagsFromAuthRecType(AuthRecType authRecType) +{ + mDNSu32 flags = 0; + if ((authRecType == AuthRecordAnyIncludeP2P) || (authRecType == AuthRecordAnyIncludeAWDLandP2P)) + flags |= kDNSServiceFlagsIncludeP2P; + else if ((authRecType == AuthRecordAnyIncludeAWDL) || (authRecType == AuthRecordAnyIncludeAWDLandP2P)) + flags |= kDNSServiceFlagsIncludeAWDL; + return flags; +} + // Note: // Name is first label of domain name (any dots in the name are actual dots, not label separators) // Type is service type (e.g. "_ipp._tcp.") @@ -13310,8 +13402,8 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr, if (mDNSIPPortIsZero(port)) return(mDNS_RegisterNoSuchService(m, &sr->RR_SRV, name, type, domain, mDNSNULL, InterfaceID, NSSCallback, sr, flags)); - // If the client is registering an oversized TXT record, - // it is the client's responsibility to alloate a ServiceRecordSet structure that is large enough for it + // If the caller is registering an oversized TXT record, + // it is the caller's responsibility to allocate a ServiceRecordSet structure that is large enough for it if (sr->RR_TXT.resrec.rdata->MaxRDLength < txtlen) sr->RR_TXT.resrec.rdata->MaxRDLength = txtlen; @@ -13349,7 +13441,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr, sr->SubTypes[i].Additional1 = &sr->RR_SRV; sr->SubTypes[i].Additional2 = &sr->RR_TXT; } - + SetAnonInfoSRS(sr, NumSubTypes); // 3. Set up the SRV record rdata. @@ -13409,6 +13501,7 @@ mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, mStatus status; AuthRecType artype; mDNSInterfaceID InterfaceID = sr->RR_PTR.resrec.InterfaceID; + ResourceRecord *rr; artype = setAuthRecType(InterfaceID, flags); @@ -13418,6 +13511,37 @@ mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, AssignDomainName(&extra->r.namestorage, sr->RR_SRV.resrec.name); mDNS_Lock(m); + rr = mDNSNULL; + if (extra->r.resrec.rrtype == kDNSType_TXT) + { + if (sr->RR_TXT.resrec.RecordType & kDNSRecordTypeUniqueMask) rr = &sr->RR_TXT.resrec; + } + else if (extra->r.resrec.rrtype == kDNSType_SRV) + { + if (sr->RR_SRV.resrec.RecordType & kDNSRecordTypeUniqueMask) rr = &sr->RR_SRV.resrec; + } + + if (!rr) + { + ExtraResourceRecord *srExtra; + + for (srExtra = sr->Extras; srExtra; srExtra = srExtra->next) + { + if ((srExtra->r.resrec.rrtype == extra->r.resrec.rrtype) && (srExtra->r.resrec.RecordType & kDNSRecordTypeUniqueMask)) + { + rr = &srExtra->r.resrec; + break; + } + } + } + + if (rr && (extra->r.resrec.rroriginalttl != rr->rroriginalttl)) + { + LogMsg("mDNS_AddRecordToService: Correcting TTL from %4d to %4d for %s", + extra->r.resrec.rroriginalttl, rr->rroriginalttl, RRDisplayString(m, &extra->r.resrec)); + extra->r.resrec.rroriginalttl = rr->rroriginalttl; + } + e = &sr->Extras; while (*e) e = &(*e)->next; @@ -13593,7 +13717,7 @@ mDNSexport mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, if (InterfaceID == mDNSInterface_LocalOnly) artype = AuthRecordLocalOnly; - else if (InterfaceID == mDNSInterface_P2P) + else if (InterfaceID == mDNSInterface_P2P || InterfaceID == mDNSInterface_BLE) artype = AuthRecordP2P; else artype = AuthRecordAny; @@ -13820,9 +13944,9 @@ mDNSlocal void mDNSCoreReceiveRawND(mDNS *const m, const mDNSEthAddr *const sha, } else if (msg == msg3) mDNSPlatformSetLocalAddressCacheEntry(m, &rr->AddressProxy, &rr->WakeUp.IMAC, InterfaceID); - else if (msg == msg4) + else if (msg == msg4) SendNDP(m, NDP_Adv, NDP_Solicited, rr, &ndp->target, mDNSNULL, spa, sha); - else if (msg == msg5) + else if (msg == msg5) SendNDP(m, NDP_Adv, 0, rr, &ndp->target, mDNSNULL, &AllHosts_v6, &AllHosts_v6_Eth); } } @@ -14250,6 +14374,14 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, m->NextScheduledSPS = timenow + 0x78000000; m->NextScheduledKA = timenow + 0x78000000; m->NextScheduledStopTime = timenow + 0x78000000; + m->NextBLEServiceTime = 0; // zero indicates inactive + +#if BONJOUR_ON_DEMAND + m->NextBonjourDisableTime = 0; // Timer active when non zero. + m->BonjourEnabled = 0; // Set when Bonjour on Demand is enabled and Bonjour is currently enabled. +#endif // BONJOUR_ON_DEMAND + + m->DelayConflictProcessing = MAX_CONFLICT_PROCESSING_DELAYS; m->RandomQueryDelay = 0; m->RandomReconfirmDelay = 0; m->PktNum = 0; @@ -14334,19 +14466,11 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, m->WABBrowseQueriesCount = 0; m->WABLBrowseQueriesCount = 0; m->WABRegQueriesCount = 0; -#if TARGET_OS_EMBEDDED || TARGET_OS_WATCH m->AutoTargetServices = 0; -#else - m->AutoTargetServices = 1; -#endif -#if TARGET_OS_WATCH + +#if BONJOUR_ON_DEMAND m->NumAllInterfaceRecords = 0; m->NumAllInterfaceQuestions = 0; -#else - // Initialize to 1 for these targets to prevent not joining multicast group for interfaces when - // both of these values are zero. - m->NumAllInterfaceRecords = 1; - m->NumAllInterfaceQuestions = 1; #endif // NAT traversal fields m->LLQNAT.clientCallback = mDNSNULL; @@ -14386,6 +14510,8 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, m->SPSBrowseCallback = mDNSNULL; m->ProxyRecords = 0; + m->DNSPushServers = mDNSNULL; + m->DNSPushZones = mDNSNULL; #endif #if APPLE_OSX_mDNSResponder @@ -14612,6 +14738,23 @@ mDNSlocal void SetConfigState(mDNS *const m, mDNSBool delete) } } +mDNSlocal void SetDynDNSHostNameIfChanged(mDNS *const m, domainname *const fqdn) +{ + // Did our FQDN change? + if (!SameDomainName(fqdn, &m->FQDN)) + { + if (m->FQDN.c[0]) mDNS_RemoveDynDNSHostName(m, &m->FQDN); + + AssignDomainName(&m->FQDN, fqdn); + + if (m->FQDN.c[0]) + { + mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1); + mDNS_AddDynDNSHostName(m, &m->FQDN, DynDNSHostNameCallback, mDNSNULL); + } + } +} + mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) { mDNSu32 slot; @@ -14642,6 +14785,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) SetConfigState(m, mDNStrue); if (!mDNSPlatformSetDNSConfig(m, mDNStrue, mDNSfalse, &fqdn, mDNSNULL, mDNSNULL, mDNStrue)) { + SetDynDNSHostNameIfChanged(m, &fqdn); SetConfigState(m, mDNSfalse); mDNS_Unlock(m); LogInfo("uDNS_SetupDNSConfig: No configuration change"); @@ -14818,6 +14962,14 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNSfalse); } } + + // If a cache record's DNSServer pointer is NULL, but its active question got a DNSServer in this DNS configuration + // update, then use its DNSServer. This way, the active question and its duplicates don't miss out on RMV events. + if (!cr->resrec.rDNSServer && cr->CRActiveQuestion && cr->CRActiveQuestion->qDNSServer) + { + cr->resrec.rDNSServer = cr->CRActiveQuestion->qDNSServer; + LogInfo("uDNS_SetupDNSConfig: Using active question's DNS server %#a for cache record %s", &cr->resrec.rDNSServer->addr, CRDisplayString(m, cr)); + } } while (*p) @@ -14848,7 +15000,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) if (qptr->qDNSServer == ptr) { - LogMsg("uDNS_SetupDNSConfig: ERROR!! Cache Record %s Active question %##s (%s) (scope:%p) poining to DNSServer Address %#a" + LogMsg("uDNS_SetupDNSConfig: ERROR!! Cache Record %s Active question %##s (%s) (scope:%p) pointing to DNSServer Address %#a" " to be freed", CRDisplayString(m, cr), qptr->qname.c, DNSTypeName(qptr->qtype), qptr->InterfaceID, &ptr->addr); qptr->validDNSServers = zeroOpaque64; qptr->qDNSServer = mDNSNULL; @@ -14858,7 +15010,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) { LogInfo("uDNS_SetupDNSConfig: Cache Record %s, Active question %##s (%s) (scope:%p), pointing to DNSServer %#a (to be deleted)," " resetting to question's DNSServer Address %#a", CRDisplayString(m, cr), qptr->qname.c, DNSTypeName(qptr->qtype), - qptr->InterfaceID, &ptr->addr, (qptr->qDNSServer ? &qptr->qDNSServer->addr : mDNSNULL)); + qptr->InterfaceID, &ptr->addr, (qptr->qDNSServer) ? &qptr->qDNSServer->addr : mDNSNULL); cr->resrec.rDNSServer = qptr->qDNSServer; } } @@ -14905,19 +15057,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) RestartRecordGetZoneData(m); } - // Did our FQDN change? - if (!SameDomainName(&fqdn, &m->FQDN)) - { - if (m->FQDN.c[0]) mDNS_RemoveDynDNSHostName(m, &m->FQDN); - - AssignDomainName(&m->FQDN, &fqdn); - - if (m->FQDN.c[0]) - { - mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1); - mDNS_AddDynDNSHostName(m, &m->FQDN, DynDNSHostNameCallback, mDNSNULL); - } - } + SetDynDNSHostNameIfChanged(m, &fqdn); mDNS_Unlock(m); diff --git a/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h b/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h index 48f8280d..3fd654eb 100755 --- a/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h +++ b/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h @@ -96,9 +96,9 @@ extern "C" { #ifdef LIMITED_RESOURCES_TARGET // Don't support jumbo frames // 40 (IPv6 header) + 8 (UDP header) + 12 (DNS message header) + 1440 (DNS message body) = 1500 total -#define AbsoluteMaxDNSMessageData 1440 +#define AbsoluteMaxDNSMessageData 1440 // StandardAuthRDSize is 264 (256+8), which is large enough to hold a maximum-sized SRV record (6 + 256 bytes) -#define MaximumRDSize 264 +#define MaximumRDSize 264 #endif // *************************************************************************** @@ -297,20 +297,20 @@ typedef mDNSOpaque48 mDNSEthAddr; // An Ethernet address is a six-byte opa #define bit_clr_opaque64(op64, index) (op64.l[((index))/(sizeof(mDNSu32) * mDNSNBBY)] &= ~(1 << ((index) % (sizeof(mDNSu32) * mDNSNBBY)))) #define bit_get_opaque64(op64, index) (op64.l[((index))/(sizeof(mDNSu32) * mDNSNBBY)] & (1 << ((index) % (sizeof(mDNSu32) * mDNSNBBY)))) -enum +typedef enum { mDNSAddrType_None = 0, mDNSAddrType_IPv4 = 4, mDNSAddrType_IPv6 = 6, mDNSAddrType_Unknown = ~0 // Special marker value used in known answer list recording -}; +} mDNSAddr_Type; -enum +typedef enum { mDNSTransport_None = 0, mDNSTransport_UDP = 1, mDNSTransport_TCP = 2 -}; +} mDNSTransport_Type; typedef struct { @@ -364,7 +364,8 @@ enum mStatus_NoRouter = -65566, mStatus_PollingMode = -65567, mStatus_Timeout = -65568, - // -65568 to -65786 currently unused; available for allocation + mStatus_HostUnreachErr = -65569, + // -65570 to -65786 currently unused; available for allocation // tcp connection status mStatus_ConnPending = -65787, @@ -808,7 +809,7 @@ typedef struct TrustAnchor struct TrustAnchor *next; int digestLen; mDNSu32 validFrom; - mDNSu32 validUntil; + mDNSu32 validUntil; domainname zone; rdataDS rds; } TrustAnchor; @@ -875,10 +876,10 @@ typedef packedstruct // For example, SHA-1 hash of 20 bytes will be encoded as 20/5 * 8 = 32 base32 // bytes. For a max domain name size of 255 bytes of base32 encoding : (255/8)*5 // is the max hash length possible. -#define NSEC3_MAX_HASH_LEN 155 +#define NSEC3_MAX_HASH_LEN 155 // In NSEC3, the names are hashed and stored in the first label and hence cannot exceed label // size. -#define NSEC3_MAX_B32_LEN MAX_DOMAIN_LABEL +#define NSEC3_MAX_B32_LEN MAX_DOMAIN_LABEL // We define it here instead of dnssec.h so that these values can be used // in files without bringing in all of dnssec.h unnecessarily. @@ -1305,14 +1306,6 @@ struct NATTraversalInfo_struct #pragma mark - DNSServer & McastResolver structures and constants #endif -enum -{ - DNSServer_Untested = 0, - DNSServer_Passed = 1, - DNSServer_Failed = 2, - DNSServer_Disabled = 3 -}; - enum { DNSServer_FlagDelete = 0x1, @@ -1342,8 +1335,9 @@ enum { kScopeNone = 0, // DNS server used by unscoped questions kScopeInterfaceID = 1, // Scoped DNS server used only by scoped questions - kScopeServiceID = 2 // Service specific DNS server used only by questions + kScopeServiceID = 2, // Service specific DNS server used only by questions // have a matching serviceID + kScopesMaxCount = 3 // Max count for scopes enum }; // Note: DNSSECAware is set if we are able to get a valid response to @@ -1360,10 +1354,7 @@ typedef struct DNSServer mDNSs32 serviceID; mDNSAddr addr; mDNSIPPort port; - mDNSOpaque16 testid; mDNSu32 flags; // Set when we're planning to delete this from the list - mDNSu32 teststate; // Have we sent bug-detection query to this server? - mDNSs32 lasttest; // Time we sent last bug-detection query to this server domainname domain; // name->server matching for "split dns" mDNSs32 penaltyTime; // amount of time this server is penalized mDNSu32 scoped; // See the scoped enum above @@ -1606,8 +1597,11 @@ struct AuthRecord_struct #define Question_uDNS(Q) ((Q)->InterfaceID == mDNSInterface_Unicast || (Q)->ProxyQuestion || \ ((Q)->InterfaceID != mDNSInterface_LocalOnly && (Q)->InterfaceID != mDNSInterface_P2P && !(Q)->ForceMCast && !IsLocalDomain(&(Q)->qname))) +// AuthRecordLocalOnly records are registered using mDNSInterface_LocalOnly and +// AuthRecordP2P records are created by D2DServiceFound events. Both record types are kept on the same list. #define RRLocalOnly(rr) ((rr)->ARType == AuthRecordLocalOnly || (rr)->ARType == AuthRecordP2P) +// All other auth records, not including those defined as RRLocalOnly(). #define RRAny(rr) ((rr)->ARType == AuthRecordAny || (rr)->ARType == AuthRecordAnyIncludeP2P || (rr)->ARType == AuthRecordAnyIncludeAWDL || (rr)->ARType == AuthRecordAnyIncludeAWDLandP2P) // Question (A or AAAA) that is suppressed currently because IPv4 or IPv6 address @@ -1802,6 +1796,25 @@ enum enum { NoAnswer_Normal = 0, NoAnswer_Suspended = 1, NoAnswer_Fail = 2 }; +// DNS Push Notification +typedef enum +{ + DNSPUSH_NOERROR = 0, + DNSPUSH_FORMERR = 1, + DNSPUSH_SERVFAIL = 2, + DNSPUSH_NOTIMP = 4, + DNSPUSH_REFUSED = 5 +} DNSPUSH_ErrorCode; + +typedef enum { + DNSPUSH_INIT = 1, + DNSPUSH_NOSERVER = 2, + DNSPUSH_SERVERFOUND = 3, + DNSPUSH_ESTABLISHED = 4 +} DNSPush_State; + + + #define HMAC_LEN 64 #define HMAC_IPAD 0x36 #define HMAC_OPAD 0x5c @@ -1893,6 +1906,10 @@ typedef struct mDNSBool answered; // Has this question been answered? } uDNSMetrics; + +extern mDNSu32 curr_num_regservices; // tracks the current number of services registered +extern mDNSu32 max_num_regservices; // tracks the max number of simultaneous services registered by the device + #endif struct DNSQuestion_struct @@ -1969,6 +1986,12 @@ struct DNSQuestion_struct // for TCP: there is some ambiguity in the use of this variable, but in general, it is // the number of TCP/TLS connection attempts for this LLQ state, or // the number of packets sent for this TCP/TLS connection + + // DNS Push Notification fields. These fields are only meaningful when LongLived flag is set + DNSPush_State dnsPushState; // The state of the DNS push notification negotiation + mDNSAddr dnsPushServerAddr; // Address of the system acting as the DNS Push Server + mDNSIPPort dnsPushServerPort; // Port on which the DNS Push Server is being advertised. + mDNSOpaque64 id; // DNS Proxy fields @@ -1976,7 +1999,7 @@ struct DNSQuestion_struct // till we populate in the cache mDNSBool DisallowPID; // Is the query allowed for the "PID" that we are sending on behalf of ? mDNSs32 ServiceID; // Service identifier to match against the DNS server - + // Client API fields: The client must set up these fields *before* calling mDNS_StartQuery() mDNSInterfaceID InterfaceID; // Non-zero if you want to issue queries only on a single specific IP interface mDNSu32 flags; // flags from original DNSService*() API request. @@ -1991,8 +2014,6 @@ struct DNSQuestion_struct mDNSBool ForceMCast; // Set by client to force mDNS query, even for apparently uDNS names mDNSBool ReturnIntermed; // Set by client to request callbacks for intermediate CNAME/NXDOMAIN results mDNSBool SuppressUnusable; // Set by client to suppress unusable queries to be sent on the wire - mDNSBool DenyOnCellInterface; // Set by client to suppress uDNS queries on cellular interface - mDNSBool DenyOnExpInterface; // Set by client to suppress uDNS queries on expensive interface mDNSu8 RetryWithSearchDomains; // Retry with search domains if there is no entry in the cache or AuthRecords mDNSu8 TimeoutQuestion; // Timeout this question if there is no reply in configured time mDNSu8 WakeOnResolve; // Send wakeup on resolve @@ -2014,43 +2035,7 @@ struct DNSQuestion_struct #endif }; -typedef struct -{ - // Client API fields: The client must set up name and InterfaceID *before* calling mDNS_StartResolveService() - // When the callback is invoked, ip, port, TXTlen and TXTinfo will have been filled in with the results learned from the network. - domainname name; - mDNSInterfaceID InterfaceID; // ID of the interface the response was received on - mDNSAddr ip; // Remote (destination) IP address where this service can be accessed - mDNSIPPort port; // Port where this service can be accessed - mDNSu16 TXTlen; - mDNSu8 TXTinfo[2048]; // Additional demultiplexing information (e.g. LPR queue name) -} ServiceInfo; - -// Note: Within an mDNSServiceInfoQueryCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute() -typedef struct ServiceInfoQuery_struct ServiceInfoQuery; -typedef void mDNSServiceInfoQueryCallback (mDNS *const m, ServiceInfoQuery *query); -struct ServiceInfoQuery_struct -{ - // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them. - // No fields need to be set up by the client prior to calling mDNS_StartResolveService(); - // all required data is passed as parameters to that function. - // The ServiceInfoQuery structure memory is working storage for mDNSCore to discover the requested information - // and place it in the ServiceInfo structure. After the client has called mDNS_StopResolveService(), it may - // dispose of the ServiceInfoQuery structure while retaining the results in the ServiceInfo structure. - DNSQuestion qSRV; - DNSQuestion qTXT; - DNSQuestion qAv4; - DNSQuestion qAv6; - mDNSu8 GotSRV; - mDNSu8 GotTXT; - mDNSu8 GotADD; - mDNSu32 Answers; - ServiceInfo *info; - mDNSServiceInfoQueryCallback *ServiceInfoQueryCallback; - void *ServiceInfoQueryContext; -}; - -typedef enum { ZoneServiceUpdate, ZoneServiceQuery, ZoneServiceLLQ } ZoneService; +typedef enum { ZoneServiceUpdate, ZoneServiceQuery, ZoneServiceLLQ, ZoneServiceDNSPush } ZoneService; typedef void ZoneDataCallback (mDNS *const m, mStatus err, const ZoneData *result); @@ -2276,6 +2261,26 @@ typedef struct extern void LogMDNSStatistics(mDNS *const m); +typedef struct mDNS_DNSPushNotificationServer DNSPushNotificationServer; +typedef struct mDNS_DNSPushNotificationZone DNSPushNotificationZone; + +struct mDNS_DNSPushNotificationServer +{ + mDNSAddr serverAddr; // Server Address + tcpInfo_t *connection; // TCP Connection pointer + mDNSu32 numberOfQuestions; // Number of questions for this server + DNSPushNotificationServer *next; +} ; + +struct mDNS_DNSPushNotificationZone +{ + domainname zoneName; + DNSPushNotificationServer *servers; // DNS Push Notification Servers for this zone + mDNSu32 numberOfQuestions; // Number of questions for this zone + DNSPushNotificationZone *next; +} ; + + struct mDNS_struct { // Internal state fields. These hold the main internal state of mDNSCore; @@ -2320,6 +2325,11 @@ struct mDNS_struct mDNSs32 NextScheduledNATOp; // Next time to send NAT-traversal packets mDNSs32 NextScheduledSPS; // Next time to purge expiring Sleep Proxy records mDNSs32 NextScheduledKA; // Next time to send Keepalive packets (SPS) +#if BONJOUR_ON_DEMAND + mDNSs32 NextBonjourDisableTime; // Next time to leave multicast group if Bonjour on Demand is enabled + mDNSu8 BonjourEnabled; // Non zero if Bonjour is currently enabled by the Bonjour on Demand logic +#endif // BONJOUR_ON_DEMAND + mDNSs32 DelayConflictProcessing; // To prevent spurious confilcts due to stale packets on the wire/air. mDNSs32 RandomQueryDelay; // For de-synchronization of query packets on the wire mDNSu32 RandomReconfirmDelay; // For de-synchronization of reconfirmation queries on the wire mDNSs32 PktNum; // Unique sequence number assigned to each received packet @@ -2348,6 +2358,7 @@ struct mDNS_struct mDNSs32 NextScheduledStopTime; // Next time to stop a question + mDNSs32 NextBLEServiceTime; // Next time to call the BLE discovery management layer. Non zero when active. // These fields only required for mDNS Searcher... DNSQuestion *Questions; // List of all registered questions, active and inactive @@ -2384,7 +2395,7 @@ struct mDNS_struct mDNSs32 ProbeFailTime; mDNSu32 NumFailedProbes; mDNSs32 SuppressProbes; - Platform_t mDNS_plat; // Why is this here in the “only required for mDNS Responder†section? -- SC + Platform_t mDNS_plat; // Why is this here in the “only required for mDNS Responder†section? -- SC // Unicast-specific data mDNSs32 NextuDNSEvent; // uDNS next event @@ -2440,6 +2451,10 @@ struct mDNS_struct mDNSu8 *UPnPRouterAddressString; // holds both the router's address and port mDNSu8 *UPnPSOAPAddressString; // holds both address and port for SOAP messages + // DNS Push Notification fields + DNSPushNotificationServer *DNSPushServers; // DNS Push Notification Servers + DNSPushNotificationZone *DNSPushZones; + // Sleep Proxy client fields AuthRecord *SPSRRSet; // To help the client keep track of the records registered with the sleep proxy @@ -2472,8 +2487,13 @@ struct mDNS_struct int notifyToken; int uds_listener_skt; // Listening socket for incoming UDS clients. This should not be here -- it's private to uds_daemon.c and nothing to do with mDNSCore -- SC mDNSu32 AutoTargetServices; // # of services that have AutoTarget set - mDNSu32 NumAllInterfaceRecords; // Right now we count *all* multicast records here. Later we may want to change to count interface-specific records separately. (This count includes records on the DuplicateRecords list too.) - mDNSu32 NumAllInterfaceQuestions; // Right now we count *all* multicast questions here. Later we may want to change to count interface-specific questions separately. + +#if BONJOUR_ON_DEMAND + // Counters used in Bonjour on Demand logic. + mDNSu32 NumAllInterfaceRecords; // Right now we count *all* multicast records here. Later we may want to change to count interface-specific records separately. (This count includes records on the DuplicateRecords list too.) + mDNSu32 NumAllInterfaceQuestions; // Right now we count *all* multicast questions here. Later we may want to change to count interface-specific questions separately. +#endif // BONJOUR_ON_DEMAND + DNSSECStatistics DNSSECStats; mDNSStatistics mDNSStats; @@ -2501,6 +2521,9 @@ extern const mDNSInterfaceID mDNSInterface_Unicast; // Special value extern const mDNSInterfaceID mDNSInterfaceMark; // Special value extern const mDNSInterfaceID mDNSInterface_P2P; // Special value extern const mDNSInterfaceID uDNSInterfaceMark; // Special value +extern const mDNSInterfaceID mDNSInterface_BLE; // Special value + +#define LocalOnlyOrP2PInterface(INTERFACE) ((INTERFACE == mDNSInterface_LocalOnly) || (INTERFACE == mDNSInterface_P2P) || (INTERFACE == mDNSInterface_BLE)) extern const mDNSIPPort DiscardPort; extern const mDNSIPPort SSHPort; @@ -2542,6 +2565,8 @@ extern const mDNSOpaque16 DNSSecQFlags; extern const mDNSOpaque16 ResponseFlags; extern const mDNSOpaque16 UpdateReqFlags; extern const mDNSOpaque16 UpdateRespFlags; +extern const mDNSOpaque16 SubscribeFlags; +extern const mDNSOpaque16 UnSubscribeFlags; extern const mDNSOpaque64 zeroOpaque64; @@ -2606,7 +2631,7 @@ mDNSinline mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v) // Every client should call mDNS_Init, passing in storage for the mDNS object and the mDNS_PlatformSupport object. // // Clients that are only advertising services should use mDNS_Init_NoCache and mDNS_Init_ZeroCacheSize. -// Clients that plan to perform queries (mDNS_StartQuery, mDNS_StartBrowse, mDNS_StartResolveService, etc.) +// Clients that plan to perform queries (mDNS_StartQuery, mDNS_StartBrowse, etc.) // need to provide storage for the resource record cache, or the query calls will return 'mStatus_NoCache'. // The rrcachestorage parameter is the address of memory for the resource record cache, and // the rrcachesize parameter is the number of entries in the CacheRecord array passed in. @@ -2719,11 +2744,6 @@ typedef enum { mDNS_Dereg_normal, mDNS_Dereg_rapid, mDNS_Dereg_conflict, mDNS_De // mDNS_RegisterService is a single call to register the set of resource records associated with a given named service. // -// mDNS_StartResolveService is single call which is equivalent to multiple calls to mDNS_StartQuery, -// to find the IP address, port number, and demultiplexing information for a given named service. -// As with mDNS_StartQuery, it executes asynchronously, and calls the ServiceInfoQueryCallback when the answer is -// found. After the service is resolved, the client should call mDNS_StopResolveService to complete the transaction. -// The client can also call mDNS_StopResolveService at any time to abort the transaction. // // mDNS_AddRecordToService adds an additional record to a Service Record Set. This record may be deregistered // via mDNS_RemoveRecordFromService, or by deregistering the service. mDNS_RemoveRecordFromService is passed a @@ -2753,6 +2773,7 @@ enum coreFlagWakeOnly = 0x8 // Service won't be registered with sleep proxy }; +extern mDNSu32 deriveD2DFlagsFromAuthRecType(AuthRecType authRecType); extern mStatus mDNS_RegisterService (mDNS *const m, ServiceRecordSet *sr, const domainlabel *const name, const domainname *const type, const domainname *const domain, const domainname *const host, mDNSIPPort port, const mDNSu8 txtinfo[], mDNSu16 txtlen, @@ -2780,8 +2801,6 @@ extern mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question, mDNSQuestionCallback *Callback, void *Context); #define mDNS_StopBrowse mDNS_StopQuery -extern mStatus mDNS_StartResolveService(mDNS *const m, ServiceInfoQuery *query, ServiceInfo *info, mDNSServiceInfoQueryCallback *Callback, void *Context); -extern void mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *query); typedef enum { @@ -2824,7 +2843,7 @@ extern mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question); // because that object is defined to be 256 bytes long, but not all domainname objects are truly the full size. // This macro uses mDNSPlatformMemCopy() to make sure it only touches the actual bytes that are valid. #define AssignDomainName(DST, SRC) do { mDNSu16 len__ = DomainNameLength((SRC)); \ - if (len__ <= MAX_DOMAIN_NAME) mDNSPlatformMemCopy((DST)->c, (SRC)->c, len__);else (DST)->c[0] = 0;} while(0) + if (len__ <= MAX_DOMAIN_NAME) mDNSPlatformMemCopy((DST)->c, (SRC)->c, len__); else (DST)->c[0] = 0; } while(0) // Comparison functions #define SameDomainLabelCS(A,B) ((A)[0] == (B)[0] && mDNSPlatformMemSame((A)+1, (B)+1, (A)[0])) @@ -2906,7 +2925,7 @@ extern mDNSBool DeconstructServiceName(const domainname *const fqdn, domainlabel // then the output will be truncated by one character to allow space for the terminating null. // Unlike standard C vsnprintf/snprintf, they return the number of characters *actually* written, // not the number of characters that *would* have been printed were buflen unlimited. -extern mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg); +extern mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg) IS_A_PRINTF_STYLE_FUNCTION(3,0); extern mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...) IS_A_PRINTF_STYLE_FUNCTION(3,4); extern mDNSu32 NumCacheRecordsForInterfaceID(const mDNS *const m, mDNSInterfaceID id); extern char *DNSTypeName(mDNSu16 rrtype); @@ -3095,14 +3114,14 @@ extern mDNSBool DNSDigest_VerifyMessage(DNSMessage *msg, mDNSu8 *end, LargeCache extern mStatus mDNSPlatformInit (mDNS *const m); extern void mDNSPlatformClose (mDNS *const m); extern mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end, - mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, + mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, mDNSIPPort dstport, mDNSBool useBackgroundTrafficClass); -extern mDNSBool mDNSPlatformPeekUDP (mDNS *const m, UDPSocket *src); extern void mDNSPlatformLock (const mDNS *const m); extern void mDNSPlatformUnlock (const mDNS *const m); extern void mDNSPlatformStrCopy ( void *dst, const void *src); +extern mDNSu32 mDNSPlatformStrLCopy ( void *dst, const void *src, mDNSu32 len); extern mDNSu32 mDNSPlatformStrLen ( const void *src); extern void mDNSPlatformMemCopy ( void *dst, const void *src, mDNSu32 len); extern mDNSBool mDNSPlatformMemSame (const void *dst, const void *src, mDNSu32 len); @@ -3199,7 +3218,8 @@ extern void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNS extern mStatus mDNSPlatformRetrieveTCPInfo(mDNS *const m, mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti); extern mStatus mDNSPlatformGetRemoteMacAddr(mDNS *const m, mDNSAddr *raddr); extern mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname); -extern mStatus mDNSPlatformClearSPSMACAddr(void); +extern mStatus mDNSPlatformClearSPSData(void); +extern mStatus mDNSPlatformStoreOwnerOptRecord(char *ifname, DNSMessage *msg, int length); // mDNSPlatformTLSSetupCerts/mDNSPlatformTLSTearDownCerts used by dnsextd extern mStatus mDNSPlatformTLSSetupCerts(void); @@ -3220,7 +3240,7 @@ extern void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID In extern mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID); extern mDNSBool mDNSPlatformInterfaceIsAWDL(const NetworkInterfaceInfo *intf); extern mDNSBool mDNSPlatformValidRecordForQuestion(const ResourceRecord *const rr, const DNSQuestion *const q); -extern mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const NetworkInterfaceInfo *intf); +extern mDNSBool mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID); extern mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf); extern void mDNSPlatformFormatTime(unsigned long t, mDNSu8 *buf, int bufsize); @@ -3315,7 +3335,7 @@ extern void RetrySearchDomainQuestions(mDNS *const m); extern mDNSBool DomainEnumQuery(const domainname *qname); extern mStatus UpdateKeepaliveRData(mDNS *const m, AuthRecord *rr, NetworkInterfaceInfo *const intf, mDNSBool updateMac, char *ethAddr); extern void UpdateKeepaliveRMACAsync(mDNS *const m, void *context); -extern void UpdateRMACCallback(mDNS *const m, void *context); +extern void UpdateRMAC(mDNS *const m, void *context); // Used only in logging to restrict the number of /etc/hosts entries printed extern void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result); @@ -3353,16 +3373,13 @@ extern void mDNSPlatformCloseDNSProxySkts(mDNS *const m); extern void mDNSPlatformDisposeProxyContext(void *context); extern mDNSu8 *DNSProxySetAttributes(DNSQuestion *q, DNSMessageHeader *h, DNSMessage *msg, mDNSu8 *start, mDNSu8 *limit); -// Sleep Assertions are specific to Mac OS X #if APPLE_OSX_mDNSResponder -extern void mDNSPlatformSleepAssertion(mDNS *const m, double timeout); -#endif - extern void mDNSPlatformGetDNSRoutePolicy(mDNS *const m, DNSQuestion *q, mDNSBool *isBlocked); -extern void mDNSPlatformSetuDNSSocktOpt(UDPSocket *src, const mDNSAddr *dst, DNSQuestion *q); +#endif +extern void mDNSPlatformSetSocktOpt(void *sock, mDNSTransport_Type transType, mDNSAddr_Type addrType, DNSQuestion *q); extern mDNSs32 mDNSPlatformGetPID(void); extern mDNSBool mDNSValidKeepAliveRecord(AuthRecord *rr); - + // *************************************************************************** #if 0 #pragma mark - @@ -3578,18 +3595,17 @@ struct CompileTimeAssertionChecks_mDNS char sizecheck_AuthRecord [(sizeof(AuthRecord) <= 1208) ? 1 : -1]; char sizecheck_CacheRecord [(sizeof(CacheRecord) <= 232) ? 1 : -1]; char sizecheck_CacheGroup [(sizeof(CacheGroup) <= 232) ? 1 : -1]; - char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 864) ? 1 : -1]; + char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 894) ? 1 : -1]; - char sizecheck_ZoneData [(sizeof(ZoneData) <= 1700) ? 1 : -1]; + char sizecheck_ZoneData [(sizeof(ZoneData) <= 1730) ? 1 : -1]; char sizecheck_NATTraversalInfo [(sizeof(NATTraversalInfo) <= 200) ? 1 : -1]; char sizecheck_HostnameInfo [(sizeof(HostnameInfo) <= 3050) ? 1 : -1]; - char sizecheck_DNSServer [(sizeof(DNSServer) <= 340) ? 1 : -1]; - char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 7184) ? 1 : -1]; + char sizecheck_DNSServer [(sizeof(DNSServer) <= 330) ? 1 : -1]; + char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 7272) ? 1 : -1]; char sizecheck_ServiceRecordSet [(sizeof(ServiceRecordSet) <= 5540) ? 1 : -1]; char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 7888) ? 1 : -1]; - char sizecheck_ServiceInfoQuery [(sizeof(ServiceInfoQuery) <= 3488) ? 1 : -1]; #if APPLE_OSX_mDNSResponder - char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1208) ? 1 : -1]; + char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1230) ? 1 : -1]; #endif }; @@ -3599,10 +3615,57 @@ mDNSu32 initializeDeviceInfoTXT(mDNS *m, mDNSu8 *ptr); #if APPLE_OSX_mDNSResponder extern void D2D_start_advertising_interface(NetworkInterfaceInfo *interface); extern void D2D_stop_advertising_interface(NetworkInterfaceInfo *interface); +extern void D2D_start_advertising_record(AuthRecord *ar); +extern void D2D_stop_advertising_record(AuthRecord *ar); +#else +#define D2D_start_advertising_interface(X) +#define D2D_stop_advertising_interface(X) +#define D2D_start_advertising_record(X) +#define D2D_stop_advertising_record(X) #endif // *************************************************************************** +#ifdef __rtems__ +typedef struct +{ + // Client API fields: The client must set up name and InterfaceID *before* calling mDNS_StartResolveService() + // When the callback is invoked, ip, port, TXTlen and TXTinfo will have been filled in with the results learned from the network. + domainname name; + mDNSInterfaceID InterfaceID; // ID of the interface the response was received on + mDNSAddr ip; // Remote (destination) IP address where this service can be accessed + mDNSIPPort port; // Port where this service can be accessed + mDNSu16 TXTlen; + mDNSu8 TXTinfo[2048]; // Additional demultiplexing information (e.g. LPR queue name) +} ServiceInfo; + +// Note: Within an mDNSServiceInfoQueryCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute() +typedef struct ServiceInfoQuery_struct ServiceInfoQuery; +typedef void mDNSServiceInfoQueryCallback (mDNS *const m, ServiceInfoQuery *query); +struct ServiceInfoQuery_struct +{ + // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them. + // No fields need to be set up by the client prior to calling mDNS_StartResolveService(); + // all required data is passed as parameters to that function. + // The ServiceInfoQuery structure memory is working storage for mDNSCore to discover the requested information + // and place it in the ServiceInfo structure. After the client has called mDNS_StopResolveService(), it may + // dispose of the ServiceInfoQuery structure while retaining the results in the ServiceInfo structure. + DNSQuestion qSRV; + DNSQuestion qTXT; + DNSQuestion qAv4; + DNSQuestion qAv6; + mDNSu8 GotSRV; + mDNSu8 GotTXT; + mDNSu8 GotADD; + mDNSu32 Answers; + ServiceInfo *info; + mDNSServiceInfoQueryCallback *ServiceInfoQueryCallback; + void *ServiceInfoQueryContext; +}; + +extern mStatus mDNS_StartResolveService(mDNS *const m, ServiceInfoQuery *query, ServiceInfo *info, mDNSServiceInfoQueryCallback *Callback, void *Context); +extern void mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *query); +#endif /* __rtems__ */ #ifdef __cplusplus } #endif diff --git a/mDNSResponder/mDNSCore/nsec3.c b/mDNSResponder/mDNSCore/nsec3.c index c16a42d5..4e9e8c82 100644 --- a/mDNSResponder/mDNSCore/nsec3.c +++ b/mDNSResponder/mDNSCore/nsec3.c @@ -238,7 +238,7 @@ mDNSlocal mDNSBool NSEC3Find(mDNS *const m, NSEC3FindValues val, CacheRecord *nc name = SkipLeadingLabels(origName, i); if (!NSEC3HashName(name, nsec3, mDNSNULL, 0, hashName, &hlen)) { - LogMsg("NSEC3Find: NSEC3HashName failed for ##s", name->c); + LogMsg("NSEC3Find: NSEC3HashName failed for %##s", name->c); continue; } @@ -708,7 +708,7 @@ mDNSexport CacheRecord *NSEC3RecordIsDelegation(mDNS *const m, domainname *name, if (!NSEC3HashName(name, nsec3, mDNSNULL, 0, hashName, &hlen)) { - LogMsg("NSEC3RecordIsDelegation: NSEC3HashName failed for ##s", name->c); + LogMsg("NSEC3RecordIsDelegation: NSEC3HashName failed for %##s", name->c); return mDNSNULL; } diff --git a/mDNSResponder/mDNSCore/uDNS.c b/mDNSResponder/mDNSCore/uDNS.c index 3ba88b5c..694c745c 100755 --- a/mDNSResponder/mDNSCore/uDNS.c +++ b/mDNSResponder/mDNSCore/uDNS.c @@ -124,7 +124,7 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons return mDNSNULL; } - if (!d) + if (!d) d = (const domainname *)""; LogInfo("mDNS_AddDNSServer(%d): Adding %#a for %##s, InterfaceID %p, serviceID %u, scoped %d, resGroupID %d req_A is %s req_AAAA is %s cell %s req_DO is %s", @@ -135,11 +135,11 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons while (*p) // Check if we already have this {interface,address,port,domain} tuple registered + reqA/reqAAAA bits { - if ((*p)->scoped == scoped && (*p)->interface == interface && (*p)->serviceID == serviceID && (*p)->teststate != DNSServer_Disabled && - mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d) && + if ((*p)->scoped == scoped && (*p)->interface == interface && (*p)->serviceID == serviceID && + mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d) && (*p)->req_A == reqA && (*p)->req_AAAA == reqAAAA) { - if (!((*p)->flags & DNSServer_FlagDelete)) + if (!((*p)->flags & DNSServer_FlagDelete)) debugf("Note: DNS Server %#a:%d for domain %##s (%p) registered more than once", addr, mDNSVal16(port), d->c, interface); tmp = *p; *p = tmp->next; @@ -192,8 +192,6 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons (*p)->addr = *addr; (*p)->port = port; (*p)->flags = DNSServer_FlagNew; - (*p)->teststate = /* DNSServer_Untested */ DNSServer_Passed; - (*p)->lasttest = m->timenow - INIT_UCAST_POLL_INTERVAL; (*p)->timeout = timeout; (*p)->cellIntf = cellIntf; (*p)->req_A = reqA; @@ -208,11 +206,13 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons (*p)->next = mDNSNULL; } } - (*p)->penaltyTime = 0; - // We always update the ID (not just when we allocate a new instance) because we could - // be adding a new non-scoped resolver with a new ID and we want all the non-scoped - // resolvers belong to the same group. - (*p)->resGroupID = resGroupID; + if (*p) { + (*p)->penaltyTime = 0; + // We always update the ID (not just when we allocate a new instance) because we could + // be adding a new non-scoped resolver with a new ID and we want all the non-scoped + // resolvers belong to the same group. + (*p)->resGroupID = resGroupID; + } return(*p); } @@ -224,7 +224,7 @@ mDNSexport void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSOpaque16 re DNSServer *new; DNSServer *orig = q->qDNSServer; mDNSu8 rcode = '\0'; - + mDNS_CheckLock(m); LogInfo("PenalizeDNSServer: Penalizing DNS server %#a question for question %p %##s (%s) SuppressUnusable %d", @@ -234,11 +234,11 @@ mDNSexport void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSOpaque16 re // return the error, then return the first error. if (mDNSOpaque16IsZero(q->responseFlags)) q->responseFlags = responseFlags; - + rcode = (mDNSu8)(responseFlags.b[1] & kDNSFlag1_RC_Mask); // After we reset the qDNSServer to NULL, we could get more SERV_FAILS that might end up - // peanlizing again. + // penalizing again. if (!q->qDNSServer) goto end; @@ -482,7 +482,7 @@ mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info, mDNSlocal mStatus uDNS_RequestAddress(mDNS *m) { mStatus err = mStatus_NoError; - + if (!m->NATTraversals) { m->retryGetAddr = NonZeroTime(m->timenow + 0x78000000); @@ -497,7 +497,7 @@ mDNSlocal mStatus uDNS_RequestAddress(mDNS *m) mDNSu8* end = start + sizeof(NATAddrRequest); err = mDNSPlatformSendUDP(m, start, end, 0, mDNSNULL, &m->Router, NATPMPPort, mDNSfalse); debugf("uDNS_RequestAddress: Sent NAT-PMP external address request %d", err); - + #ifdef _LEGACY_NAT_TRAVERSAL_ if (mDNSIPPortIsZero(m->UPnPRouterPort) || mDNSIPPortIsZero(m->UPnPSOAPPort)) { @@ -509,7 +509,7 @@ mDNSlocal mStatus uDNS_RequestAddress(mDNS *m) mStatus lnterr = LNT_GetExternalAddress(m); if (lnterr) LogMsg("uDNS_RequestAddress: LNT_GetExternalAddress returned error %d", lnterr); - + err = err ? err : lnterr; // NAT-PMP error takes precedence } #endif // _LEGACY_NAT_TRAVERSAL_ @@ -554,7 +554,7 @@ mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info, mDNSBool useP LogMsg("uDNS_SendNATMsg called unexpectedly with NULL info"); return mStatus_BadParamErr; } - + // send msg if the router's address is private (which means it's non-zero) if (mDNSv4AddrIsRFC1918(&m->Router.ip.v4)) { @@ -567,7 +567,7 @@ mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info, mDNSBool useP static NATPortMapRequest NATPortReq; static const mDNSu8* end = (mDNSu8 *)&NATPortReq + sizeof(NATPortMapRequest); mDNSu8 *p = (mDNSu8 *)&NATPortReq.NATReq_lease; - + NATPortReq.vers = NATMAP_VERS; NATPortReq.opcode = info->Protocol; NATPortReq.unused = zeroID; @@ -577,7 +577,7 @@ mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info, mDNSBool useP p[1] = (mDNSu8)((info->NATLease >> 16) & 0xFF); p[2] = (mDNSu8)((info->NATLease >> 8) & 0xFF); p[3] = (mDNSu8)( info->NATLease & 0xFF); - + err = mDNSPlatformSendUDP(m, (mDNSu8 *)&NATPortReq, end, 0, mDNSNULL, &m->Router, NATPMPPort, mDNSfalse); debugf("uDNS_SendNATMsg: Sent NAT-PMP mapping request %d", err); } @@ -604,31 +604,31 @@ mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info, mDNSBool useP mDNSu8* start = (mDNSu8*)&req; mDNSu8* end = start + sizeof(req); mDNSu8* p = (mDNSu8*)&req.lifetime; - + req.version = PCP_VERS; req.opCode = PCPOp_Map; req.reserved = zeroID; - + p[0] = (mDNSu8)((info->NATLease >> 24) & 0xFF); p[1] = (mDNSu8)((info->NATLease >> 16) & 0xFF); p[2] = (mDNSu8)((info->NATLease >> 8) & 0xFF); p[3] = (mDNSu8)( info->NATLease & 0xFF); - + mDNSAddrMapIPv4toIPv6(&m->AdvertisedV4.ip.v4, &req.clientAddr); - + req.nonce[0] = m->PCPNonce[0]; req.nonce[1] = m->PCPNonce[1]; req.nonce[2] = m->PCPNonce[2]; - + req.protocol = (info->Protocol == NATOp_MapUDP ? PCPProto_UDP : PCPProto_TCP); - + req.reservedMapOp[0] = 0; req.reservedMapOp[1] = 0; req.reservedMapOp[2] = 0; - + req.intPort = info->Protocol ? info->IntPort : DiscardPort; req.extPort = info->RequestedPort; - + // Since we only support IPv4, even if using the all-zeros address, map it, so // the PCP gateway will give us an IPv4 address & not an IPv6 address. mDNSAddrMapIPv4toIPv6(&info->NewAddress, &req.extAddress); @@ -654,7 +654,7 @@ mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info, mDNSBool useP mStatus lnterr = LNT_MapPort(m, info); if (lnterr) LogMsg("uDNS_SendNATMsg: LNT_MapPort returned error %d", lnterr); - + err = err ? err : lnterr; // PCP error takes precedence } #endif // _LEGACY_NAT_TRAVERSAL_ @@ -727,7 +727,7 @@ mDNSexport void natTraversalHandleAddressReply(mDNS *const m, mDNSu16 err, mDNSv m->NextScheduledNATOp = m->retryGetAddr; last_err = err; - + for (n = m->NATTraversals; n; n=n->next) { // We should change n->NewAddress only when n is one of: @@ -924,7 +924,7 @@ mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *tra { traversal->NATLease = 0; traversal->retryInterval = 0; - + // In case we most recently sent NAT-PMP, we need to set sentNATPMP to false so // that we'll send a NAT-PMP request to destroy the mapping. We do this because // the NATTraversal struct has already been cut from the list, and the client @@ -940,7 +940,7 @@ mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *tra // would have requested an IPv4 address. traversal->RequestedPort = zeroIPPort; traversal->NewAddress = zerov4Addr; - + uDNS_SendNATMsg(m, traversal, traversal->lastSuccessfulProtocol != NATTProtocolNATPMP); } @@ -1573,6 +1573,7 @@ mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, con } if (!info->sock) { LogMsg("MakeTCPConn: unable to create TCP socket"); mDNSPlatformMemFree(info); return(mDNSNULL); } + mDNSPlatformSetSocktOpt(info->sock, mDNSTransport_TCP, Addr->type, question); err = mDNSPlatformTCPConnect(info->sock, Addr, Port, hostname, (question ? question->InterfaceID : mDNSNULL), tcpCallback, info); // Probably suboptimal here. @@ -1703,6 +1704,7 @@ mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q) } } + // forward declaration so GetServiceTarget can do reverse lookup if needed mDNSlocal void GetStaticHostname(mDNS *m); @@ -1754,11 +1756,13 @@ mDNSlocal const domainname *PUBLIC_LLQ_SERVICE_TYPE = (const domainname*)"\x mDNSlocal const domainname *PRIVATE_UPDATE_SERVICE_TYPE = (const domainname*)"\x0F_dns-update-tls" "\x04_tcp"; mDNSlocal const domainname *PRIVATE_QUERY_SERVICE_TYPE = (const domainname*)"\x0E_dns-query-tls" "\x04_tcp"; mDNSlocal const domainname *PRIVATE_LLQ_SERVICE_TYPE = (const domainname*)"\x0C_dns-llq-tls" "\x04_tcp"; +mDNSlocal const domainname *DNS_PUSH_NOTIFICATION_SERVICE_TYPE = (const domainname*)"\x0C_dns-push-tls" "\x04_tcp"; #define ZoneDataSRV(X) ( \ - (X)->ZoneService == ZoneServiceUpdate ? ((X)->ZonePrivate ? PRIVATE_UPDATE_SERVICE_TYPE : PUBLIC_UPDATE_SERVICE_TYPE) : \ - (X)->ZoneService == ZoneServiceQuery ? ((X)->ZonePrivate ? PRIVATE_QUERY_SERVICE_TYPE : (const domainname*)"" ) : \ - (X)->ZoneService == ZoneServiceLLQ ? ((X)->ZonePrivate ? PRIVATE_LLQ_SERVICE_TYPE : PUBLIC_LLQ_SERVICE_TYPE ) : (const domainname*)"") + (X)->ZoneService == ZoneServiceUpdate ? ((X)->ZonePrivate ? PRIVATE_UPDATE_SERVICE_TYPE : PUBLIC_UPDATE_SERVICE_TYPE) : \ + (X)->ZoneService == ZoneServiceQuery ? ((X)->ZonePrivate ? PRIVATE_QUERY_SERVICE_TYPE : (const domainname*)"" ) : \ + (X)->ZoneService == ZoneServiceLLQ ? ((X)->ZonePrivate ? PRIVATE_LLQ_SERVICE_TYPE : PUBLIC_LLQ_SERVICE_TYPE ) : \ + (X)->ZoneService == ZoneServiceDNSPush ? DNS_PUSH_NOTIFICATION_SERVICE_TYPE : (const domainname*)"") // Forward reference: GetZoneData_StartQuery references GetZoneData_QuestionCallback, and // GetZoneData_QuestionCallback calls GetZoneData_StartQuery @@ -1886,7 +1890,7 @@ mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qt zd->question.InterfaceID = mDNSInterface_Any; zd->question.flags = 0; zd->question.Target = zeroAddr; - //zd->question.qname.c[0] = 0; // Already set + //zd->question.qname.c[0] = 0; // Already set zd->question.qtype = qtype; zd->question.qclass = kDNSClass_IN; zd->question.LongLived = mDNSfalse; @@ -1894,8 +1898,6 @@ mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qt zd->question.ForceMCast = mDNSfalse; zd->question.ReturnIntermed = mDNStrue; zd->question.SuppressUnusable = mDNSfalse; - zd->question.DenyOnCellInterface = mDNSfalse; - zd->question.DenyOnExpInterface = mDNSfalse; zd->question.SearchListIndex = 0; zd->question.AppendSearchDomains = 0; zd->question.RetryWithSearchDomains = mDNSfalse; @@ -2171,7 +2173,7 @@ mDNSlocal void StartRecordNatMap(mDNS *m, AuthRecord *rr) else { LogMsg("StartRecordNatMap: could not determine transport protocol of service %##s", rr->resrec.name->c); return; } //LogMsg("StartRecordNatMap: clientContext %p IntPort %d srv.port %d %s", - // rr->NATinfo.clientContext, mDNSVal16(rr->NATinfo.IntPort), mDNSVal16(rr->resrec.rdata->u.srv.port), ARDisplayString(m, rr)); + // rr->NATinfo.clientContext, mDNSVal16(rr->NATinfo.IntPort), mDNSVal16(rr->resrec.rdata->u.srv.port), ARDisplayString(m, rr)); if (rr->NATinfo.clientContext) mDNS_StopNATOperation_internal(m, &rr->NATinfo); rr->NATinfo.Protocol = protocol; @@ -2584,8 +2586,6 @@ mDNSlocal void GetStaticHostname(mDNS *m) q->ForceMCast = mDNSfalse; q->ReturnIntermed = mDNStrue; q->SuppressUnusable = mDNSfalse; - q->DenyOnCellInterface = mDNSfalse; - q->DenyOnExpInterface = mDNSfalse; q->SearchListIndex = 0; q->AppendSearchDomains = 0; q->RetryWithSearchDomains = mDNSfalse; @@ -2645,12 +2645,30 @@ mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn) // below could free the memory, and we have to make sure we don't touch hi fields after that. mDNSBool f4 = hi->arv4.resrec.RecordType != kDNSRecordTypeUnregistered && hi->arv4.state != regState_Unregistered; mDNSBool f6 = hi->arv6.resrec.RecordType != kDNSRecordTypeUnregistered && hi->arv6.state != regState_Unregistered; - if (f4) LogInfo("mDNS_RemoveDynDNSHostName removing v4 %##s", fqdn); - if (f6) LogInfo("mDNS_RemoveDynDNSHostName removing v6 %##s", fqdn); *ptr = (*ptr)->next; // unlink - if (f4) mDNS_Deregister_internal(m, &hi->arv4, mDNS_Dereg_normal); - if (f6) mDNS_Deregister_internal(m, &hi->arv6, mDNS_Dereg_normal); - // When both deregistrations complete we'll free the memory in the mStatus_MemFree callback + if (f4 || f6) + { + if (f4) + { + LogInfo("mDNS_RemoveDynDNSHostName removing v4 %##s", fqdn); + mDNS_Deregister_internal(m, &hi->arv4, mDNS_Dereg_normal); + } + if (f6) + { + LogInfo("mDNS_RemoveDynDNSHostName removing v6 %##s", fqdn); + mDNS_Deregister_internal(m, &hi->arv6, mDNS_Dereg_normal); + } + // When both deregistrations complete we'll free the memory in the mStatus_MemFree callback + } + else + { + if (hi->natinfo.clientContext) + { + mDNS_StopNATOperation_internal(m, &hi->natinfo); + hi->natinfo.clientContext = mDNSNULL; + } + mDNSPlatformMemFree(hi); + } } mDNS_CheckLock(m); m->NextSRVUpdate = NonZeroTime(m->timenow); @@ -3621,13 +3639,13 @@ mDNSlocal void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID Interface // Minimum NAT-PMP packet is vers (1) opcode (1) + err (2) = 4 bytes if (len < 4) { LogMsg("NAT-PMP message too short (%d bytes)", len); return; } - + // Read multi-byte error value (field is identical in a NATPortMapReply) AddrReply->err = (mDNSu16) ((mDNSu16)pkt[2] << 8 | pkt[3]); - + if (AddrReply->err == NATErr_Vers) { - NATTraversalInfo *n; + NATTraversalInfo *n; LogInfo("NAT-PMP version unsupported message received"); for (n = m->NATTraversals; n; n=n->next) { @@ -3635,7 +3653,7 @@ mDNSlocal void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID Interface // and update the state variables uDNS_SendNATMsg(m, n, mDNSfalse); } - + m->NextScheduledNATOp = m->timenow; return; @@ -3649,7 +3667,7 @@ mDNSlocal void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID Interface LogMsg("NAT-PMP message too short (%d bytes) 0x%X 0x%X", len, AddrReply->opcode, AddrReply->err); return; } - + // Read multi-byte upseconds value (field is identical in a NATPortMapReply) AddrReply->upseconds = (mDNSs32) ((mDNSs32)pkt[4] << 24 | (mDNSs32)pkt[5] << 16 | (mDNSs32)pkt[6] << 8 | pkt[7]); @@ -3726,16 +3744,16 @@ mDNSlocal void uDNS_ReceivePCPPacket(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 protocol = 0; mDNSIPPort intport = zeroIPPort; mDNSIPPort extport = zeroIPPort; - + // Minimum PCP packet is 24 bytes if (len < 24) { LogMsg("uDNS_ReceivePCPPacket: message too short (%d bytes)", len); return; } - + strippedOpCode = reply->opCode & 0x7f; - + if ((reply->opCode & 0x80) == 0x00 || (strippedOpCode != PCPOp_Announce && strippedOpCode != PCPOp_Map)) { LogMsg("uDNS_ReceivePCPPacket: unhandled opCode %u", reply->opCode); @@ -3774,11 +3792,11 @@ mDNSlocal void uDNS_ReceivePCPPacket(mDNS *m, const mDNSInterfaceID InterfaceID, if (strippedOpCode == PCPOp_Announce) return; - + // We globally keep track of the most recent error code for mappings. // This seems bad to do with PCP, but best not change it now. m->LastNATMapResultCode = reply->result; - + if (!reply->result) { if (len < sizeof(PCPMapReply)) @@ -3786,7 +3804,7 @@ mDNSlocal void uDNS_ReceivePCPPacket(mDNS *m, const mDNSInterfaceID InterfaceID, LogMsg("uDNS_ReceivePCPPacket: mapping response too short (%d bytes)", len); return; } - + // Check the nonce if (reply->nonce[0] != m->PCPNonce[0] || reply->nonce[1] != m->PCPNonce[1] || reply->nonce[2] != m->PCPNonce[2]) { @@ -3825,7 +3843,7 @@ mDNSlocal void uDNS_ReceivePCPPacket(mDNS *m, const mDNSInterfaceID InterfaceID, { LogInfo("uDNS_ReceivePCPPacket: error received from server. opcode %X result %X lifetime %X epoch %X", reply->opCode, reply->result, reply->lifetime, reply->epoch); - + // If the packet is long enough, get the protocol & intport for matching to report // the error if (len >= sizeof(PCPMapReply)) @@ -3858,135 +3876,6 @@ mDNSexport void uDNS_ReceiveNATPacket(mDNS *m, const mDNSInterfaceID InterfaceID LogMsg("uDNS_ReceiveNATPacket: packet with version %u (expected %u or %u)", pkt[0], PCP_VERS, NATMAP_VERS); } -// Shorten DNS-SD queries to avoid NAT bugs -// Add check to avoid crashing NAT gateways that have buggy DNS relay code -// -// We know of bugs in home NAT gateways that cause them to crash if they receive certain DNS queries. -// The DNS queries that make them crash are perfectly legal DNS queries, but even if they weren't, -// the gateway shouldn't crash -- in today's world of viruses and network attacks, software has to -// be written assuming that a malicious attacker could send them any packet, properly-formed or not. -// Still, we don't want to be crashing people's home gateways, so we go out of our way to avoid -// the queries that crash them. -// -// Some examples: -// -// 1. Any query where the name ends in ".in-addr.arpa." and the text before this is 32 or more bytes. -// The query type does not need to be PTR -- the gateway will crash for any query type. -// e.g. "ping long-name-crashes-the-buggy-router.in-addr.arpa" will crash one of these. -// -// 2. Any query that results in a large response with the TC bit set. -// -// 3. Any PTR query that doesn't begin with four decimal numbers. -// These gateways appear to assume that the only possible PTR query is a reverse-mapping query -// (e.g. "1.0.168.192.in-addr.arpa") and if they ever get a PTR query where the first four -// labels are not all decimal numbers in the range 0-255, they handle that by crashing. -// These gateways also ignore the remainder of the name following the four decimal numbers -// -- whether or not it actually says in-addr.arpa, they just make up an answer anyway. -// -// The challenge therefore is to craft a query that will discern whether the DNS server -// is one of these buggy ones, without crashing it. Furthermore we don't want our test -// queries making it all the way to the root name servers, putting extra load on those -// name servers and giving Apple a bad reputation. To this end we send this query: -// dig -t ptr 1.0.0.127.dnsbugtest.1.0.0.127.in-addr.arpa. -// -// The text preceding the ".in-addr.arpa." is under 32 bytes, so it won't cause crash (1). -// It will not yield a large response with the TC bit set, so it won't cause crash (2). -// It starts with four decimal numbers, so it won't cause crash (3). -// The name falls within the "1.0.0.127.in-addr.arpa." domain, the reverse-mapping name for the local -// loopback address, and therefore the query will black-hole at the first properly-configured DNS server -// it reaches, making it highly unlikely that this query will make it all the way to the root. -// -// Finally, the correct response to this query is NXDOMAIN or a similar error, but the -// gateways that ignore the remainder of the name following the four decimal numbers -// give themselves away by actually returning a result for this nonsense query. - -mDNSlocal const domainname *DNSRelayTestQuestion = (const domainname*) - "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\xa" "dnsbugtest" - "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\x7" "in-addr" "\x4" "arpa"; - -// See comments above for DNSRelayTestQuestion -// If this is the kind of query that has the risk of crashing buggy DNS servers, we do a test question first -mDNSlocal mDNSBool NoTestQuery(DNSQuestion *q) -{ - int i; - mDNSu8 *p = q->qname.c; - if (q->AuthInfo) return(mDNStrue); // Don't need a test query for private queries sent directly to authoritative server over TLS/TCP - if (q->qtype != kDNSType_PTR) return(mDNStrue); // Don't need a test query for any non-PTR queries - for (i=0; i<4; i++) // If qname does not begin with num.num.num.num, can't skip the test query - { - if (p[0] < 1 || p[0] > 3) return(mDNSfalse); - if ( p[1] < '0' || p[1] > '9' ) return(mDNSfalse); - if (p[0] >= 2 && (p[2] < '0' || p[2] > '9')) return(mDNSfalse); - if (p[0] >= 3 && (p[3] < '0' || p[3] > '9')) return(mDNSfalse); - p += 1 + p[0]; - } - // If remainder of qname is ".in-addr.arpa.", this is a vanilla reverse-mapping query and - // we can safely do it without needing a test query first, otherwise we need the test query. - return(SameDomainName((domainname*)p, (const domainname*)"\x7" "in-addr" "\x4" "arpa")); -} - -// Returns mDNStrue if response was handled -mDNSlocal mDNSBool uDNS_ReceiveTestQuestionResponse(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end, - const mDNSAddr *const srcaddr, const mDNSIPPort srcport) -{ - const mDNSu8 *ptr = msg->data; - DNSQuestion pktq; - DNSServer *s; - mDNSu32 result = 0; - - // 1. Find out if this is an answer to one of our test questions - if (msg->h.numQuestions != 1) return(mDNSfalse); - ptr = getQuestion(msg, ptr, end, mDNSInterface_Any, &pktq); - if (!ptr) return(mDNSfalse); - if (pktq.qtype != kDNSType_PTR || pktq.qclass != kDNSClass_IN) return(mDNSfalse); - if (!SameDomainName(&pktq.qname, DNSRelayTestQuestion)) return(mDNSfalse); - - // 2. If the DNS relay gave us a positive response, then it's got buggy firmware - // else, if the DNS relay gave us an error or no-answer response, it passed our test - if ((msg->h.flags.b[1] & kDNSFlag1_RC_Mask) == kDNSFlag1_RC_NoErr && msg->h.numAnswers > 0) - result = DNSServer_Failed; - else - result = DNSServer_Passed; - - // 3. Find occurrences of this server in our list, and mark them appropriately - for (s = m->DNSServers; s; s = s->next) - { - mDNSBool matchaddr = (s->teststate != result && mDNSSameAddress(srcaddr, &s->addr) && mDNSSameIPPort(srcport, s->port)); - mDNSBool matchid = (s->teststate == DNSServer_Untested && mDNSSameOpaque16(msg->h.id, s->testid)); - if (matchaddr || matchid) - { - DNSQuestion *q; - s->teststate = result; - if (result == DNSServer_Passed) - { - LogInfo("DNS Server %#a:%d (%#a:%d) %d passed%s", - &s->addr, mDNSVal16(s->port), srcaddr, mDNSVal16(srcport), mDNSVal16(s->testid), - matchaddr ? "" : " NOTE: Reply did not come from address to which query was sent"); - } - else - { - LogMsg("NOTE: Wide-Area Service Discovery disabled to avoid crashing defective DNS relay %#a:%d (%#a:%d) %d%s", - &s->addr, mDNSVal16(s->port), srcaddr, mDNSVal16(srcport), mDNSVal16(s->testid), - matchaddr ? "" : " NOTE: Reply did not come from address to which query was sent"); - } - - // If this server has just changed state from DNSServer_Untested to DNSServer_Passed, then retrigger any waiting questions. - // We use the NoTestQuery() test so that we only retrigger questions that were actually blocked waiting for this test to complete. - if (result == DNSServer_Passed) // Unblock any questions that were waiting for this result - for (q = m->Questions; q; q=q->next) - if (q->qDNSServer == s && !NoTestQuery(q)) - { - q->ThisQInterval = INIT_UCAST_POLL_INTERVAL / QuestionIntervalStep; - q->unansweredQueries = 0; - q->LastQTime = m->timenow - q->ThisQInterval; - m->NextScheduledQuery = m->timenow; - } - } - } - - return(mDNStrue); // Return mDNStrue to tell uDNS_ReceiveMsg it doesn't need to process this packet further -} - // Called from mDNSCoreReceive with the lock held mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport) { @@ -4015,7 +3904,6 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS if (QR_OP == StdR) { //if (srcaddr && recvLLQResponse(m, msg, end, srcaddr, srcport)) return; - if (uDNS_ReceiveTestQuestionResponse(m, msg, end, srcaddr, srcport)) return; for (qptr = m->Questions; qptr; qptr = qptr->next) if (msg->h.flags.b[0] & kDNSFlag0_TC && mDNSSameOpaque16(qptr->TargetQID, msg->h.id) && m->timenow - qptr->LastQTime < RESPONSE_WINDOW) { @@ -4037,7 +3925,7 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS mDNSs32 expire = m->timenow + (mDNSs32)lease * mDNSPlatformOneSecond; mDNSu32 random = mDNSRandom((mDNSs32)lease * mDNSPlatformOneSecond/10); - //rcode = kDNSFlag1_RC_ServFail; // Simulate server failure (rcode 2) + //rcode = kDNSFlag1_RC_ServFail; // Simulate server failure (rcode 2) // Walk through all the records that matches the messageID. There could be multiple // records if we had sent them in a group @@ -4200,6 +4088,40 @@ mDNSexport void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneI mDNS_Unlock(m); } +mDNSexport void DNSPushNotificationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo) +{ + DNSQuestion *q = (DNSQuestion *)zoneInfo->ZoneDataContext; + mDNS_Lock(m); + + // If we get here it means that the GetZoneData operation has completed. + // We hold on to the zone data if it is AutoTunnel as we use the hostname + // in zoneInfo during the TLS connection setup. + q->servAddr = zeroAddr; + q->servPort = zeroIPPort; + if (!err && zoneInfo && !mDNSIPPortIsZero(zoneInfo->Port) && !mDNSAddressIsZero(&zoneInfo->Addr) && zoneInfo->Host.c[0]) + { + q->dnsPushState = DNSPUSH_SERVERFOUND; + q->dnsPushServerAddr = zoneInfo->Addr; + q->dnsPushServerPort = zoneInfo->Port; + q->ntries = 0; + LogInfo("DNSPushNotificationGotZoneData %#a:%d", &q->dnsPushServerAddr, mDNSVal16(q->dnsPushServerPort)); + SubscribeToDNSPushNotificationServer(m,q); + } + else + { + StartLLQPolling(m,q); + if (err == mStatus_NoSuchNameErr) + { + // this actually failed, so mark it by setting address to all ones + q->servAddr.type = mDNSAddrType_IPv4; + q->servAddr.ip.v4 = onesIPv4Addr; + q->dnsPushState = DNSPUSH_NOSERVER; + } + } + mDNS_Unlock(m); +} + + // Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1) mDNSlocal void PrivateQueryGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo) { @@ -4467,7 +4389,7 @@ mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr) if (!rr->nta) { LogMsg("SendRecordDeregistration:ERROR!! nta is NULL for %s", ARDisplayString(m, rr)); return; } err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->nta->Addr, rr->nta->Port, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name), mDNSfalse); if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %d", err); - //if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr); // Don't touch rr after this + //if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr); // Don't touch rr after this } SetRecordRetry(m, rr, 0); return; @@ -4690,17 +4612,35 @@ mDNSlocal void handle_unanswered_query(mDNS *const m) if (!q->qDNSServer->req_DO) { - q->ValidationState = DNSSECValNotRequired; + q->ValidationState = DNSSECValNotRequired; q->ValidationRequired = DNSSEC_VALIDATION_NONE; - + if (q->ProxyQuestion) q->ProxyDNSSECOK = mDNSfalse; - LogInfo("handle_unanswered_query: unanswered query for %##s (%s), so turned off validation for %#a", + LogInfo("handle_unanswered_query: unanswered query for %##s (%s), so turned off validation for %#a", q->qname.c, DNSTypeName(q->qtype), &q->qDNSServer->addr); } } } +mDNSlocal void uDNS_HandleLLQState(mDNS *const m, DNSQuestion *q) +{ + // First attempt to use DNS Push Notification. + if (q->dnsPushState == DNSPUSH_INIT) + DiscoverDNSPushNotificationServer(m, q); + switch (q->state) + { + case LLQ_InitialRequest: startLLQHandshake(m, q); break; + case LLQ_SecondaryRequest: + // For PrivateQueries, we need to start the handshake again as we don't do the Challenge/Response step + if (PrivateQuery(q)) startLLQHandshake(m, q); + else sendChallengeResponse(m, q, mDNSNULL); + break; + case LLQ_Established: sendLLQRefresh(m, q); break; + case LLQ_Poll: break; // Do nothing (handled below) + } +} + // The question to be checked is not passed in as an explicit parameter; // instead it is implicit that the question to be checked is m->CurrentQuestion. mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) @@ -4710,22 +4650,10 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) if (q->LongLived) { - switch (q->state) - { - case LLQ_InitialRequest: startLLQHandshake(m, q); break; - case LLQ_SecondaryRequest: - // For PrivateQueries, we need to start the handshake again as we don't do the Challenge/Response step - if (PrivateQuery(q)) - startLLQHandshake(m, q); - else - sendChallengeResponse(m, q, mDNSNULL); - break; - case LLQ_Established: sendLLQRefresh(m, q); break; - case LLQ_Poll: break; // Do nothing (handled below) - } + uDNS_HandleLLQState(m,q); } - handle_unanswered_query(m); + handle_unanswered_query(m); // We repeat the check above (rather than just making this the "else" case) because startLLQHandshake can change q->state to LLQ_Poll if (!(q->LongLived && q->state != LLQ_Poll)) { @@ -4773,36 +4701,25 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) for (qptr = q->next ; qptr; qptr = qptr->next) if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = q->qDNSServer; } } - if (q->qDNSServer && q->qDNSServer->teststate != DNSServer_Disabled) + if (q->qDNSServer) { - mDNSu8 *end = m->omsg.data; + mDNSu8 *end; mStatus err = mStatus_NoError; mDNSBool private = mDNSfalse; InitializeDNSMessage(&m->omsg.h, q->TargetQID, (DNSSECQuestion(q) ? DNSSecQFlags : uQueryFlags)); - if (q->qDNSServer->teststate != DNSServer_Untested || NoTestQuery(q)) - { - end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass); - if (DNSSECQuestion(q) && !q->qDNSServer->cellIntf) - { - if (q->ProxyQuestion) - end = DNSProxySetAttributes(q, &m->omsg.h, &m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData); - else - end = putDNSSECOption(&m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData); - } - private = PrivateQuery(q); - } - else if (m->timenow - q->qDNSServer->lasttest >= INIT_UCAST_POLL_INTERVAL) // Make sure at least three seconds has elapsed since last test query + end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass); + if (DNSSECQuestion(q) && !q->qDNSServer->cellIntf) { - LogInfo("Sending DNS test query to %#a:%d", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port)); - q->ThisQInterval = INIT_UCAST_POLL_INTERVAL / QuestionIntervalStep; - q->qDNSServer->lasttest = m->timenow; - end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, DNSRelayTestQuestion, kDNSType_PTR, kDNSClass_IN); - q->qDNSServer->testid = m->omsg.h.id; + if (q->ProxyQuestion) + end = DNSProxySetAttributes(q, &m->omsg.h, &m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData); + else + end = putDNSSECOption(&m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData); } + private = PrivateQuery(q); - if (end > m->omsg.data && (q->qDNSServer->teststate != DNSServer_Failed || NoTestQuery(q))) + if (end > m->omsg.data) { //LogMsg("uDNS_CheckCurrentQuestion %p %d %p %##s (%s)", q, NextQSendTime(q) - m->timenow, private, q->qname.c, DNSTypeName(q->qtype)); if (private) @@ -4820,7 +4737,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) { q->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort); if (q->LocalSocket) - mDNSPlatformSetuDNSSocktOpt(q->LocalSocket, &q->qDNSServer->addr, q); + mDNSPlatformSetSocktOpt(q->LocalSocket, mDNSTransport_UDP, q->qDNSServer->addr.type, q); } if (!q->LocalSocket) err = mStatus_NoMemoryErr; // If failed to make socket (should be very rare), we'll try again next time else @@ -4829,6 +4746,11 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) #if TARGET_OS_EMBEDDED if (!err) { + if (q->metrics.answered) + { + q->metrics.querySendCount = 0; + q->metrics.answered = mDNSfalse; + } if (q->metrics.querySendCount++ == 0) { q->metrics.firstQueryTime = m->timenow; @@ -4839,32 +4761,68 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) } } - if (err != mStatus_TransientErr) // if it is not a transient error backoff and DO NOT flood queries unnecessarily + if (err == mStatus_HostUnreachErr) { - q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep; // Only increase interval if send succeeded - q->unansweredQueries++; - if (q->ThisQInterval > MAX_UCAST_POLL_INTERVAL) - q->ThisQInterval = MAX_UCAST_POLL_INTERVAL; - if (private && q->state != LLQ_Poll) + DNSServer *newServer; + + LogInfo("uDNS_CheckCurrentQuestion: host unreachable error for DNS server %#a for question [%p] %##s (%s)", + &q->qDNSServer->addr, q, q->qname.c, DNSTypeName(q->qtype)); + + if (!StrictUnicastOrdering) { - // We don't want to retransmit too soon. Hence, we always schedule our first - // retransmisson at 3 seconds rather than one second - if (q->ThisQInterval < (3 * mDNSPlatformOneSecond)) - q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep; - if (q->ThisQInterval > LLQ_POLL_INTERVAL) - q->ThisQInterval = LLQ_POLL_INTERVAL; - LogInfo("uDNS_CheckCurrentQuestion: private non polling question for %##s (%s) will be retried in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval); + q->qDNSServer->penaltyTime = NonZeroTime(m->timenow + DNSSERVER_PENALTY_TIME); } - if (q->qDNSServer->cellIntf) + + newServer = GetServerForQuestion(m, q); + DNSServerChangeForQuestion(m, q, newServer); + + if (q->triedAllServersOnce) + { + q->LastQTime = m->timenow; + } + else { - // We don't want to retransmit too soon. Schedule our first retransmisson at - // MIN_UCAST_RETRANS_TIMEOUT seconds. - if (q->ThisQInterval < MIN_UCAST_RETRANS_TIMEOUT) - q->ThisQInterval = MIN_UCAST_RETRANS_TIMEOUT; + q->ThisQInterval = InitialQuestionInterval; + q->LastQTime = m->timenow - q->ThisQInterval; } - debugf("uDNS_CheckCurrentQuestion: Increased ThisQInterval to %d for %##s (%s), cell %d", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer->cellIntf); + q->unansweredQueries = 0; + q->noServerResponse = 1; + } + else + { + if (err != mStatus_TransientErr) // if it is not a transient error backoff and DO NOT flood queries unnecessarily + { + // If all DNS Servers are not responding, then we back-off using the multiplier UDNSBackOffMultiplier(*2). + // Only increase interval if send succeeded + + q->ThisQInterval = q->ThisQInterval * UDNSBackOffMultiplier; + if ((q->ThisQInterval > 0) && (q->ThisQInterval < MinQuestionInterval)) // We do not want to retx within 1 sec + q->ThisQInterval = MinQuestionInterval; + + q->unansweredQueries++; + if (q->ThisQInterval > MAX_UCAST_POLL_INTERVAL) + q->ThisQInterval = MAX_UCAST_POLL_INTERVAL; + if (private && q->state != LLQ_Poll) + { + // We don't want to retransmit too soon. Hence, we always schedule our first + // retransmisson at 3 seconds rather than one second + if (q->ThisQInterval < (3 * mDNSPlatformOneSecond)) + q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep; + if (q->ThisQInterval > LLQ_POLL_INTERVAL) + q->ThisQInterval = LLQ_POLL_INTERVAL; + LogInfo("uDNS_CheckCurrentQuestion: private non polling question for %##s (%s) will be retried in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval); + } + if (q->qDNSServer->cellIntf) + { + // We don't want to retransmit too soon. Schedule our first retransmisson at + // MIN_UCAST_RETRANS_TIMEOUT seconds. + if (q->ThisQInterval < MIN_UCAST_RETRANS_TIMEOUT) + q->ThisQInterval = MIN_UCAST_RETRANS_TIMEOUT; + } + debugf("uDNS_CheckCurrentQuestion: Increased ThisQInterval to %d for %##s (%s), cell %d", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer->cellIntf); + } + q->LastQTime = m->timenow; } - q->LastQTime = m->timenow; SetNextQueryTime(m, q); } else @@ -4927,7 +4885,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) { if (SameNameRecordAnswersQuestion(&rr->resrec, q)) { - LogInfo("uDNS_CheckCurrentQuestion: Purged resourcerecord %s", CRDisplayString(m, rr)); + LogInfo("uDNS_CheckCurrentQuestion: Purged resourcerecord %s", CRDisplayString(m, rr)); mDNS_PurgeCacheResourceRecord(m, rr); } } @@ -5049,7 +5007,7 @@ mDNSexport void CheckNATMappings(mDNS *m) const mStatus EffectiveResult = cur->NewResult ? cur->NewResult : mDNSv4AddrIsRFC1918(&EffectiveAddress) ? mStatus_DoubleNAT : mStatus_NoError; const mDNSIPPort ExternalPort = HaveRoutable ? cur->IntPort : !mDNSIPv4AddressIsZero(EffectiveAddress) && cur->ExpiryTime ? cur->RequestedPort : zeroIPPort; - + if (!cur->Protocol || HaveRoutable || cur->ExpiryTime || cur->retryInterval > NATMAP_INIT_RETRY * 8) { if (!mDNSSameIPv4Address(cur->ExternalAddress, EffectiveAddress) || @@ -5337,8 +5295,8 @@ mDNSexport void udns_validatelists(void *const v) DNSServer *d; for (d = m->DNSServers; d; d=d->next) - if (d->next == (DNSServer *)~0 || d->teststate > DNSServer_Disabled) - LogMemCorruption("m->DNSServers: %p is garbage (%d)", d, d->teststate); + if (d->next == (DNSServer *)~0) + LogMemCorruption("m->DNSServers: %p is garbage", d); DomainAuthInfo *info; for (info = m->AuthInfoList; info; info = info->next) @@ -5810,101 +5768,327 @@ struct CompileTimeAssertionChecks_uDNS char sizecheck_SearchListElem[(sizeof(SearchListElem) <= 5000) ? 1 : -1]; }; +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - DNS Push Notification functions +#endif + +mDNSlocal tcpInfo_t * GetTCPConnectionToPushServer(mDNS *m, DNSQuestion *q) +{ + // If we already have a question for this zone and if the server is the same, reuse it + DNSPushNotificationZone *zone = mDNSNULL; + for (zone = m->DNSPushZones; zone != mDNSNULL; zone = zone->next) + { + if (SameDomainName(&q->nta->ChildName, &zone->zoneName)) + { + DNSPushNotificationServer *zoneServer = mDNSNULL; + for (zoneServer = zone->servers; zoneServer != mDNSNULL; zoneServer = zoneServer->next) + { + if (mDNSSameAddress(&q->dnsPushServerAddr, &zoneServer->serverAddr)) + { + zone->numberOfQuestions++; + zoneServer->numberOfQuestions++; + return zoneServer->connection; + } + } + } + } + + // If we have a connection to this server but it is for a differnt zone, create a new zone entry and reuse the connection + DNSPushNotificationServer *server = mDNSNULL; + for (server = m->DNSPushServers; server != mDNSNULL; server = server->next) + { + if (mDNSSameAddress(&q->dnsPushServerAddr, &server->serverAddr)) + { + DNSPushNotificationZone *newZone = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationZone)); + newZone->numberOfQuestions = 1; + newZone->zoneName = q->nta->ChildName; + newZone->servers = server; + + // Add the new zone to the begining of the list + newZone->next = m->DNSPushZones; + m->DNSPushZones = newZone; + + server->numberOfQuestions++; + return server->connection; + } + } + + // If we do not have any existing connections, create a new connection + DNSPushNotificationServer *newServer = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationServer)); + DNSPushNotificationZone *newZone = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationZone)); + + newServer->numberOfQuestions = 1; + newServer->serverAddr = q->dnsPushServerAddr; + newServer->connection = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->dnsPushServerAddr, q->dnsPushServerPort, &q->nta->Host, q, mDNSNULL); + + newZone->numberOfQuestions = 1; + newZone->zoneName = q->nta->ChildName; + newZone->servers = newServer; + + // Add the new zone to the begining of the list + newZone->next = m->DNSPushZones; + m->DNSPushZones = newZone; + + newServer->next = m->DNSPushServers; + m->DNSPushServers = newServer; + return newServer->connection; +} + +mDNSexport void DiscoverDNSPushNotificationServer(mDNS *m, DNSQuestion *q) +{ + /* Use the same NAT setup as in the LLQ case */ + if (m->LLQNAT.clientContext != mDNSNULL) // LLQNAT just started, give it some time + { + LogInfo("startLLQHandshake: waiting for NAT status for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10); // Retry in approx 15 minutes + q->LastQTime = m->timenow; + SetNextQueryTime(m, q); + return; + } + + // Either we don't have {PCP, NAT-PMP, UPnP/IGD} support (ExternalPort is zero) or behind a Double NAT that may or + // may not have {PCP, NAT-PMP, UPnP/IGD} support (NATResult is non-zero) + if (mDNSIPPortIsZero(m->LLQNAT.ExternalPort) || m->LLQNAT.Result) + { + LogInfo("startLLQHandshake: Cannot receive inbound packets; will poll for %##s (%s) External Port %d, NAT Result %d", + q->qname.c, DNSTypeName(q->qtype), mDNSVal16(m->LLQNAT.ExternalPort), m->LLQNAT.Result); + StartLLQPolling(m, q); // Actually sets up the NAT Auto Tunnel + return; + } + + if (mDNSIPPortIsZero(q->dnsPushServerPort) && q->dnsPushState == DNSPUSH_INIT) + { + LogInfo("SubscribeToDNSPushNotificationServer: StartGetZoneData for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10); // Retry in approx 15 minutes + q->LastQTime = m->timenow; + SetNextQueryTime(m, q); + q->dnsPushServerAddr = zeroAddr; + // We know q->dnsPushServerPort is zero because of check above + if (q->nta) CancelGetZoneData(m, q->nta); + q->nta = StartGetZoneData(m, &q->qname, ZoneServiceDNSPush, DNSPushNotificationGotZoneData, q); + return; + } + + if (q->tcp) + { + LogInfo("SubscribeToDNSPushNotificationServer: Disposing existing TCP connection for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + DisposeTCPConn(q->tcp); + q->tcp = mDNSNULL; + } + + if (!q->nta) + { + // Normally we lookup the zone data and then call this function. And we never free the zone data + // for "PrivateQuery". But sometimes this can happen due to some race conditions. When we + // switch networks, we might end up "Polling" the network e.g., we are behind a Double NAT. + // When we poll, we free the zone information as we send the query to the server (See + // PrivateQueryGotZoneData). The NAT callback (LLQNATCallback) may happen soon after that. If we + // are still behind Double NAT, we would have returned early in this function. But we could + // have switched to a network with no NATs and we should get the zone data again. + LogInfo("SubscribeToDNSPushNotificationServer: nta is NULL for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + q->nta = StartGetZoneData(m, &q->qname, ZoneServiceDNSPush, DNSPushNotificationGotZoneData, q); + return; + } + else if (!q->nta->Host.c[0]) + { + // This should not happen. If it happens, we print a log and MakeTCPConn will fail if it can't find a hostname + LogMsg("SubscribeToDNSPushNotificationServer: ERROR!!: nta non NULL for %##s (%s) but HostName %d NULL, LongLived %d", q->qname.c, DNSTypeName(q->qtype), q->nta->Host.c[0], q->LongLived); + } + q->tcp = GetTCPConnectionToPushServer(m,q); + // If TCP failed (transient networking glitch) try again in five seconds + q->ThisQInterval = (q->tcp != mDNSNULL) ? q->ThisQInterval = 0 : (mDNSPlatformOneSecond * 5); + q->LastQTime = m->timenow; + SetNextQueryTime(m, q); +} + + +mDNSexport void SubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q) +{ + mDNSu8 *end = mDNSNULL; + InitializeDNSMessage(&m->omsg.h, zeroID, SubscribeFlags); + end = putQuestion(&m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass); + if (!end) + { + LogMsg("ERROR: SubscribeToDNSPushNotificationServer putQuestion failed"); + return; + } + + mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->dnsPushServerAddr, q->dnsPushServerPort, q->tcp->sock, mDNSNULL, mDNSfalse); + + // update question state + q->dnsPushState = DNSPUSH_ESTABLISHED; + q->ThisQInterval = (kLLQ_INIT_RESEND * mDNSPlatformOneSecond); + q->LastQTime = m->timenow; + SetNextQueryTime(m, q); + +} + +mDNSlocal void reconcileDNSPushConnection(mDNS *m, DNSQuestion *q) +{ + DNSPushNotificationZone *zone; + DNSPushNotificationServer *server; + // Update the counts + for (zone = m->DNSPushZones; zone != mDNSNULL; zone = zone->next) + { + if (SameDomainName(&zone->zoneName, &q->nta->ChildName)) + { + zone->numberOfQuestions--; + for (server = zone->servers; server != mDNSNULL; server = server->next) + { + if (mDNSSameAddress(&server->serverAddr, &q->dnsPushServerAddr)) + server->numberOfQuestions--; + } + } + } + + // Now prune the lists + server = m->DNSPushServers; + DNSPushNotificationServer *nextServer = mDNSNULL; + while(server != mDNSNULL) + { + nextServer = server->next; + if (server->numberOfQuestions <= 0) + { + DisposeTCPConn(server->connection); + if (server == m->DNSPushServers) + m->DNSPushServers = nextServer; + mDNSPlatformMemFree(server); + server = nextServer; + } + else server = server->next; + } + + zone = m->DNSPushZones; + DNSPushNotificationZone *nextZone = mDNSNULL; + while(zone != mDNSNULL) + { + nextZone = zone->next; + if (zone->numberOfQuestions <= 0) + { + if (zone == m->DNSPushZones) + m->DNSPushZones = nextZone; + mDNSPlatformMemFree(zone); + zone = nextZone; + } + else zone = zone->next; + } + +} + +mDNSexport void UnSubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q) +{ + mDNSu8 *end = mDNSNULL; + InitializeDNSMessage(&m->omsg.h, q->TargetQID, UnSubscribeFlags); + end = putQuestion(&m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass); + if (!end) + { + LogMsg("ERROR: UnSubscribeToDNSPushNotificationServer - putQuestion failed"); + return; + } + + mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->dnsPushServerAddr, q->dnsPushServerPort, q->tcp->sock, mDNSNULL, mDNSfalse); + + reconcileDNSPushConnection(m, q); +} + +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - +#endif #else // !UNICAST_DISABLED mDNSexport const domainname *GetServiceTarget(mDNS *m, AuthRecord *const rr) { - (void) m; - (void) rr; + (void) m; + (void) rr; - return mDNSNULL; + return mDNSNULL; } mDNSexport DomainAuthInfo *GetAuthInfoForName_internal(mDNS *m, const domainname *const name) { - (void) m; - (void) name; + (void) m; + (void) name; - return mDNSNULL; + return mDNSNULL; } mDNSexport DomainAuthInfo *GetAuthInfoForQuestion(mDNS *m, const DNSQuestion *const q) { - (void) m; - (void) q; + (void) m; + (void) q; - return mDNSNULL; + return mDNSNULL; } mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q) { - (void) m; - (void) q; + (void) m; + (void) q; } mDNSexport void DisposeTCPConn(struct tcpInfo_t *tcp) { - (void) tcp; + (void) tcp; } mDNSexport mStatus mDNS_StartNATOperation_internal(mDNS *m, NATTraversalInfo *traversal) { - (void) m; - (void) traversal; + (void) m; + (void) traversal; - return mStatus_UnsupportedErr; + return mStatus_UnsupportedErr; } mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *traversal) { - (void) m; - (void) traversal; + (void) m; + (void) traversal; - return mStatus_UnsupportedErr; + return mStatus_UnsupportedErr; } mDNSexport void sendLLQRefresh(mDNS *m, DNSQuestion *q) { - (void) m; - (void) q; + (void) m; + (void) q; } mDNSexport ZoneData *StartGetZoneData(mDNS *const m, const domainname *const name, const ZoneService target, ZoneDataCallback callback, void *ZoneDataContext) { - (void) m; - (void) name; - (void) target; - (void) callback; - (void) ZoneDataContext; + (void) m; + (void) name; + (void) target; + (void) callback; + (void) ZoneDataContext; - return mDNSNULL; + return mDNSNULL; } mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneData) { - (void) m; - (void) err; - (void) zoneData; + (void) m; + (void) err; + (void) zoneData; } mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport, DNSQuestion **matchQuestion) { - (void) m; - (void) msg; - (void) end; - (void) srcaddr; - (void) srcport; - (void) matchQuestion; + (void) m; + (void) msg; + (void) end; + (void) srcaddr; + (void) srcport; + (void) matchQuestion; - return uDNS_LLQ_Not; + return uDNS_LLQ_Not; } mDNSexport void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSOpaque16 responseFlags) { - (void) m; - (void) q; - (void) responseFlags; + (void) m; + (void) q; + (void) responseFlags; } mDNSexport void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID) @@ -5928,7 +6112,7 @@ mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info, const (void) hostname; (void) port; (void) autoTunnel; - + return mStatus_UnsupportedErr; } @@ -5938,7 +6122,7 @@ mDNSexport domainname *uDNS_GetNextSearchDomain(mDNS *const m, mDNSInterfaceID (void) InterfaceID; (void) searchIndex; (void) ignoreDotLocal; - + return mDNSNULL; } @@ -5946,7 +6130,7 @@ mDNSexport DomainAuthInfo *GetAuthInfoForName(mDNS *m, const domainname *const n { (void) m; (void) name; - + return mDNSNULL; } @@ -5954,7 +6138,7 @@ mDNSexport mStatus mDNS_StartNATOperation(mDNS *const m, NATTraversalInfo *trave { (void) m; (void) traversal; - + return mStatus_UnsupportedErr; } @@ -5962,7 +6146,7 @@ mDNSexport mStatus mDNS_StopNATOperation(mDNS *const m, NATTraversalInfo *traver { (void) m; (void) traversal; - + return mStatus_UnsupportedErr; } @@ -5983,7 +6167,7 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons (void) reqA; (void) reqAAAA; (void) reqDO; - + return mDNSNULL; } @@ -6034,8 +6218,27 @@ mDNSexport void RecreateNATMappings(mDNS *const m, const mDNSu32 waitTicks) mDNSexport mDNSBool IsGetZoneDataQuestion(DNSQuestion *q) { (void)q; - + return mDNSfalse; } +mDNSexport void SubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q) +{ + (void)m; + (void)q; +} + +mDNSexport void UnSubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q) +{ + (void)m; + (void)q; +} + +mDNSexport void DiscoverDNSPushNotificationServer(mDNS *m, DNSQuestion *q) +{ + (void)m; + (void)q; +} + #endif // !UNICAST_DISABLED + diff --git a/mDNSResponder/mDNSCore/uDNS.h b/mDNSResponder/mDNSCore/uDNS.h index eca8b701..910449f1 100755 --- a/mDNSResponder/mDNSCore/uDNS.h +++ b/mDNSResponder/mDNSCore/uDNS.h @@ -47,9 +47,8 @@ extern "C" { #define QuestionIntervalStep3 (QuestionIntervalStep*QuestionIntervalStep*QuestionIntervalStep) #define InitialQuestionInterval ((mDNSPlatformOneSecond + QuestionIntervalStep-1) / QuestionIntervalStep) #define MaxQuestionInterval (3600 * mDNSPlatformOneSecond) - -// just move to MaxQuestionInterval once over this threshold -#define QuestionIntervalThreshold (QuestionIntervalStep3 * mDNSPlatformOneSecond) +#define UDNSBackOffMultiplier 2 +#define MinQuestionInterval (1 * mDNSPlatformOneSecond) // For Unicast record registrations, we initialize the interval to 1 second. When we send any query for // the record registration e.g., GetZoneData, we always back off by QuestionIntervalStep @@ -82,6 +81,11 @@ extern void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo) extern void startLLQHandshake(mDNS *m, DNSQuestion *q); extern void sendLLQRefresh(mDNS *m, DNSQuestion *q); +extern void DNSPushNotificationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo); +extern void DiscoverDNSPushNotificationServer(mDNS *m, DNSQuestion *q); +extern void SubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q); +extern void UnSubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q); + extern void SleepRecordRegistrations(mDNS *m); // uDNS_UpdateRecord @@ -144,6 +148,10 @@ extern void uDNS_ReceiveNATPacket(mDNS *m, const mDNSInterfaceID InterfaceID, mD extern void natTraversalHandleAddressReply(mDNS *const m, mDNSu16 err, mDNSv4Addr ExtAddr); extern void natTraversalHandlePortMapReply(mDNS *const m, NATTraversalInfo *n, const mDNSInterfaceID InterfaceID, mDNSu16 err, mDNSIPPort extport, mDNSu32 lease, NATTProtocol protocol); +// DNS Push Notification +extern void SubscribeToDNSPushNotification(mDNS *m, DNSQuestion *q); + + #ifdef __cplusplus } #endif diff --git a/mDNSResponder/mDNSMacOSX/BLE.c b/mDNSResponder/mDNSMacOSX/BLE.c new file mode 100644 index 00000000..85fb810c --- /dev/null +++ b/mDNSResponder/mDNSMacOSX/BLE.c @@ -0,0 +1,853 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2015-2016 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 "mDNSEmbeddedAPI.h" +#include "DNSCommon.h" +#include "mDNSMacOSX.h" +#include "BLE.h" +#include + +#pragma mark - Browse and Registration Request Handling + +// Disable use of BLE discovery APIs by default. +mDNSBool EnableBLEBasedDiscovery = mDNSfalse; + +typedef struct matchingResponses +{ + struct matchingResponses * next; + void * response; +} matchingResponses_t; + +// Initially used for both the browse and registration lists. +typedef struct requestList +{ + struct requestList * next; + unsigned int refCount; + domainname name; + mDNSu16 type; + DNSServiceFlags flags; + mDNSInterfaceID InterfaceID; + +// TODO: Possibly restructure the following browse and registration specific +// members as a union to save a bit of space. + + // The following fields are only used for browse requests currently + serviceHash_t browseHash; + DNSQuestion * question; + mDNSu8 key[MAX_DOMAIN_LABEL]; + size_t keySize; + matchingResponses_t * ourResponses; + + // The following fields are only used for registration requests currently + serviceHash_t registeredHash; + ServiceRecordSet * serviceRecordSet; // service record set in the original request + AuthRecType savedARType; + bool triggeredOnAWDL; +} requestList_t; + +// Lists for all DNSServiceBrowse() and DNSServiceRegister() requests using +// BLE beacon based triggering. +static requestList_t* BLEBrowseListHead = NULL; +static requestList_t* BLERegistrationListHead = NULL; + +#define isAutoTriggerRequest(ptr) ((ptr->InterfaceID == kDNSServiceInterfaceIndexAny) && (ptr->flags & kDNSServiceFlagsAutoTrigger)) + +#pragma mark - Manage list of responses that match this request. + +mDNSlocal bool inResponseListForRequest(requestList_t *request, void * response) +{ + matchingResponses_t * rp; + + for (rp = request->ourResponses; rp; rp = rp->next) + if (rp->response == response) + break; + + return (rp != 0); +} + +mDNSlocal void addToResponseListForRequest(requestList_t *request, void * response) +{ + matchingResponses_t *matchingResponse = calloc(1, sizeof(matchingResponses_t)); + + if (matchingResponse == NULL) + { + LogMsg("addToResponseListForRequest: calloc() failed!"); + return; + } + matchingResponse->response = response; + matchingResponse->next = request->ourResponses; + request->ourResponses = matchingResponse; +} + +// If response is currently in the list of responses, remove it and return true. +// Othewise, return false. +mDNSlocal bool removeFromResponseListForRequest(requestList_t *request, void * response) +{ + matchingResponses_t ** nextp; + bool responseRemoved = false; + + for (nextp = & request->ourResponses; *nextp; nextp = & (*nextp)->next) + if ((*nextp)->response == response) + break; + + if (*nextp) + { + LogInfo("removeFromResponseListForRequest: response no longer matches for %##s %s ", request->name.c, DNSTypeName(request->type)); + + responseRemoved = true; + matchingResponses_t *tmp = *nextp; + *nextp = (*nextp)->next; + free(tmp); + } + return responseRemoved; +} + +// Free all current entries on the response list for this request. +mDNSlocal void freeResponseListEntriesForRequest(requestList_t *request) +{ + matchingResponses_t * ptr; + + ptr = request->ourResponses; + while (ptr) + { + matchingResponses_t * tmp; + + tmp = ptr; + ptr = ptr->next; + free(tmp); + } +} + +#pragma mark - Manage request lists + +mDNSlocal requestList_t ** findInRequestList(requestList_t ** listHead, const domainname *const name, mDNSu16 type) +{ + requestList_t **ptr = listHead; + + for ( ; *ptr; ptr = &(*ptr)->next) + if ((*ptr)->type == type && SameDomainName(&(*ptr)->name, name)) + break; + + return ptr; +} + +mDNSlocal requestList_t * addToRequestList(requestList_t ** listHead, const domainname *const name, mDNSu16 type, DNSServiceFlags flags) +{ + requestList_t **ptr = findInRequestList(listHead, name, type); + + if (!*ptr) + { + *ptr = mDNSPlatformMemAllocate(sizeof(**ptr)); + mDNSPlatformMemZero(*ptr, sizeof(**ptr)); + (*ptr)->type = type; + (*ptr)->flags = flags; + AssignDomainName(&(*ptr)->name, name); + } + (*ptr)->refCount += 1; + + LogInfo("addToRequestList: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount); + + return *ptr; +} + +mDNSlocal void removeFromRequestList(requestList_t ** listHead, const domainname *const name, mDNSu16 type) +{ + requestList_t **ptr = findInRequestList(listHead, name, type); + + if (!*ptr) { LogMsg("removeFromRequestList: Didn't find %##s %s in list", name->c, DNSTypeName(type)); return; } + + (*ptr)->refCount -= 1; + + LogInfo("removeFromRequestList: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount); + + if (!(*ptr)->refCount) + { + requestList_t *tmp = *ptr; + *ptr = (*ptr)->next; + freeResponseListEntriesForRequest(tmp); + mDNSPlatformMemFree(tmp); + } +} + +#pragma mark - Hashing and beacon state + +// Simple string hash based on the Bernstein hash. + +#define PRIME 31 // small prime number +#define MODULO (sizeof(serviceHash_t) * 8) +#define CONVERT_TO_LOWER_CASE(x) (((x) <= 'Z' && (x) >= 'A') ? ((x) | 0x20) : (x)) + +mDNSlocal serviceHash_t BLELabelHash(const unsigned char *str, unsigned int length) +{ + serviceHash_t hash = 0; + + for (unsigned int i = 0; i < length; i++) { + hash = PRIME * hash + CONVERT_TO_LOWER_CASE(*str); + str++; + } + + hash %= MODULO; + LogInfo("BLELabelHash: %d characters hashed to %d", length, hash); + + return ((serviceHash_t)1 << hash); +} + +// Hash just the service type not including the protocol or first "_" character initially. +mDNSlocal serviceHash_t BLEServiceHash(const domainname *const domain) +{ + const unsigned char *p = domain->c; + unsigned int length = (unsigned int) *p; + + p++; + if (*p != '_') + { + LogInfo("BLEServiceHash: browse type does not begin with a _"); + return 0; + } + p++; // skip the '-" + length--; + + if (length > MAX_DOMAIN_LABEL || length == 0) + { + LogInfo("BLEServiceHash: invalid browse type length: %d characters", length); + return 0; + } + + return BLELabelHash(p, length); +} + +// Storage for the current Bonjour BLE beacon data; +typedef struct BLEBeacon +{ + serviceHash_t browseHash; + serviceHash_t registeredHash; +} BLEBeacon_t; + +BLEBeacon_t BLEBeacon; + +mDNSlocal void addServiceToBeacon(serviceHash_t browseHash, serviceHash_t registeredHash) +{ + bool beaconUpdated = false; + + if (BLEBeacon.browseHash & browseHash) + { + LogInfo("addServiceToBeacon: Bit 0x%x already set in browsing services hash", browseHash); + } + else + { + BLEBeacon.browseHash |= browseHash; + beaconUpdated = true; + } + + if (BLEBeacon.registeredHash & registeredHash) + { + LogInfo("addServiceToBeacon: Bit 0x%x already set in advertising services hash", registeredHash); + } + else + { + BLEBeacon.registeredHash |= registeredHash; + beaconUpdated = true; + } + + if (beaconUpdated) + updateBLEBeaconAndScan(BLEBeacon.browseHash, BLEBeacon.registeredHash); +} + +// Go through all the existing browses and registrations to get the +// current hash values for the corresponding BLE beacon. +// We must do this when any hash bits are removed do accurately generate +// the correct combination of all currently set hash bits. +mDNSlocal void updateBeacon() +{ + requestList_t *ptr; + + BLEBeacon.browseHash = 0; + BLEBeacon.registeredHash = 0; + + for (ptr = BLEBrowseListHead; ptr; ptr = ptr->next) + { + BLEBeacon.browseHash |= ptr->browseHash; + } + + for (ptr = BLERegistrationListHead; ptr; ptr = ptr->next) + { + BLEBeacon.registeredHash |= ptr->registeredHash; + } + + updateBLEBeaconAndScan(BLEBeacon.browseHash, BLEBeacon.registeredHash); +} + +#pragma mark - Request start/stop + +// Forward declarations for mDNSLocal functions that are called before they are defined. +mDNSlocal void checkForMatchingResponses(requestList_t *bp); +mDNSlocal void clearResponseLists(); + +void start_BLE_browse(DNSQuestion * q, const domainname *const domain, DNS_TypeValues type, DNSServiceFlags flags, mDNSu8 *key, size_t keySize) +{ + requestList_t * ptr; + + if (!EnableBLEBasedDiscovery) + { + LogMsg("start_BLE_browse: EnableBLEBasedDiscovery disabled"); + return; + } + + LogInfo("start_BLE_browse: Starting BLE browse for: %##s %s", domain->c, DNSTypeName(type)); + + ptr = addToRequestList(&BLEBrowseListHead, domain, type, flags); + + // If equivalent BLE browse is already running, just return. + if (ptr->refCount > 1) + { + LogInfo("start_BLE_browse: Dup of existing BLE browse."); + return; + } + + ptr->browseHash = BLEServiceHash(domain); + ptr->question = q; + + if (ptr->browseHash == 0) + { + LogInfo("BLEServiceHash failed!"); + removeFromRequestList(&BLEBrowseListHead, domain, type); + return; + } + + // Save these for use in D2D plugin callback logic. + memcpy(ptr->key, key, keySize); + ptr->keySize = keySize; + // Extract the interface ID for easier access in the requestList_t structure + ptr->InterfaceID = q->InterfaceID; + + addServiceToBeacon(ptr->browseHash, 0); + + checkForMatchingResponses(ptr); +} + +// Stop the browse. +// Return true if this is the last reference to the browse, false otherwise. +bool stop_BLE_browse(const domainname *const domain, DNS_TypeValues type, DNSServiceFlags flags) +{ + (void) flags; // not used initially + requestList_t * ptr; + bool lastReference = false; + + if (!EnableBLEBasedDiscovery) + { + LogMsg("stop_BLE_browse: EnableBLEBasedDiscovery disabled"); + return lastReference; + } + + LogInfo("stop_BLE_browse: Stopping BLE browse for: %##s %s", domain->c, DNSTypeName(type)); + + ptr = *(findInRequestList(&BLEBrowseListHead, domain, type)); + if (ptr == 0) + { + LogInfo("stop_BLE_browse: No matching browse found."); + return lastReference; + } + + // If this is the last reference for this browse, update advertising and browsing bits set in + // the beacon after removing this browse from the list. + if (ptr->refCount == 1) + lastReference = true; + + removeFromRequestList(&BLEBrowseListHead, domain, type); + + if (lastReference) + updateBeacon(); + + // If there are no active browse or registration requests, BLE scanning will be disabled. + // Clear the list of responses received to remove any stale response state. + if (BLEBrowseListHead == NULL && BLERegistrationListHead == 0) + clearResponseLists(); + + return lastReference; +} + +extern void internal_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags, DNSQuestion * q); +extern void internal_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags); + +extern void internal_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags); +extern void internal_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags); + +void start_BLE_advertise(ServiceRecordSet * serviceRecordSet, const domainname *const domain, DNS_TypeValues type, DNSServiceFlags flags) +{ + requestList_t * ptr; + const domainname * instanceRemoved; + + if (!EnableBLEBasedDiscovery) + { + LogMsg("start_BLE_advertise: EnableBLEBasedDiscovery disabled"); + return; + } + + // Just process the SRV record for each service registration. The PTR + // record already has the service type at the beginning of the domain, but + // we want to filter out reverse address PTR records at this point in time, so using + // the SRV record instead. + if (type != kDNSServiceType_SRV) + return; + + if (serviceRecordSet == NULL) + { + LogInfo("start_BLE_advertise: NULL service record set for: %##s %s, returning", domain->c, DNSTypeName(type)); + return; + } + LogInfo("start_BLE_advertise: Starting BLE advertisement for: %##s %s", domain->c, DNSTypeName(type)); + + instanceRemoved = SkipLeadingLabels(domain, 1); + + ptr = addToRequestList(&BLERegistrationListHead, instanceRemoved, type, flags); + + // If equivalent BLE registration is already running, just return. + if (ptr->refCount > 1) + { + LogInfo("start_BLE_advertise: Dup of existing BLE advertisement."); + return; + } + + ptr->registeredHash = BLEServiceHash(instanceRemoved); + if (ptr->registeredHash == 0) + { + LogInfo("BLEServiceHash failed!"); + removeFromRequestList(&BLERegistrationListHead, instanceRemoved, type); + return; + } + ptr->serviceRecordSet = serviceRecordSet; + // Extract the interface ID for easier access in the requestList_t structure + ptr->InterfaceID = serviceRecordSet->RR_SRV.resrec.InterfaceID; + + addServiceToBeacon(0, ptr->registeredHash); +} + +void stop_BLE_advertise(const domainname *const domain, DNS_TypeValues type, DNSServiceFlags flags) +{ + (void) flags; // not used initially + requestList_t * ptr; + bool lastReference = false; + const domainname * instanceRemoved; + + if (!EnableBLEBasedDiscovery) + { + LogMsg("stop_BLE_advertise: EnableBLEBasedDiscovery disabled"); + return; + } + + // Just process the SRV record for each service registration. The PTR + // record already has the service type at the beginning of the domain, but + // we want to filter out reverse address PTR records at this point in time, so using + // the SRV record instead. + if (type != kDNSServiceType_SRV) + return; + + LogInfo("stop_BLE_advertise: Stopping BLE advertisement for: %##s %s", domain->c, DNSTypeName(type)); + + instanceRemoved = SkipLeadingLabels(domain, 1); + + // Get the request pointer from the indirect pointer returned. + ptr = *(findInRequestList(&BLERegistrationListHead, instanceRemoved, type)); + + if (ptr == 0) + { + LogInfo("stop_BLE_advertise: No matching advertisement found."); + return; + } + + // If this is the last reference for this registration, update advertising and browsing bits set in + // the beacon before removing this registration from the request list. + if (ptr->refCount == 1) + { + lastReference = true; + + if (isAutoTriggerRequest(ptr) && ptr->triggeredOnAWDL) + { + // And remove the corresponding advertisements from the AWDL D2D plugin. + // Do it directly here, since we do not set the kDNSServiceFlagsIncludeAWDL bit in the original client request structure + // when we trigger the registration over AWDL, we just update the record ARType field, so our caller, external_stop_browsing_for_service() + // would not call into the D2D plugin to remove the advertisements in this case. + internal_stop_advertising_service(& ptr->serviceRecordSet->RR_PTR.resrec, (ptr->flags | kDNSServiceFlagsIncludeAWDL)); + internal_stop_advertising_service(& ptr->serviceRecordSet->RR_SRV.resrec, (ptr->flags | kDNSServiceFlagsIncludeAWDL)); + internal_stop_advertising_service(& ptr->serviceRecordSet->RR_TXT.resrec, (ptr->flags | kDNSServiceFlagsIncludeAWDL)); + } + } + removeFromRequestList(&BLERegistrationListHead, instanceRemoved, type); + + if (lastReference) + updateBeacon(); + + // If there are no active browse or registration requests, BLE scanning will be disabled. + // Clear the list of responses received to remove any stale response state. + if (BLEBrowseListHead == NULL && BLERegistrationListHead == 0) + clearResponseLists(); +} + +#pragma mark - Response Handling + +// Structure used to track the beacons received from various peers. +typedef struct responseList +{ + struct responseList * next; + serviceHash_t browseHash; + serviceHash_t registeredHash; + mDNSEthAddr senderMAC; +} responseList_t; + +#define RESPONSE_LIST_NUMBER 8 +static responseList_t* BLEResponseListHeads[RESPONSE_LIST_NUMBER]; + +mDNSlocal responseList_t ** findInResponseList(mDNSEthAddr * ptrToMAC) +{ + // Use the least significant byte of the MAC address as our hash index to find the list. + responseList_t **ptr = & BLEResponseListHeads[ptrToMAC->b[5] % RESPONSE_LIST_NUMBER]; + + for ( ; *ptr; ptr = &(*ptr)->next) + { + if (memcmp(&(*ptr)->senderMAC, ptrToMAC, sizeof(mDNSEthAddr)) == 0) + break; + } + + return ptr; +} + + +mDNSlocal responseList_t ** addToResponseList(serviceHash_t browseHash, serviceHash_t registeredHash, mDNSEthAddr * ptrToMAC) +{ + responseList_t **ptr = findInResponseList(ptrToMAC); + + if (!*ptr) + { + *ptr = mDNSPlatformMemAllocate(sizeof(**ptr)); + mDNSPlatformMemZero(*ptr, sizeof(**ptr)); + (*ptr)->browseHash = browseHash; + (*ptr)->registeredHash = registeredHash; + memcpy(& (*ptr)->senderMAC, ptrToMAC, sizeof(mDNSEthAddr)); + } + + return ptr; +} + +mDNSlocal void removeFromResponseList(mDNSEthAddr * ptrToMAC) +{ + responseList_t **ptr = findInResponseList(ptrToMAC); + + if (!*ptr) + { + LogMsg("removeFromResponseList: did not find entry for MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", + ptrToMAC->b[0], ptrToMAC->b[1], ptrToMAC->b[2], ptrToMAC->b[3], ptrToMAC->b[4], ptrToMAC->b[5]); + return; + } + + LogInfo("removeFromResponseList: removing entry for MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", + ptrToMAC->b[0], ptrToMAC->b[1], ptrToMAC->b[2], ptrToMAC->b[3], ptrToMAC->b[4], ptrToMAC->b[5]); + + responseList_t *tmp = *ptr; + *ptr = (*ptr)->next; + mDNSPlatformMemFree(tmp); +} + +// Free all current entries on the BLE response lists, removing all pointers +// to freed structures from the lists. +mDNSlocal void clearResponseLists() +{ + responseList_t **ptr; + + for (unsigned int i = 0; i < RESPONSE_LIST_NUMBER; i++) + { + ptr = & BLEResponseListHeads[i]; + while (*ptr) + { + responseList_t * tmp; + + tmp = *ptr; + *ptr = (*ptr)->next; + mDNSPlatformMemFree(tmp); + } + } +} + +// Called from mDNS_Execute() when NextBLEServiceTime is reached +// to stop the BLE beacon a few seconds after the last request has +// been stopped. This gives peers a chance to see that this device +// is no longer browsing for or advertising any services via the +// BLE beacon. +void serviceBLE(void) +{ + mDNSStorage.NextBLEServiceTime = 0; + if (BLEBrowseListHead || BLERegistrationListHead) + { + // We don't expect to be called if there are active requests. + LogInfo("serviceBLE: called with active BLE requests ??"); + return; + } + stopBLEBeacon(); +} + +// Called from start_BLE_browse() on the mDNSResonder kqueue thread +mDNSlocal void checkForMatchingResponses(requestList_t *bp) +{ + responseList_t *ptr; + + for (unsigned int i = 0; i < RESPONSE_LIST_NUMBER; i++) + { + for (ptr = BLEResponseListHeads[i]; ptr; ptr = ptr->next) + { + if ((bp->browseHash & ptr->registeredHash) == bp->browseHash) + { + // Clear the registered services hash for the response. + // The next beacon from this peer will update the hash and our + // newly started browse will get an add event if there is a match. + ptr->registeredHash = 0; + } + } + } +} + +// Define a fixed name to use for the instance name denoting that one or more instances +// of a service are being advetised by peers in their BLE beacons. +// Name format is: length byte + bytes of name string + two byte pointer to the PTR record name. +// See compression_lhs definition in the D2D plugin code for backgound on 0xc027 DNS name compression pointer value. +static Byte *BLEinstanceValue = (Byte *) "\x11ThresholdInstance\xc0\x27"; +#define BLEValueSize strlen((const char *)BLEinstanceValue) + +void xD2DAddToCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize); +void xD2DRemoveFromCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize); + +// Find each unique browse that matches the registered service hash in the BLE response. +// Called on the CFRunLoop thread while handling a callback from CoreBluetooth. +// Caller should hold KQueueLock(). +mDNSlocal void findMatchingBrowse(responseList_t *response) +{ + requestList_t *ptr; + + ptr = BLEBrowseListHead; + for ( ; ptr; ptr = ptr->next) + { + if ((ptr->browseHash & response->registeredHash) == ptr->browseHash) + { + + LogInfo("findMatchingBrowse: Registration in response matched browse for: %##s", ptr->name.c); + + if (inResponseListForRequest(ptr, response)) + { + LogInfo("findMatchingBrowse: Already on response list for browse: %##s", ptr->name.c); + + continue; + } + else + { + LogInfo("findMatchingBrowse: Adding to response list for browse: %##s", ptr->name.c); + + if (ptr->ourResponses == 0) + { + if (isAutoTriggerRequest(ptr)) + { + LogInfo("findMatchingBrowse: First BLE response, triggering browse for %##s on AWDL", ptr->name.c); + ptr->question->flags |= kDNSServiceFlagsIncludeAWDL; + mDNSCoreRestartQuestion(& mDNSStorage, ptr->question); + // register with the AWDL D2D plugin, + internal_start_browsing_for_service(ptr->question->InterfaceID, & ptr->name, ptr->type, ptr->question->flags, ptr->question); + } + + // Browse on mDNSInterface_BLE is used to determine if there are one or more instances of the + // service type discoveryed over BLE. If this is the first instance, add the psuedo instance defined by BLEinstanceValue. + if (ptr->question->InterfaceID == mDNSInterface_BLE) + { + xD2DAddToCache(& mDNSStorage, kD2DSuccess, 0, D2DBLETransport, ptr->key, ptr->keySize, BLEinstanceValue, BLEValueSize); + } + } + addToResponseListForRequest(ptr, response); + } + } + else + { + // If a previous response from this peer had matched the browse, remove that response from the + // list now. If this is the last matching response, remove the corresponding key from the AWDL D2D plugin + if (removeFromResponseListForRequest(ptr, response) && (ptr->ourResponses == 0)) + { + if (ptr->question->InterfaceID == mDNSInterface_BLE) + { + xD2DRemoveFromCache(& mDNSStorage, kD2DSuccess, 0, D2DBLETransport, ptr->key, ptr->keySize, BLEinstanceValue, BLEValueSize); + } + + if (isAutoTriggerRequest(ptr)) + { + LogInfo("findMatchingBrowse: Last BLE response, disabling browse for %##s on AWDL", ptr->name.c); + internal_stop_browsing_for_service(ptr->question->InterfaceID, & ptr->name, ptr->type, ptr->question->flags); + } + } + } + } +} + +// Find each local registration that matches the service browse hash in the BLE response. +// Called on the CFRunLoop thread while handling a callback from CoreBluetooth. +// Caller should hold KQueueLock(). +mDNSlocal void findMatchingRegistration(responseList_t *response) +{ + requestList_t *ptr; + + ptr = BLERegistrationListHead; + for ( ; ptr; ptr = ptr->next) + { + if ((ptr->registeredHash & response->browseHash) == ptr->registeredHash) + { + + LogInfo("findMatchingRegistration: Incoming browse matched registration for: %##s", ptr->name.c); + + if (inResponseListForRequest(ptr, response)) + { + LogInfo("findMatchingRegistration: Already on response list for registration: %##s", ptr->name.c); + + continue; + } + else + { + LogInfo("findMatchingRegistration: Adding to response list for registration: %##s", ptr->name.c); + + // Also pass the registration to the AWDL D2D plugin if this is the first matching peer browse for + // an auto triggered local registration. + if ((ptr->ourResponses == 0) && isAutoTriggerRequest(ptr)) + { + AuthRecType newARType; + + LogInfo("findMatchingRegistration: First BLE response, triggering registration for %##s on AWDL", ptr->name.c); + if (ptr->serviceRecordSet == 0) + { + LogInfo("findMatchingRegistration: serviceRecordSet pointer is NULL ??"); + continue; + } + // Modify the PTR, TXT, and SRV records so that they now apply to AWDL and restart the registration. + // RR_ADV is not passed to the D2D plugins froma internal_start_advertising_helper(), so we don't do it here either. + + if (ptr->flags & kDNSServiceFlagsIncludeAWDL) + { + LogInfo("findMatchingRegistration: registration for %##s already applies to AWDL, skipping", ptr->name.c); + continue; + } + + // Save the current ARType value to restore when the promotion to use AWDL is stopped. + ptr->savedARType = ptr->serviceRecordSet->RR_PTR.ARType; + + // Preserve P2P attribute if original registration was applied to P2P. + if (ptr->serviceRecordSet->RR_PTR.ARType == AuthRecordAnyIncludeP2P) + newARType = AuthRecordAnyIncludeAWDLandP2P; + else + newARType = AuthRecordAnyIncludeAWDL; + + ptr->serviceRecordSet->RR_PTR.ARType = newARType; + ptr->serviceRecordSet->RR_SRV.ARType = newARType; + ptr->serviceRecordSet->RR_TXT.ARType = newARType; + mDNSCoreRestartRegistration(& mDNSStorage, & ptr->serviceRecordSet->RR_PTR, -1); + mDNSCoreRestartRegistration(& mDNSStorage, & ptr->serviceRecordSet->RR_SRV, -1); + mDNSCoreRestartRegistration(& mDNSStorage, & ptr->serviceRecordSet->RR_TXT, -1); + + internal_start_advertising_service(& ptr->serviceRecordSet->RR_PTR.resrec, (ptr->flags | kDNSServiceFlagsIncludeAWDL)); + internal_start_advertising_service(& ptr->serviceRecordSet->RR_SRV.resrec, (ptr->flags | kDNSServiceFlagsIncludeAWDL)); + internal_start_advertising_service(& ptr->serviceRecordSet->RR_TXT.resrec, (ptr->flags | kDNSServiceFlagsIncludeAWDL)); + // indicate the registration has been applied to the AWDL interface + ptr->triggeredOnAWDL = true; + } + + addToResponseListForRequest(ptr, response); + } + } + else + { + // If a previous response from this peer had matched the browse, remove that response from the + // list now. If this is the last matching response for a local auto triggered registration, + // remove the advertised key/value pairs from the AWDL D2D plugin. + if (removeFromResponseListForRequest(ptr, response) && (ptr->ourResponses == 0) && isAutoTriggerRequest(ptr)) + { + LogInfo("findMatchingRegistration: Last BLE response, disabling registration for %##s on AWDL", ptr->name.c); + + // Restore the saved ARType and call into the AWDL D2D plugin to stop the corresponding record advertisements over AWDL. + ptr->serviceRecordSet->RR_PTR.ARType = ptr->savedARType; + ptr->serviceRecordSet->RR_SRV.ARType = ptr->savedARType; + ptr->serviceRecordSet->RR_TXT.ARType = ptr->savedARType; + internal_stop_advertising_service(& ptr->serviceRecordSet->RR_PTR.resrec, (ptr->flags | kDNSServiceFlagsIncludeAWDL)); + internal_stop_advertising_service(& ptr->serviceRecordSet->RR_SRV.resrec, (ptr->flags | kDNSServiceFlagsIncludeAWDL)); + internal_stop_advertising_service(& ptr->serviceRecordSet->RR_TXT.resrec, (ptr->flags | kDNSServiceFlagsIncludeAWDL)); + } + } + } +} + +// Called on CFRunLoop thread during CoreBluetooth beacon response processing. +// Thus, must call KQueueLock() prior to calling any core mDNSResponder routines to register records, etc. +void responseReceived(serviceHash_t browseHash, serviceHash_t registeredHash, mDNSEthAddr * ptrToMAC) +{ + responseList_t ** ptr; + + KQueueLock(& mDNSStorage); + ptr = findInResponseList(ptrToMAC); + if (*ptr == 0) + { + // Only add to list if peer is actively browsing or advertising. + if (browseHash || registeredHash) + { + LogInfo("responseReceived: First beacon of this type, adding to list"); + LogInfo("responseReceived: browseHash = 0x%x, registeredHash = 0x%x", + browseHash, registeredHash); + LogInfo("responseReceived: sender MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", + ptrToMAC->b[0], ptrToMAC->b[1], ptrToMAC->b[2], ptrToMAC->b[3], ptrToMAC->b[4], ptrToMAC->b[5]); + + ptr = addToResponseList(browseHash, registeredHash, ptrToMAC); + // See if we are browsing for any of the peers advertised services. + findMatchingBrowse(*ptr); + // See if we have a registration that matches the peer's browse. + findMatchingRegistration(*ptr); + } + } + else // have entry from this MAC in the list + { + if (((*ptr)->browseHash == browseHash) && ((*ptr)->registeredHash == registeredHash)) + { + // A duplicate of a current entry. +#if VERBOSE_BLE_DEBUG + LogInfo("responseReceived: Duplicate of previous beacon, ignoring"); + LogInfo("responseReceived: sender MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", + ptrToMAC->b[0], ptrToMAC->b[1], ptrToMAC->b[2], ptrToMAC->b[3], ptrToMAC->b[4], ptrToMAC->b[5]); +#endif // VERBOSE_BLE_DEBUG + } + else + { + LogInfo("responseReceived: Update of previous beacon"); + LogInfo("responseReceived: browseHash = 0x%x, registeredHash = 0x%x", + browseHash, registeredHash); + LogInfo("responseReceived: sender MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", + ptrToMAC->b[0], ptrToMAC->b[1], ptrToMAC->b[2], ptrToMAC->b[3], ptrToMAC->b[4], ptrToMAC->b[5]); + + (*ptr)->browseHash = browseHash; + (*ptr)->registeredHash = registeredHash; + + findMatchingBrowse(*ptr); + findMatchingRegistration(*ptr); + } + + // If peer is no longer browsing or advertising, remove from list. + if ((browseHash == 0) && (registeredHash == 0)) + { + LogInfo("responseReceived: Removing peer entry from the list"); + + removeFromResponseList(ptrToMAC); + } + } + + KQueueUnlock(& mDNSStorage, "BLE responseReceived"); +} diff --git a/mDNSResponder/mDNSMacOSX/BLE.h b/mDNSResponder/mDNSMacOSX/BLE.h new file mode 100644 index 00000000..970c8faf --- /dev/null +++ b/mDNSResponder/mDNSMacOSX/BLE.h @@ -0,0 +1,54 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2015-2016 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. + */ + +#ifndef _BLE_H_ +#define _BLE_H_ + +#include "dns_sd.h" +#include "dns_sd_private.h" + +typedef unsigned int serviceHash_t; + +void start_BLE_browse(DNSQuestion * q, const domainname *const typeDomain, DNS_TypeValues type, DNSServiceFlags flags, + mDNSu8 *key, size_t keySize); +bool stop_BLE_browse(const domainname *const typeDomain, DNS_TypeValues type, DNSServiceFlags flags); + +void start_BLE_advertise(ServiceRecordSet * serviceRecordSet, const domainname *const domain, DNS_TypeValues type, DNSServiceFlags flags); +void stop_BLE_advertise(const domainname *const typeDomain, DNS_TypeValues type, DNSServiceFlags flags); + +void responseReceived(serviceHash_t browseHash, serviceHash_t registeredHash, mDNSEthAddr *ptrToMAC); + +void serviceBLE(void); + +// C interfaces to Objective-C beacon management code. +void updateBLEBeaconAndScan(serviceHash_t browseHash, serviceHash_t registeredHash); +void stopBLEBeacon(void); + +extern mDNS mDNSStorage; +extern mDNSBool EnableBLEBasedDiscovery; + +// TODO: Add the following to a local D2D.h file +#include + +// Just define as the current max value for now. +// TODO: Will need to define in DeviceToDeviceManager.framework if we convert this +// BLE discovery code to a D2D plugin. +#define D2DBLETransport D2DTransportMax + +#define applyToBLE(interface, flags) ((interface == mDNSInterface_BLE) || ((interface == mDNSInterface_Any) && (flags & kDNSServiceFlagsAutoTrigger))) + +#endif /* _BLE_H_ */ diff --git a/mDNSResponder/mDNSMacOSX/DNSProxySupport.c b/mDNSResponder/mDNSMacOSX/DNSProxySupport.c index 34f21a57..7666cbc4 100644 --- a/mDNSResponder/mDNSMacOSX/DNSProxySupport.c +++ b/mDNSResponder/mDNSMacOSX/DNSProxySupport.c @@ -21,6 +21,7 @@ #include #include #include +#include #define ValidSocket(s) ((s) >= 0) @@ -101,6 +102,9 @@ mDNSlocal void ProxyTCPSocketCallBack(int s1, short filter, void *context) ProxyTCPInfo_t *ti = (ProxyTCPInfo_t *)context; TCPSocket *sock = &ti->sock; KQSocketSet *kq = &sock->ss; + struct tcp_info tcp_if; + socklen_t size = sizeof(tcp_if); + int32_t intf_id = 0; (void) filter; @@ -135,6 +139,12 @@ mDNSlocal void ProxyTCPSocketCallBack(int s1, short filter, void *context) mDNSPlatformDisposeProxyContext(ti); return; } + if (getsockopt(s1, IPPROTO_TCP, TCP_INFO, &tcp_if, &size) != 0) + { + LogMsg("ProxyTCPReceive: getsockopt for TCP_INFO failed (fd=%d) errno %d", s1, errno); + return; + } + intf_id = tcp_if.tcpi_last_outif; if (from.ss_family == AF_INET) { @@ -148,7 +158,8 @@ mDNSlocal void ProxyTCPSocketCallBack(int s1, short filter, void *context) destAddr.type = mDNSAddrType_IPv4; destAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr; - LogInfo("ProxyTCPReceive received IPv4 packet(len %d) from %#-15a to %#-15a on skt %d %s", ti->replyLen, &senderAddr, &destAddr, s1, NULL); + LogInfo("ProxyTCPReceive received IPv4 packet(len %d) from %#-15a to %#-15a on skt %d %s ifindex %d", + ti->replyLen, &senderAddr, &destAddr, s1, NULL, intf_id); } else if (from.ss_family == AF_INET6) { @@ -161,7 +172,8 @@ mDNSlocal void ProxyTCPSocketCallBack(int s1, short filter, void *context) destAddr.type = mDNSAddrType_IPv6; destAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr; - LogInfo("ProxyTCPReceive received IPv6 packet(len %d) from %#-15a to %#-15a on skt %d %s", ti->replyLen, &senderAddr, &destAddr, s1, NULL); + LogInfo("ProxyTCPReceive received IPv6 packet(len %d) from %#-15a to %#-15a on skt %d %s ifindex %d", + ti->replyLen, &senderAddr, &destAddr, s1, NULL, intf_id); } else { @@ -174,7 +186,7 @@ mDNSlocal void ProxyTCPSocketCallBack(int s1, short filter, void *context) // In the UDP case, there is just a single socket and nothing to free. Hence, the context (last argument) // would be NULL. kq->m->p->TCPProxyCallback(kq->m, sock, ti->reply, (mDNSu8 *)ti->reply + ti->replyLen, &senderAddr, senderPort, &destAddr, - UnicastDNSPort, 0, ti); + UnicastDNSPort, (mDNSInterfaceID)(uintptr_t)intf_id, ti); } mDNSlocal void ProxyTCPAccept(int s1, short filter, void *context) @@ -204,6 +216,7 @@ mDNSlocal void ProxyTCPAccept(int s1, short filter, void *context) return; } mDNSPlatformMemZero(ti, sizeof(ProxyTCPInfo_t)); + TCPSocket *sock = &ti->sock; kq = &sock->ss; @@ -222,6 +235,7 @@ mDNSlocal void ProxyTCPAccept(int s1, short filter, void *context) { LogMsg("ProxyTCPAccept: IP_RECVIF %d errno %d (%s)", newfd, errno, strerror(errno)); mDNSPlatformDisposeProxyContext(ti); + close(newfd); return; } } @@ -235,6 +249,7 @@ mDNSlocal void ProxyTCPAccept(int s1, short filter, void *context) { LogMsg("ProxyTCPAccept: IP_RECVPKTINFO %d errno %d (%s)", newfd, errno, strerror(errno)); mDNSPlatformDisposeProxyContext(ti); + close(newfd); return; } } @@ -244,7 +259,6 @@ mDNSlocal void ProxyTCPAccept(int s1, short filter, void *context) // Instead of remembering the address family, we remember the right fd. sock->fd = newfd; sock->kqEntry = k; - k->KQcallback = ProxyTCPSocketCallBack; k->KQcontext = ti; k->KQtask = "TCP Proxy packet reception"; diff --git a/mDNSResponder/mDNSMacOSX/DNSSECSupport.c b/mDNSResponder/mDNSMacOSX/DNSSECSupport.c index 6e5ae108..b87f0d44 100644 --- a/mDNSResponder/mDNSMacOSX/DNSSECSupport.c +++ b/mDNSResponder/mDNSMacOSX/DNSSECSupport.c @@ -44,6 +44,8 @@ // When we can't fetch the root TA due to network errors etc., we start off a timer // to fire at 60 seconds and then keep doubling it till we fetch it #define InitialTAFetchInterval 60 +#define DNSSECProbePercentage 1 + #if !TARGET_OS_IPHONE DNSQuestion DNSSECProbeQuestion; @@ -165,7 +167,7 @@ mDNSlocal mDNSu8 *ConvertDigest(char *digest, int digestType, int *diglen) int l, h; l = HexVal(digest[i]); h = HexVal(digest[i+1]); - if (l<0 || h<0) { LogMsg("ConvertDigest: Cannot convert digest"); return NULL;} + if (l<0 || h<0) { LogMsg("ConvertDigest: Cannot convert digest"); mDNSPlatformMemFree(dig); return NULL;} dig[j++] = (mDNSu8)((l << 4) | h); } return dig; @@ -560,8 +562,8 @@ mDNSexport void DNSSECProbe(mDNS *const m) return; rand = mDNSRandom(0x3FFFFFFF) % 100; - // Probe 5% of the time - if (rand > 5) + // Probe 1% of the time + if (rand >= DNSSECProbePercentage) return; mDNS_DropLockBeforeCallback(); diff --git a/mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.c b/mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.c index efd61b30..dd670ab1 100644 --- a/mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.c +++ b/mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.c @@ -25,7 +25,6 @@ #include "../mDNSMacOSX/DNSServiceDiscovery.h" #include "DNSServiceDiscoveryDefines.h" -#include "DNSServiceDiscoveryReplyServer.h" #include #include @@ -49,25 +48,6 @@ kern_return_t DNSServiceBrowserCreate_rpc DNSCString domain ); -extern -kern_return_t DNSServiceDomainEnumerationCreate_rpc -( - mach_port_t server, - mach_port_t client, - int registrationDomains -); - -extern -kern_return_t DNSServiceRegistrationCreate_rpc -( - mach_port_t server, - mach_port_t client, - DNSCString name, - DNSCString regtype, - DNSCString domain, - IPPort port, - DNSCString txtRecord -); extern kern_return_t DNSServiceResolverResolve_rpc @@ -79,36 +59,6 @@ kern_return_t DNSServiceResolverResolve_rpc DNSCString domain ); -extern -kern_return_t DNSServiceRegistrationAddRecord_rpc -( - mach_port_t server, - mach_port_t client, - int type, - record_data_t data, - mach_msg_type_number_t record_dataCnt, - uint32_t ttl, - natural_t *reference -); - -extern -int DNSServiceRegistrationUpdateRecord_rpc -( - mach_port_t server, - mach_port_t client, - natural_t reference, - record_data_t data, - mach_msg_type_number_t record_dataCnt, - uint32_t ttl -); - -extern -kern_return_t DNSServiceRegistrationRemoveRecord_rpc -( - mach_port_t server, - mach_port_t client, - natural_t reference -); struct a_requests { struct a_requests *next; @@ -122,552 +72,51 @@ struct a_requests { void *context; }; -static struct a_requests *a_requests = NULL; -static pthread_mutex_t a_requests_lock = PTHREAD_MUTEX_INITIALIZER; - typedef struct _dns_service_discovery_t { mach_port_t port; } dns_service_discovery_t; -static mach_port_t DNSServiceDiscoveryLookupServer(void) -{ - static mach_port_t sndPort = MACH_PORT_NULL; - kern_return_t result; - - if (sndPort != MACH_PORT_NULL) { - return sndPort; - } - - result = bootstrap_look_up(bootstrap_port, DNS_SERVICE_DISCOVERY_SERVER, &sndPort); - if (result != KERN_SUCCESS) { - printf("%s(): {%s:%d} bootstrap_look_up() failed: $%x\n", __FUNCTION__, __FILE__, __LINE__, (int) result); - sndPort = MACH_PORT_NULL; - } - - - return sndPort; -} - -static void _increaseQueueLengthOnPort(mach_port_t port) -{ - mach_port_limits_t qlimits; - kern_return_t result; - - qlimits.mpl_qlimit = 16; - result = mach_port_set_attributes(mach_task_self(), port, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&qlimits, MACH_PORT_LIMITS_INFO_COUNT); - - if (result != KERN_SUCCESS) { - printf("%s(): {%s:%d} mach_port_set_attributes() failed: $%x %s\n", __FUNCTION__, __FILE__, __LINE__, (int) result, mach_error_string(result)); - } -} dns_service_discovery_ref DNSServiceBrowserCreate (const char *regtype, const char *domain, DNSServiceBrowserReply callBack,void *context) { - mach_port_t serverPort = DNSServiceDiscoveryLookupServer(); - mach_port_t clientPort; - kern_return_t result; - dns_service_discovery_ref return_t; - struct a_requests *request; - - if (!serverPort) { - return NULL; - } - - result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort); - if (result != KERN_SUCCESS) { - printf("Mach port receive creation failed, %s\n", mach_error_string(result)); - return NULL; - } - result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND); - if (result != KERN_SUCCESS) { - printf("Mach port send creation failed, %s\n", mach_error_string(result)); - mach_port_destroy(mach_task_self(), clientPort); - return NULL; - } - _increaseQueueLengthOnPort(clientPort); - - return_t = malloc(sizeof(dns_service_discovery_t)); - return_t->port = clientPort; - - request = malloc(sizeof(struct a_requests)); - request->client_port = clientPort; - request->context = context; - request->callout.browserCallback = callBack; - - result = DNSServiceBrowserCreate_rpc(serverPort, clientPort, (char *)regtype, (char *)domain); - - if (result != KERN_SUCCESS) { - printf("There was an error creating a browser, %s\n", mach_error_string(result)); - free(request); - return NULL; - } - - pthread_mutex_lock(&a_requests_lock); - request->next = a_requests; - a_requests = request; - pthread_mutex_unlock(&a_requests_lock); - - return return_t; + + (void) regtype; // Unused + (void) domain; // Unused + (void) callBack; // Unused + (void) context; // Unused + + printf("DNSServiceBrowserCreate deprecated since 10.3 \n"); + return NULL; + } -/* Service Enumeration */ - -dns_service_discovery_ref DNSServiceDomainEnumerationCreate (int registrationDomains, DNSServiceDomainEnumerationReply callBack, void *context) -{ - mach_port_t serverPort = DNSServiceDiscoveryLookupServer(); - mach_port_t clientPort; - kern_return_t result; - dns_service_discovery_ref return_t; - struct a_requests *request; - - if (!serverPort) { - return NULL; - } - - result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort); - if (result != KERN_SUCCESS) { - printf("Mach port receive creation failed, %s\n", mach_error_string(result)); - return NULL; - } - result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND); - if (result != KERN_SUCCESS) { - printf("Mach port send creation failed, %s\n", mach_error_string(result)); - mach_port_destroy(mach_task_self(), clientPort); - return NULL; - } - _increaseQueueLengthOnPort(clientPort); - - return_t = malloc(sizeof(dns_service_discovery_t)); - return_t->port = clientPort; - - request = malloc(sizeof(struct a_requests)); - request->client_port = clientPort; - request->context = context; - request->callout.enumCallback = callBack; - - result = DNSServiceDomainEnumerationCreate_rpc(serverPort, clientPort, registrationDomains); - - if (result != KERN_SUCCESS) { - printf("There was an error creating an enumerator, %s\n", mach_error_string(result)); - free(request); - return NULL; - } - - pthread_mutex_lock(&a_requests_lock); - request->next = a_requests; - a_requests = request; - pthread_mutex_unlock(&a_requests_lock); - - return return_t; -} - - -/* Service Registration */ - -dns_service_discovery_ref DNSServiceRegistrationCreate - (const char *name, const char *regtype, const char *domain, uint16_t port, const char *txtRecord, DNSServiceRegistrationReply callBack, void *context) -{ - mach_port_t serverPort = DNSServiceDiscoveryLookupServer(); - mach_port_t clientPort; - kern_return_t result; - dns_service_discovery_ref return_t; - struct a_requests *request; - IPPort IpPort; - char *portptr = (char *)&port; - - if (!serverPort) { - return NULL; - } - - if (!txtRecord) { - txtRecord = ""; - } - - result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort); - if (result != KERN_SUCCESS) { - printf("Mach port receive creation failed, %s\n", mach_error_string(result)); - return NULL; - } - result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND); - if (result != KERN_SUCCESS) { - printf("Mach port send creation failed, %s\n", mach_error_string(result)); - mach_port_destroy(mach_task_self(), clientPort); - return NULL; - } - _increaseQueueLengthOnPort(clientPort); - - return_t = malloc(sizeof(dns_service_discovery_t)); - return_t->port = clientPort; - - request = malloc(sizeof(struct a_requests)); - request->client_port = clientPort; - request->context = context; - request->callout.regCallback = callBack; - - // older versions of this code passed the port via mach IPC as an int. - // we continue to pass it as 4 bytes to maintain binary compatibility, - // but now ensure that the network byte order is preserved by using a struct - IpPort.bytes[0] = 0; - IpPort.bytes[1] = 0; - IpPort.bytes[2] = portptr[0]; - IpPort.bytes[3] = portptr[1]; - - result = DNSServiceRegistrationCreate_rpc(serverPort, clientPort, (char *)name, (char *)regtype, (char *)domain, IpPort, (char *)txtRecord); - - if (result != KERN_SUCCESS) { - printf("There was an error creating a resolve, %s\n", mach_error_string(result)); - free(request); - return NULL; - } - - pthread_mutex_lock(&a_requests_lock); - request->next = a_requests; - a_requests = request; - pthread_mutex_unlock(&a_requests_lock); - - return return_t; -} - -/* Resolver requests */ - dns_service_discovery_ref DNSServiceResolverResolve(const char *name, const char *regtype, const char *domain, DNSServiceResolverReply callBack, void *context) { - mach_port_t serverPort = DNSServiceDiscoveryLookupServer(); - mach_port_t clientPort; - kern_return_t result; - dns_service_discovery_ref return_t; - struct a_requests *request; - - if (!serverPort) { - return NULL; - } + (void) name; // Unused + (void) regtype; // Unused + (void) domain; // Unused + (void) callBack; // Unused + (void) context; // Unused + + printf("DNSServiceResolverResolve deprecated since 10.3 \n"); + return NULL; - result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort); - if (result != KERN_SUCCESS) { - printf("Mach port receive creation failed, %s\n", mach_error_string(result)); - return NULL; - } - result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND); - if (result != KERN_SUCCESS) { - printf("Mach port send creation failed, %s\n", mach_error_string(result)); - mach_port_destroy(mach_task_self(), clientPort); - return NULL; - } - _increaseQueueLengthOnPort(clientPort); - - return_t = malloc(sizeof(dns_service_discovery_t)); - return_t->port = clientPort; - - request = malloc(sizeof(struct a_requests)); - request->client_port = clientPort; - request->context = context; - request->callout.resolveCallback = callBack; - - DNSServiceResolverResolve_rpc(serverPort, clientPort, (char *)name, (char *)regtype, (char *)domain); - - pthread_mutex_lock(&a_requests_lock); - request->next = a_requests; - a_requests = request; - pthread_mutex_unlock(&a_requests_lock); - - return return_t; -} - -DNSRecordReference DNSServiceRegistrationAddRecord(dns_service_discovery_ref ref, uint16_t rrtype, uint16_t rdlen, const char *rdata, uint32_t ttl) -{ - mach_port_t serverPort = DNSServiceDiscoveryLookupServer(); - mach_port_t clientPort; - natural_t reference = 0; - kern_return_t result = KERN_SUCCESS; - - if (!serverPort) { - return kDNSServiceDiscoveryUnknownErr; - } - - clientPort = DNSServiceDiscoveryMachPort(ref); - - if (!clientPort) { - return kDNSServiceDiscoveryUnknownErr; - } - - result = DNSServiceRegistrationAddRecord_rpc(serverPort, clientPort, rrtype, (record_data_t)rdata, rdlen, ttl, &reference); - - if (result != KERN_SUCCESS) { - printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result)); - } - - return reference; -} - -DNSServiceRegistrationReplyErrorType DNSServiceRegistrationUpdateRecord(dns_service_discovery_ref ref, DNSRecordReference reference, uint16_t rdlen, const char *rdata, uint32_t ttl) -{ - mach_port_t serverPort = DNSServiceDiscoveryLookupServer(); - mach_port_t clientPort; - kern_return_t result = KERN_SUCCESS; - - if (!serverPort) { - return kDNSServiceDiscoveryUnknownErr; - } - - clientPort = DNSServiceDiscoveryMachPort(ref); - - if (!clientPort) { - return kDNSServiceDiscoveryUnknownErr; - } - - result = DNSServiceRegistrationUpdateRecord_rpc(serverPort, clientPort, (natural_t)reference, (record_data_t)rdata, rdlen, ttl); - if (result != KERN_SUCCESS) { - printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result)); - return result; - } - - return kDNSServiceDiscoveryNoError; -} - - -DNSServiceRegistrationReplyErrorType DNSServiceRegistrationRemoveRecord(dns_service_discovery_ref ref, DNSRecordReference reference) -{ - mach_port_t serverPort = DNSServiceDiscoveryLookupServer(); - mach_port_t clientPort; - kern_return_t result = KERN_SUCCESS; - - if (!serverPort) { - return kDNSServiceDiscoveryUnknownErr; - } - - clientPort = DNSServiceDiscoveryMachPort(ref); - - if (!clientPort) { - return kDNSServiceDiscoveryUnknownErr; - } - - result = DNSServiceRegistrationRemoveRecord_rpc(serverPort, clientPort, (natural_t)reference); - - if (result != KERN_SUCCESS) { - printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result)); - return result; - } - - return kDNSServiceDiscoveryNoError; } void DNSServiceDiscovery_handleReply(void *replyMsg) { - mach_msg_header_t * msgSendBufPtr; - mach_msg_header_t * receivedMessage; - unsigned msgSendBufLength; - - msgSendBufLength = internal_DNSServiceDiscoveryReply_subsystem.maxsize; - msgSendBufPtr = (mach_msg_header_t *) malloc(msgSendBufLength); - - - receivedMessage = ( mach_msg_header_t * ) replyMsg; - - // Call DNSServiceDiscoveryReply_server to change mig-generated message into a - // genuine mach message. It will then cause the callback to get called. - DNSServiceDiscoveryReply_server ( receivedMessage, msgSendBufPtr ); - ( void ) mach_msg_send ( msgSendBufPtr ); - free(msgSendBufPtr); + (void) replyMsg; // Unused + printf("DNSServiceDiscovery_handleReply deprecated since 10.3 \n"); } mach_port_t DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDiscovery) { + printf("DNSServiceDiscoveryMachPort deprecated since 10.3 \n"); return dnsServiceDiscovery->port; } void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery) { - struct a_requests *request0, *request; - mach_port_t reply = dnsServiceDiscovery->port; - - if (dnsServiceDiscovery->port) { - pthread_mutex_lock(&a_requests_lock); - request0 = NULL; - request = a_requests; - while (request) { - if (request->client_port == reply) { - /* request info found, remove from list */ - if (request0) { - request0->next = request->next; - } else { - a_requests = request->next; - } - break; - } else { - /* not info for this request, skip to next */ - request0 = request; - request = request->next; - } - - } - pthread_mutex_unlock(&a_requests_lock); - - free(request); - - mach_port_destroy(mach_task_self(), dnsServiceDiscovery->port); - - free(dnsServiceDiscovery); - } - return; -} - -// reply functions, calls the users setup callbacks with function pointers - -kern_return_t internal_DNSServiceDomainEnumerationReply_rpc -( - mach_port_t reply, - int resultType, - DNSCString replyDomain, - int flags -) -{ - struct a_requests *request; - void *requestContext = NULL; - DNSServiceDomainEnumerationReply callback = NULL; - - pthread_mutex_lock(&a_requests_lock); - request = a_requests; - while (request) { - if (request->client_port == reply) { - break; - } - request = request->next; - } - - if (request != NULL) { - callback = (*request->callout.enumCallback); - requestContext = request->context; - } - pthread_mutex_unlock(&a_requests_lock); - - if (request != NULL) { - (callback)(resultType, replyDomain, flags, requestContext); - } - - return KERN_SUCCESS; - -} - -kern_return_t internal_DNSServiceBrowserReply_rpc -( - mach_port_t reply, - int resultType, - DNSCString replyName, - DNSCString replyType, - DNSCString replyDomain, - int flags -) -{ - struct a_requests *request; - void *requestContext = NULL; - DNSServiceBrowserReply callback = NULL; - - pthread_mutex_lock(&a_requests_lock); - request = a_requests; - while (request) { - if (request->client_port == reply) { - break; - } - request = request->next; - } - if (request != NULL) { - callback = (*request->callout.browserCallback); - requestContext = request->context; - } - - pthread_mutex_unlock(&a_requests_lock); - - if (request != NULL) { - (callback)(resultType, replyName, replyType, replyDomain, flags, requestContext); - } - - return KERN_SUCCESS; -} - - -kern_return_t internal_DNSServiceRegistrationReply_rpc -( - mach_port_t reply, - int resultType -) -{ - struct a_requests *request; - void *requestContext = NULL; - DNSServiceRegistrationReply callback = NULL; - - pthread_mutex_lock(&a_requests_lock); - request = a_requests; - while (request) { - if (request->client_port == reply) { - break; - } - request = request->next; - } - if (request != NULL) { - callback = (*request->callout.regCallback); - requestContext = request->context; - } - - pthread_mutex_unlock(&a_requests_lock); - if (request != NULL) { - (callback)(resultType, requestContext); - } - return KERN_SUCCESS; -} - - -kern_return_t internal_DNSServiceResolverReply_rpc -( - mach_port_t reply, - sockaddr_t interface, - sockaddr_t address, - DNSCString txtRecord, - int flags -) -{ - struct sockaddr *interface_storage = NULL; - struct sockaddr *address_storage = NULL; - struct a_requests *request; - void *requestContext = NULL; - DNSServiceResolverReply callback = NULL; - - if (interface) { - int len = ((struct sockaddr *)interface)->sa_len; - interface_storage = (struct sockaddr *)malloc(len); - memcpy(interface_storage, interface, len); - } - - if (address) { - int len = ((struct sockaddr *)address)->sa_len; - address_storage = (struct sockaddr *)malloc(len); - memcpy(address_storage, address, len); - } - - pthread_mutex_lock(&a_requests_lock); - request = a_requests; - while (request) { - if (request->client_port == reply) { - break; - } - request = request->next; - } - - if (request != NULL) { - callback = (*request->callout.resolveCallback); - requestContext = request->context; - } - pthread_mutex_unlock(&a_requests_lock); - - if (request != NULL) { - (callback)(interface_storage, address_storage, txtRecord, flags, requestContext); - } - - if (interface) { - free(interface_storage); - } - if (address) { - free(address_storage); - } - - return KERN_SUCCESS; + (void) dnsServiceDiscovery; // Unused + printf("DNSServiceDiscoveryDeallocate deprecated since 10.3 \n"); } diff --git a/mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.h b/mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.h index a743dd74..004d3259 100644 --- a/mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.h +++ b/mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.h @@ -17,31 +17,7 @@ /*! @header DNS Service Discovery (Deprecated Mach-based API) * - * @discussion This section describes the functions, callbacks, and data structures that - * make up the DNS Service Discovery API. - * - * The DNS Service Discovery API is part of Bonjour, Apple's implementation of - * zero-configuration networking (ZEROCONF). - * - * Bonjour allows you to register a network service, such as a - * printer or file server, so that it can be found by name or browsed - * for by service type and domain. Using Bonjour, applications can - * discover what services are available on the network, along with - * all necessary access information-such as name, IP address, and port - * number-for a given service. - * - * In effect, Bonjour combines the functions of a local DNS server - * and AppleTalk. Bonjour allows applications to provide user-friendly printer - * and server browsing, among other things, over standard IP networks. - * This behavior is a result of combining protocols such as multicast and DNS - * to add new functionality to the network (such as multicast DNS). - * - * Bonjour gives applications easy access to services over local IP - * networks without requiring the service or the application to support - * an AppleTalk or a Netbeui stack, and without requiring a DNS server - * for the local network. - * - * Note that this API was deprecated in Mac OS X 10.3, and replaced + * @discussion Note that this API was deprecated in Mac OS X 10.3, and replaced * by the portable cross-platform /usr/include/dns_sd.h API. */ @@ -71,29 +47,38 @@ enum { }; +typedef enum +{ + DNSServiceDomainEnumerationReplyAddDomain, + DNSServiceDomainEnumerationReplyAddDomainDefault, + DNSServiceDomainEnumerationReplyRemoveDomain, +} DNSServiceDomainEnumerationReplyResultType; + +typedef enum +{ + DNSServiceDiscoverReplyFlagsFinished, + DNSServiceDiscoverReplyFlagsMoreComing, +} DNSServiceDiscoveryReplyFlags; + +typedef void (*DNSServiceDomainEnumerationReply)( + DNSServiceDomainEnumerationReplyResultType resultType, // One of DNSServiceDomainEnumerationReplyResultType + const char *replyDomain, + DNSServiceDiscoveryReplyFlags flags, // DNS Service Discovery reply flags information + void *context +); + + /* possible error code values */ typedef enum { - kDNSServiceDiscoveryWaiting = 1, kDNSServiceDiscoveryNoError = 0, - // mDNS Error codes are in the range - // FFFE FF00 (-65792) to FFFE FFFF (-65537) - kDNSServiceDiscoveryUnknownErr = -65537, // 0xFFFE FFFF - kDNSServiceDiscoveryNoSuchNameErr = -65538, - kDNSServiceDiscoveryNoMemoryErr = -65539, - kDNSServiceDiscoveryBadParamErr = -65540, - kDNSServiceDiscoveryBadReferenceErr = -65541, - kDNSServiceDiscoveryBadStateErr = -65542, - kDNSServiceDiscoveryBadFlagsErr = -65543, - kDNSServiceDiscoveryUnsupportedErr = -65544, - kDNSServiceDiscoveryNotInitializedErr = -65545, - kDNSServiceDiscoveryNoCache = -65546, - kDNSServiceDiscoveryAlreadyRegistered = -65547, - kDNSServiceDiscoveryNameConflict = -65548, - kDNSServiceDiscoveryInvalid = -65549, - kDNSServiceDiscoveryMemFree = -65792 // 0xFFFE FF00 } DNSServiceRegistrationReplyErrorType; +typedef void (*DNSServiceRegistrationReply)( + DNSServiceRegistrationReplyErrorType errorCode, + void *context +); + typedef uint32_t DNSRecordReference; @@ -107,79 +92,6 @@ typedef uint32_t DNSRecordReference; */ void DNSServiceDiscovery_handleReply(void *replyMsg); -/* Service Registration */ - -typedef void (*DNSServiceRegistrationReply)( - DNSServiceRegistrationReplyErrorType errorCode, - void *context - ); - -/*! - @function DNSServiceRegistrationCreate - @discussion Register a named service with DNS Service Discovery - @param name The name of this service instance (e.g. "Steve's Printer") - @param regtype The service type (e.g. "_printer._tcp." -- see - RFC 2782 (DNS SRV) and ) - @param domain The domain in which to register the service (e.g. "apple.com.") - @param port The local port on which this service is being offered (in network byte order) - @param txtRecord Optional protocol-specific additional information - @param callBack The DNSServiceRegistrationReply function to be called - @param context A user specified context which will be passed to the callout function. - @result A dns_registration_t - */ -dns_service_discovery_ref DNSServiceRegistrationCreate -( - const char *name, - const char *regtype, - const char *domain, - uint16_t port, - const char *txtRecord, - DNSServiceRegistrationReply callBack, - void *context -) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3; - -/***************************************************************************/ -/* DNS Domain Enumeration */ - -typedef enum -{ - DNSServiceDomainEnumerationReplyAddDomain, // Domain found - DNSServiceDomainEnumerationReplyAddDomainDefault, // Domain found (and should be selected by default) - DNSServiceDomainEnumerationReplyRemoveDomain, // Domain has been removed from network -} DNSServiceDomainEnumerationReplyResultType; - -typedef enum -{ - DNSServiceDiscoverReplyFlagsFinished, - DNSServiceDiscoverReplyFlagsMoreComing, -} DNSServiceDiscoveryReplyFlags; - -typedef void (*DNSServiceDomainEnumerationReply)( - DNSServiceDomainEnumerationReplyResultType resultType, // One of DNSServiceDomainEnumerationReplyResultType - const char *replyDomain, - DNSServiceDiscoveryReplyFlags flags, // DNS Service Discovery reply flags information - void *context - ); - -/*! - @function DNSServiceDomainEnumerationCreate - @discussion Asynchronously create a DNS Domain Enumerator - @param registrationDomains A boolean indicating whether you are looking - for recommended registration domains - (e.g. equivalent to the AppleTalk zone list in the AppleTalk Control Panel) - or recommended browsing domains - (e.g. equivalent to the AppleTalk zone list in the Chooser). - @param callBack The function to be called when domains are found or removed - @param context A user specified context which will be passed to the callout function. - @result A dns_registration_t - */ -dns_service_discovery_ref DNSServiceDomainEnumerationCreate -( - int registrationDomains, - DNSServiceDomainEnumerationReply callBack, - void *context -) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3; - /***************************************************************************/ /* DNS Service Browser */ @@ -271,44 +183,6 @@ mach_port_t DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDisc */ void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3; -/***************************************************************************/ -/* Registration updating */ - - -/*! - @function DNSServiceRegistrationAddRecord - @discussion Request that the mDNS Responder add the DNS Record of a specific type - @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call - @param rrtype A standard DNS Resource Record Type, from http://www.iana.org/assignments/dns-parameters - @param rdlen Length of the data - @param rdata Opaque binary Resource Record data, up to 64 kB. - @param ttl time to live for the added record. - @result DNSRecordReference An opaque reference that can be passed to the update and remove record calls. If an error occurs, this value will be zero or negative - */ -DNSRecordReference DNSServiceRegistrationAddRecord(dns_service_discovery_ref dnsServiceDiscovery, uint16_t rrtype, uint16_t rdlen, const char *rdata, uint32_t ttl) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3; - -/*! - @function DNSServiceRegistrationUpdateRecord - @discussion Request that the mDNS Responder add the DNS Record of a specific type - @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call - @param dnsRecordReference A dnsRecordReference as returned from a DNSServiceRegistrationAddRecord call - @param rdlen Length of the data - @param rdata Opaque binary Resource Record data, up to 64 kB. - @param ttl time to live for the updated record. - @result DNSServiceRegistrationReplyErrorType If an error occurs, this value will be non zero - */ -DNSServiceRegistrationReplyErrorType DNSServiceRegistrationUpdateRecord(dns_service_discovery_ref ref, DNSRecordReference reference, uint16_t rdlen, const char *rdata, uint32_t ttl) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3; - -/*! - @function DNSServiceRegistrationRemoveRecord - @discussion Request that the mDNS Responder remove the DNS Record(s) of a specific type - @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call - @param dnsRecordReference A dnsRecordReference as returned from a DNSServiceRegistrationAddRecord call - @result DNSServiceRegistrationReplyErrorType If an error occurs, this value will be non zero - */ -DNSServiceRegistrationReplyErrorType DNSServiceRegistrationRemoveRecord(dns_service_discovery_ref ref, DNSRecordReference reference) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3; - - __END_DECLS #endif /* __DNS_SERVICE_DISCOVERY_H */ diff --git a/mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryDefines.h b/mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryDefines.h index 22687b90..01a28cd7 100644 --- a/mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryDefines.h +++ b/mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryDefines.h @@ -20,8 +20,6 @@ #include -#define DNS_SERVICE_DISCOVERY_SERVER "com.apple.mDNSResponder" - typedef char DNSCString[1024]; typedef char sockaddr_t[128]; diff --git a/mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryReply.defs b/mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryReply.defs deleted file mode 100644 index 993c9553..00000000 --- a/mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryReply.defs +++ /dev/null @@ -1,60 +0,0 @@ -/* -*- Mode: C; tab-width: 4 -*- - * - * Copyright (c) 2002-2003, 2006 Apple Computer, 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. - */ - -subsystem - DNSServiceDiscoveryReply 7250; - -ServerPrefix internal_; - -#include -#include - -import "DNSServiceDiscoveryDefines.h"; - -type DNSCString = c_string[*:1024]; -type sockaddr_t = array[128] of char; - -simpleroutine DNSServiceDomainEnumerationReply_rpc( - reply: mach_port_t; - in resultType: int; - in replyDomain: DNSCString; - in flags: int; - SendTime to: natural_t); - -simpleroutine DNSServiceBrowserReply_rpc( - reply: mach_port_t; - in resultType: int; - in replyName: DNSCString; - in replyType: DNSCString; - in replyDomain: DNSCString; - in flags: int; - SendTime to: natural_t); - - -simpleroutine DNSServiceRegistrationReply_rpc( - reply: mach_port_t; - in resultType: int; - SendTime to: natural_t); - - -simpleroutine DNSServiceResolverReply_rpc( - reply: mach_port_t; - in interface: sockaddr_t; - in address: sockaddr_t; - in txtRecord: DNSCString; - in flags: int; - SendTime to: natural_t); diff --git a/mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryRequest.defs b/mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryRequest.defs deleted file mode 100644 index d3fe292a..00000000 --- a/mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryRequest.defs +++ /dev/null @@ -1,80 +0,0 @@ -/* -*- Mode: C; tab-width: 4 -*- - * - * Copyright (c) 2002-2004, 2006 Apple Computer, 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. - */ - -subsystem - DNSServiceDiscoveryRequest 7200; - -ServerPrefix provide_; - -#include -#include - -import "DNSServiceDiscoveryDefines.h"; - -type DNSCString = c_string[*:1024]; -type record_data = ^ array [] of MACH_MSG_TYPE_BYTE - ctype: record_data_t; -type IPPort = struct[4] of char ctype:IPPort; - -simpleroutine DNSServiceBrowserCreate_rpc( - server: mach_port_t; - in client: mach_port_t; - in regtype: DNSCString; - in domain: DNSCString); - - -simpleroutine DNSServiceDomainEnumerationCreate_rpc( - server: mach_port_t; - in client: mach_port_t; - in registrationDomains: int); - -simpleroutine DNSServiceRegistrationCreate_rpc( - server: mach_port_t; - in client: mach_port_t; - in name: DNSCString; - in regtype: DNSCString; - in domain: DNSCString; - in port: IPPort; - in txtRecord: DNSCString); - - -simpleroutine DNSServiceResolverResolve_rpc( - server: mach_port_t; - in client: mach_port_t; - in name: DNSCString; - in regtype: DNSCString; - in domain: DNSCString); - -routine DNSServiceRegistrationAddRecord_rpc( - server: mach_port_t; - in client: mach_port_t; - in record_type: int; - in record_data: record_data; - in ttl: uint32_t; - out record_reference: natural_t); - -simpleroutine DNSServiceRegistrationUpdateRecord_rpc( - server: mach_port_t; - in client: mach_port_t; - in record_reference: natural_t; - in record_data: record_data; - in ttl: uint32_t); - -simpleroutine DNSServiceRegistrationRemoveRecord_rpc( - server: mach_port_t; - in client: mach_port_t; - in record_reference: natural_t); diff --git a/mDNSResponder/mDNSMacOSX/Metrics.h b/mDNSResponder/mDNSMacOSX/Metrics.h index a9dea79a..dbe6196a 100644 --- a/mDNSResponder/mDNSMacOSX/Metrics.h +++ b/mDNSResponder/mDNSMacOSX/Metrics.h @@ -25,9 +25,10 @@ extern "C" { #endif #if TARGET_OS_EMBEDDED -mStatus MetricsInit(void); -void MetricsUpdateUDNSStats(const domainname *inQueryName, mDNSBool inAnswered, mDNSu32 inSendCount, mDNSu32 inLatencyMs, mDNSBool inForCellular); -void LogMetrics(void); +mStatus MetricsInit(void); +void MetricsUpdateUDNSQueryStats(const domainname *inQueryName, mDNSu16 inType, const ResourceRecord *inRR, mDNSu32 inSendCount, mDNSu32 inLatencyMs, mDNSBool inForCell); +void MetricsUpdateUDNSResolveStats(const domainname *inQueryName, const ResourceRecord *inRR, mDNSBool inForCell); +void LogMetrics(void); #endif #ifdef __cplusplus diff --git a/mDNSResponder/mDNSMacOSX/Metrics.m b/mDNSResponder/mDNSMacOSX/Metrics.m index 56467dfc..8dae3f5f 100644 --- a/mDNSResponder/mDNSMacOSX/Metrics.m +++ b/mDNSResponder/mDNSMacOSX/Metrics.m @@ -17,12 +17,18 @@ #import "Metrics.h" -#if TARGET_OS_EMBEDDED +#if (TARGET_OS_EMBEDDED) #import #import #import +#import +#import +#import +#import +#import #import #import +#import #import "DNSCommon.h" #import "mDNSMacOSX.h" @@ -34,44 +40,116 @@ SOFT_LINK_FRAMEWORK(PrivateFrameworks, WirelessDiagnostics) -SOFT_LINK_CLASS(WirelessDiagnostics, AWDServerConnection) -#define AWDServerConnectionSoft getAWDServerConnectionClass() - -SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderDNSStatistics) -#define AWDMDNSResponderDNSStatisticsSoft getAWDMDNSResponderDNSStatisticsClass() - SOFT_LINK_CLASS(WirelessDiagnostics, AWDDNSDomainStats) -#define AWDDNSDomainStatsSoft getAWDDNSDomainStatsClass() +SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderDNSStatistics) +SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStats) +SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsDNSServer) +SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsDomain) +SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsHostname) +SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsResult) +SOFT_LINK_CLASS(WirelessDiagnostics, AWDServerConnection) +SOFT_LINK_CLASS(WirelessDiagnostics, AWDMetricManager) + +#define AWDDNSDomainStatsSoft getAWDDNSDomainStatsClass() +#define AWDMDNSResponderDNSStatisticsSoft getAWDMDNSResponderDNSStatisticsClass() +#define AWDMDNSResponderResolveStatsSoft getAWDMDNSResponderResolveStatsClass() +#define AWDMDNSResponderResolveStatsResultSoft getAWDMDNSResponderResolveStatsResultClass() +#define AWDMDNSResponderResolveStatsDNSServerSoft getAWDMDNSResponderResolveStatsDNSServerClass() +#define AWDMDNSResponderResolveStatsDomainSoft getAWDMDNSResponderResolveStatsDomainClass() +#define AWDMDNSResponderResolveStatsHostnameSoft getAWDMDNSResponderResolveStatsHostnameClass() +#define AWDServerConnectionSoft getAWDServerConnectionClass() +#define AWDMetricManagerSoft getAWDMetricManagerClass() //=========================================================================================================================== // Macros //=========================================================================================================================== -#define countof(X) (sizeof(X) / sizeof(X[0])) +#define countof(X) (sizeof(X) / sizeof(X[0])) +#define countof_field(TYPE, FIELD) countof(((TYPE *)0)->FIELD) +#define increment_saturate(VAR, MAX) do {if ((VAR) < (MAX)) {++(VAR);}} while (0) +#define ForgetMem(X) do {if(*(X)) {free(*(X)); *(X) = NULL;}} while(0) //=========================================================================================================================== // Constants //=========================================================================================================================== -#define kUDNSStatsMaxQuerySendCount 10 +#define kQueryStatsMaxQuerySendCount 10 +#define kQueryStatsSendCountBinCount (kQueryStatsMaxQuerySendCount + 1) +#define kQueryStatsLatencyBinCount 55 +#define kResolveStatsMaxObjCount 2000 + +//=========================================================================================================================== +// Data structures +//=========================================================================================================================== + +typedef struct +{ + const char * cstr; // Name of domain as a c-string. + const domainname * name; // Name of domain as length-prefixed labels. + int labelCount; // Number of labels in domain name. Used for domain name comparisons. + +} Domain; -// Important: Do not update this list without getting privacy approval. See . +// Important: Do not add to this list without getting privacy approval beforehand. See . +// If you get approval and do add a domain to this list, make sure it passes ValidateDNSStatsDomains() below. -static const char * const kUDNSStatsDomains[] = +static const Domain kQueryStatsDomains[] = { - ".", - "apple.com.", - "icloud.com.", - "me.com.", - "google.com.", - "facebook.com.", - "youtube.com.", - "baidu.com.", - "amazon.com.", - "yahoo.com.", - "wikipedia.org." + { ".", (domainname *)"", 0 }, + { "apple.com.", (domainname *)"\x5" "apple" "\x3" "com", 2 }, + { "icloud.com.", (domainname *)"\x6" "icloud" "\x3" "com", 2 }, + { "mzstatic.com.", (domainname *)"\x8" "mzstatic" "\x3" "com", 2 }, + { "me.com.", (domainname *)"\x2" "me" "\x3" "com", 2 }, + { "google.com.", (domainname *)"\x6" "google" "\x3" "com", 2 }, + { "youtube.com.", (domainname *)"\x7" "youtube" "\x3" "com", 2 }, + { "facebook.com.", (domainname *)"\x8" "facebook" "\x3" "com", 2 }, + { "baidu.com.", (domainname *)"\x5" "baidu" "\x3" "com", 2 }, + { "yahoo.com.", (domainname *)"\x5" "yahoo" "\x3" "com", 2 }, + { "qq.com.", (domainname *)"\x2" "qq" "\x3" "com", 2 }, }; +check_compile_time(countof(kQueryStatsDomains) == 11); + +// DNSHist contains the per domain per network type histogram data that goes in a DNSDomainStats protobuf message. See +// MDNSResponder.proto update. +// +// answeredQuerySendCountBins +// +// An array of 11 histogram bins. The value at index i, for 0 <= i <= 9, is the number of times that an answered DNS query +// was sent i times. The value at index 10 is the number of times that an answered query was sent 10+ times. +// +// unansweredQuerySendCountBins +// +// An array of 11 histogram bins. The value at index i, for 0 <= i <= 9, is the number of times that an unanswered DNS query +// was sent i times. The value at index 10 is the number of times that an unanswered query was sent 10+ times. +// +// responseLatencyBins +// +// An array of 55 histogram bins. Each array value is the number of DNS queries that were answered in a paricular time +// interval. The 55 consecutive non-overlapping time intervals have the following non-inclusive upper bounds (all values are +// in milliseconds): 1, 2, 3, 4, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, +// 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000, 1500, 2000, 2500, 3000, 3500, 4000, +// 4500, 5000, 6000, 7000, 8000, 9000, 10000, ∞. + +typedef struct +{ + uint16_t unansweredQuerySendCountBins[kQueryStatsSendCountBinCount]; + uint16_t unansweredQueryDurationBins[kQueryStatsLatencyBinCount]; + uint16_t answeredQuerySendCountBins[kQueryStatsSendCountBinCount]; + uint16_t responseLatencyBins[kQueryStatsLatencyBinCount]; + uint16_t negAnsweredQuerySendCountBins[kQueryStatsSendCountBinCount]; + uint16_t negResponseLatencyBins[kQueryStatsLatencyBinCount]; + +} DNSHist; + +check_compile_time(sizeof(DNSHist) <= 512); +check_compile_time(countof_field(DNSHist, unansweredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1)); +check_compile_time(countof_field(DNSHist, answeredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1)); +check_compile_time(countof_field(DNSHist, negAnsweredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1)); + +// Important: Do not modify kResponseLatencyMsLimits because the code used to generate AWD reports expects the response +// latency histogram bins to observe these time interval upper bounds. + static const mDNSu32 kResponseLatencyMsLimits[] = { 1, 2, 3, 4, 5, @@ -83,51 +161,200 @@ static const mDNSu32 kResponseLatencyMsLimits[] = 10000 }; -//=========================================================================================================================== -// Data structures -//=========================================================================================================================== +check_compile_time(countof(kResponseLatencyMsLimits) == 54); +check_compile_time(countof_field(DNSHist, unansweredQueryDurationBins) == (countof(kResponseLatencyMsLimits) + 1)); +check_compile_time(countof_field(DNSHist, responseLatencyBins) == (countof(kResponseLatencyMsLimits) + 1)); +check_compile_time(countof_field(DNSHist, negResponseLatencyBins) == (countof(kResponseLatencyMsLimits) + 1)); typedef struct { - uint32_t answeredQuerySendCountBins[kUDNSStatsMaxQuerySendCount + 1]; - uint32_t unansweredQuerySendCountBins[kUDNSStatsMaxQuerySendCount + 1]; - uint32_t responseLatencyBins[countof(kResponseLatencyMsLimits) + 1]; + DNSHist * histAny; // Histogram data for queries of any resource record type. + DNSHist * histA; // Histogram data for queries for A resource records. + DNSHist * histAAAA; // Histogram data for queries for AAAA resource records. -} DNSStats; +} DNSHistSet; -typedef struct DNSDomainStats * DNSDomainStatsRef; +typedef struct DNSDomainStats DNSDomainStats; struct DNSDomainStats { - DNSDomainStatsRef next; - domainname domain; - int domainLabelCount; - char * domainStr; - DNSStats stats; - DNSStats statsCellular; + DNSDomainStats * next; // Pointer to next domain stats in list. + const Domain * domain; // Domain for which these stats are collected. + DNSHistSet * nonCellular; // Query stats for queries sent over non-cellular interfaces. + DNSHistSet * cellular; // Query stats for queries sent over cellular interfaces. +}; + +check_compile_time(sizeof(struct DNSDomainStats) <= 32); + +static const Domain kResolveStatsDomains[] = +{ + { "apple.com.", (domainname *)"\x5" "apple" "\x3" "com", 2 }, + { "icloud.com.", (domainname *)"\x6" "icloud" "\x3" "com", 2 }, + { "mzstatic.com.", (domainname *)"\x8" "mzstatic" "\x3" "com", 2 }, + { "me.com.", (domainname *)"\x2" "me" "\x3" "com", 2 }, +}; + +check_compile_time(countof(kResolveStatsDomains) == 4); + +typedef struct ResolveStatsDomain ResolveStatsDomain; +typedef struct ResolveStatsHostname ResolveStatsHostname; +typedef struct ResolveStatsDNSServer ResolveStatsDNSServer; +typedef struct ResolveStatsIPv4AddrSet ResolveStatsIPv4AddrSet; +typedef struct ResolveStatsIPv6Addr ResolveStatsIPv6Addr; +typedef struct ResolveStatsNegAAAASet ResolveStatsNegAAAASet; + +struct ResolveStatsDomain +{ + ResolveStatsDomain * next; // Next domain object in list. + ResolveStatsHostname * hostnameList; // List of hostname objects in this domain. + const Domain * domainInfo; // Pointer to domain info. +}; + +struct ResolveStatsHostname +{ + ResolveStatsHostname * next; // Next hostname object in list. + ResolveStatsIPv4AddrSet * addrV4List; // List of IPv4 addresses to which this hostname resolved. + ResolveStatsIPv6Addr * addrV6List; // List of IPv6 addresses to which this hostname resolved. + ResolveStatsNegAAAASet * negV6List; // List of negative AAAA response objects. + uint8_t name[1]; // Variable length storage for hostname as length-prefixed labels. +}; + +check_compile_time(sizeof(ResolveStatsHostname) <= 64); + +struct ResolveStatsDNSServer +{ + ResolveStatsDNSServer * next; // Next DNS server object in list. + uint8_t id; // 8-bit ID assigned to this DNS server used by IP address objects. + mDNSBool isForCell; // True if this DNS server belongs to a cellular interface. + mDNSBool isAddrV6; // True if this DNS server has an IPv6 address instead of IPv4. + uint8_t addrBytes[1]; // Variable length storage for DNS server's IP address. +}; + +check_compile_time(sizeof(ResolveStatsDNSServer) <= 32); + +typedef struct +{ + uint16_t count; // Number of times this IPv4 address was provided as a resolution result. + uint8_t serverID; // 8-bit ID of the DNS server from which this IPv4 address came. + uint8_t isNegative; + uint8_t addrBytes[4]; // IPv4 address bytes. + +} IPv4AddrCounter; + +check_compile_time(sizeof(IPv4AddrCounter) <= 8); + +struct ResolveStatsIPv4AddrSet +{ + ResolveStatsIPv4AddrSet * next; // Next set of IPv4 address counters in list. + IPv4AddrCounter counters[3]; // Array of IPv4 address counters. +}; + +check_compile_time(sizeof(ResolveStatsIPv4AddrSet) <= 32); + +struct ResolveStatsIPv6Addr +{ + ResolveStatsIPv6Addr * next; // Next IPv6 address object in list. + uint16_t count; // Number of times this IPv6 address was provided as a resolution result. + uint8_t serverID; // 8-bit ID of the DNS server from which this IPv6 address came. + uint8_t addrBytes[16]; // IPv6 address bytes. +}; + +check_compile_time(sizeof(ResolveStatsIPv6Addr) <= 32); + +typedef struct +{ + uint16_t count; // Number of times that a negative response was returned by a DNS server. + uint8_t serverID; // 8-bit ID of the DNS server that sent the negative responses. + +} NegAAAACounter; + +check_compile_time(sizeof(NegAAAACounter) <= 4); + +struct ResolveStatsNegAAAASet +{ + ResolveStatsNegAAAASet * next; // Next set of negative AAAA response counters in list. + NegAAAACounter counters[6]; // Array of negative AAAA response counters. }; +check_compile_time(sizeof(ResolveStatsNegAAAASet) <= 32); + +typedef enum +{ + kResponseType_IPv4Addr = 1, + kResponseType_IPv6Addr = 2, + kResponseType_NegA = 3, + kResponseType_NegAAAA = 4 + +} ResponseType; + +typedef struct +{ + ResponseType type; + const uint8_t * data; + +} Response; + //=========================================================================================================================== // Globals //=========================================================================================================================== extern mDNS mDNSStorage; -static DNSDomainStatsRef gDomainStatsList = NULL; -static AWDServerConnection * gAWDServerConnection = nil; +static DNSDomainStats * gDomainStatsList = NULL; +static ResolveStatsDomain * gResolveStatsList = NULL; +static ResolveStatsDNSServer * gResolveStatsServerList = NULL; +static unsigned int gResolveStatsNextServerID = 0; +static int gResolveStatsObjCount = 0; +static AWDServerConnection * gAWDServerConnection = nil; //=========================================================================================================================== // Local Prototypes //=========================================================================================================================== -mDNSlocal mStatus DNSDomainStatsCreate(const char *inDomain, DNSDomainStatsRef *outStats); -mDNSlocal void DNSDomainStatsFree(DNSDomainStatsRef inStats); -mDNSlocal void DNSDomainStatsFreeList(DNSDomainStatsRef inList); - -mDNSlocal mStatus CreateDomainStatsList(DNSDomainStatsRef *outList); -mDNSlocal void UpdateDNSStats(DNSStats *inStats, mDNSBool inAnswered, mDNSu32 inQuerySendCount, mDNSu32 inLatencyMs); -mDNSlocal mStatus SubmitAWDMetric(void); -mDNSlocal mStatus CreateAWDDNSDomainStats(DNSStats *inStats, const char *inDomain, mDNSBool inIsForCellular, AWDDNSDomainStats **outAWDStats); -mDNSlocal void LogDNSStats(const DNSStats *inStats); +mDNSlocal mStatus DNSDomainStatsCreate(const Domain *inDomain, DNSDomainStats **outStats); +mDNSlocal void DNSDomainStatsFree(DNSDomainStats *inStats); +mDNSlocal void DNSDomainStatsFreeList(DNSDomainStats *inList); +mDNSlocal mStatus DNSDomainStatsUpdate(DNSDomainStats *inStats, uint16_t inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, mDNSu32 inLatencyMs, mDNSBool inForCell); + +mDNSlocal mStatus ResolveStatsDomainCreate(const Domain *inDomain, ResolveStatsDomain **outDomain); +mDNSlocal void ResolveStatsDomainFree(ResolveStatsDomain *inDomain); +mDNSlocal mStatus ResolveStatsDomainUpdate(ResolveStatsDomain *inDomain, const domainname *inHostname, const Response *inResp, const mDNSAddr *inDNSAddr, mDNSBool inForCell); +mDNSlocal mStatus ResolveStatsDomainCreateAWDVersion(const ResolveStatsDomain *inDomain, AWDMDNSResponderResolveStatsDomain **outDomain); + +mDNSlocal mStatus ResolveStatsHostnameCreate(const domainname *inName, ResolveStatsHostname **outHostname); +mDNSlocal void ResolveStatsHostnameFree(ResolveStatsHostname *inHostname); +mDNSlocal mStatus ResolveStatsHostnameUpdate(ResolveStatsHostname *inHostname, const Response *inResp, uint8_t inServerID); +mDNSlocal mStatus ResolveStatsHostnameCreateAWDVersion(const ResolveStatsHostname *inHostname, AWDMDNSResponderResolveStatsHostname **outHostname); + +mDNSlocal mStatus ResolveStatsDNSServerCreate(const mDNSAddr *inAddr, mDNSBool inForCell, ResolveStatsDNSServer **outServer); +mDNSlocal void ResolveStatsDNSServerFree(ResolveStatsDNSServer *inServer); +mDNSlocal mStatus ResolveStatsDNSServerCreateAWDVersion(const ResolveStatsDNSServer *inServer, AWDMDNSResponderResolveStatsDNSServer **outServer); + +mDNSlocal mStatus ResolveStatsIPv4AddrSetCreate(ResolveStatsIPv4AddrSet **outSet); +mDNSlocal void ResolveStatsIPv4AddrSetFree(ResolveStatsIPv4AddrSet *inSet); + +mDNSlocal mStatus ResolveStatsIPv6AddressCreate(uint8_t inServerID, const uint8_t inAddrBytes[16], ResolveStatsIPv6Addr **outAddr); +mDNSlocal void ResolveStatsIPv6AddressFree(ResolveStatsIPv6Addr *inAddr); + +mDNSlocal mStatus ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet); +mDNSlocal void ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet); +mDNSlocal mStatus ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID); + +mDNSlocal mStatus CreateDomainStatsList(DNSDomainStats **outList); +mDNSlocal mStatus CreateResolveStatsList(ResolveStatsDomain **outList); +mDNSlocal void FreeResolveStatsList(ResolveStatsDomain *inList); +mDNSlocal void FreeResolveStatsServerList(ResolveStatsDNSServer *inList); +mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID); +mDNSlocal mStatus SubmitAWDMetricQueryStats(void); +mDNSlocal mStatus SubmitAWDMetricResolveStats(void); +mDNSlocal mStatus CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain, mDNSBool inForCell, AWDDNSDomainStats_RecordType inType, AWDDNSDomainStats **outStats); +mDNSlocal mStatus AddAWDDNSDomainStats(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell); +mDNSlocal void LogDNSHistSet(const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell); +mDNSlocal void LogDNSHist(const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType); +mDNSlocal void LogDNSHistSendCounts(const uint16_t inSendCountBins[kQueryStatsSendCountBinCount]); +mDNSlocal void LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLatencyBinCount]); +#if (METRICS_VALIDATE_DNS_STATS_DOMAINS) +mDNSlocal void ValidateDNSStatsDomains(void); +#endif //=========================================================================================================================== // MetricsInit @@ -137,28 +364,48 @@ mStatus MetricsInit(void) { mStatus err; +#if (METRICS_VALIDATE_DNS_STATS_DOMAINS) + ValidateDNSStatsDomains(); +#endif + err = CreateDomainStatsList(&gDomainStatsList); require_noerr_quiet(err, exit); + err = CreateResolveStatsList(&gResolveStatsList); + require_noerr_quiet(err, exit); + @autoreleasepool { gAWDServerConnection = [[AWDServerConnectionSoft alloc] - initWithComponentId: AWDComponentId_MDNSResponder - andBlockOnConfiguration: NO]; + initWithComponentId: AWDComponentId_MDNSResponder + andBlockOnConfiguration: NO]; if (gAWDServerConnection) { [gAWDServerConnection - registerQueriableMetricCallback: ^(UInt32 metricId) + registerQueriableMetricCallback: ^(UInt32 inMetricID) { - mStatus localErr; - - (void) metricId; - - localErr = SubmitAWDMetric(); - if (localErr) LogMsg("SubmitAWDMetric failed with error %d", localErr); + SubmitAWDMetric(inMetricID); } forIdentifier: (UInt32)AWDMetricId_MDNSResponder_DNSStatistics]; + + [gAWDServerConnection + registerQueriableMetricCallback: ^(UInt32 inMetricID) + { + SubmitAWDMetric(inMetricID); + } + forIdentifier: (UInt32)AWDMetricId_MDNSResponder_ResolveStats]; + + [gAWDServerConnection + registerQueriableMetricCallback: ^(UInt32 inMetricID) + { + SubmitAWDMetric(inMetricID); + } + forIdentifier: (UInt32)AWDMetricId_MDNSResponder_ServicesStats]; + } + else + { + LogMsg("MetricsInit: failed to create AWD server connection."); } } exit: @@ -166,194 +413,239 @@ exit: } //=========================================================================================================================== -// MetricsUpdateUDNSStats +// MetricsUpdateUDNSQueryStats //=========================================================================================================================== -mDNSexport void MetricsUpdateUDNSStats(const domainname *inQueryName, mDNSBool inAnswered, mDNSu32 inSendCount, mDNSu32 inLatencyMs, mDNSBool inForCellular) +mDNSexport void MetricsUpdateUDNSQueryStats(const domainname *inQueryName, mDNSu16 inType, const ResourceRecord *inRR, mDNSu32 inSendCount, mDNSu32 inLatencyMs, mDNSBool inForCell) { - DNSStats * stats; - DNSDomainStatsRef domainStats; + DNSDomainStats * stats; int queryLabelCount; + const domainname * queryParentDomain; mDNSBool isQueryInDomain; + int skipCount; + int skipCountLast = -1; queryLabelCount = CountLabels(inQueryName); - for (domainStats = gDomainStatsList; domainStats; domainStats = domainStats->next) + for (stats = gDomainStatsList; stats; stats = stats->next) { isQueryInDomain = mDNSfalse; - if (strcmp(domainStats->domainStr, ".") == 0) + if (strcmp(stats->domain->cstr, ".") == 0) { // All queries are in the root domain. isQueryInDomain = mDNStrue; } else { - int skipCount; - const domainname * queryParentDomain; - - skipCount = queryLabelCount - domainStats->domainLabelCount; + skipCount = queryLabelCount - stats->domain->labelCount; if (skipCount >= 0) { - queryParentDomain = SkipLeadingLabels(inQueryName, skipCount); - isQueryInDomain = SameDomainName(queryParentDomain, &domainStats->domain); + if (skipCount != skipCountLast) + { + queryParentDomain = SkipLeadingLabels(inQueryName, skipCount); + skipCountLast = skipCount; + } + isQueryInDomain = SameDomainName(queryParentDomain, stats->domain->name); } } if (isQueryInDomain) { - stats = inForCellular ? &domainStats->statsCellular : &domainStats->stats; - UpdateDNSStats(stats, inAnswered, inSendCount, inLatencyMs); + DNSDomainStatsUpdate(stats, inType, inRR, inSendCount, inLatencyMs, inForCell); } } + } //=========================================================================================================================== -// CreateDomainStatsList +// MetricsUpdateUDNSResolveStats //=========================================================================================================================== -mDNSlocal mStatus CreateDomainStatsList(DNSDomainStatsRef *outList) +mDNSexport void MetricsUpdateUDNSResolveStats(const domainname *inQueryName, const ResourceRecord *inRR, mDNSBool inForCell) { - mStatus err; - size_t i; - DNSDomainStatsRef domainStats; - DNSDomainStatsRef * p; - DNSDomainStatsRef list = NULL; + ResolveStatsDomain * domain; + domainname hostname; + size_t hostnameLen; + mDNSBool isQueryInDomain; + int skipCount; + int skipCountLast = -1; + int queryLabelCount; + const domainname * queryParentDomain; + Response response; + + require_quiet((inRR->rrtype == kDNSType_A) || (inRR->rrtype == kDNSType_AAAA), exit); + require_quiet(inRR->rDNSServer, exit); - p = &list; - for (i = 0; i < countof(kUDNSStatsDomains); ++i) + queryLabelCount = CountLabels(inQueryName); + + for (domain = gResolveStatsList; domain; domain = domain->next) { - err = DNSDomainStatsCreate(kUDNSStatsDomains[i], &domainStats); - require_noerr_quiet(err, exit); + isQueryInDomain = mDNSfalse; + skipCount = queryLabelCount - domain->domainInfo->labelCount; + if (skipCount >= 0) + { + if (skipCount != skipCountLast) + { + queryParentDomain = SkipLeadingLabels(inQueryName, skipCount); + skipCountLast = skipCount; + } + isQueryInDomain = SameDomainName(queryParentDomain, domain->domainInfo->name); + } + if (!isQueryInDomain) continue; - *p = domainStats; - p = &domainStats->next; - } + hostnameLen = (size_t)(queryParentDomain->c - inQueryName->c); + if (hostnameLen >= sizeof(hostname.c)) continue; - *outList = list; - list = NULL; + memcpy(hostname.c, inQueryName->c, hostnameLen); + hostname.c[hostnameLen] = 0; + + if (inRR->RecordType == kDNSRecordTypePacketNegative) + { + response.type = (inRR->rrtype == kDNSType_A) ? kResponseType_NegA : kResponseType_NegAAAA; + response.data = NULL; + } + else + { + response.type = (inRR->rrtype == kDNSType_A) ? kResponseType_IPv4Addr : kResponseType_IPv6Addr; + response.data = (inRR->rrtype == kDNSType_A) ? inRR->rdata->u.ipv4.b : inRR->rdata->u.ipv6.b; + } + ResolveStatsDomainUpdate(domain, &hostname, &response, &inRR->rDNSServer->addr, inForCell); + } exit: - DNSDomainStatsFreeList(list); - return (err); + return; } //=========================================================================================================================== -// UpdateDNSStats +// LogMetrics //=========================================================================================================================== -mDNSlocal void UpdateDNSStats(DNSStats *inStats, mDNSBool inAnswered, mDNSu32 inQuerySendCount, mDNSu32 inLatencyMs) +mDNSexport void LogMetrics(void) { - size_t i; - - if (inAnswered) + DNSDomainStats * stats; + const ResolveStatsDomain * domain; + const ResolveStatsHostname * hostname; + const ResolveStatsDNSServer * server; + const ResolveStatsIPv4AddrSet * addrV4; + const ResolveStatsIPv6Addr * addrV6; + const ResolveStatsNegAAAASet * negV6; + int hostnameCount; + int i; + unsigned int serverID; + int serverObjCount = 0; + int hostnameObjCount = 0; + int addrObjCount = 0; + + LogMsgNoIdent("---- DNS query stats by domain -----"); + + for (stats = gDomainStatsList; stats; stats = stats->next) { - i = (inQuerySendCount <= kUDNSStatsMaxQuerySendCount) ? inQuerySendCount : kUDNSStatsMaxQuerySendCount; - inStats->answeredQuerySendCountBins[i]++; - - if (inQuerySendCount > 0) + if (!stats->nonCellular && !stats->cellular) { - for (i = 0; (i < countof(kResponseLatencyMsLimits)) && (inLatencyMs >= kResponseLatencyMsLimits[i]); ++i) {} - inStats->responseLatencyBins[i]++; + LogMsgNoIdent("No data for %s", stats->domain->cstr); + continue; } + if (stats->nonCellular) LogDNSHistSet(stats->nonCellular, stats->domain->cstr, mDNSfalse); + if (stats->cellular) LogDNSHistSet(stats->cellular, stats->domain->cstr, mDNStrue); } - else if (inQuerySendCount > 0) - { - i = (inQuerySendCount <= kUDNSStatsMaxQuerySendCount) ? inQuerySendCount : kUDNSStatsMaxQuerySendCount; - inStats->unansweredQuerySendCountBins[i]++; - } -} - -//=========================================================================================================================== -// SubmitAWDMetric -//=========================================================================================================================== - -mDNSlocal mStatus SubmitAWDMetric(void) -{ - mStatus err; - BOOL success; - DNSDomainStatsRef domainStats; - DNSDomainStatsRef newDomainStatsList; - DNSDomainStatsRef domainStatsList = NULL; - AWDMetricContainer * container = nil; - AWDMDNSResponderDNSStatistics * metric = nil; - AWDDNSDomainStats * awdDomainStats = nil; - - err = CreateDomainStatsList(&newDomainStatsList); - require_noerr_quiet(err, exit); - - domainStatsList = gDomainStatsList; - - KQueueLock(&mDNSStorage); - gDomainStatsList = newDomainStatsList; - KQueueUnlock(&mDNSStorage, "SubmitAWDMetric"); - - container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_DNSStatistics]; - require_action_quiet(container, exit, err = mStatus_UnknownErr); - metric = [[AWDMDNSResponderDNSStatisticsSoft alloc] init]; - require_action_quiet(metric, exit, err = mStatus_UnknownErr); + LogMsgNoIdent("---- DNS resolve stats by domain -----"); - for (domainStats = domainStatsList; domainStats; domainStats = domainStats->next) + LogMsgNoIdent("Servers:"); + for (server = gResolveStatsServerList; server; server = server->next) { - err = CreateAWDDNSDomainStats(&domainStats->stats, domainStats->domainStr, mDNSfalse, &awdDomainStats); - require_noerr_quiet(err, exit); + serverObjCount++; + LogMsgNoIdent(server->isAddrV6 ? "%2u: %s %.16a" : "%2u: %s %.4a", + server->id, server->isForCell ? " C" : "NC", server->addrBytes); + } - [metric addStats:awdDomainStats]; - [awdDomainStats release]; - awdDomainStats = nil; + for (domain = gResolveStatsList; domain; domain = domain->next) + { + hostnameCount = 0; + for (hostname = domain->hostnameList; hostname; hostname = hostname->next) { hostnameCount++; } + hostnameObjCount += hostnameCount; - err = CreateAWDDNSDomainStats(&domainStats->statsCellular, domainStats->domainStr, mDNStrue, &awdDomainStats); - require_noerr_quiet(err, exit); + LogMsgNoIdent("%##s (%d hostname%s)", domain->domainInfo->name, hostnameCount, (hostnameCount == 1) ? "" : "s"); - [metric addStats:awdDomainStats]; - [awdDomainStats release]; - awdDomainStats = nil; + for (hostname = domain->hostnameList; hostname; hostname = hostname->next) + { + LogMsgNoIdent(" %##s", hostname->name); + for (serverID = 0; serverID < gResolveStatsNextServerID; ++serverID) + { + for (addrV4 = hostname->addrV4List; addrV4; addrV4 = addrV4->next) + { + if (serverID == 0) addrObjCount++; + for (i = 0; i < (int)countof(addrV4->counters); ++i) + { + const IPv4AddrCounter * counter; + + counter = &addrV4->counters[i]; + if (counter->count == 0) break; + if (counter->serverID == serverID) + { + if (counter->isNegative) + { + LogMsgNoIdent("%10u: %3u negative A", counter->serverID, counter->count); + } + else + { + LogMsgNoIdent("%10u: %3u %.4a", counter->serverID, counter->count, counter->addrBytes); + } + } + } + } + for (addrV6 = hostname->addrV6List; addrV6; addrV6 = addrV6->next) + { + if (serverID == 0) addrObjCount++; + if (addrV6->serverID == serverID) + { + LogMsgNoIdent("%10u: %3u %.16a", addrV6->serverID, addrV6->count, addrV6->addrBytes); + } + } + for (negV6 = hostname->negV6List; negV6; negV6 = negV6->next) + { + if (serverID == 0) addrObjCount++; + for (i = 0; i < (int)countof(negV6->counters); ++i) + { + const NegAAAACounter * counter; + + counter = &negV6->counters[i]; + if (counter->count == 0) break; + if (counter->serverID == serverID) + { + LogMsgNoIdent("%10u: %3u negative AAAA", counter->serverID, counter->count); + } + } + } + } + } } - - container.metric = metric; - success = [gAWDServerConnection submitMetric:container]; - LogMsg("SubmitAWDMetric: metric submission %s.", success ? "succeeded" : "failed" ); - err = success ? mStatus_NoError : mStatus_UnknownErr; - -exit: - [awdDomainStats release]; - [metric release]; - [container release]; - DNSDomainStatsFreeList(domainStatsList); - return (err); + LogMsgNoIdent("Total object count: %3d (server %d hostname %d address %d)", + serverObjCount + hostnameObjCount + addrObjCount, serverObjCount, hostnameObjCount, addrObjCount); + + LogMsgNoIdent("---- Num of Services Registered -----"); + LogMsgNoIdent("Current_number_of_services_registered :[%d], Max_number_of_services_registered :[%d]", + curr_num_regservices, max_num_regservices); } //=========================================================================================================================== // DNSDomainStatsCreate //=========================================================================================================================== -mDNSlocal mStatus DNSDomainStatsCreate(const char *inDomain, DNSDomainStatsRef *outStats) +mDNSlocal mStatus DNSDomainStatsCreate(const Domain *inDomain, DNSDomainStats **outStats) { mStatus err; - DNSDomainStatsRef obj; - mDNSu8 * ptr; - - obj = (DNSDomainStatsRef) calloc(1, sizeof(*obj)); - require_action_quiet(obj, exit, err = mStatus_NoMemoryErr); + DNSDomainStats * obj; - obj->domainStr = strdup(inDomain); + obj = (DNSDomainStats *)calloc(1, sizeof(*obj)); require_action_quiet(obj, exit, err = mStatus_NoMemoryErr); - // Initialize domainname for non-root domains. - - if (strcmp(obj->domainStr, ".") != 0) - { - ptr = MakeDomainNameFromDNSNameString(&obj->domain, obj->domainStr); - require_action_quiet(ptr, exit, err = mStatus_Invalid); - obj->domainLabelCount = CountLabels(&obj->domain); - } + obj->domain = inDomain; *outStats = obj; - obj = NULL; err = mStatus_NoError; exit: - if (obj) DNSDomainStatsFree(obj); return (err); } @@ -361,9 +653,24 @@ exit: // DNSDomainStatsFree //=========================================================================================================================== -mDNSlocal void DNSDomainStatsFree(DNSDomainStatsRef inStats) +mDNSlocal void DNSDomainStatsFree(DNSDomainStats *inStats) { - if (inStats->domainStr) free(inStats->domainStr); + if (inStats->nonCellular) + { + ForgetMem(&inStats->nonCellular->histAny); + ForgetMem(&inStats->nonCellular->histA); + ForgetMem(&inStats->nonCellular->histAAAA); + free(inStats->nonCellular); + inStats->nonCellular = NULL; + } + if (inStats->cellular) + { + ForgetMem(&inStats->cellular->histAny); + ForgetMem(&inStats->cellular->histA); + ForgetMem(&inStats->cellular->histAAAA); + free(inStats->cellular); + inStats->cellular = NULL; + } free(inStats); } @@ -371,9 +678,9 @@ mDNSlocal void DNSDomainStatsFree(DNSDomainStatsRef inStats) // DNSDomainStatsFreeList //=========================================================================================================================== -mDNSlocal void DNSDomainStatsFreeList(DNSDomainStatsRef inList) +mDNSlocal void DNSDomainStatsFreeList(DNSDomainStats *inList) { - DNSDomainStatsRef stats; + DNSDomainStats * stats; while ((stats = inList) != NULL) { @@ -383,149 +690,1321 @@ mDNSlocal void DNSDomainStatsFreeList(DNSDomainStatsRef inList) } //=========================================================================================================================== -// CreateAWDDNSDomainStats +// DNSDomainStatsUpdate //=========================================================================================================================== -mDNSlocal mStatus CreateAWDDNSDomainStats(DNSStats *inStats, const char *inDomain, mDNSBool inIsCellType, AWDDNSDomainStats **outAWDStats) +mDNSlocal mStatus DNSDomainStatsUpdate(DNSDomainStats *inStats, uint16_t inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, mDNSu32 inLatencyMs, mDNSBool inForCell) { - mStatus err; - AWDDNSDomainStats * awdStats = nil; - NSString * domain = nil; - - awdStats = [[AWDDNSDomainStatsSoft alloc] init]; - require_action_quiet(awdStats, exit, err = mStatus_UnknownErr); - - domain = [[NSString alloc] initWithUTF8String:inDomain]; - require_action_quiet(domain, exit, err = mStatus_UnknownErr); - - awdStats.domain = domain; - awdStats.networkType = inIsCellType ? AWDDNSDomainStats_NetworkType_Cellular : AWDDNSDomainStats_NetworkType_NonCellular; - - [awdStats - setAnsweredQuerySendCounts: inStats->answeredQuerySendCountBins - count: (NSUInteger)countof(inStats->answeredQuerySendCountBins)]; - - [awdStats - setUnansweredQuerySendCounts: inStats->unansweredQuerySendCountBins - count: (NSUInteger)countof(inStats->unansweredQuerySendCountBins)]; + mStatus err; + DNSHistSet ** p; + DNSHistSet * set; + DNSHist * histAny; + DNSHist * hist; + int i; - [awdStats - setResponseLatencyMs: inStats->responseLatencyBins - count: (NSUInteger)countof(inStats->responseLatencyBins)]; + require_action_quiet(inRR || (inQuerySendCount > 0), exit, err = mStatus_NoError); - *outAWDStats = awdStats; - awdStats = nil; - err = mStatus_NoError; - -exit: - [domain release]; - [awdStats release]; - return (err); -} - -//=========================================================================================================================== -// LogDNSStats -//=========================================================================================================================== - -#define Percent(N, D) ((N) * 100) / (D), (((N) * 10000) / (D)) % 100 -#define PercentFmt "%3u.%02u" -#define LogStat(LABEL, COUNT, ACCUMULATOR, TOTAL) \ - LogMsgNoIdent("%s %5u " PercentFmt " " PercentFmt, (LABEL), (COUNT), Percent(COUNT, TOTAL), Percent(ACCUMULATOR, TOTAL)) - -mDNSlocal void LogDNSStats(const DNSStats *inStats) -{ - uint32_t total; - uint32_t totalUnanswered; - size_t i; - char label[16]; - - totalUnanswered = 0; - for (i = 0; i < countof(inStats->unansweredQuerySendCountBins); ++i) + p = inForCell ? &inStats->cellular : &inStats->nonCellular; + if ((set = *p) == NULL) { - totalUnanswered += inStats->unansweredQuerySendCountBins[i]; + set = (DNSHistSet *)calloc(1, sizeof(*set)); + require_action_quiet(set, exit, err = mStatus_NoMemoryErr); + *p = set; } - - total = 0; - for (i = 0; i <= countof(inStats->answeredQuerySendCountBins); ++i) + if ((histAny = set->histAny) == NULL) { - total += inStats->answeredQuerySendCountBins[i]; + histAny = (DNSHist *)calloc(1, sizeof(*histAny)); + require_action_quiet(histAny, exit, err = mStatus_NoMemoryErr); + set->histAny = histAny; } - - LogMsgNoIdent("Answered questions %5u", total); - LogMsgNoIdent("Unanswered questions %5u", totalUnanswered); - LogMsgNoIdent("+++ Number of queries sent +++"); - if (total > 0) + if (inType == kDNSType_A) { - uint32_t accumulator = 0; - - for (i = 0; i < countof(inStats->answeredQuerySendCountBins); ++i) + if ((hist = set->histA) == NULL) { - uint32_t count; - const char * suffix; - - count = inStats->answeredQuerySendCountBins[i]; - accumulator += count; - suffix = (i < (countof(inStats->answeredQuerySendCountBins) - 1)) ? " " : "+"; - snprintf(label, sizeof(label), "%2d%s", (int)i, suffix); - LogStat(label, count, accumulator, total); + hist = (DNSHist *)calloc(1, sizeof(*hist)); + require_action_quiet(hist, exit, err = mStatus_NoMemoryErr); + set->histA = hist; } } - else + else if (inType == kDNSType_AAAA) { - LogMsgNoIdent("No data."); + if ((hist = set->histAAAA) == NULL) + { + hist = (DNSHist *)calloc(1, sizeof(*hist)); + require_action_quiet(hist, exit, err = mStatus_NoMemoryErr); + set->histAAAA = hist; + } } - - total = 0; - for (i = 0; i < countof(inStats->responseLatencyBins); ++i) + else { - total += inStats->responseLatencyBins[i]; + hist = NULL; } - LogMsgNoIdent("+++++++ Response times +++++++"); - if (total > 0) + if (inRR) { - uint32_t accumulator = 0; + uint16_t * sendCountBins; + uint16_t * latencyBins; + const mDNSBool isNegative = (inRR->RecordType == kDNSRecordTypePacketNegative); - for (i = 0; i < countof(inStats->responseLatencyBins); ++i) + i = Min(inQuerySendCount, kQueryStatsMaxQuerySendCount); + + sendCountBins = isNegative ? histAny->negAnsweredQuerySendCountBins : histAny->answeredQuerySendCountBins; + increment_saturate(sendCountBins[i], UINT16_MAX); + if (hist) { - uint32_t count; + sendCountBins = isNegative ? hist->negAnsweredQuerySendCountBins : hist->answeredQuerySendCountBins; + increment_saturate(sendCountBins[i], UINT16_MAX); + } - count = inStats->responseLatencyBins[i]; - accumulator += count; - if (i < countof(kResponseLatencyMsLimits)) - { - snprintf(label, sizeof(label), "< %5u ms", kResponseLatencyMsLimits[i]); - } - else + if (inQuerySendCount > 0) + { + for (i = 0; (i < (int)countof(kResponseLatencyMsLimits)) && (inLatencyMs >= kResponseLatencyMsLimits[i]); ++i) {} + latencyBins = isNegative ? histAny->negResponseLatencyBins : histAny->responseLatencyBins; + increment_saturate(latencyBins[i], UINT16_MAX); + if (hist) { - snprintf(label, sizeof(label), "< ∞ ms"); + latencyBins = isNegative ? hist->negResponseLatencyBins : hist->responseLatencyBins; + increment_saturate(latencyBins[i], UINT16_MAX); } - LogStat(label, count, accumulator, total); - if (accumulator == total) break; } } else { - LogMsgNoIdent("No data."); + i = Min(inQuerySendCount, kQueryStatsMaxQuerySendCount); + increment_saturate(histAny->unansweredQuerySendCountBins[i], UINT16_MAX); + if (hist) increment_saturate(hist->unansweredQuerySendCountBins[i], UINT16_MAX); + + for (i = 0; (i < (int)countof(kResponseLatencyMsLimits)) && (inLatencyMs >= kResponseLatencyMsLimits[i]); ++i) {} + increment_saturate(histAny->unansweredQueryDurationBins[i], UINT16_MAX); + if (hist) increment_saturate(hist->unansweredQueryDurationBins[i], UINT16_MAX); } + err = mStatus_NoError; + +exit: + return (err); } //=========================================================================================================================== -// LogMetrics +// ResolveStatsDomainCreate //=========================================================================================================================== -mDNSexport void LogMetrics(void) +mDNSlocal mStatus ResolveStatsDomainCreate(const Domain *inDomain, ResolveStatsDomain **outDomain) { - DNSDomainStatsRef domainStats; + mStatus err; + ResolveStatsDomain * obj; - LogMsgNoIdent("---- DNS stats by domain -----"); + obj = (ResolveStatsDomain *)calloc(1, sizeof(*obj)); + require_action_quiet(obj, exit, err = mStatus_NoMemoryErr); - for (domainStats = gDomainStatsList; domainStats; domainStats = domainStats->next) - { - LogMsgNoIdent("Domain: %s (non-cellular)", domainStats->domainStr); - LogDNSStats(&domainStats->stats); - LogMsgNoIdent("Domain: %s (cellular)", domainStats->domainStr); - LogDNSStats(&domainStats->statsCellular); - } + obj->domainInfo = inDomain; + + *outDomain = obj; + err = mStatus_NoError; + +exit: + return (err); +} + +//=========================================================================================================================== +// ResolveStatsDomainFree +//=========================================================================================================================== + +mDNSlocal void ResolveStatsDomainFree(ResolveStatsDomain *inDomain) +{ + ResolveStatsHostname * hostname; + + while ((hostname = inDomain->hostnameList) != NULL) + { + inDomain->hostnameList = hostname->next; + ResolveStatsHostnameFree(hostname); + } + free(inDomain); +} + +//=========================================================================================================================== +// ResolveStatsDomainUpdate +//=========================================================================================================================== + +mDNSlocal mStatus ResolveStatsDomainUpdate(ResolveStatsDomain *inDomain, const domainname *inHostname, const Response *inResp, const mDNSAddr *inDNSAddr, mDNSBool inForCell) +{ + mStatus err; + ResolveStatsHostname ** p; + ResolveStatsHostname * hostname; + uint8_t serverID; + + for (p = &inDomain->hostnameList; (hostname = *p) != NULL; p = &hostname->next) + { + if (SameDomainName((domainname *)hostname->name, inHostname)) break; + } + + if (!hostname) + { + require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused); + err = ResolveStatsHostnameCreate(inHostname, &hostname); + require_noerr_quiet(err, exit); + gResolveStatsObjCount++; + *p = hostname; + } + + err = ResolveStatsGetServerID(inDNSAddr, inForCell, &serverID); + require_noerr_quiet(err, exit); + + err = ResolveStatsHostnameUpdate(hostname, inResp, serverID); + require_noerr_quiet(err, exit); + +exit: + return (err); +} + +//=========================================================================================================================== +// ResolveStatsHostnameCreate +//=========================================================================================================================== + +mDNSlocal mStatus ResolveStatsHostnameCreate(const domainname *inName, ResolveStatsHostname **outHostname) +{ + mStatus err; + ResolveStatsHostname * obj; + size_t nameLen; + + nameLen = DomainNameLength(inName); + require_action_quiet(nameLen > 0, exit, err = mStatus_Invalid); + + obj = (ResolveStatsHostname *)calloc(1, sizeof(*obj) - 1 + nameLen); + require_action_quiet(obj, exit, err = mStatus_NoMemoryErr); + + memcpy(obj->name, inName, nameLen); + + *outHostname = obj; + err = mStatus_NoError; + +exit: + return (err); +} + +//=========================================================================================================================== +// ResolveStatsDomainCreateAWDVersion +//=========================================================================================================================== + +mDNSlocal mStatus ResolveStatsDomainCreateAWDVersion(const ResolveStatsDomain *inDomain, AWDMDNSResponderResolveStatsDomain **outDomain) +{ + mStatus err; + AWDMDNSResponderResolveStatsDomain * domain; + ResolveStatsHostname * hostname; + AWDMDNSResponderResolveStatsHostname * awdHostname; + NSString * name; + + domain = [[AWDMDNSResponderResolveStatsDomainSoft alloc] init]; + require_action_quiet(domain, exit, err = mStatus_UnknownErr); + + name = [[NSString alloc] initWithUTF8String:inDomain->domainInfo->cstr]; + require_action_quiet(name, exit, err = mStatus_UnknownErr); + + domain.name = name; + [name release]; + name = nil; + + for (hostname = inDomain->hostnameList; hostname; hostname = hostname->next) + { + err = ResolveStatsHostnameCreateAWDVersion(hostname, &awdHostname); + require_noerr_quiet(err, exit); + + [domain addHostname:awdHostname]; + [awdHostname release]; + awdHostname = nil; + } + + *outDomain = domain; + domain = nil; + err = mStatus_NoError; + +exit: + [domain release]; + return (err); +} + +//=========================================================================================================================== +// ResolveStatsHostnameFree +//=========================================================================================================================== + +mDNSlocal void ResolveStatsHostnameFree(ResolveStatsHostname *inHostname) +{ + ResolveStatsIPv4AddrSet * addrV4; + ResolveStatsIPv6Addr * addrV6; + ResolveStatsNegAAAASet * negV6; + + while ((addrV4 = inHostname->addrV4List) != NULL) + { + inHostname->addrV4List = addrV4->next; + ResolveStatsIPv4AddrSetFree(addrV4); + } + while ((addrV6 = inHostname->addrV6List) != NULL) + { + inHostname->addrV6List = addrV6->next; + ResolveStatsIPv6AddressFree(addrV6); + } + while ((negV6 = inHostname->negV6List) != NULL) + { + inHostname->negV6List = negV6->next; + ResolveStatsNegAAAASetFree(negV6); + } + free(inHostname); +} + +//=========================================================================================================================== +// ResolveStatsHostnameUpdate +//=========================================================================================================================== + +mDNSlocal mStatus ResolveStatsHostnameUpdate(ResolveStatsHostname *inHostname, const Response *inResp, uint8_t inServerID) +{ + mStatus err; + + if ((inResp->type == kResponseType_IPv4Addr) || (inResp->type == kResponseType_NegA)) + { + ResolveStatsIPv4AddrSet ** p; + ResolveStatsIPv4AddrSet * addrV4; + int i; + IPv4AddrCounter * counter; + + for (p = &inHostname->addrV4List; (addrV4 = *p) != NULL; p = &addrV4->next) + { + for (i = 0; i < (int)countof(addrV4->counters); ++i) + { + counter = &addrV4->counters[i]; + if (counter->count == 0) break; + if (counter->serverID != inServerID) continue; + if (inResp->type == kResponseType_NegA) + { + if (counter->isNegative) break; + } + else + { + if (memcmp(counter->addrBytes, inResp->data, 4) == 0) break; + } + } + if (i < (int)countof(addrV4->counters)) break; + } + if (!addrV4) + { + require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused); + err = ResolveStatsIPv4AddrSetCreate(&addrV4); + require_noerr_quiet(err, exit); + gResolveStatsObjCount++; + + *p = addrV4; + counter = &addrV4->counters[0]; + } + if (counter->count == 0) + { + counter->serverID = inServerID; + if (inResp->type == kResponseType_NegA) + { + counter->isNegative = 1; + } + else + { + counter->isNegative = 0; + memcpy(counter->addrBytes, inResp->data, 4); + } + } + increment_saturate(counter->count, UINT16_MAX); + err = mStatus_NoError; + } + else if (inResp->type == kResponseType_IPv6Addr) + { + ResolveStatsIPv6Addr ** p; + ResolveStatsIPv6Addr * addrV6; + + for (p = &inHostname->addrV6List; (addrV6 = *p) != NULL; p = &addrV6->next) + { + if ((addrV6->serverID == inServerID) && (memcmp(addrV6->addrBytes, inResp->data, 16) == 0)) break; + } + if (!addrV6) + { + require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused); + err = ResolveStatsIPv6AddressCreate(inServerID, inResp->data, &addrV6); + require_noerr_quiet(err, exit); + gResolveStatsObjCount++; + + *p = addrV6; + } + increment_saturate(addrV6->count, UINT16_MAX); + err = mStatus_NoError; + } + else if (inResp->type == kResponseType_NegAAAA) + { + ResolveStatsNegAAAASet ** p; + ResolveStatsNegAAAASet * negV6; + int i; + NegAAAACounter * counter; + + for (p = &inHostname->negV6List; (negV6 = *p) != NULL; p = &negV6->next) + { + for (i = 0; i < (int)countof(negV6->counters); ++i) + { + counter = &negV6->counters[i]; + if ((counter->count == 0) || (counter->serverID == inServerID)) break; + } + if (i < (int)countof(negV6->counters)) break; + } + if (!negV6) + { + require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused); + err = ResolveStatsNegAAAASetCreate(&negV6); + require_noerr_quiet(err, exit); + gResolveStatsObjCount++; + + *p = negV6; + counter = &negV6->counters[0]; + } + if (counter->count == 0) counter->serverID = inServerID; + increment_saturate(counter->count, UINT16_MAX); + err = mStatus_NoError; + } + else + { + err = mStatus_Invalid; + } + +exit: + return (err); +} + +//=========================================================================================================================== +// ResolveStatsHostnameCreateAWDVersion +//=========================================================================================================================== + +mDNSlocal mStatus ResolveStatsHostnameCreateAWDVersion(const ResolveStatsHostname *inHostname, AWDMDNSResponderResolveStatsHostname **outHostname) +{ + mStatus err; + AWDMDNSResponderResolveStatsHostname * hostname; + NSString * name; + char nameBuf[MAX_ESCAPED_DOMAIN_NAME]; + const char * ptr; + ResolveStatsIPv4AddrSet * addrV4; + ResolveStatsIPv6Addr * addrV6; + ResolveStatsNegAAAASet * negV6; + AWDMDNSResponderResolveStatsResult * result = nil; + int i; + + hostname = [[AWDMDNSResponderResolveStatsHostnameSoft alloc] init]; + require_action_quiet(hostname, exit, err = mStatus_UnknownErr); + + ptr = ConvertDomainNameToCString((domainname *)inHostname->name, nameBuf); + require_action_quiet(ptr, exit, err = mStatus_UnknownErr); + + name = [[NSString alloc] initWithUTF8String:nameBuf]; + require_action_quiet(name, exit, err = mStatus_UnknownErr); + + hostname.name = name; + [name release]; + name = nil; + + for (addrV4 = inHostname->addrV4List; addrV4; addrV4 = addrV4->next) + { + for (i = 0; i < (int)countof(addrV4->counters); ++i) + { + const IPv4AddrCounter * counter; + NSData * addrBytes; + + counter = &addrV4->counters[i]; + if (counter->count == 0) break; + + result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init]; + require_action_quiet(result, exit, err = mStatus_UnknownErr); + + if (counter->isNegative) + { + result.type = AWDMDNSResponderResolveStatsResult_ResultType_NegA; + } + else + { + addrBytes = [[NSData alloc] initWithBytes:counter->addrBytes length:4]; + require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr); + + result.type = AWDMDNSResponderResolveStatsResult_ResultType_IPv4Addr; + result.data = addrBytes; + [addrBytes release]; + } + result.count = counter->count; + result.serverID = counter->serverID; + + [hostname addResult:result]; + [result release]; + result = nil; + } + } + + for (addrV6 = inHostname->addrV6List; addrV6; addrV6 = addrV6->next) + { + NSData * addrBytes; + + result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init]; + require_action_quiet(result, exit, err = mStatus_UnknownErr); + + addrBytes = [[NSData alloc] initWithBytes:addrV6->addrBytes length:16]; + require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr); + + result.type = AWDMDNSResponderResolveStatsResult_ResultType_IPv6Addr; + result.count = addrV6->count; + result.serverID = addrV6->serverID; + result.data = addrBytes; + + [addrBytes release]; + + [hostname addResult:result]; + [result release]; + result = nil; + } + + for (negV6 = inHostname->negV6List; negV6; negV6 = negV6->next) + { + for (i = 0; i < (int)countof(negV6->counters); ++i) + { + const NegAAAACounter * counter; + + counter = &negV6->counters[i]; + if (counter->count == 0) break; + + result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init]; + require_action_quiet(result, exit, err = mStatus_UnknownErr); + + result.type = AWDMDNSResponderResolveStatsResult_ResultType_NegAAAA; + result.count = counter->count; + result.serverID = counter->serverID; + + [hostname addResult:result]; + [result release]; + result = nil; + } + } + + *outHostname = hostname; + hostname = nil; + err = mStatus_NoError; + +exit: + [result release]; + [hostname release]; + return (err); +} + +//=========================================================================================================================== +// ResolveStatsDNSServerCreate +//=========================================================================================================================== + +mDNSlocal mStatus ResolveStatsDNSServerCreate(const mDNSAddr *inAddr, mDNSBool inForCell, ResolveStatsDNSServer **outServer) +{ + mStatus err; + ResolveStatsDNSServer * obj; + size_t addrLen; + + require_action_quiet((inAddr->type == mDNSAddrType_IPv4) || (inAddr->type == mDNSAddrType_IPv6), exit, err = mStatus_Invalid); + + addrLen = (inAddr->type == mDNSAddrType_IPv4) ? 4 : 16; + obj = (ResolveStatsDNSServer *)calloc(1, sizeof(*obj) - 1 + addrLen); + require_action_quiet(obj, exit, err = mStatus_NoMemoryErr); + + obj->isForCell = inForCell; + if (inAddr->type == mDNSAddrType_IPv4) + { + obj->isAddrV6 = mDNSfalse; + memcpy(obj->addrBytes, inAddr->ip.v4.b, addrLen); + } + else + { + obj->isAddrV6 = mDNStrue; + memcpy(obj->addrBytes, inAddr->ip.v6.b, addrLen); + } + + *outServer = obj; + err = mStatus_NoError; + +exit: + return (err); +} + +//=========================================================================================================================== +// ResolveStatsDNSServerFree +//=========================================================================================================================== + +mDNSlocal void ResolveStatsDNSServerFree(ResolveStatsDNSServer *inServer) +{ + free(inServer); +} + +//=========================================================================================================================== +// ResolveStatsDNSServerCreateAWDVersion +//=========================================================================================================================== + +mDNSlocal mStatus ResolveStatsDNSServerCreateAWDVersion(const ResolveStatsDNSServer *inServer, AWDMDNSResponderResolveStatsDNSServer **outServer) +{ + mStatus err; + AWDMDNSResponderResolveStatsDNSServer * server; + NSData * addrBytes = nil; + + server = [[AWDMDNSResponderResolveStatsDNSServerSoft alloc] init]; + require_action_quiet(server, exit, err = mStatus_UnknownErr); + + addrBytes = [[NSData alloc] initWithBytes:inServer->addrBytes length:(inServer->isAddrV6 ? 16 : 4)]; + require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr); + + server.serverID = inServer->id; + server.address = addrBytes; + if (inServer->isForCell) + { + server.networkType = AWDMDNSResponderResolveStatsDNSServer_NetworkType_Cellular; + } + else + { + server.networkType = AWDMDNSResponderResolveStatsDNSServer_NetworkType_NonCellular; + } + + *outServer = server; + server = nil; + err = mStatus_NoError; + +exit: + [addrBytes release]; + [server release]; + return (err); +} + +//=========================================================================================================================== +// ResolveStatsIPv4AddrSetCreate +//=========================================================================================================================== + +mDNSlocal mStatus ResolveStatsIPv4AddrSetCreate(ResolveStatsIPv4AddrSet **outSet) +{ + mStatus err; + ResolveStatsIPv4AddrSet * obj; + + obj = (ResolveStatsIPv4AddrSet *)calloc(1, sizeof(*obj)); + require_action_quiet(obj, exit, err = mStatus_NoMemoryErr); + + *outSet = obj; + err = mStatus_NoError; + +exit: + return (err); +} + +//=========================================================================================================================== +// ResolveStatsIPv4AddrSetFree +//=========================================================================================================================== + +mDNSlocal void ResolveStatsIPv4AddrSetFree(ResolveStatsIPv4AddrSet *inSet) +{ + free(inSet); +} + +//=========================================================================================================================== +// ResolveStatsIPv6AddressCreate +//=========================================================================================================================== + +mDNSlocal mStatus ResolveStatsIPv6AddressCreate(uint8_t inServerID, const uint8_t inAddrBytes[16], ResolveStatsIPv6Addr **outAddr) +{ + mStatus err; + ResolveStatsIPv6Addr * obj; + + obj = (ResolveStatsIPv6Addr *)calloc(1, sizeof(*obj)); + require_action_quiet(obj, exit, err = mStatus_NoMemoryErr); + + obj->serverID = inServerID; + memcpy(obj->addrBytes, inAddrBytes, 16); + + *outAddr = obj; + err = mStatus_NoError; + +exit: + return (err); +} + +//=========================================================================================================================== +// ResolveStatsIPv6AddressFree +//=========================================================================================================================== + +mDNSlocal void ResolveStatsIPv6AddressFree(ResolveStatsIPv6Addr *inAddr) +{ + free(inAddr); +} + +//=========================================================================================================================== +// ResolveStatsNegAAAASetCreate +//=========================================================================================================================== + +mDNSlocal mStatus ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet) +{ + mStatus err; + ResolveStatsNegAAAASet * obj; + + obj = (ResolveStatsNegAAAASet *)calloc(1, sizeof(*obj)); + require_action_quiet(obj, exit, err = mStatus_NoMemoryErr); + + *outSet = obj; + err = mStatus_NoError; + +exit: + return (err); +} + +//=========================================================================================================================== +// ResolveStatsNegAAAASetFree +//=========================================================================================================================== + +mDNSlocal void ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet) +{ + free(inSet); +} + +//=========================================================================================================================== +// ResolveStatsGetServerID +//=========================================================================================================================== + +mDNSlocal mStatus ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID) +{ + mStatus err; + ResolveStatsDNSServer ** p; + ResolveStatsDNSServer * server; + + require_action_quiet((inServerAddr->type == mDNSAddrType_IPv4) || (inServerAddr->type == mDNSAddrType_IPv6), exit, err = mStatus_Invalid); + + for (p = &gResolveStatsServerList; (server = *p) != NULL; p = &server->next) + { + if ((inForCell && server->isForCell) || (!inForCell && !server->isForCell)) + { + if (inServerAddr->type == mDNSAddrType_IPv4) + { + if (!server->isAddrV6 && (memcmp(server->addrBytes, inServerAddr->ip.v4.b, 4) == 0)) break; + } + else + { + if (server->isAddrV6 && (memcmp(server->addrBytes, inServerAddr->ip.v6.b, 16) == 0)) break; + } + } + } + + if (!server) + { + require_action_quiet(gResolveStatsNextServerID <= UINT8_MAX, exit, err = mStatus_Refused); + require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused); + err = ResolveStatsDNSServerCreate(inServerAddr, inForCell, &server); + require_noerr_quiet(err, exit); + gResolveStatsObjCount++; + + server->id = gResolveStatsNextServerID++; + server->next = gResolveStatsServerList; + gResolveStatsServerList = server; + } + else if (gResolveStatsServerList != server) + { + *p = server->next; + server->next = gResolveStatsServerList; + gResolveStatsServerList = server; + } + + *outServerID = server->id; + err = mStatus_NoError; + +exit: + return (err); +} + +//=========================================================================================================================== +// CreateDomainStatsList +//=========================================================================================================================== + +mDNSlocal mStatus CreateDomainStatsList(DNSDomainStats **outList) +{ + mStatus err; + int i; + DNSDomainStats * stats; + DNSDomainStats ** p; + DNSDomainStats * list = NULL; + + p = &list; + for (i = 0; i < (int)countof(kQueryStatsDomains); ++i) + { + err = DNSDomainStatsCreate(&kQueryStatsDomains[i], &stats); + require_noerr_quiet(err, exit); + + *p = stats; + p = &stats->next; + } + + *outList = list; + list = NULL; + +exit: + DNSDomainStatsFreeList(list); + return (err); +} + +//=========================================================================================================================== +// CreateResolveStatsList +//=========================================================================================================================== + +mDNSlocal mStatus CreateResolveStatsList(ResolveStatsDomain **outList) +{ + mStatus err; + int i; + ResolveStatsDomain * domain; + ResolveStatsDomain ** p; + ResolveStatsDomain * list = NULL; + + p = &list; + for (i = 0; i < (int)countof(kResolveStatsDomains); ++i) + { + err = ResolveStatsDomainCreate(&kResolveStatsDomains[i], &domain); + require_noerr_quiet(err, exit); + + *p = domain; + p = &domain->next; + } + + *outList = list; + list = NULL; + +exit: + FreeResolveStatsList(list); + return (err); +} + +//=========================================================================================================================== +// FreeResolveStatsList +//=========================================================================================================================== + +mDNSlocal void FreeResolveStatsList(ResolveStatsDomain *inList) +{ + ResolveStatsDomain * domain; + + while ((domain = inList) != NULL) + { + inList = domain->next; + ResolveStatsDomainFree(domain); + } +} + +//=========================================================================================================================== +// FreeResolveStatsServerList +//=========================================================================================================================== + +mDNSlocal void FreeResolveStatsServerList(ResolveStatsDNSServer *inList) +{ + ResolveStatsDNSServer * server; + + while ((server = inList) != NULL) + { + inList = server->next; + ResolveStatsDNSServerFree(server); + } +} + +//=========================================================================================================================== +// SubmitAWDMetric +//=========================================================================================================================== + +mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID) +{ + mStatus err = mStatus_NoError; + + switch (inMetricID) + { + case AWDMetricId_MDNSResponder_DNSStatistics: + err = SubmitAWDMetricQueryStats(); + break; + + case AWDMetricId_MDNSResponder_ResolveStats: + err = SubmitAWDMetricResolveStats(); + break; + + case AWDMetricId_MDNSResponder_ServicesStats: + [AWDMetricManagerSoft postMetricWithId:AWDMetricId_MDNSResponder_ServicesStats integerValue:max_num_regservices]; + KQueueLock(&mDNSStorage); + // reset the no of max services since we want to collect the max no of services registered per AWD submission period + max_num_regservices = curr_num_regservices; + KQueueUnlock(&mDNSStorage, "SubmitAWDSimpleMetricServiceStats"); + break; + + default: + err = mStatus_UnsupportedErr; + break; + } + + if (err) + LogMsg("SubmitAWDMetric for metric ID 0x%08X failed with error %d", inMetricID, err); + return (err); +} + +//=========================================================================================================================== +// SubmitAWDMetricQueryStats +//=========================================================================================================================== + +mDNSlocal mStatus SubmitAWDMetricQueryStats(void) +{ + mStatus err; + BOOL success; + DNSDomainStats * stats; + DNSDomainStats * newDomainStatsList; + DNSDomainStats * domainStatsList = NULL; + AWDMetricContainer * container = nil; + AWDMDNSResponderDNSStatistics * metric = nil; + + err = CreateDomainStatsList(&newDomainStatsList); + require_noerr_quiet(err, exit); + + domainStatsList = gDomainStatsList; + + KQueueLock(&mDNSStorage); + gDomainStatsList = newDomainStatsList; + KQueueUnlock(&mDNSStorage, "SubmitAWDMetricQueryStats"); + + container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_DNSStatistics]; + require_action_quiet(container, exit, err = mStatus_UnknownErr); + + metric = [[AWDMDNSResponderDNSStatisticsSoft alloc] init]; + require_action_quiet(metric, exit, err = mStatus_UnknownErr); + + while ((stats = domainStatsList) != NULL) + { + if (stats->nonCellular) + { + err = AddAWDDNSDomainStats(metric, stats->nonCellular, stats->domain->cstr, mDNSfalse); + require_noerr_quiet(err, exit); + } + if (stats->cellular) + { + err = AddAWDDNSDomainStats(metric, stats->cellular, stats->domain->cstr, mDNStrue); + require_noerr_quiet(err, exit); + } + domainStatsList = stats->next; + DNSDomainStatsFree(stats); + } + + container.metric = metric; + success = [gAWDServerConnection submitMetric:container]; + LogMsg("SubmitAWDMetricQueryStats: metric submission %s.", success ? "succeeded" : "failed" ); + err = success ? mStatus_NoError : mStatus_UnknownErr; + +exit: + [metric release]; + [container release]; + DNSDomainStatsFreeList(domainStatsList); + return (err); +} + +//=========================================================================================================================== +// SubmitAWDMetricResolveStats +//=========================================================================================================================== + +mDNSlocal mStatus SubmitAWDMetricResolveStats(void) +{ + mStatus err; + ResolveStatsDomain * newResolveStatsList; + ResolveStatsDomain * domainList = NULL; + ResolveStatsDNSServer * serverList = NULL; + AWDMetricContainer * container = nil; + AWDMDNSResponderResolveStats * metric = nil; + ResolveStatsDNSServer * server; + ResolveStatsDomain * domain; + BOOL success; + + err = CreateResolveStatsList(&newResolveStatsList); + require_noerr_quiet(err, exit); + + domainList = gResolveStatsList; + serverList = gResolveStatsServerList; + + KQueueLock(&mDNSStorage); + gResolveStatsList = newResolveStatsList; + gResolveStatsServerList = NULL; + gResolveStatsNextServerID = 0; + gResolveStatsObjCount = 0; + KQueueUnlock(&mDNSStorage, "SubmitAWDMetricResolveStats"); + + container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_ResolveStats]; + require_action_quiet(container, exit, err = mStatus_UnknownErr); + + metric = [[AWDMDNSResponderResolveStatsSoft alloc] init]; + require_action_quiet(metric, exit, err = mStatus_UnknownErr); + + while ((server = serverList) != NULL) + { + AWDMDNSResponderResolveStatsDNSServer * awdServer; + + serverList = server->next; + err = ResolveStatsDNSServerCreateAWDVersion(server, &awdServer); + ResolveStatsDNSServerFree(server); + require_noerr_quiet(err, exit); + + [metric addServer:awdServer]; + [awdServer release]; + } + + while ((domain = domainList) != NULL) + { + AWDMDNSResponderResolveStatsDomain * awdDomain; + + domainList = domain->next; + err = ResolveStatsDomainCreateAWDVersion(domain, &awdDomain); + ResolveStatsDomainFree(domain); + require_noerr_quiet(err, exit); + + [metric addDomain:awdDomain]; + [awdDomain release]; + } + + container.metric = metric; + success = [gAWDServerConnection submitMetric:container]; + LogMsg("SubmitAWDMetricResolveStats: metric submission %s.", success ? "succeeded" : "failed" ); + err = success ? mStatus_NoError : mStatus_UnknownErr; + +exit: + [metric release]; + [container release]; + FreeResolveStatsList(domainList); + FreeResolveStatsServerList(serverList); + return (err); +} + +//=========================================================================================================================== +// CreateAWDDNSDomainStats +//=========================================================================================================================== + +mDNSlocal mStatus CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain, mDNSBool inForCell, AWDDNSDomainStats_RecordType inType, AWDDNSDomainStats **outStats) +{ + mStatus err; + AWDDNSDomainStats * awdStats = nil; + NSString * domain = nil; + uint32_t sendCountBins[kQueryStatsSendCountBinCount]; + uint32_t latencyBins[kQueryStatsLatencyBinCount]; + int i; + unsigned int totalAnswered; + unsigned int totalNegAnswered; + unsigned int totalUnanswered; + + awdStats = [[AWDDNSDomainStatsSoft alloc] init]; + require_action_quiet(awdStats, exit, err = mStatus_UnknownErr); + + domain = [[NSString alloc] initWithUTF8String:inDomain]; + require_action_quiet(domain, exit, err = mStatus_UnknownErr); + + awdStats.domain = domain; + awdStats.networkType = inForCell ? AWDDNSDomainStats_NetworkType_Cellular : AWDDNSDomainStats_NetworkType_NonCellular; + awdStats.recordType = inType; + + totalAnswered = 0; + for (i = 0; i < kQueryStatsSendCountBinCount; ++i) + { + sendCountBins[i] = inHist->answeredQuerySendCountBins[i]; + totalAnswered += inHist->answeredQuerySendCountBins[i]; + } + [awdStats setAnsweredQuerySendCounts:sendCountBins count:kQueryStatsSendCountBinCount]; + + totalNegAnswered = 0; + for (i = 0; i < kQueryStatsSendCountBinCount; ++i) + { + sendCountBins[i] = inHist->negAnsweredQuerySendCountBins[i]; + totalNegAnswered += inHist->negAnsweredQuerySendCountBins[i]; + } + [awdStats setNegAnsweredQuerySendCounts:sendCountBins count:kQueryStatsSendCountBinCount]; + + totalUnanswered = 0; + for (i = 0; i < kQueryStatsSendCountBinCount; ++i) + { + sendCountBins[i] = inHist->unansweredQuerySendCountBins[i]; + totalUnanswered += inHist->unansweredQuerySendCountBins[i]; + } + [awdStats setUnansweredQuerySendCounts:sendCountBins count:kQueryStatsSendCountBinCount]; + + if (totalAnswered > inHist->answeredQuerySendCountBins[0]) + { + for (i = 0; i < kQueryStatsLatencyBinCount; ++i) + { + latencyBins[i] = inHist->responseLatencyBins[i]; + } + [awdStats setResponseLatencyMs:latencyBins count:kQueryStatsLatencyBinCount]; + } + + if (totalNegAnswered > inHist->negAnsweredQuerySendCountBins[0]) + { + for (i = 0; i < kQueryStatsLatencyBinCount; ++i) + { + latencyBins[i] = inHist->negResponseLatencyBins[i]; + } + [awdStats setNegResponseLatencyMs:latencyBins count:kQueryStatsLatencyBinCount]; + } + + if (totalUnanswered > 0) + { + for (i = 0; i < kQueryStatsLatencyBinCount; ++i) + { + latencyBins[i] = inHist->unansweredQueryDurationBins[i]; + } + [awdStats setUnansweredQueryDurationMs:latencyBins count:kQueryStatsLatencyBinCount]; + } + + *outStats = awdStats; + awdStats = nil; + err = mStatus_NoError; + +exit: + [domain release]; + [awdStats release]; + return (err); +} + +//=========================================================================================================================== +// AddAWDDNSDomainStats +//=========================================================================================================================== + +mDNSlocal mStatus AddAWDDNSDomainStats(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell) +{ + mStatus err; + AWDDNSDomainStats * awdStats; + + if (inSet->histAny) + { + err = CreateAWDDNSDomainStats(inSet->histAny, inDomain, inForCell, AWDDNSDomainStats_RecordType_Any, &awdStats); + require_noerr_quiet(err, exit); + + [inMetric addStats:awdStats]; + [awdStats release]; + } + if (inSet->histA) + { + err = CreateAWDDNSDomainStats(inSet->histA, inDomain, inForCell, AWDDNSDomainStats_RecordType_A, &awdStats); + require_noerr_quiet(err, exit); + + [inMetric addStats:awdStats]; + [awdStats release]; + } + if (inSet->histAAAA) + { + err = CreateAWDDNSDomainStats(inSet->histAAAA, inDomain, inForCell, AWDDNSDomainStats_RecordType_AAAA, &awdStats); + require_noerr_quiet(err, exit); + + [inMetric addStats:awdStats]; + [awdStats release]; + } + err = mStatus_NoError; + +exit: + return (err); +} + +//=========================================================================================================================== +// LogDNSHistSet +//=========================================================================================================================== + +mDNSlocal void LogDNSHistSet(const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell) +{ + if (inSet->histAny) LogDNSHist(inSet->histAny, inDomain, inForCell, "Any"); + if (inSet->histA) LogDNSHist(inSet->histA, inDomain, inForCell, "A"); + if (inSet->histAAAA) LogDNSHist(inSet->histAAAA, inDomain, inForCell, "AAAA"); +} + +//=========================================================================================================================== +// LogDNSHist +//=========================================================================================================================== + +#define Percent(N, D) ((N) * 100) / (D), (((N) * 10000) / (D)) % 100 +#define PercentFmt "%3u.%02u" +#define LogStat(LABEL, COUNT, ACCUMULATOR, TOTAL) \ + LogMsgNoIdent("%s %5u " PercentFmt " " PercentFmt, (LABEL), (COUNT), Percent(COUNT, TOTAL), Percent(ACCUMULATOR, TOTAL)) + +mDNSlocal void LogDNSHist(const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType) +{ + unsigned int totalAnswered; + unsigned int totalNegAnswered; + unsigned int totalUnanswered; + int i; + + totalAnswered = 0; + for (i = 0; i < kQueryStatsSendCountBinCount; ++i) + { + totalAnswered += inHist->answeredQuerySendCountBins[i]; + } + + totalNegAnswered = 0; + for (i = 0; i < kQueryStatsSendCountBinCount; ++i) + { + totalNegAnswered += inHist->negAnsweredQuerySendCountBins[i]; + } + + totalUnanswered = 0; + for (i = 0; i < kQueryStatsSendCountBinCount; ++i) + { + totalUnanswered += inHist->unansweredQuerySendCountBins[i]; + } + + LogMsgNoIdent("Domain: %s (%s, %s)", inDomain, inForCell ? "C" : "NC", inType); + LogMsgNoIdent("Answered questions %4u", totalAnswered); + LogMsgNoIdent("Negatively answered questions %4u", totalNegAnswered); + LogMsgNoIdent("Unanswered questions %4u", totalUnanswered); + LogMsgNoIdent("-- Query send counts ---------"); + LogDNSHistSendCounts(inHist->answeredQuerySendCountBins); + LogMsgNoIdent("-- Query send counts (NAQs) --"); + LogDNSHistSendCounts(inHist->negAnsweredQuerySendCountBins); + + if (totalAnswered > inHist->answeredQuerySendCountBins[0]) + { + LogMsgNoIdent("--- Response times -----------"); + LogDNSHistLatencies(inHist->responseLatencyBins); + } + + if (totalNegAnswered > inHist->negAnsweredQuerySendCountBins[0]) + { + LogMsgNoIdent("--- Response times (NAQs) ----"); + LogDNSHistLatencies(inHist->negResponseLatencyBins); + } + + if (totalUnanswered > 0) + { + LogMsgNoIdent("--- Unanswered query times ---"); + LogDNSHistLatencies(inHist->unansweredQueryDurationBins); + } +} + +//=========================================================================================================================== +// LogDNSHistSendCounts +//=========================================================================================================================== + +mDNSlocal void LogDNSHistSendCounts(const uint16_t inSendCountBins[kQueryStatsSendCountBinCount]) +{ + uint32_t total; + char label[16]; + int i; + + total = 0; + for (i = 0; i < kQueryStatsSendCountBinCount; ++i) + { + total += inSendCountBins[i]; + } + + if (total > 0) + { + uint32_t accumulator = 0; + + for (i = 0; i < kQueryStatsSendCountBinCount; ++i) + { + accumulator += inSendCountBins[i]; + if (i < (kQueryStatsSendCountBinCount - 1)) + { + snprintf(label, sizeof(label), "%2d ", i); + } + else + { + snprintf(label, sizeof(label), "%2d+", i); + } + LogStat(label, inSendCountBins[i], accumulator, total); + if (accumulator == total) break; + } + } + else + { + LogMsgNoIdent("No data."); + } +} + +//=========================================================================================================================== +// LogDNSHistLatencies +//=========================================================================================================================== + +mDNSlocal void LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLatencyBinCount]) +{ + uint32_t total; + int i; + char label[16]; + + total = 0; + for (i = 0; i < kQueryStatsLatencyBinCount; ++i) + { + total += inLatencyBins[i]; + } + + if (total > 0) + { + uint32_t accumulator = 0; + + for (i = 0; i < kQueryStatsLatencyBinCount; ++i) + { + accumulator += inLatencyBins[i]; + if (i < (int)countof(kResponseLatencyMsLimits)) + { + snprintf(label, sizeof(label), "< %5u ms", kResponseLatencyMsLimits[i]); + } + else + { + snprintf(label, sizeof(label), "< ∞ ms"); + } + LogStat(label, inLatencyBins[i], accumulator, total); + if (accumulator == total) break; + } + } + else + { + LogMsgNoIdent("No data."); + } +} + +//=========================================================================================================================== +// ValidateDNSStatsDomains +//=========================================================================================================================== + +#if (METRICS_VALIDATE_DNS_STATS_DOMAINS) +#warning "Do not include ValidateDNSStatsDomains() in customer release!" +mDNSlocal void ValidateDNSStatsDomains(void) +{ + int i; + const Domain * domain; + mDNSu8 * ptr; + domainname domainNameExpected; + int labelCountExpected; + mDNSBool domainNamesEqual; + mDNSBool failed = mDNSfalse; + + for (i = 0; i < countof(kQueryStatsDomains); ++i) + { + domain = &kQueryStatsDomains[i]; + + if (strcmp(domain->cstr, ".") == 0) + { + domainNameExpected.c[0] = 0; + } + else + { + ptr = MakeDomainNameFromDNSNameString(&domainNameExpected, domain->cstr); + if (!ptr) + { + LogMsg("ValidateDNSStatsDomains: Failed to make domain name for \"%s\".", domain->cstr); + failed = mDNStrue; + goto exit; + } + } + + domainNamesEqual = SameDomainName(domain->name, &domainNameExpected); + labelCountExpected = CountLabels(&domainNameExpected); + if (domainNamesEqual && (domain->labelCount == labelCountExpected)) + { + LogMsg("ValidateDNSStatsDomains: \"%s\" passed.", domain->cstr); + } + else + { + if (!domainNamesEqual) + { + LogMsg("ValidateDNSStatsDomains: \"%s\" failed: incorrect domain name.", domain->cstr); + } + if (domain->labelCount != labelCountExpected) + { + LogMsg("ValidateDNSStatsDomains: \"%s\" failed: incorrect label count. Actual %d, expected %d.", + domain->cstr, domain->labelCount, labelCountExpected); + } + failed = mDNStrue; + } + } + +exit: + if (failed) abort(); } +#endif #endif // TARGET_OS_EMBEDDED diff --git a/mDNSResponder/mDNSMacOSX/P2PPacketFilter.c b/mDNSResponder/mDNSMacOSX/P2PPacketFilter.c index 0665103f..59a5cf4a 100644 --- a/mDNSResponder/mDNSMacOSX/P2PPacketFilter.c +++ b/mDNSResponder/mDNSMacOSX/P2PPacketFilter.c @@ -228,7 +228,9 @@ static void initPortRule( struct pfioc_rule * pr, int P2PPacketFilterAddBonjourRuleSet(const char * interfaceName, u_int32_t count, pfArray_t portArray, pfArray_t protocolArray ) { int result; - u_int32_t i, ticket, poolTicket; + u_int32_t i; + u_int32_t ticket = 0; + u_int32_t poolTicket = 0; int devFD = -1; char * anchorPath = MDNS_ANCHOR_PATH; @@ -278,7 +280,7 @@ int P2PPacketFilterClearBonjourRules() { int result; int pfDev = -1; - u_int32_t ticket; + u_int32_t ticket = 0; char * anchorPath = MDNS_ANCHOR_PATH; result = openPFDevice( &pfDev ); diff --git a/mDNSResponder/mDNSMacOSX/P2PPacketFilter.h b/mDNSResponder/mDNSMacOSX/P2PPacketFilter.h index 904b43ba..23e5410b 100644 --- a/mDNSResponder/mDNSMacOSX/P2PPacketFilter.h +++ b/mDNSResponder/mDNSMacOSX/P2PPacketFilter.h @@ -20,7 +20,8 @@ #include "helpermsg-types.h" -enum { +enum +{ PF_SET_RULES, PF_CLEAR_RULES }; diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c b/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c index a2ab5464..43da5025 100644 --- a/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c +++ b/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c @@ -112,7 +112,7 @@ OSStatus InitConfigAuthority(void) CFSTR("Describes operation that requires user authorization")); require_action( rightInfo != NULL, GetStrFailed, err=coreFoundationUnknownErr;); dict = CreateRightsDict(rightInfo); - require_action( dict != NULL, GetStrFailed, err=coreFoundationUnknownErr;); + require_action( dict != NULL, GetStrFailed, err=coreFoundationUnknownErr; CFRelease(rightInfo)); err = AuthorizationRightSet(gAuthRef, UPDATE_SC_RIGHT, dict, (CFStringRef) NULL, (CFBundleRef) NULL, (CFStringRef) NULL); @@ -128,7 +128,7 @@ OSStatus InitConfigAuthority(void) CFSTR("Describes operation that requires user authorization")); require_action( rightInfo != NULL, GetStrFailed, err=coreFoundationUnknownErr;); dict = CreateRightsDict( rightInfo); - require_action( dict != NULL, GetStrFailed, err=coreFoundationUnknownErr;); + require_action( dict != NULL, GetStrFailed, err=coreFoundationUnknownErr; CFRelease(rightInfo)); err = AuthorizationRightSet(gAuthRef, EDIT_SYS_KEYCHAIN_RIGHT, dict, (CFStringRef) NULL, (CFBundleRef) NULL, (CFStringRef) NULL); diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m b/mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m index 26e3eaf0..ba5f64bf 100644 --- a/mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m +++ b/mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m @@ -333,8 +333,8 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) currentHostName = [[NSString alloc] initWithString:@""]; } - CFRelease((CFDictionaryRef)origDict); - CFRelease(store); + if (origDict) CFRelease((CFDictionaryRef)origDict); + if (store) CFRelease(store); } diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.c b/mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.c index efb41497..a279c983 100644 --- a/mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.c +++ b/mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.c @@ -75,7 +75,7 @@ OSStatus EnsureToolInstalled(void) { CFURLRef bundleURL; pid_t toolPID; - int status; + int status = 0; OSStatus err = noErr; const char *args[] = { kToolPath, "0", "V", NULL }; char toolSourcePath[PATH_MAX] = {}; @@ -98,8 +98,10 @@ OSStatus EnsureToolInstalled(void) if (bundleURL != NULL) { CFURLGetFileSystemRepresentation(bundleURL, false, (UInt8*) toolSourcePath, sizeof toolSourcePath); - if (strlcat(toolSourcePath, "/Contents/Resources/" kToolName, sizeof toolSourcePath ) >= sizeof toolSourcePath ) return(-1); CFURLGetFileSystemRepresentation(bundleURL, false, (UInt8*) toolInstallerPath, sizeof toolInstallerPath); + CFRelease(bundleURL); + + if (strlcat(toolSourcePath, "/Contents/Resources/" kToolName, sizeof toolSourcePath ) >= sizeof toolSourcePath ) return(-1); if (strlcat(toolInstallerPath, "/Contents/Resources/" kToolInstaller, sizeof toolInstallerPath) >= sizeof toolInstallerPath) return(-1); } else @@ -164,7 +166,7 @@ static OSStatus ExecWithCmdAndParam(const char *subCmd, CFDataRef paramData) } commFD = fileno(tmpfile()); - sprintf(fileNum, "%d", commFD); + snprintf(fileNum, sizeof(fileNum), "%d", commFD); args[1] = fileNum; args[3] = subCmd; @@ -185,7 +187,7 @@ static OSStatus ExecWithCmdAndParam(const char *subCmd, CFDataRef paramData) child = execTool(args); if (child > 0) { - int status; + int status = 0; waitpid(child, &status, 0); if (WIFEXITED(status)) err = WEXITSTATUS(status); diff --git a/mDNSResponder/mDNSMacOSX/Private/com.apple.mDNSResponder.plist b/mDNSResponder/mDNSMacOSX/Private/com.apple.mDNSResponder.plist new file mode 100644 index 00000000..6d403b52 --- /dev/null +++ b/mDNSResponder/mDNSMacOSX/Private/com.apple.mDNSResponder.plist @@ -0,0 +1,19 @@ + + + + + DEFAULT-OPTIONS + + Default-Privacy-Setting + Public + Level + + Persist + Inherit + Enable + Inherit + + + + + diff --git a/mDNSResponder/mDNSMacOSX/Private/dns_sd_private.h b/mDNSResponder/mDNSMacOSX/Private/dns_sd_private.h index e0b65cce..f3b480ea 100644 --- a/mDNSResponder/mDNSMacOSX/Private/dns_sd_private.h +++ b/mDNSResponder/mDNSMacOSX/Private/dns_sd_private.h @@ -1,5 +1,5 @@ /* -*- Mode: C; tab-width: 4 -*- - * + * * Copyright (c) 2015 Apple Inc. All rights reserved. */ @@ -29,4 +29,29 @@ */ DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid); +// Map the source port of the local UDP socket that was opened for sending the DNS query +// to the process ID of the application that triggered the DNS resolution. +// +/* DNSServiceGetPID() Parameters: + * + * srcport: Source port (in network byte order) of the UDP socket that was created by + * the daemon to send the DNS query on the wire. + * + * pid: Process ID of the application that started the name resolution which triggered + * the daemon to send the query on the wire. The value can be -1 if the srcport + * cannot be mapped. + * + * return value: Returns kDNSServiceErr_NoError on success, or kDNSServiceErr_ServiceNotRunning + * if the daemon is not running. The value of the pid is undefined if the return + * value has error. + */ +DNSServiceErrorType DNSSD_API DNSServiceGetPID +( + uint16_t srcport, + int32_t *pid +); + +#define kDNSServiceCompPrivateDNS "PrivateDNS" +#define kDNSServiceCompMulticastDNS "MulticastDNS" + #endif diff --git a/mDNSResponder/mDNSMacOSX/Private/dns_services.c b/mDNSResponder/mDNSMacOSX/Private/dns_services.c index 794e2526..46e2a23a 100644 --- a/mDNSResponder/mDNSMacOSX/Private/dns_services.c +++ b/mDNSResponder/mDNSMacOSX/Private/dns_services.c @@ -10,9 +10,7 @@ #include "dns_xpc.h" #include #include -#include - -#define LOG_NOW LOG_INFO +#include //************************************************************************************************************* // Globals @@ -41,7 +39,7 @@ static void LogDebug(const char *prefix, xpc_object_t o) return; char *desc = xpc_copy_description(o); - syslog(LOG_NOW, "%s: %s", prefix, desc); + os_log_info(OS_LOG_DEFAULT, "%s: %s", prefix, desc); free(desc); } @@ -51,7 +49,7 @@ void DNSXRefDeAlloc(DNSXConnRef connRef) { if (connRef == NULL) { - syslog(LOG_WARNING, "dns_services DD: DNSXRefDeAlloc called with NULL DNSXConnRef"); + os_log(OS_LOG_DEFAULT, "dns_services: DNSXRefDeAlloc called with NULL DNSXConnRef"); return; } @@ -63,18 +61,18 @@ void DNSXRefDeAlloc(DNSXConnRef connRef) dispatch_release(connRef->lib_q); connRef->lib_q = NULL; connRef->AppCallBack = NULL; - syslog(LOG_NOW, "dns_services DD: DNSXRefDeAlloc successfully DeAllocated conn_ref & lib_q"); + os_log_info(OS_LOG_DEFAULT, "dns_services: DNSXRefDeAlloc successfully DeAllocated conn_ref & lib_q"); dispatch_async((connRef)->client_q, ^{ dispatch_release(connRef->client_q); connRef->client_q = NULL; free(connRef); - syslog(LOG_NOW, "dns_services DD: DNSXRefDeAlloc successfully DeAllocated client_q & freed connRef"); + os_log_info(OS_LOG_DEFAULT, "dns_services: DNSXRefDeAlloc successfully DeAllocated client_q & freed connRef"); }); }); // DO NOT reference connRef after this comment, as it may have been freed - syslog(LOG_NOW, "dns_services DD: DNSXRefDeAlloc successfully DeAllocated connRef"); + os_log_info(OS_LOG_DEFAULT, "dns_services: DNSXRefDeAlloc successfully DeAllocated connRef"); } @@ -83,7 +81,7 @@ static DNSXErrorType SendMsgToServer(DNSXConnRef connRef, xpc_object_t msg) { DNSXErrorType errx = kDNSX_NoError; - LogDebug("dns_services DD: SendMsgToServer Sending msg to Daemon", msg); + LogDebug("dns_services: SendMsgToServer Sending msg to Daemon", msg); xpc_connection_send_message_with_reply((connRef)->conn_ref, msg, (connRef)->lib_q, ^(xpc_object_t recv_msg) { @@ -91,13 +89,13 @@ static DNSXErrorType SendMsgToServer(DNSXConnRef connRef, xpc_object_t msg) if (type == XPC_TYPE_DICTIONARY) { - LogDebug("dns_services DD: SendMsgToServer Received reply msg from Daemon", recv_msg); + LogDebug("dns_services: SendMsgToServer Received reply msg from Daemon", recv_msg); uint64_t daemon_status = xpc_dictionary_get_uint64(recv_msg, kDNSDaemonReply); if (connRef == NULL || connRef->client_q == NULL || connRef->AppCallBack == NULL) { // If connRef is bad, do not schedule any callbacks to the client - syslog(LOG_WARNING, "dns_services DD: SendMsgToServer: connRef is BAD Daemon status code [%llu]", daemon_status); + os_log(OS_LOG_DEFAULT, "dns_services: SendMsgToServer: connRef is BAD Daemon status code [%llu]", daemon_status); } else { @@ -110,14 +108,16 @@ static DNSXErrorType SendMsgToServer(DNSXConnRef connRef, xpc_object_t msg) }); break; - case kDNSMsg_BadArg: + case kDNSMsg_Busy: + os_log(OS_LOG_DEFAULT, "dns_services: SendMsgToServer: DNS Proxy already in use"); dispatch_async((connRef)->client_q, ^{ if (connRef->AppCallBack != NULL) - ((DNSXEnableProxyReply)connRef->AppCallBack)(connRef, kDNSX_BadParam); + ((DNSXEnableProxyReply)connRef->AppCallBack)(connRef, kDNSX_Busy); }); break; default: + os_log(OS_LOG_DEFAULT, "dns_services: SendMsgToServer: Unknown error"); dispatch_async((connRef)->client_q, ^{ if (connRef->AppCallBack != NULL) ((DNSXEnableProxyReply)connRef->AppCallBack)(connRef, kDNSX_UnknownErr); @@ -128,9 +128,9 @@ static DNSXErrorType SendMsgToServer(DNSXConnRef connRef, xpc_object_t msg) } else { - syslog(LOG_WARNING, "dns_services DD: SendMsgToServer Received unexpected reply from daemon [%s]", + os_log(OS_LOG_DEFAULT, "dns_services: SendMsgToServer Received unexpected reply from daemon [%s]", xpc_dictionary_get_string(recv_msg, XPC_ERROR_KEY_DESCRIPTION)); - LogDebug("dns_services DD: SendMsgToServer Unexpected Reply contents", recv_msg); + LogDebug("dns_services: SendMsgToServer Unexpected Reply contents", recv_msg); } }); @@ -141,13 +141,16 @@ static DNSXErrorType SendMsgToServer(DNSXConnRef connRef, xpc_object_t msg) static DNSXErrorType InitConnection(DNSXConnRef *connRefOut, const char *servname, dispatch_queue_t clientq, void *AppCallBack) { if (connRefOut == NULL) + { + os_log(OS_LOG_DEFAULT, "dns_services: InitConnection() connRef cannot be NULL"); return kDNSX_BadParam; + } // Use a DNSXConnRef on the stack to be captured in the blocks below, rather than capturing the DNSXConnRef* owned by the client DNSXConnRef connRef = malloc(sizeof(struct _DNSXConnRef_t)); if (connRef == NULL) { - syslog(LOG_WARNING, "dns_services DD: InitConnection() No memory to allocate!"); + os_log(OS_LOG_DEFAULT, "dns_services: InitConnection() No memory to allocate!"); return kDNSX_NoMem; } @@ -160,7 +163,7 @@ static DNSXErrorType InitConnection(DNSXConnRef *connRefOut, const char *servnam if (connRef->conn_ref == NULL || connRef->lib_q == NULL) { - syslog(LOG_WARNING, "dns_services DD: InitConnection() conn_ref/lib_q is NULL"); + os_log(OS_LOG_DEFAULT, "dns_services: InitConnection() conn_ref/lib_q is NULL"); if (connRef != NULL) free(connRef); return kDNSX_NoMem; @@ -171,12 +174,12 @@ static DNSXErrorType InitConnection(DNSXConnRef *connRefOut, const char *servnam if (connRef == NULL || connRef->client_q == NULL || connRef->AppCallBack == NULL) { // If connRef is bad, do not schedule any callbacks to the client - syslog(LOG_WARNING, "dns_services DD: InitConnection: connRef is BAD Unexpected Connection Error [%s]", + os_log(OS_LOG_DEFAULT, "dns_services: InitConnection: connRef is BAD Unexpected Connection Error [%s]", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION)); } else { - syslog(LOG_WARNING, "dns_services DD: InitConnection: Unexpected Connection Error [%s] Ping the client", + os_log(OS_LOG_DEFAULT, "dns_services: InitConnection: Unexpected Connection Error [%s] Ping the client", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION)); dispatch_async(connRef->client_q, ^{ if (connRef->AppCallBack != NULL) @@ -201,7 +204,7 @@ DNSXErrorType DNSXEnableProxy(DNSXConnRef *connRef, DNSProxyParameters proxypara // Sanity Checks if (connRef == NULL || callBack == NULL || clientq == NULL) { - syslog(LOG_WARNING, "dns_services DD: DNSXEnableProxy called with NULL DNSXConnRef OR Callback OR ClientQ parameter"); + os_log(OS_LOG_DEFAULT, "dns_services: DNSXEnableProxy called with NULL DNSXConnRef OR Callback OR ClientQ parameter"); return kDNSX_BadParam; } @@ -211,13 +214,13 @@ DNSXErrorType DNSXEnableProxy(DNSXConnRef *connRef, DNSProxyParameters proxypara errx = InitConnection(connRef, kDNSProxyService, clientq, callBack); if (errx) // On error InitConnection() leaves *connRef set to NULL { - syslog(LOG_WARNING, "dns_services DD: Since InitConnection() returned %d error returning w/o sending msg", errx); + os_log(OS_LOG_DEFAULT, "dns_services: Since InitConnection() returned %d error returning w/o sending msg", errx); return errx; } } else // Client already has a connRef and this is not valid use for this SPI { - syslog(LOG_WARNING, "dns_services DD: Client already has a valid connRef! This is incorrect usage from the client"); + os_log(OS_LOG_DEFAULT, "dns_services: Client already has a valid connRef! This is incorrect usage from the client"); return kDNSX_BadParam; } @@ -225,7 +228,7 @@ DNSXErrorType DNSXEnableProxy(DNSXConnRef *connRef, DNSProxyParameters proxypara xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); if (dict == NULL) { - syslog(LOG_WARNING, "dns_services DD: DNSXEnableProxy could not create the Msg Dict To Send!"); + os_log(OS_LOG_DEFAULT, "dns_services: DNSXEnableProxy could not create the Msg Dict To Send!"); DNSXRefDeAlloc(*connRef); return kDNSX_NoMem; } diff --git a/mDNSResponder/mDNSMacOSX/Private/dns_services.h b/mDNSResponder/mDNSMacOSX/Private/dns_services.h index 25b911f1..34c68756 100644 --- a/mDNSResponder/mDNSMacOSX/Private/dns_services.h +++ b/mDNSResponder/mDNSMacOSX/Private/dns_services.h @@ -22,7 +22,8 @@ typedef enum kDNSX_NoError = 0, kDNSX_UnknownErr = -65537, /* 0xFFFE FFFF */ kDNSX_NoMem = -65539, /* No Memory */ - kDNSX_BadParam = -65540, /* Client passes invalid arg/Bad use of SPI */ + kDNSX_BadParam = -65540, /* Client passed invalid arg */ + kDNSX_Busy = -65551, /* DNS Proxy already in use: incorrect use of SPI by client */ kDNSX_DaemonNotRunning = -65563 /* Daemon not running */ } DNSXErrorType; diff --git a/mDNSResponder/mDNSMacOSX/Private/dns_xpc.h b/mDNSResponder/mDNSMacOSX/Private/dns_xpc.h index 4c961a84..bda2bf92 100644 --- a/mDNSResponder/mDNSMacOSX/Private/dns_xpc.h +++ b/mDNSResponder/mDNSMacOSX/Private/dns_xpc.h @@ -11,6 +11,7 @@ #define DNS_XPC_H #define kDNSProxyService "com.apple.mDNSResponder.dnsproxy" +#define kDNSCTLService "com.apple.mDNSResponder.dnsctl" #define kDNSProxyParameters "DNSProxyParameters" @@ -27,7 +28,34 @@ typedef enum { kDNSMsg_NoError = 0, - kDNSMsg_BadArg + kDNSMsg_Busy } DaemonReplyStatusCodes; +#define kDNSLogLevel "DNSLoggingVerbosity" + +typedef enum +{ + log_level1 = 1, // logging off + log_level2, // logging USR1 + log_level3, // logging USR2 + log_level4, // logging USR1/2 +} DNSLogLevels; + +#define kDNSStateInfo "DNSStateInfoLevels" + +typedef enum +{ + full_state = 1, // full state info of mDNSResponder (INFO) +} DNSStateInfo; + +#define kmDNSResponderTests "mDNSResponderTests" + +typedef enum +{ + test_helper_ipc = 1, // invokes mDNSResponder to send a test msg to mDNSResponderHelper + test_mDNS_log, // invokes mDNSResponder to log using different internal macros +} mDNSTestModes; + + + #endif // DNS_XPC_H diff --git a/mDNSResponder/mDNSMacOSX/Private/dnsctl_server.c b/mDNSResponder/mDNSMacOSX/Private/dnsctl_server.c new file mode 100644 index 00000000..9b3885e6 --- /dev/null +++ b/mDNSResponder/mDNSMacOSX/Private/dnsctl_server.c @@ -0,0 +1,224 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2015 Apple Inc. All rights reserved. + * + * dnsctl_server.c + * mDNSResponder + * + * XPC as an IPC mechanism to communicate with dnsctl. Open only to Apple OSX/iOS clients + */ + +#include "xpc_services.h" +#include "dns_xpc.h" + +#include "mDNSMacOSX.h" // KQueueLock/KQueueUnlock +#include "helper.h" // mDNSResponderHelper tests +#include + +// *************************************************************************** +// Globals +extern mDNS mDNSStorage; +static dispatch_queue_t dnsctlserver_queue = NULL; +// *************************************************************************** + +mDNSlocal void handle_logging(mDNSu32 log_level) +{ + KQueueLock(&mDNSStorage); + + switch (log_level) + { + case log_level1: + mDNS_LoggingEnabled = mDNS_PacketLoggingEnabled = 0; + LogMsg("USR1 Logging:[%s] USR2 Logging:[%s]", mDNS_LoggingEnabled ? "Enabled" : "Disabled", mDNS_PacketLoggingEnabled ? "Enabled" : "Disabled"); + break; + + case log_level2: + mDNS_LoggingEnabled = 1; + LogMsg("USR1 Logging %s", mDNS_LoggingEnabled ? "Enabled" : "Disabled"); + break; + + case log_level3: + mDNS_PacketLoggingEnabled = 1; + LogMsg("USR2 Logging %s", mDNS_PacketLoggingEnabled ? "Enabled" : "Disabled"); + break; + + case log_level4: + mDNS_LoggingEnabled = 1 ; + mDNS_PacketLoggingEnabled = 1; + LogMsg("USR1 Logging:%s USR2 Logging:%s", mDNS_LoggingEnabled ? "Enabled" : "Disabled", mDNS_PacketLoggingEnabled ? "Enabled" : "Disabled"); + break; + + default: + mDNS_LoggingEnabled = 0 ; + mDNS_PacketLoggingEnabled = 0; + break; + } + UpdateDebugState(); + + KQueueUnlock(&mDNSStorage, "LogLevel changed"); +} + +mDNSlocal void handle_stateinfo(mDNSu32 state_level) +{ + KQueueLock(&mDNSStorage); + + switch (state_level) + { + case full_state: + INFOCallback(); + break; + + default: + INFOCallback(); + break; + } + + KQueueUnlock(&mDNSStorage, "StateInfo dumped"); +} + + +mDNSlocal void handle_test_mode(mDNSu32 test_mode) +{ + KQueueLock(&mDNSStorage); + + switch (test_mode) + { + case test_helper_ipc: + mDNSNotify("mDNSResponderHelperTest", "This is just a test message to mDNSResponderHelper. This is NOT an actual alert"); + break; + + case test_mDNS_log: + LogInfo("LogInfo: Should be logged at INFO level"); + LogOperation("LogOperation: Should be logged at INFO level"); + LogMsg("LogMsg: Should be logged at DEFAULT level"); + LogSPS("LogSPS: Should be logged at INFO level"); + break; + + default: + LogMsg("Unidentified Test mode: Please add this test"); + break; + } + + KQueueUnlock(&mDNSStorage, "Test Msg to mDNSResponderHelper"); +} + +mDNSlocal void handle_terminate() +{ + + LogInfo("handle_terminate: Client terminated connection."); + +} + +mDNSlocal void handle_requests(xpc_object_t req) +{ + mDNSu32 log_level, state_level, test_mode; + xpc_connection_t remote_conn = xpc_dictionary_get_remote_connection(req); + + LogInfo("handle_requests: Handler for dnsctl requests"); + + xpc_object_t response = xpc_dictionary_create_reply(req); + + // Return Success Status to the client (essentially ACKing the request) + if (response) + { + xpc_dictionary_set_uint64(response, kDNSDaemonReply, kDNSMsg_NoError); + xpc_connection_send_message(remote_conn, response); + xpc_release(response); + } + else + { + LogMsg("handle_requests: Response Dictionary could not be created"); + return; + } + + // switch here based on dictionary + // to handle various different requests like logging, INFO snapshot, etc.. + if ((xpc_dictionary_get_uint64(req, kDNSLogLevel))) + { + log_level = (mDNSu32)(xpc_dictionary_get_uint64(req, kDNSLogLevel)); + handle_logging(log_level); + } + else if ((xpc_dictionary_get_uint64(req, kDNSStateInfo))) + { + state_level = (mDNSu32)(xpc_dictionary_get_uint64(req, kDNSStateInfo)); + handle_stateinfo(state_level); + } + else if ((xpc_dictionary_get_uint64(req, kmDNSResponderTests))) + { + test_mode = (mDNSu32)(xpc_dictionary_get_uint64(req, kmDNSResponderTests)); + handle_test_mode(test_mode); + } +} + +mDNSlocal void accept_client(xpc_connection_t conn) +{ + uid_t c_euid; + int c_pid; + c_euid = xpc_connection_get_euid(conn); + c_pid = xpc_connection_get_pid(conn); + + if (c_euid != 0 || !IsEntitled(conn, kDNSCTLService)) + { + LogMsg("accept_client: Client PID[%d] is missing Entitlement or is NOT running as root!", c_pid); + xpc_connection_cancel(conn); + return; + } + + xpc_retain(conn); + xpc_connection_set_target_queue(conn, dnsctlserver_queue); + xpc_connection_set_event_handler(conn, ^(xpc_object_t req_msg) + { + xpc_type_t type = xpc_get_type(req_msg); + + if (type == XPC_TYPE_DICTIONARY) + { + handle_requests(req_msg); + } + else // We hit this case ONLY if Client Terminated Connection OR Crashed + { + LogInfo("accept_client: Client %p teared down the connection", (void *) conn); + handle_terminate(); + xpc_release(conn); + } + }); + + xpc_connection_resume(conn); + +} + +mDNSexport void init_dnsctl_service(void) +{ + + xpc_connection_t dnsctl_listener = xpc_connection_create_mach_service(kDNSCTLService, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER); + if (!dnsctl_listener || xpc_get_type(dnsctl_listener) != XPC_TYPE_CONNECTION) + { + LogMsg("init_dnsctl_service: Error Creating XPC Listener for DNSCTL Server!"); + return; + } + + dnsctlserver_queue = dispatch_queue_create("com.apple.mDNSResponder.dnsctlserver_queue", NULL); + + xpc_connection_set_event_handler(dnsctl_listener, ^(xpc_object_t eventmsg) + { + xpc_type_t type = xpc_get_type(eventmsg); + + if (type == XPC_TYPE_CONNECTION) + { + LogInfo("init_dnsctl_service: New DNSCTL Client %p", eventmsg); + accept_client(eventmsg); + } + else if (type == XPC_TYPE_ERROR) // Ideally, we would never hit these cases + { + LogMsg("init_dnsctl_service: XPCError: %s", xpc_dictionary_get_string(eventmsg, XPC_ERROR_KEY_DESCRIPTION)); + } + else + { + LogMsg("init_dnsctl_service: Unknown EventMsg type"); + } + }); + + xpc_connection_resume(dnsctl_listener); +} + + + diff --git a/mDNSResponder/mDNSMacOSX/Private/xpc_services.c b/mDNSResponder/mDNSMacOSX/Private/xpc_services.c index fb357806..4cad6ba0 100644 --- a/mDNSResponder/mDNSMacOSX/Private/xpc_services.c +++ b/mDNSResponder/mDNSMacOSX/Private/xpc_services.c @@ -15,8 +15,7 @@ #include "dnsproxy.h" // DNSProxyInit/ProxyUDPCallback/ProxyTCPCallback #include "mDNSMacOSX.h" // KQueueLock/KQueueUnlock -#include -#include // xpc_connection_copy_entitlement_value +#include // xpc_connection_copy_entitlement_value // *************************************************************************** // Globals @@ -87,10 +86,10 @@ mDNSlocal void handle_dps_request(xpc_object_t req) { LogMsg("handle_dps_request: A Client is already using DNS Proxy and your request cannot be handled at this time"); // Return Engaged Status to the client - xpc_object_t reply = xpc_dictionary_create(NULL, NULL, 0); + xpc_object_t reply = xpc_dictionary_create_reply(req); if (reply) { - xpc_dictionary_set_uint64(reply, kDNSDaemonReply, kDNSMsg_BadArg); + xpc_dictionary_set_uint64(reply, kDNSDaemonReply, kDNSMsg_Busy); xpc_connection_send_message(remote_conn, reply); xpc_release(reply); } @@ -138,7 +137,7 @@ mDNSlocal void handle_dps_request(xpc_object_t req) } // Verify Client's Entitlement -mDNSlocal mDNSBool IsEntitled(xpc_connection_t conn, const char *password) +mDNSexport mDNSBool IsEntitled(xpc_connection_t conn, const char *password) { mDNSBool entitled = mDNSfalse; xpc_object_t ent = xpc_connection_copy_entitlement_value(conn, password); @@ -157,7 +156,7 @@ mDNSlocal mDNSBool IsEntitled(xpc_connection_t conn, const char *password) } if (!entitled) - LogMsg("IsEntitled: DNSProxyService Client is missing Entitlement!"); + LogMsg("IsEntitled: Client is missing Entitlement!"); return entitled; } @@ -241,8 +240,10 @@ mDNSexport void xpc_server_init() { // Add XPC Services here init_dnsproxy_service(); + init_dnsctl_service(); } + #else // !UNICAST_DISABLED mDNSexport void xpc_server_init() diff --git a/mDNSResponder/mDNSMacOSX/Private/xpc_services.h b/mDNSResponder/mDNSMacOSX/Private/xpc_services.h index 50081bed..8d7c0433 100644 --- a/mDNSResponder/mDNSMacOSX/Private/xpc_services.h +++ b/mDNSResponder/mDNSMacOSX/Private/xpc_services.h @@ -14,8 +14,14 @@ #define XPC_SERVICES_H #include "mDNSEmbeddedAPI.h" +#include extern void xpc_server_init(void); extern void xpcserver_info(mDNS *const m); +extern mDNSBool IsEntitled(xpc_connection_t conn, const char *password); +extern void init_dnsctl_service(void); + +extern void INFOCallback(void); + #endif // XPC_SERVICES_H diff --git a/mDNSResponder/mDNSMacOSX/SymptomReporter.c b/mDNSResponder/mDNSMacOSX/SymptomReporter.c index 39ce0d41..7dde2f5e 100644 --- a/mDNSResponder/mDNSMacOSX/SymptomReporter.c +++ b/mDNSResponder/mDNSMacOSX/SymptomReporter.c @@ -22,7 +22,16 @@ #include #include #include +#include +#include + +#define TARGET_OS_MACOSX (TARGET_OS_MAC && !TARGET_OS_IPHONE) + +#if (!TARGET_OS_MACOSX || (MAC_OS_X_VERSION_MAX_ALLOWED >= 101200)) +#include +#else #include +#endif #define SYMPTOM_REPORTER_mDNSResponder_NUMERIC_ID 101 #define SYMPTOM_REPORTER_mDNSResponder_TEXT_ID "com.apple.mDNSResponder" @@ -30,7 +39,7 @@ #define SYMPTOM_DNS_NO_REPLIES 0x00065001 #define SYMPTOM_DNS_RESUMED_RESPONDING 0x00065002 -static symptom_framework_t symptomReporter; +static symptom_framework_t symptomReporter = mDNSNULL; static symptom_framework_t (*symptom_framework_init_f)(symptom_ident_t id, const char *originator_string) = mDNSNULL; static symptom_t (*symptom_new_f)(symptom_framework_t framework, symptom_ident_t id) = mDNSNULL; static int (*symptom_set_additional_qualifier_f)(symptom_t symptom, uint32_t qualifier_type, size_t qualifier_len, void *qualifier_data) = mDNSNULL; @@ -39,53 +48,43 @@ static int (*symptom_send_f)(symptom_t symptom) = mDNSNULL; mDNSlocal mStatus SymptomReporterInitCheck(void) { mStatus err; - static mDNSBool isInitialized = mDNSfalse; + static mDNSBool triedInit = mDNSfalse; static void *symptomReporterLib = mDNSNULL; +#if (!TARGET_OS_MACOSX || (MAC_OS_X_VERSION_MAX_ALLOWED >= 101200)) + static const char path[] = "/System/Library/PrivateFrameworks/SymptomReporter.framework/SymptomReporter"; +#else static const char path[] = "/System/Library/PrivateFrameworks/Symptoms.framework/Frameworks/SymptomReporter.framework/SymptomReporter"; +#endif - if (!isInitialized) + if (!triedInit) { + triedInit = mDNStrue; + + symptomReporterLib = dlopen(path, RTLD_LAZY | RTLD_LOCAL); if (!symptomReporterLib) - { - symptomReporterLib = dlopen(path, RTLD_LAZY | RTLD_LOCAL); - if (!symptomReporterLib) - goto exit; - } + goto exit; + symptom_framework_init_f = dlsym(symptomReporterLib, "symptom_framework_init"); if (!symptom_framework_init_f) - { - symptom_framework_init_f = dlsym(symptomReporterLib, "symptom_framework_init"); - if (!symptom_framework_init_f) - goto exit; - } + goto exit; + symptom_new_f = dlsym(symptomReporterLib, "symptom_new"); if (!symptom_new_f) - { - symptom_new_f = dlsym(symptomReporterLib, "symptom_new"); - if (!symptom_new_f) - goto exit; - } + goto exit; + symptom_set_additional_qualifier_f = dlsym(symptomReporterLib, "symptom_set_additional_qualifier"); if (!symptom_set_additional_qualifier_f) - { - symptom_set_additional_qualifier_f = dlsym(symptomReporterLib, "symptom_set_additional_qualifier"); - if (!symptom_set_additional_qualifier_f) - goto exit; - } + goto exit; + symptom_send_f = dlsym(symptomReporterLib, "symptom_send"); if (!symptom_send_f) - { - symptom_send_f = dlsym(symptomReporterLib, "symptom_send"); - if (!symptom_send_f) - goto exit; - } + goto exit; symptomReporter = symptom_framework_init_f(SYMPTOM_REPORTER_mDNSResponder_NUMERIC_ID, SYMPTOM_REPORTER_mDNSResponder_TEXT_ID); - isInitialized = mDNStrue; } exit: - err = isInitialized ? mStatus_NoError : mStatus_NotInitializedErr; + err = symptomReporter ? mStatus_NoError : mStatus_NotInitializedErr; return err; } diff --git a/mDNSResponder/mDNSMacOSX/com.apple.dnsextd.plist b/mDNSResponder/mDNSMacOSX/com.apple.dnsextd.plist index e31b391f..86d7b777 100644 --- a/mDNSResponder/mDNSMacOSX/com.apple.dnsextd.plist +++ b/mDNSResponder/mDNSMacOSX/com.apple.dnsextd.plist @@ -6,8 +6,6 @@ Label com.apple.dnsextd - OnDemand - ProgramArguments /usr/sbin/dnsextd diff --git a/mDNSResponder/mDNSMacOSX/com.apple.mDNSResponder.plist b/mDNSResponder/mDNSMacOSX/com.apple.mDNSResponder.plist index 8f5a6408..881f8c9e 100644 --- a/mDNSResponder/mDNSMacOSX/com.apple.mDNSResponder.plist +++ b/mDNSResponder/mDNSMacOSX/com.apple.mDNSResponder.plist @@ -1,11 +1,9 @@ - + Label com.apple.mDNSResponder.reloaded - OnDemand - InitGroups UserName @@ -18,10 +16,10 @@ MachServices - com.apple.mDNSResponder + com.apple.mDNSResponder.dnsproxy + + com.apple.mDNSResponder.dnsctl - com.apple.mDNSResponder.dnsproxy - Sockets diff --git a/mDNSResponder/mDNSMacOSX/com.apple.mDNSResponderHelper.plist b/mDNSResponder/mDNSMacOSX/com.apple.mDNSResponderHelper.plist index f1e3027b..91ed1da3 100644 --- a/mDNSResponder/mDNSMacOSX/com.apple.mDNSResponderHelper.plist +++ b/mDNSResponder/mDNSMacOSX/com.apple.mDNSResponderHelper.plist @@ -12,7 +12,7 @@ MachServices - com.apple.mDNSResponderHelper + com.apple.mDNSResponder_Helper POSIXSpawnType diff --git a/mDNSResponder/mDNSMacOSX/com.apple.networking.mDNSResponder b/mDNSResponder/mDNSMacOSX/com.apple.networking.mDNSResponder deleted file mode 100644 index d07c99d0..00000000 --- a/mDNSResponder/mDNSMacOSX/com.apple.networking.mDNSResponder +++ /dev/null @@ -1 +0,0 @@ -? [= LoggerID com.apple.networking.mDNSResponder] file /Library/Logs/CrashReporter/com.apple.networking.mDNSResponder.log rotate file_max=1M compress diff --git a/mDNSResponder/mDNSMacOSX/coreBLE.h b/mDNSResponder/mDNSMacOSX/coreBLE.h new file mode 100644 index 00000000..cc00923a --- /dev/null +++ b/mDNSResponder/mDNSMacOSX/coreBLE.h @@ -0,0 +1,32 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2015-2016 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. + */ + +#ifndef _coreBLE_H_ +#define _coreBLE_H_ + +#include "BLE.h" + +@interface coreBLE : NSObject + +- (id)init; +- (void) advertiseBrowses:(serviceHash_t) browseHash andRegistrations:(serviceHash_t) registeredHash; +- (void) stopBeacon; +- (void) updateScan:(bool) start; + +@end + +#endif /* _coreBLE_H_ */ diff --git a/mDNSResponder/mDNSMacOSX/coreBLE.m b/mDNSResponder/mDNSMacOSX/coreBLE.m new file mode 100644 index 00000000..e764169a --- /dev/null +++ b/mDNSResponder/mDNSMacOSX/coreBLE.m @@ -0,0 +1,371 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2015-2016 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 "mDNSEmbeddedAPI.h" +#include "DNSCommon.h" + +#import +#import +#import +#import "mDNSMacOSX.h" +#import "BLE.h" +#import "coreBLE.h" + +static coreBLE * coreBLEptr; + +// Call Bluetooth subsystem to start/stop the the Bonjour BLE beacon and +// beacon scanning based on the current browse and registration hashes. +void updateBLEBeaconAndScan(serviceHash_t browseHash, serviceHash_t registeredHash) +{ + if (coreBLEptr == 0) + coreBLEptr = [[coreBLE alloc] init]; + + LogInfo("updateBLEBeaconAndScan: browseHash = 0x%x, registeredHash = 0x%x", browseHash, registeredHash); + + [coreBLEptr advertiseBrowses:browseHash andRegistrations: registeredHash]; + [coreBLEptr updateScan:(browseHash || registeredHash)]; +} + +// Stop the current BLE beacon. +void stopBLEBeacon(void) +{ + if (coreBLEptr == 0) + { + LogInfo("stopBLEBeacon called before BLE scan initialized ??"); + return; + } + + LogInfo("stopBLEBeacon Stopping beacon"); + [coreBLEptr stopBeacon]; +} + +@implementation coreBLE +{ + CBCentralManager *_centralManager; + CBPeripheralManager *_peripheralManager; + + NSData *_currentlyAdvertisedData; + + // [_centralManager isScanning] is only avilable on iOS and not OSX, + // so track scanning state locally. + BOOL _isScanning; +} + +- (id)init +{ + self = [super init]; + + if (self) + { + _centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()]; + _peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()]; + _currentlyAdvertisedData = nil; + _isScanning = NO; + + if (_centralManager == nil || _peripheralManager == nil ) + { + LogMsg("coreBLE initialization failed!"); + } + else + { + LogInfo("coreBLE initialised"); + } + } + + return self; +} + +#define ADVERTISEMENTDATALENGTH 28 // 31 - 3 (3 bytes for flags) + +// TODO: +// DBDeviceTypeBonjour should eventually be added to the DBDeviceType definitions in WirelessProximity +// The Bluetooth team recommended using a value < 32 for prototyping, since 32 is the number of +// beacon types they can track in their duplicate beacon filtering logic. +#define DBDeviceTypeBonjour 26 + +// Beacon flags and version byte +#define BonjourBLEVersion 1 + +extern mDNS mDNSStorage; +extern mDNSInterfaceID AWDLInterfaceID; + +// Transmit the last beacon indicating we are no longer advertising or browsing any services for two seconds. +#define LastBeaconTime 2 + +- (void) advertiseBrowses:(serviceHash_t) browseHash andRegistrations:(serviceHash_t) registeredHash +{ + uint8_t advertisingData[ADVERTISEMENTDATALENGTH] = {0, 0xff, 0x4c, 0x00 }; + uint8_t advertisingLength = 4; + + // TODO: If we have been transmitting a beacon, we probably want to continue transmitting + // for a few seconds after both hashes are zero so that that any devices scanning + // can see the beacon indicating we have stopped all browses and advertisements. + + // Stop the beacon if there is no data to advertise. + if (browseHash == 0 && registeredHash == 0) + { + LogInfo("advertiseBrowses:andRegistrations Stopping beacon in %d seconds", LastBeaconTime); + if (mDNSStorage.NextBLEServiceTime) + LogInfo("advertiseBrowses:andRegistrations: NextBLEServiceTime already set ??"); + + mDNSStorage.NextBLEServiceTime = NonZeroTime(mDNS_TimeNow_NoLock(& mDNSStorage) + LastBeaconTime * mDNSPlatformOneSecond); + } + else + { + mDNSStorage.NextBLEServiceTime = 0; + } + + // The beacon type. + advertisingData[advertisingLength++] = DBDeviceTypeBonjour; + + // Flags and Version field + advertisingData[advertisingLength++] = BonjourBLEVersion; + + memcpy(& advertisingData[advertisingLength], & browseHash, sizeof(serviceHash_t)); + advertisingLength += sizeof(serviceHash_t); + memcpy(& advertisingData[advertisingLength], & registeredHash, sizeof(serviceHash_t)); + advertisingLength += sizeof(serviceHash_t); + + + // Add the MAC address of the awdl0 interface. Don't cache it since + // it can get updated periodically. + if (AWDLInterfaceID) + { + NetworkInterfaceInfoOSX *intf = IfindexToInterfaceInfoOSX(& mDNSStorage, AWDLInterfaceID); + if (intf) + memcpy(& advertisingData[advertisingLength], & intf->ifinfo.MAC, sizeof(mDNSEthAddr)); + else + memset( & advertisingData[advertisingLength], 0, sizeof(mDNSEthAddr)); + } + else + { + // just use zero if not avaiblable + memset( & advertisingData[advertisingLength], 0, sizeof(mDNSEthAddr)); + } + advertisingLength += sizeof(mDNSEthAddr); + + // Total length of data advertised, minus this lenght byte. + advertisingData[0] = (advertisingLength - 1); + + LogInfo("advertiseBrowses:andRegistrations advertisingLength = %d", advertisingLength); + + NSData* data = [NSData dataWithBytes:advertisingData length:advertisingLength]; + + if([_peripheralManager isAdvertising] && [data isEqualToData: _currentlyAdvertisedData]) + { + // No need to restart the advertisement if it is already active with the same data. + LogInfo("advertiseBrowses:andRegistrations: No change in advertised data"); + } + else + { + _currentlyAdvertisedData = data; + + if ([_peripheralManager isAdvertising]) + { + LogInfo("advertiseBrowses:andRegistrations: Stop current advertisement before restarting"); + [_peripheralManager stopAdvertising]; + } + LogInfo("advertiseBrowses:andRegistrations: Starting beacon"); + + [_peripheralManager startAdvertising:@{ CBAdvertisementDataAppleMfgData : _currentlyAdvertisedData, CBCentralManagerScanOptionIsPrivilegedDaemonKey : @YES, @"kCBAdvOptionUseFGInterval" : @YES }]; + } +} + +- (void) stopBeacon +{ + [_peripheralManager stopAdvertising]; +} + +- (void) updateScan:(bool) start +{ + if (_isScanning) + { + if (!start) + { + LogInfo("updateScan: stopping scan"); + [_centralManager stopScan]; + _isScanning = NO; + } + } + else + { + if (start) + { + LogInfo("updateScan: starting scan"); + + _isScanning = YES; + [_centralManager scanForPeripheralsWithServices:nil options:@{ CBCentralManagerScanOptionAllowDuplicatesKey : @NO }]; + } + } +} + +#pragma mark - CBCentralManagerDelegate protocol + +- (void)centralManagerDidUpdateState:(CBCentralManager *)central +{ + switch (central.state) { + case CBCentralManagerStateUnknown: + LogInfo("centralManagerDidUpdateState: CBCentralManagerStateUnknown"); + break; + + case CBCentralManagerStateResetting: + LogInfo("centralManagerDidUpdateState: CBCentralManagerStateResetting"); + break; + + case CBCentralManagerStateUnsupported: + LogInfo("centralManagerDidUpdateState: CBCentralManagerStateUnsupported"); + break; + + case CBCentralManagerStateUnauthorized: + LogInfo("centralManagerDidUpdateState: CBCentralManagerStateUnauthorized"); + break; + + case CBCentralManagerStatePoweredOff: + LogInfo("centralManagerDidUpdateState: CBCentralManagerStatePoweredOff"); + break; + + case CBCentralManagerStatePoweredOn: + LogInfo("centralManagerDidUpdateState: CBCentralManagerStatePoweredOn"); + break; + + default: + LogInfo("centralManagerDidUpdateState: Unknown state ??"); + break; + } +} + +// offset of beacon type in recieved CBAdvertisementDataManufacturerDataKey bytes +#define beaconTypeByteIndex 2 + +- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI +{ + (void) central; + (void) peripheral; + (void) RSSI; + + NSData *data = [advertisementData objectForKey:CBAdvertisementDataManufacturerDataKey]; + + if (!data) { + return; + } + + unsigned char *bytes = (unsigned char *)data.bytes; + + // Just parse the DBDeviceTypeBonjour beacons. + if (bytes[beaconTypeByteIndex] == DBDeviceTypeBonjour) + { + serviceHash_t browseHash, registeredHash; + mDNSEthAddr senderMAC; + unsigned char flagsAndVersion; + unsigned char *ptr; + +#if VERBOSE_BLE_DEBUG + LogInfo("didDiscoverPeripheral: received DBDeviceTypeBonjour beacon, length = %d", [data length]); + LogInfo("didDiscoverPeripheral: central = 0x%x, peripheral = 0x%x", central, peripheral); +#endif // VERBOSE_BLE_DEBUG + + // The DBDeviceTypeBonjour beacon bytes will be: + // x4C, 0x0, 0x2A, flags_and_version_byte,, browseHash, advertisingServices_hash_bytes, + // 6_bytes_of_sender_AWDL_MAC_address + + ptr = & bytes[beaconTypeByteIndex + 1]; + flagsAndVersion = *ptr++; + memcpy(& browseHash, ptr, sizeof(serviceHash_t)); + ptr += sizeof(serviceHash_t); + memcpy(& registeredHash, ptr, sizeof(serviceHash_t)); + ptr += sizeof(serviceHash_t); + memcpy(& senderMAC, ptr, sizeof(senderMAC)); + +#if VERBOSE_BLE_DEBUG + LogInfo("didDiscoverPeripheral: version = 0x%x, browseHash = 0x%x, registeredHash = 0x%x", + flagsAndVersion, browseHash, registeredHash); + LogInfo("didDiscoverPeripheral: sender MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", + senderMAC.b[0], senderMAC.b[1], senderMAC.b[2], senderMAC.b[3], senderMAC.b[4], senderMAC.b[5]); +#else + (void)flagsAndVersion; // Unused +#endif // VERBOSE_BLE_DEBUG + + responseReceived(browseHash, registeredHash, & senderMAC); + +#if VERBOSE_BLE_DEBUG + // Log every 4th package during debug + static int pkgsIn = 0; + + if (((pkgsIn++) & 3) == 0) + { + LogInfo("0x%x 0x%x 0x%x 0x%x 0x%x", bytes[0], bytes[1], bytes[2], bytes[3], bytes[4]); +// LogInfo("0x%x 0x%x 0x%x 0x%x 0x%x", bytes[5], bytes[6], bytes[7], bytes[9], bytes[9]); +// LogInfo("0x%x 0x%x 0x%x 0x%x 0x%x", bytes[10], bytes[11], bytes[12], bytes[13], bytes[14]); +// LogInfo("0x%x 0x%x 0x%x 0x%x 0x%x", bytes[15], bytes[16], bytes[17], bytes[18], bytes[19]); + } +#endif // VERBOSE_BLE_DEBUG + + } +} + +#pragma mark - CBPeripheralManagerDelegate protocol + +- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral +{ + + switch (peripheral.state) { + case CBPeripheralManagerStateUnknown: + LogInfo("peripheralManagerDidUpdateState: CBPeripheralManagerStateUnknown"); + break; + + case CBPeripheralManagerStateResetting: + LogInfo("peripheralManagerDidUpdateState: CBPeripheralManagerStateResetting"); + break; + + case CBPeripheralManagerStateUnsupported: + LogInfo("peripheralManagerDidUpdateState: CBPeripheralManagerStateUnsupported"); + break; + + case CBPeripheralManagerStateUnauthorized: + LogInfo("peripheralManagerDidUpdateState: CBPeripheralManagerStateUnauthorized"); + break; + + case CBPeripheralManagerStatePoweredOff: + LogInfo("peripheralManagerDidUpdateState: CBPeripheralManagerStatePoweredOff"); + break; + + case CBPeripheralManagerStatePoweredOn: + LogInfo("peripheralManagerDidUpdateState: CBPeripheralManagerStatePoweredOn"); + break; + + default: + LogInfo("peripheralManagerDidUpdateState: Unknown state ??"); + break; + } +} + +- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(nullable NSError *)error +{ + (void) peripheral; + + if (error) + { + const char * errorString = [[error localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]; + LogInfo("peripheralManagerDidStartAdvertising: error = %s", errorString ? errorString: "unknown"); + } + else + { + LogInfo("peripheralManagerDidStartAdvertising:"); + } +} + +@end diff --git a/mDNSResponder/mDNSMacOSX/daemon.c b/mDNSResponder/mDNSMacOSX/daemon.c index c1cabb1a..f5478b57 100644 --- a/mDNSResponder/mDNSMacOSX/daemon.c +++ b/mDNSResponder/mDNSMacOSX/daemon.c @@ -30,14 +30,8 @@ #include #include #include -#include -#include #include #include -#include // for bootstrap_check_in() - -#include "DNSServiceDiscoveryRequestServer.h" -#include "DNSServiceDiscoveryReply.h" #include "uDNS.h" #include "DNSCommon.h" @@ -45,35 +39,30 @@ #include "uds_daemon.h" // Interface to the server side implementation of dns_sd.h #include "xpc_services.h" // Interface to XPC services - -#include "../mDNSMacOSX/DNSServiceDiscovery.h" #include "helper.h" #if TARGET_OS_EMBEDDED #include "Metrics.h" #endif -static aslclient log_client = NULL; -static aslmsg log_msg = NULL; - -// Used on iOS ONLY for reading mDNSResponder Managed Preferences Profile -#if TARGET_OS_EMBEDDED -#define kmDNSEnableLoggingStr CFSTR("EnableLogging") -#define kmDNSResponderPrefIDStr "com.apple.mDNSResponder.plist" -#define kmDNSResponderPrefID CFSTR(kmDNSResponderPrefIDStr) +#if APPLE_OSX_mDNSResponder +static os_log_t log_general = NULL; #endif // Used on OSX(10.11.x onwards) for manipulating mDNSResponder program arguments -#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED +#if APPLE_OSX_mDNSResponder // plist file to read the user's preferences -#define kProgramArguments CFSTR("/Library/Preferences/com.apple.mDNSResponder.plist") +#define kProgramArguments CFSTR("com.apple.mDNSResponder") // possible arguments for external customers -#define kDebugLogging CFSTR("DebugLogging") -#define kUnicastPacketLogging CFSTR("UnicastPacketLogging") -#define kAlwaysAppendSearchDomains CFSTR("AlwaysAppendSearchDomains") -#define kNoMulticastAdvertisements CFSTR("NoMulticastAdvertisements") -#define kStrictUnicastOrdering CFSTR("StrictUnicastOrdering") +#define kPreferencesKey_DebugLogging CFSTR("DebugLogging") +#define kPreferencesKey_UnicastPacketLogging CFSTR("UnicastPacketLogging") +#define kPreferencesKey_AlwaysAppendSearchDomains CFSTR("AlwaysAppendSearchDomains") +#define kPreferencesKey_NoMulticastAdvertisements CFSTR("NoMulticastAdvertisements") +#define kPreferencesKey_StrictUnicastOrdering CFSTR("StrictUnicastOrdering") +#define kPreferencesKey_OfferSleepProxyService CFSTR("OfferSleepProxyService") +#define kPreferencesKey_UseInternalSleepProxy CFSTR("UseInternalSleepProxy") +#define kPreferencesKey_EnableBLEBasedDiscovery CFSTR("EnableBLEBasedDiscovery") #endif //************************************************************************************************************* @@ -91,124 +80,21 @@ static mDNS_PlatformSupport PlatformStorage; static CacheEntity rrcachestorage[RR_CACHE_SIZE]; struct CompileTimeAssertionChecks_RR_CACHE_SIZE { char a[(RR_CACHE_SIZE >= 141) ? 1 : -1]; }; -static mach_port_t m_port = MACH_PORT_NULL; #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM mDNSlocal void PrepareForIdle(void *m_param); #else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM -static mach_port_t client_death_port = MACH_PORT_NULL; static mach_port_t signal_port = MACH_PORT_NULL; #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM static dnssd_sock_t *launchd_fds = mDNSNULL; static size_t launchd_fds_count = 0; -// mDNS Mach Message Timeout, in milliseconds. -// We need this to be short enough that we don't deadlock the mDNSResponder if a client -// fails to service its mach message queue, but long enough to give a well-written -// client a chance to service its mach message queue without getting cut off. -// Empirically, 50ms seems to work, so we set the timeout to 250ms to give -// even extra-slow clients a fair chance before we cut them off. -#define MDNS_MM_TIMEOUT 250 - -static mDNSBool advertise = mDNS_Init_AdvertiseLocalAddresses; // By default, advertise addresses (& other records) via multicast +static mDNSBool NoMulticastAdvertisements = mDNSfalse; // By default, advertise addresses (& other records) via multicast extern mDNSBool StrictUnicastOrdering; extern mDNSBool AlwaysAppendSearchDomains; - -//************************************************************************************************************* -#if COMPILER_LIKES_PRAGMA_MARK -#pragma mark - -#pragma mark - Active client list structures -#endif - -typedef struct DNSServiceDomainEnumeration_struct DNSServiceDomainEnumeration; -struct DNSServiceDomainEnumeration_struct -{ - DNSServiceDomainEnumeration *next; - mach_port_t ClientMachPort; - DNSQuestion dom; // Question asking for domains - DNSQuestion def; // Question asking for default domain -}; - -typedef struct DNSServiceBrowserResult_struct DNSServiceBrowserResult; -struct DNSServiceBrowserResult_struct -{ - DNSServiceBrowserResult *next; - int resultType; - domainname result; -}; - -typedef struct DNSServiceBrowser_struct DNSServiceBrowser; - -typedef struct DNSServiceBrowserQuestion -{ - struct DNSServiceBrowserQuestion *next; - DNSQuestion q; - domainname domain; -} DNSServiceBrowserQuestion; - -struct DNSServiceBrowser_struct -{ - DNSServiceBrowser *next; - mach_port_t ClientMachPort; - DNSServiceBrowserQuestion *qlist; - DNSServiceBrowserResult *results; - mDNSs32 lastsuccess; - mDNSBool DefaultDomain; // was the browse started on an explicit domain? - domainname type; // registration type -}; - -typedef struct DNSServiceResolver_struct DNSServiceResolver; -struct DNSServiceResolver_struct -{ - DNSServiceResolver *next; - mach_port_t ClientMachPort; - ServiceInfoQuery q; - ServiceInfo i; - mDNSs32 ReportTime; -}; - -// A single registered service: ServiceRecordSet + bookkeeping -// Note that we duplicate some fields from parent DNSServiceRegistration object -// to facilitate cleanup, when instances and parent may be deallocated at different times. -typedef struct ServiceInstance -{ - struct ServiceInstance *next; - mach_port_t ClientMachPort; - mDNSBool autoname; // Set if this name is tied to the Computer Name - mDNSBool renameonmemfree; // Set if we just got a name conflict and now need to automatically pick a new name - domainlabel name; - domainname domain; - ServiceRecordSet srs; - // Don't add any fields after ServiceRecordSet. - // This is where the implicit extra space goes if we allocate an oversized ServiceRecordSet object -} ServiceInstance; - -// A client-created service. May reference several ServiceInstance objects if default -// settings cause registration in multiple domains. -typedef struct DNSServiceRegistration -{ - struct DNSServiceRegistration *next; - mach_port_t ClientMachPort; - mDNSBool DefaultDomain; - mDNSBool autoname; - size_t rdsize; - int NumSubTypes; - char regtype[MAX_ESCAPED_DOMAIN_NAME]; // for use in AllocateSubtypes - domainlabel name; // used only if autoname is false - domainname type; - mDNSIPPort port; - unsigned char txtinfo[1024]; - size_t txt_len; - uint32_t NextRef; - ServiceInstance *regs; -} DNSServiceRegistration; - -static DNSServiceDomainEnumeration *DNSServiceDomainEnumerationList = NULL; -static DNSServiceBrowser *DNSServiceBrowserList = NULL; -static DNSServiceResolver *DNSServiceResolverList = NULL; -static DNSServiceRegistration *DNSServiceRegistrationList = NULL; +extern mDNSBool EnableBLEBasedDiscovery; // We keep a list of client-supplied event sources in KQSocketEventSource records typedef struct KQSocketEventSource @@ -230,15 +116,12 @@ static KQSocketEventSource *gEventSources; char _malloc_options[] = "AXZ"; -mDNSlocal void validatelists(mDNS *const m, bool checkCRActiveQuestion) +mDNSlocal void validatelists(mDNS *const m) { -#if TARGET_OS_WATCH +#if BONJOUR_ON_DEMAND mDNSu32 NumAllInterfaceRecords = 0; mDNSu32 NumAllInterfaceQuestions = 0; -#else - mDNSu32 NumAllInterfaceRecords = 1; - mDNSu32 NumAllInterfaceQuestions = 1; -#endif +#endif // BONJOUR_ON_DEMAND // Check local lists KQSocketEventSource *k; @@ -246,27 +129,6 @@ mDNSlocal void validatelists(mDNS *const m, bool checkCRActiveQuestion) if (k->next == (KQSocketEventSource *)~0 || k->fd < 0) LogMemCorruption("gEventSources: %p is garbage (%d)", k, k->fd); - // Check Mach client lists - DNSServiceDomainEnumeration *e; - for (e = DNSServiceDomainEnumerationList; e; e=e->next) - if (e->next == (DNSServiceDomainEnumeration *)~0 || e->ClientMachPort == 0 || e->ClientMachPort == (mach_port_t) ~0) - LogMemCorruption("DNSServiceDomainEnumerationList: %p is garbage (%X)", e, e->ClientMachPort); - - DNSServiceBrowser *b; - for (b = DNSServiceBrowserList; b; b=b->next) - if (b->next == (DNSServiceBrowser *)~0 || b->ClientMachPort == 0 || b->ClientMachPort == (mach_port_t) ~0) - LogMemCorruption("DNSServiceBrowserList: %p is garbage (%X)", b, b->ClientMachPort); - - DNSServiceResolver *l; - for (l = DNSServiceResolverList; l; l=l->next) - if (l->next == (DNSServiceResolver *)~0 || l->ClientMachPort == 0 || l->ClientMachPort == (mach_port_t) ~0) - LogMemCorruption("DNSServiceResolverList: %p is garbage (%X)", l, l->ClientMachPort); - - DNSServiceRegistration *r; - for (r = DNSServiceRegistrationList; r; r=r->next) - if (r->next == (DNSServiceRegistration *)~0 || r->ClientMachPort == 0 || r->ClientMachPort == (mach_port_t) ~0) - LogMemCorruption("DNSServiceRegistrationList: %p is garbage (%X)", r, r->ClientMachPort); - // Check Unix Domain Socket client lists (uds_daemon.c) uds_validatelists(); @@ -279,14 +141,18 @@ mDNSlocal void validatelists(mDNS *const m, bool checkCRActiveQuestion) if (rr->resrec.name != &rr->namestorage) LogMemCorruption("ResourceRecords list: %p name %p does not point to namestorage %p %##s", rr, rr->resrec.name->c, rr->namestorage.c, rr->namestorage.c); +#if BONJOUR_ON_DEMAND if (!AuthRecord_uDNS(rr) && !RRLocalOnly(rr)) NumAllInterfaceRecords++; +#endif // BONJOUR_ON_DEMAND } for (rr = m->DuplicateRecords; rr; rr=rr->next) { if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF) LogMemCorruption("DuplicateRecords list: %p is garbage (%X)", rr, rr->resrec.RecordType); +#if BONJOUR_ON_DEMAND if (!AuthRecord_uDNS(rr) && !RRLocalOnly(rr)) NumAllInterfaceRecords++; +#endif // BONJOUR_ON_DEMAND } rr = m->NewLocalRecords; @@ -304,23 +170,25 @@ mDNSlocal void validatelists(mDNS *const m, bool checkCRActiveQuestion) { if (q->next == (DNSQuestion*)~0 || q->ThisQInterval == (mDNSs32) ~0) LogMemCorruption("Questions list: %p is garbage (%lX %p)", q, q->ThisQInterval, q->next); - if (q->InterfaceID != mDNSInterface_LocalOnly && q->InterfaceID != mDNSInterface_P2P && mDNSOpaque16IsZero(q->TargetQID)) + if (q->DuplicateOf && q->LocalSocket) + LogMemCorruption("Questions list: Duplicate Question %p should not have LocalSocket set %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype)); +#if BONJOUR_ON_DEMAND + if (!LocalOnlyOrP2PInterface(q->InterfaceID) && mDNSOpaque16IsZero(q->TargetQID)) NumAllInterfaceQuestions++; +#endif // BONJOUR_ON_DEMAND } - if (checkCRActiveQuestion) { - CacheGroup *cg; - CacheRecord *cr; - mDNSu32 slot; - FORALL_CACHERECORDS(slot, cg, cr) + CacheGroup *cg; + CacheRecord *cr; + mDNSu32 slot; + FORALL_CACHERECORDS(slot, cg, cr) + { + if (cr->resrec.RecordType == 0 || cr->resrec.RecordType == 0xFF) + LogMemCorruption("Cache slot %lu: %p is garbage (%X)", slot, cr, cr->resrec.RecordType); + if (cr->CRActiveQuestion) { - if (cr->resrec.RecordType == 0 || cr->resrec.RecordType == 0xFF) - LogMemCorruption("Cache slot %lu: %p is garbage (%X)", slot, cr, cr->resrec.RecordType); - if (cr->CRActiveQuestion) - { - for (q = m->Questions; q; q=q->next) if (q == cr->CRActiveQuestion) break; - if (!q) LogMemCorruption("Cache slot %lu: CRActiveQuestion %p not in m->Questions list %s", slot, cr->CRActiveQuestion, CRDisplayString(m, cr)); - } + for (q = m->Questions; q; q=q->next) if (q == cr->CRActiveQuestion) break; + if (!q) LogMemCorruption("Cache slot %lu: CRActiveQuestion %p not in m->Questions list %s", slot, cr->CRActiveQuestion, CRDisplayString(m, cr)); } } @@ -338,13 +206,13 @@ mDNSlocal void validatelists(mDNS *const m, bool checkCRActiveQuestion) if (t->next == (ClientTunnel *)~0 || t->dstname.c[0] > 63) LogMemCorruption("m->TunnelClients: %p is garbage (%d)", t, t->dstname.c[0]); -#if TARGET_OS_WATCH +#if BONJOUR_ON_DEMAND if (m->NumAllInterfaceRecords != NumAllInterfaceRecords) LogMemCorruption("NumAllInterfaceRecords is %d should be %d", m->NumAllInterfaceRecords, NumAllInterfaceRecords); if (m->NumAllInterfaceQuestions != NumAllInterfaceQuestions) LogMemCorruption("NumAllInterfaceQuestions is %d should be %d", m->NumAllInterfaceQuestions, NumAllInterfaceQuestions); -#endif +#endif // BONJOUR_ON_DEMAND } mDNSexport void *mallocL(char *msg, unsigned int size) @@ -361,7 +229,7 @@ mDNSexport void *mallocL(char *msg, unsigned int size) mem[1] = size; //mDNSPlatformMemZero(&mem[2], size); memset(&mem[2], 0xFF, size); - validatelists(&mDNSStorage, true); + validatelists(&mDNSStorage); return(&mem[2]); } } @@ -379,617 +247,13 @@ mDNSexport void freeL(char *msg, void *x) else if (MACOSX_MDNS_MALLOC_DEBUGGING >= 2) LogMsg("free( %s : %ld @ %p)", msg, mem[1], &mem[2]); mem[0] = 0xDEADDEAD; memset(mem+2, 0xFF, mem[1]); - validatelists(&mDNSStorage, false); + validatelists(&mDNSStorage); free(mem); } } #endif -//************************************************************************************************************* -#if COMPILER_LIKES_PRAGMA_MARK -#pragma mark - -#pragma mark - Mach client request handlers -#endif - -//************************************************************************************************************* -// Client Death Detection - -// This gets called after ALL constituent records of the Service Record Set have been deregistered -mDNSlocal void FreeServiceInstance(ServiceInstance *x) -{ - ServiceRecordSet *s = &x->srs; - ExtraResourceRecord *e = x->srs.Extras, *tmp; - - while (e) - { - e->r.RecordContext = e; - tmp = e; - e = e->next; - FreeExtraRR(&mDNSStorage, &tmp->r, mStatus_MemFree); - } - - if (s->RR_TXT.resrec.rdata != &s->RR_TXT.rdatastorage) - freeL("TXT RData", s->RR_TXT.resrec.rdata); - - if (s->SubTypes) freeL("ServiceSubTypes", s->SubTypes); - freeL("ServiceInstance", x); -} - -// AbortClient finds whatever client is identified by the given Mach port, -// stops whatever operation that client was doing, and frees its memory. -// In the case of a service registration, the actual freeing may be deferred -// until we get the mStatus_MemFree message, if necessary -mDNSlocal void AbortClient(mach_port_t ClientMachPort, void *m) -{ - DNSServiceDomainEnumeration **e = &DNSServiceDomainEnumerationList; - DNSServiceBrowser **b = &DNSServiceBrowserList; - DNSServiceResolver **l = &DNSServiceResolverList; - DNSServiceRegistration **r = &DNSServiceRegistrationList; - - while (*e && (*e)->ClientMachPort != ClientMachPort) e = &(*e)->next; - if (*e) - { - DNSServiceDomainEnumeration *x = *e; - *e = (*e)->next; - if (m && m != x) - LogMsg("%5d: DNSServiceDomainEnumeration(%##s) STOP; WARNING m %p != x %p", ClientMachPort, x->dom.qname.c, m, x); - else LogOperation("%5d: DNSServiceDomainEnumeration(%##s) STOP", ClientMachPort, x->dom.qname.c); - mDNS_StopGetDomains(&mDNSStorage, &x->dom); - mDNS_StopGetDomains(&mDNSStorage, &x->def); - freeL("DNSServiceDomainEnumeration", x); - return; - } - - while (*b && (*b)->ClientMachPort != ClientMachPort) b = &(*b)->next; - if (*b) - { - DNSServiceBrowser *x = *b; - DNSServiceBrowserQuestion *freePtr, *qptr = x->qlist; - *b = (*b)->next; - while (qptr) - { - if (m && m != x) - LogMsg("%5d: DNSServiceBrowse(%##s) STOP; WARNING m %p != x %p", ClientMachPort, qptr->q.qname.c, m, x); - else LogOperation("%5d: DNSServiceBrowse(%##s) STOP", ClientMachPort, qptr->q.qname.c); - mDNS_StopBrowse(&mDNSStorage, &qptr->q); - freePtr = qptr; - qptr = qptr->next; - freeL("DNSServiceBrowserQuestion", freePtr); - } - while (x->results) - { - DNSServiceBrowserResult *t = x->results; - x->results = x->results->next; - freeL("DNSServiceBrowserResult", t); - } - freeL("DNSServiceBrowser", x); - return; - } - - while (*l && (*l)->ClientMachPort != ClientMachPort) l = &(*l)->next; - if (*l) - { - DNSServiceResolver *x = *l; - *l = (*l)->next; - if (m && m != x) - LogMsg("%5d: DNSServiceResolve(%##s) STOP; WARNING m %p != x %p", ClientMachPort, x->i.name.c, m, x); - else LogOperation("%5d: DNSServiceResolve(%##s) STOP", ClientMachPort, x->i.name.c); - mDNS_StopResolveService(&mDNSStorage, &x->q); - freeL("DNSServiceResolver", x); - return; - } - - while (*r && (*r)->ClientMachPort != ClientMachPort) r = &(*r)->next; - if (*r) - { - ServiceInstance *si = NULL; - DNSServiceRegistration *x = *r; - *r = (*r)->next; - - si = x->regs; - while (si) - { - ServiceInstance *instance = si; - si = si->next; - instance->renameonmemfree = mDNSfalse; - if (m && m != x) LogMsg("%5d: DNSServiceRegistration(%##s, %u) STOP; WARNING m %p != x %p", ClientMachPort, instance->srs.RR_SRV.resrec.name->c, SRS_PORT(&instance->srs), m, x); - else LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort, instance->srs.RR_SRV.resrec.name->c, SRS_PORT(&instance->srs)); - - // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list, - // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory. - // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from - // the list, so we should go ahead and free the memory right now - if (mDNS_DeregisterService(&mDNSStorage, &instance->srs)) FreeServiceInstance(instance); // FreeServiceInstance invalidates pointer - } - x->regs = NULL; - freeL("DNSServiceRegistration", x); - return; - } - - LogMsg("%5d: died or deallocated, but no record of client can be found!", ClientMachPort); -} - -#define AbortBlockedClient(C,MSG,M) AbortClientWithLogMessage((C), "stopped accepting Mach messages", " (" MSG ")", (M)) - -mDNSlocal void AbortClientWithLogMessage(mach_port_t c, char *reason, char *msg, void *m) -{ - DNSServiceDomainEnumeration *e = DNSServiceDomainEnumerationList; - DNSServiceBrowser *b = DNSServiceBrowserList; - DNSServiceResolver *l = DNSServiceResolverList; - DNSServiceRegistration *r = DNSServiceRegistrationList; - DNSServiceBrowserQuestion *qptr; - - while (e && e->ClientMachPort != c) e = e->next; - while (b && b->ClientMachPort != c) b = b->next; - while (l && l->ClientMachPort != c) l = l->next; - while (r && r->ClientMachPort != c) r = r->next; - - if (e) LogMsg("%5d: DomainEnumeration(%##s) %s%s", c, e->dom.qname.c, reason, msg); - else if (b) - { - for (qptr = b->qlist; qptr; qptr = qptr->next) - LogMsg("%5d: Browser(%##s) %s%s", c, qptr->q.qname.c, reason, msg); - } - else if (l) LogMsg("%5d: Resolver(%##s) %s%s", c, l->i.name.c, reason, msg); - else if (r) - { - ServiceInstance *si; - for (si = r->regs; si; si = si->next) - LogMsg("%5d: Registration(%##s) %s%s", c, si->srs.RR_SRV.resrec.name->c, reason, msg); - } - else LogMsg("%5d: (%s) %s, but no record of client can be found!", c, reason, msg); - - AbortClient(c, m); -} - -mDNSlocal mDNSBool CheckForExistingClient(mach_port_t c) -{ - DNSServiceDomainEnumeration *e = DNSServiceDomainEnumerationList; - DNSServiceBrowser *b = DNSServiceBrowserList; - DNSServiceResolver *l = DNSServiceResolverList; - DNSServiceRegistration *r = DNSServiceRegistrationList; - DNSServiceBrowserQuestion *qptr; - - while (e && e->ClientMachPort != c) e = e->next; - while (b && b->ClientMachPort != c) b = b->next; - while (l && l->ClientMachPort != c) l = l->next; - while (r && r->ClientMachPort != c) r = r->next; - if (e) LogMsg("%5d: DomainEnumeration(%##s) already exists!", c, e->dom.qname.c); - if (b) - { - for (qptr = b->qlist; qptr; qptr = qptr->next) - LogMsg("%5d: Browser(%##s) already exists!", c, qptr->q.qname.c); - } - if (l) LogMsg("%5d: Resolver(%##s) already exists!", c, l->i.name.c); - if (r) LogMsg("%5d: Registration(%##s) already exists!", c, r->regs ? r->regs->srs.RR_SRV.resrec.name->c : NULL); - return(e || b || l || r); -} - -#ifndef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM - -mDNSlocal void ClientDeathCallback(CFMachPortRef unusedport, void *voidmsg, CFIndex size, void *info) -{ - KQueueLock(&mDNSStorage); - mach_msg_header_t *msg = (mach_msg_header_t *)voidmsg; - (void)unusedport; // Unused - (void)size; // Unused - (void)info; // Unused - if (msg->msgh_id == MACH_NOTIFY_DEAD_NAME) - { - const mach_dead_name_notification_t *const deathMessage = (mach_dead_name_notification_t *)msg; - AbortClient(deathMessage->not_port, NULL); - - /* Deallocate the send right that came in the dead name notification */ - mach_port_destroy(mach_task_self(), deathMessage->not_port); - } - KQueueUnlock(&mDNSStorage, "Mach AbortClient"); -} - -#endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM - -mDNSlocal void EnableDeathNotificationForClient(mach_port_t ClientMachPort, void *m) -{ -#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM - dispatch_source_t mach_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, ClientMachPort, 0, dispatch_get_main_queue()); - if (mach_source == mDNSNULL) - { - AbortClientWithLogMessage(ClientMachPort, "died/deallocated before we could enable death notification", "", m); - return; - } - dispatch_source_set_event_handler(mach_source, ^{ - mach_port_destroy(mach_task_self(), ClientMachPort); - }); - dispatch_resume(mach_source); -#else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM - mach_port_t prev; - kern_return_t r = mach_port_request_notification(mach_task_self(), ClientMachPort, MACH_NOTIFY_DEAD_NAME, 0, - client_death_port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev); - // If the port already died while we were thinking about it, then abort the operation right away - if (r != KERN_SUCCESS) - AbortClientWithLogMessage(ClientMachPort, "died/deallocated before we could enable death notification", "", m); -#endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM -} - -//************************************************************************************************************* -// Domain Enumeration - -mDNSlocal void DomainEnumFound(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) -{ - kern_return_t status; - char buffer[MAX_ESCAPED_DOMAIN_NAME]; - DNSServiceDomainEnumerationReplyResultType rt; - DNSServiceDomainEnumeration *x = (DNSServiceDomainEnumeration *)question->QuestionContext; - (void)m; // Unused - - debugf("DomainEnumFound: %##s PTR %##s", answer->name->c, answer->rdata->u.name.c); - if (answer->rrtype != kDNSType_PTR) return; - if (!x) { debugf("DomainEnumFound: DNSServiceDomainEnumeration is NULL"); return; } - - if (AddRecord) - { - if (question == &x->dom) rt = DNSServiceDomainEnumerationReplyAddDomain; - else rt = DNSServiceDomainEnumerationReplyAddDomainDefault; - } - else - { - if (question == &x->dom) rt = DNSServiceDomainEnumerationReplyRemoveDomain; - else return; - } - - LogOperation("%5d: DNSServiceDomainEnumeration(%##s) %##s %s", - x->ClientMachPort, x->dom.qname.c, answer->rdata->u.name.c, - !AddRecord ? "RemoveDomain" : - question == &x->dom ? "AddDomain" : "AddDomainDefault"); - - ConvertDomainNameToCString(&answer->rdata->u.name, buffer); - status = DNSServiceDomainEnumerationReply_rpc(x->ClientMachPort, rt, buffer, 0, MDNS_MM_TIMEOUT); - if (status == MACH_SEND_TIMED_OUT) - AbortBlockedClient(x->ClientMachPort, "enumeration", x); -} - -mDNSexport kern_return_t provide_DNSServiceDomainEnumerationCreate_rpc(mach_port_t unusedserver, mach_port_t client, - int regDom) -{ - // Check client parameter - (void)unusedserver; // Unused - mStatus err = mStatus_NoError; - const char *errormsg = "Unknown"; - if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; } - if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; } - - mDNS_DomainType dt1 = regDom ? mDNS_DomainTypeRegistration : mDNS_DomainTypeBrowse; - mDNS_DomainType dt2 = regDom ? mDNS_DomainTypeRegistrationDefault : mDNS_DomainTypeBrowseDefault; - - // Allocate memory, and handle failure - DNSServiceDomainEnumeration *x = mallocL("DNSServiceDomainEnumeration", sizeof(*x)); - if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } - - // Set up object, and link into list - x->ClientMachPort = client; - x->next = DNSServiceDomainEnumerationList; - DNSServiceDomainEnumerationList = x; - - verbosedebugf("%5d: Enumerate %s Domains", client, regDom ? "Registration" : "Browsing"); - - // Do the operation - err = mDNS_GetDomains(&mDNSStorage, &x->dom, dt1, NULL, mDNSInterface_LocalOnly, DomainEnumFound, x); - if (!err) err = mDNS_GetDomains(&mDNSStorage, &x->def, dt2, NULL, mDNSInterface_LocalOnly, DomainEnumFound, x); - if (err) { AbortClient(client, x); errormsg = "mDNS_GetDomains"; goto fail; } - - // Succeeded: Wrap up and return - LogOperation("%5d: DNSServiceDomainEnumeration(%##s) START", client, x->dom.qname.c); - EnableDeathNotificationForClient(client, x); - return(mStatus_NoError); - -fail: - LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%d)", client, regDom, errormsg, err); - return(err); -} - -//************************************************************************************************************* -// Browse for services - -mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) -{ - (void)m; // Unused - - if (answer->rrtype != kDNSType_PTR) - { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer->rrtype); return; } - - domainlabel name; - domainname type, domain; - if (!DeconstructServiceName(&answer->rdata->u.name, &name, &type, &domain)) - { - LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer", - answer->name->c, answer->rdata->u.name.c); - return; - } - - DNSServiceBrowserResult *x = mallocL("DNSServiceBrowserResult", sizeof(*x)); - if (!x) { LogMsg("FoundInstance: Failed to allocate memory for result %##s", answer->rdata->u.name.c); return; } - - verbosedebugf("FoundInstance: %s %##s", AddRecord ? "Add" : "Rmv", answer->rdata->u.name.c); - AssignDomainName(&x->result, &answer->rdata->u.name); - if (AddRecord) - x->resultType = DNSServiceBrowserReplyAddInstance; - else x->resultType = DNSServiceBrowserReplyRemoveInstance; - x->next = NULL; - - DNSServiceBrowser *browser = (DNSServiceBrowser *)question->QuestionContext; - DNSServiceBrowserResult **p = &browser->results; - while (*p) p = &(*p)->next; - *p = x; - - LogOperation("%5d: DNSServiceBrowse(%##s, %s) RESULT %s %s", - browser->ClientMachPort, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer)); -} - -mDNSlocal mStatus AddDomainToBrowser(DNSServiceBrowser *browser, const domainname *d) -{ - mStatus err = mStatus_NoError; - DNSServiceBrowserQuestion *ptr, *question = NULL; - - for (ptr = browser->qlist; ptr; ptr = ptr->next) - { - if (SameDomainName(&ptr->q.qname, d)) - { debugf("Domain %##s already contained in browser", d->c); return mStatus_AlreadyRegistered; } - } - - question = mallocL("DNSServiceBrowserQuestion", sizeof(DNSServiceBrowserQuestion)); - if (!question) { LogMsg("Error: malloc"); return mStatus_NoMemoryErr; } - AssignDomainName(&question->domain, d); - question->next = browser->qlist; - LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", browser->ClientMachPort, browser->type.c, d->c); - err = mDNS_StartBrowse(&mDNSStorage, &question->q, &browser->type, d, mDNSNULL, mDNSInterface_Any, 0, mDNSfalse, mDNSfalse, FoundInstance, browser); - if (!err) - browser->qlist = question; - else - { - LogMsg("Error: AddDomainToBrowser: mDNS_StartBrowse %d", err); - freeL("DNSServiceBrowserQuestion", question); - } - return err; -} - -mDNSexport void machserver_automatic_browse_domain_changed(const domainname *d, mDNSBool add) -{ - DNSServiceBrowser *ptr; - for (ptr = DNSServiceBrowserList; ptr; ptr = ptr->next) - { - if (ptr->DefaultDomain) - { - if (add) - { - mStatus err = AddDomainToBrowser(ptr, d); - if (err && err != mStatus_AlreadyRegistered) LogMsg("Default browse in domain %##s for client %5d failed. Continuing", d, ptr->ClientMachPort); - } - else - { - DNSServiceBrowserQuestion **q = &ptr->qlist; - while (*q) - { - if (SameDomainName(&(*q)->domain, d)) - { - DNSServiceBrowserQuestion *rem = *q; - *q = (*q)->next; - mDNS_StopQueryWithRemoves(&mDNSStorage, &rem->q); - freeL("DNSServiceBrowserQuestion", rem); - return; - } - q = &(*q)->next; - } - LogMsg("Requested removal of default domain %##s not in client %5d's list", d->c, ptr->ClientMachPort); - } - } - } -} - -mDNSexport kern_return_t provide_DNSServiceBrowserCreate_rpc(mach_port_t unusedserver, mach_port_t client, - DNSCString regtype, DNSCString domain) -{ - // Check client parameter - (void)unusedserver; // Unused - mStatus err = mStatus_NoError; - const char *errormsg = "Unknown"; - - if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; } - if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; } - - // Check other parameters - domainname t, d; - t.c[0] = 0; - mDNSs32 NumSubTypes = ChopSubTypes(regtype, mDNSNULL); // Note: Modifies regtype string to remove trailing subtypes - if (NumSubTypes < 0 || NumSubTypes > 1) { errormsg = "Bad Service SubType"; goto badparam; } - if (NumSubTypes == 1 && !AppendDNSNameString(&t, regtype + strlen(regtype) + 1)) - { errormsg = "Bad Service SubType"; goto badparam; } - if (!regtype[0] || !AppendDNSNameString(&t, regtype)) { errormsg = "Illegal regtype"; goto badparam; } - domainname temp; - if (!MakeDomainNameFromDNSNameString(&temp, regtype)) { errormsg = "Illegal regtype"; goto badparam; } - if (temp.c[0] > 15 && (!domain || domain[0] == 0)) domain = "local."; // For over-long service types, we only allow domain "local" - - // Allocate memory, and handle failure - DNSServiceBrowser *x = mallocL("DNSServiceBrowser", sizeof(*x)); - if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } - - // Set up object, and link into list - AssignDomainName(&x->type, &t); - x->ClientMachPort = client; - x->results = NULL; - x->lastsuccess = 0; - x->qlist = NULL; - x->next = DNSServiceBrowserList; - DNSServiceBrowserList = x; - - if (domain[0]) - { - // Start browser for an explicit domain - x->DefaultDomain = mDNSfalse; - if (!MakeDomainNameFromDNSNameString(&d, domain)) { errormsg = "Illegal domain"; goto badparam; } - err = AddDomainToBrowser(x, &d); - if (err) { AbortClient(client, x); errormsg = "AddDomainToBrowser"; goto fail; } - } - else - { - DNameListElem *sdPtr; - // Start browser on all domains - x->DefaultDomain = mDNStrue; - if (!AutoBrowseDomains) { AbortClient(client, x); errormsg = "GetSearchDomainList"; goto fail; } - for (sdPtr = AutoBrowseDomains; sdPtr; sdPtr = sdPtr->next) - { - err = AddDomainToBrowser(x, &sdPtr->name); - if (err) - { - // only terminally bail if .local fails - if (!SameDomainName(&localdomain, &sdPtr->name)) - LogMsg("Default browse in domain %##s failed. Continuing", sdPtr->name.c); - else { AbortClient(client, x); errormsg = "AddDomainToBrowser"; goto fail; } - } - } - } - - // Succeeded: Wrap up and return - EnableDeathNotificationForClient(client, x); - return(mStatus_NoError); - -badparam: - err = mStatus_BadParamErr; -fail: - LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%d)", client, regtype, domain, errormsg, err); - return(err); -} - -//************************************************************************************************************* -// Resolve Service Info - -mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query) -{ - kern_return_t status; - DNSServiceResolver *x = (DNSServiceResolver *)query->ServiceInfoQueryContext; - NetworkInterfaceInfoOSX *ifx = IfindexToInterfaceInfoOSX(m, query->info->InterfaceID); - if (query->info->InterfaceID == mDNSInterface_LocalOnly || query->info->InterfaceID == mDNSInterface_P2P) ifx = mDNSNULL; - struct sockaddr_storage interface; - struct sockaddr_storage address; - char cstring[1024]; - int i, pstrlen = query->info->TXTinfo[0]; - (void)m; // Unused - - //debugf("FoundInstanceInfo %.4a %.4a %##s", &query->info->InterfaceAddr, &query->info->ip, &query->info->name); - - if (query->info->TXTlen > sizeof(cstring)) return; - - mDNSPlatformMemZero(&interface, sizeof(interface)); - mDNSPlatformMemZero(&address, sizeof(address)); - - if (ifx && ifx->ifinfo.ip.type == mDNSAddrType_IPv4) - { - struct sockaddr_in *s = (struct sockaddr_in*)&interface; - s->sin_len = sizeof(*s); - s->sin_family = AF_INET; - s->sin_port = 0; - s->sin_addr.s_addr = ifx->ifinfo.ip.ip.v4.NotAnInteger; - } - else if (ifx && ifx->ifinfo.ip.type == mDNSAddrType_IPv6) - { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&interface; - sin6->sin6_len = sizeof(*sin6); - sin6->sin6_family = AF_INET6; - sin6->sin6_flowinfo = 0; - sin6->sin6_port = 0; - sin6->sin6_addr = *(struct in6_addr*)&ifx->ifinfo.ip.ip.v6; - sin6->sin6_scope_id = ifx->scope_id; - } - - if (query->info->ip.type == mDNSAddrType_IPv4) - { - struct sockaddr_in *s = (struct sockaddr_in*)&address; - s->sin_len = sizeof(*s); - s->sin_family = AF_INET; - s->sin_port = query->info->port.NotAnInteger; - s->sin_addr.s_addr = query->info->ip.ip.v4.NotAnInteger; - } - else - { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&address; - sin6->sin6_len = sizeof(*sin6); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = query->info->port.NotAnInteger; - sin6->sin6_flowinfo = 0; - sin6->sin6_addr = *(struct in6_addr*)&query->info->ip.ip.v6; - sin6->sin6_scope_id = ifx ? ifx->scope_id : 0; - } - - // The OS X DNSServiceResolverResolve() API is defined using a C-string, - // but the mDNS_StartResolveService() call actually returns a packed block of P-strings. - // Hence we have to convert the P-string(s) to a C-string before returning the result to the client. - // ASCII-1 characters are used in the C-string as boundary markers, - // to indicate the boundaries between the original constituent P-strings. - for (i=1; iinfo->TXTlen; i++) - { - if (--pstrlen >= 0) - cstring[i-1] = query->info->TXTinfo[i]; - else - { - cstring[i-1] = 1; - pstrlen = query->info->TXTinfo[i]; - } - } - cstring[i-1] = 0; // Put the terminating NULL on the end - - LogOperation("%5d: DNSServiceResolver(%##s) -> %#a:%u", x->ClientMachPort, - x->i.name.c, &query->info->ip, mDNSVal16(query->info->port)); - status = DNSServiceResolverReply_rpc(x->ClientMachPort, - (char*)&interface, (char*)&address, cstring, 0, MDNS_MM_TIMEOUT); - if (status == MACH_SEND_TIMED_OUT) - AbortBlockedClient(x->ClientMachPort, "resolve", x); -} - -mDNSexport kern_return_t provide_DNSServiceResolverResolve_rpc(mach_port_t unusedserver, mach_port_t client, - DNSCString name, DNSCString regtype, DNSCString domain) -{ - // Check client parameter - (void)unusedserver; // Unused - mStatus err = mStatus_NoError; - const char *errormsg = "Unknown"; - if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; } - if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; } - - // Check other parameters - domainlabel n; - domainname t, d, srv; - if (!name[0] || !MakeDomainLabelFromLiteralString(&n, name)) { errormsg = "Bad Instance Name"; goto badparam; } - if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type"; goto badparam; } - if (!domain[0] || !MakeDomainNameFromDNSNameString(&d, domain)) { errormsg = "Bad Domain"; goto badparam; } - if (!ConstructServiceName(&srv, &n, &t, &d)) { errormsg = "Bad Name"; goto badparam; } - - // Allocate memory, and handle failure - DNSServiceResolver *x = mallocL("DNSServiceResolver", sizeof(*x)); - if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } - - // Set up object, and link into list - x->ClientMachPort = client; - x->i.InterfaceID = mDNSInterface_Any; - x->i.name = srv; - x->ReportTime = NonZeroTime(mDNS_TimeNow(&mDNSStorage) + 130 * mDNSPlatformOneSecond); - x->next = DNSServiceResolverList; - DNSServiceResolverList = x; - - // Do the operation - LogOperation("%5d: DNSServiceResolve(%##s) START", client, x->i.name.c); - err = mDNS_StartResolveService(&mDNSStorage, &x->q, &x->i, FoundInstanceInfo, x); - if (err) { AbortClient(client, x); errormsg = "mDNS_StartResolveService"; goto fail; } - - // Succeeded: Wrap up and return - EnableDeathNotificationForClient(client, x); - return(mStatus_NoError); - -badparam: - err = mStatus_BadParamErr; -fail: - LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%d)", client, name, regtype, domain, errormsg, err); - return(err); -} - //************************************************************************************************************* // Registration @@ -998,274 +262,6 @@ mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay) m->p->NotifyUser = NonZeroTime(m->timenow + delay); } -mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus result) -{ - ServiceInstance *si = (ServiceInstance*)srs->ServiceContext; - - if (result == mStatus_NoError) - { - kern_return_t status; - LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Registered", si->ClientMachPort, srs->RR_SRV.resrec.name->c, SRS_PORT(srs)); - status = DNSServiceRegistrationReply_rpc(si->ClientMachPort, result, MDNS_MM_TIMEOUT); - if (status == MACH_SEND_TIMED_OUT) - AbortBlockedClient(si->ClientMachPort, "registration success", si); - if (si->autoname && CountPeerRegistrations(m, srs) == 0) - RecordUpdatedNiceLabel(m, 0); // Successfully got new name, tell user immediately - } - - else if (result == mStatus_NameConflict) - { - LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Conflict", si->ClientMachPort, srs->RR_SRV.resrec.name->c, SRS_PORT(srs)); - // Note: By the time we get the mStatus_NameConflict message, the service is already deregistered - // and the memory is free, so we don't have to wait for an mStatus_MemFree message as well. - if (si->autoname && CountPeerRegistrations(m, srs) == 0) - { - // On conflict for an autoname service, rename and reregister *all* autoname services - IncrementLabelSuffix(&m->nicelabel, mDNStrue); - mDNS_ConfigChanged(m); - } - else if (si->autoname) - { - mDNS_RenameAndReregisterService(m, srs, mDNSNULL); - return; - } - else - { - // If we get a name conflict, we tell the client about it, and then they are expected to dispose - // of their registration in the usual way (which we will catch via client death notification). - // If the Mach queue is full, we forcibly abort the client immediately. - kern_return_t status = DNSServiceRegistrationReply_rpc(si->ClientMachPort, result, MDNS_MM_TIMEOUT); - if (status == MACH_SEND_TIMED_OUT) - AbortBlockedClient(si->ClientMachPort, "registration conflict", NULL); - } - } - - else if (result == mStatus_MemFree) - { - if (si->renameonmemfree) // We intentionally terminated registration so we could re-register with new name - { - debugf("RegCallback renaming %#s to %#s", si->name.c, m->nicelabel.c); - si->renameonmemfree = mDNSfalse; - si->name = m->nicelabel; - mDNS_RenameAndReregisterService(m, srs, &si->name); - } - else - { - // SANITY CHECK: make sure service instance is no longer in any ServiceRegistration's list - DNSServiceRegistration *r; - for (r = DNSServiceRegistrationList; r; r = r->next) - { - ServiceInstance **sp = &r->regs; - while (*sp) - { - if (*sp == si) { LogMsg("RegCallback: %##s Still in list; removing", srs->RR_SRV.resrec.name->c); *sp = (*sp)->next; break; } - sp = &(*sp)->next; - } - } - // END SANITY CHECK - FreeServiceInstance(si); - } - } - - else if (result != mStatus_NATTraversal) - LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %d", si->ClientMachPort, srs->RR_SRV.resrec.name->c, SRS_PORT(srs), result); -} - -mDNSlocal mStatus AddServiceInstance(DNSServiceRegistration *x, const domainname *domain) -{ - mStatus err = 0; - ServiceInstance *si = NULL; - AuthRecord *SubTypes = NULL; - - for (si = x->regs; si; si = si->next) - { - if (SameDomainName(&si->domain, domain)) - { LogMsg("Requested addition of domain %##s already in list", domain->c); return mStatus_AlreadyRegistered; } - } - - SubTypes = AllocateSubTypes(x->NumSubTypes, x->regtype, mDNSNULL); - if (x->NumSubTypes && !SubTypes) return mStatus_NoMemoryErr; - - si = mallocL("ServiceInstance", sizeof(*si) - sizeof(RDataBody) + x->rdsize); - if (!si) return mStatus_NoMemoryErr; - - si->ClientMachPort = x->ClientMachPort; - si->renameonmemfree = mDNSfalse; - si->autoname = x->autoname; - si->name = x->autoname ? mDNSStorage.nicelabel : x->name; - si->domain = *domain; - si->srs.AnonData = mDNSNULL; - - err = mDNS_RegisterService(&mDNSStorage, &si->srs, &si->name, &x->type, domain, NULL, - x->port, x->txtinfo, x->txt_len, SubTypes, x->NumSubTypes, mDNSInterface_Any, RegCallback, si, 0); - if (!err) - { - si->next = x->regs; - x->regs = si; - } - else - { - LogMsg("Error %d for registration of service in domain %##s", err, domain->c); - freeL("ServiceInstance", si); - } - return err; -} - -mDNSexport void machserver_automatic_registration_domain_changed(const domainname *d, mDNSBool add) -{ - DNSServiceRegistration *reg; - - for (reg = DNSServiceRegistrationList; reg; reg = reg->next) - { - if (reg->DefaultDomain) - { - if (add) - AddServiceInstance(reg, d); - else - { - ServiceInstance **si = ®->regs; - while (*si) - { - if (SameDomainName(&(*si)->domain, d)) - { - ServiceInstance *s = *si; - *si = (*si)->next; - if (mDNS_DeregisterService(&mDNSStorage, &s->srs)) FreeServiceInstance(s); // only free memory synchronously on error - break; - } - si = &(*si)->next; - } - if (!si) debugf("Requested removal of default domain %##s not in client %5d's list", d, reg->ClientMachPort); // normal if registration failed - } - } - } -} - -mDNSexport kern_return_t provide_DNSServiceRegistrationCreate_rpc(mach_port_t unusedserver, mach_port_t client, - DNSCString name, DNSCString regtype, DNSCString domain, IPPort IpPort, DNSCString txtRecord) -{ - (void)unusedserver; // Unused - mStatus err = mStatus_NoError; - const char *errormsg = "Unknown"; - - // older versions of this code passed the port via mach IPC as an int. - // we continue to pass it as 4 bytes to maintain binary compatibility, - // but now ensure that the network byte order is preserved by using a struct - mDNSIPPort port; - port.b[0] = IpPort.bytes[2]; - port.b[1] = IpPort.bytes[3]; - - if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; } - if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; } - - // Check for sub-types after the service type - size_t reglen = strlen(regtype) + 1; - if (reglen > MAX_ESCAPED_DOMAIN_NAME) { errormsg = "reglen too long"; goto badparam; } - mDNSs32 NumSubTypes = ChopSubTypes(regtype, mDNSNULL); // Note: Modifies regtype string to remove trailing subtypes - if (NumSubTypes < 0) { errormsg = "Bad Service SubType"; goto badparam; } - - // Check other parameters - domainlabel n; - domainname t, d; - domainname srv; - if (!name[0]) n = mDNSStorage.nicelabel; - else if (!MakeDomainLabelFromLiteralString(&n, name)) { errormsg = "Bad Instance Name"; goto badparam; } - if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type"; goto badparam; } - if (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) { errormsg = "Bad Domain"; goto badparam; } - if (!ConstructServiceName(&srv, &n, &t, &d)) { errormsg = "Bad Name"; goto badparam; } - - unsigned char txtinfo[1024] = ""; - unsigned int data_len = 0; - unsigned int size = sizeof(RDataBody); - unsigned char *pstring = &txtinfo[data_len]; - char *ptr = txtRecord; - - // The OS X DNSServiceRegistrationCreate() API is defined using a C-string, - // but the mDNS_RegisterService() call actually requires a packed block of P-strings. - // Hence we have to convert the C-string to a P-string. - // ASCII-1 characters are allowed in the C-string as boundary markers, - // so that a single C-string can be used to represent one or more P-strings. - while (*ptr) - { - if (++data_len >= sizeof(txtinfo)) { errormsg = "TXT record too long"; goto badtxt; } - if (*ptr == 1) // If this is our boundary marker, start a new P-string - { - pstring = &txtinfo[data_len]; - pstring[0] = 0; - ptr++; - } - else - { - if (pstring[0] == 255) { errormsg = "TXT record invalid (component longer than 255)"; goto badtxt; } - pstring[++pstring[0]] = *ptr++; - } - } - - data_len++; - if (size < data_len) - size = data_len; - - // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with - // a port number of zero. When two instances of the protected client are allowed to run on one - // machine, we don't want to see misleading "Bogus client" messages in syslog and the console. - if (!mDNSIPPortIsZero(port)) - { - int count = CountExistingRegistrations(&srv, port); - if (count) - LogMsg("%5d: Client application registered %d identical instances of service %##s port %u.", - client, count+1, srv.c, mDNSVal16(port)); - } - - // Allocate memory, and handle failure - DNSServiceRegistration *x = mallocL("DNSServiceRegistration", sizeof(*x)); - if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } - mDNSPlatformMemZero(x, sizeof(*x)); - - // Set up object, and link into list - x->ClientMachPort = client; - x->DefaultDomain = !domain[0]; - x->autoname = (!name[0]); - x->rdsize = size; - x->NumSubTypes = NumSubTypes; - memcpy(x->regtype, regtype, reglen); - x->name = n; - x->type = t; - x->port = port; - memcpy(x->txtinfo, txtinfo, 1024); - x->txt_len = data_len; - x->NextRef = 0; - x->regs = NULL; - - x->next = DNSServiceRegistrationList; - DNSServiceRegistrationList = x; - - LogOperation("%5d: DNSServiceRegistration(\"%s\", \"%s\", \"%s\", %u) START", - x->ClientMachPort, name, regtype, domain, mDNSVal16(port)); - - err = AddServiceInstance(x, &d); - if (err) { AbortClient(client, x); errormsg = "mDNS_RegisterService"; goto fail; } // bail if .local (or explicit domain) fails - - if (x->DefaultDomain) - { - DNameListElem *p; - for (p = AutoRegistrationDomains; p; p = p->next) - AddServiceInstance(x, &p->name); - } - - // Succeeded: Wrap up and return - EnableDeathNotificationForClient(client, x); - return(mStatus_NoError); - -badtxt: - LogMsg("%5d: TXT record: %.100s...", client, txtRecord); -badparam: - err = mStatus_BadParamErr; -fail: - LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%d)", - client, name, regtype, domain, mDNSVal16(port), errormsg, err); - return(err); -} - mDNSlocal void mDNSPreferencesSetNames(mDNS *const m, int key, domainlabel *old, domainlabel *new) { domainlabel *prevold, *prevnew; @@ -1331,271 +327,48 @@ mDNSlocal void mDNSPreferencesSetNames(mDNS *const m, int key, domainlabel *old, mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result) { (void)m; // Unused - if (result == mStatus_NoError) - { - if (!SameDomainLabelCS(m->p->userhostlabel.c, m->hostlabel.c)) - LogInfo("Local Hostname changed from \"%#s.local\" to \"%#s.local\"", m->p->userhostlabel.c, m->hostlabel.c); - // One second pause in case we get a Computer Name update too -- don't want to alert the user twice - RecordUpdatedNiceLabel(m, mDNSPlatformOneSecond); - } - else if (result == mStatus_NameConflict) - { - LogInfo("Local Hostname conflict for \"%#s.local\"", m->hostlabel.c); - if (!m->p->HostNameConflict) m->p->HostNameConflict = NonZeroTime(m->timenow); - else if (m->timenow - m->p->HostNameConflict > 60 * mDNSPlatformOneSecond) - { - // Tell the helper we've given up - mDNSPreferencesSetNames(m, kmDNSLocalHostName, &m->p->userhostlabel, NULL); - } - } - else if (result == mStatus_GrowCache) - { - // Allocate another chunk of cache storage - static unsigned int allocated = 0; -#if TARGET_OS_IPHONE - if (allocated >= 1000000) return; // For now we limit the cache to at most 1MB on iOS devices -#endif - allocated += sizeof(CacheEntity) * RR_CACHE_SIZE; - // LogMsg("GrowCache %d * %d = %d; total so far %6u", sizeof(CacheEntity), RR_CACHE_SIZE, sizeof(CacheEntity) * RR_CACHE_SIZE, allocated); - CacheEntity *storage = mallocL("mStatus_GrowCache", sizeof(CacheEntity) * RR_CACHE_SIZE); - //LogInfo("GrowCache %d * %d = %d", sizeof(CacheEntity), RR_CACHE_SIZE, sizeof(CacheEntity) * RR_CACHE_SIZE); - if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE); - } - else if (result == mStatus_ConfigChanged) - { - // Tell the helper we've seen a change in the labels. It will dismiss the name conflict alert if needed. - mDNSPreferencesSetNames(m, kmDNSComputerName, &m->p->usernicelabel, &m->nicelabel); - mDNSPreferencesSetNames(m, kmDNSLocalHostName, &m->p->userhostlabel, &m->hostlabel); - - // First we check our list of old Mach-based registered services, to see if any need to be updated to a new name - DNSServiceRegistration *r; - for (r = DNSServiceRegistrationList; r; r=r->next) - if (r->autoname) - { - ServiceInstance *si; - for (si = r->regs; si; si = si->next) - { - if (!SameDomainLabelCS(si->name.c, m->nicelabel.c)) - { - debugf("NetworkChanged renaming %##s to %#s", si->srs.RR_SRV.resrec.name->c, m->nicelabel.c); - si->renameonmemfree = mDNStrue; - if (mDNS_DeregisterService_drt(m, &si->srs, mDNS_Dereg_rapid)) - RegCallback(m, &si->srs, mStatus_MemFree); // If service deregistered already, we can re-register immediately - } - } - } - - // Then we call into the UDS daemon code, to let it do the same - udsserver_handle_configchange(m); - } -} - -//************************************************************************************************************* -// Add / Update / Remove records from existing Registration - -mDNSexport kern_return_t provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t unusedserver, mach_port_t client, - int type, const char *data, mach_msg_type_number_t data_len, uint32_t ttl, natural_t *reference) -{ - // Check client parameter - uint32_t id; - mStatus err = mStatus_NoError; - const char *errormsg = "Unknown"; - DNSServiceRegistration *x = DNSServiceRegistrationList; - if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; } - ServiceInstance *si; - size_t size; - (void)unusedserver; // Unused - while (x && x->ClientMachPort != client) x = x->next; - if (!x) { err = mStatus_BadReferenceErr; errormsg = "No such client"; goto fail; } - - // Check other parameters - if (data_len > 8192) { err = mStatus_BadParamErr; errormsg = "data_len > 8K"; goto fail; } - if (data_len > sizeof(RDataBody)) size = data_len; - else size = sizeof(RDataBody); - - id = x->NextRef++; - *reference = (natural_t)id; - for (si = x->regs; si; si = si->next) - { - // Allocate memory, and handle failure - ExtraResourceRecord *extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size); - if (!extra) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } - - // Fill in type, length, and data of new record - extra->r.resrec.rrtype = type; - extra->r.rdatastorage.MaxRDLength = size; - extra->r.resrec.rdlength = data_len; - memcpy(&extra->r.rdatastorage.u.data, data, data_len); - - // Do the operation - LogOperation("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) REF %p", - client, si->srs.RR_SRV.resrec.name->c, type, data_len, extra); - err = mDNS_AddRecordToService(&mDNSStorage, &si->srs, extra, &extra->r.rdatastorage, ttl, 0); - - if (err) - { - freeL("Extra Resource Record", extra); - errormsg = "mDNS_AddRecordToService"; - goto fail; - } - - extra->ClientID = id; - } - - return mStatus_NoError; - -fail: - LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%d)", client, x ? x->name.c : (mDNSu8*)"\x8" "«NULL»", type, data_len, errormsg, err); - return mStatus_UnknownErr; -} - -mDNSlocal void UpdateCallback(mDNS *const m, AuthRecord *const rr, RData *OldRData, mDNSu16 OldRDLen) -{ - (void)m; // Unused - (void)OldRDLen; // Unused - if (OldRData != &rr->rdatastorage) - freeL("Old RData", OldRData); -} - -mDNSlocal mStatus UpdateRecord(ServiceRecordSet *srs, mach_port_t client, AuthRecord *rr, const char *data, mach_msg_type_number_t data_len, uint32_t ttl) -{ - // Check client parameter - mStatus err = mStatus_NoError; - const char *errormsg = "Unknown"; - const domainname *name = (const domainname *)""; - - name = srs->RR_SRV.resrec.name; - - unsigned int size = sizeof(RDataBody); - if (size < data_len) - size = data_len; - - // Allocate memory, and handle failure - RData *newrdata = mallocL("RData", sizeof(*newrdata) - sizeof(RDataBody) + size); - if (!newrdata) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } - - // Fill in new length, and data - newrdata->MaxRDLength = size; - memcpy(&newrdata->u, data, data_len); - - // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct, - // since RFC 1035 specifies a TXT record as "One or more s", not "Zero or more s". - // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here. - if (rr->resrec.rrtype == kDNSType_TXT && data_len == 0) { data_len = 1; newrdata->u.txt.c[0] = 0; } - - // Do the operation - LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, new length %d)", - client, srs->RR_SRV.resrec.name->c, data_len); - - err = mDNS_Update(&mDNSStorage, rr, ttl, data_len, newrdata, UpdateCallback); - if (err) - { - errormsg = "mDNS_Update"; - freeL("RData", newrdata); - goto fail; - } - return(mStatus_NoError); - -fail: - LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %d) failed: %s (%d)", client, name->c, data_len, errormsg, err); - return(err); -} - -mDNSexport kern_return_t provide_DNSServiceRegistrationUpdateRecord_rpc(mach_port_t unusedserver, mach_port_t client, - natural_t reference, const char *data, mach_msg_type_number_t data_len, uint32_t ttl) -{ - // Check client parameter - mStatus err = mStatus_NoError; - const char *errormsg = "Unknown"; - const domainname *name = (const domainname *)""; - ServiceInstance *si; - - (void)unusedserver; // unused - if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; } - DNSServiceRegistration *x = DNSServiceRegistrationList; - while (x && x->ClientMachPort != client) x = x->next; - if (!x) { err = mStatus_BadReferenceErr; errormsg = "No such client"; goto fail; } - - // Check other parameters - if (data_len > 8192) { err = mStatus_BadParamErr; errormsg = "data_len > 8K"; goto fail; } - - for (si = x->regs; si; si = si->next) - { - AuthRecord *r = NULL; - - // Find the record we're updating. NULL reference means update the primary TXT record - if (!reference) r = &si->srs.RR_TXT; - else - { - ExtraResourceRecord *ptr; - for (ptr = si->srs.Extras; ptr; ptr = ptr->next) - { - if ((natural_t)ptr->ClientID == reference) - { r = &ptr->r; break; } - } - if (!r) { err = mStatus_BadReferenceErr; errormsg = "No such record"; goto fail; } - } - err = UpdateRecord(&si->srs, client, r, data, data_len, ttl); - if (err) goto fail; //!!!KRS this will cause failures for non-local defaults! - } - - return mStatus_NoError; - -fail: - LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%d)", client, name->c, reference, data_len, errormsg, err); - return(err); -} - -mDNSlocal mStatus RemoveRecord(ServiceRecordSet *srs, ExtraResourceRecord *extra, mach_port_t client) -{ - const domainname *const name = srs->RR_SRV.resrec.name; - mStatus err = mStatus_NoError; - - // Do the operation - LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s)", client, srs->RR_SRV.resrec.name->c); - - err = mDNS_RemoveRecordFromService(&mDNSStorage, srs, extra, FreeExtraRR, extra); - if (err) LogMsg("%5d: DNSServiceRegistrationRemoveRecord (%##s) failed: %d", client, name->c, err); - - return err; -} - -mDNSexport kern_return_t provide_DNSServiceRegistrationRemoveRecord_rpc(mach_port_t unusedserver, mach_port_t client, - natural_t reference) -{ - // Check client parameter - (void)unusedserver; // Unused - mStatus err = mStatus_NoError; - const char *errormsg = "Unknown"; - if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; } - DNSServiceRegistration *x = DNSServiceRegistrationList; - ServiceInstance *si; - - while (x && x->ClientMachPort != client) x = x->next; - if (!x) { err = mStatus_BadReferenceErr; errormsg = "No such client"; goto fail; } - - for (si = x->regs; si; si = si->next) + if (result == mStatus_NoError) + { + if (!SameDomainLabelCS(m->p->userhostlabel.c, m->hostlabel.c)) + LogInfo("Local Hostname changed from \"%#s.local\" to \"%#s.local\"", m->p->userhostlabel.c, m->hostlabel.c); + // One second pause in case we get a Computer Name update too -- don't want to alert the user twice + RecordUpdatedNiceLabel(m, mDNSPlatformOneSecond); + } + else if (result == mStatus_NameConflict) { - ExtraResourceRecord *e; - for (e = si->srs.Extras; e; e = e->next) + LogInfo("Local Hostname conflict for \"%#s.local\"", m->hostlabel.c); + if (!m->p->HostNameConflict) m->p->HostNameConflict = NonZeroTime(m->timenow); + else if (m->timenow - m->p->HostNameConflict > 60 * mDNSPlatformOneSecond) { - if ((natural_t)e->ClientID == reference) - { - err = RemoveRecord(&si->srs, e, client); - if (err) { errormsg = "RemoveRecord failed"; goto fail; } - break; - } + // Tell the helper we've given up + mDNSPreferencesSetNames(m, kmDNSLocalHostName, &m->p->userhostlabel, NULL); } - if (!e) { err = mStatus_BadReferenceErr; errormsg = "No such reference"; goto fail; } } + else if (result == mStatus_GrowCache) + { + // Allocate another chunk of cache storage + static unsigned int allocated = 0; +#if TARGET_OS_IPHONE + if (allocated >= 1000000) return; // For now we limit the cache to at most 1MB on iOS devices +#endif + allocated += sizeof(CacheEntity) * RR_CACHE_SIZE; + // LogMsg("GrowCache %d * %d = %d; total so far %6u", sizeof(CacheEntity), RR_CACHE_SIZE, sizeof(CacheEntity) * RR_CACHE_SIZE, allocated); + CacheEntity *storage = mallocL("mStatus_GrowCache", sizeof(CacheEntity) * RR_CACHE_SIZE); + //LogInfo("GrowCache %d * %d = %d", sizeof(CacheEntity), RR_CACHE_SIZE, sizeof(CacheEntity) * RR_CACHE_SIZE); + if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE); + } + else if (result == mStatus_ConfigChanged) + { + // Tell the helper we've seen a change in the labels. It will dismiss the name conflict alert if needed. + mDNSPreferencesSetNames(m, kmDNSComputerName, &m->p->usernicelabel, &m->nicelabel); + mDNSPreferencesSetNames(m, kmDNSLocalHostName, &m->p->userhostlabel, &m->hostlabel); - return mStatus_NoError; - -fail: - LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%d)", client, reference, errormsg, err); - return(err); + // Then we call into the UDS daemon code, to let it do the same + udsserver_handle_configchange(m); + } } + //************************************************************************************************************* #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - @@ -1607,16 +380,6 @@ mDNSlocal void ExitCallback(int sig) (void)sig; // Unused LogMsg("%s stopping", mDNSResponderVersionString); - debugf("ExitCallback: Aborting MIG clients"); - while (DNSServiceDomainEnumerationList) - AbortClient(DNSServiceDomainEnumerationList->ClientMachPort, DNSServiceDomainEnumerationList); - while (DNSServiceBrowserList) - AbortClient(DNSServiceBrowserList->ClientMachPort, DNSServiceBrowserList); - while (DNSServiceResolverList) - AbortClient(DNSServiceResolverList->ClientMachPort, DNSServiceResolverList); - while (DNSServiceRegistrationList) - AbortClient(DNSServiceRegistrationList->ClientMachPort, DNSServiceRegistrationList); - if (udsserver_exit() < 0) LogMsg("ExitCallback: udsserver_exit failed"); @@ -1626,99 +389,6 @@ mDNSlocal void ExitCallback(int sig) #ifndef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM -mDNSlocal void DNSserverCallback(CFMachPortRef port, void *msg, CFIndex size, void *info) -{ - mig_reply_error_t *request = msg; - mig_reply_error_t *reply; - mach_msg_return_t mr; - int options; - (void)port; // Unused - (void)size; // Unused - (void)info; // Unused - - KQueueLock(&mDNSStorage); - - /* allocate a reply buffer */ - reply = CFAllocatorAllocate(NULL, provide_DNSServiceDiscoveryRequest_subsystem.maxsize, 0); - - /* call the MiG server routine */ - (void) DNSServiceDiscoveryRequest_server(&request->Head, &reply->Head); - - if (!(reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) && (reply->RetCode != KERN_SUCCESS)) - { - if (reply->RetCode == MIG_NO_REPLY) - { - /* - * This return code is a little tricky -- it appears that the - * demux routine found an error of some sort, but since that - * error would not normally get returned either to the local - * user or the remote one, we pretend it's ok. - */ - CFAllocatorDeallocate(NULL, reply); - goto done; - } - - /* - * destroy any out-of-line data in the request buffer but don't destroy - * the reply port right (since we need that to send an error message). - */ - request->Head.msgh_remote_port = MACH_PORT_NULL; - mach_msg_destroy(&request->Head); - } - - if (reply->Head.msgh_remote_port == MACH_PORT_NULL) - { - /* no reply port, so destroy the reply */ - if (reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) - mach_msg_destroy(&reply->Head); - CFAllocatorDeallocate(NULL, reply); - goto done; - } - - /* - * send reply. - * - * We don't want to block indefinitely because the client - * isn't receiving messages from the reply port. - * If we have a send-once right for the reply port, then - * this isn't a concern because the send won't block. - * If we have a send right, we need to use MACH_SEND_TIMEOUT. - * To avoid falling off the kernel's fast RPC path unnecessarily, - * we only supply MACH_SEND_TIMEOUT when absolutely necessary. - */ - - options = MACH_SEND_MSG; - if (MACH_MSGH_BITS_REMOTE(reply->Head.msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE) - options |= MACH_SEND_TIMEOUT; - - mr = mach_msg(&reply->Head, /* msg */ - options, /* option */ - reply->Head.msgh_size, /* send_size */ - 0, /* rcv_size */ - MACH_PORT_NULL, /* rcv_name */ - MACH_MSG_TIMEOUT_NONE, /* timeout */ - MACH_PORT_NULL); /* notify */ - - /* Has a message error occurred? */ - switch (mr) - { - case MACH_SEND_INVALID_DEST: - case MACH_SEND_TIMED_OUT: - /* the reply can't be delivered, so destroy it */ - mach_msg_destroy(&reply->Head); - break; - - default: - /* Includes success case. */ - break; - } - - CFAllocatorDeallocate(NULL, reply); - -done: - KQueueUnlock(&mDNSStorage, "Mach client event"); -} - // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit mDNSlocal void HandleSIG(int sig) { @@ -1744,7 +414,7 @@ mDNSlocal void HandleSIG(int sig) #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM -mDNSlocal void INFOCallback(void) +mDNSexport void INFOCallback(void) { mDNSs32 utc = mDNSPlatformUTC(); const mDNSs32 now = mDNS_TimeNow(&mDNSStorage); @@ -1752,11 +422,6 @@ mDNSlocal void INFOCallback(void) DNSServer *s; McastResolver *mr; - // Create LoggerID(Key)->com.apple.networking.mDNSResponder(Value) pair when SIGINFO is received. - // This key-value pair is used as a condition by syslogd to Log to com.apple.networking.mDNSResponder.log file - // present in /etc/asl/com.apple.networking.mDNSResponder. - asl_set(log_msg, "LoggerID", "com.apple.networking.mDNSResponder"); - LogMsg("---- BEGIN STATE LOG ---- %s %s %d", mDNSResponderVersionString, OSXVers ? "OSXVers" : "iOSVers", OSXVers ? OSXVers : iOSVers); udsserver_info(&mDNSStorage); @@ -1821,14 +486,10 @@ mDNSlocal void INFOCallback(void) for (s = mDNSStorage.DNSServers; s; s = s->next) { NetworkInterfaceInfoOSX *ifx = IfindexToInterfaceInfoOSX(&mDNSStorage, s->interface); - LogMsgNoIdent("DNS Server %##s %s%s%#a:%d %d %s %d %d %s %s %s %s %s", + LogMsgNoIdent("DNS Server %##s %s%s%#a:%d %d %s %d %d %s %s %s %s", s->domain.c, ifx ? ifx->ifinfo.ifname : "", ifx ? " " : "", &s->addr, mDNSVal16(s->port), s->penaltyTime ? s->penaltyTime - mDNS_TimeNow(&mDNSStorage) : 0, DNSScopeToString(s->scoped), s->timeout, s->resGroupID, - s->teststate == DNSServer_Untested ? "(Untested)" : - s->teststate == DNSServer_Passed ? "" : - s->teststate == DNSServer_Failed ? "(Failed)" : - s->teststate == DNSServer_Disabled ? "(Disabled)" : "(Unknown state)", s->req_A ? "v4" : "!v4", s->req_AAAA ? "v6" : "!v6", s->cellIntf ? "cell" : "!cell", @@ -1848,75 +509,40 @@ mDNSlocal void INFOCallback(void) LogMsgNoIdent("Mcast Resolver %##s timeout %u", mr->domain.c, mr->timeout); } + LogMsgNoIdent("------------ Hostnames -------------"); + if (!mDNSStorage.Hostnames) LogMsgNoIdent(""); + else + { + HostnameInfo *hi; + for (hi = mDNSStorage.Hostnames; hi; hi = hi->next) + { + LogMsgNoIdent("%##s v4 %d %s", hi->fqdn.c, hi->arv4.state, ARDisplayString(&mDNSStorage, &hi->arv4)); + LogMsgNoIdent("%##s v6 %d %s", hi->fqdn.c, hi->arv6.state, ARDisplayString(&mDNSStorage, &hi->arv6)); + } + } + + LogMsgNoIdent("--------------- FQDN ---------------"); + if (!mDNSStorage.FQDN.c[0]) LogMsgNoIdent(""); + else + { + LogMsgNoIdent("%##s", mDNSStorage.FQDN.c); + } + #if TARGET_OS_EMBEDDED LogMetrics(); #endif LogMsgNoIdent("Timenow 0x%08lX (%d)", (mDNSu32)now, now); LogMsg("---- END STATE LOG ---- %s %s %d", mDNSResponderVersionString, OSXVers ? "OSXVers" : "iOSVers", OSXVers ? OSXVers : iOSVers); - - // If logging is disabled, only then clear the key we set at the top of this func - if (!mDNS_LoggingEnabled) - asl_unset(log_msg, "LoggerID"); } -mDNSlocal void DebugSetFilter() -{ - if (!log_client) - return; - - // When USR1 is turned on, we log only the LOG_WARNING and LOG_NOTICE messages by default. - // The user has to manually do "syslog -c mDNSResponder -i" to get the LOG_INFO messages - // also to be logged. Most of the times, we need the INFO level messages for debugging. - // Hence, we set the filter to INFO level when USR1 logging is turned on to avoid - // having the user to do this extra step manually. - - if (mDNS_LoggingEnabled) - { - asl_set_filter(log_client, ASL_FILTER_MASK_UPTO(ASL_LEVEL_INFO)); - asl_set(log_msg, "LoggerID", "com.apple.networking.mDNSResponder"); - // Create LoggerID(Key)->com.apple.networking.mDNSResponder(Value) pair when USR1 Logging is Enabled. - // This key-value pair is used as a condition by syslogd to Log to com.apple.networking.mDNSResponder.log file - // present in /etc/asl/com.apple.networking.mDNSResponder. - } - else - { - asl_set_filter(log_client, ASL_FILTER_MASK_UPTO(ASL_LEVEL_ERR)); - asl_unset(log_msg, "LoggerID"); - // Clear the key-value pair when USR1 Logging is Disabled, as we do not want to log to - // com.apple.networking.mDNSResponder.log file in this case. - } -} mDNSexport void mDNSPlatformLogToFile(int log_level, const char *buffer) { - int asl_level = ASL_LEVEL_ERR; - - if (!log_client) - { - syslog(log_level, "%s", buffer); - return; - } - switch (log_level) - { - case LOG_ERR: - asl_level = ASL_LEVEL_ERR; - break; - case LOG_WARNING: - asl_level = ASL_LEVEL_WARNING; - break; - case LOG_NOTICE: - asl_level = ASL_LEVEL_NOTICE; - break; - case LOG_INFO: - asl_level = ASL_LEVEL_INFO; - break; - case LOG_DEBUG: - asl_level = ASL_LEVEL_DEBUG; - break; - default: - break; - } - asl_log(log_client, log_msg, asl_level, "%s", buffer); + if (!log_general) + os_log_error(OS_LOG_DEFAULT, "Could NOT create log handle in init_logging()"); + else + os_log_with_type(log_general, log_level, "%s", buffer); + } // Writes the state out to the dynamic store and also affects the ASL filter level @@ -1970,35 +596,9 @@ mDNSexport void UpdateDebugState() CFRelease(numZero); mDNSDynamicStoreSetConfig(kmDNSDebugState, mDNSNULL, dict); CFRelease(dict); - // If we turned off USR1 logging, we need to reset the filter - DebugSetFilter(); -} -#if TARGET_OS_EMBEDDED -mDNSlocal void Prefschanged() -{ - mDNSBool mDNSProf_installed; - LogMsg("Prefschanged: mDNSResponder Managed Preferences have changed"); - mDNSProf_installed = GetmDNSManagedPref(kmDNSEnableLoggingStr); - dispatch_async(dispatch_get_main_queue(), - ^{ - if (mDNSProf_installed) - { - mDNS_LoggingEnabled = mDNS_PacketLoggingEnabled = 1; - } - else - { - LogMsg("Prefschanged: mDNSDebugProfile is uninstalled -> Turning OFF USR1/USR2 Logging with SIGINFO o/p"); - INFOCallback(); - mDNS_LoggingEnabled = mDNS_PacketLoggingEnabled = 0; - } - UpdateDebugState(); - // If Logging Enabled: Start Logging to com.apple.networking.mDNSResponder.log (has to be LogInfo) - LogInfo("Prefschanged: mDNSDebugProfile is installed -> Turned ON USR1/USR2 Logging"); - }); - return; } -#endif //TARGET_OS_EMBEDDED + #ifndef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM @@ -2031,15 +631,26 @@ mDNSlocal void SignalCallback(CFMachPortRef port, void *msg, CFIndex size, void case SIGINT: case SIGTERM: ExitCallback(msg_header->msgh_id); break; case SIGINFO: INFOCallback(); break; - case SIGUSR1: mDNS_LoggingEnabled = mDNS_LoggingEnabled ? 0 : 1; + case SIGUSR1: +#if APPLE_OSX_mDNSResponder + mDNS_LoggingEnabled = 1; + LogMsg("SIGUSR1: Logging %s on Apple Platforms", mDNS_LoggingEnabled ? "Enabled" : "Disabled"); +#else + mDNS_LoggingEnabled = mDNS_LoggingEnabled ? 0 : 1; LogMsg("SIGUSR1: Logging %s", mDNS_LoggingEnabled ? "Enabled" : "Disabled"); +#endif WatchDogReportingThreshold = mDNS_LoggingEnabled ? 50 : 250; UpdateDebugState(); - // If Logging Enabled: Start Logging to com.apple.networking.mDNSResponder.log - LogInfo("USR1 Logging Enabled: Start Logging to mDNSResponder Log file"); + LogInfo("USR1 Logging Enabled"); break; - case SIGUSR2: mDNS_PacketLoggingEnabled = mDNS_PacketLoggingEnabled ? 0 : 1; + case SIGUSR2: +#if APPLE_OSX_mDNSResponder + mDNS_PacketLoggingEnabled = 1; + LogMsg("SIGUSR2: Packet Logging %s on Apple Platforms", mDNS_PacketLoggingEnabled ? "Enabled" : "Disabled"); +#else + mDNS_PacketLoggingEnabled = mDNS_PacketLoggingEnabled ? 0 : 1; LogMsg("SIGUSR2: Packet Logging %s", mDNS_PacketLoggingEnabled ? "Enabled" : "Disabled"); +#endif mDNS_McastTracingEnabled = (mDNS_PacketLoggingEnabled && mDNS_McastLoggingEnabled) ? mDNStrue : mDNSfalse; LogInfo("SIGUSR2: Multicast Tracing is %s", mDNS_McastTracingEnabled ? "Enabled" : "Disabled"); UpdateDebugState(); @@ -2065,37 +676,24 @@ mDNSlocal void SignalCallback(CFMachPortRef port, void *msg, CFIndex size, void mDNSlocal kern_return_t mDNSDaemonInitialize(void) { mStatus err; - CFMachPortRef s_port; - CFRunLoopSourceRef s_rls; - CFRunLoopSourceRef d_rls; - - s_port = CFMachPortCreateWithPort(NULL, m_port, DNSserverCallback, NULL, NULL); - CFMachPortRef d_port = CFMachPortCreate(NULL, ClientDeathCallback, NULL, NULL); err = mDNS_Init(&mDNSStorage, &PlatformStorage, rrcachestorage, RR_CACHE_SIZE, - advertise, + !NoMulticastAdvertisements, mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext); - if (err) { LogMsg("Daemon start: mDNS_Init failed %d", err); return(err); } - - client_death_port = CFMachPortGetPort(d_port); - - s_rls = CFMachPortCreateRunLoopSource(NULL, s_port, 0); - CFRunLoopAddSource(PlatformStorage.CFRunLoop, s_rls, kCFRunLoopDefaultMode); - CFRelease(s_rls); - - d_rls = CFMachPortCreateRunLoopSource(NULL, d_port, 0); - CFRunLoopAddSource(PlatformStorage.CFRunLoop, d_rls, kCFRunLoopDefaultMode); - CFRelease(d_rls); + if (err) + { + LogMsg("Daemon start: mDNS_Init failed %d", err); + return(err); + } CFMachPortRef i_port = CFMachPortCreate(NULL, SignalCallback, NULL, NULL); CFRunLoopSourceRef i_rls = CFMachPortCreateRunLoopSource(NULL, i_port, 0); signal_port = CFMachPortGetPort(i_port); - CFRunLoopAddSource(PlatformStorage.CFRunLoop, i_rls, kCFRunLoopDefaultMode); + CFRunLoopAddSource(CFRunLoopGetMain(), i_rls, kCFRunLoopDefaultMode); CFRelease(i_rls); - - if (mDNS_DebugMode) printf("Service registered with Mach Port %d\n", m_port); + return(err); } @@ -2162,28 +760,21 @@ mDNSlocal void mDNSSetupSignal(dispatch_queue_t queue, int sig) } } -// On 10.2 the MachServerName is DNSServiceDiscoveryServer -// On 10.3 and later, the MachServerName is com.apple.mDNSResponder mDNSlocal kern_return_t mDNSDaemonInitialize(void) { mStatus err; - dispatch_source_t mach_source; dispatch_queue_t queue = dispatch_get_main_queue(); err = mDNS_Init(&mDNSStorage, &PlatformStorage, rrcachestorage, RR_CACHE_SIZE, - advertise, + !NoMulticastAdvertisements, mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext); - if (err) { LogMsg("Daemon start: mDNS_Init failed %d", err); return(err); } - - mach_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, m_port, 0, queue); - if (mach_source == mDNSNULL) {LogMsg("mDNSDaemonInitialize: Error creating source for m_port"); return -1;} - dispatch_source_set_event_handler(mach_source, ^{ - dispatch_mig_server(mach_source, sizeof(union __RequestUnion__DNSServiceDiscoveryReply_subsystem), - DNSServiceDiscoveryRequest_server); - }); - dispatch_resume(mach_source); + if (err) + { + LogMsg("Daemon start: mDNS_Init failed %d", err); + return(err); + } mDNSSetupSignal(queue, SIGHUP); mDNSSetupSignal(queue, SIGINT); @@ -2215,7 +806,6 @@ mDNSlocal kern_return_t mDNSDaemonInitialize(void) LogMsg("DaemonIntialize done successfully"); - if (mDNS_DebugMode) printf("Service registered with Mach Port %d\n", m_port); return(err); } @@ -2245,7 +835,11 @@ mDNSlocal mDNSs32 mDNSDaemonIdle(mDNS *const m) // we then systematically lose our own looped-back packets. if (m->NetworkChanged && now - m->NetworkChanged >= 0) mDNSMacOSXNetworkChanged(m); - if (m->p->RequestReSleep && now - m->p->RequestReSleep >= 0) { m->p->RequestReSleep = 0; mDNSPowerRequest(0, 0); } + if (m->p->RequestReSleep && now - m->p->RequestReSleep >= 0) + { + m->p->RequestReSleep = 0; + mDNSPowerRequest(0, 0); + } // 3. Call mDNS_Execute() to let mDNSCore do what it needs to do mDNSs32 nextevent = mDNS_Execute(m); @@ -2262,61 +856,7 @@ mDNSlocal mDNSs32 mDNSDaemonIdle(mDNS *const m) if (nextevent - m->p->RequestReSleep > 0) nextevent = m->p->RequestReSleep; - // 4. Deliver any waiting browse messages to clients - DNSServiceBrowser *b = DNSServiceBrowserList; - - while (b) - { - // Note: Need to advance b to the next element BEFORE we call DeliverInstance(), because in the - // event that the client Mach queue overflows, DeliverInstance() will call AbortBlockedClient() - // and that will cause the DNSServiceBrowser object's memory to be freed before it returns - DNSServiceBrowser *x = b; - b = b->next; - if (x->results) // Try to deliver the list of results - { - while (x->results) - { - DNSServiceBrowserResult *const r = x->results; - domainlabel name; - domainname type, domain; - DeconstructServiceName(&r->result, &name, &type, &domain); // Don't need to check result; already validated in FoundInstance() - char cname[MAX_DOMAIN_LABEL+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL. - char ctype[MAX_ESCAPED_DOMAIN_NAME]; - char cdom [MAX_ESCAPED_DOMAIN_NAME]; - ConvertDomainLabelToCString_unescaped(&name, cname); - ConvertDomainNameToCString(&type, ctype); - ConvertDomainNameToCString(&domain, cdom); - DNSServiceDiscoveryReplyFlags flags = (r->next) ? DNSServiceDiscoverReplyFlagsMoreComing : 0; - kern_return_t status = DNSServiceBrowserReply_rpc(x->ClientMachPort, r->resultType, cname, ctype, cdom, flags, 1); - // If we failed to send the mach message, try again in one second - if (status == MACH_SEND_TIMED_OUT) - { - if (nextevent - now > mDNSPlatformOneSecond) - nextevent = now + mDNSPlatformOneSecond; - break; - } - else - { - x->lastsuccess = now; - x->results = x->results->next; - freeL("DNSServiceBrowserResult", r); - } - } - // If this client hasn't read a single message in the last 60 seconds, abort it - if (now - x->lastsuccess >= 60 * mDNSPlatformOneSecond) - AbortBlockedClient(x->ClientMachPort, "browse", x); - } - } - - DNSServiceResolver *l; - for (l = DNSServiceResolverList; l; l=l->next) - if (l->ReportTime && now - l->ReportTime >= 0) - { - l->ReportTime = 0; - LogMsgNoIdent("Client application bug: DNSServiceResolver(%##s) active for over two minutes. " - "This places considerable burden on the network.", l->i.name.c); - } - + if (m->p->NotifyUser) { if (m->p->NotifyUser - now < 0) @@ -2488,7 +1028,8 @@ mDNSlocal mDNSBool AllowSleepNow(mDNS *const m, mDNSs32 now) // so we should put it back to sleep. To avoid frustrating the user, we always request at least // 60 seconds sleep, so if they immediately re-wake the system within seconds of it going to sleep, // we then shouldn't hit our 30-second window, and we won't attempt to re-sleep the machine. - if (interval < 60) interval = 60; + if (interval < 60) + interval = 60; result = mDNSPowerRequest(1, interval); @@ -2683,7 +1224,7 @@ mDNSlocal void * KQueueLoop(void *m_param) LogInfo("WARNING: Idle task took %dms to complete", end - start); #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1 - validatelists(m, true); + validatelists(m); #endif mDNSs32 now = mDNS_TimeNow(m); @@ -2810,44 +1351,109 @@ mDNSlocal void * KQueueLoop(void *m_param) #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM -mDNSlocal void LaunchdCheckin(void) +mDNSlocal size_t LaunchdCheckin(void) { // Ask launchd for our socket int result = launch_activate_socket("Listeners", &launchd_fds, &launchd_fds_count); if (result != 0) { LogMsg("launch_activate_socket() failed errno %d (%s)", errno, strerror(errno)); } + return launchd_fds_count; } -static mach_port_t RegisterMachService(const char *service_name) + +extern int sandbox_init(const char *profile, uint64_t flags, char **errorbuf) __attribute__((weak_import)); + +#if APPLE_OSX_mDNSResponder +mDNSlocal mDNSBool PreferencesGetValueBool(CFStringRef key, mDNSBool defaultValue) { - mach_port_t port = MACH_PORT_NULL; - kern_return_t kr; - - if (KERN_SUCCESS != (kr = bootstrap_check_in(bootstrap_port, (char *)service_name, &port))) - { - LogMsg("RegisterMachService: %d %X %s", kr, kr, mach_error_string(kr)); - return MACH_PORT_NULL; - } - - if (KERN_SUCCESS != (kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND))) - { - LogMsg("RegisterMachService: %d %X %s", kr, kr, mach_error_string(kr)); - mach_port_deallocate(mach_task_self(), port); - return MACH_PORT_NULL; - } - - return port; + CFBooleanRef boolean; + mDNSBool result = defaultValue; + + boolean = CFPreferencesCopyAppValue(key, kProgramArguments); + if (boolean) + { + if (CFGetTypeID(boolean) == CFBooleanGetTypeID()) + result = CFBooleanGetValue(boolean) ? mDNStrue : mDNSfalse; + CFRelease(boolean); + } + + return result; } -extern int sandbox_init(const char *profile, uint64_t flags, char **errorbuf) __attribute__((weak_import)); +mDNSlocal int PreferencesGetValueInt(CFStringRef key, int defaultValue) +{ + CFNumberRef number; + int numberValue; + int result = defaultValue; + + number = CFPreferencesCopyAppValue(key, kProgramArguments); + if (number) + { + if ((CFGetTypeID(number) == CFNumberGetTypeID()) && CFNumberGetValue(number, kCFNumberIntType, &numberValue)) + result = numberValue; + CFRelease(number); + } + + return result; +} +#endif + +mDNSlocal void SandboxProcess(void) +{ + // Invoke sandbox profile /usr/share/sandbox/mDNSResponder.sb +#if MDNS_NO_SANDBOX + LogMsg("Note: Compiled without Apple Sandbox support"); +#else // MDNS_NO_SANDBOX + if (!sandbox_init) + LogMsg("Note: Running without Apple Sandbox support (not available on this OS)"); + else + { + char *sandbox_msg; + uint64_t sandbox_flags = SANDBOX_NAMED; + + (void)confstr(_CS_DARWIN_USER_CACHE_DIR, NULL, 0); + + int sandbox_err = sandbox_init("mDNSResponder", sandbox_flags, &sandbox_msg); + if (sandbox_err) + { + LogMsg("WARNING: sandbox_init error %s", sandbox_msg); + // If we have errors in the sandbox during development, to prevent + // exiting, uncomment the following line. + //sandbox_free_error(sandbox_msg); + + errx(EX_OSERR, "sandbox_init() failed: %s", sandbox_msg); + } + else LogInfo("Now running under Apple Sandbox restrictions"); + } +#endif // MDNS_NO_SANDBOX +} + +#if APPLE_OSX_mDNSResponder +mDNSlocal void init_logging(void) +{ + log_general = os_log_create("com.apple.mDNSResponder", "AllINFO"); + + if (!log_general) + { + // OS_LOG_DEFAULT is the default logging object, if you are not creating a custom subsystem/category + os_log_error(OS_LOG_DEFAULT, "Could NOT create log handle in mDNSResponder"); + } +} +#endif mDNSexport int main(int argc, char **argv) { int i; kern_return_t status; - log_client = asl_open(NULL, "mDNSResponder", 0); - log_msg = asl_new(ASL_TYPE_MSG); - +#if DEBUG + bool useDebugSocket = mDNSfalse; + bool useSandbox = mDNStrue; +#endif + +#if APPLE_OSX_mDNSResponder + init_logging(); +#endif + mDNSMacOSXSystemBuildNumber(NULL); LogMsg("%s starting %s %d", mDNSResponderVersionString, OSXVers ? "OSXVers" : "iOSVers", OSXVers ? OSXVers : iOSVers); @@ -2872,7 +1478,7 @@ mDNSexport int main(int argc, char **argv) for (i=1; i com.apple.mDNSResponder.dnsproxy + com.apple.mDNSResponder.dnsctl + diff --git a/mDNSResponder/mDNSMacOSX/helper-error.h b/mDNSResponder/mDNSMacOSX/helper-error.h deleted file mode 100644 index 6465b734..00000000 --- a/mDNSResponder/mDNSMacOSX/helper-error.h +++ /dev/null @@ -1,49 +0,0 @@ -/* -*- Mode: C; tab-width: 4 -*- - * - * Copyright (c) 2007-2013 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. - */ - -ERROR(kmDNSHelperCommunicationFailed, "Mach communication failed") -ERROR(kmDNSHelperNotAuthorized, "Not authorized") -ERROR(kmDNSHelperCreationFailed, "Object creation failed") -ERROR(kmDNSHelperInvalidPList, "Invalid property list") -ERROR(kmDNSHelperInvalidNameKey, "Invalid name key") -ERROR(kmDNSHelperInvalidConfigKey, "Invalid configuration key") -ERROR(kmDNSHelperTypeError, "Object was not of expected type") -ERROR(kmDNSHelperPreferencesFailed, "Could not create preferences session") -ERROR(kmDNSHelperPreferencesLockFailed, "Could not lock preferences") -ERROR(kmDNSHelperPreferencesSetFailed, "Could not update preferences") -ERROR(kmDNSHelperKeychainCopyDefaultFailed, "Could not copy keychain default") -ERROR(kmDNSHelperKeychainSearchCreationFailed, "Could not create keychain search") -ERROR(kmDNSHelperPListWriteFailed, "Could not write property list to stream") -ERROR(kmDNSHelperResultTooLarge, "Result too large") -ERROR(kmDNSHelperInterfaceCreationFailed, "Could not create auto-tunnel interface") -ERROR(kmDNSHelperInterfaceDeletionFailed, "Could not delete auto-tunnel interface") -ERROR(kmDNSHelperInvalidInterfaceState, "Invalid interface state requested") -ERROR(kmDNSHelperInvalidServerState, "Invalid server state requested") -ERROR(kmDNSHelperRacoonConfigCreationFailed, "Could not create racoon configuration file") -ERROR(kmDNSHelperRacoonStartFailed, "Could not start racoon") -ERROR(kmDNSHelperRacoonNotificationFailed, "Could not notify racoon") -ERROR(kmDNSHelperInvalidTunnelSetKeysOperation, "Invalid tunnel setkey operation requested") -ERROR(kmDNSHelperInvalidNetworkAddress, "Invalid network address") -ERROR(kmDNSHelperRouteAdditionFailed, "Could not add route") -ERROR(kmDNSHelperRouteDeletionFailed, "Could not remove route") -ERROR(kmDNSHelperRoutingSocketCreationFailed, "Could not create routing socket") -ERROR(kmDNSHelperDatagramSocketCreationFailed, "Could not create datagram socket") -ERROR(kmDNSHelperIPsecPolicyCreationFailed, "Could not create IPsec policy") -ERROR(kmDNSHelperIPsecPolicySetFailed, "Could not set IPsec policy") -ERROR(kmDNSHelperIPsecRemoveSAFailed, "Could not remove IPsec SA") -ERROR(kmDNSHelperIPsecPolicySocketCreationFailed, "Could not create IPsec policy socket") -ERROR(kmDNSHelperIPsecDisabled, "IPSec support was not compiled in to the helper") diff --git a/mDNSResponder/mDNSMacOSX/helper-main.c b/mDNSResponder/mDNSMacOSX/helper-main.c index 5e4d9481..9c61e48c 100644 --- a/mDNSResponder/mDNSMacOSX/helper-main.c +++ b/mDNSResponder/mDNSMacOSX/helper-main.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -37,8 +36,7 @@ #include #include "helper.h" #include "helper-server.h" -#include "helpermsg.h" -#include "helpermsgServer.h" +#include #if TARGET_OS_EMBEDDED #define NO_SECURITYFRAMEWORK 1 @@ -50,14 +48,11 @@ #define launch_data_get_machport launch_data_get_fd #endif -union max_msg_size -{ - union __RequestUnion__proxy_helper_subsystem req; - union __ReplyUnion__proxy_helper_subsystem rep; -}; -static const mach_msg_size_t MAX_MSG_SIZE = sizeof(union max_msg_size) + MAX_TRAILER_SIZE; -static aslclient logclient = NULL; +int mDNSHelperLogEnabled = 0; +os_log_t log_handle = NULL; + +static dispatch_queue_t xpc_queue = NULL; static int opt_debug; static pthread_t idletimer_thread; @@ -67,45 +62,24 @@ unsigned long actualidle = 3600; CFRunLoopRef gRunLoop = NULL; CFRunLoopTimerRef gTimer = NULL; -mach_port_t gPort = MACH_PORT_NULL; - -static void helplogv(int level, const char *fmt, va_list ap) -{ - if (NULL == logclient) { vfprintf(stderr, fmt, ap); fflush(stderr); } - else asl_vlog(logclient, NULL, level, fmt, ap); -} - -void helplog(int level, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - helplogv(level, fmt, ap); - va_end(ap); -} - -// for safe_vproc -void LogMsgWithLevel(mDNSLogLevel_t logLevel, const char *fmt, ...) -{ - (void)logLevel; - va_list ap; - va_start(ap, fmt); - // safe_vproc only calls LogMsg, so assume logLevel maps to ASL_LEVEL_ERR - helplog(ASL_LEVEL_ERR, fmt, ap); - va_end(ap); -} static void handle_sigterm(int sig) { - // debug("entry sig=%d", sig); Can't use syslog from within a signal handler + // os_log_debug(log_handle,"entry sig=%d", sig); Can't use syslog from within a signal handler assert(sig == SIGTERM); - (void)proxy_mDNSExit(gPort); + helper_exit(); } static void initialize_logging(void) { - logclient = asl_open(NULL, "mDNSResponderHelper", (opt_debug ? ASL_OPT_STDERR : 0)); - if (NULL == logclient) { fprintf(stderr, "Could not initialize ASL logging.\n"); fflush(stderr); return; } - if (opt_debug) asl_set_filter(logclient, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG)); + log_handle = os_log_create("com.apple.mDNSResponderHelper", "INFO"); + + if (!log_handle) + { + // OS_LOG_DEFAULT is the default logging object, if you are not creating a custom subsystem/category + os_log_error(OS_LOG_DEFAULT, "Could NOT create log handle in mDNSResponderHelper"); + } + } static void initialize_id(void) @@ -116,23 +90,29 @@ static void initialize_id(void) hardcode.pw_uid = 65; hardcode.pw_gid = 65; - if (!pwd) { helplog(ASL_LEVEL_ERR, "Could not find account name `%s'. I will only help root.", login); return; } + if (!pwd) + { + os_log(log_handle, "Could not find account name `%s'. I will only help root.", login); + return; + } mDNSResponderUID = pwd->pw_uid; mDNSResponderGID = pwd->pw_gid; } static void diediedie(CFRunLoopTimerRef timer, void *context) { - debug("entry %p %p %d", timer, context, actualidle); + os_log_info(log_handle, "entry %p %p %lu", timer, context, actualidle); + assert(gTimer == timer); - helplog(ASL_LEVEL_INFO, "mDNSResponder exiting after %d seconds", actualidle); + os_log_info(log_handle, "mDNSResponderHelper exiting after [%lu] seconds", actualidle); + if (actualidle) - (void)proxy_mDNSExit(gPort); + helper_exit(); } void pause_idle_timer(void) { - debug("entry"); + os_log_debug(log_handle,"entry"); assert(gTimer); assert(gRunLoop); CFRunLoopRemoveTimer(gRunLoop, gTimer, kCFRunLoopDefaultMode); @@ -140,7 +120,7 @@ void pause_idle_timer(void) void unpause_idle_timer(void) { - debug("entry"); + os_log_debug(log_handle,"entry"); assert(gRunLoop); assert(gTimer); CFRunLoopAddTimer(gRunLoop, gTimer, kCFRunLoopDefaultMode); @@ -148,21 +128,21 @@ void unpause_idle_timer(void) void update_idle_timer(void) { - debug("entry"); + os_log_debug(log_handle,"entry"); assert(gTimer); CFRunLoopTimerSetNextFireDate(gTimer, CFAbsoluteTimeGetCurrent() + actualidle); } static void *idletimer(void *context) { - debug("entry context=%p", context); - gRunLoop = CFRunLoopGetCurrent(); + os_log_debug(log_handle,"entry context=%p", context); + gRunLoop = CFRunLoopGetMain(); unpause_idle_timer(); for (;;) { - debug("Running CFRunLoop"); + // os_log_debug(log_handle,"Running CFRunLoop"); CFRunLoopRun(); sleep(1); } @@ -174,106 +154,504 @@ static int initialize_timer() { gTimer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + actualidle, actualidle, 0, 0, diediedie, NULL); int err = 0; + os_log_info(log_handle, "mDNSResponderHelper initialize_timer() started"); - debug("entry"); if (0 != (err = pthread_create(&idletimer_thread, NULL, idletimer, NULL))) - helplog(ASL_LEVEL_ERR, "Could not start idletimer thread: %s", strerror(err)); + os_log(log_handle, "Could not start idletimer thread: %s", strerror(err)); return err; } -static mach_port_t register_service(const char *service_name) +/* + Reads the user's program arguments for mDNSResponderHelper + For now we have only one option: mDNSHelperDebugLogging which is used to turn on mDNSResponderHelperLogging + + To turn ON mDNSResponderHelper Verbose Logging, + 1] sudo defaults write /Library/Preferences/com.apple.mDNSResponderHelper.plist mDNSHelperDebugLogging -bool YES + 2] sudo reboot + + To turn OFF mDNSResponderHelper Logging, + 1] sudo defaults delete /Library/Preferences/com.apple.mDNSResponderHelper.plist + + To view the current options set, + 1] plutil -p /Library/Preferences/com.apple.mDNSResponderHelper.plist + OR + 1] sudo defaults read /Library/Preferences/com.apple.mDNSResponderHelper.plist +*/ + +static mDNSBool HelperPrefsGetValueBool(CFStringRef key, mDNSBool defaultVal) +{ + CFBooleanRef boolean; + mDNSBool result = defaultVal; + + boolean = CFPreferencesCopyAppValue(key, kmDNSHelperProgramArgs); + if (boolean) + { + if (CFGetTypeID(boolean) == CFBooleanGetTypeID()) + result = CFBooleanGetValue(boolean) ? mDNStrue : mDNSfalse; + CFRelease(boolean); + } + + return result; +} + + +// Verify Client's Entitlement +static mDNSBool check_entitlement(xpc_connection_t conn, const char *password) +{ + mDNSBool entitled = mDNSfalse; + xpc_object_t ent = xpc_connection_copy_entitlement_value(conn, password); + + if (ent) + { + if (xpc_get_type(ent) == XPC_TYPE_BOOL && xpc_bool_get_value(ent)) + { + entitled = mDNStrue; + } + xpc_release(ent); + } + else + { + os_log(log_handle, "client entitlement is NULL"); + } + + if (!entitled) + os_log(log_handle, "entitlement check failed -> client is missing entitlement!"); + + return entitled; +} + + +static void handle_request(xpc_object_t req) { - mach_port_t port = MACH_PORT_NULL; - kern_return_t kr; + mDNSu32 helper_mode = 0; + int error_code = 0; + + xpc_connection_t remote_conn = xpc_dictionary_get_remote_connection(req); + xpc_object_t response = xpc_dictionary_create_reply(req); + + // switch here based on dictionary to handle different requests from mDNSResponder + if ((xpc_dictionary_get_uint64(req, kHelperMode))) + { + os_log_info(log_handle, "Getting mDNSResponder request mode"); + helper_mode = (mDNSu32)(xpc_dictionary_get_uint64(req, kHelperMode)); + } + + switch (helper_mode) + { + case bpf_request: + { + os_log_info(log_handle, "Calling new RequestBPF()"); + RequestBPF(); + break; + } + + case set_name: + { + const char *old_name; + const char *new_name; + int pref_key = 0; + + pref_key = (int)(xpc_dictionary_get_uint64(req, kPrefsNameKey)); + old_name = xpc_dictionary_get_string(req, kPrefsOldName); + new_name = xpc_dictionary_get_string(req, kPrefsNewName); + + os_log_info(log_handle, "Calling new SetName() oldname: %s newname: %s key:%d", old_name, new_name, pref_key); + PreferencesSetName(pref_key, old_name, new_name); + break; + } + + case p2p_packetfilter: + { + pfArray_t pfports; + pfArray_t pfprotocols; + const char *if_name; + uint32_t cmd; + uint32_t count; + + cmd = xpc_dictionary_get_uint64(req, "pf_opcode"); + if_name = xpc_dictionary_get_string(req, "pf_ifname"); + count = xpc_dictionary_get_uint64(req, "pf_count"); + + pfports[0] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_port0"); + pfports[1] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_port1"); + pfports[2] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_port2"); + pfports[3] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_port3"); + + pfprotocols[0] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_protocol0"); + pfprotocols[1] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_protocol1"); + pfprotocols[2] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_protocol2"); + pfprotocols[3] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_protocol3"); + + os_log_info(log_handle,"Calling new PacketFilterControl()"); + PacketFilterControl(cmd, if_name, count, pfports, pfprotocols); + break; + } + + case user_notify: + { + const char *title; + const char *msg; + title = xpc_dictionary_get_string(req, "notify_title"); + msg = xpc_dictionary_get_string(req, "notify_msg"); + + os_log_info(log_handle,"Calling new UserNotify() title:%s msg:%s", title, msg); + UserNotify(title, msg); + break; + } + + case power_req: + { + int key, interval; + key = xpc_dictionary_get_uint64(req, "powerreq_key"); + interval = xpc_dictionary_get_uint64(req, "powerreq_interval"); + + os_log_info(log_handle,"Calling new PowerRequest() key[%d] interval[%d]", key, interval); + PowerRequest(key, interval, &error_code); + break; + } + + case send_wakepkt: + { + const char *ether_addr; + const char *ip_addr; + int iteration; + unsigned int if_id; + + if_id = (unsigned int)xpc_dictionary_get_uint64(req, "interface_index"); + ether_addr = xpc_dictionary_get_string(req, "ethernet_address"); + ip_addr = xpc_dictionary_get_string(req, "ip_address"); + iteration = (int)xpc_dictionary_get_uint64(req, "swp_iteration"); + + os_log_info(log_handle, "Calling new SendWakeupPacket() ether_addr[%s] ip_addr[%s] if_id[%d] iteration[%d]", + ether_addr, ip_addr, if_id, iteration); + SendWakeupPacket(if_id, ether_addr, ip_addr, iteration); + break; + } + + case set_localaddr_cacheentry: + { + int if_index, family; + + if_index = xpc_dictionary_get_uint64(req, "slace_ifindex"); + family = xpc_dictionary_get_uint64(req, "slace_family"); + + const uint8_t* ip = xpc_dictionary_get_data(req, "slace_ip", NULL); + const uint8_t* eth = xpc_dictionary_get_data(req, "slace_eth", NULL); + + os_log_info(log_handle, "Calling new SetLocalAddressCacheEntry() if_index[%d] family[%d] ", if_index, family); + + SetLocalAddressCacheEntry(if_index, family, ip, eth, &error_code); + + /* + static int v6addr_to_string(const v6addr_t addr, char *buf, size_t buflen) + { + if (NULL == inet_ntop(AF_INET6, addr, buf, buflen)) + { + os_log(log_handle, "inet_ntop failed: %s", strerror(errno)); + return -1; + } + else + { + return 0; + } + } + + ethaddr_t eth = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 } ; + const uint8_t* slace_ip = NULL; + v6addr_t addr_ipv6; + size_t ip_len; + slace_ip = xpc_dictionary_get_data(req, "slace_ip", &ip_len); + if (slace_ip && (ip_len == sizeof(v6addr_t))) + { + os_log(log_handle, "mDNSResponderHelper: doing memcpy()"); + memcpy(&addr_ipv6, slace_ip, ip_len); + } + char test_ipv6_str[46]; + v6addr_to_string(addr_ipv6, test_ipv6_str, sizeof(test_ipv6_str)); + os_log(log_handle, "mDNSResponderHelper: handle_request: set_localaddr_cacheentry: test_ipv6_str is %s", test_ipv6_str); + */ + + break; + } + + case send_keepalive: + { + uint16_t lport, rport, win; + uint32_t seq, ack; + + lport = xpc_dictionary_get_uint64(req, "send_keepalive_lport"); + rport = xpc_dictionary_get_uint64(req, "send_keepalive_rport"); + seq = xpc_dictionary_get_uint64(req, "send_keepalive_seq"); + ack = xpc_dictionary_get_uint64(req, "send_keepalive_ack"); + win = xpc_dictionary_get_uint64(req, "send_keepalive_win"); + + const uint8_t* sadd6 = xpc_dictionary_get_data(req, "send_keepalive_sadd", NULL); + const uint8_t* dadd6 = xpc_dictionary_get_data(req, "send_keepalive_dadd", NULL); + + os_log_info(log_handle, "helper-main: handle_request: send_keepalive: lport is[%d] rport is[%d] seq is[%d] ack is[%d] win is[%d]", + lport, rport, seq, ack, win); + + SendKeepalive(sadd6, dadd6, lport, rport, seq, ack, win); + break; + } + + case retreive_tcpinfo: + { + uint16_t lport, rport; + int family; + uint32_t seq, ack; + uint16_t win; + int32_t intfid; + + lport = xpc_dictionary_get_uint64(req, "retreive_tcpinfo_lport"); + rport = xpc_dictionary_get_uint64(req, "retreive_tcpinfo_rport"); + family = xpc_dictionary_get_uint64(req, "retreive_tcpinfo_family"); + + const uint8_t* laddr = xpc_dictionary_get_data(req, "retreive_tcpinfo_laddr", NULL); + const uint8_t* raddr = xpc_dictionary_get_data(req, "retreive_tcpinfo_raddr", NULL); + + os_log_info(log_handle, "helper-main: handle_request: retreive_tcpinfo: lport is[%d] rport is[%d] family is [%d]", + lport, rport, family); + + RetrieveTCPInfo(family, laddr, lport, raddr, rport, &seq, &ack, &win, &intfid, &error_code); + + if (response) + { + xpc_dictionary_set_uint64(response, "retreive_tcpinfo_seq", seq); + xpc_dictionary_set_uint64(response, "retreive_tcpinfo_ack", ack); + xpc_dictionary_set_uint64(response, "retreive_tcpinfo_win", win); + xpc_dictionary_set_uint64(response, "retreive_tcpinfo_ifid", intfid); + } + + os_log_info(log_handle, "helper-main: handle_request: retreive_tcpinfo: seq is[%d] ack is[%d] win is [%d] intfid is [%d]", + seq, ack, win, intfid); + + break; + } + + case autotunnel_setkeys: + { + uint16_t lport, rport; + int replace_del; + const char *fqdnstr; + + lport = xpc_dictionary_get_uint64(req, "autotunnelsetkeys_lport"); + rport = xpc_dictionary_get_uint64(req, "autotunnelsetkeys_rport"); + replace_del = xpc_dictionary_get_uint64(req, "autotunnelsetkeys_repdel"); + + const uint8_t* local_inner = xpc_dictionary_get_data(req, "autotunnelsetkeys_localinner", NULL); + const uint8_t* local_outer = xpc_dictionary_get_data(req, "autotunnelsetkeys_localouter", NULL); + const uint8_t* remote_inner = xpc_dictionary_get_data(req, "autotunnelsetkeys_remoteinner", NULL); + const uint8_t* remote_outer = xpc_dictionary_get_data(req, "autotunnelsetkeys_remoteouter", NULL); + + fqdnstr = xpc_dictionary_get_string(req, "autotunnelsetkeys_fqdnStr"); + + os_log_info(log_handle, "helper-main: handle_request: autotunnel_setkeys: lport is[%d] rport is[%d] replace_del is [%d]", + lport, rport, replace_del); + + + HelperAutoTunnelSetKeys(replace_del, local_inner, local_outer, lport, remote_inner, remote_outer, rport, fqdnstr, &error_code); - if (KERN_SUCCESS != (kr = bootstrap_check_in(bootstrap_port, (char *)service_name, &port))) + break; + } + + + case keychain_getsecrets: + { + unsigned int num_sec = 0; + unsigned long secrets = 0; + unsigned int sec_cnt = 0; + + os_log_info(log_handle,"Calling new KeyChainGetSecrets()"); + + KeychainGetSecrets(&num_sec, &secrets, &sec_cnt, &error_code); + + if (response) + { + xpc_dictionary_set_uint64(response, "keychain_num_secrets", num_sec); + xpc_dictionary_set_data(response, "keychain_secrets", (void *)secrets, sec_cnt); + xpc_dictionary_set_uint64(response, "keychain_secrets_count", sec_cnt); + } + + os_log_info(log_handle,"helper-main: handle_request: keychain_getsecrets: num_secrets is %d, secrets is %lu, secrets_Cnt is %d", + num_sec, secrets, sec_cnt); + + if (secrets) + vm_deallocate(mach_task_self(), secrets, sec_cnt); + + break; + } + + default: + { + os_log(log_handle, "handle_request: Unrecognized mode!"); + error_code = kHelperErr_UndefinedMode; + break; + } + } + + // Return Response Status back to the client (essentially ACKing the request) + if (response) { - helplog(ASL_LEVEL_ERR, "bootstrap_check_in: %d %X %s", kr, kr, mach_error_string(kr)); - return MACH_PORT_NULL; + xpc_dictionary_set_uint64(response, kHelperReplyStatus, kHelperReply_ACK); + xpc_dictionary_set_int64(response, kHelperErrCode, error_code); + xpc_connection_send_message(remote_conn, response); + xpc_release(response); } + else + { + os_log(log_handle, "handle_requests: Response Dictionary could not be created!"); + return; + } + +} + +static void accept_client(xpc_connection_t conn) +{ + int c_pid = xpc_connection_get_pid(conn); - if (KERN_SUCCESS != (kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND))) + if (!(check_entitlement(conn, kHelperService))) { - helplog(ASL_LEVEL_ERR, "mach_port_insert_right: %d %X %s", kr, kr, mach_error_string(kr)); - mach_port_deallocate(mach_task_self(), port); - return MACH_PORT_NULL; + os_log(log_handle, "accept_client: Helper Client PID[%d] is missing Entitlement. Cancelling connection", c_pid); + xpc_connection_cancel(conn); + return; } + + xpc_retain(conn); + xpc_connection_set_target_queue(conn, xpc_queue); + xpc_connection_set_event_handler(conn, ^(xpc_object_t req_msg) + { + xpc_type_t type = xpc_get_type(req_msg); + + if (type == XPC_TYPE_DICTIONARY) + { + os_log_info(log_handle,"accept_client:conn:[%p] client[%d](mDNSResponder) requesting service", (void *) conn, c_pid); + handle_request(req_msg); + } + else // We hit this case ONLY if Client Terminated Connection OR Crashed + { + os_log(log_handle, "accept_client:conn:[%p] client[%d](mDNSResponder) teared down the connection (OR Crashed)", (void *) conn, c_pid); + // handle_termination(); + xpc_release(conn); + } + }); + + xpc_connection_resume(conn); +} + - return port; +static void init_helper_service(const char *service_name) +{ + + xpc_connection_t xpc_listener = xpc_connection_create_mach_service(service_name, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER); + if (!xpc_listener || xpc_get_type(xpc_listener) != XPC_TYPE_CONNECTION) + { + os_log(log_handle, "init_helper_service: Error Creating XPC Listener for mDNSResponderHelperService !!"); + return; + } + + os_log_info(log_handle,"init_helper_service: XPC Listener for mDNSResponderHelperService Listening"); + + xpc_queue = dispatch_queue_create("com.apple.mDNSHelper.service_queue", NULL); + + xpc_connection_set_event_handler(xpc_listener, ^(xpc_object_t eventmsg) + { + xpc_type_t type = xpc_get_type(eventmsg); + + if (type == XPC_TYPE_CONNECTION) + { + os_log_info(log_handle,"init_helper_service: new mDNSResponderHelper Client %p", eventmsg); + accept_client(eventmsg); + } + else if (type == XPC_TYPE_ERROR) // Ideally, we would never hit these cases below + { + os_log(log_handle, "init_helper_service: XPCError: %s", xpc_dictionary_get_string(eventmsg, XPC_ERROR_KEY_DESCRIPTION)); + return; + } + else + { + os_log(log_handle, "init_helper_service: Unknown EventMsg type"); + return; + } + }); + + xpc_connection_resume(xpc_listener); } + int main(int ac, char *av[]) { char *p = NULL; - kern_return_t kr = KERN_FAILURE; long n; int ch; - mach_msg_header_t hdr; while ((ch = getopt(ac, av, "dt:")) != -1) + { switch (ch) { - case 'd': opt_debug = 1; break; - case 't': - n = strtol(optarg, &p, 0); - if ('\0' == optarg[0] || '\0' != *p || n > LONG_MAX || n < 0) - { fprintf(stderr, "Invalid idle timeout: %s\n", optarg); exit(EXIT_FAILURE); } - maxidle = n; - break; - case '?': - default: - fprintf(stderr, "Usage: mDNSResponderHelper [-d] [-t maxidle]\n"); - exit(EXIT_FAILURE); + case 'd': + opt_debug = 1; + break; + case 't': + n = strtol(optarg, &p, 0); + if ('\0' == optarg[0] || '\0' != *p || n > LONG_MAX || n < 0) + { + fprintf(stderr, "Invalid idle timeout: %s\n", optarg); + exit(EXIT_FAILURE); + } + maxidle = n; + break; + case '?': + default: + fprintf(stderr, "Usage: mDNSResponderHelper [-d] [-t maxidle]\n"); + exit(EXIT_FAILURE); } + } ac -= optind; av += optind; (void)ac; // Unused (void)av; // Unused initialize_logging(); - helplog(ASL_LEVEL_INFO, "Starting"); initialize_id(); + mDNSHelperLogEnabled = HelperPrefsGetValueBool(kPreferencesKey_mDNSHelperLog, mDNSHelperLogEnabled); + +// Currently on Fuji/Whitetail releases we are keeping the logging always enabled. +// Hence mDNSHelperLogEnabled is set to true below by default. + mDNSHelperLogEnabled = 1; + + os_log_info(log_handle,"mDNSResponderHelper Starting to run"); + #ifndef NO_SECURITYFRAMEWORK // We should normally be running as a system daemon. However, that might not be the case in some scenarios (e.g. debugging). // Explicitly ensure that our Keychain operations utilize the system domain. - if (opt_debug) SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem); + if (opt_debug) + SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem); #endif - gPort = register_service(kmDNSHelperServiceName); - if (!gPort) - exit(EXIT_FAILURE); - if (maxidle) actualidle = maxidle; + if (maxidle) + actualidle = maxidle; signal(SIGTERM, handle_sigterm); - if (initialize_timer()) exit(EXIT_FAILURE); - for (n=0; n<100000; n++) if (!gRunLoop) usleep(100); + if (initialize_timer()) + exit(EXIT_FAILURE); + for (n=0; n<100000; n++) + if (!gRunLoop) + usleep(100); + if (!gRunLoop) { - helplog(ASL_LEVEL_ERR, "gRunLoop not set after waiting"); + os_log(log_handle, "gRunLoop not set after waiting"); exit(EXIT_FAILURE); } - for(;;) - { - hdr.msgh_bits = 0; - hdr.msgh_local_port = gPort; - hdr.msgh_remote_port = MACH_PORT_NULL; - hdr.msgh_size = sizeof(hdr); - hdr.msgh_id = 0; - kr = mach_msg(&hdr, MACH_RCV_LARGE | MACH_RCV_MSG, 0, hdr.msgh_size, gPort, 0, 0); - if (MACH_RCV_TOO_LARGE != kr) - helplog(ASL_LEVEL_ERR, "main MACH_RCV_MSG error: %d %X %s", kr, kr, mach_error_string(kr)); - - kr = mach_msg_server_once(helper_server, MAX_MSG_SIZE, gPort, - MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)); - if (KERN_SUCCESS != kr) - { helplog(ASL_LEVEL_ERR, "mach_msg_server: %d %X %s", kr, kr, mach_error_string(kr)); exit(EXIT_FAILURE); } - - } - exit(EXIT_SUCCESS); + init_helper_service(kHelperService); + os_log_info(log_handle,"mDNSResponderHelper is now running"); + dispatch_main(); + } // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion diff --git a/mDNSResponder/mDNSMacOSX/helper-server.h b/mDNSResponder/mDNSMacOSX/helper-server.h index eb0e6ae1..8a342748 100644 --- a/mDNSResponder/mDNSMacOSX/helper-server.h +++ b/mDNSResponder/mDNSMacOSX/helper-server.h @@ -18,14 +18,11 @@ #ifndef H_HELPER_SERVER_H #define H_HELPER_SERVER_H -extern void helplog(int, const char *, ...); extern void pause_idle_timer(void); extern void unpause_idle_timer(void); extern void update_idle_timer(void); extern uid_t mDNSResponderUID; extern uid_t mDNSResponderGID; extern CFRunLoopRef gRunLoop; -#define debug(...) debug_(__func__, __VA_ARGS__) -extern void debug_(const char *func, const char *fmt, ...); #endif /* H_HELPER_SERVER_H */ diff --git a/mDNSResponder/mDNSMacOSX/helper-stubs.c b/mDNSResponder/mDNSMacOSX/helper-stubs.c index e08f5050..a1e804fd 100644 --- a/mDNSResponder/mDNSMacOSX/helper-stubs.c +++ b/mDNSResponder/mDNSMacOSX/helper-stubs.c @@ -23,9 +23,10 @@ #include #include "mDNSDebug.h" #include "helper.h" -#include "helpermsg.h" #include #include +#include +#include // // Implementation Notes about the HelperQueue: @@ -40,67 +41,176 @@ // an argument to the function, the blocks can reference them as they are passed in as pointers. But care should // be taken to copy them locally as they may cease to exist when the function returns. // + + +//************************************************************************************************************* +// Globals static dispatch_queue_t HelperQueue; +static xpc_connection_t helper_xpc_conn = NULL; + +static int64_t maxwait_secs = 5LL; + +#define mDNSHELPER_DEBUG LogOperation -#define ERROR(x, y) y, -static const char *errorstring[] = +//************************************************************************************************************* +// Utility Functions + +static void LogDebug(const char *prefix, xpc_object_t o) { - #include "helper-error.h" - NULL -}; -#undef ERROR + char *desc = xpc_copy_description(o); + mDNSHELPER_DEBUG("LogDebug %s: %s", prefix, desc); + free(desc); +} -mDNSexport mStatus mDNSHelperInit() +//************************************************************************************************************* +// XPC Funcs: +//************************************************************************************************************* + + +mDNSlocal void Init_Connection(const char *servname) { - HelperQueue = dispatch_queue_create("com.apple.mDNSResponder.HelperQueue", NULL); - if (HelperQueue == NULL) + helper_xpc_conn = xpc_connection_create_mach_service(servname, HelperQueue, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED); + + xpc_connection_set_event_handler(helper_xpc_conn, ^(xpc_object_t event) { - LogMsg("dispatch_queue_create: Helper queue NULL"); - return mStatus_NoMemoryErr; - } - return mStatus_NoError; + mDNSHELPER_DEBUG("Init_Connection xpc: [%s] \n", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION)); + }); + + xpc_connection_resume(helper_xpc_conn); } -static mach_port_t getHelperPort(int retry) +mDNSlocal int SendDict_ToServer(xpc_object_t msg) { - 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; + __block int errorcode = kHelperErr_NoResponse; + + LogDebug("SendDict_ToServer Sending msg to Daemon", msg); + + dispatch_semaphore_t sem = dispatch_semaphore_create(0); + dispatch_retain(sem); // for the block below + + xpc_connection_send_message_with_reply(helper_xpc_conn, msg, HelperQueue, ^(xpc_object_t recv_msg) + { + xpc_type_t type = xpc_get_type(recv_msg); + + if (type == XPC_TYPE_DICTIONARY) + { + LogDebug("SendDict_ToServer Received reply msg from Daemon", recv_msg); + uint64_t reply_status = xpc_dictionary_get_uint64(recv_msg, kHelperReplyStatus); + errorcode = xpc_dictionary_get_int64(recv_msg, kHelperErrCode); + + switch (reply_status) + { + case kHelperReply_ACK: + mDNSHELPER_DEBUG("NoError: successful reply"); + break; + default: + LogMsg("default: Unexpected reply from Helper"); + break; + } + } + else + { + LogMsg("SendDict_ToServer Received unexpected reply from daemon [%s]", + xpc_dictionary_get_string(recv_msg, XPC_ERROR_KEY_DESCRIPTION)); + LogDebug("SendDict_ToServer Unexpected Reply contents", recv_msg); + } + + dispatch_semaphore_signal(sem); + dispatch_release(sem); + + }); + + if (dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, (maxwait_secs * NSEC_PER_SEC))) != 0) + LogMsg("SendDict_ToServer: UNEXPECTED WAIT_TIME in dispatch_semaphore_wait"); + + dispatch_release(sem); + + mDNSHELPER_DEBUG("SendDict_ToServer returning with errorcode[%d]", errorcode); + + return errorcode; } -const char *mDNSHelperError(int err) +mDNSlocal xpc_object_t SendDict_GetReply(xpc_object_t msg) { - static const char *p = ""; - if (mDNSHelperErrorBase < err && mDNSHelperErrorEnd > err) - p = errorstring[err - mDNSHelperErrorBase - 1]; - return p; + // Create empty dictionary + __block xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); + if (!dict) return NULL; + xpc_retain(dict); + + LogDebug("SendDict_GetReply Sending msg to Daemon", msg); + + dispatch_semaphore_t sem = dispatch_semaphore_create(0); + dispatch_retain(sem); // for the block below + + xpc_connection_send_message_with_reply(helper_xpc_conn, msg, HelperQueue, ^(xpc_object_t recv_msg) + { + xpc_type_t type = xpc_get_type(recv_msg); + + if (type == XPC_TYPE_DICTIONARY) + { + LogDebug("SendDict_GetReply Received reply msg from Daemon", recv_msg); + uint64_t reply_status = xpc_dictionary_get_uint64(recv_msg, kHelperReplyStatus); + + switch (reply_status) + { + case kHelperReply_ACK: + mDNSHELPER_DEBUG("NoError: successful reply"); + break; + default: + LogMsg("default: Unexpected reply from Helper"); + break; + } + // Copy result into dict reply + xpc_dictionary_apply(recv_msg, ^bool(const char *key, xpc_object_t value) + { + xpc_dictionary_set_value(dict, key, value); + return true; + }); + } + else + { + LogMsg("SendDict_GetReply Received unexpected reply from daemon [%s]", + xpc_dictionary_get_string(recv_msg, XPC_ERROR_KEY_DESCRIPTION)); + LogDebug("SendDict_GetReply Unexpected Reply contents", recv_msg); + } + + dispatch_semaphore_signal(sem); + dispatch_release(sem); + xpc_release(dict); + + }); + + if (dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, (maxwait_secs * NSEC_PER_SEC))) != 0) + { + LogMsg("SendDict_GetReply: UNEXPECTED WAIT_TIME in dispatch_semaphore_wait"); + xpc_release(dict); + dispatch_release(sem); + + return NULL; + } + + dispatch_release(sem); + + return dict; } -/* 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 (;;) \ +mDNSexport mStatus mDNSHelperInit() +{ + HelperQueue = dispatch_queue_create("com.apple.mDNSResponder.HelperQueue", NULL); + if (HelperQueue == NULL) { -#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; } + LogMsg("dispatch_queue_create: Helper queue NULL"); + return mStatus_NoMemoryErr; + } + return mStatus_NoError; +} void mDNSPreferencesSetName(int key, domainlabel *old, domainlabel *new) { - struct { + struct + { char oldname[MAX_DOMAIN_LABEL+1]; char newname[MAX_DOMAIN_LABEL+1]; } names; @@ -109,250 +219,272 @@ void mDNSPreferencesSetName(int key, domainlabel *old, domainlabel *new) mDNSPlatformMemZero(names.newname, MAX_DOMAIN_LABEL + 1); ConvertDomainLabelToCString_unescaped(old, names.oldname); - if (new) ConvertDomainLabelToCString_unescaped(new, names.newname); - dispatch_async(HelperQueue, ^{ - - kern_return_t kr = KERN_FAILURE; - int retry = 0; - int err = 0; - - LogInfo("%s: oldname %s newname %s", __func__, names.oldname, names.newname); - MACHRETRYLOOP_BEGIN(kr, retry, err, fin); - kr = proxy_mDNSPreferencesSetName(getHelperPort(retry), key, names.oldname, names.newname); - MACHRETRYLOOP_END(kr, retry, err, fin); - -fin: - (void)err; - }); + + if (new) + ConvertDomainLabelToCString_unescaped(new, names.newname); + + + mDNSHELPER_DEBUG("mDNSPreferencesSetName: XPC IPC Test oldname %s newname %s", names.oldname, names.newname); + Init_Connection(kHelperService); + + // Create Dictionary To Send + xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_uint64(dict, kHelperMode, set_name); + + xpc_dictionary_set_uint64(dict, kPrefsNameKey, key); + xpc_dictionary_set_string(dict, kPrefsOldName, names.oldname); + xpc_dictionary_set_string(dict, kPrefsNewName, names.newname); + + SendDict_ToServer(dict); + xpc_release(dict); + dict = NULL; + } -void mDNSRequestBPF(void) +void mDNSRequestBPF() { - dispatch_async(HelperQueue, ^{ - - kern_return_t kr = KERN_FAILURE; - int retry = 0, err = 0; - LogInfo("%s: BPF", __func__); - MACHRETRYLOOP_BEGIN(kr, retry, err, fin); - kr = proxy_mDNSRequestBPF(getHelperPort(retry)); - MACHRETRYLOOP_END(kr, retry, err, fin); -fin: - (void)err; - }); + mDNSHELPER_DEBUG("mDNSRequestBPF: Using XPC IPC"); + Init_Connection(kHelperService); + + // Create Dictionary To Send + xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_uint64(dict, kHelperMode, bpf_request); + SendDict_ToServer(dict); + xpc_release(dict); + dict = NULL; + } 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 err_code = kHelperErr_NotConnected; + + mDNSHELPER_DEBUG("mDNSPowerRequest: Using XPC IPC calling out to Helper key is [%d] interval is [%d]", key, interval); + Init_Connection(kHelperService); + + // Create Dictionary To Send + xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_uint64(dict, kHelperMode, power_req); + xpc_dictionary_set_uint64(dict, "powerreq_key", key); + xpc_dictionary_set_uint64(dict, "powerreq_interval", interval); + + err_code = SendDict_ToServer(dict); + xpc_release(dict); + dict = NULL; + + mDNSHELPER_DEBUG("mDNSPowerRequest: Using XPC IPC returning error_code %d", err_code); + return err_code; } 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; + int err_code = kHelperErr_NotConnected; + + mDNSHELPER_DEBUG("mDNSSetLocalAddressCacheEntry: Using XPC IPC calling out to Helper: ifindex is [%d] family is [%d]", ifindex, family); + + Init_Connection(kHelperService); + + // Create Dictionary To Send + xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_uint64(dict, kHelperMode, set_localaddr_cacheentry); + + xpc_dictionary_set_uint64(dict, "slace_ifindex", ifindex); + xpc_dictionary_set_uint64(dict, "slace_family", family); + + xpc_dictionary_set_data(dict, "slace_ip", (uint8_t*)ip, sizeof(v6addr_t)); + xpc_dictionary_set_data(dict, "slace_eth", (uint8_t*)eth, sizeof(ethaddr_t)); + + err_code = SendDict_ToServer(dict); + xpc_release(dict); + dict = NULL; + + mDNSHELPER_DEBUG("mDNSSetLocalAddressCacheEntry: Using XPC IPC returning error_code %d", err_code); + return err_code; } + void mDNSNotify(const char *title, const char *msg) // Both strings are UTF-8 text { - char *titleCopy = NULL; - char *msgCopy = NULL; - - if (title) - { - // Don’t try to call mDNSPlatformMem* routines here, because they call validatelists, - // which calls back into mDNSNotify, resulting an infinite loop until stack space is exhausted - int len = strlen(title); - titleCopy = malloc(len + 1); - if (!titleCopy) - { - LogMsg("mDNSNotify: titleCopy NULL for %s", msg); - return; - } - memcpy(titleCopy, title, len); - titleCopy[len] = 0; - } - if (msg) - { - int len = strlen(msg); - msgCopy = malloc(len + 1); - if (!msgCopy) - { - LogMsg("mDNSNotify: msgCopy NULL for %s", msg); - return; - } - memcpy(msgCopy, msg, len); - msgCopy[len] = 0; - } - - dispatch_async(HelperQueue, ^{ - - kern_return_t kr = KERN_FAILURE; - int retry = 0, err = 0; - - LogInfo("%s: title %s, msg %s", __func__, titleCopy, msgCopy); + mDNSHELPER_DEBUG("mDNSNotify() calling out to Helper XPC IPC title[%s] msg[%s]", title, msg); - MACHRETRYLOOP_BEGIN(kr, retry, err, fin); - kr = proxy_mDNSNotify(getHelperPort(retry), titleCopy, msgCopy); - MACHRETRYLOOP_END(kr, retry, err, fin); -fin: - // Don’t try to call mDNSPlatformMem* routines here, because they call validatelists, - // which calls back into mDNSNotify, resulting an infinite loop until stack space is exhausted - free(titleCopy); - free(msgCopy); - (void)err; - }); + Init_Connection(kHelperService); + + // Create Dictionary To Send + xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_uint64(dict, kHelperMode, user_notify); + + xpc_dictionary_set_string(dict, "notify_title", title); + xpc_dictionary_set_string(dict, "notify_msg", msg); + + SendDict_ToServer(dict); + xpc_release(dict); + dict = NULL; + } + 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); + unsigned int secretsCnt = 0; + int error_code = kHelperErr_NotConnected; + xpc_object_t reply_dict = NULL; + const void *sec = NULL; + size_t secrets_size = 0; + + mDNSHELPER_DEBUG("mDNSKeychainGetSecrets: Using XPC IPC calling out to Helper"); + + Init_Connection(kHelperService); + + // Create Dictionary To Send + xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_uint64(dict, kHelperMode, keychain_getsecrets); - if (NULL == (bytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (void*)secrets, secretsCnt, kCFAllocatorNull))) + reply_dict = SendDict_GetReply(dict); + + if (reply_dict != NULL) { - err = kmDNSHelperCreationFailed; - LogMsg("%s: CFDataCreateWithBytesNoCopy failed", __func__); + numsecrets = xpc_dictionary_get_uint64(reply_dict, "keychain_num_secrets"); + sec = xpc_dictionary_get_data(reply_dict, "keychain_secrets", &secrets_size); + secretsCnt = xpc_dictionary_get_uint64(reply_dict, "keychain_secrets_count"); + error_code = xpc_dictionary_get_int64(reply_dict, kHelperErrCode); + } + + mDNSHELPER_DEBUG("mDNSKeychainGetSecrets: Using XPC IPC calling out to Helper: numsecrets is %d, secretsCnt is %d error_code is %d secret_size is %d", + numsecrets, secretsCnt, error_code, secrets_size); + + if (NULL == (bytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (void*)sec, secretsCnt, kCFAllocatorNull))) + { + error_code = kHelperErr_ApiErr; + LogMsg("mDNSKeychainGetSecrets: CFDataCreateWithBytesNoCopy failed"); goto fin; } + if (NULL == (plist = CFPropertyListCreateWithData(kCFAllocatorDefault, bytes, kCFPropertyListImmutable, NULL, NULL))) { - err = kmDNSHelperInvalidPList; - LogMsg("%s: CFPropertyListCreateFromXMLData failed", __func__); + error_code = kHelperErr_ApiErr; + LogMsg("mDNSKeychainGetSecrets: CFPropertyListCreateFromXMLData failed"); goto fin; } + if (CFArrayGetTypeID() != CFGetTypeID(plist)) { - err = kmDNSHelperTypeError; - LogMsg("%s: Unexpected result type", __func__); + error_code = kHelperErr_ApiErr; + LogMsg("mDNSKeychainGetSecrets: Unexpected result type"); 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; + if (bytes) + CFRelease(bytes); + if (dict) + xpc_release(dict); + if (reply_dict) + xpc_release(reply_dict); + + dict = NULL; + reply_dict = NULL; + + return error_code; } -void mDNSConfigureServer(int updown, const char *const prefix, const domainname *const fqdn) -{ - struct - { - // Assume the prefix is no larger than 10 chars - char fqdnStr[MAX_ESCAPED_DOMAIN_NAME + 10]; - } name; - - mDNSPlatformMemZero(name.fqdnStr, MAX_DOMAIN_LABEL + 10); - - if (fqdn) - { - mDNSPlatformStrCopy(name.fqdnStr, prefix); - ConvertDomainNameToCString(fqdn, name.fqdnStr + mDNSPlatformStrLen(prefix)); - } - - dispatch_async(HelperQueue, ^{ - - kern_return_t kr = KERN_SUCCESS; - int retry = 0, err = 0; - - LogInfo("%s: fqdnStr %s", __func__, name.fqdnStr); - - MACHRETRYLOOP_BEGIN(kr, retry, err, fin); - kr = proxy_mDNSConfigureServer(getHelperPort(retry), updown, name.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 char* const prefix, const domainname *const fqdn) { - kern_return_t kr = KERN_SUCCESS; - int retry = 0, err = 0; + + int err_code = kHelperErr_NotConnected; + + mDNSHELPER_DEBUG("mDNSAutoTunnelSetKeys: Using XPC IPC calling out to Helper. Parameters are repdel[%d], lport[%d], rport[%d], prefix[%s], fqdn[%##s]", + replacedelete, local_port, remote_port, prefix, fqdn->c); + + + char buf1[INET6_ADDRSTRLEN]; + char buf2[INET6_ADDRSTRLEN]; + char buf3[INET6_ADDRSTRLEN]; + char buf4[INET6_ADDRSTRLEN]; + + buf1[0] = 0; + buf2[0] = 0; + buf3[0] = 0; + buf4[0] = 0; + + inet_ntop(AF_INET6, local_inner, buf1, sizeof(buf1)); + inet_ntop(AF_INET6, local_outer, buf2, sizeof(buf2)); + inet_ntop(AF_INET6, remote_inner, buf3, sizeof(buf3)); + inet_ntop(AF_INET6, remote_outer, buf4, sizeof(buf4)); + char fqdnStr[MAX_ESCAPED_DOMAIN_NAME + 10] = { 0 }; // Assume the prefix is no larger than 10 chars if (fqdn) { mDNSPlatformStrCopy(fqdnStr, prefix); ConvertDomainNameToCString(fqdn, fqdnStr + mDNSPlatformStrLen(prefix)); } - 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; -} + + mDNSHELPER_DEBUG("mDNSAutoTunnelSetKeys: Using XPC IPC calling out to Helper: Parameters are local_inner is %s, local_outeris %s, remote_inner is %s, remote_outer is %s", + buf1, buf2, buf3, buf4); + + Init_Connection(kHelperService); + + // Create Dictionary To Send + xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_uint64(dict, kHelperMode, autotunnel_setkeys); + + xpc_dictionary_set_data(dict, "autotunnelsetkeys_localinner", (uint8_t*)local_inner, sizeof(v6addr_t)); + xpc_dictionary_set_data(dict, "autotunnelsetkeys_localouter", (uint8_t*)local_outer, sizeof(v6addr_t)); + xpc_dictionary_set_data(dict, "autotunnelsetkeys_remoteinner", (uint8_t*)remote_inner, sizeof(v6addr_t)); + xpc_dictionary_set_data(dict, "autotunnelsetkeys_remoteouter", (uint8_t*)remote_outer, sizeof(v6addr_t)); + + xpc_dictionary_set_uint64(dict, "autotunnelsetkeys_lport", local_port); + xpc_dictionary_set_uint64(dict, "autotunnelsetkeys_rport", remote_port); + xpc_dictionary_set_uint64(dict, "autotunnelsetkeys_repdel", replacedelete); -void mDNSSendWakeupPacket(unsigned ifid, char *eth_addr, char *ip_addr, int iteration) -{ - char *ip_addr_copy = NULL; - char *eth_addr_copy = NULL; + // xpc_dictionary_set_string(dict, "autotunnelsetkeys_prefix", prefix); + xpc_dictionary_set_string(dict, "autotunnelsetkeys_fqdnStr", fqdnStr); + + err_code = SendDict_ToServer(dict); + + xpc_release(dict); + dict = NULL; - if (eth_addr) - { - int len = strlen(eth_addr); - eth_addr_copy = mDNSPlatformMemAllocate(len + 1); - if (!eth_addr_copy) - { - LogMsg("mDNSSendWakeupPacket: eth_addr_copy NULL for %s", eth_addr); - return; - } - mDNSPlatformMemCopy(eth_addr_copy, eth_addr, len); - eth_addr_copy[len] = 0; - } - if (ip_addr) - { - int len = strlen(ip_addr); - ip_addr_copy = mDNSPlatformMemAllocate(len + 1); - if (!ip_addr_copy) - { - LogMsg("mDNSSendWakeupPacket: ip_addr_copy NULL for %s", ip_addr); - return; - } - mDNSPlatformMemCopy(ip_addr_copy, ip_addr, len); - ip_addr_copy[len] = 0; - } - dispatch_async(HelperQueue, ^{ + mDNSHELPER_DEBUG("mDNSAutoTunnelSetKeys: Using XPC IPC returning error_code %d", err_code); + + mDNSHELPER_DEBUG("mDNSAutoTunnelSetKeys: this should NOT be done in mDNSResponder/Helper. For future we shall be using "); + return err_code; +} - kern_return_t kr = KERN_SUCCESS; - int retry = 0, err = 0; +void mDNSSendWakeupPacket(unsigned int ifid, char *eth_addr, char *ip_addr, int iteration) +{ + // (void) ip_addr; // unused + // (void) iteration; // unused - LogInfo("%s: Entered ethernet address %s, ip address %s", __func__, eth_addr_copy, ip_addr_copy); + mDNSHELPER_DEBUG("mDNSSendWakeupPacket: Entered ethernet address[%s],ip_address[%s], interface_id[%d], iteration[%d]", + eth_addr, ip_addr, ifid, iteration); + + Init_Connection(kHelperService); + + // Create Dictionary To Send + xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_uint64(dict, kHelperMode, send_wakepkt); + + xpc_dictionary_set_uint64(dict, "interface_index", ifid); + xpc_dictionary_set_string(dict, "ethernet_address", eth_addr); + xpc_dictionary_set_string(dict, "ip_address", ip_addr); + xpc_dictionary_set_uint64(dict, "swp_iteration", iteration); + + SendDict_ToServer(dict); + xpc_release(dict); + dict = NULL; - MACHRETRYLOOP_BEGIN(kr, retry, err, fin); - kr = proxy_mDNSSendWakeupPacket(getHelperPort(retry), ifid, eth_addr_copy, ip_addr_copy, iteration); - MACHRETRYLOOP_END(kr, retry, err, fin); -fin: - if (eth_addr_copy) - mDNSPlatformMemFree(eth_addr_copy); - if (ip_addr_copy) - mDNSPlatformMemFree(ip_addr_copy); - (void) err; - }); } void mDNSPacketFilterControl(uint32_t command, char * ifname, uint32_t count, pfArray_t portArray, pfArray_t protocolArray) @@ -362,138 +494,127 @@ void mDNSPacketFilterControl(uint32_t command, char * ifname, uint32_t count, pf pfArray_t portArray; pfArray_t protocolArray; } pfa; - char *ifnameCopy = NULL; mDNSPlatformMemCopy(pfa.portArray, portArray, sizeof(pfArray_t)); mDNSPlatformMemCopy(pfa.protocolArray, protocolArray, sizeof(pfArray_t)); - if (ifname) - { - int len = strlen(ifname); - ifnameCopy = mDNSPlatformMemAllocate(len + 1); - if (!ifnameCopy) - { - LogMsg("mDNSPacketFilterControl: ifnameCopy NULL"); - return; - } - mDNSPlatformMemCopy(ifnameCopy, ifname, len); - ifnameCopy[len] = 0; - } - dispatch_async(HelperQueue, ^{ - kern_return_t kr = KERN_SUCCESS; - int retry = 0, err = 0; - - LogInfo("%s, ifname %s", __func__, ifnameCopy); + mDNSHELPER_DEBUG("mDNSPacketFilterControl: XPC IPC, ifname %s", ifname); + Init_Connection(kHelperService); + + // Create Dictionary To Send + xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_uint64(dict, kHelperMode, p2p_packetfilter); + + xpc_dictionary_set_uint64(dict, "pf_opcode", command); + if (ifname) + xpc_dictionary_set_string(dict, "pf_ifname", ifname); + xpc_dictionary_set_uint64(dict, "pf_count", count); - MACHRETRYLOOP_BEGIN(kr, retry, err, fin); - kr = proxy_mDNSPacketFilterControl(getHelperPort(retry), command, ifnameCopy, count, (uint16_t *)pfa.portArray, (uint16_t *)pfa.protocolArray); - MACHRETRYLOOP_END(kr, retry, err, fin); -fin: - if (ifnameCopy) - mDNSPlatformMemFree(ifnameCopy); - (void) err; - }); + xpc_dictionary_set_uint64(dict, "pf_port0", pfa.portArray[0]); + xpc_dictionary_set_uint64(dict, "pf_port1", pfa.portArray[1]); + xpc_dictionary_set_uint64(dict, "pf_port2", pfa.portArray[2]); + xpc_dictionary_set_uint64(dict, "pf_port3", pfa.portArray[3]); + + xpc_dictionary_set_uint64(dict, "pf_protocol0", pfa.protocolArray[0]); + xpc_dictionary_set_uint64(dict, "pf_protocol1", pfa.protocolArray[1]); + xpc_dictionary_set_uint64(dict, "pf_protocol2", pfa.protocolArray[2]); + xpc_dictionary_set_uint64(dict, "pf_protocol3", pfa.protocolArray[3]); + SendDict_ToServer(dict); + xpc_release(dict); + dict = NULL; + + mDNSHELPER_DEBUG("mDNSPacketFilterControl: portArray0[%d] portArray1[%d] portArray2[%d] portArray3[%d] protocolArray0[%d] protocolArray1[%d] protocolArray2[%d] protocolArray3[%d]", + pfa.portArray[0], pfa.portArray[1], pfa.portArray[2], pfa.portArray[3], pfa.protocolArray[0], pfa.protocolArray[1], pfa.protocolArray[2], pfa.protocolArray[3]); + } -void mDNSSendKeepalive(v6addr_t sadd, v6addr_t dadd, uint16_t lport, uint16_t rport, unsigned seq, unsigned ack, uint16_t win) +void mDNSSendKeepalive(const v6addr_t sadd, const v6addr_t dadd, uint16_t lport, uint16_t rport, uint32_t seq, uint32_t ack, uint16_t win) { - struct - { - v6addr_t sadd; - v6addr_t dadd; - } addr; - - mDNSPlatformMemCopy(addr.sadd, sadd, sizeof(v6addr_t)); - mDNSPlatformMemCopy(addr.dadd, dadd, sizeof(v6addr_t)); - - dispatch_async(HelperQueue, ^{ - kern_return_t kr = KERN_FAILURE; - int retry = 0, err = 0; - char buf1[INET6_ADDRSTRLEN]; - char buf2[INET6_ADDRSTRLEN]; - - buf1[0] = 0; - buf2[0] = 0; - - inet_ntop(AF_INET6, addr.sadd, buf1, sizeof(buf1)); - inet_ntop(AF_INET6, addr.dadd, buf2, sizeof(buf2)); - LogInfo("%s: sadd is %s, dadd is %s", __func__, buf1, buf2); - - MACHRETRYLOOP_BEGIN(kr, retry, err, fin); - kr = proxy_mDNSSendKeepalive(getHelperPort(retry), (uint8_t *)addr.sadd, (uint8_t *)addr.dadd, lport, rport, seq, ack, win); - MACHRETRYLOOP_END(kr, retry, err, fin); -fin: - (void) err; - }); + mDNSHELPER_DEBUG("mDNSSendKeepalive: Using XPC IPC calling out to Helper: lport is[%d] rport is[%d] seq is[%d] ack is[%d] win is[%d]", + lport, rport, seq, ack, win); + + char buf1[INET6_ADDRSTRLEN]; + char buf2[INET6_ADDRSTRLEN]; + + buf1[0] = 0; + buf2[0] = 0; + + inet_ntop(AF_INET6, sadd, buf1, sizeof(buf1)); + inet_ntop(AF_INET6, dadd, buf2, sizeof(buf2)); + mDNSHELPER_DEBUG("mDNSSendKeepalive: Using XPC IPC calling out to Helper: sadd is %s, dadd is %s", buf1, buf2); + + Init_Connection(kHelperService); + + // Create Dictionary To Send + xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_uint64(dict, kHelperMode, send_keepalive); + + xpc_dictionary_set_data(dict, "send_keepalive_sadd", (uint8_t*)sadd, sizeof(v6addr_t)); + xpc_dictionary_set_data(dict, "send_keepalive_dadd", (uint8_t*)dadd, sizeof(v6addr_t)); + + xpc_dictionary_set_uint64(dict, "send_keepalive_lport", lport); + xpc_dictionary_set_uint64(dict, "send_keepalive_rport", rport); + xpc_dictionary_set_uint64(dict, "send_keepalive_seq", seq); + xpc_dictionary_set_uint64(dict, "send_keepalive_ack", ack); + xpc_dictionary_set_uint64(dict, "send_keepalive_win", win); + + SendDict_ToServer(dict); + xpc_release(dict); + dict = NULL; + } 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) { - kern_return_t kr = KERN_FAILURE; - int retry = 0, err = 0; - MACHRETRYLOOP_BEGIN(kr, retry, err, fin); - kr = proxy_mDNSRetrieveTCPInfo(getHelperPort(retry), family, (uint8_t *)laddr, lport, (uint8_t *)raddr, rport, seq, ack, win, intfid); - MACHRETRYLOOP_END(kr, retry, err, fin); -fin: - return err; -} - -void mDNSGetRemoteMAC(mDNS *const m, int family, v6addr_t raddr) -{ - struct { - v6addr_t addr; - } dst; - - mDNSPlatformMemCopy(dst.addr, raddr, sizeof(v6addr_t)); - dispatch_async(HelperQueue, ^{ - kern_return_t kr = KERN_FAILURE; - int retry = 0, err = 0; - ethaddr_t eth; - IPAddressMACMapping *addrMapping; - - MACHRETRYLOOP_BEGIN(kr, retry, err, fin); - kr = proxy_mDNSGetRemoteMAC(getHelperPort(retry), family, (uint8_t *)dst.addr, eth); - MACHRETRYLOOP_END(kr, retry, err, fin); - // If the call to get the remote MAC address succeeds, allocate and copy - // the values and schedule a task to update the MAC address in the TCP Keepalive record. - if (kr == KERN_SUCCESS) - { - addrMapping = mDNSPlatformMemAllocate(sizeof(IPAddressMACMapping)); - snprintf(addrMapping->ethaddr, sizeof(addrMapping->ethaddr), "%02x:%02x:%02x:%02x:%02x:%02x", - eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]); - if (family == AF_INET) - { - addrMapping->ipaddr.type = mDNSAddrType_IPv4; - mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v4.b, dst.addr, sizeof(v6addr_t)); - } - else - { - addrMapping->ipaddr.type = mDNSAddrType_IPv6; - mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v6.b, dst.addr, sizeof(v6addr_t)); - } - mDNSPlatformDispatchAsync(m, addrMapping, UpdateRMACCallback); - } -fin: - (void) err; - }); - -} - -void mDNSStoreSPSMACAddress(int family, v6addr_t spsaddr, char *ifname) -{ - struct { - v6addr_t saddr; - } addr; - mDNSPlatformMemCopy(addr.saddr, spsaddr, sizeof(v6addr_t)); - - dispatch_async(HelperQueue, ^{ - kern_return_t kr = KERN_FAILURE; - int retry = 0, err = 0; - MACHRETRYLOOP_BEGIN(kr, retry, err, fin); - kr = proxy_mDNSStoreSPSMACAddress(getHelperPort(retry), family, (uint8_t *)addr.saddr, ifname); - MACHRETRYLOOP_END(kr, retry, err, fin); -fin: - (void)err; - }); + int error_code = kHelperErr_NotConnected; + xpc_object_t reply_dict = NULL; + + mDNSHELPER_DEBUG("mDNSRetrieveTCPInfo: Using XPC IPC calling out to Helper: lport is[%d] rport is[%d] family is[%d]", + lport, rport, family); + + char buf1[INET6_ADDRSTRLEN]; + char buf2[INET6_ADDRSTRLEN]; + buf1[0] = 0; + buf2[0] = 0; + + inet_ntop(AF_INET6, laddr, buf1, sizeof(buf1)); + inet_ntop(AF_INET6, raddr, buf2, sizeof(buf2)); + mDNSHELPER_DEBUG("mDNSRetrieveTCPInfo:: Using XPC IPC calling out to Helper: laddr is %s, raddr is %s", buf1, buf2); + + Init_Connection(kHelperService); + + // Create Dictionary To Send + xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_uint64(dict, kHelperMode, retreive_tcpinfo); + + xpc_dictionary_set_data(dict, "retreive_tcpinfo_laddr", (uint8_t*)laddr, sizeof(v6addr_t)); + xpc_dictionary_set_data(dict, "retreive_tcpinfo_raddr", (uint8_t*)raddr, sizeof(v6addr_t)); + + xpc_dictionary_set_uint64(dict, "retreive_tcpinfo_family", family); + xpc_dictionary_set_uint64(dict, "retreive_tcpinfo_lport", lport); + xpc_dictionary_set_uint64(dict, "retreive_tcpinfo_rport", rport); + + reply_dict = SendDict_GetReply(dict); + + if (reply_dict != NULL) + { + *seq = xpc_dictionary_get_uint64(reply_dict, "retreive_tcpinfo_seq"); + *ack = xpc_dictionary_get_uint64(reply_dict, "retreive_tcpinfo_ack"); + *win = xpc_dictionary_get_uint64(reply_dict, "retreive_tcpinfo_win"); + *intfid = (int32_t)xpc_dictionary_get_uint64(reply_dict, "retreive_tcpinfo_ifid"); + error_code = xpc_dictionary_get_int64(reply_dict, kHelperErrCode); + } + + mDNSHELPER_DEBUG("mDNSRetrieveTCPInfo: Using XPC IPC calling out to Helper: seq is %d, ack is %d, win is %d, intfid is %d, error is %d", + *seq, *ack, *win, *intfid, error_code); + + if (dict) + xpc_release(dict); + if (reply_dict) + xpc_release(reply_dict); + dict = NULL; + reply_dict = NULL; + + return error_code; } diff --git a/mDNSResponder/mDNSMacOSX/helper.c b/mDNSResponder/mDNSMacOSX/helper.c index 7cf0e523..f5b4f3b2 100644 --- a/mDNSResponder/mDNSMacOSX/helper.c +++ b/mDNSResponder/mDNSMacOSX/helper.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -53,9 +52,7 @@ #include "dnssd_ipc.h" #include "libpfkey.h" #include "helper.h" -#include "helpermsgServer.h" #include "helper-server.h" -#include "ipsec_options.h" #include "P2PPacketFilter.h" #include @@ -71,6 +68,7 @@ #ifndef MDNS_NO_IPSEC #define MDNS_NO_IPSEC 1 #endif + #define NO_CFUSERNOTIFICATION 1 #define NO_SECURITYFRAMEWORK 1 #endif @@ -81,79 +79,51 @@ typedef struct sadb_x_policy *ipsec_policy_t; -unsigned short InetChecksum(unsigned short *ptr,int nbytes); -unsigned long in_cksum(unsigned short *ptr,int nbytes); -void TCPCheckSum(int af, struct tcphdr *t, int tcplen, v6addr_t sadd6, v6addr_t dadd6); - uid_t mDNSResponderUID; gid_t mDNSResponderGID; -void -debug_(const char *func, const char *fmt, ...) -{ - char buf[2048]; - va_list ap; - - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - helplog(ASL_LEVEL_DEBUG, "%s: %s", func, buf); -} - -static int -authorized(audit_token_t *token) -{ - int ok = 0; - pid_t pid = (pid_t)-1; - uid_t euid = (uid_t)-1; - - audit_token_to_au32(*token, NULL, &euid, NULL, NULL, NULL, &pid, NULL, - NULL); - ok = (euid == mDNSResponderUID || euid == 0); - if (!ok) - helplog(ASL_LEVEL_NOTICE, - "Unauthorized access by euid=%lu pid=%lu", - (unsigned long)euid, (unsigned long)pid); - return ok; -} - -kern_return_t -do_mDNSExit(__unused mach_port_t port, audit_token_t token) +void helper_exit() { - debug("entry"); - if (!authorized(&token)) - goto fin; - helplog(ASL_LEVEL_INFO, "exit"); + os_log_info(log_handle,"mDNSResponderHelper exiting"); exit(0); - -fin: - debug("fin"); - return KERN_SUCCESS; } -kern_return_t do_mDNSRequestBPF(__unused mach_port_t port, audit_token_t token) +mDNSexport void RequestBPF() { - if (!authorized(&token)) return KERN_SUCCESS; DNSServiceRef ref; + DNSServiceErrorType err = ConnectToServer(&ref, 0, send_bpf, NULL, NULL, NULL); - if (err) { helplog(ASL_LEVEL_ERR, "do_mDNSRequestBPF: ConnectToServer %d", err); return err; } - + if (err) + { + os_log(log_handle, "RequestBPF: ConnectToServer %d", err); + return; + } + char *ptr; size_t len = sizeof(DNSServiceFlags); ipc_msg_hdr *hdr = create_hdr(send_bpf, &len, &ptr, 0, ref); - if (!hdr) { DNSServiceRefDeallocate(ref); return kDNSServiceErr_NoMemory; } + if (!hdr) + { + os_log(log_handle, "RequestBPF: No mem to allocate"); + DNSServiceRefDeallocate(ref); + return; + } + put_flags(0, &ptr); deliver_request(hdr, ref); // Will free hdr for us DNSServiceRefDeallocate(ref); update_idle_timer(); - return KERN_SUCCESS; + + os_log_info(log_handle,"RequestBPF: Successful"); } -kern_return_t do_mDNSPowerRequest(__unused mach_port_t port, int key, int interval, int *err, audit_token_t token) -{ - *err = -1; - if (!authorized(&token)) { *err = kmDNSHelperNotAuthorized; goto fin; } +void PowerRequest(int key, int interval, int *err) +{ + *err = kHelperErr_DefaultErr; + + os_log_info(log_handle,"PowerRequest: key %d interval %d, err %d", key, interval, *err); + CFArrayRef events = IOPMCopyScheduledPowerEvents(); if (events) { @@ -168,19 +138,26 @@ kern_return_t do_mDNSPowerRequest(__unused mach_port_t port, int key, int interv CFDateRef EventTime = CFDictionaryGetValue(dict, CFSTR(kIOPMPowerEventTimeKey)); CFStringRef EventType = CFDictionaryGetValue(dict, CFSTR(kIOPMPowerEventTypeKey)); IOReturn result = IOPMCancelScheduledPowerEvent(EventTime, id, EventType); - //helplog(ASL_LEVEL_ERR, "Deleting old event %s"); - if (result) helplog(ASL_LEVEL_ERR, "IOPMCancelScheduledPowerEvent %d failed %d", i, result); + //os_log(log_handle, "Deleting old event %s"); + if (result) + os_log(log_handle, "IOPMCancelScheduledPowerEvent %d failed %d", i, result); } } CFRelease(events); } - - if (key < 0) // mDNSPowerRequest(-1,-1) means "clear any stale schedules" (see above) - *err = 0; + + if (key < 0) // mDNSPowerRequest(-1,-1) means "clear any stale schedules" (see above) + { + *err = kHelperErr_NoErr; + } else if (key == 0) // mDNSPowerRequest(0, 0) means "sleep now" { IOReturn r = IOPMSleepSystem(IOPMFindPowerManagement(MACH_PORT_NULL)); - if (r) { usleep(100000); helplog(ASL_LEVEL_ERR, "IOPMSleepSystem %d", r); } + if (r) + { + usleep(100000); + os_log_info(log_handle, "IOPMSleepSystem %d", r); + } *err = r; } else if (key > 0) @@ -189,48 +166,51 @@ kern_return_t do_mDNSPowerRequest(__unused mach_port_t port, int key, int interv if (wakeTime) { CFMutableDictionaryRef scheduleDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - + CFDictionaryAddValue(scheduleDict, CFSTR(kIOPMPowerEventTimeKey), wakeTime); CFDictionaryAddValue(scheduleDict, CFSTR(kIOPMPowerEventAppNameKey), CFSTR("mDNSResponderHelper")); CFDictionaryAddValue(scheduleDict, CFSTR(kIOPMPowerEventTypeKey), key ? CFSTR(kIOPMAutoWake) : CFSTR(kIOPMAutoSleep)); - + IOReturn r = IOPMRequestSysWake(scheduleDict); if (r) { usleep(100000); - helplog(ASL_LEVEL_ERR, "IOPMRequestSysWake(%d) %d %x", interval, r, r); + os_log_info(log_handle, "IOPMRequestSysWake(%d) %d %x", interval, r, r); } *err = r; CFRelease(wakeTime); CFRelease(scheduleDict); } } -fin: + update_idle_timer(); - return KERN_SUCCESS; } -kern_return_t do_mDNSSetLocalAddressCacheEntry(__unused mach_port_t port, int ifindex, int family, v6addr_t ip, ethaddr_t eth, int *err, audit_token_t token) +void SetLocalAddressCacheEntry(int ifindex, int family, const v6addr_t ip, const ethaddr_t eth, int *err) { - #define IPv6FMTSTRING "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X" - #define IPv6FMTARGS ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip[8], ip[9], ip[10], ip[11], ip[12], ip[13], ip[14], ip[15] - #if 0 + +#define IPv6FMTSTRING "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X" +#define IPv6FMTARGS ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip[8], ip[9], ip[10], ip[11], ip[12], ip[13], ip[14], ip[15] + if (family == 4) - helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry %d IPv%d %d.%d.%d.%d %02X:%02X:%02X:%02X:%02X:%02X", - ifindex, family, ip[0], ip[1], ip[2], ip[3], eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]); + { + os_log_info(log_handle,"SetLocalAddressCacheEntry %d IPv%d %d.%d.%d.%d %02X:%02X:%02X:%02X:%02X:%02X", + ifindex, family, ip[0], ip[1], ip[2], ip[3], eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]); + } else - helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry %d IPv%d " IPv6FMTSTRING " %02X:%02X:%02X:%02X:%02X:%02X", - ifindex, family, IPv6FMTARGS, eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]); - #endif - - *err = -1; - if (!authorized(&token)) { *err = kmDNSHelperNotAuthorized; goto fin; } - + { + os_log_info(log_handle,"SetLocalAddressCacheEntry %d IPv%d " IPv6FMTSTRING " %02X:%02X:%02X:%02X:%02X:%02X", + ifindex, family, IPv6FMTARGS, eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]); + } + + *err = kHelperErr_DefaultErr; + static int s = -1, seq = 0; if (s < 0) { s = socket(PF_ROUTE, SOCK_RAW, 0); - if (s < 0) helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: socket(PF_ROUTE, SOCK_RAW, 0) failed %d (%s)", errno, strerror(errno)); + if (s < 0) + os_log(log_handle, "SetLocalAddressCacheEntry: socket(PF_ROUTE, SOCK_RAW, 0) failed %d (%s)", errno, strerror(errno)); } if (s >= 0) @@ -241,7 +221,7 @@ kern_return_t do_mDNSSetLocalAddressCacheEntry(__unused mach_port_t port, int if { struct { struct rt_msghdr hdr; struct sockaddr_inarp dst; struct sockaddr_dl sdl; } rtmsg; memset(&rtmsg, 0, sizeof(rtmsg)); - + rtmsg.hdr.rtm_msglen = sizeof(rtmsg); rtmsg.hdr.rtm_version = RTM_VERSION; rtmsg.hdr.rtm_type = RTM_ADD; @@ -254,7 +234,7 @@ kern_return_t do_mDNSSetLocalAddressCacheEntry(__unused mach_port_t port, int if rtmsg.hdr.rtm_use = 0; rtmsg.hdr.rtm_inits = RTV_EXPIRE; rtmsg.hdr.rtm_rmx.rmx_expire = tv.tv_sec + 30; - + rtmsg.dst.sin_len = sizeof(rtmsg.dst); rtmsg.dst.sin_family = AF_INET; rtmsg.dst.sin_port = 0; @@ -262,7 +242,7 @@ kern_return_t do_mDNSSetLocalAddressCacheEntry(__unused mach_port_t port, int if rtmsg.dst.sin_srcaddr.s_addr = 0; rtmsg.dst.sin_tos = 0; rtmsg.dst.sin_other = 0; - + rtmsg.sdl.sdl_len = sizeof(rtmsg.sdl); rtmsg.sdl.sdl_family = AF_LINK; rtmsg.sdl.sdl_index = ifindex; @@ -270,26 +250,26 @@ kern_return_t do_mDNSSetLocalAddressCacheEntry(__unused mach_port_t port, int if rtmsg.sdl.sdl_nlen = 0; rtmsg.sdl.sdl_alen = ETHER_ADDR_LEN; rtmsg.sdl.sdl_slen = 0; - + // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h) memcpy(rtmsg.sdl.sdl_data, eth, sizeof(ethaddr_t)); - + int len = write(s, (char *)&rtmsg, sizeof(rtmsg)); if (len < 0) - helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: write(%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s)", + os_log(log_handle, "SetLocalAddressCacheEntry: write(%zu) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s)", sizeof(rtmsg), ifindex, ip[0], ip[1], ip[2], ip[3], rtmsg.hdr.rtm_seq, len, errno, strerror(errno)); len = read(s, (char *)&rtmsg, sizeof(rtmsg)); if (len < 0 || rtmsg.hdr.rtm_errno) - helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: read (%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s) %d", + os_log(log_handle, "SetLocalAddressCacheEntry: read (%zu) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s) %d", sizeof(rtmsg), ifindex, ip[0], ip[1], ip[2], ip[3], rtmsg.hdr.rtm_seq, len, errno, strerror(errno), rtmsg.hdr.rtm_errno); - - *err = 0; + + *err = kHelperErr_NoErr; } else { struct { struct rt_msghdr hdr; struct sockaddr_in6 dst; struct sockaddr_dl sdl; } rtmsg; memset(&rtmsg, 0, sizeof(rtmsg)); - + rtmsg.hdr.rtm_msglen = sizeof(rtmsg); rtmsg.hdr.rtm_version = RTM_VERSION; rtmsg.hdr.rtm_type = RTM_ADD; @@ -302,14 +282,14 @@ kern_return_t do_mDNSSetLocalAddressCacheEntry(__unused mach_port_t port, int if rtmsg.hdr.rtm_use = 0; rtmsg.hdr.rtm_inits = RTV_EXPIRE; rtmsg.hdr.rtm_rmx.rmx_expire = tv.tv_sec + 30; - + rtmsg.dst.sin6_len = sizeof(rtmsg.dst); rtmsg.dst.sin6_family = AF_INET6; rtmsg.dst.sin6_port = 0; rtmsg.dst.sin6_flowinfo = 0; rtmsg.dst.sin6_addr = *(struct in6_addr*)ip; rtmsg.dst.sin6_scope_id = ifindex; - + rtmsg.sdl.sdl_len = sizeof(rtmsg.sdl); rtmsg.sdl.sdl_family = AF_LINK; rtmsg.sdl.sdl_index = ifindex; @@ -317,36 +297,33 @@ kern_return_t do_mDNSSetLocalAddressCacheEntry(__unused mach_port_t port, int if rtmsg.sdl.sdl_nlen = 0; rtmsg.sdl.sdl_alen = ETHER_ADDR_LEN; rtmsg.sdl.sdl_slen = 0; - + // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h) memcpy(rtmsg.sdl.sdl_data, eth, sizeof(ethaddr_t)); - + int len = write(s, (char *)&rtmsg, sizeof(rtmsg)); if (len < 0) - helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: write(%d) interface %d address " IPv6FMTSTRING " seq %d result %d errno %d (%s)", + os_log(log_handle, "SetLocalAddressCacheEntry: write(%zu) interface %d address " IPv6FMTSTRING " seq %d result %d errno %d (%s)", sizeof(rtmsg), ifindex, IPv6FMTARGS, rtmsg.hdr.rtm_seq, len, errno, strerror(errno)); len = read(s, (char *)&rtmsg, sizeof(rtmsg)); if (len < 0 || rtmsg.hdr.rtm_errno) - helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: read (%d) interface %d address " IPv6FMTSTRING " seq %d result %d errno %d (%s) %d", + os_log(log_handle, "SetLocalAddressCacheEntry: read (%zu) interface %d address " IPv6FMTSTRING " seq %d result %d errno %d (%s) %d", sizeof(rtmsg), ifindex, IPv6FMTARGS, rtmsg.hdr.rtm_seq, len, errno, strerror(errno), rtmsg.hdr.rtm_errno); - - *err = 0; + + *err = kHelperErr_NoErr; } - } - -fin: + update_idle_timer(); - return KERN_SUCCESS; } -kern_return_t do_mDNSNotify(__unused mach_port_t port, const char *title, const char *msg, audit_token_t token) -{ - if (!authorized(&token)) return KERN_SUCCESS; +void UserNotify(const char *title, const char *msg) +{ + #ifndef NO_CFUSERNOTIFICATION static const char footer[] = "(Note: This message only appears on machines with 17.x.x.x IP addresses" - " or on debugging builds with ForceAlerts set — i.e. only at Apple — not on customer machines.)"; + " or on debugging builds with ForceAlerts set — i.e. only at Apple — not on customer machines.)"; CFStringRef alertHeader = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8); CFStringRef alertBody = CFStringCreateWithCString(NULL, msg, kCFStringEncodingUTF8); CFStringRef alertFooter = CFStringCreateWithCString(NULL, footer, kCFStringEncodingUTF8); @@ -354,18 +331,19 @@ kern_return_t do_mDNSNotify(__unused mach_port_t port, const char *title, const CFRelease(alertBody); CFRelease(alertFooter); int err = CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage, NULL); - if (err) helplog(ASL_LEVEL_ERR, "CFUserNotificationDisplayNotice returned %d", err); + if (err) + os_log(log_handle, "CFUserNotificationDisplayNotice returned %d", err); CFRelease(alertHeader); CFRelease(alertMessage); #else (void)title; (void)msg; #endif /* NO_CFUSERNOTIFICATION */ - + update_idle_timer(); - return KERN_SUCCESS; } + char usercompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name the user saw char userhostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name the user saw char lastcompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name saved to preferences @@ -386,9 +364,9 @@ static CFRunLoopSourceRef gNotificationRLS = NULL; static void NotificationCallBackDismissed(CFUserNotificationRef userNotification, CFOptionFlags responseFlags) { - debug("entry"); + os_log_debug(log_handle,"entry"); (void)responseFlags; // Unused - if (userNotification != gNotification) helplog(ASL_LEVEL_ERR, "NotificationCallBackDismissed: Wrong CFUserNotificationRef"); + if (userNotification != gNotification) os_log(log_handle, "NotificationCallBackDismissed: Wrong CFUserNotificationRef"); if (gNotificationRLS) { // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread. @@ -416,7 +394,7 @@ static void ShowNameConflictNotification(CFMutableArrayRef header, CFStringRef s CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (!dictionary) return; - debug("entry"); + os_log_debug(log_handle,"entry"); CFDictionarySetValue(dictionary, kCFUserNotificationAlertHeaderKey, header); CFDictionarySetValue(dictionary, kCFUserNotificationAlertMessageKey, subtext); @@ -430,13 +408,13 @@ static void ShowNameConflictNotification(CFMutableArrayRef header, CFStringRef s { SInt32 error; gNotification = CFUserNotificationCreate(NULL, 0, kCFUserNotificationCautionAlertLevel, &error, dictionary); - if (!gNotification || error) { helplog(ASL_LEVEL_ERR, "ShowNameConflictNotification: CFUserNotificationRef: Error %d", error); return; } + if (!gNotification || error) { os_log(log_handle, "ShowNameConflictNotification: CFUserNotificationRef: Error %d", error); return; } gNotificationRLS = CFUserNotificationCreateRunLoopSource(NULL, gNotification, NotificationCallBackDismissed, 0); - if (!gNotificationRLS) { helplog(ASL_LEVEL_ERR,"ShowNameConflictNotification: RLS"); CFRelease(gNotification); gNotification = NULL; return; } + if (!gNotificationRLS) { os_log(log_handle, "ShowNameConflictNotification: RLS"); CFRelease(gNotification); gNotification = NULL; return; } // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread. // We need to explicitly specify the desired CFRunLoop to which we want to add this event source. CFRunLoopAddSource(gRunLoop, gNotificationRLS, kCFRunLoopDefaultMode); - debug("gRunLoop=%p gNotification=%p gNotificationRLS=%p", gRunLoop, gNotification, gNotificationRLS); + os_log_debug(log_handle,"gRunLoop=%p gNotification=%p gNotificationRLS=%p", gRunLoop, gNotification, gNotificationRLS); pause_idle_timer(); } @@ -454,9 +432,13 @@ static CFMutableArrayRef CreateAlertHeader(const char* oldname, const char* newn // arbitrary computer name the user may choose, this exact text (with zero-width non-breaking space added) // can never be one that occurs in the Localizable.strings translation file. if (!cfoldname) - helplog(ASL_LEVEL_ERR,"Could not construct CFStrings for old=%s", newname); + { + os_log(log_handle, "Could not construct CFStrings for old=%s", newname); + } else if (newname && !cfnewname) - helplog(ASL_LEVEL_ERR,"Could not construct CFStrings for new=%s", newname); + { + os_log(log_handle, "Could not construct CFStrings for new=%s", newname); + } else { const CFStringRef s1 = CFStringCreateWithFormat(NULL, NULL, CFS_Format, cfoldname, suffix); @@ -465,11 +447,17 @@ static CFMutableArrayRef CreateAlertHeader(const char* oldname, const char* newn alertHeader = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); if (!s1) - helplog(ASL_LEVEL_ERR, "Could not construct secondary CFString for old=%s", oldname); + { + os_log(log_handle, "Could not construct secondary CFString for old=%s", oldname); + } else if (cfnewname && !s2) - helplog(ASL_LEVEL_ERR, "Could not construct secondary CFString for new=%s", newname); + { + os_log(log_handle, "Could not construct secondary CFString for new=%s", newname); + } else if (!alertHeader) - helplog(ASL_LEVEL_ERR, "Could not construct CFArray for notification"); + { + os_log(log_handle, "Could not construct CFArray for notification"); + } else { // Make sure someone is logged in. We don't want this popping up over the login window @@ -490,7 +478,9 @@ static CFMutableArrayRef CreateAlertHeader(const char* oldname, const char* newn CFArrayAppendValue(alertHeader, CFSTR(".")); } else + { CFArrayAppendValue(alertHeader, CFSTR("All attempts to find an available name by adding a number to the name were also unsuccessful.")); + } } CFRelease(userName); } @@ -508,7 +498,7 @@ static CFMutableArrayRef CreateAlertHeader(const char* oldname, const char* newn static void update_notification(void) { #ifndef NO_CFUSERNOTIFICATION - debug("entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname, userhostname, lastcompname, lasthostname); + os_log_debug(log_handle,"entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname, userhostname, lastcompname, lasthostname); if (!CFS_OQ) { // Note: The "\xEF\xBB\xBF" byte sequence (U+FEFF) in the CFS_Format string is the UTF-8 encoding of the zero-width non-breaking space character. @@ -539,7 +529,7 @@ static void update_notification(void) { if (gNotificationRLS) { - debug("canceling notification %p", gNotification); + os_log_debug(log_handle,"canceling notification %p", gNotification); CFUserNotificationCancel(gNotification); unpause_idle_timer(); } @@ -569,8 +559,7 @@ static void update_notification(void) #endif } -kern_return_t -do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, const char* new, audit_token_t token) +void PreferencesSetName(int key, const char* old, const char* new) { SCPreferencesRef session = NULL; Boolean ok = FALSE; @@ -579,37 +568,37 @@ do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, c char* user = NULL; char* last = NULL; Boolean needUpdate = FALSE; - - debug("entry %s old=%s new=%s", key==kmDNSComputerName ? "ComputerName" : (key==kmDNSLocalHostName ? "LocalHostName" : "UNKNOWN"), old, new); - if (!authorized(&token)) goto fin; - + + os_log_info(log_handle,"PreferencesSetName: entry %s old=%s new=%s", + key==kmDNSComputerName ? "ComputerName" : (key==kmDNSLocalHostName ? "LocalHostName" : "UNKNOWN"), old, new); + switch ((enum mDNSPreferencesSetNameKey)key) { - case kmDNSComputerName: - user = usercompname; - last = lastcompname; - break; - case kmDNSLocalHostName: - user = userhostname; - last = lasthostname; - break; - default: - debug("unrecognized key: %d", key); - goto fin; + case kmDNSComputerName: + user = usercompname; + last = lastcompname; + break; + case kmDNSLocalHostName: + user = userhostname; + last = lasthostname; + break; + default: + os_log(log_handle, "PreferencesSetName: unrecognized key: %d", key); + goto fin; } - + if (!last) { - helplog(ASL_LEVEL_ERR, "%s: no last ptr", __func__); + os_log(log_handle, "PreferencesSetName: no last ptr"); goto fin; } - + if (!user) { - helplog(ASL_LEVEL_ERR, "%s: no user ptr", __func__); + os_log(log_handle, "PreferencesSetName:: no user ptr"); goto fin; } - + if (0 == strncmp(old, new, MAX_DOMAIN_LABEL+1)) { // old and new are same means the config changed i.e, the user has set something in the preferences pane. @@ -634,7 +623,7 @@ do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, c needUpdate = TRUE; } } - + // If we are not showing the dialogue, we need to remember the first "old" value so that // we maintain the same through the lifetime of the dialogue. Subsequent conflicts don't // update the "old" value. @@ -643,57 +632,66 @@ do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, c strncpy(user, old, MAX_DOMAIN_LABEL); needUpdate = TRUE; } - + if (!new[0]) // we've given up trying to construct a name that doesn't conflict goto fin; - + cfstr = CFStringCreateWithCString(NULL, new, kCFStringEncodingUTF8); - - session = SCPreferencesCreate(NULL, CFSTR(kmDNSHelperServiceName), NULL); - + + session = SCPreferencesCreate(NULL, CFSTR(kHelperService), NULL); + if (cfstr == NULL || session == NULL) { - debug("SCPreferencesCreate failed"); + os_log(log_handle, "PreferencesSetName: SCPreferencesCreate failed"); goto fin; } if (!SCPreferencesLock(session, 0)) { - debug("lock failed"); + os_log(log_handle,"PreferencesSetName: lock failed"); goto fin; } locked = TRUE; - + switch ((enum mDNSPreferencesSetNameKey)key) { - case kmDNSComputerName: - { - // We want to write the new Computer Name to System Preferences, without disturbing the user-selected - // system-wide default character set used for things like AppleTalk NBP and NETBIOS service advertising. - // Note that this encoding is not used for the computer name, but since both are set by the same call, - // we need to take care to set the name without changing the character set. - CFStringEncoding encoding = kCFStringEncodingUTF8; - CFStringRef unused = SCDynamicStoreCopyComputerName(NULL, &encoding); - if (unused) { CFRelease(unused); unused = NULL; } - else encoding = kCFStringEncodingUTF8; - - ok = SCPreferencesSetComputerName(session, cfstr, encoding); - } - break; - case kmDNSLocalHostName: - ok = SCPreferencesSetLocalHostName(session, cfstr); - break; - default: - break; - } - + case kmDNSComputerName: + { + // We want to write the new Computer Name to System Preferences, without disturbing the user-selected + // system-wide default character set used for things like AppleTalk NBP and NETBIOS service advertising. + // Note that this encoding is not used for the computer name, but since both are set by the same call, + // we need to take care to set the name without changing the character set. + CFStringEncoding encoding = kCFStringEncodingUTF8; + CFStringRef unused = SCDynamicStoreCopyComputerName(NULL, &encoding); + if (unused) + { + CFRelease(unused); + unused = NULL; + } + else + { + encoding = kCFStringEncodingUTF8; + } + + ok = SCPreferencesSetComputerName(session, cfstr, encoding); + } + break; + + case kmDNSLocalHostName: + ok = SCPreferencesSetLocalHostName(session, cfstr); + break; + + default: + break; + } + if (!ok || !SCPreferencesCommitChanges(session) || !SCPreferencesApplyChanges(session)) { - debug("SCPreferences update failed"); + os_log(log_handle, "PreferencesSetName: SCPreferences update failed"); goto fin; } - debug("succeeded"); - + os_log_info(log_handle,"PreferencesSetName: succeeded"); + fin: if (NULL != cfstr) CFRelease(cfstr); @@ -704,10 +702,12 @@ fin: CFRelease(session); } update_idle_timer(); - if (needUpdate) update_notification(); - return KERN_SUCCESS; + if (needUpdate) + update_notification(); + } + enum DNSKeyFormat { formatNotDNSKey, formatDdnsTypeItem, formatDnsPrefixedServiceItem, formatBtmmPrefixedServiceItem @@ -725,8 +725,7 @@ static const char dnsprefix[] = "dns:"; static const char ddns[] = "ddns"; static const char ddnsrev[] = "sndd"; -static enum DNSKeyFormat -getDNSKeyFormat(SecKeychainItemRef item, SecKeychainAttributeList **attributesp) +static enum DNSKeyFormat getDNSKeyFormat(SecKeychainItemRef item, SecKeychainAttributeList **attributesp) { static UInt32 tags[4] = { @@ -741,13 +740,11 @@ getDNSKeyFormat(SecKeychainItemRef item, SecKeychainAttributeList **attributesp) Boolean malformed = FALSE; OSStatus status = noErr; int i = 0; - + *attributesp = NULL; - if (noErr != (status = SecKeychainItemCopyAttributesAndData(item, - &attributeInfo, NULL, &attributes, NULL, NULL))) + if (noErr != (status = SecKeychainItemCopyAttributesAndData(item, &attributeInfo, NULL, &attributes, NULL, NULL))) { - debug("SecKeychainItemCopyAttributesAndData %d - skipping", - status); + os_log_info(log_handle,"getDNSKeyFormat: SecKeychainItemCopyAttributesAndData %d - skipping", status); goto skip; } if (attributeInfo.count != attributes->count) @@ -757,137 +754,127 @@ getDNSKeyFormat(SecKeychainItemRef item, SecKeychainAttributeList **attributesp) malformed = TRUE; if (malformed) { - debug( - "malformed result from SecKeychainItemCopyAttributesAndData - skipping"); + os_log(log_handle, "getDNSKeyFormat: malformed result from SecKeychainItemCopyAttributesAndData - skipping"); goto skip; } + + os_log_info(log_handle,"getDNSKeyFormat: entry (\"%.*s\", \"%.*s\", \"%.*s\")", + (int)attributes->attr[0].length, attributes->attr[0].data, + (int)attributes->attr[1].length, attributes->attr[1].data, + (int)attributes->attr[2].length, attributes->attr[2].data); - debug("entry (\"%.*s\", \"%.*s\", \"%.*s\")", - (int)attributes->attr[0].length, attributes->attr[0].data, - (int)attributes->attr[1].length, attributes->attr[1].data, - (int)attributes->attr[2].length, attributes->attr[2].data); if (attributes->attr[1].length >= MAX_ESCAPED_DOMAIN_NAME + sizeof(dnsprefix)-1) { - debug("kSecServiceItemAttr too long (%u) - skipping", + os_log(log_handle, "getDNSKeyFormat: kSecServiceItemAttr too long (%u) - skipping", (unsigned int)attributes->attr[1].length); goto skip; } if (attributes->attr[2].length >= MAX_ESCAPED_DOMAIN_NAME) { - debug("kSecAccountItemAttr too long (%u) - skipping", + os_log(log_handle, "getDNSKeyFormat: kSecAccountItemAttr too long (%u) - skipping", (unsigned int)attributes->attr[2].length); goto skip; } - if (attributes->attr[1].length >= sizeof(dnsprefix)-1 && - 0 == strncasecmp(attributes->attr[1].data, dnsprefix, - sizeof(dnsprefix)-1)) + if (attributes->attr[1].length >= sizeof(dnsprefix)-1 && 0 == strncasecmp(attributes->attr[1].data, dnsprefix, sizeof(dnsprefix)-1)) format = formatDnsPrefixedServiceItem; - else if (attributes->attr[1].length >= sizeof(btmmprefix)-1 && - 0 == strncasecmp(attributes->attr[1].data, btmmprefix, sizeof(btmmprefix)-1)) + else if (attributes->attr[1].length >= sizeof(btmmprefix)-1 && 0 == strncasecmp(attributes->attr[1].data, btmmprefix, sizeof(btmmprefix)-1)) format = formatBtmmPrefixedServiceItem; - else if (attributes->attr[0].length == sizeof(ddns)-1 && - 0 == strncasecmp(attributes->attr[0].data, ddns, sizeof(ddns)-1)) + else if (attributes->attr[0].length == sizeof(ddns)-1 && 0 == strncasecmp(attributes->attr[0].data, ddns, sizeof(ddns)-1)) format = formatDdnsTypeItem; - else if (attributes->attr[0].length == sizeof(ddnsrev)-1 && - 0 == strncasecmp(attributes->attr[0].data, ddnsrev, sizeof(ddnsrev)-1)) + else if (attributes->attr[0].length == sizeof(ddnsrev)-1 && 0 == strncasecmp(attributes->attr[0].data, ddnsrev, sizeof(ddnsrev)-1)) format = formatDdnsTypeItem; else { - debug("uninterested in this entry"); + os_log_info(log_handle,"getDNSKeyFormat: uninterested in this entry"); goto skip; } + *attributesp = attributes; - debug("accepting this entry"); + os_log_info(log_handle,"getDNSKeyFormat: accepting this entry"); return format; - + skip: SecKeychainItemFreeAttributesAndData(attributes, NULL); return formatNotDNSKey; } // Insert the attributes as defined by mDNSKeyChainAttributes -static CFPropertyListRef -getKeychainItemInfo(SecKeychainItemRef item, - SecKeychainAttributeList *attributes, enum DNSKeyFormat format) +static CFPropertyListRef copyKeychainItemInfo(SecKeychainItemRef item, SecKeychainAttributeList *attributes, enum DNSKeyFormat format) { CFMutableArrayRef entry = NULL; CFDataRef data = NULL; OSStatus status = noErr; UInt32 keylen = 0; void *keyp = 0; - - if (NULL == (entry = CFArrayCreateMutable(NULL, 0, - &kCFTypeArrayCallBacks))) + + if (NULL == (entry = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks))) { - debug("CFArrayCreateMutable failed"); + os_log(log_handle, "copyKeychainItemInfo: CFArrayCreateMutable failed"); goto error; } - + // Insert the Account attribute (kmDNSKcWhere) switch ((enum DNSKeyFormat)format) { - case formatDdnsTypeItem: - data = CFDataCreate(kCFAllocatorDefault, - attributes->attr[1].data, attributes->attr[1].length); - break; - case formatDnsPrefixedServiceItem: - case formatBtmmPrefixedServiceItem: - data = CFDataCreate(kCFAllocatorDefault, - attributes->attr[1].data, attributes->attr[1].length); - break; - default: - assert("unknown DNSKeyFormat value"); - break; + case formatDdnsTypeItem: + data = CFDataCreate(kCFAllocatorDefault, attributes->attr[1].data, attributes->attr[1].length); + break; + case formatDnsPrefixedServiceItem: + case formatBtmmPrefixedServiceItem: + data = CFDataCreate(kCFAllocatorDefault, attributes->attr[1].data, attributes->attr[1].length); + break; + default: + os_log(log_handle, "copyKeychainItemInfo: unknown DNSKeyFormat value"); + break; } if (NULL == data) { - debug("CFDataCreate for attr[1] failed"); + os_log(log_handle, "copyKeychainItemInfo: CFDataCreate for attr[1] failed"); goto error; } CFArrayAppendValue(entry, data); CFRelease(data); - + // Insert the Where attribute (kmDNSKcAccount) - if (NULL == (data = CFDataCreate(kCFAllocatorDefault, - attributes->attr[2].data, attributes->attr[2].length))) + if (NULL == (data = CFDataCreate(kCFAllocatorDefault, attributes->attr[2].data, attributes->attr[2].length))) { - debug("CFDataCreate for attr[2] failed"); + os_log(log_handle, "copyKeychainItemInfo: CFDataCreate for attr[2] failed"); goto error; } + CFArrayAppendValue(entry, data); CFRelease(data); - + // Insert the Key attribute (kmDNSKcKey) - if (noErr != (status = SecKeychainItemCopyAttributesAndData(item, NULL, - NULL, NULL, &keylen, &keyp))) + if (noErr != (status = SecKeychainItemCopyAttributesAndData(item, NULL, NULL, NULL, &keylen, &keyp))) { - debug("could not retrieve key for \"%.*s\": %d", - (int)attributes->attr[1].length, attributes->attr[1].data, - status); + os_log(log_handle, "copyKeychainItemInfo: could not retrieve key for \"%.*s\": %d", + (int)attributes->attr[1].length, attributes->attr[1].data, status); goto error; } + data = CFDataCreate(kCFAllocatorDefault, keyp, keylen); SecKeychainItemFreeAttributesAndData(NULL, keyp); if (NULL == data) { - debug("CFDataCreate for keyp failed"); + os_log(log_handle, "copyKeychainItemInfo: CFDataCreate for keyp failed"); goto error; } CFArrayAppendValue(entry, data); CFRelease(data); - + // Insert the Name attribute (kmDNSKcName) - if (NULL == (data = CFDataCreate(kCFAllocatorDefault, - attributes->attr[3].data, attributes->attr[3].length))) + if (NULL == (data = CFDataCreate(kCFAllocatorDefault, attributes->attr[3].data, attributes->attr[3].length))) { - debug("CFDataCreate for attr[3] failed"); + os_log(log_handle, "copyKeychainItemInfo: CFDataCreate for attr[3] failed"); goto error; } + CFArrayAppendValue(entry, data); CFRelease(data); return entry; - + error: if (NULL != entry) CFRelease(entry); @@ -895,10 +882,7 @@ error: } #endif -kern_return_t -do_mDNSKeychainGetSecrets(__unused mach_port_t port, __unused unsigned int *numsecrets, - __unused vm_offset_t *secrets, __unused mach_msg_type_number_t *secretsCnt, __unused int *err, - __unused audit_token_t token) +void KeychainGetSecrets(__unused unsigned int *numsecrets,__unused unsigned long *secrets, __unused unsigned int *secretsCnt, __unused int *err) { #ifndef NO_SECURITYFRAMEWORK CFWriteStreamRef stream = NULL; @@ -911,43 +895,34 @@ do_mDNSKeychainGetSecrets(__unused mach_port_t port, __unused unsigned int *nums SecKeychainAttributeList *attributes = NULL; enum DNSKeyFormat format; OSStatus status = 0; - - debug("entry"); - *err = 0; + + os_log_info(log_handle,"KeychainGetSecrets: entry"); + *err = kHelperErr_NoErr; *numsecrets = 0; *secrets = (vm_offset_t)NULL; - if (!authorized(&token)) - { - *err = kmDNSHelperNotAuthorized; - goto fin; - } - if (NULL == (keys = CFArrayCreateMutable(NULL, 0, - &kCFTypeArrayCallBacks))) + + if (NULL == (keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks))) { - debug("CFArrayCreateMutable failed"); - *err = kmDNSHelperCreationFailed; + os_log(log_handle, "KeychainGetSecrets: CFArrayCreateMutable failed"); + *err = kHelperErr_ApiErr; goto fin; } if (noErr != (status = SecKeychainCopyDefault(&skc))) { - *err = kmDNSHelperKeychainCopyDefaultFailed; + *err = kHelperErr_ApiErr; goto fin; } #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" if (noErr != (status = SecKeychainSearchCreateFromAttributes(skc, kSecGenericPasswordItemClass, NULL, &search))) { - *err = kmDNSHelperKeychainSearchCreationFailed; + *err = kHelperErr_ApiErr; goto fin; } - for (status = SecKeychainSearchCopyNext(search, &item); - noErr == status; - status = SecKeychainSearchCopyNext(search, &item)) + for (status = SecKeychainSearchCopyNext(search, &item); noErr == status; status = SecKeychainSearchCopyNext(search, &item)) { - if (formatNotDNSKey != (format = getDNSKeyFormat(item, - &attributes)) && - NULL != (entry = getKeychainItemInfo(item, attributes, - format))) + if (formatNotDNSKey != (format = getDNSKeyFormat(item, &attributes)) && + NULL != (entry = copyKeychainItemInfo(item, attributes, format))) { CFArrayAppendValue(keys, entry); CFRelease(entry); @@ -957,41 +932,41 @@ do_mDNSKeychainGetSecrets(__unused mach_port_t port, __unused unsigned int *nums } #pragma clang diagnostic pop if (errSecItemNotFound != status) - helplog(ASL_LEVEL_ERR, "%s: SecKeychainSearchCopyNext failed: %d", - __func__, status); - if (NULL == (stream = - CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault, - kCFAllocatorDefault))) - { - *err = kmDNSHelperCreationFailed; - debug("CFWriteStreamCreateWithAllocatedBuffers failed"); + os_log(log_handle, "KeychainGetSecrets: SecKeychainSearchCopyNext failed: %d", status); + + if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault, kCFAllocatorDefault))) + { + *err = kHelperErr_ApiErr; + os_log(log_handle, "KeychainGetSecrets:CFWriteStreamCreateWithAllocatedBuffers failed"); goto fin; } + CFWriteStreamOpen(stream); - if (0 == CFPropertyListWrite(keys, stream, - kCFPropertyListBinaryFormat_v1_0, 0, NULL)) + if (0 == CFPropertyListWrite(keys, stream, kCFPropertyListBinaryFormat_v1_0, 0, NULL)) { - *err = kmDNSHelperPListWriteFailed; - debug("CFPropertyListWriteToStream failed"); + *err = kHelperErr_ApiErr; + os_log(log_handle, "KeychainGetSecrets:CFPropertyListWriteToStream failed"); goto fin; } - result = CFWriteStreamCopyProperty(stream, - kCFStreamPropertyDataWritten); - if (KERN_SUCCESS != vm_allocate(mach_task_self(), secrets, - CFDataGetLength(result), VM_FLAGS_ANYWHERE)) + result = CFWriteStreamCopyProperty(stream, kCFStreamPropertyDataWritten); + + if (KERN_SUCCESS != vm_allocate(mach_task_self(), secrets, CFDataGetLength(result), VM_FLAGS_ANYWHERE)) { - *err = kmDNSHelperCreationFailed; - debug("vm_allocate failed"); + *err = kHelperErr_ApiErr; + os_log(log_handle, "KeychainGetSecrets: vm_allocate failed"); goto fin; } - CFDataGetBytes(result, CFRangeMake(0, CFDataGetLength(result)), - (void *)*secrets); + + CFDataGetBytes(result, CFRangeMake(0, CFDataGetLength(result)), (void *)*secrets); *secretsCnt = CFDataGetLength(result); *numsecrets = CFArrayGetCount(keys); - debug("succeeded"); - + + os_log_info(log_handle,"KeychainGetSecrets: succeeded"); + fin: - debug("returning %u secrets", *numsecrets); + os_log_info(log_handle,"KeychainGetSecrets: returning numsecrets[%u] secrets[%lu] secrets addr[%p] secretscount[%u]", + *numsecrets, *secrets, secrets, *secretsCnt); + if (NULL != stream) { CFWriteStreamClose(stream); @@ -1006,465 +981,679 @@ fin: if (NULL != skc) CFRelease(skc); update_idle_timer(); - return KERN_SUCCESS; + + *err = KERN_SUCCESS; + #else - return KERN_FAILURE; + + *err = KERN_FAILURE; + #endif + } -#ifndef MDNS_NO_IPSEC -typedef enum _mDNSTunnelPolicyWhich -{ - kmDNSTunnelPolicySetup, - kmDNSTunnelPolicyTeardown, - kmDNSTunnelPolicyGenerate -} mDNSTunnelPolicyWhich; - -// For kmDNSTunnelPolicySetup, you can setup IPv6-in-IPv6 tunnel or IPv6-in-IPv4 tunnel -// kmDNSNoTunnel is used for other Policy types -typedef enum _mDNSTunnelType -{ - kmDNSNoTunnel, - kmDNSIPv6IPv4Tunnel, - kmDNSIPv6IPv6Tunnel -} mDNSTunnelType; - -static const uint8_t kWholeV6Mask = 128; - -#endif /* ifndef MDNS_NO_IPSEC */ - -#ifndef MDNS_NO_IPSEC - -static const char g_racoon_config_dir[] = "/var/run/racoon/"; -static const char g_racoon_config_dir_old[] = "/etc/racoon/remote/"; CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void); CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey; -// Major version 6 is 10.2.x (Jaguar) -// Major version 7 is 10.3.x (Panther) -// Major version 8 is 10.4.x (Tiger) -// Major version 9 is 10.5.x (Leopard) -// Major version 10 is 10.6.x (SnowLeopard) -// Major version 11 is 10.7.x (Lion) -// Major version 12 is 10.8.x (MountainLion) -// Major version 13 is 10.9.x (Mavericks) -// Major version 14 is 10.10.x (Yosemite) -// Major version 15 is 10.11.x (ElCapitan) -static int MacOSXSystemBuildNumber(char* letter_out, int* minor_out) -{ - int major = 0, minor = 0; - char letter = 0, buildver[256]=""; - CFDictionaryRef vers = _CFCopySystemVersionDictionary(); - if (vers) - { - CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey); - if (cfbuildver) CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8); - sscanf(buildver, "%d%c%d", &major, &letter, &minor); - CFRelease(vers); - } - else - helplog(ASL_LEVEL_NOTICE, "_CFCopySystemVersionDictionary failed"); - - if (!major) { major=10; letter = 'A'; minor = 190; helplog(ASL_LEVEL_NOTICE, "Note: No Major Build Version number found; assuming 10A190"); } - if (letter_out) *letter_out = letter; - if (minor_out) *minor_out = minor; - return(major); -} -static int UseOldRacoon() +void SendWakeupPacket(unsigned int ifid, const char *eth_addr, const char *ip_addr, int iteration) { - static int g_oldRacoon = -1; - - if (g_oldRacoon == -1) + int bpf_fd, i, j; + struct ifreq ifr; + char ifname[IFNAMSIZ]; + char packet[512]; + char *ptr = packet; + char bpf_device[12]; + struct ether_addr *ea; + // (void) ip_addr; // unused + // (void) iteration; // unused + + os_log_info(log_handle,"SendWakeupPacket() ether_addr[%s] ip_addr[%s] if_id[%d] iteration[%d]", + eth_addr, ip_addr, ifid, iteration); + + if (if_indextoname(ifid, ifname) == NULL) { - char letter = 0; - int minor = 0; - g_oldRacoon = (MacOSXSystemBuildNumber(&letter, &minor) < 10); - debug("%s", g_oldRacoon ? "old" : "new"); + os_log(log_handle, "SendWakeupPacket: invalid interface index %u", ifid); + return; } - - return g_oldRacoon; -} - -static int RacoonSignal() -{ - return UseOldRacoon() ? SIGHUP : SIGUSR1; -} - -static const char* GetRacoonConfigDir() -{ - return UseOldRacoon() ? g_racoon_config_dir_old : g_racoon_config_dir; -} - -static const char* GetOldRacoonConfigDir() -{ - return UseOldRacoon() ? NULL : g_racoon_config_dir_old; -} - -static const char racoon_config_file[] = "anonymous.conf"; -static const char racoon_config_file_orig[] = "anonymous.conf.orig"; - -static const char configHeader[] = "# BackToMyMac\n"; - -static int IsFamiliarRacoonConfiguration(const char* racoon_config_path) -{ - int fd = open(racoon_config_path, O_RDONLY); - debug("entry %s", racoon_config_path); - if (0 > fd) + + ea = ether_aton(eth_addr); + if (ea == NULL) { - helplog(ASL_LEVEL_NOTICE, "open \"%s\" failed: %s", racoon_config_path, strerror(errno)); - return 0; + os_log(log_handle, "SendWakeupPacket: invalid ethernet address %s", eth_addr); + return; } - else + + for (i = 0; i < 100; i++) { - char header[sizeof(configHeader)] = {0}; - ssize_t bytesRead = read(fd, header, sizeof(header)-1); - close(fd); - if (bytesRead != sizeof(header)-1) return 0; - return (0 == memcmp(header, configHeader, sizeof(header)-1)); + snprintf(bpf_device, sizeof(bpf_device), "/dev/bpf%d", i); + bpf_fd = open(bpf_device, O_RDWR, 0); + + if (bpf_fd == -1) + continue; + else + break; } -} - -static void -revertAnonymousRacoonConfiguration(const char* dir) -{ - if (!dir) return; - - debug("entry %s", dir); - - char racoon_config_path[64]; - strlcpy(racoon_config_path, dir, sizeof(racoon_config_path)); - strlcat(racoon_config_path, racoon_config_file, sizeof(racoon_config_path)); - - struct stat s; - int ret = stat(racoon_config_path, &s); - debug("stat(%s): %d errno=%d", racoon_config_path, ret, errno); - if (ret == 0) + + if (bpf_fd == -1) { - if (IsFamiliarRacoonConfiguration(racoon_config_path)) - { - helplog(ASL_LEVEL_INFO, "\"%s\" looks familiar, unlinking", racoon_config_path); - unlink(racoon_config_path); - } - else - { - helplog(ASL_LEVEL_NOTICE, "\"%s\" does not look familiar, leaving in place", racoon_config_path); - return; - } + os_log(log_handle, "SendWakeupPacket: cannot find a bpf device"); + return; } - else if (errno != ENOENT) + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + + if (ioctl(bpf_fd, BIOCSETIF, (char *)&ifr) < 0) { - helplog(ASL_LEVEL_NOTICE, "stat failed for \"%s\", leaving in place: %s", racoon_config_path, strerror(errno)); + os_log(log_handle, "SendWakeupPacket: BIOCSETIF failed %s", strerror(errno)); return; } - - char racoon_config_path_orig[64]; - strlcpy(racoon_config_path_orig, dir, sizeof(racoon_config_path_orig)); - strlcat(racoon_config_path_orig, racoon_config_file_orig, sizeof(racoon_config_path_orig)); - - ret = stat(racoon_config_path_orig, &s); - debug("stat(%s): %d errno=%d", racoon_config_path_orig, ret, errno); - if (ret == 0) + + // 0x00 Destination address + for (i=0; i<6; i++) + *ptr++ = ea->octet[i]; + + // 0x06 Source address (Note: Since we don't currently set the BIOCSHDRCMPLT option, + // BPF will fill in the real interface address for us) + for (i=0; i<6; i++) + *ptr++ = 0; + + // 0x0C Ethertype (0x0842) + *ptr++ = 0x08; + *ptr++ = 0x42; + + // 0x0E Wakeup sync sequence + for (i=0; i<6; i++) + *ptr++ = 0xFF; + + // 0x14 Wakeup data + for (j=0; j<16; j++) + for (i=0; i<6; i++) + *ptr++ = ea->octet[i]; + + // 0x74 Password + for (i=0; i<6; i++) + *ptr++ = 0; + + if (write(bpf_fd, packet, ptr - packet) < 0) { - if (0 > rename(racoon_config_path_orig, racoon_config_path)) - helplog(ASL_LEVEL_NOTICE, "rename \"%s\" \"%s\" failed: %s", racoon_config_path_orig, racoon_config_path, strerror(errno)); - else - debug("reverted \"%s\" to \"%s\"", racoon_config_path_orig, racoon_config_path); + os_log(log_handle, "SendWakeupPacket: write failed %s", strerror(errno)); + return; } - else if (errno != ENOENT) + os_log(log_handle, "SendWakeupPacket: sent unicast eth_addr %s, ip_addr %s", eth_addr, ip_addr); + + // Send a broadcast one to handle ethernet switches that don't flood forward packets with + // unknown mac addresses. + for (i=0; i<6; i++) + packet[i] = 0xFF; + + if (write(bpf_fd, packet, ptr - packet) < 0) { - helplog(ASL_LEVEL_NOTICE, "stat failed for \"%s\", leaving in place: %s", racoon_config_path_orig, strerror(errno)); + os_log(log_handle, "SendWakeupPacket: write failed %s", strerror(errno)); return; } + os_log(log_handle, "SendWakeupPacket: sent broadcast eth_addr %s, ip_addr %s", eth_addr, ip_addr); + + close(bpf_fd); + } -static void -moveAsideAnonymousRacoonConfiguration(const char* dir) -{ - if (!dir) return; - debug("entry %s", dir); +// Open the specified port for protocol in the P2P firewall. +void PacketFilterControl(uint32_t command, const char * ifname, uint32_t count, pfArray_t portArray, pfArray_t protocolArray) +{ + int error; + + os_log_info(log_handle,"PacketFilterControl: command %d ifname %s, count %d", + command, ifname, count); + os_log_info(log_handle,"PacketFilterControl: portArray0[%d] portArray1[%d] portArray2[%d] portArray3[%d] protocolArray0[%d] protocolArray1[%d] protocolArray2[%d] protocolArray3[%d]", portArray[0], portArray[1], portArray[2], portArray[3], protocolArray[0], protocolArray[1], protocolArray[2], protocolArray[3]); + + switch (command) + { + case PF_SET_RULES: + error = P2PPacketFilterAddBonjourRuleSet(ifname, count, portArray, protocolArray); + if (error) + os_log(log_handle, "P2PPacketFilterAddBonjourRuleSet failed %s", strerror(error)); + break; + + case PF_CLEAR_RULES: + error = P2PPacketFilterClearBonjourRules(); + if (error) + os_log(log_handle, "P2PPacketFilterClearBonjourRules failed %s", strerror(error)); + break; + + default: + os_log(log_handle, "PacketFilterControl: invalid command %d", command); + break; + } - char racoon_config_path[64]; - strlcpy(racoon_config_path, dir, sizeof(racoon_config_path)); - strlcat(racoon_config_path, racoon_config_file, sizeof(racoon_config_path)); +} - struct stat s; - int ret = stat(racoon_config_path, &s); - if (ret == 0) - { - if (IsFamiliarRacoonConfiguration(racoon_config_path)) - { - helplog(ASL_LEVEL_INFO, "\"%s\" looks familiar, unlinking", racoon_config_path); - unlink(racoon_config_path); - } - else - { - char racoon_config_path_orig[64]; - strlcpy(racoon_config_path_orig, dir, sizeof(racoon_config_path_orig)); - strlcat(racoon_config_path_orig, racoon_config_file_orig, sizeof(racoon_config_path_orig)); - if (0 > rename(racoon_config_path, racoon_config_path_orig)) // If we didn't write it, move it to the side so it can be reverted later - helplog(ASL_LEVEL_NOTICE, "rename \"%s\" to \"%s\" failed: %s", racoon_config_path, racoon_config_path_orig, strerror(errno)); - else - debug("successfully renamed \"%s\" to \"%s\"", racoon_config_path, racoon_config_path_orig); - } - } - else if (errno != ENOENT) - { - helplog(ASL_LEVEL_NOTICE, "stat failed for \"%s\", leaving in place: %s", racoon_config_path, strerror(errno)); - return; - } -} - -static int -ensureExistenceOfRacoonConfigDir(const char* const racoon_config_dir) +static unsigned long in_cksum(unsigned short *ptr, int nbytes) { - struct stat s; - int ret = stat(racoon_config_dir, &s); - if (ret != 0) + unsigned long sum; + u_short oddbyte; + + /* + * Our algorithm is simple, using a 32-bit accumulator (sum), + * we add sequential 16-bit words to it, and at the end, fold back + * all the carry bits from the top 16 bits into the lower 16 bits. + */ + sum = 0; + while (nbytes > 1) { - if (errno != ENOENT) - { - helplog(ASL_LEVEL_ERR, "stat of \"%s\" failed (%d): %s", - racoon_config_dir, ret, strerror(errno)); - return -1; - } - else - { - ret = mkdir(racoon_config_dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); - if (ret != 0) - { - helplog(ASL_LEVEL_ERR, "mkdir \"%s\" failed: %s", - racoon_config_dir, strerror(errno)); - return -1; - } - else - helplog(ASL_LEVEL_INFO, "created directory \"%s\"", racoon_config_dir); - } + sum += *ptr++; + nbytes -= 2; } - else if (!(s.st_mode & S_IFDIR)) + + /* mop up an odd byte, if necessary */ + if (nbytes == 1) { - helplog(ASL_LEVEL_ERR, "\"%s\" is not a directory!", - racoon_config_dir); - return -1; + /* make sure top half is zero */ + oddbyte = 0; + + /* one byte only */ + *((u_char *)&oddbyte) = *(u_char *)ptr; + sum += oddbyte; } - - return 0; + /* Add back carry outs from top 16 bits to low 16 bits. */ + sum = (sum >> 16) + (sum & 0xffff); + + /* add carry */ + sum += (sum >> 16); + + return sum; } -static int -createAnonymousRacoonConfiguration(const char *fqdn) +static unsigned short InetChecksum(unsigned short *ptr, int nbytes) { - static const char config1[] = - "remote anonymous {\n" - " exchange_mode aggressive;\n" - " doi ipsec_doi;\n" - " situation identity_only;\n" - " verify_identifier off;\n" - " generate_policy on;\n" - " shared_secret keychain_by_id \""; - static const char config2[] = - "\";\n" - " nonce_size 16;\n" - " lifetime time 15 min;\n" - " initial_contact on;\n" - " support_proxy on;\n" - " nat_traversal force;\n" - " proposal_check claim;\n" - " proposal {\n" - " encryption_algorithm aes;\n" - " hash_algorithm sha256;\n" - " authentication_method pre_shared_key;\n" - " dh_group 2;\n" - " lifetime time 15 min;\n" - " }\n" - " proposal {\n" - " encryption_algorithm aes;\n" - " hash_algorithm sha1;\n" - " authentication_method pre_shared_key;\n" - " dh_group 2;\n" - " lifetime time 15 min;\n" - " }\n" - "}\n\n" - "sainfo anonymous { \n" - " pfs_group 2;\n" - " lifetime time 10 min;\n" - " encryption_algorithm aes;\n" - " authentication_algorithm hmac_sha256,hmac_sha1;\n" - " compression_algorithm deflate;\n" - "}\n"; - char tmp_config_path[64]; - char racoon_config_path[64]; - const char* const racoon_config_dir = GetRacoonConfigDir(); - const char* const racoon_config_dir_old = GetOldRacoonConfigDir(); - int fd = -1; - - debug("entry"); - - if (0 > ensureExistenceOfRacoonConfigDir(racoon_config_dir)) - return -1; - - strlcpy(tmp_config_path, racoon_config_dir, sizeof(tmp_config_path)); - strlcat(tmp_config_path, "tmp.XXXXXX", sizeof(tmp_config_path)); - - fd = mkstemp(tmp_config_path); + unsigned long sum; + + sum = in_cksum(ptr, nbytes); + return (unsigned short)~sum; +} - if (0 > fd) +static void TCPCheckSum(int af, struct tcphdr *t, int tcplen, const v6addr_t sadd6, const v6addr_t dadd6) +{ + unsigned long sum = 0; + unsigned short *ptr; + + /* TCP header checksum */ + sum = in_cksum((unsigned short *)t, tcplen); + + if (af == AF_INET) { - helplog(ASL_LEVEL_ERR, "mkstemp \"%s\" failed: %s", - tmp_config_path, strerror(errno)); - return -1; + /* Pseudo header */ + ptr = (unsigned short *)sadd6; + sum += *ptr++; + sum += *ptr++; + ptr = (unsigned short *)dadd6; + sum += *ptr++; + sum += *ptr++; } - write(fd, configHeader, sizeof(configHeader)-1); - write(fd, config1, sizeof(config1)-1); - write(fd, fqdn, strlen(fqdn)); - write(fd, config2, sizeof(config2)-1); - close(fd); - - strlcpy(racoon_config_path, racoon_config_dir, sizeof(racoon_config_path)); - strlcat(racoon_config_path, racoon_config_file, sizeof(racoon_config_path)); - - moveAsideAnonymousRacoonConfiguration(racoon_config_dir_old); - moveAsideAnonymousRacoonConfiguration(racoon_config_dir); - - if (0 > rename(tmp_config_path, racoon_config_path)) + else if (af == AF_INET6) { - unlink(tmp_config_path); - helplog(ASL_LEVEL_ERR, "rename \"%s\" \"%s\" failed: %s", - tmp_config_path, racoon_config_path, strerror(errno)); - revertAnonymousRacoonConfiguration(racoon_config_dir_old); - revertAnonymousRacoonConfiguration(racoon_config_dir); - return -1; + /* Pseudo header */ + ptr = (unsigned short *)sadd6; + sum += *ptr++; + sum += *ptr++; + sum += *ptr++; + sum += *ptr++; + sum += *ptr++; + sum += *ptr++; + sum += *ptr++; + sum += *ptr++; + ptr = (unsigned short *)dadd6; + sum += *ptr++; + sum += *ptr++; + sum += *ptr++; + sum += *ptr++; + sum += *ptr++; + sum += *ptr++; + sum += *ptr++; + sum += *ptr++; } - - debug("successfully renamed \"%s\" \"%s\"", tmp_config_path, racoon_config_path); - return 0; + + sum += htons(tcplen); + sum += htons(IPPROTO_TCP); + + while (sum >> 16) + sum = (sum >> 16) + (sum & 0xFFFF); + + t->th_sum = ~sum; + } -static int -notifyRacoon(void) +void SendKeepalive(const v6addr_t sadd6, const v6addr_t dadd6, uint16_t lport, uint16_t rport, uint32_t seq, uint32_t ack, uint16_t win) { - debug("entry"); - static const char racoon_pid_path[] = "/var/run/racoon.pid"; - char buf[] = "18446744073709551615"; /* largest 64-bit integer */ - char *p = NULL; - ssize_t n = 0; - unsigned long m = 0; - int fd = open(racoon_pid_path, O_RDONLY); + +#define IPv6FMTSTRING "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X" +#define IPv6FMTSARGS sadd6[0], sadd6[1], sadd6[2], sadd6[3], sadd6[4], sadd6[5], sadd6[6], sadd6[7], sadd6[8], sadd6[9], sadd6[10], sadd6[11], sadd6[12], sadd6[13], sadd6[14], sadd6[15] +#define IPv6FMTDARGS dadd6[0], dadd6[1], dadd6[2], dadd6[3], dadd6[4], dadd6[5], dadd6[6], dadd6[7], dadd6[8], dadd6[9], dadd6[10], dadd6[11], dadd6[12], dadd6[13], dadd6[14], dadd6[15] - if (0 > fd) + os_log_info(log_handle, "SendKeepalive: "IPv6FMTSTRING" :space: "IPv6FMTSTRING"", + IPv6FMTSARGS, IPv6FMTDARGS); + + struct packet4 { - debug("open \"%s\" failed, and that's OK: %s", racoon_pid_path, - strerror(errno)); - return kmDNSHelperRacoonNotificationFailed; + struct ip ip; + struct tcphdr tcp; + } packet4; + struct packet6 + { + struct tcphdr tcp; + } packet6; + int sock, on; + struct tcphdr *t; + int af; + struct sockaddr_storage ss_to; + struct sockaddr_in *sin_to = (struct sockaddr_in *)&ss_to; + struct sockaddr_in6 *sin6_to = (struct sockaddr_in6 *)&ss_to; + void *packet; + ssize_t packetlen; + char ctlbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; + struct msghdr msghdr; + struct iovec iov; + ssize_t len; + + os_log_info(log_handle,"SendKeepalive invoked: lport is[%d] rport is[%d] seq is[%d] ack is[%d] win is[%d]", + lport, rport, seq, ack, win); + + char buf1[INET6_ADDRSTRLEN]; + char buf2[INET6_ADDRSTRLEN]; + + buf1[0] = 0; + buf2[0] = 0; + + inet_ntop(AF_INET6, sadd6, buf1, sizeof(buf1)); + inet_ntop(AF_INET6, dadd6, buf2, sizeof(buf2)); + + os_log_info(log_handle,"SendKeepalive invoked: sadd6 is %s, dadd6 is %s", buf1, buf2); + + // all the incoming arguments are in network order + if ((*(unsigned *)(sadd6 +4) == 0) && (*(unsigned *)(sadd6 + 8) == 0) && (*(unsigned *)(sadd6 + 12) == 0)) + { + af = AF_INET; + memset(&packet4, 0, sizeof (packet4)); + + /* Fill in all the IP header information - should be in host order*/ + packet4.ip.ip_v = 4; /* 4-bit Version */ + packet4.ip.ip_hl = 5; /* 4-bit Header Length */ + packet4.ip.ip_tos = 0; /* 8-bit Type of service */ + packet4.ip.ip_len = 40; /* 16-bit Total length */ + packet4.ip.ip_id = 9864; /* 16-bit ID field */ + packet4.ip.ip_off = 0; /* 13-bit Fragment offset */ + packet4.ip.ip_ttl = 63; /* 8-bit Time To Live */ + packet4.ip.ip_p = IPPROTO_TCP; /* 8-bit Protocol */ + packet4.ip.ip_sum = 0; /* 16-bit Header checksum (below) */ + memcpy(&packet4.ip.ip_src.s_addr, sadd6, 4); + memcpy(&packet4.ip.ip_dst.s_addr, dadd6, 4); + + /* IP header checksum */ + packet4.ip.ip_sum = InetChecksum((unsigned short *)&packet4.ip, 20); + t = &packet4.tcp; + packet = &packet4; + packetlen = 40; // sum of IPv4 header len(20) and TCP header len(20) } - n = read(fd, buf, sizeof(buf)-1); - close(fd); - if (1 > n) + else { - debug("read of \"%s\" failed: %s", racoon_pid_path, - n == 0 ? "empty file" : strerror(errno)); - return kmDNSHelperRacoonNotificationFailed; + af = AF_INET6; + memset(&packet6, 0, sizeof (packet6)); + t = &packet6.tcp; + packet = &packet6; + // We don't send IPv6 header, hence just the TCP header len (20) + packetlen = 20; } - buf[n] = '\0'; - m = strtoul(buf, &p, 10); - if (*p != '\0' && !isspace(*p)) + + /* Fill in all the TCP header information */ + t->th_sport = lport; /* 16-bit Source port number */ + t->th_dport = rport; /* 16-bit Destination port */ + t->th_seq = seq; /* 32-bit Sequence Number */ + t->th_ack = ack; /* 32-bit Acknowledgement Number */ + t->th_off = 5; /* Data offset */ + t->th_flags = TH_ACK; + t->th_win = win; + t->th_sum = 0; /* 16-bit checksum (below) */ + t->th_urp = 0; /* 16-bit urgent offset */ + + TCPCheckSum(af, t, 20, sadd6, dadd6); + + /* Open up a RAW socket */ + if ((sock = socket(af, SOCK_RAW, IPPROTO_TCP)) < 0) { - debug("invalid PID \"%s\" (around '%c')", buf, *p); - return kmDNSHelperRacoonNotificationFailed; + os_log(log_handle, "SendKeepalive: socket %s", strerror(errno)); + return; } - if (2 > m) + + if (af == AF_INET) { - debug("refusing to kill PID %lu", m); - return kmDNSHelperRacoonNotificationFailed; + on = 1; + if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &on, sizeof (on))) + { + close(sock); + os_log(log_handle, "SendKeepalive: setsockopt %s", strerror(errno)); + return; + } + + memset(sin_to, 0, sizeof(struct sockaddr_in)); + sin_to->sin_len = sizeof(struct sockaddr_in); + sin_to->sin_family = AF_INET; + memcpy(&sin_to->sin_addr, sadd6, sizeof(struct in_addr)); + sin_to->sin_port = rport; + + msghdr.msg_control = NULL; + msghdr.msg_controllen = 0; + } - if (0 != kill(m, RacoonSignal())) + else { - debug("Could not signal racoon (%lu): %s", m, strerror(errno)); - return kmDNSHelperRacoonNotificationFailed; + struct cmsghdr *ctl; + + memset(sin6_to, 0, sizeof(struct sockaddr_in6)); + sin6_to->sin6_len = sizeof(struct sockaddr_in6); + sin6_to->sin6_family = AF_INET6; + memcpy(&sin6_to->sin6_addr, dadd6, sizeof(struct in6_addr)); + + sin6_to->sin6_port = rport; + sin6_to->sin6_flowinfo = 0; + + + msghdr.msg_control = ctlbuf; + msghdr.msg_controllen = sizeof(ctlbuf); + ctl = CMSG_FIRSTHDR(&msghdr); + ctl->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + ctl->cmsg_level = IPPROTO_IPV6; + ctl->cmsg_type = IPV6_PKTINFO; + struct in6_pktinfo *pktinfo = (struct in6_pktinfo *) CMSG_DATA(ctl); + memcpy(&pktinfo->ipi6_addr, sadd6, sizeof(struct in6_addr)); + pktinfo->ipi6_ifindex = 0; } - debug("Sent racoon (%lu) signal %d", m, RacoonSignal()); - return 0; -} - -static void -closefds(int from) -{ - int fd = 0; - struct dirent entry, *entryp = NULL; - DIR *dirp = opendir("/dev/fd"); - - if (dirp == NULL) + + msghdr.msg_name = (struct sockaddr *)&ss_to; + msghdr.msg_namelen = ss_to.ss_len; + iov.iov_base = packet; + iov.iov_len = packetlen; + msghdr.msg_iov = &iov; + msghdr.msg_iovlen = 1; + msghdr.msg_flags = 0; + +again: + len = sendmsg(sock, &msghdr, 0); + if (len == -1) { - /* fall back to the erroneous getdtablesize method */ - for (fd = from; fd < getdtablesize(); ++fd) - close(fd); - return; + if (errno == EINTR) + goto again; } - while (0 == readdir_r(dirp, &entry, &entryp) && NULL != entryp) + + if (len != packetlen) { - fd = atoi(entryp->d_name); - if (fd >= from && fd != dirfd(dirp)) - close(fd); + os_log(log_handle, "SendKeepalive: sendmsg failed %s", strerror(errno)); } - closedir(dirp); -} - -static int -startRacoonOld(void) + else + { + char source[INET6_ADDRSTRLEN], dest[INET6_ADDRSTRLEN]; + + inet_ntop(af, (void *)sadd6, source, sizeof(source)); + inet_ntop(af, (void *)dadd6, dest, sizeof(dest)); + + os_log(log_handle, "SendKeepalive: Success Source %s:%d, Dest %s:%d, %u, %u, %u", + source, ntohs(lport), dest, ntohs(rport), ntohl(seq), ntohl(ack), ntohs(win)); + + } + close(sock); + +} + + +void RetrieveTCPInfo(int family, const v6addr_t laddr, uint16_t lport, const v6addr_t raddr, uint16_t rport, uint32_t *seq, uint32_t *ack, uint16_t *win, int32_t *intfid, int *err) +{ + + struct tcp_info ti; + struct info_tuple itpl; + int mib[4]; + unsigned int miblen; + size_t len; + size_t sz; + + memset(&itpl, 0, sizeof(struct info_tuple)); + memset(&ti, 0, sizeof(struct tcp_info)); + + char buf1[INET6_ADDRSTRLEN]; + char buf2[INET6_ADDRSTRLEN]; + + buf1[0] = 0; + buf2[0] = 0; + + inet_ntop(AF_INET6, laddr, buf1, sizeof(buf1)); + inet_ntop(AF_INET6, raddr, buf2, sizeof(buf2)); + + os_log_info(log_handle, "RetrieveTCPInfo invoked: laddr is %s, raddr is %s", buf1, buf2); + + os_log_info(log_handle,"RetrieveTCPInfo invoked: lport is[%d] rport is[%d] family is [%d]", + lport, rport, family); + + if (family == AF_INET) + { + memcpy(&itpl.itpl_local_sin.sin_addr, laddr, sizeof(struct in_addr)); + memcpy(&itpl.itpl_remote_sin.sin_addr, raddr, sizeof(struct in_addr)); + itpl.itpl_local_sin.sin_port = lport; + itpl.itpl_remote_sin.sin_port = rport; + itpl.itpl_local_sin.sin_family = AF_INET; + itpl.itpl_remote_sin.sin_family = AF_INET; + } + else + { + memcpy(&itpl.itpl_local_sin6.sin6_addr, laddr, sizeof(struct in6_addr)); + memcpy(&itpl.itpl_remote_sin6.sin6_addr, raddr, sizeof(struct in6_addr)); + itpl.itpl_local_sin6.sin6_port = lport; + itpl.itpl_remote_sin6.sin6_port = rport; + itpl.itpl_local_sin6.sin6_family = AF_INET6; + itpl.itpl_remote_sin6.sin6_family = AF_INET6; + } + itpl.itpl_proto = IPPROTO_TCP; + sz = sizeof(mib)/sizeof(mib[0]); + if (sysctlnametomib("net.inet.tcp.info", mib, &sz) == -1) + { + os_log(log_handle, "RetrieveTCPInfo: sysctlnametomib failed %d, %s", errno, strerror(errno)); + *err = errno; + } + miblen = (unsigned int)sz; + len = sizeof(struct tcp_info); + if (sysctl(mib, miblen, &ti, &len, &itpl, sizeof(struct info_tuple)) == -1) + { + os_log(log_handle, "RetrieveTCPInfo: sysctl failed %d, %s", errno, strerror(errno)); + *err = errno; + } + + *seq = ti.tcpi_snd_nxt - 1; + *ack = ti.tcpi_rcv_nxt; + *win = ti.tcpi_rcv_space >> ti.tcpi_rcv_wscale; + *intfid = ti.tcpi_last_outif; + *err = KERN_SUCCESS; + +} + +#ifndef MDNS_NO_IPSEC + +static const char configHeader[] = "# BackToMyMac\n"; +static const char g_racoon_config_dir[] = "/var/run/racoon/"; +static const char g_racoon_config_dir_old[] = "/etc/racoon/remote/"; + +static int MacOSXSystemBuildNumber(char* letter_out, int* minor_out) +{ + int major = 0, minor = 0; + char letter = 0, buildver[256]=""; + CFDictionaryRef vers = _CFCopySystemVersionDictionary(); + if (vers) + { + CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey); + if (cfbuildver) CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8); + sscanf(buildver, "%d%c%d", &major, &letter, &minor); + CFRelease(vers); + } + else + os_log_info(log_handle, "_CFCopySystemVersionDictionary failed"); + + if (!major) { major=16; letter = 'A'; minor = 300; os_log_info(log_handle, "Note: No Major Build Version number found; assuming 16A300"); } + if (letter_out) *letter_out = letter; + if (minor_out) *minor_out = minor; + return(major); +} + +static int UseOldRacoon() +{ + static int g_oldRacoon = -1; + + if (g_oldRacoon == -1) + { + char letter = 0; + int minor = 0; + g_oldRacoon = (MacOSXSystemBuildNumber(&letter, &minor) < 10); + os_log_debug(log_handle, "%s", g_oldRacoon ? "old" : "new"); + } + + return g_oldRacoon; +} + +static int RacoonSignal() +{ + return UseOldRacoon() ? SIGHUP : SIGUSR1; +} + +static int notifyRacoon(void) +{ + os_log_debug(log_handle,"entry"); + static const char racoon_pid_path[] = "/var/run/racoon.pid"; + char buf[] = "18446744073709551615"; /* largest 64-bit integer */ + char *p = NULL; + ssize_t n = 0; + unsigned long m = 0; + int fd = open(racoon_pid_path, O_RDONLY); + + if (0 > fd) + { + os_log_debug(log_handle,"open \"%s\" failed, and that's OK: %s", racoon_pid_path, + strerror(errno)); + return kHelperErr_RacoonNotificationFailed; + } + n = read(fd, buf, sizeof(buf)-1); + close(fd); + if (1 > n) + { + os_log_debug(log_handle,"read of \"%s\" failed: %s", racoon_pid_path, + n == 0 ? "empty file" : strerror(errno)); + return kHelperErr_RacoonNotificationFailed; + } + buf[n] = '\0'; + m = strtoul(buf, &p, 10); + if (*p != '\0' && !isspace(*p)) + { + os_log_debug(log_handle,"invalid PID \"%s\" (around '%c')", buf, *p); + return kHelperErr_RacoonNotificationFailed; + } + if (2 > m) + { + os_log_debug(log_handle,"refusing to kill PID %lu", m); + return kHelperErr_RacoonNotificationFailed; + } + if (0 != kill(m, RacoonSignal())) + { + os_log_debug(log_handle,"Could not signal racoon (%lu): %s", m, strerror(errno)); + return kHelperErr_RacoonNotificationFailed; + } + + os_log_debug(log_handle, "Sent racoon (%lu) signal %d", m, RacoonSignal()); + return 0; +} + +static const char* GetRacoonConfigDir() { - debug("entry"); + return UseOldRacoon() ? g_racoon_config_dir_old : g_racoon_config_dir; +} +/* +static const char* GetOldRacoonConfigDir() +{ + return UseOldRacoon() ? NULL : g_racoon_config_dir_old; +} +*/ + +static void closefds(int from) +{ + int fd = 0; + struct dirent entry, *entryp = NULL; + DIR *dirp = opendir("/dev/fd"); + + if (dirp == NULL) + { + /* fall back to the erroneous getdtablesize method */ + for (fd = from; fd < getdtablesize(); ++fd) + close(fd); + return; + } + while (0 == readdir_r(dirp, &entry, &entryp) && NULL != entryp) + { + fd = atoi(entryp->d_name); + if (fd >= from && fd != dirfd(dirp)) + close(fd); + } + closedir(dirp); +} + + +static int startRacoonOld(void) +{ + os_log_debug(log_handle,"entry"); char * const racoon_args[] = { "/usr/sbin/racoon", "-e", NULL }; ssize_t n = 0; pid_t pid = 0; int status = 0; - + if (0 == (pid = fork())) { closefds(0); execve(racoon_args[0], racoon_args, NULL); - helplog(ASL_LEVEL_ERR, "execve of \"%s\" failed: %s", + os_log_info(log_handle, "execve of \"%s\" failed: %s", racoon_args[0], strerror(errno)); exit(2); } - helplog(ASL_LEVEL_NOTICE, "racoon (pid=%lu) started", + os_log_info(log_handle,"racoon (pid=%lu) started", (unsigned long)pid); n = waitpid(pid, &status, 0); if (-1 == n) { - helplog(ASL_LEVEL_ERR, "Unexpected waitpid failure: %s", + os_log(log_handle, "Unexpected waitpid failure: %s", strerror(errno)); - return kmDNSHelperRacoonStartFailed; + return kHelperErr_RacoonStartFailed; } else if (pid != n) { - helplog(ASL_LEVEL_ERR, "Unexpected waitpid return value %d", - (int)n); - return kmDNSHelperRacoonStartFailed; + os_log(log_handle, "Unexpected waitpid return value %d", (int)n); + return kHelperErr_RacoonStartFailed; } else if (WIFSIGNALED(status)) { - helplog(ASL_LEVEL_ERR, + os_log(log_handle, "racoon (pid=%lu) terminated due to signal %d", (unsigned long)pid, WTERMSIG(status)); - return kmDNSHelperRacoonStartFailed; + return kHelperErr_RacoonStartFailed; } else if (WIFSTOPPED(status)) { - helplog(ASL_LEVEL_ERR, + os_log(log_handle, "racoon (pid=%lu) has stopped due to signal %d", (unsigned long)pid, WSTOPSIG(status)); - return kmDNSHelperRacoonStartFailed; + return kHelperErr_RacoonStartFailed; } else if (0 != WEXITSTATUS(status)) { - helplog(ASL_LEVEL_ERR, + os_log(log_handle, "racoon (pid=%lu) exited with status %d", (unsigned long)pid, WEXITSTATUS(status)); - return kmDNSHelperRacoonStartFailed; + return kHelperErr_RacoonStartFailed; } - debug("racoon (pid=%lu) daemonized normally", (unsigned long)pid); + os_log_debug(log_handle, "racoon (pid=%lu) daemonized normally", (unsigned long)pid); return 0; } @@ -1480,18 +1669,17 @@ typedef struct vpnctl_hdr_struct u_int16_t len; } vpnctl_hdr; -static int -startRacoon(void) +static int startRacoon(void) { - debug("entry"); + os_log_debug(log_handle,"entry"); int fd = socket(PF_UNIX, SOCK_STREAM, 0); if (0 > fd) { - helplog(ASL_LEVEL_ERR, "Could not create endpoint for racoon control socket: %d %s", + os_log(log_handle,"Could not create endpoint for racoon control socket: %d %s", errno, strerror(errno)); - return kmDNSHelperRacoonStartFailed; + return kHelperErr_RacoonStartFailed; } - + struct sockaddr_un saddr; memset(&saddr, 0, sizeof(saddr)); saddr.sun_family = AF_UNIX; @@ -1501,52 +1689,50 @@ startRacoon(void) int result = connect(fd, (struct sockaddr*) &saddr, saddr.sun_len); if (0 > result) { - helplog(ASL_LEVEL_ERR, "Could not connect racoon control socket %s: %d %s", + os_log(log_handle, "Could not connect racoon control socket %s: %d %s", racoon_control_sock_path, errno, strerror(errno)); - return kmDNSHelperRacoonStartFailed; + return kHelperErr_RacoonStartFailed; } - + u_int32_t btmm_cookie = 0x4d4d5442; vpnctl_hdr h = { htons(VPNCTL_CMD_PING), 0, btmm_cookie, 0, 0, 0 }; size_t bytes = 0; ssize_t ret = 0; - + while (bytes < sizeof(vpnctl_hdr)) { ret = write(fd, ((unsigned char*)&h)+bytes, sizeof(vpnctl_hdr) - bytes); if (ret == -1) { - helplog(ASL_LEVEL_ERR, "Could not write to racoon control socket: %d %s", - errno, strerror(errno)); - return kmDNSHelperRacoonStartFailed; + os_log(log_handle, "Could not write to racoon control socket: %d %s", errno, strerror(errno)); + return kHelperErr_RacoonStartFailed; } bytes += ret; } - + int nfds = fd + 1; fd_set fds; int counter = 0; struct timeval tv; bytes = 0; h.cookie = 0; - + for (counter = 0; counter < 100; counter++) { FD_ZERO(&fds); FD_SET(fd, &fds); tv = (struct timeval){ 0, 10000 }; // 10 milliseconds * 100 iterations = 1 second max wait time - + result = select(nfds, &fds, (fd_set*)NULL, (fd_set*)NULL, &tv); if (result > 0) { if (FD_ISSET(fd, &fds)) { ret = read(fd, ((unsigned char*)&h)+bytes, sizeof(vpnctl_hdr) - bytes); - + if (ret == -1) { - helplog(ASL_LEVEL_ERR, "Could not read from racoon control socket: %d %s", - strerror(errno)); + os_log(log_handle,"Could not read from racoon control socket: %d %s", errno, strerror(errno)); break; } bytes += ret; @@ -1554,1367 +1740,701 @@ startRacoon(void) } else { - debug("select returned but fd_isset not on expected fd\n"); + os_log_debug(log_handle, "select returned but fd_isset not on expected fd"); } } else if (result < 0) { - debug("select returned %d errno %d %s\n", result, errno, strerror(errno)); + os_log_debug(log_handle, "select returned %d errno %d %s", result, errno, strerror(errno)); if (errno != EINTR) break; } } - + close(fd); - - if (bytes < sizeof(vpnctl_hdr) || h.cookie != btmm_cookie) return kmDNSHelperRacoonStartFailed; - - debug("racoon started"); + + if (bytes < sizeof(vpnctl_hdr) || h.cookie != btmm_cookie) + return kHelperErr_RacoonStartFailed; + + os_log_debug(log_handle, "racoon started"); return 0; } -static int -kickRacoon(void) +static int kickRacoon(void) { if ( 0 == notifyRacoon() ) return 0; return UseOldRacoon() ? startRacoonOld() : startRacoon(); } -#endif /* ndef MDNS_NO_IPSEC */ - -int -do_mDNSConfigureServer(__unused mach_port_t port, int updown, const char *fqdn, audit_token_t token) -{ -#ifndef MDNS_NO_IPSEC - debug("entry"); - if (!authorized(&token)) goto fin; - - switch ((enum mDNSUpDown)updown) - { - case kmDNSUp: - if (0 != createAnonymousRacoonConfiguration(fqdn)) goto fin; - break; - case kmDNSDown: - revertAnonymousRacoonConfiguration(GetOldRacoonConfigDir()); - revertAnonymousRacoonConfiguration(GetRacoonConfigDir()); - break; - default: - goto fin; - } - - if (0 != kickRacoon()) - goto fin; - debug("succeeded"); - -fin: -#else - (void)port; (void)updown; (void)fqdn; (void)token; -#endif - update_idle_timer(); - return KERN_SUCCESS; -} - -#ifndef MDNS_NO_IPSEC - -static unsigned int routeSeq = 1; - -static int -setupTunnelRoute(v6addr_t local, v6addr_t remote) +typedef enum _mDNSTunnelPolicyWhich { - struct - { - struct rt_msghdr hdr; - struct sockaddr_in6 dst; - struct sockaddr_in6 gtwy; - } msg; - int err = 0; - int s = -1; - - if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET))) - { - helplog(ASL_LEVEL_ERR, "socket(PF_ROUTE, ...) failed: %s", - strerror(errno)); - err = kmDNSHelperRoutingSocketCreationFailed; - goto fin; - } - memset(&msg, 0, sizeof(msg)); - msg.hdr.rtm_msglen = sizeof(msg); - msg.hdr.rtm_type = RTM_ADD; - /* The following flags are set by `route add -inet6 -host ...` */ - msg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_HOST | RTF_STATIC; - msg.hdr.rtm_version = RTM_VERSION; - msg.hdr.rtm_seq = routeSeq++; - msg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY; - msg.hdr.rtm_inits = RTV_MTU; - msg.hdr.rtm_rmx.rmx_mtu = 1280; - - msg.dst.sin6_len = sizeof(msg.dst); - msg.dst.sin6_family = AF_INET6; - memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr)); - - msg.gtwy.sin6_len = sizeof(msg.gtwy); - msg.gtwy.sin6_family = AF_INET6; - memcpy(&msg.gtwy.sin6_addr, local, sizeof(msg.gtwy.sin6_addr)); - - /* send message, ignore error when route already exists */ - if (0 > write(s, &msg, msg.hdr.rtm_msglen)) - { - int errno_ = errno; - - debug("write to routing socket failed: %s", strerror(errno_)); - if (EEXIST != errno_) - { - err = kmDNSHelperRouteAdditionFailed; - goto fin; - } - } - -fin: - if (0 <= s) - close(s); - return err; -} + kmDNSTunnelPolicySetup, + kmDNSTunnelPolicyTeardown, + kmDNSTunnelPolicyGenerate +} mDNSTunnelPolicyWhich; -static int -teardownTunnelRoute(v6addr_t remote) +// For kmDNSTunnelPolicySetup, you can setup IPv6-in-IPv6 tunnel or IPv6-in-IPv4 tunnel +// kmDNSNoTunnel is used for other Policy types +typedef enum _mDNSTunnelType { - struct - { - struct rt_msghdr hdr; - struct sockaddr_in6 dst; - } msg; - int err = 0; - int s = -1; - - if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET))) - { - helplog(ASL_LEVEL_ERR, "socket(PF_ROUTE, ...) failed: %s", - strerror(errno)); - err = kmDNSHelperRoutingSocketCreationFailed; - goto fin; - } - memset(&msg, 0, sizeof(msg)); - - msg.hdr.rtm_msglen = sizeof(msg); - msg.hdr.rtm_type = RTM_DELETE; - msg.hdr.rtm_version = RTM_VERSION; - msg.hdr.rtm_seq = routeSeq++; - msg.hdr.rtm_addrs = RTA_DST; - - msg.dst.sin6_len = sizeof(msg.dst); - msg.dst.sin6_family = AF_INET6; - memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr)); - if (0 > write(s, &msg, msg.hdr.rtm_msglen)) - { - int errno_ = errno; - - debug("write to routing socket failed: %s", strerror(errno_)); - if (ESRCH != errno_) - { - err = kmDNSHelperRouteDeletionFailed; - goto fin; - } - } - -fin: - if (0 <= s) - close(s); - return err; -} - -static int -v4addr_to_string(v4addr_t addr, char *buf, size_t buflen) -{ - if (NULL == inet_ntop(AF_INET, addr, buf, buflen)) - { - helplog(ASL_LEVEL_ERR, "inet_ntop failed: %s", - strerror(errno)); - return kmDNSHelperInvalidNetworkAddress; - } - else - return 0; -} - -static int -v6addr_to_string(v6addr_t addr, char *buf, size_t buflen) -{ - if (NULL == inet_ntop(AF_INET6, addr, buf, buflen)) - { - helplog(ASL_LEVEL_ERR, "inet_ntop failed: %s", - strerror(errno)); - return kmDNSHelperInvalidNetworkAddress; - } - else - return 0; -} - -/* Caller owns object returned in `policy' */ -static int -generateTunnelPolicy(mDNSTunnelPolicyWhich which, mDNSTunnelType type, int in, - v4addr_t src, uint16_t src_port, - v4addr_t dst, uint16_t dst_port, - v6addr_t src6, v6addr_t dst6, - ipsec_policy_t *policy, size_t *len) -{ - char srcs[INET_ADDRSTRLEN], dsts[INET_ADDRSTRLEN]; - char srcs6[INET6_ADDRSTRLEN], dsts6[INET6_ADDRSTRLEN]; - char buf[512]; - char *inOut = in ? "in" : "out"; - ssize_t n = 0; - int err = 0; - - *policy = NULL; - *len = 0; - - switch (which) - { - case kmDNSTunnelPolicySetup: - if (type == kmDNSIPv6IPv4Tunnel) - { - if (0 != (err = v4addr_to_string(src, srcs, sizeof(srcs)))) - goto fin; - if (0 != (err = v4addr_to_string(dst, dsts, sizeof(dsts)))) - goto fin; - n = snprintf(buf, sizeof(buf), - "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require", - inOut, srcs, src_port, dsts, dst_port); - } - else if (type == kmDNSIPv6IPv6Tunnel) - { - if (0 != (err = v6addr_to_string(src6, srcs6, sizeof(srcs6)))) - goto fin; - if (0 != (err = v6addr_to_string(dst6, dsts6, sizeof(dsts6)))) - goto fin; - n = snprintf(buf, sizeof(buf), - "%s ipsec esp/tunnel/%s-%s/require", - inOut, srcs6, dsts6); - } - break; - case kmDNSTunnelPolicyTeardown: - n = strlcpy(buf, inOut, sizeof(buf)); - break; - case kmDNSTunnelPolicyGenerate: - n = snprintf(buf, sizeof(buf), "%s generate", inOut); - break; - default: - err = kmDNSHelperIPsecPolicyCreationFailed; - goto fin; - } - - if (n >= (int)sizeof(buf)) - { - err = kmDNSHelperResultTooLarge; - goto fin; - } - - debug("policy=\"%s\"", buf); - if (NULL == (*policy = (ipsec_policy_t)ipsec_set_policy(buf, n))) - { - helplog(ASL_LEVEL_ERR, - "Could not create IPsec policy from \"%s\"", buf); - err = kmDNSHelperIPsecPolicyCreationFailed; - goto fin; - } - *len = ((ipsec_policy_t)(*policy))->sadb_x_policy_len * 8; - -fin: - return err; -} - -static int -sendPolicy(int s, int setup, - struct sockaddr *src, uint8_t src_bits, - struct sockaddr *dst, uint8_t dst_bits, - ipsec_policy_t policy, size_t len) -{ - static unsigned int policySeq = 0; - int err = 0; - - debug("entry, setup=%d", setup); - if (setup) - err = pfkey_send_spdadd(s, src, src_bits, dst, dst_bits, -1, - (char *)policy, len, policySeq++); - else - err = pfkey_send_spddelete(s, src, src_bits, dst, dst_bits, -1, - (char *)policy, len, policySeq++); - if (0 > err) - { - helplog(ASL_LEVEL_ERR, "Could not set IPsec policy: %s", - ipsec_strerror()); - err = kmDNSHelperIPsecPolicySetFailed; - goto fin; - } - else - err = 0; - debug("succeeded"); - -fin: - return err; -} - -static int -removeSA(int s, struct sockaddr *src, struct sockaddr *dst) -{ - int err = 0; - - debug("entry"); - err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, src, dst); - if (0 > err) - { - helplog(ASL_LEVEL_ERR, "Could not remove IPsec SA: %s", ipsec_strerror()); - err = kmDNSHelperIPsecRemoveSAFailed; - goto fin; - } - err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, dst, src); - if (0 > err) - { - helplog(ASL_LEVEL_ERR, "Could not remove IPsec SA: %s", ipsec_strerror()); - err = kmDNSHelperIPsecRemoveSAFailed; - goto fin; - } - else - err = 0; - - debug("succeeded"); - -fin: - return err; -} - -static int -doTunnelPolicy(mDNSTunnelPolicyWhich which, mDNSTunnelType type, - v6addr_t loc_inner, uint8_t loc_bits, - v4addr_t loc_outer, uint16_t loc_port, - v6addr_t rmt_inner, uint8_t rmt_bits, - v4addr_t rmt_outer, uint16_t rmt_port, - v6addr_t loc_outer6, v6addr_t rmt_outer6) -{ - struct sockaddr_in6 sin6_loc; - struct sockaddr_in6 sin6_rmt; - ipsec_policy_t policy = NULL; - size_t len = 0; - int s = -1; - int err = 0; - - debug("entry"); - if (0 > (s = pfkey_open())) - { - helplog(ASL_LEVEL_ERR, - "Could not create IPsec policy socket: %s", - ipsec_strerror()); - err = kmDNSHelperIPsecPolicySocketCreationFailed; - goto fin; - } - - memset(&sin6_loc, 0, sizeof(sin6_loc)); - sin6_loc.sin6_len = sizeof(sin6_loc); - sin6_loc.sin6_family = AF_INET6; - sin6_loc.sin6_port = htons(0); - memcpy(&sin6_loc.sin6_addr, loc_inner, sizeof(sin6_loc.sin6_addr)); - - memset(&sin6_rmt, 0, sizeof(sin6_rmt)); - sin6_rmt.sin6_len = sizeof(sin6_rmt); - sin6_rmt.sin6_family = AF_INET6; - sin6_rmt.sin6_port = htons(0); - memcpy(&sin6_rmt.sin6_addr, rmt_inner, sizeof(sin6_rmt.sin6_addr)); - - int setup = which != kmDNSTunnelPolicyTeardown; - - if (0 != (err = generateTunnelPolicy(which, type, 1, - rmt_outer, rmt_port, - loc_outer, loc_port, - rmt_outer6, loc_outer6, - &policy, &len))) - goto fin; - if (0 != (err = sendPolicy(s, setup, - (struct sockaddr *)&sin6_rmt, rmt_bits, - (struct sockaddr *)&sin6_loc, loc_bits, - policy, len))) - goto fin; - if (NULL != policy) - { - free(policy); - policy = NULL; - } - if (0 != (err = generateTunnelPolicy(which, type, 0, - loc_outer, loc_port, - rmt_outer, rmt_port, - loc_outer6, rmt_outer6, - &policy, &len))) - goto fin; - if (0 != (err = sendPolicy(s, setup, - (struct sockaddr *)&sin6_loc, loc_bits, - (struct sockaddr *)&sin6_rmt, rmt_bits, - policy, len))) - goto fin; - - if (which == kmDNSTunnelPolicyTeardown) - { - if (rmt_port) // Outer tunnel is IPv4 - { - if (loc_outer && rmt_outer) - { - struct sockaddr_in sin_loc; - struct sockaddr_in sin_rmt; - memset(&sin_loc, 0, sizeof(sin_loc)); - sin_loc.sin_len = sizeof(sin_loc); - sin_loc.sin_family = AF_INET; - memcpy(&sin_loc.sin_addr, loc_outer, sizeof(sin_loc.sin_addr)); - - memset(&sin_rmt, 0, sizeof(sin_rmt)); - sin_rmt.sin_len = sizeof(sin_rmt); - sin_rmt.sin_family = AF_INET; - memcpy(&sin_rmt.sin_addr, rmt_outer, sizeof(sin_rmt.sin_addr)); - if (0 != (err = removeSA(s, (struct sockaddr *)&sin_loc, (struct sockaddr *)&sin_rmt))) - goto fin; - } - } - else - { - if (loc_outer6 && rmt_outer6) - { - struct sockaddr_in6 sin6_lo; - struct sockaddr_in6 sin6_rm; - - memset(&sin6_lo, 0, sizeof(sin6_lo)); - sin6_lo.sin6_len = sizeof(sin6_lo); - sin6_lo.sin6_family = AF_INET6; - memcpy(&sin6_lo.sin6_addr, loc_outer6, sizeof(sin6_lo.sin6_addr)); - - memset(&sin6_rm, 0, sizeof(sin6_rm)); - sin6_rm.sin6_len = sizeof(sin6_rm); - sin6_rm.sin6_family = AF_INET6; - memcpy(&sin6_rm.sin6_addr, rmt_outer6, sizeof(sin6_rm.sin6_addr)); - if (0 != (err = removeSA(s, (struct sockaddr *)&sin6_lo, (struct sockaddr *)&sin6_rm))) - goto fin; - } - } - } - - - debug("succeeded"); - -fin: - if (s >= 0) - pfkey_close(s); - if (NULL != policy) - free(policy); - return err; -} - -#endif /* ndef MDNS_NO_IPSEC */ - -int -do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete, - v6addr_t loc_inner, v6addr_t loc_outer6, uint16_t loc_port, - v6addr_t rmt_inner, v6addr_t rmt_outer6, uint16_t rmt_port, - const char *id, int *err, audit_token_t token) -{ -#ifndef MDNS_NO_IPSEC - static const char config[] = - "%s" - "remote %s [%u] {\n" - " disconnect_on_idle idle_timeout 600 idle_direction idle_outbound;\n" - " exchange_mode aggressive;\n" - " doi ipsec_doi;\n" - " situation identity_only;\n" - " verify_identifier off;\n" - " generate_policy on;\n" - " my_identifier user_fqdn \"%s\";\n" - " shared_secret keychain \"%s\";\n" - " nonce_size 16;\n" - " lifetime time 15 min;\n" - " initial_contact on;\n" - " support_proxy on;\n" - " nat_traversal force;\n" - " proposal_check claim;\n" - " proposal {\n" - " encryption_algorithm aes;\n" - " hash_algorithm sha256;\n" - " authentication_method pre_shared_key;\n" - " dh_group 2;\n" - " lifetime time 15 min;\n" - " }\n" - " proposal {\n" - " encryption_algorithm aes;\n" - " hash_algorithm sha1;\n" - " authentication_method pre_shared_key;\n" - " dh_group 2;\n" - " lifetime time 15 min;\n" - " }\n" - "}\n\n" - "sainfo address %s any address %s any {\n" - " pfs_group 2;\n" - " lifetime time 10 min;\n" - " encryption_algorithm aes;\n" - " authentication_algorithm hmac_sha256,hmac_sha1;\n" - " compression_algorithm deflate;\n" - "}\n\n" - "sainfo address %s any address %s any {\n" - " pfs_group 2;\n" - " lifetime time 10 min;\n" - " encryption_algorithm aes;\n" - " authentication_algorithm hmac_sha256,hmac_sha1;\n" - " compression_algorithm deflate;\n" - "}\n"; - char path[PATH_MAX] = ""; - char li[INET6_ADDRSTRLEN], lo[INET_ADDRSTRLEN], lo6[INET6_ADDRSTRLEN], - ri[INET6_ADDRSTRLEN], ro[INET_ADDRSTRLEN], ro6[INET6_ADDRSTRLEN]; - FILE *fp = NULL; - int fd = -1; - char tmp_path[PATH_MAX] = ""; - v4addr_t loc_outer, rmt_outer; - - debug("entry"); - *err = 0; - if (!authorized(&token)) - { - *err = kmDNSHelperNotAuthorized; - goto fin; - } - switch ((enum mDNSAutoTunnelSetKeysReplaceDelete)replacedelete) - { - case kmDNSAutoTunnelSetKeysReplace: - case kmDNSAutoTunnelSetKeysDelete: - break; - default: - *err = kmDNSHelperInvalidTunnelSetKeysOperation; - goto fin; - } - - if (0 != (*err = v6addr_to_string(loc_inner, li, sizeof(li)))) - goto fin; - if (0 != (*err = v6addr_to_string(rmt_inner, ri, sizeof(ri)))) - goto fin; - - debug("loc_inner=%s rmt_inner=%s", li, ri); - if (!rmt_port) - { - loc_outer[0] = loc_outer[1] = loc_outer[2] = loc_outer[3] = 0; - rmt_outer[0] = rmt_outer[1] = rmt_outer[2] = rmt_outer[3] = 0; - - if (0 != (*err = v6addr_to_string(loc_outer6, lo6, sizeof(lo6)))) - goto fin; - if (0 != (*err = v6addr_to_string(rmt_outer6, ro6, sizeof(ro6)))) - goto fin; - debug("IPv6 outer tunnel: loc_outer6=%s rmt_outer6=%s", lo6, ro6); - if ((int)sizeof(path) <= snprintf(path, sizeof(path), - "%s%s.conf", GetRacoonConfigDir(), ro6)) - { - *err = kmDNSHelperResultTooLarge; - goto fin; - } - } - else - { - loc_outer[0] = loc_outer6[0]; - loc_outer[1] = loc_outer6[1]; - loc_outer[2] = loc_outer6[2]; - loc_outer[3] = loc_outer6[3]; - - rmt_outer[0] = rmt_outer6[0]; - rmt_outer[1] = rmt_outer6[1]; - rmt_outer[2] = rmt_outer6[2]; - rmt_outer[3] = rmt_outer6[3]; - - if (0 != (*err = v4addr_to_string(loc_outer, lo, sizeof(lo)))) - goto fin; - if (0 != (*err = v4addr_to_string(rmt_outer, ro, sizeof(ro)))) - goto fin; - debug("IPv4 outer tunnel: loc_outer=%s loc_port=%u rmt_outer=%s rmt_port=%u", - lo, loc_port, ro, rmt_port); - - if ((int)sizeof(path) <= snprintf(path, sizeof(path), - "%s%s.%u.conf", GetRacoonConfigDir(), ro, - rmt_port)) - { - *err = kmDNSHelperResultTooLarge; - goto fin; - } - } - - - - if (kmDNSAutoTunnelSetKeysReplace == replacedelete) - { - if (0 > ensureExistenceOfRacoonConfigDir(GetRacoonConfigDir())) - { - *err = kmDNSHelperRacoonConfigCreationFailed; - goto fin; - } - if ((int)sizeof(tmp_path) <= - snprintf(tmp_path, sizeof(tmp_path), "%s.XXXXXX", path)) - { - *err = kmDNSHelperResultTooLarge; - goto fin; - } - if (0 > (fd = mkstemp(tmp_path))) - { - helplog(ASL_LEVEL_ERR, "mkstemp \"%s\" failed: %s", - tmp_path, strerror(errno)); - *err = kmDNSHelperRacoonConfigCreationFailed; - goto fin; - } - if (NULL == (fp = fdopen(fd, "w"))) - { - helplog(ASL_LEVEL_ERR, "fdopen: %s", - strerror(errno)); - *err = kmDNSHelperRacoonConfigCreationFailed; - goto fin; - } - fd = -1; - fprintf(fp, config, configHeader, (!rmt_port ? ro6 : ro), rmt_port, id, id, ri, li, li, ri); - fclose(fp); - fp = NULL; - if (0 > rename(tmp_path, path)) - { - helplog(ASL_LEVEL_ERR, - "rename \"%s\" \"%s\" failed: %s", - tmp_path, path, strerror(errno)); - *err = kmDNSHelperRacoonConfigCreationFailed; - goto fin; - } - } - else - { - if (0 != unlink(path)) - debug("unlink \"%s\" failed: %s", path, - strerror(errno)); - } - - if (0 != (*err = doTunnelPolicy(kmDNSTunnelPolicyTeardown, kmDNSNoTunnel, - loc_inner, kWholeV6Mask, loc_outer, loc_port, - rmt_inner, kWholeV6Mask, rmt_outer, rmt_port, loc_outer6, rmt_outer6))) - goto fin; - if (kmDNSAutoTunnelSetKeysReplace == replacedelete && - 0 != (*err = doTunnelPolicy(kmDNSTunnelPolicySetup, (!rmt_port ? kmDNSIPv6IPv6Tunnel : kmDNSIPv6IPv4Tunnel), - loc_inner, kWholeV6Mask, loc_outer, loc_port, - rmt_inner, kWholeV6Mask, rmt_outer, rmt_port, loc_outer6, rmt_outer6))) - goto fin; - - if (0 != (*err = teardownTunnelRoute(rmt_inner))) - goto fin; - if (kmDNSAutoTunnelSetKeysReplace == replacedelete && - 0 != (*err = setupTunnelRoute(loc_inner, rmt_inner))) - goto fin; - - if (kmDNSAutoTunnelSetKeysReplace == replacedelete && - 0 != (*err = kickRacoon())) - goto fin; - - debug("succeeded"); - -fin: - if (NULL != fp) - fclose(fp); - if (0 <= fd) - close(fd); - unlink(tmp_path); -#else - (void)replacedelete; (void)loc_inner; (void)loc_outer6; (void)loc_port; (void)rmt_inner; - (void)rmt_outer6; (void)rmt_port; (void)id; (void)token; - - *err = kmDNSHelperIPsecDisabled; -#endif /* MDNS_NO_IPSEC */ - update_idle_timer(); - return KERN_SUCCESS; -} - -kern_return_t -do_mDNSSendWakeupPacket(__unused mach_port_t port, unsigned ifid, const char *eth_addr, const char *ip_addr, int iteration, audit_token_t token) -{ - int bpf_fd, i, j; - struct ifreq ifr; - char ifname[IFNAMSIZ]; - char packet[512]; - char *ptr = packet; - char bpf_device[12]; - struct ether_addr *ea; - (void) ip_addr; // unused - (void) iteration; // unused - (void) token; // unused - - if (if_indextoname(ifid, ifname) == NULL) - { - helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket invalid interface index %u", ifid); - return errno; - } - - ea = ether_aton(eth_addr); - if (ea == NULL) - { - helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket invalid ethernet address %s", eth_addr); - return errno; - } - - for (i = 0; i < 100; i++) - { - snprintf(bpf_device, sizeof(bpf_device), "/dev/bpf%d", i); - bpf_fd = open(bpf_device, O_RDWR, 0); - if (bpf_fd == -1) - continue; - else break; - } - - if (bpf_fd == -1) - { - helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket cannot find a bpf device"); - return ENXIO; - } - - memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); - - if (ioctl(bpf_fd, BIOCSETIF, (char *)&ifr) < 0) - { - helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket BIOCSETIF failed %s", strerror(errno)); - return errno; - } - - // 0x00 Destination address - for (i=0; i<6; i++) *ptr++ = ea->octet[i]; - - // 0x06 Source address (Note: Since we don't currently set the BIOCSHDRCMPLT option, BPF will fill in the real interface address for us) - for (i=0; i<6; i++) *ptr++ = 0; - - // 0x0C Ethertype (0x0842) - *ptr++ = 0x08; - *ptr++ = 0x42; - - // 0x0E Wakeup sync sequence - for (i=0; i<6; i++) *ptr++ = 0xFF; - - // 0x14 Wakeup data - for (j=0; j<16; j++) for (i=0; i<6; i++) *ptr++ = ea->octet[i]; - - // 0x74 Password - for (i=0; i<6; i++) *ptr++ = 0; - - if (write(bpf_fd, packet, ptr - packet) < 0) - { - helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket write failed %s", strerror(errno)); - return errno; - } - helplog(ASL_LEVEL_INFO, "do_mDNSSendWakeupPacket sent unicast eth_addr %s, ip_addr %s", eth_addr, ip_addr); - // Send a broadcast one to handle ethernet switches that don't flood forward packets with - // unknown mac addresses. - for (i=0; i<6; i++) packet[i] = 0xFF; - if (write(bpf_fd, packet, ptr - packet) < 0) - { - helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket write failed %s", strerror(errno)); - return errno; - } - helplog(ASL_LEVEL_INFO, "do_mDNSSendWakeupPacket sent broadcast eth_addr %s, ip_addr %s", eth_addr, ip_addr); - close(bpf_fd); - return KERN_SUCCESS; -} - -// Open the specified port for protocol in the P2P firewall. -kern_return_t -do_mDNSPacketFilterControl(__unused mach_port_t port, uint32_t command, const char * ifname, uint32_t count, pfArray_t portArray, pfArray_t protocolArray, audit_token_t token) -{ - (void) token; // unused - int error; - kern_return_t result = KERN_SUCCESS; - - helplog(ASL_LEVEL_INFO, "do_mDNSPacketFilterControl: command %d ifname %s, count %d", - command, ifname, count); - - switch (command) - { - case PF_SET_RULES: - error = P2PPacketFilterAddBonjourRuleSet(ifname, count, portArray, protocolArray); - if (error) - { - helplog(ASL_LEVEL_ERR, "P2PPacketFilterAddBonjourRuleSet failed %s", strerror(error)); - result = KERN_FAILURE; - } - break; - - case PF_CLEAR_RULES: - error = P2PPacketFilterClearBonjourRules(); - if (error) - { - helplog(ASL_LEVEL_ERR, "P2PPacketFilterClearBonjourRules failed %s", strerror(error)); - result = KERN_FAILURE; - } - break; - - default: - helplog(ASL_LEVEL_ERR, "do_mDNSPacketFilterControl: invalid command %d", command); - result = KERN_INVALID_ARGUMENT; - break; - } - - return result; -} - -unsigned long -in_cksum(unsigned short *ptr,int nbytes) -{ - unsigned long sum; - u_short oddbyte; - - /* - * Our algorithm is simple, using a 32-bit accumulator (sum), - * we add sequential 16-bit words to it, and at the end, fold back - * all the carry bits from the top 16 bits into the lower 16 bits. - */ - sum = 0; - while (nbytes > 1) - { - sum += *ptr++; - nbytes -= 2; - } - - /* mop up an odd byte, if necessary */ - if (nbytes == 1) - { - /* make sure top half is zero */ - oddbyte = 0; - - /* one byte only */ - *((u_char *)&oddbyte) = *(u_char *)ptr; - sum += oddbyte; - } - /* Add back carry outs from top 16 bits to low 16 bits. */ - sum = (sum >> 16) + (sum & 0xffff); - - /* add carry */ - sum += (sum >> 16); - - return sum; -} - -unsigned short -InetChecksum(unsigned short *ptr,int nbytes) -{ - unsigned long sum; - - sum = in_cksum(ptr, nbytes); - return (unsigned short)~sum; -} - -void TCPCheckSum(int af, struct tcphdr *t, int tcplen, v6addr_t sadd6, v6addr_t dadd6) -{ - unsigned long sum = 0; - unsigned short *ptr; - - /* TCP header checksum */ - sum = in_cksum((unsigned short *)t, tcplen); - - if (af == AF_INET) - { - /* Pseudo header */ - ptr = (unsigned short *)sadd6; - sum += *ptr++; - sum += *ptr++; - ptr = (unsigned short *)dadd6; - sum += *ptr++; - sum += *ptr++; - } - else if (af == AF_INET6) - { - /* Pseudo header */ - ptr = (unsigned short *)sadd6; - sum += *ptr++; - sum += *ptr++; - sum += *ptr++; - sum += *ptr++; - sum += *ptr++; - sum += *ptr++; - sum += *ptr++; - sum += *ptr++; - ptr = (unsigned short *)dadd6; - sum += *ptr++; - sum += *ptr++; - sum += *ptr++; - sum += *ptr++; - sum += *ptr++; - sum += *ptr++; - sum += *ptr++; - sum += *ptr++; - } - - sum += htons(tcplen); - sum += htons(IPPROTO_TCP); - - while (sum >> 16) - sum = (sum >> 16) + (sum & 0xFFFF); - - t->th_sum = ~sum; - -} - -kern_return_t do_mDNSSendKeepalive(__unused mach_port_t port, v6addr_t sadd6, v6addr_t dadd6, uint16_t lport, uint16_t rport, unsigned seq, unsigned ack, uint16_t win, audit_token_t token) -{ - struct packet4 { - struct ip ip; - struct tcphdr tcp; - } packet4; - struct packet6 { - struct tcphdr tcp; - } packet6; - int sock, on; - struct tcphdr *t; - int af; - struct sockaddr_storage ss_to; - struct sockaddr_in *sin_to = (struct sockaddr_in *)&ss_to; - struct sockaddr_in6 *sin6_to = (struct sockaddr_in6 *)&ss_to; - void *packet; - ssize_t packetlen; - char ctlbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; - struct msghdr msghdr; - struct iovec iov; - ssize_t len; - - if (!authorized(&token)) - { - helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: Not authorized"); - return kmDNSHelperNotAuthorized; - } - - helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: called"); - - // all the incoming arguments are in network order - if ((*(unsigned *)(sadd6 +4) == 0) && (*(unsigned *)(sadd6 + 8) == 0) && (*(unsigned *)(sadd6 + 12) == 0)) - { - af = AF_INET; - memset(&packet4, 0, sizeof (packet4)); - - /* Fill in all the IP header information - should be in host order*/ - packet4.ip.ip_v = 4; /* 4-bit Version */ - packet4.ip.ip_hl = 5; /* 4-bit Header Length */ - packet4.ip.ip_tos = 0; /* 8-bit Type of service */ - packet4.ip.ip_len = 40; /* 16-bit Total length */ - packet4.ip.ip_id = 9864; /* 16-bit ID field */ - packet4.ip.ip_off = 0; /* 13-bit Fragment offset */ - packet4.ip.ip_ttl = 63; /* 8-bit Time To Live */ - packet4.ip.ip_p = IPPROTO_TCP; /* 8-bit Protocol */ - packet4.ip.ip_sum = 0; /* 16-bit Header checksum (below) */ - memcpy(&packet4.ip.ip_src.s_addr, sadd6, 4); - memcpy(&packet4.ip.ip_dst.s_addr, dadd6, 4); - - /* IP header checksum */ - packet4.ip.ip_sum = InetChecksum((unsigned short *)&packet4.ip, 20); - t = &packet4.tcp; - packet = &packet4; - packetlen = 40; // sum of IPv4 header len(20) and TCP header len(20) - } - else - { - af = AF_INET6; - memset(&packet6, 0, sizeof (packet6)); - t = &packet6.tcp; - packet = &packet6; - // We don't send IPv6 header, hence just the TCP header len (20) - packetlen = 20; - } + kmDNSNoTunnel, + kmDNSIPv6IPv4Tunnel, + kmDNSIPv6IPv6Tunnel +} mDNSTunnelType; - /* Fill in all the TCP header information */ - t->th_sport = lport; /* 16-bit Source port number */ - t->th_dport = rport; /* 16-bit Destination port */ - t->th_seq = seq; /* 32-bit Sequence Number */ - t->th_ack = ack; /* 32-bit Acknowledgement Number */ - t->th_off = 5; /* Data offset */ - t->th_flags = TH_ACK; - t->th_win = win; - t->th_sum = 0; /* 16-bit checksum (below) */ - t->th_urp = 0; /* 16-bit urgent offset */ +static const uint8_t kWholeV6Mask = 128; - TCPCheckSum(af, t, 20, sadd6, dadd6); +static unsigned int routeSeq = 1; - /* Open up a RAW socket */ - if ((sock = socket(af, SOCK_RAW, IPPROTO_TCP)) < 0) +static int setupTunnelRoute(const v6addr_t local, const v6addr_t remote) +{ + struct + { + struct rt_msghdr hdr; + struct sockaddr_in6 dst; + struct sockaddr_in6 gtwy; + } msg; + int err = 0; + int s = -1; + + if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET))) { - helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: socket %s", strerror(errno)); - return errno; + os_log(log_handle,"socket(PF_ROUTE, ...) failed: %s", strerror(errno)); + + err = kHelperErr_RoutingSocketCreationFailed; + goto fin; } - - - if (af == AF_INET) + + memset(&msg, 0, sizeof(msg)); + msg.hdr.rtm_msglen = sizeof(msg); + msg.hdr.rtm_type = RTM_ADD; + /* The following flags are set by `route add -inet6 -host ...` */ + msg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_HOST | RTF_STATIC; + msg.hdr.rtm_version = RTM_VERSION; + msg.hdr.rtm_seq = routeSeq++; + msg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY; + msg.hdr.rtm_inits = RTV_MTU; + msg.hdr.rtm_rmx.rmx_mtu = 1280; + + msg.dst.sin6_len = sizeof(msg.dst); + msg.dst.sin6_family = AF_INET6; + memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr)); + + msg.gtwy.sin6_len = sizeof(msg.gtwy); + msg.gtwy.sin6_family = AF_INET6; + memcpy(&msg.gtwy.sin6_addr, local, sizeof(msg.gtwy.sin6_addr)); + + /* send message, ignore error when route already exists */ + if (0 > write(s, &msg, msg.hdr.rtm_msglen)) { - on = 1; - if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &on, sizeof (on))) + int errno_ = errno; + + os_log_info(log_handle,"write to routing socket failed: %s", strerror(errno_)); + if (EEXIST != errno_) { - close(sock); - helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: setsockopt %s", strerror(errno)); - return errno; + err = kHelperErr_RouteAdditionFailed; + goto fin; } - - memset(sin_to, 0, sizeof(struct sockaddr_in)); - sin_to->sin_len = sizeof(struct sockaddr_in); - sin_to->sin_family = AF_INET; - memcpy(&sin_to->sin_addr, sadd6, sizeof(struct in_addr)); - sin_to->sin_port = rport; - - msghdr.msg_control = NULL; - msghdr.msg_controllen = 0; - } - else - { - struct cmsghdr *ctl; - - memset(sin6_to, 0, sizeof(struct sockaddr_in6)); - sin6_to->sin6_len = sizeof(struct sockaddr_in6); - sin6_to->sin6_family = AF_INET6; - memcpy(&sin6_to->sin6_addr, dadd6, sizeof(struct in6_addr)); - - sin6_to->sin6_port = rport; - sin6_to->sin6_flowinfo = 0; - + +fin: + if (0 <= s) + close(s); + return err; +} - msghdr.msg_control = ctlbuf; - msghdr.msg_controllen = sizeof(ctlbuf); - ctl = CMSG_FIRSTHDR(&msghdr); - ctl->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); - ctl->cmsg_level = IPPROTO_IPV6; - ctl->cmsg_type = IPV6_PKTINFO; - struct in6_pktinfo *pktinfo = (struct in6_pktinfo *) CMSG_DATA(ctl); - memcpy(&pktinfo->ipi6_addr, sadd6, sizeof(struct in6_addr)); - pktinfo->ipi6_ifindex = 0; +static int teardownTunnelRoute(const v6addr_t remote) +{ + struct + { + struct rt_msghdr hdr; + struct sockaddr_in6 dst; + } msg; + int err = 0; + int s = -1; + + if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET))) + { + os_log(log_handle, "socket(PF_ROUTE, ...) failed: %s", strerror(errno)); + err = kHelperErr_RoutingSocketCreationFailed; + goto fin; } - - msghdr.msg_name = (struct sockaddr *)&ss_to; - msghdr.msg_namelen = ss_to.ss_len; - iov.iov_base = packet; - iov.iov_len = packetlen; - msghdr.msg_iov = &iov; - msghdr.msg_iovlen = 1; - msghdr.msg_flags = 0; -again: - len = sendmsg(sock, &msghdr, 0); - if (len == -1) + memset(&msg, 0, sizeof(msg)); + + msg.hdr.rtm_msglen = sizeof(msg); + msg.hdr.rtm_type = RTM_DELETE; + msg.hdr.rtm_version = RTM_VERSION; + msg.hdr.rtm_seq = routeSeq++; + msg.hdr.rtm_addrs = RTA_DST; + + msg.dst.sin6_len = sizeof(msg.dst); + msg.dst.sin6_family = AF_INET6; + memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr)); + if (0 > write(s, &msg, msg.hdr.rtm_msglen)) { - if (errno == EINTR) - goto again; + int errno_ = errno; + + os_log_debug(log_handle,"write to routing socket failed: %s", strerror(errno_)); + + if (ESRCH != errno_) + { + err = kHelperErr_RouteDeletionFailed; + goto fin; + } } + +fin: + if (0 <= s) + close(s); + return err; +} - if (len != packetlen) +static int v4addr_to_string(v4addr_t addr, char *buf, size_t buflen) +{ + if (NULL == inet_ntop(AF_INET, addr, buf, buflen)) { - helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: sendmsg failed %s", strerror(errno)); + os_log(log_handle, "v4addr_to_string() inet_ntop failed: %s", strerror(errno)); + return kHelperErr_InvalidNetworkAddress; } else { - char source[INET6_ADDRSTRLEN], dest[INET6_ADDRSTRLEN]; - - inet_ntop(af, (void *)sadd6, source, sizeof(source)); - inet_ntop(af, (void *)dadd6, dest, sizeof(dest)); - - helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: Success Source %s:%d, Dest %s:%d, %u, %u, %u", source, ntohs(lport), dest, ntohs(rport), ntohl(seq), ntohl(ack), ntohs(win)); - + return 0; } - close(sock); - return KERN_SUCCESS; } - -kern_return_t do_mDNSRetrieveTCPInfo(__unused mach_port_t port, 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, audit_token_t token) +static int v6addr_to_string(const v6addr_t addr, char *buf, size_t buflen) { - struct tcp_info ti; - struct info_tuple itpl; - int mib[4]; - unsigned int miblen; - size_t len; - size_t sz; - - memset(&itpl, 0, sizeof(struct info_tuple)); - memset(&ti, 0, sizeof(struct tcp_info)); - - if (!authorized(&token)) - { - helplog(ASL_LEVEL_ERR, "mDNSRetrieveTCPInfo: Not authorized"); - return kmDNSHelperNotAuthorized; - } - - if (family == AF_INET) + if (NULL == inet_ntop(AF_INET6, addr, buf, buflen)) { - memcpy(&itpl.itpl_local_sin.sin_addr, laddr, sizeof(struct in_addr)); - memcpy(&itpl.itpl_remote_sin.sin_addr, raddr, sizeof(struct in_addr)); - itpl.itpl_local_sin.sin_port = lport; - itpl.itpl_remote_sin.sin_port = rport; - itpl.itpl_local_sin.sin_family = AF_INET; - itpl.itpl_remote_sin.sin_family = AF_INET; + os_log(log_handle, "v6addr_to_string inet_ntop failed: %s", strerror(errno)); + return kHelperErr_InvalidNetworkAddress; } else { - memcpy(&itpl.itpl_local_sin6.sin6_addr, laddr, sizeof(struct in6_addr)); - memcpy(&itpl.itpl_remote_sin6.sin6_addr, raddr, sizeof(struct in6_addr)); - itpl.itpl_local_sin6.sin6_port = lport; - itpl.itpl_remote_sin6.sin6_port = rport; - itpl.itpl_local_sin6.sin6_family = AF_INET6; - itpl.itpl_remote_sin6.sin6_family = AF_INET6; + return 0; } - itpl.itpl_proto = IPPROTO_TCP; - sz = sizeof(mib)/sizeof(mib[0]); - if (sysctlnametomib("net.inet.tcp.info", mib, &sz) == -1) +} + +static int ensureExistenceOfRacoonConfigDir(const char* const racoon_config_dir) +{ + struct stat s; + int ret = stat(racoon_config_dir, &s); + if (ret != 0) { - helplog(ASL_LEVEL_ERR, "do_RetrieveTCPInfo: sysctlnametomib failed %d, %s", errno, strerror(errno)); - return errno; + if (errno != ENOENT) + { + os_log(log_handle, "stat of \"%s\" failed (%d): %s", + racoon_config_dir, ret, strerror(errno)); + return -1; + } + else + { + ret = mkdir(racoon_config_dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); + if (ret != 0) + { + os_log(log_handle, "mkdir \"%s\" failed: %s", + racoon_config_dir, strerror(errno)); + return -1; + } + else + { + os_log_info(log_handle, "created directory \"%s\"", racoon_config_dir); + } + } } - miblen = (unsigned int)sz; - len = sizeof(struct tcp_info); - if (sysctl(mib, miblen, &ti, &len, &itpl, sizeof(struct info_tuple)) == -1) + else if (!(s.st_mode & S_IFDIR)) { - helplog(ASL_LEVEL_ERR, "do_RetrieveTCPInfo: sysctl failed %d, %s", errno, strerror(errno)); - return errno; + os_log(log_handle, "\"%s\" is not a directory!", + racoon_config_dir); + return -1; } - - *seq = ti.tcpi_snd_nxt - 1; - *ack = ti.tcpi_rcv_nxt; - *win = ti.tcpi_rcv_space >> ti.tcpi_rcv_wscale; - *intfid = ti.tcpi_last_outif; - return KERN_SUCCESS; + + return 0; } -static int getMACAddress(int family, v6addr_t raddr, v6addr_t gaddr, int *gfamily, ethaddr_t eth) -{ - struct - { - struct rt_msghdr m_rtm; - char m_space[512]; - } m_rtmsg; - - struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); - char *cp = m_rtmsg.m_space; - int seq = 6367, sock, rlen, i; - struct sockaddr_in *sin = NULL; - struct sockaddr_in6 *sin6 = NULL; - struct sockaddr_dl *sdl = NULL; - struct sockaddr_storage sins; - struct sockaddr_dl sdl_m; -#define NEXTADDR(w, s, len) \ - if (rtm->rtm_addrs & (w)) \ - { \ - bcopy((char *)s, cp, len); \ - cp += len; \ - } - - bzero(&sins, sizeof(struct sockaddr_storage)); - bzero(&sdl_m, sizeof(struct sockaddr_dl)); - bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); - sock = socket(PF_ROUTE, SOCK_RAW, 0); - if (sock < 0) +/* Caller owns object returned in `policy' */ +static int generateTunnelPolicy(mDNSTunnelPolicyWhich which, mDNSTunnelType type, int in, + v4addr_t src, uint16_t src_port, + v4addr_t dst, uint16_t dst_port, + const v6addr_t src6, const v6addr_t dst6, + ipsec_policy_t *policy, size_t *len) +{ + char srcs[INET_ADDRSTRLEN], dsts[INET_ADDRSTRLEN]; + char srcs6[INET6_ADDRSTRLEN], dsts6[INET6_ADDRSTRLEN]; + char buf[512]; + char *inOut = in ? "in" : "out"; + ssize_t n = 0; + int err = 0; + + *policy = NULL; + *len = 0; + + switch (which) { - helplog(ASL_LEVEL_ERR, "mDNSGetRemoteMAC: Can not open the socket - %s", strerror(errno)); - return errno; + case kmDNSTunnelPolicySetup: + if (type == kmDNSIPv6IPv4Tunnel) + { + if (0 != (err = v4addr_to_string(src, srcs, sizeof(srcs)))) + goto fin; + if (0 != (err = v4addr_to_string(dst, dsts, sizeof(dsts)))) + goto fin; + n = snprintf(buf, sizeof(buf), + "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require", + inOut, srcs, src_port, dsts, dst_port); + } + else if (type == kmDNSIPv6IPv6Tunnel) + { + if (0 != (err = v6addr_to_string(src6, srcs6, sizeof(srcs6)))) + goto fin; + if (0 != (err = v6addr_to_string(dst6, dsts6, sizeof(dsts6)))) + goto fin; + n = snprintf(buf, sizeof(buf), + "%s ipsec esp/tunnel/%s-%s/require", + inOut, srcs6, dsts6); + } + break; + case kmDNSTunnelPolicyTeardown: + n = strlcpy(buf, inOut, sizeof(buf)); + break; + case kmDNSTunnelPolicyGenerate: + n = snprintf(buf, sizeof(buf), "%s generate", inOut); + break; + default: + err = kHelperErr_IPsecPolicyCreationFailed; + goto fin; } - - rtm->rtm_addrs |= RTA_DST | RTA_GATEWAY; - rtm->rtm_type = RTM_GET; - rtm->rtm_flags = 0; - rtm->rtm_version = RTM_VERSION; - rtm->rtm_seq = ++seq; - - sdl_m.sdl_len = sizeof(sdl_m); - sdl_m.sdl_family = AF_LINK; - if (family == AF_INET) + + if (n >= (int)sizeof(buf)) { - sin = (struct sockaddr_in*)&sins; - sin->sin_family = AF_INET; - sin->sin_len = sizeof(struct sockaddr_in); - memcpy(&sin->sin_addr, raddr, sizeof(struct in_addr)); - NEXTADDR(RTA_DST, sin, sin->sin_len); + err = kHelperErr_ResultTooLarge; + goto fin; } - else if (family == AF_INET6) + + os_log_info(log_handle, "policy=\"%s\"", buf); + + if (NULL == (*policy = (ipsec_policy_t)ipsec_set_policy(buf, n))) { - sin6 = (struct sockaddr_in6 *)&sins; - sin6->sin6_len = sizeof(struct sockaddr_in6); - sin6->sin6_family = AF_INET6; - memcpy(&sin6->sin6_addr, raddr, sizeof(struct in6_addr)); - NEXTADDR(RTA_DST, sin6, sin6->sin6_len); + os_log_info(log_handle, "Could not create IPsec policy from \"%s\"", buf); + err = kHelperErr_IPsecPolicyCreationFailed; + goto fin; } - NEXTADDR(RTA_GATEWAY, &sdl_m, sdl_m.sdl_len); - rtm->rtm_msglen = rlen = cp - (char *)&m_rtmsg; + *len = ((ipsec_policy_t)(*policy))->sadb_x_policy_len * 8; + +fin: + return err; +} - if (write(sock, (char *)&m_rtmsg, rlen) < 0) +static int sendPolicy(int s, int setup, + struct sockaddr *src, uint8_t src_bits, + struct sockaddr *dst, uint8_t dst_bits, + ipsec_policy_t policy, size_t len) +{ + static unsigned int policySeq = 0; + int err = 0; + + os_log_debug(log_handle, "entry, setup=%d", setup); + + if (setup) + err = pfkey_send_spdadd(s, src, src_bits, dst, dst_bits, -1, + (char *)policy, len, policySeq++); + else + err = pfkey_send_spddelete(s, src, src_bits, dst, dst_bits, -1, + (char *)policy, len, policySeq++); + + if (0 > err) { - helplog(ASL_LEVEL_INFO, "do_mDNSGetRemoteMAC: writing to routing socket: %s", strerror(errno)); - close(sock); - return errno; + os_log(log_handle, "Could not set IPsec policy: %s", ipsec_strerror()); + err = kHelperErr_IPsecPolicySetFailed; + goto fin; } - - do + else { - rlen = read(sock, (char *)&m_rtmsg, sizeof(m_rtmsg)); + err = 0; } - while (rlen > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != getpid())); - - if (rlen < 0) - helplog(ASL_LEVEL_ERR, "do_mDNSGetRemoteMAC: Read from routing socket failed"); + + os_log_debug(log_handle, "succeeded"); + +fin: + return err; +} - if (family == AF_INET) +static int removeSA(int s, struct sockaddr *src, struct sockaddr *dst) +{ + int err = 0; + + os_log_debug(log_handle, "entry"); + + err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, src, dst); + if (0 > err) { - sin = (struct sockaddr_in *) (rtm + 1); - sdl = (struct sockaddr_dl *) (sin->sin_len + (char *) sin); + os_log(log_handle, "Could not remove IPsec SA: %s", ipsec_strerror()); + err = kHelperErr_IPsecRemoveSAFailed; + goto fin; } - else if (family == AF_INET6) + err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, dst, src); + if (0 > err) { - sin6 = (struct sockaddr_in6 *) (rtm +1); - sdl = (struct sockaddr_dl *) (sin6->sin6_len + (char *) sin6); + os_log(log_handle, "Could not remove IPsec SA: %s", ipsec_strerror()); + err = kHelperErr_IPsecRemoveSAFailed; + goto fin; } + else + err = 0; + + os_log_debug(log_handle, "succeeded"); + +fin: + return err; +} - if (!sdl) +static int doTunnelPolicy(mDNSTunnelPolicyWhich which, mDNSTunnelType type, + const v6addr_t loc_inner, uint8_t loc_bits, + v4addr_t loc_outer, uint16_t loc_port, + const v6addr_t rmt_inner, uint8_t rmt_bits, + v4addr_t rmt_outer, uint16_t rmt_port, + const v6addr_t loc_outer6, const v6addr_t rmt_outer6) +{ + struct sockaddr_in6 sin6_loc; + struct sockaddr_in6 sin6_rmt; + ipsec_policy_t policy = NULL; + size_t len = 0; + int s = -1; + int err = 0; + + os_log_debug(log_handle,"entry"); + if (0 > (s = pfkey_open())) { - helplog(ASL_LEVEL_ERR, "do_mDNSGetRemoteMAC: sdl is NULL for family %d", family); - close(sock); - return -1; + os_log(log_handle, "Could not create IPsec policy socket: %s", ipsec_strerror()); + err = kHelperErr_IPsecPolicySocketCreationFailed; + goto fin; } - - // If the address is not on the local net, we get the IP address of the gateway. - // We would have to repeat the process to get the MAC address of the gateway - *gfamily = sdl->sdl_family; - if (sdl->sdl_family == AF_INET) + + memset(&sin6_loc, 0, sizeof(sin6_loc)); + sin6_loc.sin6_len = sizeof(sin6_loc); + sin6_loc.sin6_family = AF_INET6; + sin6_loc.sin6_port = htons(0); + memcpy(&sin6_loc.sin6_addr, loc_inner, sizeof(sin6_loc.sin6_addr)); + + memset(&sin6_rmt, 0, sizeof(sin6_rmt)); + sin6_rmt.sin6_len = sizeof(sin6_rmt); + sin6_rmt.sin6_family = AF_INET6; + sin6_rmt.sin6_port = htons(0); + memcpy(&sin6_rmt.sin6_addr, rmt_inner, sizeof(sin6_rmt.sin6_addr)); + + int setup = which != kmDNSTunnelPolicyTeardown; + + if (0 != (err = generateTunnelPolicy(which, type, 1, + rmt_outer, rmt_port, + loc_outer, loc_port, + rmt_outer6, loc_outer6, + &policy, &len))) + goto fin; + + if (0 != (err = sendPolicy(s, setup, + (struct sockaddr *)&sin6_rmt, rmt_bits, + (struct sockaddr *)&sin6_loc, loc_bits, + policy, len))) + goto fin; + + if (NULL != policy) { - if (sin) - { - struct sockaddr_in *new_sin = (struct sockaddr_in *)(sin->sin_len +(char*) sin); - memcpy(gaddr, &new_sin->sin_addr, sizeof(struct in_addr)); - } - else - { - helplog(ASL_LEVEL_ERR, "do_mDNSGetRemoteMAC: sin is NULL"); - } - close(sock); - return -1; + free(policy); + policy = NULL; } - else if (sdl->sdl_family == AF_INET6) + + if (0 != (err = generateTunnelPolicy(which, type, 0, + loc_outer, loc_port, + rmt_outer, rmt_port, + loc_outer6, rmt_outer6, + &policy, &len))) + goto fin; + if (0 != (err = sendPolicy(s, setup, + (struct sockaddr *)&sin6_loc, loc_bits, + (struct sockaddr *)&sin6_rmt, rmt_bits, + policy, len))) + goto fin; + + if (which == kmDNSTunnelPolicyTeardown) { - if (sin6) + if (rmt_port) // Outer tunnel is IPv4 { - struct sockaddr_in6 *new_sin6 = (struct sockaddr_in6 *)(sin6->sin6_len +(char*) sin6); - memcpy(gaddr, &new_sin6->sin6_addr, sizeof(struct in6_addr)); + if (loc_outer && rmt_outer) + { + struct sockaddr_in sin_loc; + struct sockaddr_in sin_rmt; + memset(&sin_loc, 0, sizeof(sin_loc)); + sin_loc.sin_len = sizeof(sin_loc); + sin_loc.sin_family = AF_INET; + memcpy(&sin_loc.sin_addr, loc_outer, sizeof(sin_loc.sin_addr)); + + memset(&sin_rmt, 0, sizeof(sin_rmt)); + sin_rmt.sin_len = sizeof(sin_rmt); + sin_rmt.sin_family = AF_INET; + memcpy(&sin_rmt.sin_addr, rmt_outer, sizeof(sin_rmt.sin_addr)); + if (0 != (err = removeSA(s, (struct sockaddr *)&sin_loc, (struct sockaddr *)&sin_rmt))) + goto fin; + } } else { - helplog(ASL_LEVEL_ERR, "do_mDNSGetRemoteMAC: sin6 is NULL"); + if (loc_outer6 && rmt_outer6) + { + struct sockaddr_in6 sin6_lo; + struct sockaddr_in6 sin6_rm; + + memset(&sin6_lo, 0, sizeof(sin6_lo)); + sin6_lo.sin6_len = sizeof(sin6_lo); + sin6_lo.sin6_family = AF_INET6; + memcpy(&sin6_lo.sin6_addr, loc_outer6, sizeof(sin6_lo.sin6_addr)); + + memset(&sin6_rm, 0, sizeof(sin6_rm)); + sin6_rm.sin6_len = sizeof(sin6_rm); + sin6_rm.sin6_family = AF_INET6; + memcpy(&sin6_rm.sin6_addr, rmt_outer6, sizeof(sin6_rm.sin6_addr)); + if (0 != (err = removeSA(s, (struct sockaddr *)&sin6_lo, (struct sockaddr *)&sin6_rm))) + goto fin; + } } - close(sock); - return -1; } - - unsigned char *ptr = (unsigned char *)LLADDR(sdl); - for (i = 0; i < ETHER_ADDR_LEN; i++) - (eth)[i] = *(ptr +i); - - close(sock); - return KERN_SUCCESS; + + os_log_debug(log_handle,"succeeded"); + +fin: + if (s >= 0) + pfkey_close(s); + if (NULL != policy) + free(policy); + return err; } -kern_return_t do_mDNSGetRemoteMAC(__unused mach_port_t port, int family, v6addr_t raddr, ethaddr_t eth, audit_token_t token) -{ - int ret = 0; - v6addr_t gateway; - int gfamily; - int count = 0; +#endif /* ndef MDNS_NO_IPSEC */ - if (!authorized(&token)) +int HelperAutoTunnelSetKeys(int replacedelete, const v6addr_t loc_inner, const v6addr_t loc_outer6, uint16_t loc_port, const v6addr_t rmt_inner, + const v6addr_t rmt_outer6, uint16_t rmt_port, const char *id, int *err) +{ +#ifndef MDNS_NO_IPSEC + static const char config[] = + "%s" + "remote %s [%u] {\n" + " disconnect_on_idle idle_timeout 600 idle_direction idle_outbound;\n" + " exchange_mode aggressive;\n" + " doi ipsec_doi;\n" + " situation identity_only;\n" + " verify_identifier off;\n" + " generate_policy on;\n" + " my_identifier user_fqdn \"%s\";\n" + " shared_secret keychain \"%s\";\n" + " nonce_size 16;\n" + " lifetime time 15 min;\n" + " initial_contact on;\n" + " support_proxy on;\n" + " nat_traversal force;\n" + " proposal_check claim;\n" + " proposal {\n" + " encryption_algorithm aes;\n" + " hash_algorithm sha256;\n" + " authentication_method pre_shared_key;\n" + " dh_group 2;\n" + " lifetime time 15 min;\n" + " }\n" + " proposal {\n" + " encryption_algorithm aes;\n" + " hash_algorithm sha1;\n" + " authentication_method pre_shared_key;\n" + " dh_group 2;\n" + " lifetime time 15 min;\n" + " }\n" + "}\n\n" + "sainfo address %s any address %s any {\n" + " pfs_group 2;\n" + " lifetime time 10 min;\n" + " encryption_algorithm aes;\n" + " authentication_algorithm hmac_sha256,hmac_sha1;\n" + " compression_algorithm deflate;\n" + "}\n\n" + "sainfo address %s any address %s any {\n" + " pfs_group 2;\n" + " lifetime time 10 min;\n" + " encryption_algorithm aes;\n" + " authentication_algorithm hmac_sha256,hmac_sha1;\n" + " compression_algorithm deflate;\n" + "}\n"; + char path[PATH_MAX] = ""; + char li[INET6_ADDRSTRLEN], lo[INET_ADDRSTRLEN], lo6[INET6_ADDRSTRLEN], + ri[INET6_ADDRSTRLEN], ro[INET_ADDRSTRLEN], ro6[INET6_ADDRSTRLEN]; + FILE *fp = NULL; + int fd = -1; + char tmp_path[PATH_MAX] = ""; + v4addr_t loc_outer, rmt_outer; + + os_log_debug(log_handle,"HelperAutoTunnelSetKeys: entry"); + *err = kHelperErr_NoErr; + + char buf1[INET6_ADDRSTRLEN]; + char buf2[INET6_ADDRSTRLEN]; + char buf3[INET6_ADDRSTRLEN]; + char buf4[INET6_ADDRSTRLEN]; + + buf1[0] = 0; + buf2[0] = 0; + buf3[0] = 0; + buf4[0] = 0; + + inet_ntop(AF_INET6, loc_inner, buf1, sizeof(buf1)); + inet_ntop(AF_INET6, loc_outer6, buf2, sizeof(buf2)); + inet_ntop(AF_INET6, rmt_inner, buf3, sizeof(buf3)); + inet_ntop(AF_INET6, rmt_outer6, buf4, sizeof(buf4)); + + os_log_info(log_handle, "HelperAutoTunnelSetKeys: Parameters are local_inner is %s, local_outer is %s, remote_inner is %s, remote_outer is %s id is %s", + buf1, buf2, buf3, buf4, id); + + switch ((enum mDNSAutoTunnelSetKeysReplaceDelete)replacedelete) { - helplog(ASL_LEVEL_ERR, "mDNSGetRemoteMAC: Not authorized"); - return kmDNSHelperNotAuthorized; + case kmDNSAutoTunnelSetKeysReplace: + case kmDNSAutoTunnelSetKeysDelete: + break; + default: + *err = kHelperErr_InvalidTunnelSetKeysOperation; + goto fin; } - - do + + if (0 != (*err = v6addr_to_string(loc_inner, li, sizeof(li)))) + goto fin; + if (0 != (*err = v6addr_to_string(rmt_inner, ri, sizeof(ri)))) + goto fin; + + os_log_debug(log_handle, "loc_inner=%s rmt_inner=%s", li, ri); + + if (!rmt_port) { - ret = getMACAddress(family, raddr, gateway, &gfamily, eth); - if (ret == -1) + loc_outer[0] = loc_outer[1] = loc_outer[2] = loc_outer[3] = 0; + rmt_outer[0] = rmt_outer[1] = rmt_outer[2] = rmt_outer[3] = 0; + + if (0 != (*err = v6addr_to_string(loc_outer6, lo6, sizeof(lo6)))) + goto fin; + if (0 != (*err = v6addr_to_string(rmt_outer6, ro6, sizeof(ro6)))) + goto fin; + + os_log_debug(log_handle, "IPv6 outer tunnel: loc_outer6=%s rmt_outer6=%s", lo6, ro6); + + if ((int)sizeof(path) <= snprintf(path, sizeof(path), "%s%s.conf", GetRacoonConfigDir(), ro6)) { - memcpy(raddr, gateway, sizeof(family)); - family = gfamily; - count++; + *err = kHelperErr_ResultTooLarge; + goto fin; } } - while ((ret == -1) && (count < 5)); - return ret; -} - - -kern_return_t do_mDNSStoreSPSMACAddress(__unused mach_port_t port, int family, v6addr_t spsaddr, const char *ifname, audit_token_t token) -{ - ethaddr_t eth; - char spsip[INET6_ADDRSTRLEN]; - int ret = 0; - CFStringRef sckey = NULL; - SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:StoreSPSMACAddress"), NULL, NULL); - SCDynamicStoreRef ipstore = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetIPv6Addresses"), NULL, NULL); - CFMutableDictionaryRef dict = NULL; - CFStringRef entityname = NULL; - CFDictionaryRef ipdict = NULL; - CFArrayRef addrs = NULL; - - if (!authorized(&token)) + else { - helplog(ASL_LEVEL_ERR, "mDNSStoreSPSMAC: Not authorized"); - return kmDNSHelperNotAuthorized; + loc_outer[0] = loc_outer6[0]; + loc_outer[1] = loc_outer6[1]; + loc_outer[2] = loc_outer6[2]; + loc_outer[3] = loc_outer6[3]; + + rmt_outer[0] = rmt_outer6[0]; + rmt_outer[1] = rmt_outer6[1]; + rmt_outer[2] = rmt_outer6[2]; + rmt_outer[3] = rmt_outer6[3]; + + if (0 != (*err = v4addr_to_string(loc_outer, lo, sizeof(lo)))) + goto fin; + if (0 != (*err = v4addr_to_string(rmt_outer, ro, sizeof(ro)))) + goto fin; + + os_log_debug(log_handle, "IPv4 outer tunnel: loc_outer=%s loc_port=%u rmt_outer=%s rmt_port=%u", + lo, loc_port, ro, rmt_port); + + if ((int)sizeof(path) <= snprintf(path, sizeof(path), "%s%s.%u.conf", GetRacoonConfigDir(), ro, rmt_port)) + { + *err = kHelperErr_ResultTooLarge; + goto fin; + } } - - if ((store == NULL) || (ipstore == NULL)) + + if (kmDNSAutoTunnelSetKeysReplace == replacedelete) { - helplog(ASL_LEVEL_ERR, "Unable to access SC Dynamic Store"); - return KERN_FAILURE; + if (0 > ensureExistenceOfRacoonConfigDir(GetRacoonConfigDir())) + { + *err = kHelperErr_RacoonConfigCreationFailed; + goto fin; + } + if ((int)sizeof(tmp_path) <= + snprintf(tmp_path, sizeof(tmp_path), "%s.XXXXXX", path)) + { + *err = kHelperErr_ResultTooLarge; + goto fin; + } + if (0 > (fd = mkstemp(tmp_path))) + { + os_log(log_handle, "mkstemp \"%s\" failed: %s", tmp_path, strerror(errno)); + *err = kHelperErr_RacoonConfigCreationFailed; + goto fin; + } + if (NULL == (fp = fdopen(fd, "w"))) + { + os_log(log_handle, "fdopen: %s", strerror(errno)); + *err = kHelperErr_RacoonConfigCreationFailed; + goto fin; + } + + fd = -1; + fprintf(fp, config, configHeader, (!rmt_port ? ro6 : ro), rmt_port, id, id, ri, li, li, ri); + fclose(fp); + fp = NULL; + + if (0 > rename(tmp_path, path)) + { + os_log(log_handle, "rename \"%s\" \"%s\" failed: %s", tmp_path, path, strerror(errno)); + *err = kHelperErr_RacoonConfigCreationFailed; + goto fin; + } } - - // Get the MAC address of the Sleep Proxy Server - memset(eth, 0, sizeof(eth)); - ret = do_mDNSGetRemoteMAC(port, family, spsaddr, eth, token); - if (ret != KERN_SUCCESS) + else { - helplog(ASL_LEVEL_ERR, "mDNSStoreSPSMAC: Failed to determine the MAC address"); - goto fin; + if (0 != unlink(path)) + os_log_debug(log_handle, "unlink \"%s\" failed: %s", path, strerror(errno)); } - - // Create/Update the dynamic store entry for the specified interface - sckey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname, "/BonjourSleepProxyAddress"); - dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (!dict) - { - helplog(ASL_LEVEL_ERR, "SPSCreateDict: Could not create CFDictionary dict"); - ret = KERN_FAILURE; + + if (0 != (*err = doTunnelPolicy(kmDNSTunnelPolicyTeardown, kmDNSNoTunnel, + loc_inner, kWholeV6Mask, loc_outer, loc_port, + rmt_inner, kWholeV6Mask, rmt_outer, rmt_port, loc_outer6, rmt_outer6))) goto fin; - } - - CFStringRef macaddr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%02x:%02x:%02x:%02x:%02x:%02x"), eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]); - CFDictionarySetValue(dict, CFSTR("MACAddress"), macaddr); - if (NULL != macaddr) CFRelease(macaddr); - - if( NULL == inet_ntop(family, (void *)spsaddr, spsip, sizeof(spsip))) - { - helplog(ASL_LEVEL_ERR, "inet_ntop failed: %s", strerror(errno)); - ret = kmDNSHelperInvalidNetworkAddress; - goto fin; - } + if (kmDNSAutoTunnelSetKeysReplace == replacedelete && + 0 != (*err = doTunnelPolicy(kmDNSTunnelPolicySetup, (!rmt_port ? kmDNSIPv6IPv6Tunnel : kmDNSIPv6IPv4Tunnel), + loc_inner, kWholeV6Mask, loc_outer, loc_port, + rmt_inner, kWholeV6Mask, rmt_outer, rmt_port, loc_outer6, rmt_outer6))) + goto fin; + + if (0 != (*err = teardownTunnelRoute(rmt_inner))) + goto fin; + + if (kmDNSAutoTunnelSetKeysReplace == replacedelete && + 0 != (*err = setupTunnelRoute(loc_inner, rmt_inner))) + goto fin; + + if (kmDNSAutoTunnelSetKeysReplace == replacedelete && + 0 != (*err = kickRacoon())) + goto fin; + + os_log_debug(log_handle, "succeeded"); + +fin: + if (NULL != fp) + fclose(fp); + if (0 <= fd) + close(fd); + unlink(tmp_path); +#else + (void)replacedelete; (void)loc_inner; (void)loc_outer6; (void)loc_port; (void)rmt_inner; + (void)rmt_outer6; (void)rmt_port; (void)id; + + *err = kHelperErr_IPsecDisabled; +#endif /* MDNS_NO_IPSEC */ + update_idle_timer(); + return KERN_SUCCESS; +} - CFStringRef ipaddr = CFStringCreateWithCString(NULL, spsip, kCFStringEncodingUTF8); - CFDictionarySetValue(dict, CFSTR("IPAddress"), ipaddr); - if (NULL != ipaddr) CFRelease(ipaddr); - // Get the current IPv6 addresses on this interface and store them so NAs can be sent on wakeup - if ((entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/IPv6"), ifname)) != NULL) - { - if ((ipdict = SCDynamicStoreCopyValue(ipstore, entityname)) != NULL) - { - if((addrs = CFDictionaryGetValue(ipdict, CFSTR("Addresses"))) != NULL) - { - addrs = CFRetain(addrs); - CFDictionarySetValue(dict, CFSTR("RegisteredAddresses"), addrs); - } - } - } - SCDynamicStoreSetValue(store, sckey, dict); -fin: - if (store) CFRelease(store); - if (ipstore) CFRelease(ipstore); - if (sckey) CFRelease(sckey); - if (dict) CFRelease(dict); - if (ipdict) CFRelease(ipdict); - if (entityname) CFRelease(entityname); - if (addrs) CFRelease(addrs); - update_idle_timer(); - return ret; -} diff --git a/mDNSResponder/mDNSMacOSX/helper.h b/mDNSResponder/mDNSMacOSX/helper.h index 04332eff..eedf7380 100644 --- a/mDNSResponder/mDNSMacOSX/helper.h +++ b/mDNSResponder/mDNSMacOSX/helper.h @@ -18,7 +18,71 @@ #ifndef H_HELPER_H #define H_HELPER_H -#define kmDNSHelperServiceName "com.apple.mDNSResponderHelper" +#include + +#define kHelperService "com.apple.mDNSResponder_Helper" + +#define kmDNSHelperProgramArgs CFSTR("com.apple.mDNSResponderHelper") +#define kPreferencesKey_mDNSHelperLog CFSTR("mDNSHelperDebugLogging") + +#define kHelperMode "HelperMode" +#define kHelperReplyStatus "HelperReplyStatusToClient" +#define kHelperErrCode "HelperErrorCodefromCall" + +#define kPrefsNameKey "PreferencesNameKey" +#define kPrefsOldName "PreferencesOldName" +#define kPrefsNewName "PreferencesNewName" + +extern int mDNSHelperLogEnabled; + +extern os_log_t log_handle; + +typedef enum +{ + bpf_request = 1, + set_name = 2, + p2p_packetfilter = 3, + user_notify = 4, + power_req = 5, + send_wakepkt = 6, + set_localaddr_cacheentry = 7, + send_keepalive = 8, + retreive_tcpinfo = 9, + keychain_getsecrets = 10, + autotunnel_setkeys = 11, + request_other, +} HelperModes; + +typedef enum +{ + kHelperReply_ACK = 0, +} HelperReplyStatusCodes; + + +typedef enum +{ + kHelperErr_NoErr = 0, + kHelperErr_DefaultErr = -1, + kHelperErr_NotConnected = -2, + kHelperErr_NoResponse = -3, + kHelperErr_UndefinedMode = -4, + kHelperErr_ApiErr = -5, + kHelperErr_InvalidTunnelSetKeysOperation = -6, + kHelperErr_InvalidNetworkAddress = -7, + kHelperErr_ResultTooLarge = -8, + kHelperErr_RacoonConfigCreationFailed = -9, + kHelperErr_IPsecPolicySocketCreationFailed = -10, + kHelperErr_IPsecPolicyCreationFailed = -11, + kHelperErr_IPsecPolicySetFailed = -12, + kHelperErr_IPsecRemoveSAFailed = -13, + kHelperErr_IPsecDisabled = -14, + kHelperErr_RoutingSocketCreationFailed = -15, + kHelperErr_RouteDeletionFailed = -16, + kHelperErr_RouteAdditionFailed = -17, + kHelperErr_RacoonStartFailed = -18, + kHelperErr_RacoonNotificationFailed = -19, +} HelperErrorCodes; + enum mDNSPreferencesSetNameKey { @@ -38,6 +102,7 @@ enum mDNSAutoTunnelSetKeysReplaceDelete kmDNSAutoTunnelSetKeysDelete }; + // helper parses the system keychain and returns the information to mDNSResponder. // It returns four attributes. Attributes are defined after how they show up in // keychain access utility (the actual attribute name to retrieve these are different). @@ -49,36 +114,40 @@ enum mDNSKeyChainAttributes kmDNSKcName // Name }; -#define ERROR(x, y) x, -enum mDNSHelperErrors -{ - mDNSHelperErrorBase = 2300, - #include "helper-error.h" - mDNSHelperErrorEnd -}; -#undef ERROR - #include "mDNSEmbeddedAPI.h" #include "helpermsg-types.h" extern const char *mDNSHelperError(int errornum); extern mStatus mDNSHelperInit(void); + + extern void mDNSRequestBPF(void); extern int mDNSPowerRequest(int key, int interval); extern int mDNSSetLocalAddressCacheEntry(int ifindex, int family, const v6addr_t ip, const ethaddr_t eth); extern void mDNSNotify(const char *title, const char *msg); // Both strings are UTF-8 text extern void mDNSPreferencesSetName(int key, domainlabel *old, domainlabel *new); extern int mDNSKeychainGetSecrets(CFArrayRef *secrets); -extern void mDNSConfigureServer(int updown, const char *const prefix, const domainname *const fqdn); extern 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 char *const prefix, const domainname *const fqdn); extern void mDNSSendWakeupPacket(unsigned ifid, char *eth_addr, char *ip_addr, int iteration); extern void mDNSPacketFilterControl(uint32_t command, char * ifname, uint32_t count, pfArray_t portArray, pfArray_t protocolArray); -extern void mDNSSendKeepalive(v6addr_t sadd, v6addr_t dadd, uint16_t lport, uint16_t rport, unsigned seq, unsigned ack, uint16_t win); +extern void mDNSSendKeepalive(const v6addr_t sadd, const v6addr_t dadd, uint16_t lport, uint16_t rport, unsigned seq, unsigned ack, uint16_t win); extern 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); -extern void mDNSGetRemoteMAC(mDNS *const m, int family, v6addr_t raddr); -extern void mDNSStoreSPSMACAddress(int family, v6addr_t spsaddr, char *ifname); + +extern void RequestBPF(void); +extern void PreferencesSetName(int key, const char* old, const char* new); +extern void PacketFilterControl(uint32_t command, const char * ifname, uint32_t count, pfArray_t portArray, pfArray_t protocolArray); +extern void UserNotify(const char *title, const char *msg); // Both strings are UTF-8 text +extern void PowerRequest(int key, int interval, int *error); +extern void SendWakeupPacket(unsigned int ifid, const char *eth_addr, const char *ip_addr, int iteration); +extern void SetLocalAddressCacheEntry(int ifindex, int family, const v6addr_t ip, const ethaddr_t eth, int *err); +extern void SendKeepalive(const v6addr_t sadd6, const v6addr_t dadd6, uint16_t lport, uint16_t rport, uint32_t seq, uint32_t ack, uint16_t win); +extern void RetrieveTCPInfo(int family, const v6addr_t laddr, uint16_t lport, const v6addr_t raddr, uint16_t rport, uint32_t *seq, uint32_t *ack, uint16_t *win, int32_t *intfid, int *err); +extern void KeychainGetSecrets(__unused unsigned int *numsecrets,__unused unsigned long *secrets, __unused unsigned int *secretsCnt, __unused int *err); +extern int HelperAutoTunnelSetKeys(int replacedelete, const v6addr_t loc_inner, const v6addr_t loc_outer6, uint16_t loc_port, const v6addr_t rmt_inner, + const v6addr_t rmt_outer6, uint16_t rmt_port, const char *id, int *err); +extern void helper_exit(void); #endif /* H_HELPER_H */ diff --git a/mDNSResponder/mDNSMacOSX/helpermsg-types.h b/mDNSResponder/mDNSMacOSX/helpermsg-types.h index 88411800..689b249e 100644 --- a/mDNSResponder/mDNSMacOSX/helpermsg-types.h +++ b/mDNSResponder/mDNSMacOSX/helpermsg-types.h @@ -24,7 +24,7 @@ typedef uint8_t ethaddr_t[ 6]; typedef uint8_t v6addr_t [16]; typedef const char *string_t; -#define PFPortArraySize 16 +#define PFPortArraySize 4 typedef uint16_t pfArray_t [PFPortArraySize]; #endif /* H_HELPERMSG_TYPES_H */ diff --git a/mDNSResponder/mDNSMacOSX/helpermsg.defs b/mDNSResponder/mDNSMacOSX/helpermsg.defs deleted file mode 100644 index 35239967..00000000 --- a/mDNSResponder/mDNSMacOSX/helpermsg.defs +++ /dev/null @@ -1,143 +0,0 @@ -/* -*- Mode: C; tab-width: 4 -*- - * - * Copyright (c) 2007-2013 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 - -import "helpermsg-types.h"; - -type v4addr_t = array [ 4] of uint8_t; -type ethaddr_t = array [ 6] of uint8_t; -type v6addr_t = array [16] of uint8_t; -type string_t = c_string[*:1024]; - -// Mig doesn't generate the output file if I use the constant PFPortArraySize below -type pfArray_t = array [16] of uint16_t; - -subsystem helper 1833193043; -serverprefix do_; -userprefix proxy_; - -simpleroutine mDNSExit( port : mach_port_t; - ServerAuditToken token : audit_token_t); - -simpleroutine mDNSRequestBPF( port : mach_port_t; - ServerAuditToken token : audit_token_t); - -routine mDNSPowerRequest( port : mach_port_t; - key : int; - interval : int; - out err : int; - ServerAuditToken token : audit_token_t); - -routine mDNSSetLocalAddressCacheEntry( - port : mach_port_t; - ifindex : int; - family : int; - ip : v6addr_t; - eth : ethaddr_t; - out err : int; - ServerAuditToken token : audit_token_t); - -simpleroutine mDNSNotify( port : mach_port_t; - title : string_t; - msg : string_t; - ServerAuditToken token : audit_token_t); - -simpleroutine mDNSPreferencesSetName( - port : mach_port_t; - key : int; - old : string_t; - new : string_t; - ServerAuditToken token : audit_token_t); - -routine mDNSKeychainGetSecrets( port : mach_port_t; - out numsecrets : unsigned; - out secrets : pointer_t; - out err : int; - ServerAuditToken token : audit_token_t); - -simpleroutine mDNSConfigureServer( - port : mach_port_t; - updown : int; - id : string_t; - ServerAuditToken token : audit_token_t); - -routine mDNSAutoTunnelSetKeys( port : mach_port_t; - replacedelete : int; - local_inner : v6addr_t; - local_outer : v6addr_t; - local_port : uint16_t; /* Port expressed as a numeric integer value */ - remote_inner : v6addr_t; - remote_outer : v6addr_t; - remote_port : uint16_t; /* Port expressed as a numeric integer value */ - id : string_t; - out err : int; - ServerAuditToken token : audit_token_t); - -simpleroutine mDNSSendWakeupPacket( - port : mach_port_t; - ifid : unsigned; - eth_addr : string_t; - ip_addr : string_t; - iteration : int; - ServerAuditToken token : audit_token_t); - -simpleroutine mDNSPacketFilterControl( - port : mach_port_t; - command : uint32_t; - ifname : string_t; - arraySize : uint32_t; - portArray : pfArray_t; - protocolArray : pfArray_t; - ServerAuditToken token : audit_token_t); - - -simpleroutine mDNSSendKeepalive( port : mach_port_t; - sadd : v6addr_t; - dadd : v6addr_t; - lport : uint16_t; - rport : uint16_t; - seq : unsigned; - ack : unsigned; - win : uint16_t; - ServerAuditToken token : audit_token_t); - -routine mDNSRetrieveTCPInfo( - port : mach_port_t; - family : int; - laddr : v6addr_t; - lport : uint16_t; - raddr : v6addr_t; - rport : uint16_t; - out seq : uint32_t; - out ack : uint32_t; - out win : uint16_t; - out intfid : int32_t; - ServerAuditToken token : audit_token_t); - -routine mDNSGetRemoteMAC( port : mach_port_t; - family : int; - raddr : v6addr_t; - out eth : ethaddr_t; - ServerAuditToken token : audit_token_t); - -simpleroutine mDNSStoreSPSMACAddress( port : mach_port_t; - family : int; - spsaddr : v6addr_t; - ifname : string_t; - ServerAuditToken token : audit_token_t); diff --git a/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c b/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c index deae0d1a..c57eddda 100644 --- a/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c +++ b/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 4 -*- * - * Copyright (c) 2002-2015 Apple Inc. All rights reserved. + * Copyright (c) 2002-2016 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. @@ -29,6 +29,7 @@ #include "uDNS.h" #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform #include "dns_sd.h" // For mDNSInterface_LocalOnly etc. +#include "dns_sd_private.h" #include "PlatformCommon.h" #include "uds_daemon.h" #include "CryptoSupport.h" @@ -60,7 +61,7 @@ #include // For n_long, required by below #include // For IPTOS_LOWDELAY etc. -#include // For IN6_IFF_NOTREADY etc. +#include // For IN6_IFF_TENTATIVE etc. #include @@ -100,6 +101,8 @@ #include #include // for ne_session_set_socket_attributes() #if !NO_D2D +#include "BLE.h" + D2DStatus D2DInitialize(CFRunLoopRef runLoop, D2DServiceCallback serviceCallback, void* userData) __attribute__((weak_import)); D2DStatus D2DRetain(D2DServiceInstance instanceHandle, D2DTransportType transportType) __attribute__((weak_import)); D2DStatus D2DStopAdvertisingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import)); @@ -111,6 +114,9 @@ void D2DStartResolvingPairOnTransport(const Byte *key, const size_t keySize, con void D2DStopResolvingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import)); D2DStatus D2DTerminate() __attribute__((weak_import)); +void xD2DAddToCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize); +void xD2DRemoveFromCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize); + #endif // ! NO_D2D #else @@ -132,7 +138,7 @@ D2DStatus D2DTerminate() __attribute__((weak_import)); #define DARK_WAKE_TIME 16 // Time we hold an idle sleep assertion for maintenance after a wake notification // cache the InterfaceID of the AWDL interface -static mDNSInterfaceID AWDLInterfaceID; +mDNSInterfaceID AWDLInterfaceID; // *************************************************************************** // Globals @@ -176,9 +182,6 @@ mDNSexport int WatchDogReportingThreshold = 250; dispatch_queue_t SSLqueue; -//To prevent blocking the main queue, all writes to DynamicStore happen on the DynamicStoreQueue -static dispatch_queue_t DynamicStoreQueue; - #if TARGET_OS_EMBEDDED #define kmDNSResponderManagedPrefsID CFSTR("/Library/Managed Preferences/mobile/com.apple.mDNSResponder.plist") #endif @@ -243,6 +246,26 @@ mDNSexport void D2D_stop_advertising_interface(NetworkInterfaceInfo *interface) } } +// If record would have been advertised to the D2D plugin layer, stop that advertisement. +mDNSexport void D2D_stop_advertising_record(AuthRecord *ar) +{ + DNSServiceFlags flags = deriveD2DFlagsFromAuthRecType(ar->ARType); + if (callExternalHelpers(ar->resrec.InterfaceID, ar->resrec.name, flags)) + { + external_stop_advertising_service(&ar->resrec, flags); + } +} + +// If record should be advertised to the D2D plugin layer, start that advertisement. +mDNSexport void D2D_start_advertising_record(AuthRecord *ar) +{ + DNSServiceFlags flags = deriveD2DFlagsFromAuthRecType(ar->ARType); + if (callExternalHelpers(ar->resrec.InterfaceID, ar->resrec.name, flags)) + { + external_start_advertising_service(&ar->resrec, flags); + } +} + // Name compression items for fake packet version number 1 static const mDNSu8 compression_packet_v1 = 0x01; @@ -304,65 +327,6 @@ mDNSlocal void DomainnameToLower(const domainname * const in, domainname * const out->c[ptr-start] = *ptr; } -mDNSlocal mStatus DNSNameCompressionParseBytes(mDNS *const m, const mDNSu8 *const lhs, const mDNSu16 lhs_len, const mDNSu8 *const rhs, const mDNSu16 rhs_len, AuthRecord *rr) -{ - if (mDNS_LoggingEnabled) - { - LogInfo("%s", __func__); - LogInfo(" Static Bytes: (%d bytes)", compression_lhs - (mDNSu8*)&compression_base_msg); - PrintHex((mDNSu8*)&compression_base_msg, compression_lhs - (mDNSu8*)&compression_base_msg); - } - - mDNSu8 *ptr = compression_lhs; // pointer to the end of our fake packet - - // Check to make sure we're not going to go past the end of the DNSMessage data - // 7 = 2 for CLASS (-1 for our version) + 4 for TTL + 2 for RDLENGTH - if (ptr + lhs_len - 7 + rhs_len >= compression_limit) return mStatus_NoMemoryErr; - - // Copy the LHS onto our fake wire packet - mDNSPlatformMemCopy(ptr, lhs, lhs_len); - ptr += lhs_len - 1; - - // Check the 'fake packet' version number, to ensure that we know how to decompress this data - if (*ptr != compression_packet_v1) return mStatus_Incompatible; - - // two bytes of CLASS - ptr = putVal16(ptr, kDNSClass_IN | kDNSClass_UniqueRRSet); - - // four bytes of TTL - ptr = putVal32(ptr, 120); - - // Copy the RHS length into the RDLENGTH of our fake wire packet - ptr = putVal16(ptr, rhs_len); - - // Copy the RHS onto our fake wire packet - mDNSPlatformMemCopy(ptr, rhs, rhs_len); - ptr += rhs_len; - - if (mDNS_LoggingEnabled) - { - LogInfo(" Our Bytes (%d bytes): ", ptr - compression_lhs); - PrintHex(compression_lhs, ptr - compression_lhs); - } - - ptr = (mDNSu8 *) GetLargeResourceRecord(m, &compression_base_msg, compression_lhs, ptr, mDNSInterface_Any, kDNSRecordTypePacketAns, &m->rec); - if (!ptr || m->rec.r.resrec.RecordType == kDNSRecordTypePacketNegative) - { LogMsg("DNSNameCompressionParseBytes: failed to get large RR"); m->rec.r.resrec.RecordType = 0; return mStatus_UnknownErr; } - else LogInfo("DNSNameCompressionParseBytes: got rr: %s", CRDisplayString(m, &m->rec.r)); - - mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_P2P, m->rec.r.resrec.rrtype, 7200, kDNSRecordTypeShared, AuthRecordP2P, FreeD2DARElemCallback, NULL); - AssignDomainName(&rr->namestorage, &m->rec.namestorage); - rr->resrec.rdlength = m->rec.r.resrec.rdlength; - rr->resrec.rdata->MaxRDLength = m->rec.r.resrec.rdlength; - mDNSPlatformMemCopy(rr->resrec.rdata->u.data, m->rec.r.resrec.rdata->u.data, m->rec.r.resrec.rdlength); - rr->resrec.namehash = DomainNameHashValue(rr->resrec.name); - SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us - - m->rec.r.resrec.RecordType = 0; // Mark m->rec as no longer in use - - return mStatus_NoError; -} - mDNSlocal mDNSu8 * DNSNameCompressionBuildLHS(const domainname* typeDomain, DNS_TypeValues qtype) { mDNSu8 *ptr = putDomainNameAsLabels(&compression_base_msg, compression_lhs, compression_limit, typeDomain); @@ -459,8 +423,8 @@ mDNSlocal void xD2DClearCache(const domainname *regType, DNS_TypeValues qtype) { if ((ptr->ar.resrec.rrtype == qtype) && SameDomainName(&ptr->ar.namestorage, regType)) { - mDNS_Deregister(&mDNSStorage, &ptr->ar); LogInfo("xD2DClearCache: Clearing cache record and deregistering %s", ARDisplayString(&mDNSStorage, &ptr->ar)); + mDNS_Deregister(&mDNSStorage, &ptr->ar); } } } @@ -498,11 +462,12 @@ mDNSlocal void D2DBrowseListRetain(const domainname *const name, mDNSu16 type) LogInfo("D2DBrowseListRetain: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount); } -mDNSlocal void D2DBrowseListRelease(const domainname *const name, mDNSu16 type) +// Returns true if found in list, false otherwise +mDNSlocal bool D2DBrowseListRelease(const domainname *const name, mDNSu16 type) { D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type); - if (!*ptr) { LogMsg("D2DBrowseListRelease: Didn't find %##s %s in list", name->c, DNSTypeName(type)); return; } + if (!*ptr) { LogMsg("D2DBrowseListRelease: Didn't find %##s %s in list", name->c, DNSTypeName(type)); return false; } (*ptr)->refCount -= 1; @@ -514,35 +479,125 @@ mDNSlocal void D2DBrowseListRelease(const domainname *const name, mDNSu16 type) *ptr = (*ptr)->next; mDNSPlatformMemFree(tmp); } + return true; } -mDNSlocal mStatus xD2DParse(mDNS *const m, const mDNSu8 * const lhs, const mDNSu16 lhs_len, const mDNSu8 * const rhs, const mDNSu16 rhs_len, AuthRecord *rr) +mDNSlocal mStatus xD2DParse(mDNS *const m, const mDNSu8 * const lhs, const mDNSu16 lhs_len, const mDNSu8 * const rhs, const mDNSu16 rhs_len, D2DRecordListElem **D2DListp) { - if (*(lhs + (lhs_len - 1)) == compression_packet_v1) - return DNSNameCompressionParseBytes(m, lhs, lhs_len, rhs, rhs_len, rr); - else + // Sanity check that key array (lhs) has one domain name, followed by the record type and single byte D2D + // plugin protocol version number. + // Note, we don't have a DNSMessage pointer at this point, so just pass in the lhs value as the lower bound + // of the input bytes we are processing. skipDomainName() does not try to follow name compression pointers, + // so it is safe to pass it the key byte array since it will stop parsing the DNS name and return a pointer + // to the byte after the first name compression pointer it encounters. + const mDNSu8 *keyp = skipDomainName((const DNSMessage *const) lhs, lhs, lhs + lhs_len); + + // There should be 3 bytes remaining in a valid key, + // two for the DNS record type, and one for the D2D protocol version number. + if (keyp == NULL || (keyp + 3 != (lhs + lhs_len))) + { + LogInfo("xD2DParse: Could not parse DNS name in key"); return mStatus_Incompatible; + } + keyp += 2; // point to D2D compression packet format version byte + if (*keyp != compression_packet_v1) + { + LogInfo("xD2DParse: Invalid D2D packet version: %d", *keyp); + return mStatus_Incompatible; + } + + if (mDNS_LoggingEnabled) + { + LogInfo("%s", __func__); + LogInfo(" Static Bytes: (%d bytes)", compression_lhs - (mDNSu8*)&compression_base_msg); + PrintHex((mDNSu8*)&compression_base_msg, compression_lhs - (mDNSu8*)&compression_base_msg); + } + + mDNSu8 *ptr = compression_lhs; // pointer to the end of our fake packet + + // Check to make sure we're not going to go past the end of the DNSMessage data + // 7 = 2 for CLASS (-1 for our version) + 4 for TTL + 2 for RDLENGTH + if (ptr + lhs_len - 7 + rhs_len >= compression_limit) return mStatus_NoMemoryErr; + + // Copy the LHS onto our fake wire packet + mDNSPlatformMemCopy(ptr, lhs, lhs_len); + ptr += lhs_len - 1; + + // Check the 'fake packet' version number, to ensure that we know how to decompress this data + if (*ptr != compression_packet_v1) return mStatus_Incompatible; + + // two bytes of CLASS + ptr = putVal16(ptr, kDNSClass_IN | kDNSClass_UniqueRRSet); + + // four bytes of TTL + ptr = putVal32(ptr, 120); + + // Copy the RHS length into the RDLENGTH of our fake wire packet + ptr = putVal16(ptr, rhs_len); + + // Copy the RHS onto our fake wire packet + mDNSPlatformMemCopy(ptr, rhs, rhs_len); + ptr += rhs_len; + + if (mDNS_LoggingEnabled) + { + LogInfo(" Our Bytes (%d bytes): ", ptr - compression_lhs); + PrintHex(compression_lhs, ptr - compression_lhs); + } + + ptr = (mDNSu8 *) GetLargeResourceRecord(m, &compression_base_msg, compression_lhs, ptr, mDNSInterface_Any, kDNSRecordTypePacketAns, &m->rec); + if (!ptr || m->rec.r.resrec.RecordType == kDNSRecordTypePacketNegative) + { + LogMsg("xD2DParse: failed to get large RR"); + m->rec.r.resrec.RecordType = 0; + return mStatus_UnknownErr; + } + else + { + LogInfo("xD2DParse: got rr: %s", CRDisplayString(m, &m->rec.r)); + } + + *D2DListp = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (m->rec.r.resrec.rdlength <= sizeof(RDataBody) ? 0 : m->rec.r.resrec.rdlength - sizeof(RDataBody))); + if (!*D2DListp) return mStatus_NoMemoryErr; + + AuthRecord *rr = &(*D2DListp)->ar; + mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_P2P, m->rec.r.resrec.rrtype, 7200, kDNSRecordTypeShared, AuthRecordP2P, FreeD2DARElemCallback, NULL); + AssignDomainName(&rr->namestorage, &m->rec.namestorage); + rr->resrec.rdlength = m->rec.r.resrec.rdlength; + rr->resrec.rdata->MaxRDLength = m->rec.r.resrec.rdlength; + mDNSPlatformMemCopy(rr->resrec.rdata->u.data, m->rec.r.resrec.rdata->u.data, m->rec.r.resrec.rdlength); + rr->resrec.namehash = DomainNameHashValue(rr->resrec.name); + SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us + + m->rec.r.resrec.RecordType = 0; // Mark m->rec as no longer in use + + return mStatus_NoError; } -mDNSlocal void xD2DAddToCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize) +mDNSexport void xD2DAddToCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize) { if (result == kD2DSuccess) { if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DAddToCache: NULL Byte * passed in or length == 0"); return; } mStatus err; - D2DRecordListElem *ptr = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData))); + D2DRecordListElem *ptr = NULL; - if (ptr == NULL) { LogMsg("xD2DAddToCache: memory allocation failure"); return; } - - err = xD2DParse(m, (const mDNSu8 * const)key, (const mDNSu16)keySize, (const mDNSu8 * const)value, (const mDNSu16)valueSize, &ptr->ar); + err = xD2DParse(m, (const mDNSu8 * const)key, (const mDNSu16)keySize, (const mDNSu8 * const)value, (const mDNSu16)valueSize, &ptr); if (err) { LogMsg("xD2DAddToCache: xD2DParse returned error: %d", err); PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize); - mDNSPlatformMemFree(ptr); + if (ptr) + mDNSPlatformMemFree(ptr); return; } + + // If the record was created based on a BLE beacon, update the interface index to indicate + // this and thus match BLE specific queries. + if (transportType == D2DBLETransport) + ptr->ar.resrec.InterfaceID = mDNSInterface_BLE; + err = mDNS_Register(m, &ptr->ar); if (err) { @@ -564,17 +619,17 @@ mDNSlocal void xD2DAddToCache(mDNS *const m, D2DStatus result, D2DServiceInstanc mDNSlocal D2DRecordListElem * xD2DFindInList(mDNS *const m, const Byte *const key, const size_t keySize, const Byte *const value, const size_t valueSize) { D2DRecordListElem *ptr = D2DRecords; - D2DRecordListElem *arptr; + D2DRecordListElem *arptr = NULL; if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL; } - arptr = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData))); - if (arptr == NULL) { LogMsg("xD2DFindInList: memory allocation failure"); return NULL; } - - if (xD2DParse(m, (const mDNSu8 *const)key, (const mDNSu16)keySize, (const mDNSu8 *const)value, (const mDNSu16)valueSize, &arptr->ar) != mStatus_NoError) + mStatus err = xD2DParse(m, (const mDNSu8 *const)key, (const mDNSu16)keySize, (const mDNSu8 *const)value, (const mDNSu16)valueSize, &arptr); + if (err) { - LogMsg("xD2DFindInList: xD2DParse failed for key: %p (%u) value: %p (%u)", key, keySize, value, valueSize); - mDNSPlatformMemFree(arptr); + LogMsg("xD2DFindInList: xD2DParse returned error: %d", err); + PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize); + if (arptr) + mDNSPlatformMemFree(arptr); return NULL; } @@ -589,7 +644,7 @@ mDNSlocal D2DRecordListElem * xD2DFindInList(mDNS *const m, const Byte *const ke return ptr; } -mDNSlocal void xD2DRemoveFromCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize) +mDNSexport void xD2DRemoveFromCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize) { (void)transportType; // We don't care about this, yet. (void)instanceHandle; // We don't care about this, yet. @@ -777,23 +832,45 @@ mDNSlocal D2DTransportType xD2DInterfaceToTransportType(mDNSInterfaceID Interfac return D2DTransportMax; } -mDNSexport void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags) +// Similar to callExternalHelpers(), but without the checks for the BLE specific interface or flags. +// It's assumed that the domain was already verified to be .local once we are at this level. +mDNSlocal mDNSBool callInternalHelpers(mDNSInterfaceID InterfaceID, DNSServiceFlags flags) { - domainname lower; + if ( ((InterfaceID == mDNSInterface_Any) && (flags & (kDNSServiceFlagsIncludeP2P | kDNSServiceFlagsIncludeAWDL))) + || mDNSPlatformInterfaceIsD2D(InterfaceID)) + return mDNStrue; + else + return mDNSfalse; +} - if (qtype == kDNSServiceType_A || qtype == kDNSServiceType_AAAA) +mDNSexport void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags, DNSQuestion * q) +{ + // BLE support currently not handled by a D2D plugin + if (applyToBLE(InterfaceID, flags)) { - LogInfo("external_start_browsing_for_service: ignoring address record"); - return; + domainname lower; + + DomainnameToLower(typeDomain, &lower); + // pass in the key and keySize + mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype); + start_BLE_browse(q, &lower, qtype, flags, compression_lhs, end - compression_lhs); } + if (callInternalHelpers(InterfaceID, flags)) + internal_start_browsing_for_service(InterfaceID, typeDomain, qtype, flags); +} + +mDNSexport void internal_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags) +{ + domainname lower; + DomainnameToLower(typeDomain, &lower); if (!D2DBrowseListRefCount(&lower, qtype)) { D2DTransportType transportType, excludedTransport; - LogInfo("external_start_browsing_for_service: Starting browse for: %##s %s", lower.c, DNSTypeName(qtype)); + LogInfo("%s: Starting browse for: %##s %s", __func__, lower.c, DNSTypeName(qtype)); mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype); PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0); @@ -817,22 +894,34 @@ mDNSexport void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, mDNSexport void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags) { - domainname lower; - - if (qtype == kDNSServiceType_A || qtype == kDNSServiceType_AAAA) + // BLE support currently not handled by a D2D plugin + if (applyToBLE(InterfaceID, flags)) { - LogInfo("external_stop_browsing_for_service: ignoring address record"); - return; + domainname lower; + + // If this is the last instance of this browse, clear any cached records recieved for it. + // We are not guaranteed to get a D2DServiceLost event for all key, value pairs cached over BLE. + DomainnameToLower(typeDomain, &lower); + if (stop_BLE_browse(&lower, qtype, flags)) + xD2DClearCache(&lower, qtype); } + if (callInternalHelpers(InterfaceID, flags)) + internal_stop_browsing_for_service(InterfaceID, typeDomain, qtype, flags); +} + +mDNSexport void internal_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags) +{ + domainname lower; + DomainnameToLower(typeDomain, &lower); - D2DBrowseListRelease(&lower, qtype); - if (!D2DBrowseListRefCount(&lower, qtype)) + // If found in list and this is the last reference to this browse, remove the key from the D2D plugins. + if (D2DBrowseListRelease(&lower, qtype) && !D2DBrowseListRefCount(&lower, qtype)) { D2DTransportType transportType, excludedTransport; - LogInfo("external_stop_browsing_for_service: Stopping browse for: %##s %s", lower.c, DNSTypeName(qtype)); + LogInfo("%s: Stopping browse for: %##s %s", __func__, lower.c, DNSTypeName(qtype)); mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype); PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0); @@ -859,6 +948,16 @@ mDNSexport void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID, } mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) +{ + // Note, start_BLE_advertise() is currently called directly from external_start_advertising_helper() since + // it needs to pass the ServiceRecordSet so that we can promote the record advertisements to AWDL + // when we see the corresponding browse indication over BLE. + + if (callInternalHelpers(resourceRecord->InterfaceID, flags)) + internal_start_advertising_service(resourceRecord, flags); +} + +mDNSexport void internal_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { domainname lower; mDNSu8 *rhs = NULL; @@ -866,7 +965,8 @@ mDNSexport void external_start_advertising_service(const ResourceRecord *const r D2DTransportType transportType, excludedTransport; DomainnameToLower(resourceRecord->name, &lower); - LogInfo("external_start_advertising_service: %s", RRDisplayString(&mDNSStorage, resourceRecord)); + LogInfo("%s: %s", __func__, RRDisplayString(&mDNSStorage, resourceRecord)); + // For SRV records, update packet filter if p2p interface already exists, otherwise, // if will be updated when we get the KEV_DL_IF_ATTACHED event for the interface. if (resourceRecord->rrtype == kDNSType_SRV) @@ -893,6 +993,21 @@ mDNSexport void external_start_advertising_service(const ResourceRecord *const r } mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) +{ + // BLE support currently not handled by a D2D plugin + if (applyToBLE(resourceRecord->InterfaceID, flags)) + { + domainname lower; + + DomainnameToLower(resourceRecord->name, &lower); + stop_BLE_advertise(&lower, resourceRecord->rrtype, flags); + } + + if (callInternalHelpers(resourceRecord->InterfaceID, flags)) + internal_stop_advertising_service(resourceRecord, flags); +} + +mDNSexport void internal_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { domainname lower; mDNSu8 *rhs = NULL; @@ -900,8 +1015,9 @@ mDNSexport void external_stop_advertising_service(const ResourceRecord *const re D2DTransportType transportType, excludedTransport; DomainnameToLower(resourceRecord->name, &lower); - LogInfo("external_stop_advertising_service: %s", RRDisplayString(&mDNSStorage, resourceRecord)); + LogInfo("%s: %s", __func__, RRDisplayString(&mDNSStorage, resourceRecord)); + // For SRV records, update packet filter if p2p interface already exists, otherwise, // For SRV records, update packet filter to to remove this port from list if (resourceRecord->rrtype == kDNSType_SRV) mDNSUpdatePacketFilter(resourceRecord); @@ -969,8 +1085,8 @@ mDNSexport void external_start_resolving_service(mDNSInterfaceID InterfaceID, co if (AWDL_used && AWDLInterfaceID) { LogInfo("external_start_resolving_service: browse for TXT and SRV over AWDL"); - external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_TXT, 0); - external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, 0); + external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_TXT, 0, 0); + external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, 0, 0); } } @@ -1022,7 +1138,12 @@ mDNSexport void external_stop_resolving_service(mDNSInterfaceID InterfaceID, con #elif APPLE_OSX_mDNSResponder -mDNSexport void external_start_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags) { (void)m; (void)type; (void)qtype; (void)flags;} +mDNSexport void internal_start_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags) { (void)m; (void)type; (void)qtype; (void)flags } +mDNSexport void internal_stop_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags) { (void)m; (void)type; (void)qtype; (void)flags;} +mDNSexport void internal_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;} +mDNSexport void internal_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;} + +mDNSexport void external_start_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags) { (void)m; (void)type; (void)qtype; (void)flags; (void)q } mDNSexport void external_stop_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags) { (void)m; (void)type; (void)qtype; (void)flags;} mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;} mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;} @@ -1046,14 +1167,12 @@ mDNSexport void external_stop_resolving_service(const domainname *const fqdn, DN // to run up the user's bill sending multicast traffic over a link where there's only a single device at the // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway. -// We also don't want to use multicast on *any* physical interface on very constrained devices. -#if 0 -#define MulticastInterface(i) ((i)->ifa_flags & IFF_LOOPBACK) -#elif TARGET_OS_WATCH -#define MulticastInterface(i) ((i)->m->NumAllInterfaceRecords + (i)->m->NumAllInterfaceQuestions > 0 && ((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT)) +#if BONJOUR_ON_DEMAND +#define MulticastInterface(i) ((i)->m->BonjourEnabled && ((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT)) #else #define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT)) #endif +#define SPSInterface(i) ((i)->ifinfo.McastTxRx && !((i)->ifa_flags & IFF_LOOPBACK) && !(i)->D2DInterface) mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text { @@ -1065,7 +1184,8 @@ mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both for (i = mDNSStorage.p->InterfaceList; i; i = i->next) if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && i->ifinfo.ip.ip.v4.b[0] == 17) break; - if (!i) return; // If not at Apple, don't show the alert + if (!i) + return; // If not at Apple, don't show the alert } #endif @@ -1075,12 +1195,20 @@ mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both // If we display our alert early in the boot process, then it vanishes once the desktop appears. // To avoid this, we don't try to display alerts in the first three minutes after boot. if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) - { LogMsg("Suppressing notification early in boot: %d", mDNSPlatformRawTime()); return; } + { + LogMsg("Suppressing notification early in boot: %d", mDNSPlatformRawTime()); + return; + } #ifndef NO_CFUSERNOTIFICATION static int notifyCount = 0; // To guard against excessive display of warning notifications - if (notifyCount < 5) { notifyCount++; mDNSNotify(title, msg); } + if (notifyCount < 5) + { + notifyCount++; + mDNSNotify(title, msg); + } #endif /* NO_CFUSERNOTIFICATION */ + } // Write a syslog message and display an alert, then if ForceAlerts is set, generate a stack trace @@ -1249,10 +1377,11 @@ mDNSexport void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropert subkeyCopy[len] = 0; } - dispatch_async(DynamicStoreQueue, ^{ + dispatch_async(dispatch_get_main_queue(), ^{ CFWriteStreamRef stream = NULL; CFDataRef bytes = NULL; CFIndex ret; + KQueueLock(&mDNSStorage); if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL, NULL))) { @@ -1274,7 +1403,6 @@ mDNSexport void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropert CFWriteStreamClose(stream); CFRelease(stream); stream = NULL; - LogInfo("mDNSDynamicStoreSetConfig: key %d subkey %s", key, subkeyCopy); DynamicStoreWrite(key, subkeyCopy ? subkeyCopy : "", (uintptr_t)CFDataGetBytePtr(bytes), CFDataGetLength(bytes)); END: @@ -1288,6 +1416,8 @@ mDNSexport void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropert CFRelease(bytes); if (subkeyCopy) mDNSPlatformMemFree(subkeyCopy); + + KQueueUnlock(&mDNSStorage, "mDNSDynamicStoreSetConfig"); }); } @@ -1303,50 +1433,6 @@ mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const return(NULL); } -#if TARGET_OS_EMBEDDED -mDNSlocal SCPreferencesRef mDNSManagedPrefsGet(void) -{ - SCPreferencesRef smDNSManagedPrefs = NULL; - smDNSManagedPrefs = SCPreferencesCreate(kCFAllocatorDefault, CFSTR("mDNSManagedPrefs"), kmDNSResponderManagedPrefsID); - - return (smDNSManagedPrefs); -} - -mDNSlocal mDNSBool GetmDNSManagedPrefKeyVal(SCPreferencesRef prefs, CFStringRef key) -{ - mDNSBool val = mDNSfalse; - CFBooleanRef val_cf = NULL; - - if (prefs != NULL) - { - val_cf = SCPreferencesGetValue(prefs, key); - if (isA_CFBoolean(val_cf) != NULL) - val = CFBooleanGetValue(val_cf); //When mDNSResponder-Debug-profile is Installed - else - val = mDNSfalse; //When mDNSResponder-Debug-profile is Uninstalled - } - else - { - LogMsg("GetmDNSManagedPrefKeyVal: mDNSManagedPrefs are NULL!"); - val = mDNSfalse; - } - return (val); -} - -mDNSexport mDNSBool GetmDNSManagedPref(CFStringRef key) -{ - SCPreferencesRef managed = NULL; - mDNSBool ret_value; - - managed = mDNSManagedPrefsGet(); - ret_value = GetmDNSManagedPrefKeyVal(managed, key); - - if (managed) - CFRelease(managed); - return (ret_value); -} -#endif //TARGET_OS_EMBEDDED - mDNSlocal int myIfIndexToName(u_short ifindex, char *name) { struct ifaddrs *ifa; @@ -1373,6 +1459,7 @@ mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const { if (ifindex == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly); if (ifindex == kDNSServiceInterfaceIndexP2P ) return(mDNSInterface_P2P); + if (ifindex == kDNSServiceInterfaceIndexBLE ) return(mDNSInterface_BLE); if (ifindex == kDNSServiceInterfaceIndexAny ) return(mDNSNULL); NetworkInterfaceInfoOSX* ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex); @@ -1393,9 +1480,11 @@ mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange) { NetworkInterfaceInfoOSX *i; + if (id == mDNSInterface_Any ) return(0); if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly); + if (id == mDNSInterface_Unicast ) return(0); if (id == mDNSInterface_P2P ) return(kDNSServiceInterfaceIndexP2P); - if (id == mDNSInterface_Any ) return(0); + if (id == mDNSInterface_BLE ) return(kDNSServiceInterfaceIndexBLE); mDNSu32 scope_id = (mDNSu32)(uintptr_t)id; @@ -1727,62 +1816,74 @@ mDNSlocal void setTrafficClass(int socketfd, mDNSBool useBackgroundTrafficClass) (void) setsockopt(socketfd, SOL_SOCKET, SO_TRAFFIC_CLASS, (void *)&traffic_class, sizeof(traffic_class)); } -mDNSexport void mDNSPlatformSetuDNSSocktOpt(UDPSocket *src, const mDNSAddr *dst, DNSQuestion *q) +mDNSlocal int mDNSPlatformGetSocktFd(void *sockCxt, mDNSTransport_Type transType, mDNSAddr_Type addrType) { - if (src) + if (transType == mDNSTransport_UDP) + { + UDPSocket* sock = (UDPSocket*) sockCxt; + return (addrType == mDNSAddrType_IPv4) ? sock->ss.sktv4 : sock->ss.sktv6; + } + else if (transType == mDNSTransport_TCP) + { + TCPSocket* sock = (TCPSocket*) sockCxt; + return (addrType == mDNSAddrType_IPv4) ? sock->ss.sktv4 : sock->ss.sktv6; + } + else { - int s; - char unenc_name[MAX_ESCAPED_DOMAIN_NAME]; - ConvertDomainNameToCString(&q->qname, unenc_name); + LogInfo("mDNSPlatformGetSocktFd: invalid transport %d", transType); + return kInvalidSocketRef; + } +} - if (dst->type == mDNSAddrType_IPv4) - s = src->ss.sktv4; - else - s = src->ss.sktv6; +mDNSexport void mDNSPlatformSetSocktOpt(void *sockCxt, mDNSTransport_Type transType, mDNSAddr_Type addrType, DNSQuestion *q) +{ + int sockfd; + char unenc_name[MAX_ESCAPED_DOMAIN_NAME]; - if (q->pid) - { - if (setsockopt(s, SOL_SOCKET, SO_DELEGATED, &q->pid, sizeof(q->pid)) == -1) - LogInfo("mDNSPlatformSetuDNSSocktOpt: Delegate PID failed %s for PID %d", strerror(errno), q->pid); - } - else - { - if (setsockopt(s, SOL_SOCKET, SO_DELEGATED_UUID, &q->uuid, sizeof(q->uuid)) == -1) - LogInfo("mDNSPlatformSetuDNSSocktOpt: Delegate UUID failed %s", strerror(errno)); - } - - // set the domain on the UDP socket - if (!(ne_session_set_socket_attributes(s, unenc_name, NULL))) - LogInfo("mDNSPlatformSetuDNSSocktOpt: ne_session_set_socket_attributes()-> setting domain failed for %s", unenc_name); + // verify passed-in arguments exist and that sockfd is valid + if (q == mDNSNULL || sockCxt == mDNSNULL || (sockfd = mDNSPlatformGetSocktFd(sockCxt, transType, addrType)) < 0) + return; -#if defined(SO_NOWAKEFROMSLEEP) - int nowake = 1; - if (setsockopt(s, SOL_SOCKET, SO_NOWAKEFROMSLEEP, &nowake, sizeof(nowake)) == -1) - LogInfo("mDNSPlatformSetuDNSSocktOpt: SO_NOWAKEFROMSLEEP failed %s", strerror(errno)); -#endif - - if (q->DenyOnCellInterface || q->DenyOnExpInterface) - { + if (q->pid) + { + if (setsockopt(sockfd, SOL_SOCKET, SO_DELEGATED, &q->pid, sizeof(q->pid)) == -1) + LogMsg("mDNSPlatformSetSocktOpt: Delegate PID failed %s for PID %d", strerror(errno), q->pid); + } + else + { + if (setsockopt(sockfd, SOL_SOCKET, SO_DELEGATED_UUID, &q->uuid, sizeof(q->uuid)) == -1) + LogMsg("mDNSPlatformSetSocktOpt: Delegate UUID failed %s", strerror(errno)); + } + + // set the domain on the socket + ConvertDomainNameToCString(&q->qname, unenc_name); + if (!(ne_session_set_socket_attributes(sockfd, unenc_name, NULL))) + LogInfo("mDNSPlatformSetSocktOpt: ne_session_set_socket_attributes()-> setting domain failed for %s", unenc_name); + + int nowake = 1; + if (setsockopt(sockfd, SOL_SOCKET, SO_NOWAKEFROMSLEEP, &nowake, sizeof(nowake)) == -1) + LogInfo("mDNSPlatformSetSocktOpt: SO_NOWAKEFROMSLEEP failed %s", strerror(errno)); + + if ((q->flags & kDNSServiceFlagsDenyCellular) || (q->flags & kDNSServiceFlagsDenyExpensive)) + { #if defined(SO_RESTRICT_DENY_CELLULAR) - if (q->DenyOnCellInterface) - { - int restrictions = 0; - restrictions = SO_RESTRICT_DENY_CELLULAR; - if (setsockopt(s, SOL_SOCKET, SO_RESTRICTIONS, &restrictions, sizeof(restrictions)) == -1) - LogInfo("mDNSPlatformSetuDNSSocktOpt: SO_RESTRICT_DENY_CELLULAR failed %s", strerror(errno)); - } + if (q->flags & kDNSServiceFlagsDenyCellular) + { + int restrictions = 0; + restrictions = SO_RESTRICT_DENY_CELLULAR; + if (setsockopt(sockfd, SOL_SOCKET, SO_RESTRICTIONS, &restrictions, sizeof(restrictions)) == -1) + LogMsg("mDNSPlatformSetSocktOpt: SO_RESTRICT_DENY_CELLULAR failed %s", strerror(errno)); + } #endif #if defined(SO_RESTRICT_DENY_EXPENSIVE) - if (q->DenyOnExpInterface) - { - int restrictions = 0; - restrictions = SO_RESTRICT_DENY_EXPENSIVE; - if (setsockopt(s, SOL_SOCKET, SO_RESTRICTIONS, &restrictions, sizeof(restrictions)) == -1) - LogInfo("mDNSPlatformSetuDNSSocktOpt: SO_RESTRICT_DENY_EXPENSIVE failed %s", strerror(errno)); - } + if (q->flags & kDNSServiceFlagsDenyExpensive) + { + int restrictions = 0; + restrictions = SO_RESTRICT_DENY_EXPENSIVE; + if (setsockopt(sockfd, SOL_SOCKET, SO_RESTRICTIONS, &restrictions, sizeof(restrictions)) == -1) + LogMsg("mDNSPlatformSetSocktOpt: SO_RESTRICT_DENY_EXPENSIVE failed %s", strerror(errno)); + } #endif - } - } } @@ -1938,7 +2039,10 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms LogInfo("mDNSPlatformSendUDP -> sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu", s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow)); if (!mDNSAddressIsAllDNSLinkGroup(dst)) - if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr); + { + if (errno == EHOSTUNREACH) return(mStatus_HostUnreachErr); + if (errno == EHOSTDOWN || errno == ENETDOWN || errno == ENETUNREACH) return(mStatus_TransientErr); + } // Don't report EHOSTUNREACH in the first three minutes after boot // This is because mDNSResponder intentionally starts up early in the boot process (See ) // but this means that sometimes it starts before configd has finished setting up the multicast routing entries. @@ -1962,14 +2066,6 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms result = mStatus_UnknownErr; } -#ifdef IP_BOUND_IF - if (dst->type == mDNSAddrType_IPv4 && info && !mDNSAddrIsDNSMulticast(dst)) - { - static const mDNSu32 ifindex = 0; - setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex)); - } -#endif - return(result); } @@ -2089,33 +2185,6 @@ mDNSlocal mDNSInterfaceID FindMyInterface(mDNS *const m, const mDNSAddr *addr) return(mDNSInterface_Any); } -// This is a stupid hack and we should get rid of it. -// The chance of there being a second unicast UDP packet already waiting in the kernel before we’ve -// finished processing the previous one is virtually nil, and will only happen by luck on very rare -// occasions when running on a machine with a fast network connection and a slow or busy processor. -// The idea that we’d rely for correctness on this random chance event occurring is ridiculous. -// -- SC -mDNSexport mDNSBool mDNSPlatformPeekUDP(mDNS *const m, UDPSocket *src) -{ - // We should have a DNSMessage header followed by the question and an answer - // which also includes a CNAME (that's when this function is called). To keep it - // simple, we expect at least the size of DNSMessage header(12) and size of "A" - // record (14 bytes). - char buffer[26]; - int ret; - - (void) m; - - if (!src) - return mDNSfalse; - - ret = recv(src->ss.sktv4, buffer, sizeof(buffer), MSG_PEEK); - if (ret > 0) - return mDNStrue; - else - return mDNSfalse; -} - mDNSexport void myKQSocketCallBack(int s1, short filter, void *context) { KQSocketSet *const ss = (KQSocketSet *)context; @@ -2133,7 +2202,7 @@ mDNSexport void myKQSocketCallBack(int s1, short filter, void *context) while (!closed) { - mDNSAddr senderAddr, destAddr; + mDNSAddr senderAddr, destAddr = zeroAddr; mDNSIPPort senderPort; struct sockaddr_storage from; size_t fromlen = sizeof(from); @@ -2680,16 +2749,16 @@ mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, u_short sa_family, mDNSIPPort addr.sin_family = AF_INET; addr.sin_port = port->NotAnInteger; err = bind(skt, (struct sockaddr*) &addr, sizeof(addr)); - if (err < 0) { LogMsg("ERROR: bind %s", strerror(errno)); return err; } + if (err < 0) { LogMsg("ERROR: bind %s", strerror(errno)); close(skt); return err; } // Receive interface identifiers err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)); - if (err < 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); return err; } + if (err < 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); close(skt); return err; } mDNSPlatformMemZero(&addr, sizeof(addr)); socklen_t len = sizeof(addr); err = getsockname(skt, (struct sockaddr*) &addr, &len); - if (err < 0) { LogMsg("getsockname - %s", strerror(errno)); return err; } + if (err < 0) { LogMsg("getsockname - %s", strerror(errno)); close(skt); return err; } port->NotAnInteger = addr.sin_port; } @@ -2701,16 +2770,16 @@ mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, u_short sa_family, mDNSIPPort addr6.sin6_family = AF_INET6; addr6.sin6_port = port->NotAnInteger; err = bind(skt, (struct sockaddr*) &addr6, sizeof(addr6)); - if (err < 0) { LogMsg("ERROR: bind6 %s", strerror(errno)); return err; } + if (err < 0) { LogMsg("ERROR: bind6 %s", strerror(errno)); close(skt); return err; } // We want to receive destination addresses and receive interface identifiers err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)); - if (err < 0) { LogMsg("ERROR: setsockopt IPV6_RECVPKTINFO %s", strerror(errno)); return err; } + if (err < 0) { LogMsg("ERROR: setsockopt IPV6_RECVPKTINFO %s", strerror(errno)); close(skt); return err; } mDNSPlatformMemZero(&addr6, sizeof(addr6)); socklen_t len = sizeof(addr6); err = getsockname(skt, (struct sockaddr *) &addr6, &len); - if (err < 0) { LogMsg("getsockname6 - %s", strerror(errno)); return err; } + if (err < 0) { LogMsg("getsockname6 - %s", strerror(errno)); close(skt); return err; } port->NotAnInteger = addr6.sin6_port; @@ -3106,6 +3175,14 @@ mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; } } + // Don't want to wake from sleep for inbound packets on the mDNS sockets + if (mDNSSameIPPort(port, MulticastDNSPort)) + { + int nowake = 1; + if (setsockopt(skt, SOL_SOCKET, SO_NOWAKEFROMSLEEP, &nowake, sizeof(nowake)) == -1) + LogInfo("SetupSocket: SO_NOWAKEFROMSLEEP failed %s", strerror(errno)); + } + if (sa_family == AF_INET) { // We want to receive destination addresses @@ -3140,7 +3217,7 @@ mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa else if (sa_family == AF_INET6) { // NAT-PMP Announcements make no sense on IPv6, and we don't support IPv6 for PCP, so bail early w/o error - if (mDNSSameIPPort(port, NATPMPAnnouncementPort)) { if (outport) *outport = zeroIPPort;return mStatus_NoError; } + if (mDNSSameIPPort(port, NATPMPAnnouncementPort)) { if (outport) *outport = zeroIPPort; close(skt); return mStatus_NoError; } // We want to receive destination addresses and receive interface identifiers err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)); @@ -3329,7 +3406,7 @@ mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i) // Note: MUST NOT close() the underlying native BSD sockets. // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them. - CFRunLoopRemoveSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode); + CFRunLoopRemoveSource(CFRunLoopGetMain(), i->BPF_rls, kCFRunLoopDefaultMode); CFRelease(i->BPF_rls); CFSocketInvalidate(i->BPF_cfs); CFRelease(i->BPF_cfs); @@ -3346,95 +3423,435 @@ mDNSlocal void bpf_callback_common(NetworkInterfaceInfoOSX *info) // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition). if (info->BPF_fd < 0) goto exit; - ssize_t n = read(info->BPF_fd, &info->m->imsg, info->BPF_len); - const mDNSu8 *ptr = (const mDNSu8 *)&info->m->imsg; - const mDNSu8 *end = (const mDNSu8 *)&info->m->imsg + n; - debugf("%3d: bpf_callback got %d bytes on %s", info->BPF_fd, n, info->ifinfo.ifname); + ssize_t n = read(info->BPF_fd, &info->m->imsg, info->BPF_len); + const mDNSu8 *ptr = (const mDNSu8 *)&info->m->imsg; + const mDNSu8 *end = (const mDNSu8 *)&info->m->imsg + n; + debugf("%3d: bpf_callback got %d bytes on %s", info->BPF_fd, n, info->ifinfo.ifname); + + if (n<0) + { + /* + * sometimes there can be a race condition btw when the bpf socket + * gets data and the callback get scheduled and when we call BIOCSETF (which + * clears the socket). this can cause the read to hang for a really long time + * and effectively prevent us from responding to requests for long periods of time. + * to prevent this make the socket non blocking and just bail if we dont get anything + */ + if (errno == EAGAIN) + { + LogMsg("bpf_callback got EAGAIN bailing"); + goto exit; + } + LogMsg("Closing %s BPF fd %d due to error %d (%s)", info->ifinfo.ifname, info->BPF_fd, errno, strerror(errno)); + CloseBPF(info); + goto exit; + } + + while (ptr < end) + { + const struct bpf_hdr *const bh = (const struct bpf_hdr *)ptr; + debugf("%3d: bpf_callback ptr %p bh_hdrlen %d data %p bh_caplen %4d bh_datalen %4d next %p remaining %4d", + info->BPF_fd, ptr, bh->bh_hdrlen, ptr + bh->bh_hdrlen, bh->bh_caplen, bh->bh_datalen, + ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen), end - (ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen))); + // Note that BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header. + // Given that An Ethernet header is 14 bytes, this means that if the network layer header (e.g. IP header, + // ARP message, etc.) is 4-byte aligned, then necessarily the Ethernet header will be NOT be 4-byte aligned. + mDNSCoreReceiveRawPacket(info->m, ptr + bh->bh_hdrlen, ptr + bh->bh_hdrlen + bh->bh_caplen, info->ifinfo.InterfaceID); + ptr += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen); + } +exit: + KQueueUnlock(info->m, "bpf_callback"); +} +#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM +mDNSlocal void bpf_callback_dispatch(NetworkInterfaceInfoOSX *const info) +{ + bpf_callback_common(info); +} +#else +mDNSlocal void bpf_callback(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context) +{ + (void)cfs; + (void)CallBackType; + (void)address; + (void)data; + bpf_callback_common((NetworkInterfaceInfoOSX *)context); +} +#endif + +mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win) +{ + LogMsg("mDNSPlatformSendKeepalive called\n"); + mDNSSendKeepalive(sadd->ip.v6.b, dadd->ip.v6.b, lport->NotAnInteger, rport->NotAnInteger, seq, ack, win); +} + +mDNSexport mStatus mDNSPlatformClearSPSData(void) +{ + CFStringRef spsAddress = NULL; + CFStringRef ownerOPTRec = NULL; + + if ((spsAddress = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", "[^/]", "/BonjourSleepProxyAddress"))) + { + if (SCDynamicStoreRemoveValue(NULL, spsAddress) == false) + LogSPS("mDNSPlatformClearSPSData: Unable to remove sleep proxy address key"); + } + + if((ownerOPTRec = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", "[^/]", "/BonjourSleepProxyOPTRecord"))) + { + if (SCDynamicStoreRemoveValue(NULL, ownerOPTRec) == false) + LogSPS("mDNSPlatformClearSPSData: Unable to remove sleep proxy owner option record key"); + } + + if (spsAddress) CFRelease(spsAddress); + if (ownerOPTRec) CFRelease(ownerOPTRec); + return KERN_SUCCESS; +} + +mDNSlocal int getMACAddress(int family, v6addr_t raddr, v6addr_t gaddr, int *gfamily, ethaddr_t eth) +{ + struct + { + struct rt_msghdr m_rtm; + char m_space[512]; + } m_rtmsg; + + struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); + char *cp = m_rtmsg.m_space; + int seq = 6367, sock, rlen, i; + struct sockaddr_in *sin = NULL; + struct sockaddr_in6 *sin6 = NULL; + struct sockaddr_dl *sdl = NULL; + struct sockaddr_storage sins; + struct sockaddr_dl sdl_m; + +#define NEXTADDR(w, s, len) \ +if (rtm->rtm_addrs & (w)) \ +{ \ +bcopy((char *)s, cp, len); \ +cp += len; \ +} + + bzero(&sins, sizeof(struct sockaddr_storage)); + bzero(&sdl_m, sizeof(struct sockaddr_dl)); + bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); + + sock = socket(PF_ROUTE, SOCK_RAW, 0); + if (sock < 0) + { + LogMsg("getMACAddress: Can not open the socket - %s", strerror(errno)); + return errno; + } + + rtm->rtm_addrs |= RTA_DST | RTA_GATEWAY; + rtm->rtm_type = RTM_GET; + rtm->rtm_flags = 0; + rtm->rtm_version = RTM_VERSION; + rtm->rtm_seq = ++seq; + + sdl_m.sdl_len = sizeof(sdl_m); + sdl_m.sdl_family = AF_LINK; + if (family == AF_INET) + { + sin = (struct sockaddr_in*)&sins; + sin->sin_family = AF_INET; + sin->sin_len = sizeof(struct sockaddr_in); + memcpy(&sin->sin_addr, raddr, sizeof(struct in_addr)); + NEXTADDR(RTA_DST, sin, sin->sin_len); + } + else if (family == AF_INET6) + { + sin6 = (struct sockaddr_in6 *)&sins; + sin6->sin6_len = sizeof(struct sockaddr_in6); + sin6->sin6_family = AF_INET6; + memcpy(&sin6->sin6_addr, raddr, sizeof(struct in6_addr)); + NEXTADDR(RTA_DST, sin6, sin6->sin6_len); + } + NEXTADDR(RTA_GATEWAY, &sdl_m, sdl_m.sdl_len); + rtm->rtm_msglen = rlen = cp - (char *)&m_rtmsg; + + if (write(sock, (char *)&m_rtmsg, rlen) < 0) + { + LogMsg("getMACAddress: writing to routing socket: %s", strerror(errno)); + close(sock); + return errno; + } + + do + { + rlen = read(sock, (char *)&m_rtmsg, sizeof(m_rtmsg)); + } + while (rlen > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != getpid())); + + if (rlen < 0) + LogMsg("getMACAddress: Read from routing socket failed"); + + if (family == AF_INET) + { + sin = (struct sockaddr_in *) (rtm + 1); + sdl = (struct sockaddr_dl *) (sin->sin_len + (char *) sin); + } + else if (family == AF_INET6) + { + sin6 = (struct sockaddr_in6 *) (rtm +1); + sdl = (struct sockaddr_dl *) (sin6->sin6_len + (char *) sin6); + } + + if (!sdl) + { + LogMsg("getMACAddress: sdl is NULL for family %d", family); + close(sock); + return -1; + } + + // If the address is not on the local net, we get the IP address of the gateway. + // We would have to repeat the process to get the MAC address of the gateway + *gfamily = sdl->sdl_family; + if (sdl->sdl_family == AF_INET) + { + if (sin) + { + struct sockaddr_in *new_sin = (struct sockaddr_in *)(sin->sin_len +(char*) sin); + memcpy(gaddr, &new_sin->sin_addr, sizeof(struct in_addr)); + } + else + { + LogMsg("getMACAddress: sin is NULL"); + } + close(sock); + return -1; + } + else if (sdl->sdl_family == AF_INET6) + { + if (sin6) + { + struct sockaddr_in6 *new_sin6 = (struct sockaddr_in6 *)(sin6->sin6_len +(char*) sin6); + memcpy(gaddr, &new_sin6->sin6_addr, sizeof(struct in6_addr)); + } + else + { + LogMsg("getMACAddress: sin6 is NULL"); + } + close(sock); + return -1; + } + + unsigned char *ptr = (unsigned char *)LLADDR(sdl); + for (i = 0; i < ETHER_ADDR_LEN; i++) + (eth)[i] = *(ptr +i); + + close(sock); + + return KERN_SUCCESS; +} + +mDNSlocal int GetRemoteMacinternal(int family, v6addr_t raddr, ethaddr_t eth) +{ + int ret = 0; + v6addr_t gateway; + int gfamily = 0; + int count = 0; - if (n<0) + do { - /* - * sometimes there can be a race condition btw when the bpf socket - * gets data and the callback get scheduled and when we call BIOCSETF (which - * clears the socket). this can cause the read to hang for a really long time - * and effectively prevent us from responding to requests for long periods of time. - * to prevent this make the socket non blocking and just bail if we dont get anything - */ - if (errno == EAGAIN) + ret = getMACAddress(family, raddr, gateway, &gfamily, eth); + if (ret == -1) { - LogMsg("bpf_callback got EAGAIN bailing"); - goto exit; + memcpy(raddr, gateway, sizeof(family)); + family = gfamily; + count++; } - LogMsg("Closing %s BPF fd %d due to error %d (%s)", info->ifinfo.ifname, info->BPF_fd, errno, strerror(errno)); - CloseBPF(info); - goto exit; } + while ((ret == -1) && (count < 5)); + return ret; +} - while (ptr < end) +mDNSlocal int StoreSPSMACAddressinternal(int family, v6addr_t spsaddr, const char *ifname) +{ + ethaddr_t eth; + char spsip[INET6_ADDRSTRLEN]; + int ret = 0; + CFStringRef sckey = NULL; + SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:StoreSPSMACAddress"), NULL, NULL); + SCDynamicStoreRef ipstore = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetIPv6Addresses"), NULL, NULL); + CFMutableDictionaryRef dict = NULL; + CFStringRef entityname = NULL; + CFDictionaryRef ipdict = NULL; + CFArrayRef addrs = NULL; + + if ((store == NULL) || (ipstore == NULL)) { - const struct bpf_hdr *const bh = (const struct bpf_hdr *)ptr; - debugf("%3d: bpf_callback ptr %p bh_hdrlen %d data %p bh_caplen %4d bh_datalen %4d next %p remaining %4d", - info->BPF_fd, ptr, bh->bh_hdrlen, ptr + bh->bh_hdrlen, bh->bh_caplen, bh->bh_datalen, - ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen), end - (ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen))); - // Note that BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header. - // Given that An Ethernet header is 14 bytes, this means that if the network layer header (e.g. IP header, - // ARP message, etc.) is 4-byte aligned, then necessarily the Ethernet header will be NOT be 4-byte aligned. - mDNSCoreReceiveRawPacket(info->m, ptr + bh->bh_hdrlen, ptr + bh->bh_hdrlen + bh->bh_caplen, info->ifinfo.InterfaceID); - ptr += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen); + LogMsg("StoreSPSMACAddressinternal: Unable to accesss SC Dynamic Store"); + ret = -1; + goto fin; } -exit: - KQueueUnlock(info->m, "bpf_callback"); -} -#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM -mDNSlocal void bpf_callback_dispatch(NetworkInterfaceInfoOSX *const info) -{ - bpf_callback_common(info); + + // Get the MAC address of the Sleep Proxy Server + memset(eth, 0, sizeof(eth)); + ret = GetRemoteMacinternal(family, spsaddr, eth); + if (ret != 0) + { + LogMsg("StoreSPSMACAddressinternal: Failed to determine the MAC address"); + goto fin; + } + + // Create/Update the dynamic store entry for the specified interface + sckey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname, "/BonjourSleepProxyAddress"); + dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (!dict) + { + LogMsg("StoreSPSMACAddressinternal: SPSCreateDict() Could not create CFDictionary dict"); + ret = -1; + goto fin; + } + + CFStringRef macaddr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%02x:%02x:%02x:%02x:%02x:%02x"), eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]); + CFDictionarySetValue(dict, CFSTR("MACAddress"), macaddr); + if (NULL != macaddr) + CFRelease(macaddr); + + if( NULL == inet_ntop(family, (void *)spsaddr, spsip, sizeof(spsip))) + { + LogMsg("StoreSPSMACAddressinternal: inet_ntop failed: %s", strerror(errno)); + ret = -1; + goto fin; + } + + CFStringRef ipaddr = CFStringCreateWithCString(NULL, spsip, kCFStringEncodingUTF8); + CFDictionarySetValue(dict, CFSTR("IPAddress"), ipaddr); + if (NULL != ipaddr) + CFRelease(ipaddr); + + // Get the current IPv6 addresses on this interface and store them so NAs can be sent on wakeup + if ((entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/IPv6"), ifname)) != NULL) + { + if ((ipdict = SCDynamicStoreCopyValue(ipstore, entityname)) != NULL) + { + if((addrs = CFDictionaryGetValue(ipdict, CFSTR("Addresses"))) != NULL) + { + addrs = CFRetain(addrs); + CFDictionarySetValue(dict, CFSTR("RegisteredAddresses"), addrs); + } + } + } + SCDynamicStoreSetValue(store, sckey, dict); + +fin: + if (store) CFRelease(store); + if (ipstore) CFRelease(ipstore); + if (sckey) CFRelease(sckey); + if (dict) CFRelease(dict); + if (ipdict) CFRelease(ipdict); + if (entityname) CFRelease(entityname); + if (addrs) CFRelease(addrs); + + return ret; } -#else -mDNSlocal void bpf_callback(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context) + +mDNSlocal void mDNSStoreSPSMACAddress(int family, v6addr_t spsaddr, char *ifname) { - (void)cfs; - (void)CallBackType; - (void)address; - (void)data; - bpf_callback_common((NetworkInterfaceInfoOSX *)context); + struct + { + v6addr_t saddr; + } addr; + int err = 0; + + mDNSPlatformMemCopy(addr.saddr, spsaddr, sizeof(v6addr_t)); + + err = StoreSPSMACAddressinternal(family, (uint8_t *)addr.saddr, ifname); + if (err != 0) + LogMsg("mDNSStoreSPSMACAddress : failed"); } -#endif -mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win) +mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname) { - LogMsg("mDNSPlatformSendKeepalive called\n"); - mDNSSendKeepalive(sadd->ip.v6.b, dadd->ip.v6.b, lport->NotAnInteger, rport->NotAnInteger, seq, ack, win); + int family = (spsaddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6; + + LogInfo("mDNSPlatformStoreSPSMACAddr : Storing %#a on interface %s", spsaddr, ifname); + mDNSStoreSPSMACAddress(family, spsaddr->ip.v6.b, ifname); + + return KERN_SUCCESS; } -mDNSexport mStatus mDNSPlatformClearSPSMACAddr(void) + +mDNSexport mStatus mDNSPlatformStoreOwnerOptRecord(char *ifname, DNSMessage* msg, int length) { - CFStringRef entityname = NULL; + int ret = 0; + CFStringRef sckey = NULL; + SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:StoreOwnerOPTRecord"), NULL, NULL); + CFMutableDictionaryRef dict = NULL; + + if (store == NULL) + { + LogMsg("mDNSPlatformStoreOwnerOptRecord: Unable to accesss SC Dynamic Store"); + ret = -1; + goto fin; + } - if ((entityname = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", "[^/]", "/BonjourSleepProxyAddress"))) + // Create/Update the dynamic store entry for the specified interface + sckey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname, "/BonjourSleepProxyOPTRecord"); + dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (!dict) { - if (SCDynamicStoreRemoveValue(NULL, entityname) == false) - LogSPS("mDNSPlatformClearSPSMACAddr: Unable to remove key"); + LogMsg("mDNSPlatformStoreOwnerOptRecord: Could not create CFDictionary dictionary to store OPT Record"); + ret =-1; + goto fin; } - if (entityname) - CFRelease(entityname); - return KERN_SUCCESS; + CFDataRef optRec = NULL; + optRec = CFDataCreate(NULL, (const uint8_t *)msg, (CFIndex)length); + CFDictionarySetValue(dict, CFSTR("OwnerOPTRecord"), optRec); + if (NULL != optRec) CFRelease(optRec); + + SCDynamicStoreSetValue(store, sckey, dict); + +fin: + if (NULL != store) CFRelease(store); + if (NULL != sckey) CFRelease(sckey); + if (NULL != dict) CFRelease(dict); + return ret; } -mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname) +mDNSlocal void mDNSGet_RemoteMAC(mDNS *const m, int family, v6addr_t raddr) { - int family = (spsaddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6; - LogSPS("mDNSPlatformStoreSPSMACAddr : Storing %#a on interface %s", spsaddr, ifname); - mDNSStoreSPSMACAddress(family, spsaddr->ip.v6.b, ifname); - return KERN_SUCCESS; + ethaddr_t eth; + IPAddressMACMapping *addrMapping; + int kr = KERN_FAILURE; + struct + { + v6addr_t addr; + } dst; + + mDNSPlatformMemCopy(dst.addr, raddr, sizeof(v6addr_t)); + + kr = GetRemoteMacinternal(family, (uint8_t *)dst.addr, eth); + + // If the call to get the remote MAC address succeeds, allocate and copy + // the values and schedule a task to update the MAC address in the TCP Keepalive record. + if (kr == 0) + { + addrMapping = mDNSPlatformMemAllocate(sizeof(IPAddressMACMapping)); + snprintf(addrMapping->ethaddr, sizeof(addrMapping->ethaddr), "%02x:%02x:%02x:%02x:%02x:%02x", + eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]); + if (family == AF_INET) + { + addrMapping->ipaddr.type = mDNSAddrType_IPv4; + mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v4.b, raddr, sizeof(v6addr_t)); + } + else + { + addrMapping->ipaddr.type = mDNSAddrType_IPv6; + mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v6.b, raddr, sizeof(v6addr_t)); + } + UpdateRMAC(m, addrMapping); + } } mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNS *const m, mDNSAddr *raddr) { int family = (raddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6; - - mDNSGetRemoteMAC(m, family, raddr->ip.v6.b); + + LogInfo("mDNSPlatformGetRemoteMacAddr calling mDNSGet_RemoteMAC"); + mDNSGet_RemoteMAC(m, family, raddr->ip.v6.b); + return KERN_SUCCESS; } @@ -3485,7 +3902,7 @@ mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID NetworkInterfaceInfoOSX *x; // Note: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also. - for (x = m->p->InterfaceList; x; x = x->next) if (x->ifinfo.InterfaceID == InterfaceID) break; + for (x = m->p->InterfaceList; x; x = x->next) if ((x->ifinfo.InterfaceID == InterfaceID) && (x->BPF_fd >= 0)) break; if (!x) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID); return; } @@ -3711,7 +4128,7 @@ mDNSexport void mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd) i->BPF_fd = fd; i->BPF_cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, bpf_callback, &myCFSocketContext); i->BPF_rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, i->BPF_cfs, 0); - CFRunLoopAddSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode); + CFRunLoopAddSource(CFRunLoopGetMain(), i->BPF_rls, kCFRunLoopDefaultMode); #endif mDNSPlatformUpdateProxyList(m, i->ifinfo.InterfaceID); } @@ -3999,8 +4416,8 @@ mDNSlocal mDNSBool InterfaceSupportsKeepAlive(NetworkInterfaceInfo *const intf) mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i) { - if (!MulticastInterface(i) ) return(mDNSfalse); // We only use Sleep Proxy Service on multicast-capable interfaces - if (i->ifa_flags & IFF_LOOPBACK) return(mDNSfalse); // except loopback + // We only use Sleep Proxy Service on multicast-capable interfaces, except loopback and D2D. + if (!SPSInterface(i)) return(mDNSfalse); // If the interface supports TCPKeepalive, it is capable of waking up for a magic packet // This check is needed since the SIOCGIFWAKEFLAGS ioctl returns wrong values for WOMP capability @@ -4140,6 +4557,7 @@ exit: // Return true if the interface is associate to a CarPlay hosted SSID. mDNSlocal mDNSBool IsCarPlaySSID(char *ifa_name) { + static WiFiManagerClientRef manager = NULL; mDNSBool rvalue = mDNSfalse; if (!MobileWiFiLibLoad()) @@ -4148,10 +4566,15 @@ mDNSlocal mDNSBool IsCarPlaySSID(char *ifa_name) // If we have associated with a CarPlay hosted SSID, then use the same // optimizations that are used if an interface has the IFEF_DIRECTLINK flag set. - WiFiManagerClientRef manager; + // Get one WiFiManagerClientRef to use for all calls. + if (manager == NULL) + manager = WiFiManagerClientCreate_p(NULL, kWiFiClientTypeNormal); - manager = WiFiManagerClientCreate_p(NULL, kWiFiClientTypeNormal); - if (manager != NULL) + if (manager == NULL) + { + LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!"); + } + else { CFArrayRef devices; @@ -4174,7 +4597,6 @@ mDNSlocal mDNSBool IsCarPlaySSID(char *ifa_name) } CFRelease(devices); } - CFRelease(manager); } return rvalue; @@ -4263,6 +4685,8 @@ mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifad i->ifinfo.Loopback = ((ifa->ifa_flags & IFF_LOOPBACK) != 0) ? mDNStrue : mDNSfalse; i->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue; + // Setting DirectLink indicates we can do the optimization of skipping the probe phase + // for the interface address records since they should be unique. if (eflags & IFEF_DIRECTLINK) i->ifinfo.DirectLink = mDNStrue; else @@ -4281,6 +4705,7 @@ mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifad // Bonjour requests over the AWDL interface. i->ifinfo.SupportsUnicastMDNSResponse = mDNSfalse; AWDLInterfaceID = i->ifinfo.InterfaceID; + i->ifinfo.DirectLink = mDNStrue; LogInfo("AddInterfaceToList: AWDLInterfaceID = %d", (int) AWDLInterfaceID); } else @@ -4555,7 +4980,7 @@ mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAut else if (llqStatus == mStatus_NoSuchRecord) { status = llqStatus; - mDNS_snprintf(buffer, sizeof(buffer), llqBuffer); + mDNS_snprintf(buffer, sizeof(buffer), "%s", llqBuffer); } else if ((llq && llq->Result == mStatus_DoubleNAT) || (tun && tun->Result == mStatus_DoubleNAT)) { @@ -4582,7 +5007,7 @@ mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAut else { status = llqStatus; - mDNS_snprintf(buffer, sizeof(buffer), llqBuffer); + mDNS_snprintf(buffer, sizeof(buffer), "%s", llqBuffer); LogInfo("UpdateAutoTunnelDomainStatus: LLQ Status %d, %s", status, buffer); } @@ -4649,8 +5074,7 @@ mDNSlocal void UpdateAnonymousRacoonConfig(mDNS *m) // Determine whether we if (info != AnonymousRacoonConfig) { AnonymousRacoonConfig = info; - // Create or revert configuration file, and start (or SIGHUP) Racoon - (void)mDNSConfigureServer(AnonymousRacoonConfig ? kmDNSUp : kmDNSDown, AnonymousRacoonConfig ? btmmprefix : mDNSNULL, AnonymousRacoonConfig ? &AnonymousRacoonConfig->domain : mDNSNULL); + LogInfo("UpdateAnonymousRacoonConfig need not be done in mDNSResponder"); } } @@ -5388,8 +5812,6 @@ mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q) p->q.ForceMCast = mDNSfalse; p->q.ReturnIntermed = mDNStrue; p->q.SuppressUnusable = mDNSfalse; - p->q.DenyOnCellInterface = mDNSfalse; - p->q.DenyOnExpInterface = mDNSfalse; p->q.SearchListIndex = 0; p->q.AppendSearchDomains = 0; p->q.RetryWithSearchDomains = mDNSfalse; @@ -5507,7 +5929,7 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc) verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6); } - if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY))) + if (!(ifru_flags6 & (IN6_IFF_TENTATIVE | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY))) { if (ifa->ifa_flags & IFF_LOOPBACK) { @@ -5634,6 +6056,9 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc) { NetworkInterfaceInfoOSX *i; int count = 0; + + // Recalculate SuppressProbes time based on the current set of active interfaces. + m->SuppressProbes = 0; for (i = m->p->InterfaceList; i; i = i->next) if (i->Exists) { @@ -5687,8 +6112,8 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc) if (!n->McastTxRx) { debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, &n->ip); -#if TARGET_OS_WATCH - // We join the Bonjour multicast group on the watch only when a client request is active, +#if TARGET_OS_EMBEDDED + // We join the Bonjour multicast group on Apple embedded platforms ONLY when a client request is active, // so we leave the multicast group here to clear any residual group membership. if (i->sa_family == AF_INET) { @@ -5719,7 +6144,7 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc) LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface); } } -#endif // TARGET_OS_WATCH +#endif // TARGET_OS_EMBEDDED } else { @@ -5963,21 +6388,38 @@ mDNSexport const char *DNSScopeToString(mDNSu32 scope) } } -mDNSlocal void ConfigSearchDomains(mDNS *const m, dns_resolver_t *resolver, mDNSInterfaceID interface, mDNSu32 scope, MD5_CTX *sdc) +mDNSlocal void ConfigSearchDomains(mDNS *const m, dns_resolver_t *resolver, mDNSInterfaceID interfaceId, mDNSu32 scope, MD5_CTX *sdc, uint64_t generation) { const char *scopeString = DNSScopeToString(scope); int j; + domainname d; - if (scope != kScopeNone) + if (scope == kScopeNone) + interfaceId = mDNSInterface_Any; + + if (scope == kScopeNone || scope == kScopeInterfaceID) { - LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for Interface %p", scopeString, interface); - return; + for (j = 0; j < resolver->n_search; j++) + { + if (MakeDomainNameFromDNSNameString(&d, resolver->search[j]) != NULL) + { + static char interface_buf[32]; + mDNS_snprintf(interface_buf, sizeof(interface_buf), "for interface %s", InterfaceNameForID(m, interfaceId)); + LogInfo("ConfigSearchDomains: (%s) configuring search domain %s %s (generation= %llu)", scopeString, + resolver->search[j], (interfaceId == mDNSInterface_Any) ? "" : interface_buf, generation); + UpdateSearchDomainHash(m, sdc, resolver->search[j], interfaceId); + mDNS_AddSearchDomain_CString(resolver->search[j], interfaceId); + } + else + { + LogInfo("ConfigSearchDomains: An invalid search domain was detected for %s domain %s n_nameserver %d, (generation= %llu)", + DNSScopeToString(scope), resolver->domain, resolver->n_nameserver, generation); + } + } } - for (j = 0; j < resolver->n_search; j++) + else { - LogInfo("ConfigSearchDomains: (%s) configuring search list %s", scopeString, resolver->search[j]); - UpdateSearchDomainHash(m, sdc, resolver->search[j], NULL); - mDNS_AddSearchDomain_CString(resolver->search[j], NULL); + LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for interface %s", scopeString, InterfaceNameForID(m,interfaceId)); } } @@ -6140,7 +6582,8 @@ mDNSlocal void ConfigResolvers(mDNS *const m, dns_config_t *config, mDNSu32 scop if (setsearch) { - ConfigSearchDomains(m, resolver[i], interface, scope, sdc); + ConfigSearchDomains(m, resolver[i], interface, scope, sdc, config->generation); + // Parse other scoped resolvers for search lists if (!setservers) continue; @@ -6522,9 +6965,8 @@ mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, } else { - LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d, generation %llu", config->n_resolver, config->generation); - // SameDomainName check below is to fix Dynamic DNS hostname changes not noticed - if (m->p->LastConfigGeneration == config->generation && (!fqdn || (SameDomainName(fqdn, &m->FQDN)))) + LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d, generation %llu, last %llu", config->n_resolver, config->generation, m->p->LastConfigGeneration); + if (m->p->LastConfigGeneration == config->generation) { LogInfo("mDNSPlatformSetDNSConfig: generation number %llu same, not processing", config->generation); dns_configuration_free(config); @@ -6855,7 +7297,7 @@ mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m) else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect"); } } -#else +#elif !TARGET_OS_EMBEDDED mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m) { (void) m; // Unused @@ -6863,12 +7305,14 @@ mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m) } #endif // ! NO_AWACS +#if !TARGET_OS_EMBEDDED mDNSlocal void ProcessConndConfigChanges(mDNS *const m); +#endif #endif // APPLE_OSX_mDNSResponder // MUST be called holding the lock -mDNSexport void SetDomainSecrets(mDNS *m) +mDNSlocal void SetDomainSecrets_internal(mDNS *m) { #ifdef NO_SECURITYFRAMEWORK (void) m; @@ -7134,6 +7578,15 @@ mDNSexport void SetDomainSecrets(mDNS *m) #endif /* NO_SECURITYFRAMEWORK */ } +mDNSexport void SetDomainSecrets(mDNS *m) +{ +#if DEBUG + // Don't get secrets for BTMM if running in debug mode + if (!IsDebugSocketInUse()) +#endif + SetDomainSecrets_internal(m); +} + mDNSlocal void SetLocalDomains(void) { CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); @@ -7303,6 +7756,7 @@ mDNSlocal void UpdateSPSStatus(mDNS *const m, DNSQuestion *question, const Resou CFRelease(ifname); } +#if !TARGET_OS_EMBEDDED mDNSlocal mDNSs32 GetSystemSleepTimerSetting(void) { mDNSs32 val = -1; @@ -7365,6 +7819,7 @@ mDNSlocal void SetSPS(mDNS *const m) mDNSCoreBeSleepProxyServer(m, sps, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures); } +#endif // !TARGET_OS_EMBEDDED // The definitions below should eventually come from some externally-supplied header file. // However, since these definitions can't really be changed without breaking binary compatibility, @@ -7396,14 +7851,28 @@ typedef struct mDNSlocal mDNSu16 GetPortArray(mDNS *const m, int trans, mDNSIPPort *portarray) { const domainlabel *const tp = (trans == mDNSTransport_UDP) ? (const domainlabel *)"\x4_udp" : (const domainlabel *)"\x4_tcp"; - int count = 0; + int count = 0; + AuthRecord *rr; for (rr = m->ResourceRecords; rr; rr=rr->next) + { if (rr->resrec.rrtype == kDNSType_SRV && SameDomainLabel(ThirdLabel(rr->resrec.name)->c, tp->c)) { - if (portarray) portarray[count] = rr->resrec.rdata->u.srv.port; - count++; + if (!portarray) + count++; + else + { + int i; + for (i = 0; i < count; i++) + if (mDNSSameIPPort(portarray[i], rr->resrec.rdata->u.srv.port)) + break; + + // Add it into the port list only if it not already present in the list + if (i >= count) + portarray[count++] = rr->resrec.rdata->u.srv.port; + } } + } // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500) if (trans == mDNSTransport_UDP && m->AutoTunnelNAT.clientContext) @@ -7546,7 +8015,7 @@ mDNSexport mDNSBool SupportsInNICProxy(NetworkInterfaceInfo *const intf) { if(!UseInternalSleepProxy) { - LogSPS("SupportsInNICProxy: Internal Sleep Proxy is disabled"); + LogMsg("SupportsInNICProxy: Internal Sleep Proxy is disabled"); return mDNSfalse; } return CheckInterfaceSupport(intf, mDNS_IOREG_KEY); @@ -7607,10 +8076,10 @@ mDNSexport mStatus ActivateLocalProxy(mDNS *const m, NetworkInterfaceInfo *const cmd.numRRRecords = CountProxyRecords(m, &cmd.rrBufferSize, intf, TCPKAOnly, supportsTCPKA); cmd.compression = sizeof(DNSMessageHeader); - DNSMessage *msg = (DNSMessage *)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader) + cmd.rrBufferSize); - cmd.rrRecords.ptr = mallocL("mDNSOffloadCmd rrRecords", cmd.numRRRecords * sizeof(FatPtr)); - cmd.udpPorts.ptr = mallocL("mDNSOffloadCmd udpPorts", cmd.numUDPPorts * sizeof(mDNSIPPort)); - cmd.tcpPorts.ptr = mallocL("mDNSOffloadCmd tcpPorts", cmd.numTCPPorts * sizeof(mDNSIPPort)); + DNSMessage *msg = (DNSMessage *)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader) + cmd.rrBufferSize); + cmd.rrRecords.ptr = cmd.numRRRecords ? mallocL("mDNSOffloadCmd rrRecords", cmd.numRRRecords * sizeof(FatPtr)) : NULL; + cmd.udpPorts.ptr = cmd.numUDPPorts ? mallocL("mDNSOffloadCmd udpPorts" , cmd.numUDPPorts * sizeof(mDNSIPPort)) : NULL; + cmd.tcpPorts.ptr = cmd.numTCPPorts ? mallocL("mDNSOffloadCmd tcpPorts" , cmd.numTCPPorts * sizeof(mDNSIPPort)) : NULL; LogSPS("ActivateLocalProxy: msg %p %d RR %p %d, UDP %p %d, TCP %p %d", msg, cmd.rrBufferSize, @@ -7618,23 +8087,15 @@ mDNSexport mStatus ActivateLocalProxy(mDNS *const m, NetworkInterfaceInfo *const cmd.udpPorts.ptr, cmd.numUDPPorts, cmd.tcpPorts.ptr, cmd.numTCPPorts); - if (!msg || !cmd.rrRecords.ptr || !cmd.udpPorts.ptr || !cmd.tcpPorts.ptr) - LogMsg("ActivateLocalProxy: Failed to allocate memory: msg %p %d RR %p %d, UDP %p %d, TCP %p %d", - msg, cmd.rrBufferSize, - cmd.rrRecords.ptr, cmd.numRRRecords, - cmd.udpPorts.ptr, cmd.numUDPPorts, - cmd.tcpPorts.ptr, cmd.numTCPPorts); - else - { - GetProxyRecords(m, msg, &cmd.rrBufferSize, cmd.rrRecords.ptr, TCPKAOnly, supportsTCPKA); - GetPortArray(m, mDNSTransport_UDP, cmd.udpPorts.ptr); - GetPortArray(m, mDNSTransport_TCP, cmd.tcpPorts.ptr); - char outputData[2]; - size_t outputDataSize = sizeof(outputData); - kr = IOConnectCallStructMethod(conObj, 0, &cmd, sizeof(cmd), outputData, &outputDataSize); - LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", intf->ifname, n1, n2, kr); - if (kr == KERN_SUCCESS) result = mStatus_NoError; - } + if (msg && cmd.rrRecords.ptr) GetProxyRecords(m, msg, &cmd.rrBufferSize, cmd.rrRecords.ptr, TCPKAOnly, supportsTCPKA); + if (cmd.udpPorts.ptr) cmd.numUDPPorts = GetPortArray(m, mDNSTransport_UDP, cmd.udpPorts.ptr); + if (cmd.tcpPorts.ptr) cmd.numTCPPorts = GetPortArray(m, mDNSTransport_TCP, cmd.tcpPorts.ptr); + + char outputData[2]; + size_t outputDataSize = sizeof(outputData); + kr = IOConnectCallStructMethod(conObj, 0, &cmd, sizeof(cmd), outputData, &outputDataSize); + LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", intf->ifname, n1, n2, kr); + if (kr == KERN_SUCCESS) result = mStatus_NoError; if (cmd.tcpPorts.ptr) freeL("mDNSOffloadCmd udpPorts", cmd.tcpPorts.ptr); if (cmd.udpPorts.ptr) freeL("mDNSOffloadCmd tcpPorts", cmd.udpPorts.ptr); @@ -7683,10 +8144,15 @@ mDNSlocal mDNSu8 SystemWakeForNetworkAccess(void) mDNSlocal mDNSBool SystemSleepOnlyIfWakeOnLAN(void) { mDNSs32 val = 0; - GetCurrentPMSetting(CFSTR("PrioritizeNetworkReachabilityOverSleep"), &val); + // PrioritizeNetworkReachabilityOverSleep has been deprecated. + // GetCurrentPMSetting(CFSTR("PrioritizeNetworkReachabilityOverSleep"), &val); + // Statically set the PrioritizeNetworkReachabilityOverSleep value to 1 for AppleTV + if (IsAppleTV()) + val = 1; return val != 0 ? mDNStrue : mDNSfalse; } + #if APPLE_OSX_mDNSResponder // When sleeping, we always ensure that the _autotunnel6 record (if connected to RR relay) // gets deregistered, so that older peers are forced to connect over direct UDP instead of @@ -7744,6 +8210,7 @@ mDNSexport void RemoveAutoTunnel6Record(mDNS *const m) UpdateAutoTunnel6Record(m, info); } +#if !TARGET_OS_EMBEDDED mDNSlocal mDNSBool IPv6AddressIsOnInterface(mDNSv6Addr ipv6Addr, char *ifname) { struct ifaddrs *ifa; @@ -7978,6 +8445,7 @@ mDNSlocal void ProcessConndConfigChanges(mDNS *const m) // If awacsd crashes or exits for some reason, restart it UpdateBTMMRelayConnection(m); } +#endif // !TARGET_OS_EMBEDDED #endif /* APPLE_OSX_mDNSResponder */ mDNSlocal mDNSBool IsAppleNetwork(mDNS *const m) @@ -8027,11 +8495,11 @@ mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m) m->NetworkChanged ? "" : " (no scheduled configuration change)"); m->NetworkChanged = 0; // If we received a network change event and deferred processing, we're now dealing with it - // If we have any NOTREADY IPv6 addresses, wait until they've finished configuring + // If we have *any* TENTATIVE IPv6 addresses, wait until they've finished configuring int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0); if (InfoSocket > 0) { - mDNSBool notready = mDNSfalse; + mDNSBool tentative = mDNSfalse; struct ifaddrs *ifa = myGetIfAddrs(1); while (ifa) { @@ -8046,25 +8514,29 @@ mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m) // We can expect that an IN6_IFF_TENTATIVE address will shortly become ready, // but an IN6_IFF_DUPLICATED address may not. if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1) + { if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE) { LogInfo("*** Network Configuration Change *** IPv6 address %.16a TENTATIVE, will retry", &ifr6.ifr_addr.sin6_addr); - notready = mDNStrue; + tentative = mDNStrue; + // no need to check other interfaces if we already found out that one interface is TENTATIVE + break; } + } } ifa = ifa->ifa_next; } close(InfoSocket); - if (notready) + if (tentative) { mDNS_Lock(m); SetNetworkChanged(m, mDNSPlatformOneSecond / 2); mDNS_Unlock(m); return; } - LogInfo("*** Network Configuration Change *** No IPv6 address NOTREADY, will continue"); + LogInfo("*** Network Configuration Change *** No IPv6 address TENTATIVE, will continue"); } - + mDNSs32 utc = mDNSPlatformUTC(); m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess(); m->SystemSleepOnlyIfWakeOnLAN = SystemSleepOnlyIfWakeOnLAN(); @@ -8073,7 +8545,7 @@ mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m) ClearInactiveInterfaces(m, utc); SetupActiveInterfaces(m, utc); -#if APPLE_OSX_mDNSResponder +#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED mDNS_Lock(m); ProcessConndConfigChanges(m); @@ -8129,14 +8601,19 @@ mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m) NetworkInterfaceInfoOSX *i; for (i = m->p->InterfaceList; i; i = i->next) { - if (!m->SPSSocket) // Not being Sleep Proxy Server; close any open BPF fds + if (!m->SPSSocket) // Not being Sleep Proxy Server; close any open BPF fds { - if (i->BPF_fd >= 0 && CountProxyTargets(m, i, mDNSNULL, mDNSNULL) == 0) CloseBPF(i); + if (i->BPF_fd >= 0 && CountProxyTargets(m, i, mDNSNULL, mDNSNULL) == 0) + CloseBPF(i); } - else // else, we're Sleep Proxy Server; open BPF fds + else // else, we're Sleep Proxy Server; open BPF fds { - if (i->Exists && i->Registered == i && i->ifinfo.McastTxRx && !(i->ifa_flags & IFF_LOOPBACK) && i->BPF_fd == -1) - { LogSPS("%s requesting BPF", i->ifinfo.ifname); i->BPF_fd = -2; mDNSRequestBPF(); } + if (i->Exists && (i->Registered == i) && SPSInterface(i) && i->BPF_fd == -1) + { + LogMsg("%s mDNSMacOSXNetworkChanged: requesting BPF", i->ifinfo.ifname); + i->BPF_fd = -2; + mDNSRequestBPF(); + } } } @@ -8411,6 +8888,8 @@ mDNSlocal void DynamicStoreReconnected(SCDynamicStoreRef store, void *info) mDNS *const m = (mDNS *const)info; (void)store; + KQueueLock(m); // serialize with KQueueLoop() + LogInfo("DynamicStoreReconnected: Reconnected"); // State:/Network/MulticastDNS @@ -8429,15 +8908,14 @@ mDNSlocal void DynamicStoreReconnected(SCDynamicStoreRef store, void *info) mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray); #if APPLE_OSX_mDNSResponder - mDNS_Lock(m); // State:/Network/BackToMyMac UpdateAutoTunnelDomainStatuses(m); - mDNS_Unlock(m); // State:/Network/Interface/en0/SleepProxyServers if (spsStatusDict) CFDictionaryApplyFunction(spsStatusDict, RefreshSPSStatus, NULL); #endif + KQueueUnlock(m, "DynamicStoreReconnected"); } mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m) @@ -8474,7 +8952,7 @@ mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m) #else m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0); if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; } - CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode); + CFRunLoopAddSource(CFRunLoopGetMain(), m->p->StoreRLS, kCFRunLoopDefaultMode); #endif SCDynamicStoreSetDisconnectCallBack(store, DynamicStoreReconnected); m->p->Store = store; @@ -8521,7 +8999,7 @@ mDNSlocal void mDNSSetPacketFilterRules(mDNS *const m, char * ifname, const Reso continue; } - LogInfo("mDNSSetPacketFilterRules: found %s", ARDisplayString(m, rr)); + LogMsg("mDNSSetPacketFilterRules: found %s", ARDisplayString(m, rr)); portArray[count] = rr->resrec.rdata->u.srv.port.NotAnInteger; @@ -8529,13 +9007,21 @@ mDNSlocal void mDNSSetPacketFilterRules(mDNS *const m, char * ifname, const Reso p = rr->resrec.name->c; // Skip to App Protocol - if (p[0]) p += 1 + p[0]; + if (p[0]) + p += 1 + p[0]; // Skip to Transport Protocol - if (p[0]) p += 1 + p[0]; + if (p[0]) + p += 1 + p[0]; - if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp")) protocolArray[count] = IPPROTO_TCP; - else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) protocolArray[count] = IPPROTO_UDP; + if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp")) + { + protocolArray[count] = IPPROTO_TCP; + } + else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) + { + protocolArray[count] = IPPROTO_UDP; + } else { LogMsg("mDNSSetPacketFilterRules: could not determine transport protocol of service"); @@ -8651,12 +9137,8 @@ mDNSlocal mDNSBool allZeroSSTH(struct opaque_presence_indication *op) return mDNStrue; } -// mDNS_Reconfirm_internal() adds 33% to this interval, so the records should -// be removed in 4 seconds. -#define kAWDLReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 3) - // Mark records from this peer for deletion from the cache. -mDNSlocal void removeCachedPeerRecords(mDNS *const m, mDNSu32 ifindex, mDNSAddr *ap) +mDNSlocal void removeCachedPeerRecords(mDNS *const m, mDNSu32 ifindex, mDNSAddr *ap, bool purgeNow) { mDNSu32 slot; CacheGroup *cg; @@ -8680,7 +9162,11 @@ mDNSlocal void removeCachedPeerRecords(mDNS *const m, mDNSu32 ifindex, mDNSAddr { LogInfo("removeCachedPeerRecords: %s %##s marking for deletion", DNSTypeName(cr->resrec.rrtype), cr->resrec.name->c); - mDNS_Reconfirm_internal(m, cr, kAWDLReconfirmTime); + + if (purgeNow) + mDNS_PurgeCacheResourceRecord(m, cr); + else + mDNS_Reconfirm_internal(m, cr, 0); // use default minimum reconfirm time } } } @@ -8705,8 +9191,8 @@ mDNSlocal void nodePresence(mDNS *const m, struct kev_dl_node_presence * p) peerAddr.type = mDNSAddrType_IPv6; peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr; - LogInfo("nodePresence: ssth is all zeroes, delete cached records from this peer"); - removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr); + LogInfo("nodePresence: ssth is all zeroes, reconfirm cached records for this peer"); + removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr, false); } } @@ -8724,8 +9210,8 @@ mDNSlocal void nodeAbsence(mDNS *const m, struct kev_dl_node_absence * p) peerAddr.type = mDNSAddrType_IPv6; peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr; - LogInfo("nodeAbsence: delete cached records from this peer"); - removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr); + LogInfo("nodeAbsence: immediately purge cached records from this peer"); + removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr, true); } mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context) @@ -8922,25 +9408,20 @@ mDNSlocal void PowerOn(mDNS *const m) { mDNSCoreMachineSleep(m, false); // Will set m->SleepState = SleepState_Awake; - // Hold on to a sleep assertion to allow mDNSResponder to perform its maintenance activities. - // This allows for the network link to come up, DHCP to get an address, mDNS to issue queries etc. - // We will clear this assertion as soon as we think the mainenance activities are done. - mDNSPlatformPreventSleep(m, DARK_WAKE_TIME, "mDNSResponder:maintenance"); - if (m->p->WakeAtUTC) { long utc = mDNSPlatformUTC(); mDNSPowerRequest(-1,-1); // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake if (m->p->WakeAtUTC - utc > 30) - { + { LogSPS("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m->p->WakeAtUTC - utc); } - else if (utc - m->p->WakeAtUTC > 30) + else if (utc - m->p->WakeAtUTC > 30) { LogSPS("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc - m->p->WakeAtUTC); } else if (IsAppleTV()) - { + { LogSPS("PowerChanged PowerOn %d seconds late, device is an AppleTV running iOS so not re-sleeping", utc - m->p->WakeAtUTC); } else @@ -8949,6 +9430,12 @@ mDNSlocal void PowerOn(mDNS *const m) m->p->RequestReSleep = mDNS_TimeNow(m) + 20 * mDNSPlatformOneSecond; } } + + // Hold on to a sleep assertion to allow mDNSResponder to perform its maintenance activities. + // This allows for the network link to come up, DHCP to get an address, mDNS to issue queries etc. + // We will clear this assertion as soon as we think the mainenance activities are done. + mDNSPlatformPreventSleep(m, DARK_WAKE_TIME, "mDNSResponder:maintenance"); + } mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument) @@ -8969,7 +9456,7 @@ mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messag if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m); break; case kIOMessageSystemWillNotPowerOff: LogSPS("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260 - case kIOMessageCanSystemSleep: LogSPS("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270 + case kIOMessageCanSystemSleep: LogSPS("PowerChanged kIOMessageCanSystemSleep"); break; // E0000270 case kIOMessageSystemWillSleep: LogSPS("PowerChanged kIOMessageSystemWillSleep"); // E0000280 mDNSCoreMachineSleep(m, true); break; @@ -9004,8 +9491,11 @@ mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messag default: LogSPS("PowerChanged unknown message %X", messageType); break; } - if (messageType == kIOMessageSystemWillSleep) m->p->SleepCookie = (long)messageArgument; - else IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument); + if ((messageType == kIOMessageSystemWillSleep) || (messageType== kIOMessageCanSystemSleep)) + { + m->p->SleepCookie = (long)messageArgument; + IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument); + } KQueueUnlock(m, "PowerChanged Sleep/Wake"); } @@ -9329,93 +9819,77 @@ mDNSlocal void mDNSMacOSXParseEtcHostsLine(mDNS *const m, char *buffer, ssize_t // We might have some extra white spaces at the end for the common case of "1.2.3.4 somehost". // When we parse again below, EtchHostsParseOneName would return -1 and we will end up // doing the right thing. + if (!MakeDomainNameFromDNSNameString(&first, name1)) { LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1); freeaddrinfo(gairesults); return; } + mDNSMacOSXCreateEtcHostsEntry(m, &first, gairesults->ai_addr, mDNSNULL, ifname, auth); + + // /etc/hosts alias discussion: + // // If the /etc/hosts has an entry like this // - // 1.2.3.4 sun star bright + // ip_address cname [aliases...] + // 1.2.3.4 sun star bright // // star and bright are aliases (gethostbyname h_alias should point to these) and sun is the canonical // name (getaddrinfo ai_cannonname and gethostbyname h_name points to "sun") // // To achieve this, we need to add the entry like this: // - // star CNAME bright - // bright CNAME sun // sun A 1.2.3.4 + // star CNAME sun + // bright CNAME sun // - // We store the first name we parsed in "first". Then we parse additional names adding CNAME records - // till we reach the end. When we reach the end, we wrap around and add one final CNAME with the last - // entry and the first entry. Finally, we add the Address (A/AAAA) record. + // We store the first name we parsed in "first" and add the address (A/AAAA) record. + // Then we parse additional names adding CNAME records till we reach the end. + aliasIndex = 0; - while (i <= length) + while (i < length) { - // Parse a name. If there are no names, we need to know whether we - // parsed CNAMEs before or not. If we parsed CNAMEs before, then we - // add a CNAME with the last name and the first name. Otherwise, this - // is same as the common case above where the line has just one name - // but with trailing white spaces. + // Continue to parse additional aliases until we reach end of the line and + // for each "alias" parsed, add a CNAME record where "alias" points to the first "name". + // See also /etc/hosts alias discussion above + i = EtcHostsParseOneName(i + 1, length, buffer, &name2); + if (name2) { + if ((aliasIndex) && (*buffer == *name2)) + break; // break out of the loop if we wrap around + if (!MakeDomainNameFromDNSNameString(&name2d, name2)) { LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name2); freeaddrinfo(gairesults); return; } - aliasIndex++; - } - else if (!aliasIndex) - { - // We have never parsed any aliases. This case happens if there - // is just one name and some extra white spaces at the end. - LogInfo("mDNSMacOSXParseEtcHostsLine: White space at the end of %##s", first.c); - break; - } - else - { - // We have parsed at least one alias before and we reached the end of the line. - // Setup a CNAME for the last name with "first" name as its RDATA - name2d.c[0] = 0; - AssignDomainName(&name2d, &first); - } - - // Don't add a CNAME for the first alias we parse (see the example above). - // As we parse more, we might discover that there are no more aliases, in - // which case we would have set "name2d" to "first" above. We need to add - // the CNAME in that case. - - if (aliasIndex > 1 || SameDomainName(&name2d, &first)) - { // Ignore if it points to itself - if (!SameDomainName(&name1d, &name2d)) + if (!SameDomainName(&first, &name2d)) { - if (!mDNSMacOSXCreateEtcHostsEntry(m, &name1d, mDNSNULL, &name2d, ifname, auth)) + if (!mDNSMacOSXCreateEtcHostsEntry(m, &name2d, mDNSNULL, &first, ifname, auth)) { freeaddrinfo(gairesults); return; } } else - LogMsg("mDNSMacOSXParseEtcHostsLine: Ignoring entry with same names name1 %##s, name2 %##s", name1d.c, name2d.c); + { + LogInfo("mDNSMacOSXParseEtcHostsLine: Ignoring entry with same names first %##s, name2 %##s", first.c, name2d.c); + } + aliasIndex++; + } + else if (!aliasIndex) + { + // We have never parsed any aliases. This case happens if there + // is just one name and some extra white spaces at the end. + LogInfo("mDNSMacOSXParseEtcHostsLine: White space at the end of %##s", first.c); + break; } - - // If we have already wrapped around, we just need to add the A/AAAA record alone - // which is done below - if (SameDomainName(&name2d, &first)) break; - - // Remember the current name so that we can set the CNAME record if we parse one - // more name - name1d.c[0] = 0; - AssignDomainName(&name1d, &name2d); } - // Added all the CNAMEs if any, add the "A/AAAA" record - mDNSMacOSXCreateEtcHostsEntry(m, &first, gairesults->ai_addr, mDNSNULL, ifname, auth); } freeaddrinfo(gairesults); } @@ -9813,9 +10287,9 @@ mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m) if (!EtcHostsDeleteOldEntries(m, &newhosts, mDNStrue)) { LogInfo("mDNSMacOSXUpdateEtcHosts: No work"); + FreeNewHosts(&newhosts); mDNS_Unlock(m); KQueueUnlock(m, "/etc/hosts changed"); - FreeNewHosts(&newhosts); return; } } @@ -9838,10 +10312,9 @@ mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m) // is called back where we do the Registration of the record. This results in RMV followed by ADD which // looks normal. mDNSCoreRestartAddressQueries(m, mDNSfalse, FlushAllCacheRecords, UpdateEtcHosts, &newhosts); + FreeNewHosts(&newhosts); mDNS_Unlock(m); - KQueueUnlock(m, "/etc/hosts changed"); - FreeNewHosts(&newhosts); } #if COMPILER_LIKES_PRAGMA_MARK @@ -9988,7 +10461,6 @@ mDNSlocal void SetupLocalHostRecords(mDNS *const m) mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m) { mStatus err; - m->p->CFRunLoop = CFRunLoopGetCurrent(); char HINFO_SWstring[256] = ""; mDNSMacOSXSystemBuildNumber(HINFO_SWstring); @@ -9997,13 +10469,6 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m) if (err) return err; - DynamicStoreQueue = dispatch_queue_create("com.apple.mDNSResponder.DynamicStoreQueue", NULL); - if (DynamicStoreQueue == NULL) - { - LogMsg("dispatch_queue_create: DynamicStoreQueue NULL!"); - return mStatus_NoMemoryErr; - } - // Store mDNSResponder Platform if (OSXVers) { @@ -10170,7 +10635,7 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m) IOPMConnectionSetDispatchQueue(c, dispatch_get_main_queue()); LogInfo("IOPMConnectionSetDispatchQueue is now running"); #else - iopmerr = IOPMConnectionScheduleWithRunLoop(c, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + iopmerr = IOPMConnectionScheduleWithRunLoop(c, CFRunLoopGetMain(), kCFRunLoopDefaultMode); if (iopmerr) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr); LogInfo("IOPMConnectionScheduleWithRunLoop is now running"); #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */ @@ -10187,7 +10652,7 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m) #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM IONotificationPortSetDispatchQueue(m->p->PowerPortRef, dispatch_get_main_queue()); #else - CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode); + CFRunLoopAddSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode); #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */ } } @@ -10252,7 +10717,7 @@ mDNSexport mStatus mDNSPlatformInit(mDNS *const m) // We only initialize if mDNSCore successfully initialized. if (D2DInitialize) { - D2DStatus ds = D2DInitialize(m->p->CFRunLoop, xD2DServiceCallback, m) ; + D2DStatus ds = D2DInitialize(CFRunLoopGetMain(), xD2DServiceCallback, m) ; if (ds != kD2DSuccess) LogMsg("D2DInitialiize failed: %d", ds); else @@ -10272,7 +10737,7 @@ mDNSexport void mDNSPlatformClose(mDNS *const m) #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM IONotificationPortSetDispatchQueue(m->p->PowerPortRef, NULL); #else - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode); + CFRunLoopRemoveSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode); #endif // According to , a single call // to IORegisterForSystemPower creates *three* objects that need to be disposed individually: @@ -10288,7 +10753,7 @@ mDNSexport void mDNSPlatformClose(mDNS *const m) if (!SCDynamicStoreSetDispatchQueue(m->p->Store, NULL)) LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed"); #else - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode); + CFRunLoopRemoveSource(CFRunLoopGetMain(), m->p->StoreRLS, kCFRunLoopDefaultMode); CFRunLoopSourceInvalidate(m->p->StoreRLS); CFRelease(m->p->StoreRLS); m->p->StoreRLS = NULL; @@ -10299,7 +10764,7 @@ mDNSexport void mDNSPlatformClose(mDNS *const m) if (m->p->PMRLS) { - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->PMRLS, kCFRunLoopDefaultMode); + CFRunLoopRemoveSource(CFRunLoopGetMain(), m->p->PMRLS, kCFRunLoopDefaultMode); CFRunLoopSourceInvalidate(m->p->PMRLS); CFRelease(m->p->PMRLS); m->p->PMRLS = NULL; @@ -10338,8 +10803,7 @@ mDNSexport void mDNSPlatformClose(mDNS *const m) if (AnonymousRacoonConfig) { AnonymousRacoonConfig = mDNSNULL; - LogInfo("mDNSPlatformClose: Deconfiguring autotunnel"); - (void)mDNSConfigureServer(kmDNSDown, mDNSNULL, mDNSNULL); + LogInfo("mDNSPlatformClose: Deconfiguring autotunnel need not be done in mDNSResponder"); } #endif // APPLE_OSX_mDNSResponder } @@ -10416,8 +10880,9 @@ mDNSexport mDNSs32 mDNSPlatformUTC(void) // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; } mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; } -mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { strcpy((char *)dst, (char *)src); } -mDNSexport mDNSu32 mDNSPlatformStrLen ( const void *src) { return(strlen((char*)src)); } +mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { strcpy((char *)dst, (const char *)src); } +mDNSexport mDNSu32 mDNSPlatformStrLCopy( void *dst, const void *src, mDNSu32 dstlen) { return (strlcpy((char *)dst, (const char *)src, dstlen)); } +mDNSexport mDNSu32 mDNSPlatformStrLen ( const void *src) { return(strlen((const char*)src)); } mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); } mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len) == 0); } mDNSexport int mDNSPlatformMemCmp(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len)); } @@ -10513,6 +10978,11 @@ mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID) if (InterfaceID == mDNSInterface_P2P) return mDNStrue; + // mDNSInterface_BLE not considered a D2D interface for the purpose of this + // routine, since it's not implemented via a D2D plugin. + if (InterfaceID == mDNSInterface_BLE) + return mDNSfalse; + if ( (InterfaceID == mDNSInterface_Any) || (InterfaceID == mDNSInterfaceMark) || (InterfaceID == mDNSInterface_LocalOnly) @@ -10536,18 +11006,18 @@ mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID) // Filter records send over P2P (D2D) type interfaces // Note that the terms P2P and D2D are used synonymously in the current code and comments. -mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const NetworkInterfaceInfo *intf) +mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID) { // For an explicit match to a valid interface ID, return true. - if (rr->resrec.InterfaceID == intf->InterfaceID) + if (rr->resrec.InterfaceID == InterfaceID) return mDNStrue; // Only filtering records for D2D type interfaces, return true for all other interface types. - if (!mDNSPlatformInterfaceIsD2D(intf->InterfaceID)) + if (!mDNSPlatformInterfaceIsD2D(InterfaceID)) return mDNStrue; // If it's an AWDL interface the record must be explicitly marked to include AWDL. - if (intf->InterfaceID == AWDLInterfaceID) + if (InterfaceID == AWDLInterfaceID) { if (rr->ARType == AuthRecordAnyIncludeAWDL || rr->ARType == AuthRecordAnyIncludeAWDLandP2P) return mDNStrue; @@ -10600,11 +11070,7 @@ mDNSexport mDNSBool mDNSPlatformValidRecordForQuestion(const ResourceRecord *c return mDNStrue; if ((rr->InterfaceID == AWDLInterfaceID) && !(q->flags & kDNSServiceFlagsIncludeAWDL)) - { - LogInfo("mDNSPlatformValidRecordForQuestion: Record recieved over AWDL not returned for %s %##s query", - DNSTypeName(q->qtype), q->qname.c); return mDNSfalse; - } return mDNStrue; } diff --git a/mDNSResponder/mDNSMacOSX/mDNSMacOSX.h b/mDNSResponder/mDNSMacOSX/mDNSMacOSX.h index 56c0902a..20f7a321 100644 --- a/mDNSResponder/mDNSMacOSX/mDNSMacOSX.h +++ b/mDNSResponder/mDNSMacOSX/mDNSMacOSX.h @@ -31,6 +31,7 @@ extern "C" { #include "mDNSEmbeddedAPI.h" // for domain name structure #include +#include //#define MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM @@ -41,9 +42,7 @@ extern "C" { #if TARGET_OS_EMBEDDED #define NO_SECURITYFRAMEWORK 1 #define NO_CFUSERNOTIFICATION 1 -#include // for IsAppleTV() -#include // for _scprefs_observer_watch() -extern mDNSBool GetmDNSManagedPref(CFStringRef key); +#include // for IsAppleTV() #endif #ifndef NO_SECURITYFRAMEWORK @@ -51,8 +50,6 @@ extern mDNSBool GetmDNSManagedPref(CFStringRef key); #include #endif /* NO_SECURITYFRAMEWORK */ -#define kmDNSResponderServName "com.apple.mDNSResponder" - enum mDNSDynamicStoreSetConfigKey { kmDNSMulticastConfig = 1, @@ -177,7 +174,6 @@ struct mDNS_PlatformSupport_struct mDNSs32 HostNameConflict; // Time we experienced conflict on our link-local host name mDNSs32 KeyChainTimer; - CFRunLoopRef CFRunLoop; SCDynamicStoreRef Store; CFRunLoopSourceRef StoreRLS; CFRunLoopSourceRef PMRLS; diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponder-entitlements.plist b/mDNSResponder/mDNSMacOSX/mDNSResponder-entitlements.plist index 8f7f77d9..ef23e4b6 100644 --- a/mDNSResponder/mDNSMacOSX/mDNSResponder-entitlements.plist +++ b/mDNSResponder/mDNSMacOSX/mDNSResponder-entitlements.plist @@ -10,6 +10,8 @@ com.apple.private.SCNetworkConnection-proxy-user + com.apple.mDNSResponder_Helper + com.apple.private.network.reserved-port com.apple.SystemConfiguration.SCDynamicStore-write-access @@ -24,5 +26,11 @@ com.apple.private.network.awdl.restricted + com.apple.BTServer.allowRestrictedServices + + com.apple.BTServer.appleMfgDataAdvertising + + com.apple.BTServer.appleMfgDataScanner + diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponder.sb b/mDNSResponder/mDNSMacOSX/mDNSResponder.sb index 5c8eedd7..30747491 100644 --- a/mDNSResponder/mDNSMacOSX/mDNSResponder.sb +++ b/mDNSResponder/mDNSMacOSX/mDNSResponder.sb @@ -50,10 +50,12 @@ (global-name "com.apple.CoreServices.coreservicesd") (global-name "com.apple.coreservices.quarantine-resolver") (global-name "com.apple.distributed_notifications.2") + (global-name "com.apple.distributed_notifications@1v3") (global-name "com.apple.lsd.mapdb") (global-name "com.apple.ocspd") (global-name "com.apple.PowerManagement.control") (global-name "com.apple.mDNSResponderHelper") + (global-name "com.apple.mDNSResponder_Helper") (global-name "com.apple.SecurityServer") (global-name "com.apple.SystemConfiguration.configd") (global-name "com.apple.SystemConfiguration.SCNetworkReachability") @@ -110,7 +112,11 @@ (literal "/Library/Security/Trust Settings/Admin.plist") (regex #"^/Library/Preferences/com\.apple\.security\.") (literal "/Library/Preferences/SystemConfiguration/com.apple.PowerManagement.plist") - (literal "/private/var/preferences/SystemConfiguration/preferences.plist")) + (literal "/private/var/preferences/SystemConfiguration/preferences.plist") + (subpath "/System/Library/Preferences/Logging") + (subpath "/AppleInternal/Library/Preferences/Logging") + (subpath "/Library/Preferences/Logging")) + ; For MAC Address (allow system-info (info-type "net.link.addr")) @@ -122,12 +128,6 @@ (deny file-read-data (regex #"^/Library/Keychains/") (with no-log)) (allow file-read-data (literal "/Library/Keychains/System.keychain")) -; Access to mDNSResponder Managed Preferences profile -; instead of using (mobile-preferences-read "com.apple.mDNSResponder") we use the lines below for OSX compatibility -(allow file-read* (literal "/private/var/Managed Preferences/mobile")) -(allow file-read* (literal "/private/var/Library/Preferences/")) -(allow file-read* (literal "/Library/Managed Preferences")) -(allow file-read* (literal "/private/var/Managed Preferences/mobile/com.apple.mDNSResponder.plist")) ; Our Module Directory Services cache (allow file-read-data diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj b/mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj index ef2fecbd..3e6c3fd7 100644 --- a/mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj +++ b/mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj @@ -103,21 +103,12 @@ 215FFAEE124000F900470DE1 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; }; 215FFAEF124000F900470DE1 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; }; 215FFAF0124000F900470DE1 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; }; - 215FFAF1124000F900470DE1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; }; - 215FFAF2124000F900470DE1 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; }; - 215FFAF3124000F900470DE1 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; }; 215FFAF41240011800470DE1 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; }; 215FFAF51240011800470DE1 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; }; 215FFAF61240011800470DE1 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; }; - 215FFAF71240011800470DE1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; }; - 215FFAF81240011800470DE1 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; }; - 215FFAF91240011800470DE1 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; }; 215FFAFA1240013400470DE1 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; }; 215FFAFB1240013400470DE1 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; }; 215FFAFC1240013400470DE1 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; }; - 215FFAFD1240013400470DE1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; }; - 215FFAFE1240013400470DE1 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; }; - 215FFAFF1240013400470DE1 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; }; 216D9ACE1720C9F5008066E1 /* uDNSPathEvalulation.c in Sources */ = {isa = PBXBuildFile; fileRef = 216D9ACD1720C9F5008066E1 /* uDNSPathEvalulation.c */; }; 218E8E51156D8C0300720DA0 /* dnsproxy.c in Sources */ = {isa = PBXBuildFile; fileRef = 218E8E4F156D8C0300720DA0 /* dnsproxy.c */; }; 218E8E53156D8C0300720DA0 /* dnsproxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 218E8E50156D8C0300720DA0 /* dnsproxy.h */; }; @@ -133,15 +124,22 @@ 21F51DC11B3541940070B05C /* com.apple.mDNSResponder.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21F51DBF1B35412D0070B05C /* com.apple.mDNSResponder.plist */; }; 21F51DC31B3541F50070B05C /* com.apple.mDNSResponderHelper.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21F51DBE1B3541030070B05C /* com.apple.mDNSResponderHelper.plist */; }; 21F51DC51B3542210070B05C /* com.apple.dnsextd.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21F51DBD1B3540DB0070B05C /* com.apple.dnsextd.plist */; }; + 222A3C5B1C1B75F2003A6FFD /* DNSServiceDiscoveryDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 222A3C581C1B743B003A6FFD /* DNSServiceDiscoveryDefines.h */; }; + 222A3C6A1C1B7777003A6FFD /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = 222A3C561C1B7415003A6FFD /* DNSServiceDiscovery.c */; }; + 222A3C6B1C1B7778003A6FFD /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = 222A3C561C1B7415003A6FFD /* DNSServiceDiscovery.c */; }; + 222A3C6C1C1B7779003A6FFD /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = 222A3C561C1B7415003A6FFD /* DNSServiceDiscovery.c */; }; + 222A3C6D1C1B777A003A6FFD /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = 222A3C561C1B7415003A6FFD /* DNSServiceDiscovery.c */; }; + 222A3C6E1C1B777B003A6FFD /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = 222A3C561C1B7415003A6FFD /* DNSServiceDiscovery.c */; }; + 222A3C6F1C1B777C003A6FFD /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = 222A3C561C1B7415003A6FFD /* DNSServiceDiscovery.c */; }; + 2243AE391C90AECF0079023E /* CoreBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2243AE381C90AECF0079023E /* CoreBluetooth.framework */; }; + 22448EA31C90A7BE004F25CC /* BLE.c in Sources */ = {isa = PBXBuildFile; fileRef = 22448EA11C90A7B5004F25CC /* BLE.c */; }; + 22448EA41C90A7CB004F25CC /* BLE.h in Headers */ = {isa = PBXBuildFile; fileRef = 22448EA21C90A7B5004F25CC /* BLE.h */; }; + 22448EA71C90A837004F25CC /* coreBLE.h in Headers */ = {isa = PBXBuildFile; fileRef = 22448EA51C90A82D004F25CC /* coreBLE.h */; }; + 227687F31C90AD580019382D /* coreBLE.m in Sources */ = {isa = PBXBuildFile; fileRef = 22448EA61C90A82D004F25CC /* coreBLE.m */; }; 2E0405F50C3195F700F13B59 /* helper.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405F40C3195F700F13B59 /* helper.c */; }; - 2E0405F60C31961100F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; settings = {ATTRIBUTES = (Client, Server, ); COMPILER_FLAGS = "-Wno-error"; }; }; 2E0406150C3197CB00F13B59 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E0406140C3197CB00F13B59 /* libbsm.dylib */; }; - 2E04061F0C3198B700F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; }; 2E04070A0C31EEEC00F13B59 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; }; 2E04070B0C31EEEC00F13B59 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; }; - 2E3552900C3A95C100CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; }; - 2E3552920C3A95C100CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; }; - 2E35529D0C3A9E7600CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; }; 2E35529E0C3A9E7600CA1CB7 /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; }; 2E35529F0C3A9E7600CA1CB7 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; }; 2E4D9B050C38C19500480551 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; }; @@ -152,35 +150,39 @@ 2E96A51D0C39BDAC0087C4D2 /* helper-main.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E0406CA0C31E9AD00F13B59 /* helper-main.c */; }; 2E96A5260C39BE480087C4D2 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; }; 2E96A5320C39C1A50087C4D2 /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; }; - 2EAE955A0C31F4D30021F738 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; }; 2EC8F8EC0C39CCAC003C9C48 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; }; 2ECC11A60C4FEC3800CB1885 /* helpermsg-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */; }; 2ECC11A80C4FEC3800CB1885 /* helpermsg-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */; }; 2EDC5E730C39EA640092701B /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; }; 2EDC5E750C39EA640092701B /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; }; + 371D0FBC1BF545FA00E5DB26 /* InterfaceTest.c in Sources */ = {isa = PBXBuildFile; fileRef = 371D0FBA1BF545FA00E5DB26 /* InterfaceTest.c */; }; + 371D0FBF1BF666EB00E5DB26 /* ResourceRecordTest.c in Sources */ = {isa = PBXBuildFile; fileRef = 371D0FBD1BF666EB00E5DB26 /* ResourceRecordTest.c */; }; + 373202101BAB4444007DE806 /* DNSMessageTest.c in Sources */ = {isa = PBXBuildFile; fileRef = 3732020F1BAB4349007DE806 /* DNSMessageTest.c */; }; + 3771F67D1BA387DD0072355E /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 37DDE9351BA386E70092AC61 /* main.c */; }; + 37DDE9331BA383D30092AC61 /* unittest.c in Sources */ = {isa = PBXBuildFile; fileRef = 37DDE9271BA3825C0092AC61 /* unittest.c */; }; + 37FEBD581BC789AA00638EA4 /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; }; 4A7B9E8014FDA25000B84CC1 /* mDNSResponder.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4A7B9E7E14FDA1BB00B84CC1 /* mDNSResponder.plist */; }; 4A7B9E8214FDA26C00B84CC1 /* mDNSResponder.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4A7B9E7C14FDA19F00B84CC1 /* mDNSResponder.txt */; }; 4AAE0C9A0C68EA81003882A5 /* mDNSResponderHelper.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */; }; 4BD2B63A134FE09F002B96D5 /* P2PPacketFilter.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BD2B638134FE09F002B96D5 /* P2PPacketFilter.c */; }; 4BD2B63B134FE09F002B96D5 /* P2PPacketFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BD2B639134FE09F002B96D5 /* P2PPacketFilter.h */; }; + 729DF4601CD40630005ECF70 /* com.apple.mDNSResponder.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 729DF45F1CD40630005ECF70 /* com.apple.mDNSResponder.plist */; }; 72FB5467166D5FCA0090B2D9 /* dnsctl.c in Sources */ = {isa = PBXBuildFile; fileRef = 72FB545A166D5F960090B2D9 /* dnsctl.c */; }; 8415A6571897109000BDBA26 /* libdns_services.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8415A6561897109000BDBA26 /* libdns_services.dylib */; }; - 8418673E15AB8C2D00BB7F70 /* com.apple.networking.mDNSResponder in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8418673A15AB8B6900BB7F70 /* com.apple.networking.mDNSResponder */; }; + 8417375C1B967D37000CD5C2 /* dnsctl_server.c in Sources */ = {isa = PBXBuildFile; fileRef = 8417375A1B967CBE000CD5C2 /* dnsctl_server.c */; }; 848DA5C7165477E000D2E8B4 /* xpc_services.c in Sources */ = {isa = PBXBuildFile; fileRef = 848DA5C6165477E000D2E8B4 /* xpc_services.c */; }; 848DA5CA165477EB00D2E8B4 /* xpc_services.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5C9165477EB00D2E8B4 /* xpc_services.h */; }; 848DA5D616547F7200D2E8B4 /* dns_xpc.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5D516547F7200D2E8B4 /* dns_xpc.h */; }; 84C5B33C166553F100C324A8 /* dns_services.c in Sources */ = {isa = PBXBuildFile; fileRef = 84C5B339166553AF00C324A8 /* dns_services.c */; }; 84F4C090188F050200D1E1DE /* dns_services.h in Headers */ = {isa = PBXBuildFile; fileRef = 84F4C08F188F04CF00D1E1DE /* dns_services.h */; settings = {ATTRIBUTES = (Private, ); }; }; BD03E88D1AD31278005E8A81 /* SymptomReporter.c in Sources */ = {isa = PBXBuildFile; fileRef = BD03E88C1AD31278005E8A81 /* SymptomReporter.c */; }; - BD2806081C40775600455151 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BD2806071C40775600455151 /* Foundation.framework */; }; - BD64FE9C1C40762F0040EAB3 /* Metrics.h in Headers */ = {isa = PBXBuildFile; fileRef = BD64FE9A1C40762F0040EAB3 /* Metrics.h */; }; - BD64FE9D1C40762F0040EAB3 /* Metrics.m in Sources */ = {isa = PBXBuildFile; fileRef = BD64FE9B1C40762F0040EAB3 /* Metrics.m */; }; + BDA3F08A1C48DB920054FB4B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDA3F0891C48DB910054FB4B /* Foundation.framework */; }; + BDA3F08D1C48DBEA0054FB4B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDA3F0891C48DB910054FB4B /* Foundation.framework */; }; + BDA3F08E1C48DCA50054FB4B /* Metrics.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA3F0871C48DB6D0054FB4B /* Metrics.h */; }; + BDA3F08F1C48DCA50054FB4B /* Metrics.m in Sources */ = {isa = PBXBuildFile; fileRef = BDA3F0881C48DB6D0054FB4B /* Metrics.m */; }; BDA9A7881B3A924C00523835 /* dns_sd_private.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA9A7871B3A923600523835 /* dns_sd_private.h */; settings = {ATTRIBUTES = (Private, ); }; }; BDA9A7891B3A92A500523835 /* dns_sd_private.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA9A7871B3A923600523835 /* dns_sd_private.h */; settings = {ATTRIBUTES = (Private, ); }; }; - D284BE530ADD80740027CCDF /* DNSServiceDiscoveryDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */; }; D284BE540ADD80740027CCDF /* dnssd_ipc.h in Headers */ = {isa = PBXBuildFile; fileRef = F5E11B5B04A28126019798ED /* dnssd_ipc.h */; }; - D284BE560ADD80740027CCDF /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Client, ); }; }; - D284BE570ADD80740027CCDF /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; settings = {ATTRIBUTES = (Server, ); }; }; D284BE580ADD80740027CCDF /* mDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBE9022EAF5A00000109 /* mDNS.c */; }; D284BE590ADD80740027CCDF /* uDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F70587CEF6001880B3 /* uDNS.c */; }; D284BE5A0ADD80740027CCDF /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; }; @@ -216,7 +218,6 @@ D284BED20ADD80A20027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; }; D284BED50ADD80A20027CCDF /* dnsextd.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FFF4F63A06CFE4DD00459EFD /* dnsextd.8 */; }; D284BEDE0ADD80A70027CCDF /* ddnswriteconfig.m in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAF07B43CBA00B88D48 /* ddnswriteconfig.m */; }; - D284BEE00ADD80A70027CCDF /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FFFB0DB407B43D2700B88D48 /* Foundation.framework */; }; D284BEE10ADD80A70027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; }; D284BEE20ADD80A70027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; }; D284BEE30ADD80A70027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; }; @@ -241,23 +242,15 @@ D284BF040ADD80B00027CCDF /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF2609FA07B4433800CE10E5 /* Cocoa.framework */; }; D284BF050ADD80B00027CCDF /* PreferencePanes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */; }; D284BF060ADD80B00027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; }; + FF3C72AA1CE3E62200CDF81E /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FF3C72A91CE3E62200CDF81E /* libicucore.dylib */; }; FFA572330AF18F1C0055A0F1 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; }; FFA572340AF18F1C0055A0F1 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; }; FFA572350AF18F1C0055A0F1 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; }; FFA5723F0AF18F450055A0F1 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; }; FFA572400AF18F450055A0F1 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; }; FFA572410AF18F450055A0F1 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; }; - FFA572490AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; }; - FFA5724A0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; }; - FFA5724B0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; }; FFAE66F0105F0CD900162116 /* ddnswriteconfig in Resources */ = {isa = PBXBuildFile; fileRef = D284BEE80ADD80A70027CCDF /* ddnswriteconfig */; }; FFB437150EB165BD00E17C68 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; }; - FFC22AA20B00F42A00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; }; - FFC22AA30B00F42B00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; }; - FFC22AA40B00F42C00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; }; - FFC22AA50B00F43000BAB070 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; }; - FFC22AA60B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; }; - FFC22AA70B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; }; FFD52A9E1AF858DD00CAD3EC /* CryptoAlg.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A57F4B145B2AE100939099 /* CryptoAlg.h */; }; FFF589B70E37F66800EF515C /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; }; FFF589C10E37F67E00EF515C /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; }; @@ -528,10 +521,10 @@ 8418673D15AB8BFF00BB7F70 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; - dstPath = /private/etc/asl/; + dstPath = /System/Library/Preferences/Logging/Subsystems; dstSubfolderSpec = 0; files = ( - 8418673E15AB8C2D00BB7F70 /* com.apple.networking.mDNSResponder in CopyFiles */, + 729DF4601CD40630005ECF70 /* com.apple.mDNSResponder.plist in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 1; }; @@ -610,17 +603,35 @@ 21F51DBD1B3540DB0070B05C /* com.apple.dnsextd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.dnsextd.plist; sourceTree = ""; }; 21F51DBE1B3541030070B05C /* com.apple.mDNSResponderHelper.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.mDNSResponderHelper.plist; sourceTree = ""; }; 21F51DBF1B35412D0070B05C /* com.apple.mDNSResponder.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.mDNSResponder.plist; sourceTree = ""; }; - 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.mig; path = helpermsg.defs; sourceTree = ""; }; + 222A3C561C1B7415003A6FFD /* DNSServiceDiscovery.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = DNSServiceDiscovery.c; sourceTree = ""; }; + 222A3C571C1B743B003A6FFD /* DNSServiceDiscovery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSServiceDiscovery.h; sourceTree = ""; }; + 222A3C581C1B743B003A6FFD /* DNSServiceDiscoveryDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSServiceDiscoveryDefines.h; sourceTree = ""; }; + 2243AE381C90AECF0079023E /* CoreBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreBluetooth.framework; path = System/Library/Frameworks/CoreBluetooth.framework; sourceTree = SDKROOT; }; + 22448EA11C90A7B5004F25CC /* BLE.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = BLE.c; sourceTree = ""; }; + 22448EA21C90A7B5004F25CC /* BLE.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BLE.h; sourceTree = ""; }; + 22448EA51C90A82D004F25CC /* coreBLE.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = coreBLE.h; sourceTree = ""; }; + 22448EA61C90A82D004F25CC /* coreBLE.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = coreBLE.m; sourceTree = ""; }; 2E0405F00C31955500F13B59 /* mDNSResponderHelper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSResponderHelper; sourceTree = BUILT_PRODUCTS_DIR; }; 2E0405F40C3195F700F13B59 /* helper.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = helper.c; sourceTree = ""; }; 2E0406140C3197CB00F13B59 /* libbsm.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbsm.dylib; path = /usr/lib/libbsm.dylib; sourceTree = ""; }; 2E0406CA0C31E9AD00F13B59 /* helper-main.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = "helper-main.c"; sourceTree = ""; }; - 2E35528F0C3A95C100CA1CB7 /* helper-error.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "helper-error.h"; sourceTree = ""; }; 2E8165F60C59835F00485EB2 /* libipsec.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libipsec.dylib; path = /usr/lib/libipsec.dylib; sourceTree = ""; }; 2E96A5250C39BE480087C4D2 /* helper.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = helper.h; sourceTree = ""; }; 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "helper-stubs.c"; sourceTree = ""; }; 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "helpermsg-types.h"; sourceTree = ""; }; 2EDC5E720C39EA640092701B /* helper-server.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "helper-server.h"; sourceTree = ""; }; + 371D0FBA1BF545FA00E5DB26 /* InterfaceTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = InterfaceTest.c; path = ../unittests/InterfaceTest.c; sourceTree = ""; }; + 371D0FBB1BF545FA00E5DB26 /* InterfaceTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InterfaceTest.h; path = ../unittests/InterfaceTest.h; sourceTree = ""; }; + 371D0FBD1BF666EB00E5DB26 /* ResourceRecordTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ResourceRecordTest.c; path = ../unittests/ResourceRecordTest.c; sourceTree = ""; }; + 371D0FBE1BF666EB00E5DB26 /* ResourceRecordTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResourceRecordTest.h; path = ../unittests/ResourceRecordTest.h; sourceTree = ""; }; + 3732020F1BAB4349007DE806 /* DNSMessageTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = DNSMessageTest.c; path = ../unittests/DNSMessageTest.c; sourceTree = ""; }; + 373202111BAB63E8007DE806 /* DNSMessageTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DNSMessageTest.h; path = ../unittests/DNSMessageTest.h; sourceTree = ""; }; + 37AF802A1BF699AF00D657F6 /* DomainNameTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = DomainNameTest.c; path = ../unittests/DomainNameTest.c; sourceTree = ""; }; + 37AF802B1BF699AF00D657F6 /* DomainNameTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DomainNameTest.h; path = ../unittests/DomainNameTest.h; sourceTree = ""; }; + 37DDE9271BA3825C0092AC61 /* unittest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unittest.c; path = ../unittests/unittest.c; sourceTree = ""; }; + 37DDE9281BA382670092AC61 /* unittest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = unittest.h; path = ../unittests/unittest.h; sourceTree = ""; }; + 37DDE92D1BA383610092AC61 /* unittests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = unittests; sourceTree = BUILT_PRODUCTS_DIR; }; + 37DDE9351BA386E70092AC61 /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = ../unittests/main.c; sourceTree = ""; }; 4A2E69DD0F5475A3004A87B0 /* uds_daemon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = uds_daemon.h; path = ../mDNSShared/uds_daemon.h; sourceTree = SOURCE_ROOT; }; 4A3600DF0F34F8CD00453EFB /* DeviceToDeviceManager.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DeviceToDeviceManager.framework; path = /System/Library/PrivateFrameworks/DeviceToDeviceManager.framework; sourceTree = ""; }; 4A7B9E7C14FDA19F00B84CC1 /* mDNSResponder.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = mDNSResponder.txt; sourceTree = ""; }; @@ -635,12 +646,10 @@ 654BE64F02B63B93000001D1 /* mDNSEmbeddedAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mDNSEmbeddedAPI.h; path = ../mDNSCore/mDNSEmbeddedAPI.h; sourceTree = ""; }; 654BE65002B63B93000001D1 /* mDNSDebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mDNSDebug.h; path = ../mDNSCore/mDNSDebug.h; sourceTree = ""; }; 65713D46025A293200000109 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = /System/Library/Frameworks/SystemConfiguration.framework; sourceTree = ""; }; - 6575FBE9022EAF5A00000109 /* mDNS.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = mDNS.c; path = ../mDNSCore/mDNS.c; sourceTree = ""; tabWidth = 4; usesTabs = 1; }; - 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = mDNSMacOSX.c; sourceTree = ""; tabWidth = 4; usesTabs = 1; }; - 6575FBEC022EAF7200000109 /* daemon.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = daemon.c; sourceTree = ""; tabWidth = 4; usesTabs = 1; }; - 6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSServiceDiscoveryDefines.h; sourceTree = ""; }; - 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; path = DNSServiceDiscoveryReply.defs; sourceTree = ""; }; - 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; path = DNSServiceDiscoveryRequest.defs; sourceTree = ""; }; + 6575FBE9022EAF5A00000109 /* mDNS.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = mDNS.c; path = ../mDNSCore/mDNS.c; sourceTree = ""; tabWidth = 4; usesTabs = 0; }; + 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = mDNSMacOSX.c; sourceTree = ""; tabWidth = 4; usesTabs = 0; }; + 6575FBEC022EAF7200000109 /* daemon.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = daemon.c; sourceTree = ""; tabWidth = 4; usesTabs = 0; }; + 729DF45F1CD40630005ECF70 /* com.apple.mDNSResponder.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = com.apple.mDNSResponder.plist; path = Private/com.apple.mDNSResponder.plist; sourceTree = ""; }; 72FB545A166D5F960090B2D9 /* dnsctl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dnsctl.c; path = ../Clients/dnsctl.c; sourceTree = ""; }; 72FB545F166D5FB00090B2D9 /* dnsctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dnsctl; sourceTree = BUILT_PRODUCTS_DIR; }; 7F18A9F60587CEF6001880B3 /* DNSCommon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = DNSCommon.c; path = ../mDNSCore/DNSCommon.c; sourceTree = SOURCE_ROOT; }; @@ -649,8 +658,7 @@ 7F869685066EE02400D2A2DC /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = ""; }; 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = LegacyNATTraversal.c; sourceTree = SOURCE_ROOT; }; 8415A6561897109000BDBA26 /* libdns_services.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libdns_services.dylib; path = /usr/lib/libdns_services.dylib; sourceTree = ""; }; - 8418673A15AB8B6900BB7F70 /* com.apple.networking.mDNSResponder */ = {isa = PBXFileReference; lastKnownFileType = text; path = com.apple.networking.mDNSResponder; sourceTree = ""; }; - 8418673C15AB8B8000BB7F70 /* mDNSResponderLogging.mobileconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = mDNSResponderLogging.mobileconfig; sourceTree = ""; }; + 8417375A1B967CBE000CD5C2 /* dnsctl_server.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnsctl_server.c; path = Private/dnsctl_server.c; sourceTree = ""; }; 848DA5C6165477E000D2E8B4 /* xpc_services.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = xpc_services.c; path = Private/xpc_services.c; sourceTree = ""; }; 848DA5C9165477EB00D2E8B4 /* xpc_services.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = xpc_services.h; path = Private/xpc_services.h; sourceTree = ""; }; 848DA5D516547F7200D2E8B4 /* dns_xpc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dns_xpc.h; path = Private/dns_xpc.h; sourceTree = ""; }; @@ -658,10 +666,9 @@ 84C5B339166553AF00C324A8 /* dns_services.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dns_services.c; path = Private/dns_services.c; sourceTree = ""; }; 84F4C08F188F04CF00D1E1DE /* dns_services.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dns_services.h; path = Private/dns_services.h; sourceTree = ""; }; BD03E88C1AD31278005E8A81 /* SymptomReporter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SymptomReporter.c; sourceTree = ""; }; - BD2806071C40775600455151 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - BD64FE9A1C40762F0040EAB3 /* Metrics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Metrics.h; sourceTree = ""; }; - BD64FE9B1C40762F0040EAB3 /* Metrics.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Metrics.m; sourceTree = ""; }; - BD64FE9E1C4076B40040EAB3 /* WirelessDiagnostics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WirelessDiagnostics.framework; path = System/Library/PrivateFrameworks/WirelessDiagnostics.framework; sourceTree = SDKROOT; }; + BDA3F0871C48DB6D0054FB4B /* Metrics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Metrics.h; sourceTree = ""; }; + BDA3F0881C48DB6D0054FB4B /* Metrics.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Metrics.m; sourceTree = ""; }; + BDA3F0891C48DB910054FB4B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; BDA9A7871B3A923600523835 /* dns_sd_private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dns_sd_private.h; path = Private/dns_sd_private.h; sourceTree = ""; }; D284BE730ADD80740027CCDF /* mDNSResponder */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSResponder; sourceTree = BUILT_PRODUCTS_DIR; }; D284BEB00ADD80920027CCDF /* dns-sd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "dns-sd"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -685,14 +692,14 @@ DB2CC4680662DFF500335AB3 /* JavaVM.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaVM.framework; path = /System/Library/Frameworks/JavaVM.framework; sourceTree = ""; }; DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mDNSDebug.c; path = ../mDNSShared/mDNSDebug.c; sourceTree = SOURCE_ROOT; }; DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = GenLinkedList.c; path = ../mDNSShared/GenLinkedList.c; sourceTree = SOURCE_ROOT; }; - F525E72804AA167501F1CF4D /* uds_daemon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = uds_daemon.c; path = ../mDNSShared/uds_daemon.c; sourceTree = SOURCE_ROOT; }; + F525E72804AA167501F1CF4D /* uds_daemon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = uds_daemon.c; path = ../mDNSShared/uds_daemon.c; sourceTree = SOURCE_ROOT; usesTabs = 0; }; F5E11B5A04A28126019798ED /* dnssd_ipc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssd_ipc.c; path = ../mDNSShared/dnssd_ipc.c; sourceTree = SOURCE_ROOT; }; F5E11B5B04A28126019798ED /* dnssd_ipc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dnssd_ipc.h; path = ../mDNSShared/dnssd_ipc.h; sourceTree = SOURCE_ROOT; }; FF08480607CEB8E800AE6769 /* inprogress.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = inprogress.tiff; path = PreferencePane/Artwork/inprogress.tiff; sourceTree = SOURCE_ROOT; }; FF13FFEA0A5DA44A00897C81 /* dnsextd_lexer.l */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.lex; name = dnsextd_lexer.l; path = ../mDNSShared/dnsextd_lexer.l; sourceTree = SOURCE_ROOT; }; FF13FFEC0A5DA45500897C81 /* dnsextd_parser.y */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.yacc; name = dnsextd_parser.y; path = ../mDNSShared/dnsextd_parser.y; sourceTree = SOURCE_ROOT; }; FF1C919D07021D77001048AB /* dns-sd.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = "dns-sd.1"; path = "../mDNSShared/dns-sd.1"; sourceTree = SOURCE_ROOT; }; - FF1C919F07021E3F001048AB /* dns-sd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "dns-sd.c"; path = "../Clients/dns-sd.c"; sourceTree = SOURCE_ROOT; }; + FF1C919F07021E3F001048AB /* dns-sd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "dns-sd.c"; path = "../Clients/dns-sd.c"; sourceTree = SOURCE_ROOT; usesTabs = 0; }; FF25794606C9A8BF00376F7B /* dnsextd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnsextd.c; path = ../mDNSShared/dnsextd.c; sourceTree = SOURCE_ROOT; }; FF2609FA07B4433800CE10E5 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PreferencePanes.framework; path = /System/Library/Frameworks/PreferencePanes.framework; sourceTree = ""; }; @@ -710,14 +717,13 @@ FF2C5FB00A48B8680066DA11 /* DNSSDRecordRegistrar.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSDRecordRegistrar.java; path = ../mDNSShared/Java/DNSSDRecordRegistrar.java; sourceTree = SOURCE_ROOT; }; FF2C5FB20A48B86E0066DA11 /* RegisterRecordListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = RegisterRecordListener.java; path = ../mDNSShared/Java/RegisterRecordListener.java; sourceTree = SOURCE_ROOT; }; FF354EB108516C63007C00E1 /* installtool */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; name = installtool; path = PreferencePane/installtool; sourceTree = SOURCE_ROOT; }; + FF3C72A91CE3E62200CDF81E /* libicucore.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libicucore.dylib; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.Internal.sdk/usr/lib/libicucore.dylib; sourceTree = DEVELOPER_DIR; }; FF485D5105632E0000130380 /* mDNSResponder.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = mDNSResponder.8; path = ../mDNSShared/mDNSResponder.8; sourceTree = SOURCE_ROOT; }; FF5852100DD27BD300862BDF /* ClientCommon.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = ClientCommon.c; path = ../Clients/ClientCommon.c; sourceTree = SOURCE_ROOT; }; FF85880B0BD599F40080D89F /* mDNSResponder.sb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mDNSResponder.sb; sourceTree = SOURCE_ROOT; }; FFA572390AF18F1C0055A0F1 /* libsystem_dnssd_debug.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libsystem_dnssd_debug.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; FFA572450AF18F450055A0F1 /* libsystem_dnssd_profile.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libsystem_dnssd_profile.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; - FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = DNSServiceDiscovery.c; sourceTree = ""; }; - FFA572600AF1908D0055A0F1 /* DNSServiceDiscovery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSServiceDiscovery.h; sourceTree = ""; }; - FFA572630AF190C20055A0F1 /* dns_sd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dns_sd.h; path = ../mDNSShared/dns_sd.h; sourceTree = SOURCE_ROOT; }; + FFA572630AF190C20055A0F1 /* dns_sd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dns_sd.h; path = ../mDNSShared/dns_sd.h; sourceTree = SOURCE_ROOT; usesTabs = 0; }; FFB765840AEED9C700583A2C /* libsystem_dnssd.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libsystem_dnssd.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; FFCB6D73075D539900B8AF62 /* PlatformCommon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = PlatformCommon.c; path = ../mDNSShared/PlatformCommon.c; sourceTree = SOURCE_ROOT; }; FFE6935007C2CA7F00283007 /* ConfigurationAuthority.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ConfigurationAuthority.h; path = PreferencePane/ConfigurationAuthority.h; sourceTree = SOURCE_ROOT; }; @@ -730,7 +736,6 @@ FFFB0DAD07B43CBA00B88D48 /* PrivilegedOperations.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = PrivilegedOperations.c; sourceTree = ""; }; FFFB0DAE07B43CBA00B88D48 /* ConfigurationAuthority.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ConfigurationAuthority.c; sourceTree = ""; }; FFFB0DAF07B43CBA00B88D48 /* ddnswriteconfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ddnswriteconfig.m; sourceTree = ""; }; - FFFB0DB407B43D2700B88D48 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; FFFF8F800C3307AC00722979 /* dnsextd.conf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = dnsextd.conf; path = ../mDNSShared/dnsextd.conf; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ @@ -776,6 +781,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 37DDE92A1BA383610092AC61 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 72FB545C166D5FB00090B2D9 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -795,8 +807,10 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 2243AE391C90AECF0079023E /* CoreBluetooth.framework in Frameworks */, D284BE650ADD80740027CCDF /* CoreFoundation.framework in Frameworks */, - BD2806081C40775600455151 /* Foundation.framework in Frameworks */, + FF3C72AA1CE3E62200CDF81E /* libicucore.dylib in Frameworks */, + BDA3F08A1C48DB920054FB4B /* Foundation.framework in Frameworks */, D284BE670ADD80740027CCDF /* IOKit.framework in Frameworks */, D284BE680ADD80740027CCDF /* Security.framework in Frameworks */, D284BE660ADD80740027CCDF /* SystemConfiguration.framework in Frameworks */, @@ -835,7 +849,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - D284BEE00ADD80A70027CCDF /* Foundation.framework in Frameworks */, + BDA3F08D1C48DBEA0054FB4B /* Foundation.framework in Frameworks */, D284BEE10ADD80A70027CCDF /* Security.framework in Frameworks */, D284BEE20ADD80A70027CCDF /* SystemConfiguration.framework in Frameworks */, D284BEE30ADD80A70027CCDF /* CoreFoundation.framework in Frameworks */, @@ -881,14 +895,16 @@ 08FB7794FE84155DC02AAC07 /* mDNSResponder */ = { isa = PBXGroup; children = ( + 2243AE381C90AECF0079023E /* CoreBluetooth.framework */, + 729DF45F1CD40630005ECF70 /* com.apple.mDNSResponder.plist */, 08FB7795FE84155DC02AAC07 /* mDNS Server Sources */, 6575FC1F022EB78C00000109 /* Command-Line Clients */, 213FB20912028902002B3A08 /* Bonjour Events Plugin */, - 6575FBFE022EAFA800000109 /* MIG files */, DB2CC4420662DCE500335AB3 /* Java Support */, FFFB0DA407B43BED00B88D48 /* PreferencePane */, 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */, 19C28FBDFE9D53C911CA2CBB /* Products */, + 37DDE9241BA382280092AC61 /* Unit Tests */, ); name = mDNSResponder; sourceTree = ""; @@ -896,12 +912,18 @@ 08FB7795FE84155DC02AAC07 /* mDNS Server Sources */ = { isa = PBXGroup; children = ( + 22448EA51C90A82D004F25CC /* coreBLE.h */, + 22448EA61C90A82D004F25CC /* coreBLE.m */, + 22448EA11C90A7B5004F25CC /* BLE.c */, + 22448EA21C90A7B5004F25CC /* BLE.h */, + 222A3C571C1B743B003A6FFD /* DNSServiceDiscovery.h */, + 222A3C581C1B743B003A6FFD /* DNSServiceDiscoveryDefines.h */, + 222A3C561C1B7415003A6FFD /* DNSServiceDiscovery.c */, 21DD8FBD161E9A250033C8F8 /* anonymous.c */, 21DD8FBE161E9A250033C8F8 /* anonymous.h */, 21F51DBD1B3540DB0070B05C /* com.apple.dnsextd.plist */, 21F51DBF1B35412D0070B05C /* com.apple.mDNSResponder.plist */, 21F51DBE1B3541030070B05C /* com.apple.mDNSResponderHelper.plist */, - 8418673A15AB8B6900BB7F70 /* com.apple.networking.mDNSResponder */, 21A57F4A145B2AE100939099 /* CryptoAlg.c */, 21A57F4B145B2AE100939099 /* CryptoAlg.h */, 21A57F51145B2B1400939099 /* CryptoSupport.c */, @@ -930,11 +952,8 @@ 2124FA2F1471E9B50021D7BB /* dnssec.h */, 21070E5D16486B9000A69507 /* DNSSECSupport.c */, 21070E5E16486B9000A69507 /* DNSSECSupport.h */, - FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */, - FFA572600AF1908D0055A0F1 /* DNSServiceDiscovery.h */, DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */, 4ADB5F230F6AB9F400B95BF3 /* helper-entitlements.plist */, - 2E35528F0C3A95C100CA1CB7 /* helper-error.h */, 2E0406CA0C31E9AD00F13B59 /* helper-main.c */, 2EDC5E720C39EA640092701B /* helper-server.h */, 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */, @@ -955,9 +974,8 @@ FF85880B0BD599F40080D89F /* mDNSResponder.sb */, 4A7B9E7C14FDA19F00B84CC1 /* mDNSResponder.txt */, 4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */, - 8418673C15AB8B8000BB7F70 /* mDNSResponderLogging.mobileconfig */, - BD64FE9A1C40762F0040EAB3 /* Metrics.h */, - BD64FE9B1C40762F0040EAB3 /* Metrics.m */, + BDA3F0871C48DB6D0054FB4B /* Metrics.h */, + BDA3F0881C48DB6D0054FB4B /* Metrics.m */, 2124FA321471E9DE0021D7BB /* nsec.c */, 2124FA2B1471E98C0021D7BB /* nsec.h */, 2127A47515C3C7B900A857FC /* nsec3.c */, @@ -971,6 +989,7 @@ 216D9ACD1720C9F5008066E1 /* uDNSPathEvalulation.c */, F525E72804AA167501F1CF4D /* uds_daemon.c */, 4A2E69DD0F5475A3004A87B0 /* uds_daemon.h */, + 8417375A1B967CBE000CD5C2 /* dnsctl_server.c */, 848DA5C6165477E000D2E8B4 /* xpc_services.c */, 848DA5C9165477EB00D2E8B4 /* xpc_services.h */, ); @@ -983,19 +1002,18 @@ FF2609FA07B4433800CE10E5 /* Cocoa.framework */, 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */, 4A3600DF0F34F8CD00453EFB /* DeviceToDeviceManager.framework */, - FFFB0DB407B43D2700B88D48 /* Foundation.framework */, - BD2806071C40775600455151 /* Foundation.framework */, + BDA3F0891C48DB910054FB4B /* Foundation.framework */, 00CA213D02786FC30CCA2C71 /* IOKit.framework */, DB2CC4680662DFF500335AB3 /* JavaVM.framework */, 2E0406140C3197CB00F13B59 /* libbsm.dylib */, 8415A6561897109000BDBA26 /* libdns_services.dylib */, 2E8165F60C59835F00485EB2 /* libipsec.dylib */, 219D5541149ED645004464AE /* libxml2.dylib */, + FF3C72A91CE3E62200CDF81E /* libicucore.dylib */, FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */, 7F869685066EE02400D2A2DC /* Security.framework */, 65713D46025A293200000109 /* SystemConfiguration.framework */, 21F432971134AA6800581B69 /* WebFilterDNS.framework */, - BD64FE9E1C4076B40040EAB3 /* WirelessDiagnostics.framework */, ); name = "External Frameworks and Libraries"; sourceTree = ""; @@ -1019,6 +1037,7 @@ FFA572450AF18F450055A0F1 /* libsystem_dnssd_profile.dylib */, D284BE730ADD80740027CCDF /* mDNSResponder */, 2E0405F00C31955500F13B59 /* mDNSResponderHelper */, + 37DDE92D1BA383610092AC61 /* unittests */, ); name = Products; sourceTree = ""; @@ -1032,15 +1051,22 @@ name = "Bonjour Events Plugin"; sourceTree = ""; }; - 6575FBFE022EAFA800000109 /* MIG files */ = { + 37DDE9241BA382280092AC61 /* Unit Tests */ = { isa = PBXGroup; children = ( - 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */, - 6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */, - 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */, - 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */, - ); - name = "MIG files"; + 37AF802A1BF699AF00D657F6 /* DomainNameTest.c */, + 37AF802B1BF699AF00D657F6 /* DomainNameTest.h */, + 371D0FBD1BF666EB00E5DB26 /* ResourceRecordTest.c */, + 371D0FBE1BF666EB00E5DB26 /* ResourceRecordTest.h */, + 373202111BAB63E8007DE806 /* DNSMessageTest.h */, + 3732020F1BAB4349007DE806 /* DNSMessageTest.c */, + 37DDE9351BA386E70092AC61 /* main.c */, + 37DDE9271BA3825C0092AC61 /* unittest.c */, + 37DDE9281BA382670092AC61 /* unittest.h */, + 371D0FBA1BF545FA00E5DB26 /* InterfaceTest.c */, + 371D0FBB1BF545FA00E5DB26 /* InterfaceTest.h */, + ); + name = "Unit Tests"; sourceTree = ""; }; 6575FC1F022EB78C00000109 /* Command-Line Clients */ = { @@ -1142,7 +1168,6 @@ files = ( 2EC8F8EC0C39CCAC003C9C48 /* helper.h in Headers */, 2EDC5E730C39EA640092701B /* helper-server.h in Headers */, - 2E3552920C3A95C100CA1CB7 /* helper-error.h in Headers */, 2ECC11A80C4FEC3800CB1885 /* helpermsg-types.h in Headers */, 2E8165E80C5980E300485EB2 /* libpfkey.h in Headers */, 2E8165EA0C5980F700485EB2 /* ipsec_strerror.h in Headers */, @@ -1162,12 +1187,9 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - BD64FE9C1C40762F0040EAB3 /* Metrics.h in Headers */, - D284BE530ADD80740027CCDF /* DNSServiceDiscoveryDefines.h in Headers */, D284BE540ADD80740027CCDF /* dnssd_ipc.h in Headers */, 2E96A5260C39BE480087C4D2 /* helper.h in Headers */, 2EDC5E750C39EA640092701B /* helper-server.h in Headers */, - 2E3552900C3A95C100CA1CB7 /* helper-error.h in Headers */, 2ECC11A60C4FEC3800CB1885 /* helpermsg-types.h in Headers */, 21A57F4E145B2AE100939099 /* CryptoAlg.h in Headers */, 21A57F55145B2B1400939099 /* CryptoSupport.h in Headers */, @@ -1175,9 +1197,13 @@ 2124FA301471E9B50021D7BB /* dnssec.h in Headers */, 218E8E53156D8C0300720DA0 /* dnsproxy.h in Headers */, 2127A47915C3C7B900A857FC /* nsec3.h in Headers */, + 222A3C5B1C1B75F2003A6FFD /* DNSServiceDiscoveryDefines.h in Headers */, 21DD8FC1161E9A250033C8F8 /* anonymous.h in Headers */, 21070E6116486B9000A69507 /* DNSSECSupport.h in Headers */, 848DA5CA165477EB00D2E8B4 /* xpc_services.h in Headers */, + BDA3F08E1C48DCA50054FB4B /* Metrics.h in Headers */, + 22448EA71C90A837004F25CC /* coreBLE.h in Headers */, + 22448EA41C90A7CB004F25CC /* BLE.h in Headers */, 848DA5D616547F7200D2E8B4 /* dns_xpc.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1200,7 +1226,6 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 2E35529D0C3A9E7600CA1CB7 /* helper-error.h in Headers */, 2E35529F0C3A9E7600CA1CB7 /* helper.h in Headers */, FFD52A9E1AF858DD00CAD3EC /* CryptoAlg.h in Headers */, ); @@ -1352,6 +1377,23 @@ productReference = 2E0405F00C31955500F13B59 /* mDNSResponderHelper */; productType = "com.apple.product-type.tool"; }; + 37DDE92C1BA383610092AC61 /* unittests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 37DDE9311BA383610092AC61 /* Build configuration list for PBXNativeTarget "unittests" */; + buildPhases = ( + 37DDE9291BA383610092AC61 /* Sources */, + 37DDE92A1BA383610092AC61 /* Frameworks */, + 37DDE9341BA384000092AC61 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = unittests; + productName = unittests; + productReference = 37DDE92D1BA383610092AC61 /* unittests */; + productType = "com.apple.product-type.tool"; + }; 72FB545E166D5FB00090B2D9 /* dnsctl */ = { isa = PBXNativeTarget; buildConfigurationList = 72FB5465166D5FB00090B2D9 /* Build configuration list for PBXNativeTarget "dnsctl" */; @@ -1572,6 +1614,11 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 0700; + TargetAttributes = { + 37DDE92C1BA383610092AC61 = { + CreatedOnToolsVersion = 7.0; + }; + }; }; buildConfigurationList = D284BE2B0ADD78180027CCDF /* Build configuration list for PBXProject "mDNSResponder" */; compatibilityVersion = "Xcode 3.2"; @@ -1610,6 +1657,7 @@ 84C5B3341665529800C324A8 /* dns_services */, D284BEB20ADD809A0027CCDF /* libjdns_sd.jnilib */, 4AE471670EAFF81900A6C5AD /* dns_sd.jar */, + 37DDE92C1BA383610092AC61 /* unittests */, ); }; /* End PBXProject section */ @@ -1683,7 +1731,22 @@ ); runOnlyForDeploymentPostprocessing = 1; shellPath = "/bin/bash -e -x"; - shellScript = "DSTROOT=${DSTROOT}\nmkdir -p \"$DSTROOT/usr/include\"\nsed 's/\\(^#define _DNS_SD_LIBDISPATCH \\)0$/\\1 1/' \"$SRCROOT/../mDNSShared/dns_sd.h\" > \"$DSTROOT/usr/include/dns_sd.h\"\n\nif [[ \"${ACTION}\" == \"installhdrs\" ]]; then\n DSTROOT=${DSTROOT}\n mkdir -p \"$DSTROOT/usr/local/include\"\n sed 's/\\(^#define _DNS_SD_LIBDISPATCH \\)0$/\\1 1/' \"$SRCROOT/../mDNSMacOSX/Private/dns_services.h\" > \"$DSTROOT/usr/local/include/dns_services.h\"\n exit 0\nfi\n\nif [[ \"${PLATFORM_NAME}\" =~ \"simulator\" ]]; then\n ln -s libsystem_dnssd.dylib ${DSTROOT}${INSTALL_PATH}/libsystem_sim_dnssd.dylib\nfi\n"; + shellScript = "DSTROOT=${DSTROOT}\nmkdir -p \"$DSTROOT/usr/include\"\nsed 's/\\(^#define _DNS_SD_LIBDISPATCH \\)0$/\\1 1/' \"$SRCROOT/../mDNSShared/dns_sd.h\" > \"$DSTROOT/usr/include/dns_sd.h\"\n\nif [[ \"${ACTION}\" == \"installhdrs\" ]]; then\n exit 0\nfi\n\nif [[ \"${PLATFORM_NAME}\" =~ \"simulator\" ]]; then\n ln -s libsystem_dnssd.dylib ${DSTROOT}${INSTALL_PATH}/libsystem_sim_dnssd.dylib\nfi\n"; + }; + 37DDE9341BA384000092AC61 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(TARGET_BUILD_DIR)/$(TARGET_NAME)", + ); + outputPaths = ( + "$(TARGET_BUILD_DIR)/unittest_success", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "cd \"$TARGET_BUILD_DIR\"\n./\"$TARGET_NAME\"\n# touch unittest_success\nif [ ! -f unittest_success ] ; then exit -1; fi"; }; 4A4EE3A413CB8E82005C624B /* Build yacc file into derived source files */ = { isa = PBXShellScriptBuildPhase; @@ -1738,10 +1801,8 @@ files = ( 215FFAEE124000F900470DE1 /* dnssd_ipc.c in Sources */, 215FFAEF124000F900470DE1 /* dnssd_clientlib.c in Sources */, + 222A3C6A1C1B7777003A6FFD /* DNSServiceDiscovery.c in Sources */, 215FFAF0124000F900470DE1 /* dnssd_clientstub.c in Sources */, - 215FFAF1124000F900470DE1 /* DNSServiceDiscovery.c in Sources */, - 215FFAF2124000F900470DE1 /* DNSServiceDiscoveryRequest.defs in Sources */, - 215FFAF3124000F900470DE1 /* DNSServiceDiscoveryReply.defs in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1751,10 +1812,8 @@ files = ( 215FFAF41240011800470DE1 /* dnssd_ipc.c in Sources */, 215FFAF51240011800470DE1 /* dnssd_clientlib.c in Sources */, + 222A3C6B1C1B7778003A6FFD /* DNSServiceDiscovery.c in Sources */, 215FFAF61240011800470DE1 /* dnssd_clientstub.c in Sources */, - 215FFAF71240011800470DE1 /* DNSServiceDiscovery.c in Sources */, - 215FFAF81240011800470DE1 /* DNSServiceDiscoveryRequest.defs in Sources */, - 215FFAF91240011800470DE1 /* DNSServiceDiscoveryReply.defs in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1764,10 +1823,8 @@ files = ( 215FFAFA1240013400470DE1 /* dnssd_ipc.c in Sources */, 215FFAFB1240013400470DE1 /* dnssd_clientlib.c in Sources */, + 222A3C6C1C1B7779003A6FFD /* DNSServiceDiscovery.c in Sources */, 215FFAFC1240013400470DE1 /* dnssd_clientstub.c in Sources */, - 215FFAFD1240013400470DE1 /* DNSServiceDiscovery.c in Sources */, - 215FFAFE1240013400470DE1 /* DNSServiceDiscoveryRequest.defs in Sources */, - 215FFAFF1240013400470DE1 /* DNSServiceDiscoveryReply.defs in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1776,13 +1833,25 @@ buildActionMask = 2147483647; files = ( 2E0405F50C3195F700F13B59 /* helper.c in Sources */, - 2E0405F60C31961100F13B59 /* helpermsg.defs in Sources */, 2E96A51D0C39BDAC0087C4D2 /* helper-main.c in Sources */, 2E8165E90C5980EE00485EB2 /* pfkey.c in Sources */, 4BD2B63A134FE09F002B96D5 /* P2PPacketFilter.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; + 37DDE9291BA383610092AC61 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 371D0FBF1BF666EB00E5DB26 /* ResourceRecordTest.c in Sources */, + 37FEBD581BC789AA00638EA4 /* DNSCommon.c in Sources */, + 371D0FBC1BF545FA00E5DB26 /* InterfaceTest.c in Sources */, + 373202101BAB4444007DE806 /* DNSMessageTest.c in Sources */, + 3771F67D1BA387DD0072355E /* main.c in Sources */, + 37DDE9331BA383D30092AC61 /* unittest.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 72FB545B166D5FB00090B2D9 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1803,26 +1872,25 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - D284BE560ADD80740027CCDF /* DNSServiceDiscoveryReply.defs in Sources */, - D284BE570ADD80740027CCDF /* DNSServiceDiscoveryRequest.defs in Sources */, + 227687F31C90AD580019382D /* coreBLE.m in Sources */, D284BE580ADD80740027CCDF /* mDNS.c in Sources */, D284BE590ADD80740027CCDF /* uDNS.c in Sources */, D284BE5A0ADD80740027CCDF /* DNSCommon.c in Sources */, D284BE5B0ADD80740027CCDF /* DNSDigest.c in Sources */, D284BE5D0ADD80740027CCDF /* mDNSDebug.c in Sources */, D284BE5E0ADD80740027CCDF /* uds_daemon.c in Sources */, + 22448EA31C90A7BE004F25CC /* BLE.c in Sources */, D284BE5F0ADD80740027CCDF /* dnssd_ipc.c in Sources */, D284BE600ADD80740027CCDF /* PlatformCommon.c in Sources */, D284BE610ADD80740027CCDF /* mDNSMacOSX.c in Sources */, + BDA3F08F1C48DCA50054FB4B /* Metrics.m in Sources */, D284BE620ADD80740027CCDF /* LegacyNATTraversal.c in Sources */, D284BE630ADD80740027CCDF /* daemon.c in Sources */, - 2E04061F0C3198B700F13B59 /* helpermsg.defs in Sources */, 2E96A5320C39C1A50087C4D2 /* helper-stubs.c in Sources */, 21A57F4C145B2AE100939099 /* CryptoAlg.c in Sources */, 21A57F53145B2B1400939099 /* CryptoSupport.c in Sources */, 2124FA331471E9DE0021D7BB /* nsec.c in Sources */, 213BDC6D147319F400000896 /* dnssec.c in Sources */, - BD64FE9D1C40762F0040EAB3 /* Metrics.m in Sources */, 218E8E51156D8C0300720DA0 /* dnsproxy.c in Sources */, 21DED43515702C0F0060B6B9 /* DNSProxySupport.c in Sources */, 216D9ACE1720C9F5008066E1 /* uDNSPathEvalulation.c in Sources */, @@ -1831,6 +1899,7 @@ 21DD8FBF161E9A250033C8F8 /* anonymous.c in Sources */, 21070E5F16486B9000A69507 /* DNSSECSupport.c in Sources */, 848DA5C7165477E000D2E8B4 /* xpc_services.c in Sources */, + 8417375C1B967D37000CD5C2 /* dnsctl_server.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1865,7 +1934,6 @@ D284BECC0ADD80A20027CCDF /* dnsextd_parser.y in Sources */, D284BECB0ADD80A20027CCDF /* dnsextd_lexer.l in Sources */, D284BECD0ADD80A20027CCDF /* PlatformCommon.c in Sources */, - 2EAE955A0C31F4D30021F738 /* helpermsg.defs in Sources */, 2E35529E0C3A9E7600CA1CB7 /* helper-stubs.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1895,10 +1963,8 @@ files = ( FFA572330AF18F1C0055A0F1 /* dnssd_ipc.c in Sources */, FFA572340AF18F1C0055A0F1 /* dnssd_clientlib.c in Sources */, + 222A3C6E1C1B777B003A6FFD /* DNSServiceDiscovery.c in Sources */, FFA572350AF18F1C0055A0F1 /* dnssd_clientstub.c in Sources */, - FFA5724A0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */, - FFC22AA40B00F42C00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */, - FFC22AA60B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1908,10 +1974,8 @@ files = ( FFA5723F0AF18F450055A0F1 /* dnssd_ipc.c in Sources */, FFA572400AF18F450055A0F1 /* dnssd_clientlib.c in Sources */, + 222A3C6F1C1B777C003A6FFD /* DNSServiceDiscovery.c in Sources */, FFA572410AF18F450055A0F1 /* dnssd_clientstub.c in Sources */, - FFA5724B0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */, - FFC22AA30B00F42B00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */, - FFC22AA70B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1921,10 +1985,8 @@ files = ( FFFA38660AEEDB2B0065B80A /* dnssd_ipc.c in Sources */, FFFA38630AEEDB090065B80A /* dnssd_clientlib.c in Sources */, + 222A3C6D1C1B777A003A6FFD /* DNSServiceDiscovery.c in Sources */, FFFA38650AEEDB130065B80A /* dnssd_clientstub.c in Sources */, - FFA572490AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */, - FFC22AA20B00F42A00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */, - FFC22AA50B00F43000BAB070 /* DNSServiceDiscoveryReply.defs in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2070,97 +2132,134 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ - 03067D740C83A3CB0022BE1F /* Development */ = { + 03067D740C83A3CB0022BE1F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - GCC_OPTIMIZATION_LEVEL = s; PRODUCT_NAME = "Build Some"; }; - name = Development; - }; - 213FB21A12028A7B002B3A08 /* Development */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - BUNDLE_LOADER = /usr/libexec/UserEventAgent; - CODE_SIGN_IDENTITY = "-"; - INFOPLIST_FILE = "BonjourEvents-Info.plist"; - INSTALL_PATH = /System/Library/UserEventPlugins/; - PRODUCT_NAME = BonjourEvents; - PROVISIONING_PROFILE = ""; - WRAPPER_EXTENSION = plugin; - }; - name = Development; + name = Release; }; - 2141DCF9123FFB5D0086D23E /* Development */ = { + 0C419F121BA20DF600A70FF7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/Debug"; + CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)/Debug"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; GCC_OPTIMIZATION_LEVEL = 0; - PRODUCT_NAME = SystemLibraries; + GCC_PREPROCESSOR_DEFINITIONS = ( + "__APPLE_USE_RFC_3542=1", + "_DNS_SD_LIBDISPATCH=1", + "APPLE_OSX_mDNSResponder=1", + "__MigTypeCheck=1", + "mDNSResponderVersion=${MVERS}", + _LEGACY_NAT_TRAVERSAL_, + "_BUILDING_XCODE_PROJECT_=1", + "DEBUG=1", + "BONJOUR_ON_DEMAND=1", + "USE_LIBIDN=1", + ); + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = NO; + MVERS = "\"(Engineering Build)\""; + OTHER_CFLAGS = ( + "-DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS", + "-fwrapv", + ); + SDKROOT = macosx.internal; + STRIP_INSTALLED_PRODUCT = NO; + STRIP_STYLE = debugging; + SUPPORTED_PLATFORMS = "macosx iphoneos"; + WARNING_CFLAGS = ( + "-W", + "-Wall", + "-Wmissing-prototypes", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + "-Wshadow", + "-Wno-format", + "-Wformat-security", + ); + YACC_GENERATED_FILE_STEM = Standard; }; - name = Development; + name = Debug; }; - 2141DD0C123FFC7F0086D23E /* Development */ = { + 0C419F131BA20DF600A70FF7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - GCC_OPTIMIZATION_LEVEL = s; - PRODUCT_NAME = SystemLibrariesStatic; + PRODUCT_NAME = "Build All"; }; - name = Development; + name = Debug; }; - 2141DD1E123FFCDB0086D23E /* Development */ = { + 0C419F141BA20DF600A70FF7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - GCC_PREPROCESSOR_DEFINITIONS = ( - "$(inherited)", - "__DARWIN_NON_CANCELABLE=1", - ); - HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/"; - INSTALLHDRS_COPY_PHASE = YES; - INSTALLHDRS_SCRIPT_PHASE = YES; - INSTALL_PATH = /usr/local/lib/system; - PRODUCT_NAME = dns_sd; - "SKIP_INSTALL[sdk=iphonesimulator*]" = YES; + PRODUCT_NAME = "Build Some"; }; - name = Development; + name = Debug; }; - 2141DD25123FFD100086D23E /* Development */ = { + 0C419F151BA20DF600A70FF7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - GCC_PREPROCESSOR_DEFINITIONS = ( - "$(inherited)", - "__DARWIN_NON_CANCELABLE=1", - ); - HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/"; - INSTALL_PATH = /usr/local/lib/system; - PRODUCT_NAME = dns_sd_debug; - "SKIP_INSTALL[sdk=iphonesimulator*]" = YES; + PRODUCT_NAME = "Build All"; }; - name = Development; + name = Debug; }; - 2141DD2B123FFD2C0086D23E /* Development */ = { + 0C419F161BA20DF600A70FF7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - GCC_GENERATE_DEBUGGING_SYMBOLS = NO; - GCC_PREPROCESSOR_DEFINITIONS = ( + "APPLY_RULES_IN_COPY_FILES[sdk=appletvos*]" = YES; + "APPLY_RULES_IN_COPY_FILES[sdk=iphoneos*]" = YES; + "APPLY_RULES_IN_COPY_FILES[sdk=watchos*]" = YES; + CODE_SIGN_ENTITLEMENTS = "mDNSResponder-entitlements.plist"; + CODE_SIGN_IDENTITY = "-"; + FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "__DARWIN_NON_CANCELABLE=1", + "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", + "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", ); - GENERATE_PROFILING_CODE = YES; - HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/"; - INSTALL_PATH = /usr/local/lib/system; - PRODUCT_NAME = dns_sd_profile; - "SKIP_INSTALL[sdk=iphonesimulator*]" = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; + HEADER_SEARCH_PATHS = ( + "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/PrivateHeaders", + ../mDNSShared, + "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders", + "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers", + "${CONFIGURATION_TEMP_DIR}", + "$(SDKROOT)/usr/include/libxml2", + "$(SDKROOT)/usr/local/include/", + ); + INSTALL_PATH = /usr/sbin; + LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\""; + MACOSX_DEPLOYMENT_TARGET = 10.10; + ORDER_FILE = "${SRCROOT}/mDNSResponder.order"; + OTHER_LDFLAGS = ""; + "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( + "-weak_framework", + DeviceToDeviceManager, + "-lMobileGestalt", + ); + "OTHER_LDFLAGS[sdk=macosx*][arch=*]" = ( + "-lAWACS", + "-weak_framework", + WebFilterDNS, + "-weak_framework", + DeviceToDeviceManager, + ); + "PLIST_FILE_OUTPUT_FORMAT[sdk=appletvos*]" = binary; + "PLIST_FILE_OUTPUT_FORMAT[sdk=iphoneos*]" = binary; + "PLIST_FILE_OUTPUT_FORMAT[sdk=watchos*]" = binary; + PRODUCT_NAME = mDNSResponder; + PROVISIONING_PROFILE = ""; }; - name = Development; + name = Debug; }; - 2E0405F20C31955500F13B59 /* Development */ = { + 0C419F171BA20DF600A70FF7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { "APPLY_RULES_IN_COPY_FILES[sdk=appletvos*]" = YES; "APPLY_RULES_IN_COPY_FILES[sdk=iphoneos*]" = YES; "APPLY_RULES_IN_COPY_FILES[sdk=watchos*]" = YES; - "CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = "helper-entitlements.plist"; + CODE_SIGN_ENTITLEMENTS = "helper-entitlements.plist"; CODE_SIGN_IDENTITY = "-"; HEADER_SEARCH_PATHS = ( "${CONFIGURATION_TEMP_DIR}", @@ -2177,17 +2276,21 @@ PRODUCT_NAME = mDNSResponderHelper; PROVISIONING_PROFILE = ""; }; - name = Development; + name = Debug; }; - 4AE471680EAFF81900A6C5AD /* Development */ = { + 0C419F181BA20DF600A70FF7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - GCC_OPTIMIZATION_LEVEL = 0; - PRODUCT_NAME = dns_sd.jar; + HEADER_SEARCH_PATHS = ( + ../mDNSShared, + "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders", + ); + INSTALL_PATH = /usr/bin; + PRODUCT_NAME = "dns-sd"; }; - name = Development; + name = Debug; }; - 72FB5466166D5FB00090B2D9 /* Development */ = { + 0C419F191BA20DF600A70FF7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -2203,7 +2306,6 @@ CODE_SIGN_IDENTITY = "-"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_ENABLE_OBJC_EXCEPTIONS = YES; - GCC_OPTIMIZATION_LEVEL = s; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", @@ -2220,101 +2322,587 @@ PROVISIONING_PROFILE = ""; SDKROOT = macosx; }; - name = Development; + name = Debug; }; - 84C5B3371665529800C324A8 /* Development */ = { + 0C419F1A1BA20DF600A70FF7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - EXECUTABLE_PREFIX = lib; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_ENABLE_OBJC_EXCEPTIONS = YES; - GCC_OPTIMIZATION_LEVEL = s; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", + HEADER_SEARCH_PATHS = ( + "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders", + "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers", + "${CONFIGURATION_TEMP_DIR}", + /System/Library/Frameworks/System.Framework/PrivateHeaders, ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = NO; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - INSTALL_PATH = /usr/lib; - MACOSX_DEPLOYMENT_TARGET = 10.8; - ONLY_ACTIVE_ARCH = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx; + INSTALL_PATH = /usr/sbin; + LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\""; + MACOSX_DEPLOYMENT_TARGET = 10.10; + OTHER_CFLAGS = "-UAPPLE_OSX_mDNSResponder"; + PRODUCT_NAME = dnsextd; }; - name = Development; + name = Debug; }; - D284BE290ADD78180027CCDF /* Development */ = { + 0C419F1B1BA20DF600A70FF7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - PRODUCT_NAME = "Build All"; + INSTALL_PATH = "/Library/Application Support/Bonjour"; + MACOSX_DEPLOYMENT_TARGET = 10.6; + OTHER_LDFLAGS = "-Wl,-pie"; + PRODUCT_NAME = ddnswriteconfig; }; - name = Development; + name = Debug; }; - D284BE2C0ADD78180027CCDF /* Development */ = { + 0C419F1C1BA20DF600A70FF7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)"; - CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)"; - COPY_PHASE_STRIP = NO; - DEAD_CODE_STRIPPING = YES; - GCC_PREPROCESSOR_DEFINITIONS = ( - "__APPLE_USE_RFC_3542=1", - "_DNS_SD_LIBDISPATCH=1", - "APPLE_OSX_mDNSResponder=1", - "__MigTypeCheck=1", - "mDNSResponderVersion=${MVERS}", - _LEGACY_NAT_TRAVERSAL_, - "_BUILDING_XCODE_PROJECT_=1", - ); - GCC_TREAT_WARNINGS_AS_ERRORS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = NO; - MVERS = "\"(Engineering Build)\""; - OTHER_CFLAGS = ( - "-DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS", - "-fwrapv", - ); - SDKROOT = macosx.internal; - STRIP_STYLE = debugging; - WARNING_CFLAGS = ( - "-W", - "-Wall", - "-Wmissing-prototypes", - "-Wno-four-char-constants", - "-Wno-unknown-pragmas", - "-Wshadow", - ); - YACC_GENERATED_FILE_STEM = Standard; + GCC_ENABLE_OBJC_GC = supported; + INFOPLIST_FILE = "PreferencePane/Info-PreferencePane.plist"; + INSTALL_PATH = /AppleInternal/Library/PreferencePanes; + MACOSX_DEPLOYMENT_TARGET = 10.6; + PRODUCT_NAME = Bonjour; + WRAPPER_EXTENSION = prefPane; }; - name = Development; + name = Debug; }; - D284BE6E0ADD80740027CCDF /* Development */ = { + 0C419F1D1BA20DF600A70FF7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - "APPLY_RULES_IN_COPY_FILES[sdk=appletvos*]" = YES; - "APPLY_RULES_IN_COPY_FILES[sdk=iphoneos*]" = YES; - "APPLY_RULES_IN_COPY_FILES[sdk=watchos*]" = YES; - CODE_SIGN_ENTITLEMENTS = "mDNSResponder-entitlements.plist"; + ALWAYS_SEARCH_USER_PATHS = NO; + BUNDLE_LOADER = /usr/libexec/UserEventAgent; CODE_SIGN_IDENTITY = "-"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); - GCC_TREAT_WARNINGS_AS_ERRORS = NO; - HEADER_SEARCH_PATHS = ( - "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/PrivateHeaders", - ../mDNSShared, - "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders", - "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers", - "${CONFIGURATION_TEMP_DIR}", + INFOPLIST_FILE = "BonjourEvents-Info.plist"; + INSTALL_PATH = /System/Library/UserEventPlugins/; + PRODUCT_NAME = BonjourEvents; + PROVISIONING_PROFILE = ""; + WRAPPER_EXTENSION = plugin; + }; + name = Debug; + }; + 0C419F1E1BA20DF600A70FF7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = SystemLibraries; + }; + name = Debug; + }; + 0C419F1F1BA20DF600A70FF7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = SystemLibrariesStatic; + }; + name = Debug; + }; + 0C419F201BA20DF600A70FF7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = SystemLibrariesDynamic; + }; + name = Debug; + }; + 0C419F211BA20DF600A70FF7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "__DARWIN_NON_CANCELABLE=1", + ); + HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/"; + INSTALLHDRS_COPY_PHASE = YES; + INSTALLHDRS_SCRIPT_PHASE = YES; + INSTALL_PATH = /usr/local/lib/system; + PRODUCT_NAME = dns_sd; + "SKIP_INSTALL[sdk=iphonesimulator*]" = YES; + }; + name = Debug; + }; + 0C419F221BA20DF600A70FF7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "__DARWIN_NON_CANCELABLE=1", + ); + HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/"; + INSTALL_PATH = /usr/local/lib/system; + PRODUCT_NAME = dns_sd_debug; + "SKIP_INSTALL[sdk=iphonesimulator*]" = YES; + }; + name = Debug; + }; + 0C419F231BA20DF600A70FF7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "__DARWIN_NON_CANCELABLE=1", + ); + GENERATE_PROFILING_CODE = YES; + HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/"; + INSTALL_PATH = /usr/local/lib/system; + PRODUCT_NAME = dns_sd_profile; + "SKIP_INSTALL[sdk=iphonesimulator*]" = YES; + }; + name = Debug; + }; + 0C419F241BA20DF600A70FF7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DYLIB_CURRENT_VERSION = "$(RC_ProjectSourceVersion)"; + EXECUTABLE_EXTENSION = dylib; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "__DARWIN_NON_CANCELABLE=1", + ); + HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/"; + INSTALLHDRS_COPY_PHASE = YES; + INSTALLHDRS_SCRIPT_PHASE = YES; + INSTALL_PATH = /usr/lib/system; + INTERPOSITION_SIM_SUFFIX = ""; + "INTERPOSITION_SIM_SUFFIX[sdk=iphonesimulator*]" = _sim; + LINK_WITH_STANDARD_LIBRARIES = NO; + OTHER_LDFLAGS = ( + "-Wl,-umbrella,System", + "-L/usr/lib/system", + "-ldyld", + "-lcompiler_rt", + "-lsystem$(INTERPOSITION_SIM_SUFFIX)_kernel", + "-lsystem$(INTERPOSITION_SIM_SUFFIX)_platform", + "-lsystem$(INTERPOSITION_SIM_SUFFIX)_pthread", + "-lsystem_malloc", + "-lsystem_c", + "-lsystem_blocks", + "-ldispatch", + "-llaunch", + "-lsystem_asl", + ); + PRODUCT_NAME = libsystem_dnssd; + }; + name = Debug; + }; + 0C419F251BA20DF600A70FF7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DYLIB_CURRENT_VERSION = "$(RC_ProjectSourceVersion)"; + EXECUTABLE_EXTENSION = dylib; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "__DARWIN_NON_CANCELABLE=1", + ); + HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/"; + INSTALL_PATH = /usr/lib/system; + INTERPOSITION_SIM_SUFFIX = ""; + "INTERPOSITION_SIM_SUFFIX[sdk=iphonesimulator*]" = _sim; + LINK_WITH_STANDARD_LIBRARIES = NO; + OTHER_LDFLAGS = ( + "-Wl,-umbrella,System", + "-L/usr/lib/system", + "-ldyld", + "-lcompiler_rt", + "-lsystem$(INTERPOSITION_SIM_SUFFIX)_kernel", + "-lsystem$(INTERPOSITION_SIM_SUFFIX)_platform", + "-lsystem$(INTERPOSITION_SIM_SUFFIX)_pthread", + "-lsystem_malloc", + "-lsystem_c", + "-lsystem_blocks", + "-ldispatch", + "-llaunch", + "-lsystem_asl", + ); + PRODUCT_NAME = libsystem_dnssd_debug; + }; + name = Debug; + }; + 0C419F261BA20DF600A70FF7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DYLIB_CURRENT_VERSION = "$(RC_ProjectSourceVersion)"; + EXECUTABLE_EXTENSION = dylib; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "__DARWIN_NON_CANCELABLE=1", + ); + GENERATE_PROFILING_CODE = YES; + HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/"; + INSTALL_PATH = /usr/lib/system; + INTERPOSITION_SIM_SUFFIX = ""; + "INTERPOSITION_SIM_SUFFIX[sdk=iphonesimulator*]" = _sim; + LINK_WITH_STANDARD_LIBRARIES = NO; + OTHER_LDFLAGS = ( + "-Wl,-umbrella,System", + "-L/usr/lib/system", + "-ldyld", + "-lcompiler_rt", + "-lsystem$(INTERPOSITION_SIM_SUFFIX)_kernel", + "-lsystem$(INTERPOSITION_SIM_SUFFIX)_platform", + "-lsystem$(INTERPOSITION_SIM_SUFFIX)_pthread", + "-lsystem_malloc", + "-lsystem_c", + "-lsystem_blocks", + "-ldispatch", + "-llaunch", + "-lsystem_asl", + ); + PRODUCT_NAME = libsystem_dnssd_profile; + }; + name = Debug; + }; + 0C419F271BA20DF600A70FF7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + EXECUTABLE_PREFIX = lib; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INSTALL_PATH = /usr/lib; + MACOSX_DEPLOYMENT_TARGET = 10.8; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 0C419F281BA20DF600A70FF7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + EXECUTABLE_EXTENSION = jnilib; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + HEADER_SEARCH_PATHS = ( + ../mDNSShared, + "${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/A/Headers", + "${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/1.3.1/Headers", + "${PROJECT_DERIVED_FILE_DIR}", + ); + INSTALL_PATH = /usr/lib/java; + LIBRARY_STYLE = DYNAMIC; + MACH_O_TYPE = mh_dylib; + PRODUCT_NAME = libjdns_sd; + }; + name = Debug; + }; + 0C419F291BA20DF600A70FF7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = dns_sd.jar; + }; + name = Debug; + }; + 213FB21A12028A7B002B3A08 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + BUNDLE_LOADER = /usr/libexec/UserEventAgent; + CODE_SIGN_IDENTITY = "-"; + INFOPLIST_FILE = "BonjourEvents-Info.plist"; + INSTALL_PATH = /System/Library/UserEventPlugins/; + PRODUCT_NAME = BonjourEvents; + PROVISIONING_PROFILE = ""; + WRAPPER_EXTENSION = plugin; + }; + name = Release; + }; + 2141DCF9123FFB5D0086D23E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = SystemLibraries; + }; + name = Release; + }; + 2141DD0C123FFC7F0086D23E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = SystemLibrariesStatic; + }; + name = Release; + }; + 2141DD1E123FFCDB0086D23E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "__DARWIN_NON_CANCELABLE=1", + ); + HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/"; + INSTALLHDRS_COPY_PHASE = YES; + INSTALLHDRS_SCRIPT_PHASE = YES; + INSTALL_PATH = /usr/local/lib/system; + PRODUCT_NAME = dns_sd; + "SKIP_INSTALL[sdk=iphonesimulator*]" = YES; + }; + name = Release; + }; + 2141DD25123FFD100086D23E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "__DARWIN_NON_CANCELABLE=1", + ); + HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/"; + INSTALL_PATH = /usr/local/lib/system; + PRODUCT_NAME = dns_sd_debug; + "SKIP_INSTALL[sdk=iphonesimulator*]" = YES; + }; + name = Release; + }; + 2141DD2B123FFD2C0086D23E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "__DARWIN_NON_CANCELABLE=1", + ); + GENERATE_PROFILING_CODE = YES; + HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/"; + INSTALL_PATH = /usr/local/lib/system; + PRODUCT_NAME = dns_sd_profile; + "SKIP_INSTALL[sdk=iphonesimulator*]" = YES; + }; + name = Release; + }; + 2E0405F20C31955500F13B59 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + "APPLY_RULES_IN_COPY_FILES[sdk=appletvos*]" = YES; + "APPLY_RULES_IN_COPY_FILES[sdk=iphoneos*]" = YES; + "APPLY_RULES_IN_COPY_FILES[sdk=watchos*]" = YES; + CODE_SIGN_ENTITLEMENTS = "helper-entitlements.plist"; + CODE_SIGN_IDENTITY = "-"; + HEADER_SEARCH_PATHS = ( + "${CONFIGURATION_TEMP_DIR}", + "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders", + "$(SDKROOT)/usr/local/include", + ); + INSTALL_PATH = /usr/sbin; + LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\""; + MACOSX_DEPLOYMENT_TARGET = 10.10; + OTHER_LDFLAGS = "-lipsec"; + "PLIST_FILE_OUTPUT_FORMAT[sdk=appletvos*]" = binary; + "PLIST_FILE_OUTPUT_FORMAT[sdk=iphoneos*]" = binary; + "PLIST_FILE_OUTPUT_FORMAT[sdk=watchos*]" = binary; + PRODUCT_NAME = mDNSResponderHelper; + PROVISIONING_PROFILE = ""; + }; + name = Release; + }; + 37AF80271BF6997A00D657F6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + PRODUCT_NAME = dns_sd.jar; + }; + name = Release; + }; + 37AF80281BF6997A00D657F6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + PRODUCT_NAME = unittests; + }; + name = Release; + }; + 37AF80291BF6997A00D657F6 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + PRODUCT_NAME = unittests; + }; + name = Debug; + }; + 37DDE9321BA383610092AC61 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = "$(CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION)"; + CLANG_WARN_CONSTANT_CONVERSION = "$(CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION)"; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = NO; + CLANG_WARN_ENUM_CONVERSION = "$(CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION)"; + CLANG_WARN_INT_CONVERSION = "$(CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION)"; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = NO; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = NO; + GCC_WARN_ABOUT_RETURN_TYPE = NO; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = NO; + GCC_WARN_UNUSED_FUNCTION = NO; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + STRIP_INSTALLED_PRODUCT = NO; + }; + name = Development; + }; + 72FB5466166D5FB00090B2D9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = "dnsctl-entitlements.plist"; + CODE_SIGN_IDENTITY = "-"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_STRICT_ALIASING = YES; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INSTALL_PATH = /usr/local/bin; + MACOSX_DEPLOYMENT_TARGET = 10.9; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + SDKROOT = macosx; + }; + name = Release; + }; + 84C5B3371665529800C324A8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + EXECUTABLE_PREFIX = lib; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INSTALL_PATH = /usr/lib; + MACOSX_DEPLOYMENT_TARGET = 10.8; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; + D284BE290ADD78180027CCDF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "Build All"; + }; + name = Release; + }; + D284BE2C0ADD78180027CCDF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/Release"; + CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)/Release"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "__APPLE_USE_RFC_3542=1", + "_DNS_SD_LIBDISPATCH=1", + "APPLE_OSX_mDNSResponder=1", + "__MigTypeCheck=1", + "mDNSResponderVersion=${MVERS}", + _LEGACY_NAT_TRAVERSAL_, + "_BUILDING_XCODE_PROJECT_=1", + "BONJOUR_ON_DEMAND=1", + "USE_LIBIDN=1", + ); + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = NO; + MVERS = "\"(Engineering Build)\""; + OTHER_CFLAGS = ( + "-DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS", + "-fwrapv", + ); + SDKROOT = macosx.internal; + STRIP_STYLE = debugging; + WARNING_CFLAGS = ( + "-W", + "-Wall", + "-Wmissing-prototypes", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + "-Wshadow", + "-Wno-format", + "-Wformat-security", + ); + YACC_GENERATED_FILE_STEM = Standard; + }; + name = Release; + }; + D284BE6E0ADD80740027CCDF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + "APPLY_RULES_IN_COPY_FILES[sdk=appletvos*]" = YES; + "APPLY_RULES_IN_COPY_FILES[sdk=iphoneos*]" = YES; + "APPLY_RULES_IN_COPY_FILES[sdk=watchos*]" = YES; + CODE_SIGN_ENTITLEMENTS = "mDNSResponder-entitlements.plist"; + CODE_SIGN_IDENTITY = "-"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", + "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", + ); + GCC_TREAT_WARNINGS_AS_ERRORS = NO; + HEADER_SEARCH_PATHS = ( + "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/PrivateHeaders", + ../mDNSShared, + "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders", + "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers", + "${CONFIGURATION_TEMP_DIR}", "$(SDKROOT)/usr/include/libxml2", "$(SDKROOT)/usr/local/include/", ); @@ -2340,11 +2928,10 @@ "PLIST_FILE_OUTPUT_FORMAT[sdk=watchos*]" = binary; PRODUCT_NAME = mDNSResponder; PROVISIONING_PROFILE = ""; - SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; }; - name = Development; + name = Release; }; - D284BEAE0ADD80920027CCDF /* Development */ = { + D284BEAE0ADD80920027CCDF /* Release */ = { isa = XCBuildConfiguration; buildSettings = { HEADER_SEARCH_PATHS = ( @@ -2354,9 +2941,9 @@ INSTALL_PATH = /usr/bin; PRODUCT_NAME = "dns-sd"; }; - name = Development; + name = Release; }; - D284BEBC0ADD809A0027CCDF /* Development */ = { + D284BEBC0ADD809A0027CCDF /* Release */ = { isa = XCBuildConfiguration; buildSettings = { DYLIB_COMPATIBILITY_VERSION = 1; @@ -2372,14 +2959,11 @@ INSTALL_PATH = /usr/lib/java; LIBRARY_STYLE = DYNAMIC; MACH_O_TYPE = mh_dylib; - OTHER_CFLAGS = ""; - OTHER_LIBTOOL_FLAGS = ""; PRODUCT_NAME = libjdns_sd; - SECTORDER_FLAGS = ""; }; - name = Development; + name = Release; }; - D284BED70ADD80A20027CCDF /* Development */ = { + D284BED70ADD80A20027CCDF /* Release */ = { isa = XCBuildConfiguration; buildSettings = { HEADER_SEARCH_PATHS = ( @@ -2394,9 +2978,9 @@ OTHER_CFLAGS = "-UAPPLE_OSX_mDNSResponder"; PRODUCT_NAME = dnsextd; }; - name = Development; + name = Release; }; - D284BEE60ADD80A70027CCDF /* Development */ = { + D284BEE60ADD80A70027CCDF /* Release */ = { isa = XCBuildConfiguration; buildSettings = { INSTALL_PATH = "/Library/Application Support/Bonjour"; @@ -2404,23 +2988,21 @@ OTHER_LDFLAGS = "-Wl,-pie"; PRODUCT_NAME = ddnswriteconfig; }; - name = Development; + name = Release; }; - D284BF090ADD80B00027CCDF /* Development */ = { + D284BF090ADD80B00027CCDF /* Release */ = { isa = XCBuildConfiguration; buildSettings = { GCC_ENABLE_OBJC_GC = supported; - GCC_SYMBOLS_PRIVATE_EXTERN = NO; INFOPLIST_FILE = "PreferencePane/Info-PreferencePane.plist"; INSTALL_PATH = /AppleInternal/Library/PreferencePanes; MACOSX_DEPLOYMENT_TARGET = 10.6; - OTHER_LDFLAGS = "-twolevel_namespace"; PRODUCT_NAME = Bonjour; WRAPPER_EXTENSION = prefPane; }; - name = Development; + name = Release; }; - FFA572380AF18F1C0055A0F1 /* Development */ = { + FFA572380AF18F1C0055A0F1 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { DYLIB_CURRENT_VERSION = "$(RC_ProjectSourceVersion)"; @@ -2451,9 +3033,9 @@ ); PRODUCT_NAME = libsystem_dnssd_debug; }; - name = Development; + name = Release; }; - FFA572440AF18F450055A0F1 /* Development */ = { + FFA572440AF18F450055A0F1 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { DYLIB_CURRENT_VERSION = "$(RC_ProjectSourceVersion)"; @@ -2486,23 +3068,23 @@ ); PRODUCT_NAME = libsystem_dnssd_profile; }; - name = Development; + name = Release; }; - FFA5726F0AF191200055A0F1 /* Development */ = { + FFA5726F0AF191200055A0F1 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = SystemLibrariesDynamic; }; - name = Development; + name = Release; }; - FFB7657F0AEED99D00583A2C /* Development */ = { + FFB7657F0AEED99D00583A2C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = "Build All"; }; - name = Development; + name = Release; }; - FFB7658A0AEED9FB00583A2C /* Development */ = { + FFB7658A0AEED9FB00583A2C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { DYLIB_CURRENT_VERSION = "$(RC_ProjectSourceVersion)"; @@ -2535,7 +3117,7 @@ ); PRODUCT_NAME = libsystem_dnssd; }; - name = Development; + name = Release; }; /* End XCBuildConfiguration section */ @@ -2543,63 +3125,81 @@ 03067D730C83A3CB0022BE1F /* Build configuration list for PBXAggregateTarget "Build Some" */ = { isa = XCConfigurationList; buildConfigurations = ( - 03067D740C83A3CB0022BE1F /* Development */, + 03067D740C83A3CB0022BE1F /* Release */, + 0C419F141BA20DF600A70FF7 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; 213FB21B12028A7C002B3A08 /* Build configuration list for PBXNativeTarget "BonjourEvents" */ = { isa = XCConfigurationList; buildConfigurations = ( - 213FB21A12028A7B002B3A08 /* Development */, + 213FB21A12028A7B002B3A08 /* Release */, + 0C419F1D1BA20DF600A70FF7 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; 2141DD08123FFB830086D23E /* Build configuration list for PBXAggregateTarget "SystemLibraries" */ = { isa = XCConfigurationList; buildConfigurations = ( - 2141DCF9123FFB5D0086D23E /* Development */, + 2141DCF9123FFB5D0086D23E /* Release */, + 0C419F1E1BA20DF600A70FF7 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; 2141DD18123FFC990086D23E /* Build configuration list for PBXAggregateTarget "SystemLibrariesStatic" */ = { isa = XCConfigurationList; buildConfigurations = ( - 2141DD0C123FFC7F0086D23E /* Development */, + 2141DD0C123FFC7F0086D23E /* Release */, + 0C419F1F1BA20DF600A70FF7 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; 2141DD1F123FFCF90086D23E /* Build configuration list for PBXNativeTarget "libdns_sd_static" */ = { isa = XCConfigurationList; buildConfigurations = ( - 2141DD1E123FFCDB0086D23E /* Development */, + 2141DD1E123FFCDB0086D23E /* Release */, + 0C419F211BA20DF600A70FF7 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; 2141DD35123FFD3B0086D23E /* Build configuration list for PBXNativeTarget "libdns_sd_debug_static" */ = { isa = XCConfigurationList; buildConfigurations = ( - 2141DD25123FFD100086D23E /* Development */, + 2141DD25123FFD100086D23E /* Release */, + 0C419F221BA20DF600A70FF7 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; 2141DD36123FFD3B0086D23E /* Build configuration list for PBXNativeTarget "libdns_sd_profile_static" */ = { isa = XCConfigurationList; buildConfigurations = ( - 2141DD2B123FFD2C0086D23E /* Development */, + 2141DD2B123FFD2C0086D23E /* Release */, + 0C419F231BA20DF600A70FF7 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; 2E0405F30C31956600F13B59 /* Build configuration list for PBXNativeTarget "mDNSResponderHelper" */ = { isa = XCConfigurationList; buildConfigurations = ( - 2E0405F20C31955500F13B59 /* Development */, + 2E0405F20C31955500F13B59 /* Release */, + 0C419F171BA20DF600A70FF7 /* Debug */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 37DDE9311BA383610092AC61 /* Build configuration list for PBXNativeTarget "unittests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 37DDE9321BA383610092AC61 /* Development */, + 37AF80281BF6997A00D657F6 /* Release */, + 37AF80291BF6997A00D657F6 /* Debug */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Development; @@ -2607,130 +3207,146 @@ 4AE471770EAFF84000A6C5AD /* Build configuration list for PBXLegacyTarget "dns_sd.jar" */ = { isa = XCConfigurationList; buildConfigurations = ( - 4AE471680EAFF81900A6C5AD /* Development */, + 0C419F291BA20DF600A70FF7 /* Debug */, + 37AF80271BF6997A00D657F6 /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; 72FB5465166D5FB00090B2D9 /* Build configuration list for PBXNativeTarget "dnsctl" */ = { isa = XCConfigurationList; buildConfigurations = ( - 72FB5466166D5FB00090B2D9 /* Development */, + 72FB5466166D5FB00090B2D9 /* Release */, + 0C419F191BA20DF600A70FF7 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; 84C5B3361665529800C324A8 /* Build configuration list for PBXNativeTarget "dns_services" */ = { isa = XCConfigurationList; buildConfigurations = ( - 84C5B3371665529800C324A8 /* Development */, + 84C5B3371665529800C324A8 /* Release */, + 0C419F271BA20DF600A70FF7 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; D284BE280ADD78180027CCDF /* Build configuration list for PBXAggregateTarget "Build More" */ = { isa = XCConfigurationList; buildConfigurations = ( - D284BE290ADD78180027CCDF /* Development */, + D284BE290ADD78180027CCDF /* Release */, + 0C419F131BA20DF600A70FF7 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; D284BE2B0ADD78180027CCDF /* Build configuration list for PBXProject "mDNSResponder" */ = { isa = XCConfigurationList; buildConfigurations = ( - D284BE2C0ADD78180027CCDF /* Development */, + D284BE2C0ADD78180027CCDF /* Release */, + 0C419F121BA20DF600A70FF7 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; D284BE6D0ADD80740027CCDF /* Build configuration list for PBXNativeTarget "mDNSResponder" */ = { isa = XCConfigurationList; buildConfigurations = ( - D284BE6E0ADD80740027CCDF /* Development */, + D284BE6E0ADD80740027CCDF /* Release */, + 0C419F161BA20DF600A70FF7 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; D284BEAD0ADD80920027CCDF /* Build configuration list for PBXNativeTarget "dns-sd tool" */ = { isa = XCConfigurationList; buildConfigurations = ( - D284BEAE0ADD80920027CCDF /* Development */, + D284BEAE0ADD80920027CCDF /* Release */, + 0C419F181BA20DF600A70FF7 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; D284BEBB0ADD809A0027CCDF /* Build configuration list for PBXNativeTarget "libjdns_sd.jnilib" */ = { isa = XCConfigurationList; buildConfigurations = ( - D284BEBC0ADD809A0027CCDF /* Development */, + D284BEBC0ADD809A0027CCDF /* Release */, + 0C419F281BA20DF600A70FF7 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; D284BED60ADD80A20027CCDF /* Build configuration list for PBXNativeTarget "dnsextd" */ = { isa = XCConfigurationList; buildConfigurations = ( - D284BED70ADD80A20027CCDF /* Development */, + D284BED70ADD80A20027CCDF /* Release */, + 0C419F1A1BA20DF600A70FF7 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; D284BEE50ADD80A70027CCDF /* Build configuration list for PBXNativeTarget "ddnswriteconfig" */ = { isa = XCConfigurationList; buildConfigurations = ( - D284BEE60ADD80A70027CCDF /* Development */, + D284BEE60ADD80A70027CCDF /* Release */, + 0C419F1B1BA20DF600A70FF7 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; D284BF080ADD80B00027CCDF /* Build configuration list for PBXNativeTarget "PreferencePane" */ = { isa = XCConfigurationList; buildConfigurations = ( - D284BF090ADD80B00027CCDF /* Development */, + D284BF090ADD80B00027CCDF /* Release */, + 0C419F1C1BA20DF600A70FF7 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; FFA572370AF18F1C0055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd_debug_dynamic" */ = { isa = XCConfigurationList; buildConfigurations = ( - FFA572380AF18F1C0055A0F1 /* Development */, + FFA572380AF18F1C0055A0F1 /* Release */, + 0C419F251BA20DF600A70FF7 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; FFA572430AF18F450055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd_profile_dynamic" */ = { isa = XCConfigurationList; buildConfigurations = ( - FFA572440AF18F450055A0F1 /* Development */, + FFA572440AF18F450055A0F1 /* Release */, + 0C419F261BA20DF600A70FF7 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; FFA5726E0AF191200055A0F1 /* Build configuration list for PBXAggregateTarget "SystemLibrariesDynamic" */ = { isa = XCConfigurationList; buildConfigurations = ( - FFA5726F0AF191200055A0F1 /* Development */, + FFA5726F0AF191200055A0F1 /* Release */, + 0C419F201BA20DF600A70FF7 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; FFB7657E0AEED99D00583A2C /* Build configuration list for PBXAggregateTarget "Build All" */ = { isa = XCConfigurationList; buildConfigurations = ( - FFB7657F0AEED99D00583A2C /* Development */, + FFB7657F0AEED99D00583A2C /* Release */, + 0C419F151BA20DF600A70FF7 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; FFB765890AEED9FB00583A2C /* Build configuration list for PBXNativeTarget "libdns_sd_dynamic" */ = { isa = XCConfigurationList; buildConfigurations = ( - FFB7658A0AEED9FB00583A2C /* Development */, + FFB7658A0AEED9FB00583A2C /* Release */, + 0C419F241BA20DF600A70FF7 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Development; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/xcshareddata/xcschemes/Build All.xcscheme b/mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/xcshareddata/xcschemes/Build All.xcscheme new file mode 100644 index 00000000..6bc511e5 --- /dev/null +++ b/mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/xcshareddata/xcschemes/Build All.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/xcshareddata/xcschemes/mDNSResponder.xcscheme b/mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/xcshareddata/xcschemes/mDNSResponder.xcscheme new file mode 100644 index 00000000..7ba2fe06 --- /dev/null +++ b/mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/xcshareddata/xcschemes/mDNSResponder.xcscheme @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponderLogging.mobileconfig b/mDNSResponder/mDNSMacOSX/mDNSResponderLogging.mobileconfig deleted file mode 100644 index 34ec0d9a..00000000 --- a/mDNSResponder/mDNSMacOSX/mDNSResponderLogging.mobileconfig +++ /dev/null @@ -1,57 +0,0 @@ - - - - - PayloadIdentifier - com.apple.mDNSResponder - PayloadUUID - 6D0962E1-558A-44FB-8FE0-1F4F0BD157F4 - PayloadDescription - Turns on mDNSResponder Debug Logging - PayloadDisplayName - mDNSResponder Debug Logging - PayloadOrganization - Apple, Inc - PayloadType - Configuration - PayloadVersion - 2 - - ConsentText - - en - English consent text - jp - Japanese consent text - default - Default consent text - used if none of the other languages match - - - PayloadContent - - - PayloadUUID - 6D0962E1-558A-44FB-8FE0-1F4F0BD157F4 - PayloadIdentifier - com.apple.defaults.1 - PayloadType - com.apple.defaults.managed - PayloadVersion - 1 - PayloadContent - - - DefaultsDomainName - com.apple.mDNSResponder - DefaultsData - - EnableLogging - - - - - - - - - diff --git a/mDNSResponder/mDNSMacOSX/uDNSPathEvalulation.c b/mDNSResponder/mDNSMacOSX/uDNSPathEvalulation.c index 1314584d..cc0d0bae 100644 --- a/mDNSResponder/mDNSMacOSX/uDNSPathEvalulation.c +++ b/mDNSResponder/mDNSMacOSX/uDNSPathEvalulation.c @@ -20,7 +20,7 @@ #include //Gets the DNSPolicy from NW PATH EVALUATOR -mDNSexport void mDNSPlatformGetDNSRoutePolicy(mDNS *const m, DNSQuestion *q, mDNSBool *isCellBlocked) +mDNSexport void mDNSPlatformGetDNSRoutePolicy(mDNS *const m, DNSQuestion *q, mDNSBool *isBlocked) { (void) m; q->ServiceID = -1; // initialize the ServiceID to default value of -1 @@ -28,7 +28,7 @@ mDNSexport void mDNSPlatformGetDNSRoutePolicy(mDNS *const m, DNSQuestion *q, mDN // Return for non-unicast DNS queries, invalid pid, if NWPathEvaluation is already done by the client, or NWPathEvaluation not available on this OS if (mDNSOpaque16IsZero(q->TargetQID) || (q->pid < 0) || (q->flags & kDNSServiceFlagsPathEvaluationDone) || !nw_endpoint_create_host) { - *isCellBlocked = mDNSfalse; + *isBlocked = mDNSfalse; return; } @@ -142,10 +142,10 @@ mDNSexport void mDNSPlatformGetDNSRoutePolicy(mDNS *const m, DNSQuestion *q, mDN } } - if (isUUIDSet && TARGET_OS_IPHONE && nw_path_get_status(path) == nw_path_status_unsatisfied && nw_path_get_reason(path) == nw_path_reason_policy_drop) - *isCellBlocked = mDNStrue; + if (isUUIDSet && (nw_path_get_status(path) == nw_path_status_unsatisfied) && (nw_path_get_reason(path) == nw_path_reason_policy_drop)) + *isBlocked = mDNStrue; else - *isCellBlocked = mDNSfalse; + *isBlocked = mDNSfalse; if (path != NULL) network_release(path); diff --git a/mDNSResponder/mDNSPosix/._ReadMe.txt b/mDNSResponder/mDNSPosix/._ReadMe.txt deleted file mode 100755 index cd621b2a..00000000 Binary files a/mDNSResponder/mDNSPosix/._ReadMe.txt and /dev/null differ diff --git a/mDNSResponder/mDNSPosix/Makefile b/mDNSResponder/mDNSPosix/Makefile index de8bd00c..4f98e90f 100755 --- a/mDNSResponder/mDNSPosix/Makefile +++ b/mDNSResponder/mDNSPosix/Makefile @@ -146,6 +146,7 @@ ifeq ($(os),x) # we get build failures: ‘daemon’ is deprecated (declared at /usr/include/stdlib.h:283) CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp -Werror -Wdeclaration-after-statement \ -D__MAC_OS_X_VERSION_MIN_REQUIRED=__MAC_OS_X_VERSION_10_4 \ + -DHAVE_STRLCPY=1 \ -D__APPLE_USE_RFC_2292 #-Wunreachable-code CC = gcc LD = $(CC) -dynamiclib @@ -218,7 +219,7 @@ CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_OS) $(CFLAGS_DEBUG) all: setup Daemon libdns_sd Clients SAClient SAResponder SAProxyResponder Identify NetMonitor $(OPTIONALTARG) -install: setup InstalledDaemon InstalledStartup InstalledLib InstalledManPages InstalledClients $(OPTINSTALL) +install: setup InstalledStartup InstalledDaemon InstalledLib InstalledManPages InstalledClients $(OPTINSTALL) # 'setup' sets up the build directory structure the way we want setup: @@ -297,9 +298,10 @@ InstalledNSS: $(NSSINSTPATH)/$(NSSLINKNAME) /etc/nss_mdns.conf $(MANPATH)/man5/n @echo $+ " installed" # Note: If daemon already installed, we make sure it's stopped before overwriting it -$(INSTBASE)/sbin/mdnsd: $(BUILDDIR)/mdnsd +$(INSTBASE)/sbin/mdnsd: $(BUILDDIR)/mdnsd $(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME) @if test -x $@; then $(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME) stop; fi $(CP) $< $@ + @$(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME) start $(INSTBASE)/lib/libdns_sd.$(LDSUFFIX).$(LIBVERS): $(BUILDDIR)/libdns_sd.$(LDSUFFIX) $(CP) $< $@ @@ -312,12 +314,9 @@ endif $(INSTBASE)/include/dns_sd.h: $(SHAREDDIR)/dns_sd.h $(CP) $< $@ -# We make this target dependent on $(INSTBASE)/sbin/mdnsd because we need to ensure -# that the daemon is installed *before* we try to execute the command to start it. -$(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME): mdnsd.sh $(STARTUPSCRIPTDIR) $(INSTBASE)/sbin/mdnsd +$(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME): mdnsd.sh $(STARTUPSCRIPTDIR) $(CP) $< $@ chmod ugo+x $@ - $@ start ifdef RUNLEVELSCRIPTSDIR ifeq ($(wildcard $(RUNLEVELSCRIPTSDIR)/runlevels/default), $(RUNLEVELSCRIPTSDIR)/runlevels/default) $(LN) $@ $(RUNLEVELSCRIPTSDIR)/runlevels/default/mdns diff --git a/mDNSResponder/mDNSPosix/ReadMe.txt b/mDNSResponder/mDNSPosix/ReadMe.txt index a374ddf0..c2f56412 100755 --- a/mDNSResponder/mDNSPosix/ReadMe.txt +++ b/mDNSResponder/mDNSPosix/ReadMe.txt @@ -308,20 +308,6 @@ CVE-ID CVE-2011-0220 : JaeSeung Song of the Department of Computing at Imperial College London -Impact:  A local application may be able to cause a denial of service -Description:  A denial of service issue was addressed through -improved memory handling. -CVE-ID -CVE-2015-7988 : Alexandre Helie - -Impact:  A remote attacker may be able to cause unexpected -application termination or arbitrary code execution -Description:  Multiple memory corruption issues existed in DNS -data parsing. These issues were addressed through improved bounds -checking. -CVE-ID -CVE-2015-7987 : Alexandre Helie - To Do List ---------- • port to a System V that's not Solaris diff --git a/mDNSResponder/mDNSPosix/mDNSPosix.c b/mDNSResponder/mDNSPosix/mDNSPosix.c index 77b57149..07633703 100755 --- a/mDNSResponder/mDNSPosix/mDNSPosix.c +++ b/mDNSResponder/mDNSPosix/mDNSPosix.c @@ -147,7 +147,7 @@ mDNSlocal void SockAddrTomDNSAddr(const struct sockaddr *const sa, mDNSAddr *ipA // mDNS core calls this routine when it needs to send a packet. mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end, - mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, + mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, mDNSIPPort dstPort, mDNSBool useBackgroundTrafficClass) { int err = 0; @@ -320,13 +320,6 @@ mDNSlocal void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int s &senderAddr, senderPort, &destAddr, MulticastDNSPort, InterfaceID); } -mDNSexport mDNSBool mDNSPlatformPeekUDP(mDNS *const m, UDPSocket *src) -{ - (void)m; // unused - (void)src; // unused - return mDNSfalse; -} - mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS * const m, TCPSocketFlags flags, mDNSIPPort * port, mDNSBool useBackgroundTrafficClass) { (void)m; // Unused @@ -929,8 +922,8 @@ mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct // and skip the probe phase of the probe/announce packet sequence. intf->coreIntf.DirectLink = mDNSfalse; #ifdef DIRECTLINK_INTERFACE_NAME - if (strcmp(intfName, STRINGIFY(DIRECTLINK_INTERFACE_NAME)) == 0) - intf->coreIntf.DirectLink = mDNStrue; + if (strcmp(intfName, STRINGIFY(DIRECTLINK_INTERFACE_NAME)) == 0) + intf->coreIntf.DirectLink = mDNStrue; #endif intf->coreIntf.SupportsUnicastMDNSResponse = mDNStrue; @@ -1419,14 +1412,36 @@ mDNSexport void mDNSPlatformUnlock (const mDNS *const m) // On the Posix platform this maps directly to the ANSI C strcpy. mDNSexport void mDNSPlatformStrCopy(void *dst, const void *src) { - strcpy((char *)dst, (char *)src); + strcpy((char *)dst, (const char *)src); +} + +mDNSexport mDNSu32 mDNSPlatformStrLCopy(void *dst, const void *src, mDNSu32 len) +{ +#if HAVE_STRLCPY + return ((mDNSu32)strlcpy((char *)dst, (const char *)src, len)); +#else + size_t srcLen; + + srcLen = strlen((const char *)src); + if (srcLen < len) + { + memcpy(dst, src, srcLen + 1); + } + else if (len > 0) + { + memcpy(dst, src, len - 1); + ((char *)dst)[len - 1] = '\0'; + } + + return ((mDNSu32)srcLen); +#endif } // mDNS core calls this routine to get the length of a C string. // On the Posix platform this maps directly to the ANSI C strlen. mDNSexport mDNSu32 mDNSPlatformStrLen (const void *src) { - return strlen((char*)src); + return strlen((const char*)src); } // mDNS core calls this routine to copy memory. @@ -1558,10 +1573,10 @@ mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID Inte (void) iteration; } -mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const NetworkInterfaceInfo *intf) +mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID) { (void) rr; - (void) intf; + (void) InterfaceID; return 1; } @@ -1620,37 +1635,38 @@ mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifnam return mStatus_NoError; } -mDNSexport mStatus mDNSPlatformClearSPSMACAddr(void) +mDNSexport mStatus mDNSPlatformClearSPSData(void) { return mStatus_NoError; } +mDNSexport mStatus mDNSPlatformStoreOwnerOptRecord(char *ifname, DNSMessage *msg, int length) +{ + (void) ifname; // Unused + (void) msg; // Unused + (void) length; // Unused + return mStatus_UnsupportedErr; +} + mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock) { (void) sock; // unused - + return (mDNSu16)-1; } mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID) { (void) InterfaceID; // unused - - return mDNSfalse; -} - -mDNSexport void mDNSPlatformGetDNSRoutePolicy(mDNS *const m, DNSQuestion *q, mDNSBool *isCellBlocked) -{ - (void) m; - q->ServiceID = -1; - *isCellBlocked = mDNSfalse; + return mDNSfalse; } -mDNSexport void mDNSPlatformSetuDNSSocktOpt(UDPSocket *src, const mDNSAddr *dst, DNSQuestion *q) +mDNSexport void mDNSPlatformSetSocktOpt(void *sock, mDNSTransport_Type transType, mDNSAddr_Type addrType, DNSQuestion *q) { - (void) src; - (void) dst; + (void) sock; + (void) transType; + (void) addrType; (void) q; } diff --git a/mDNSResponder/mDNSPosix/mdnsd.sh b/mDNSResponder/mDNSPosix/mdnsd.sh index c43d9fcb..6e65612b 100644 --- a/mDNSResponder/mDNSPosix/mdnsd.sh +++ b/mDNSResponder/mDNSPosix/mdnsd.sh @@ -40,6 +40,7 @@ if [ -r /sbin/start-stop-daemon ]; then else killmdnsd() { kill -TERM `cat /var/run/mdnsd.pid` + sleep 1 } START= STOP=killmdnsd @@ -60,7 +61,6 @@ case "$1" in reload|restart|force-reload) echo -n "Restarting Apple Darwin Multicast DNS / DNS Service Discovery daemon:" $STOP $DAEMON - sleep 1 $START $DAEMON echo -n " mdnsd" ;; diff --git a/mDNSResponder/mDNSPosix/nss_mdns.c b/mDNSResponder/mDNSPosix/nss_mdns.c index ade4d4d2..afadb3c6 100755 --- a/mDNSResponder/mDNSPosix/nss_mdns.c +++ b/mDNSResponder/mDNSPosix/nss_mdns.c @@ -1088,6 +1088,7 @@ mdns_lookup_callback ns_type_t expected_rr_type = af_to_rr (result->hostent->h_addrtype); + // Idiot check class if (rrclass != C_IN) { syslog (LOG_WARNING, @@ -1269,6 +1270,7 @@ add_address_to_buffer (result_map_t * result, const void * data, int len) return NULL; } + // Idiot check if (len != result->hostent->h_length) { syslog (LOG_WARNING, @@ -1309,6 +1311,7 @@ contains_address (result_map_t * result, const void * data, int len) { int i; + // Idiot check if (len != result->hostent->h_length) { syslog (LOG_WARNING, @@ -2470,6 +2473,7 @@ cmp_dns_suffix (const char * name, const char * domain) const char * nametail; const char * domaintail; + // Idiot checks if (*name == 0 || *name == k_dns_separator) { // Name can't be empty or start with separator diff --git a/mDNSResponder/mDNSShared/PlatformCommon.c b/mDNSResponder/mDNSShared/PlatformCommon.c index 4f844560..49c8fd19 100644 --- a/mDNSResponder/mDNSShared/PlatformCommon.c +++ b/mDNSResponder/mDNSShared/PlatformCommon.c @@ -23,6 +23,10 @@ #include // Needed for sockaddr_in #include +#if APPLE_OSX_mDNSResponder +#include +#endif + #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above #include "DNSCommon.h" #include "PlatformCommon.h" @@ -174,6 +178,14 @@ mDNSexport void mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, m int syslog_level = LOG_ERR; switch (loglevel) { +#if APPLE_OSX_mDNSResponder + case MDNS_LOG_MSG: syslog_level = OS_LOG_TYPE_DEFAULT; break; + case MDNS_LOG_OPERATION: syslog_level = OS_LOG_TYPE_INFO; break; + case MDNS_LOG_SPS: syslog_level = OS_LOG_TYPE_INFO; break; + case MDNS_LOG_INFO: syslog_level = OS_LOG_TYPE_INFO; break; + case MDNS_LOG_DEBUG: syslog_level = OS_LOG_TYPE_DEBUG; break; + default: syslog_level = OS_LOG_TYPE_DEFAULT; break; +#else case MDNS_LOG_MSG: syslog_level = LOG_ERR; break; case MDNS_LOG_OPERATION: syslog_level = LOG_WARNING; break; case MDNS_LOG_SPS: syslog_level = LOG_NOTICE; break; @@ -182,6 +194,7 @@ mDNSexport void mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, m default: fprintf(stderr, "Unknown loglevel %d, assuming LOG_ERR\n", loglevel); fflush(stderr); +#endif } if (!log_inited) { openlog(ident, LOG_CONS, LOG_DAEMON); log_inited++; } diff --git a/mDNSResponder/mDNSShared/dns_sd.h b/mDNSResponder/mDNSShared/dns_sd.h index cf32ea1e..33ecfef2 100644 --- a/mDNSResponder/mDNSShared/dns_sd.h +++ b/mDNSResponder/mDNSShared/dns_sd.h @@ -66,7 +66,7 @@ */ #ifndef _DNS_SD_H -#define _DNS_SD_H 6254102 +#define _DNS_SD_H 7650102 #ifdef __cplusplus extern "C" { @@ -88,6 +88,13 @@ extern "C" { #define DNSSD_API #endif +#if defined(_WIN32) +#include +typedef SOCKET dnssd_sock_t; +#else +typedef int dnssd_sock_t; +#endif + /* stdint.h does not exist on FreeBSD 4.x; its types are defined in sys/types.h instead */ #if defined(__FreeBSD__) && (__FreeBSD__ < 5) #include @@ -180,6 +187,15 @@ enum * in the future they will be delivered as usual. */ + kDNSServiceFlagsAutoTrigger = 0x1, + /* Valid for browses using kDNSServiceInterfaceIndexAny. + * Will auto trigger the browse over AWDL as well once the service is discoveryed + * over BLE. + * This flag is an input value to DNSServiceBrowse(), which is why we can + * use the same value as kDNSServiceFlagsMoreComing, which is an output flag + * for various client callbacks. + */ + kDNSServiceFlagsAdd = 0x2, kDNSServiceFlagsDefault = 0x4, /* Flags for domain enumeration and browse/query reply callbacks. @@ -330,10 +346,21 @@ enum * * 5. Thread Safety * The dns_sd.h API does not presuppose any particular threading model, and consequently - * does no locking of its own (which would require linking some specific threading library). - * If client code calls API routines on the same DNSServiceRef concurrently - * from multiple threads, it is the client's responsibility to use a mutext - * lock or take similar appropriate precautions to serialize those calls. + * does no locking internally (which would require linking with a specific threading library). + * If the client concurrently, from multiple threads (or contexts), calls API routines using + * the same DNSServiceRef, it is the client's responsibility to provide mutual exclusion for + * that DNSServiceRef. + + * For example, use of DNSServiceRefDeallocate requires caution. A common mistake is as follows: + * Thread B calls DNSServiceRefDeallocate to deallocate sdRef while Thread A is processing events + * using sdRef. Doing this will lead to intermittent crashes on thread A if the sdRef is used after + * it was deallocated. + + * A telltale sign of this crash type is to see DNSServiceProcessResult on the stack preceding the + * actual crash location. + + * To state this more explicitly, mDNSResponder does not queue DNSServiceRefDeallocate so + * that it occurs discretely before or after an event is handled. */ kDNSServiceFlagsSuppressUnusable = 0x8000, @@ -405,7 +432,7 @@ enum kDNSServiceFlagsSecure = 0x200010, /* - * The response has been validated by verifying all the signaures in the response and was able to + * The response has been validated by verifying all the signatures in the response and was able to * build a successful authentication chain starting from a known trust anchor. */ @@ -673,24 +700,49 @@ enum * -- or -- * "Why is kDNSServiceMaxDomainName 1009, when the maximum legal domain name is 256 bytes?" * - * All strings used in the DNS-SD APIs are UTF-8 strings. Apart from the exceptions noted below, - * the APIs expect the strings to be properly escaped, using the conventional DNS escaping rules: + * All strings used in the DNS-SD APIs are UTF-8 strings. + * Apart from the exceptions noted below, the APIs expect the strings to be properly escaped, using the + * conventional DNS escaping rules, as used by the traditional DNS res_query() API, as described below: * - * '\\' represents a single literal '\' in the name - * '\.' represents a single literal '.' in the name + * Generally all UTF-8 characters (which includes all US ASCII characters) represent themselves, + * with two exceptions, the dot ('.') character, which is the label separator, + * and the backslash ('\') character, which is the escape character. + * The escape character ('\') is interpreted as described below: + * * '\ddd', where ddd is a three-digit decimal value from 000 to 255, - * represents a single literal byte with that value. - * A bare unescaped '.' is a label separator, marking a boundary between domain and subdomain. + * represents a single literal byte with that value. Any byte value may be + * represented in '\ddd' format, even characters that don't strictly need to be escaped. + * For example, the ASCII code for 'w' is 119, and therefore '\119' is equivalent to 'w'. + * Thus the command "ping '\119\119\119.apple.com'" is the equivalent to the command "ping 'www.apple.com'". + * Nonprinting ASCII characters in the range 0-31 are often represented this way. + * In particular, the ASCII NUL character (0) cannot appear in a C string because C uses it as the + * string terminator character, so ASCII NUL in a domain name has to be represented in a C string as '\000'. + * Other characters like space (ASCII code 32) are sometimes represented as '\032' + * in contexts where having an actual space character in a C string would be inconvenient. + * + * Otherwise, for all cases where a '\' is followed by anything other than a three-digit decimal value + * from 000 to 255, the character sequence '\x' represents a single literal occurrence of character 'x'. + * This is legal for any character, so, for example, '\w' is equivalent to 'w'. + * Thus the command "ping '\w\w\w.apple.com'" is the equivalent to the command "ping 'www.apple.com'". + * However, this encoding is most useful when representing the characters '.' and '\', + * which otherwise would have special meaning in DNS name strings. + * This means that the following encodings are particularly common: + * '\\' represents a single literal '\' in the name + * '\.' represents a single literal '.' in the name + * + * A lone escape character ('\') appearing at the end of a string is not allowed, since it is + * followed by neither a three-digit decimal value from 000 to 255 nor a single character. + * If a lone escape character ('\') does appear as the last character of a string, it is silently ignored. * * The exceptions, that do not use escaping, are the routines where the full * DNS name of a resource is broken, for convenience, into servicename/regtype/domain. * In these routines, the "servicename" is NOT escaped. It does not need to be, since * it is, by definition, just a single literal string. Any characters in that string * represent exactly what they are. The "regtype" portion is, technically speaking, - * escaped, but since legal regtypes are only allowed to contain letters, digits, - * and hyphens, there is nothing to escape, so the issue is moot. The "domain" - * portion is also escaped, though most domains in use on the public Internet - * today, like regtypes, don't contain any characters that need to be escaped. + * escaped, but since legal regtypes are only allowed to contain US ASCII letters, + * digits, and hyphens, there is nothing to escape, so the issue is moot. + * The "domain" portion is also escaped, though most domains in use on the public + * Internet today, like regtypes, don't contain any characters that need to be escaped. * As DNS-SD becomes more popular, rich-text domains for service discovery will * become common, so software should be written to cope with domains with escaping. * @@ -742,12 +794,23 @@ enum * in a way such that it does not inadvertently appear in service lists on * all the other machines on the network. * - * If the client passes kDNSServiceInterfaceIndexLocalOnly when browsing - * then it will find *all* records registered on that same local machine. - * Clients explicitly wishing to discover *only* LocalOnly services can - * accomplish this by inspecting the interfaceIndex of each service reported - * to their DNSServiceBrowseReply() callback function, and discarding those - * where the interface index is not kDNSServiceInterfaceIndexLocalOnly. + * If the client passes kDNSServiceInterfaceIndexLocalOnly when querying or + * browsing, then the LocalOnly authoritative records and /etc/hosts caches + * are searched and will find *all* records registered or configured on that + * same local machine. + * + * If interested in getting negative answers to local questions while querying + * or browsing, then set both the kDNSServiceInterfaceIndexLocalOnly and the + * kDNSServiceFlagsReturnIntermediates flags. If no local answers exist at this + * moment in time, then the reply will return an immediate negative answer. If + * local records are subsequently created that answer the question, then those + * answers will be delivered, for as long as the question is still active. + * + * Clients explicitly wishing to discover *only* LocalOnly services during a + * browse may do this, without flags, by inspecting the interfaceIndex of each + * service reported to a DNSServiceBrowseReply() callback function, and + * discarding those answers where the interface index is not set to + * kDNSServiceInterfaceIndexLocalOnly. * * kDNSServiceInterfaceIndexP2P is meaningful only in Browse, QueryRecord, Register, * and Resolve operations. It should not be used in other DNSService APIs. @@ -776,6 +839,7 @@ enum #define kDNSServiceInterfaceIndexLocalOnly ((uint32_t)-1) #define kDNSServiceInterfaceIndexUnicast ((uint32_t)-2) #define kDNSServiceInterfaceIndexP2P ((uint32_t)-3) +#define kDNSServiceInterfaceIndexBLE ((uint32_t)-4) typedef uint32_t DNSServiceFlags; typedef uint32_t DNSServiceProtocol; @@ -833,29 +897,6 @@ DNSServiceErrorType DNSSD_API DNSServiceGetProperty #define kDNSServiceProperty_DaemonVersion "DaemonVersion" - -// Map the source port of the local UDP socket that was opened for sending the DNS query -// to the process ID of the application that triggered the DNS resolution. -// -/* DNSServiceGetPID() Parameters: - * - * srcport: Source port (in network byte order) of the UDP socket that was created by - * the daemon to send the DNS query on the wire. - * - * pid: Process ID of the application that started the name resolution which triggered - * the daemon to send the query on the wire. The value can be -1 if the srcport - * cannot be mapped. - * - * return value: Returns kDNSServiceErr_NoError on success, or kDNSServiceErr_ServiceNotRunning - * if the daemon is not running. The value of the pid is undefined if the return - * value has error. - */ -DNSServiceErrorType DNSSD_API DNSServiceGetPID -( - uint16_t srcport, - int32_t *pid -); - /********************************************************************************************* * * Unix Domain Socket access, DNSServiceRef deallocation, and data processing functions @@ -876,8 +917,8 @@ DNSServiceErrorType DNSSD_API DNSServiceGetPID * a client can choose to fork a thread and have it loop calling "DNSServiceProcessResult(ref);" * If DNSServiceProcessResult() is called when no data is available for reading on the socket, it * will block until data does become available, and then process the data and return to the caller. - * The application is reponsible for checking the return value of DNSServiceProcessResult() to determine - * if the socket is valid and if it should continue to process data on the socket. + * The application is responsible for checking the return value of DNSServiceProcessResult() + * to determine if the socket is valid and if it should continue to process data on the socket. * When data arrives on the socket, the client is responsible for calling DNSServiceProcessResult(ref) * in a timely fashion -- if the client allows a large backlog of data to build up the daemon * may terminate the connection. @@ -888,7 +929,7 @@ DNSServiceErrorType DNSSD_API DNSServiceGetPID * error. */ -int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef); +dnssd_sock_t DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef); /* DNSServiceProcessResult() @@ -1237,7 +1278,7 @@ DNSServiceErrorType DNSSD_API DNSServiceRegister * Note that the DNSServiceAddRecord/UpdateRecord/RemoveRecord are *NOT* thread-safe * with respect to a single DNSServiceRef. If you plan to have multiple threads * in your program simultaneously add, update, or remove records from the same - * DNSServiceRef, then it's the caller's responsibility to use a mutext lock + * DNSServiceRef, then it's the caller's responsibility to use a mutex lock * or take similar appropriate precautions to serialize those calls. * * Parameters; @@ -2247,8 +2288,8 @@ typedef union _TXTRecordRef_t { char PrivateData[16]; char *ForceNaturalAlignmen * For most applications, DNS-SD TXT records are generally * less than 100 bytes, so in most cases a simple fixed-sized * 256-byte buffer will be more than sufficient. - * Recommended size limits for DNS-SD TXT Records are discussed in - * + * Recommended size limits for DNS-SD TXT Records are discussed in RFC 6763 + * * * Note: When passing parameters to and from these TXT record APIs, * the key name does not include the '=' character. The '=' character @@ -2298,8 +2339,8 @@ void DNSSD_API TXTRecordDeallocate * - Present with no value ("key" appears alone) * - Present with empty value ("key=" appears in TXT record) * - Present with non-empty value ("key=value" appears in TXT record) - * For more details refer to "Data Syntax for DNS-SD TXT Records" in - * + * For more details refer to "Data Syntax for DNS-SD TXT Records" in RFC 6763 + * * * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate(). * @@ -2611,13 +2652,6 @@ DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive ); #endif -#ifdef __APPLE_API_PRIVATE - -#define kDNSServiceCompPrivateDNS "PrivateDNS" -#define kDNSServiceCompMulticastDNS "MulticastDNS" - -#endif //__APPLE_API_PRIVATE - /* Some C compiler cleverness. We can make the compiler check certain things for us, * and report errors at compile-time if anything is wrong. The usual way to do this would * be to use a run-time "if" statement or the conventional run-time "assert" mechanism, but diff --git a/mDNSResponder/mDNSShared/dnssd_clientshim.c b/mDNSResponder/mDNSShared/dnssd_clientshim.c index f6997295..b4824b4d 100644 --- a/mDNSResponder/mDNSShared/dnssd_clientshim.c +++ b/mDNSResponder/mDNSShared/dnssd_clientshim.c @@ -97,7 +97,7 @@ typedef struct DNSQuestion q; } mDNS_DirectOP_QueryRecord; -int DNSServiceRefSockFD(DNSServiceRef sdRef) +dnssd_sock_t DNSServiceRefSockFD(DNSServiceRef sdRef) { (void)sdRef; // Unused return(0); diff --git a/mDNSResponder/mDNSShared/dnssd_clientstub.c b/mDNSResponder/mDNSShared/dnssd_clientstub.c index 5e151d08..5e12e0b1 100644 --- a/mDNSResponder/mDNSShared/dnssd_clientstub.c +++ b/mDNSResponder/mDNSShared/dnssd_clientstub.c @@ -172,6 +172,19 @@ struct _DNSRecordRef_t DNSServiceOp *sdr; }; +#if !defined(USE_TCP_LOOPBACK) +static void SetUDSPath(struct sockaddr_un *saddr, const char *path) +{ + size_t pathLen; + + pathLen = strlen(path); + if (pathLen < sizeof(saddr->sun_path)) + memcpy(saddr->sun_path, path, pathLen + 1); + else + saddr->sun_path[0] = '\0'; +} +#endif + // Write len bytes. Return 0 on success, -1 on error static int write_all(dnssd_sock_t sd, char *buf, size_t len) { @@ -185,7 +198,7 @@ static int write_all(dnssd_sock_t sd, char *buf, size_t len) // Should never happen. If it does, it indicates some OS bug, // or that the mDNSResponder daemon crashed (which should never happen). #if !defined(__ppc__) && defined(SO_ISDEFUNCT) - int defunct; + int defunct = 0; socklen_t dlen = sizeof (defunct); if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0) syslog(LOG_WARNING, "dnssd_clientstub write_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); @@ -272,6 +285,12 @@ static int more_bytes(dnssd_sock_t sd) fd_set *fs; int ret; +#if defined(_WIN32) + fs = &readfds; + FD_ZERO(fs); + FD_SET(sd, fs); + ret = select((int)sd+1, fs, (fd_set*)NULL, (fd_set*)NULL, &tv); +#else if (sd < FD_SETSIZE) { fs = &readfds; @@ -296,6 +315,7 @@ static int more_bytes(dnssd_sock_t sd) ret = select((int)sd+1, fs, (fd_set*)NULL, (fd_set*)NULL, &tv); if (fs != &readfds) free(fs); +#endif return (ret > 0); } @@ -561,7 +581,7 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f saddr.sin_port = htons(MDNS_TCP_SERVERPORT); #else saddr.sun_family = AF_LOCAL; - strcpy(saddr.sun_path, uds_serverpath); + SetUDSPath(&saddr, uds_serverpath); #if !defined(__ppc__) && defined(SO_DEFUNCTOK) { int defunct = 1; @@ -671,7 +691,7 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr) #ifndef NOT_HAVE_SA_LEN caddr.sun_len = sizeof(struct sockaddr_un); #endif - strcpy(caddr.sun_path, data); + SetUDSPath(&caddr, data); mask = umask(0); bindresult = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr)); umask(mask); @@ -852,7 +872,7 @@ cleanup: return err; } -int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef) +dnssd_sock_t DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef) { if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with NULL DNSServiceRef"); return dnssd_InvalidSocket; } @@ -869,7 +889,7 @@ int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef) return dnssd_InvalidSocket; } - return (int) sdRef->sockfd; + return sdRef->sockfd; } #if _DNS_SD_LIBDISPATCH @@ -1154,13 +1174,18 @@ void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef) DNSServiceErrorType DNSSD_API DNSServiceGetProperty(const char *property, void *result, uint32_t *size) { + DNSServiceErrorType err; char *ptr; - size_t len = strlen(property) + 1; + size_t len; ipc_msg_hdr *hdr; DNSServiceOp *tmp; uint32_t actualsize; - DNSServiceErrorType err = ConnectToServer(&tmp, 0, getproperty_request, NULL, NULL, NULL); + if (!property || !result || !size) + return kDNSServiceErr_BadParam; + + len = strlen(property) + 1; + err = ConnectToServer(&tmp, 0, getproperty_request, NULL, NULL, NULL); if (err) return err; hdr = create_hdr(getproperty_request, &len, &ptr, 0, tmp); @@ -1280,7 +1305,7 @@ DNSServiceErrorType DNSSD_API DNSServiceResolve ipc_msg_hdr *hdr; DNSServiceErrorType err; - if (!name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam; + if (!sdRef || !name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam; // Need a real InterfaceID for WakeOnResolve if ((flags & kDNSServiceFlagsWakeOnResolve) != 0 && @@ -1355,6 +1380,9 @@ DNSServiceErrorType DNSSD_API DNSServiceQueryRecord ipc_msg_hdr *hdr; DNSServiceErrorType err; + // NULL name handled below. + if (!sdRef || !callBack) return kDNSServiceErr_BadParam; + if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny()) flags |= kDNSServiceFlagsIncludeP2P; @@ -1464,7 +1492,7 @@ DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo ipc_msg_hdr *hdr; DNSServiceErrorType err; - if (!hostname) return kDNSServiceErr_BadParam; + if (!sdRef || !hostname || !callBack) return kDNSServiceErr_BadParam; err = ConnectToServer(sdRef, flags, addrinfo_request, handle_addrinfo_response, callBack, context); if (err) @@ -1518,6 +1546,9 @@ DNSServiceErrorType DNSSD_API DNSServiceBrowse ipc_msg_hdr *hdr; DNSServiceErrorType err; + // NULL domain handled below + if (!sdRef || !regtype || !callBack) return kDNSServiceErr_BadParam; + if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny()) flags |= kDNSServiceFlagsIncludeP2P; @@ -1546,11 +1577,16 @@ DNSServiceErrorType DNSSD_API DNSServiceBrowse DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain); DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain) { + DNSServiceErrorType err; DNSServiceOp *tmp; char *ptr; - size_t len = sizeof(flags) + strlen(domain) + 1; + size_t len; ipc_msg_hdr *hdr; - DNSServiceErrorType err = ConnectToServer(&tmp, 0, setdomain_request, NULL, NULL, NULL); + + if (!domain) return kDNSServiceErr_BadParam; + len = sizeof(flags) + strlen(domain) + 1; + + err = ConnectToServer(&tmp, 0, setdomain_request, NULL, NULL, NULL); if (err) return err; hdr = create_hdr(setdomain_request, &len, &ptr, 0, tmp); @@ -1596,8 +1632,8 @@ DNSServiceErrorType DNSSD_API DNSServiceRegister DNSServiceErrorType err; union { uint16_t s; u_char b[2]; } port = { PortInNetworkByteOrder }; + if (!sdRef || !regtype) return kDNSServiceErr_BadParam; if (!name) name = ""; - if (!regtype) return kDNSServiceErr_BadParam; if (!domain) domain = ""; if (!host) host = ""; if (!txtRecord) txtRecord = (void*)""; @@ -1659,9 +1695,13 @@ DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains size_t len; ipc_msg_hdr *hdr; DNSServiceErrorType err; + int f1; + int f2; + + if (!sdRef || !callBack) return kDNSServiceErr_BadParam; - int f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0; - int f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0; + f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0; + f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0; if (f1 + f2 != 1) return kDNSServiceErr_BadParam; err = ConnectToServer(sdRef, flags, enumeration_request, handle_enumeration_response, callBack, context); @@ -1736,10 +1776,13 @@ static void ConnectionResponse(DNSServiceOp *const sdr, const CallbackHeader *co DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef) { + DNSServiceErrorType err; char *ptr; size_t len = 0; ipc_msg_hdr *hdr; - DNSServiceErrorType err = ConnectToServer(sdRef, 0, connection_request, ConnectionResponse, NULL, NULL); + + if (!sdRef) return kDNSServiceErr_BadParam; + err = ConnectToServer(sdRef, 0, connection_request, ConnectionResponse, NULL, NULL); if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL hdr = create_hdr(connection_request, &len, &ptr, 0, *sdRef); @@ -1757,6 +1800,7 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef * size_t len = 0; ipc_msg_hdr *hdr; + if (!sdRef) return kDNSServiceErr_BadParam; DNSServiceErrorType err = ConnectToServer(sdRef, 0, connection_delegate_request, ConnectionResponse, NULL, NULL); if (err) { @@ -1846,7 +1890,11 @@ DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny()) flags |= kDNSServiceFlagsIncludeP2P; - if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; } + if (!sdRef || !RecordRef || !fullname || !rdata || !callBack) + { + syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with NULL parameter"); + return kDNSServiceErr_BadParam; + } if (!DNSServiceRefValid(sdRef)) { @@ -1927,8 +1975,11 @@ DNSServiceErrorType DNSSD_API DNSServiceAddRecord DNSRecordRef rref; DNSRecord **p; - if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; } - if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSRecordRef pointer"); return kDNSServiceErr_BadParam; } + if (!sdRef || !RecordRef || !rdata) + { + syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL parameter"); + return kDNSServiceErr_BadParam; + } if (sdRef->op != reg_service_request) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with non-DNSServiceRegister DNSServiceRef %p %d", sdRef, sdRef->op); @@ -1988,7 +2039,11 @@ DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord size_t len = 0; char *ptr; - if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; } + if (!sdRef || !rdata) + { + syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with NULL parameter"); + return kDNSServiceErr_BadParam; + } if (!DNSServiceRefValid(sdRef)) { @@ -2064,12 +2119,15 @@ DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord const void *rdata ) { + DNSServiceErrorType err; char *ptr; size_t len; ipc_msg_hdr *hdr; DNSServiceOp *tmp; - DNSServiceErrorType err = ConnectToServer(&tmp, flags, reconfirm_record_request, NULL, NULL, NULL); + if (!fullname || !rdata) return kDNSServiceErr_BadParam; + + err = ConnectToServer(&tmp, flags, reconfirm_record_request, NULL, NULL, NULL); if (err) return err; len = sizeof(DNSServiceFlags); diff --git a/mDNSResponder/mDNSShared/dnssd_ipc.h b/mDNSResponder/mDNSShared/dnssd_ipc.h index 7dc64c5f..96466a94 100644 --- a/mDNSResponder/mDNSShared/dnssd_ipc.h +++ b/mDNSResponder/mDNSShared/dnssd_ipc.h @@ -41,7 +41,6 @@ # define dnssd_EWOULDBLOCK WSAEWOULDBLOCK # define dnssd_EINTR WSAEINTR # define dnssd_ECONNRESET WSAECONNRESET -# define dnssd_sock_t SOCKET # define dnssd_socklen_t int # define dnssd_close(sock) closesocket(sock) # define dnssd_errno WSAGetLastError() @@ -67,7 +66,6 @@ extern char *win32_strerror(int inErrorCode); # define dnssd_EINTR EINTR # define dnssd_ECONNRESET ECONNRESET # define dnssd_EPIPE EPIPE -# define dnssd_sock_t int # define dnssd_socklen_t unsigned int # define dnssd_close(sock) close(sock) # define dnssd_errno errno diff --git a/mDNSResponder/mDNSShared/uds_daemon.c b/mDNSResponder/mDNSShared/uds_daemon.c index be89f319..0102453f 100644 --- a/mDNSResponder/mDNSShared/uds_daemon.c +++ b/mDNSResponder/mDNSShared/uds_daemon.c @@ -48,17 +48,18 @@ mDNSBool AlwaysAppendSearchDomains = mDNSfalse; #endif #endif -#ifdef LOCAL_PEERPID -#include // for LOCAL_PEERPID +#ifdef LOCAL_PEEREPID +#include // for LOCAL_PEEREPID #include // for getsockopt #include // for struct proc_bsdshortinfo #include // for proc_pidinfo() -#endif //LOCAL_PEERPID +#endif //LOCAL_PEEREPID //upto 16 characters of process name (defined in but we do not want to include that file) #define MAXCOMLEN 16 #if APPLE_OSX_mDNSResponder #include +#include "BLE.h" #if !NO_WCF @@ -225,7 +226,8 @@ struct request_state DNSServiceFlags flags; DNSQuestion q_all; DNSQuestion q_default; - } enumeration; + DNSQuestion q_autoall; + } enumeration; struct { DNSQuestion q; @@ -271,11 +273,19 @@ typedef struct reply_state mDNSexport mDNS mDNSStorage; mDNSexport const char ProgramName[] = "mDNSResponder"; +#if defined(USE_TCP_LOOPBACK) +static char* boundPath = NULL; +#else +static char* boundPath = MDNS_UDS_SERVERPATH; +#endif +#if DEBUG +#define MDNS_UDS_SERVERPATH_DEBUG "/var/tmp/mDNSResponder" +#endif static dnssd_sock_t listenfd = dnssd_InvalidSocket; static request_state *all_requests = NULL; -#ifdef LOCAL_PEERPID +#ifdef LOCAL_PEEREPID struct proc_bsdshortinfo proc; -#endif //LOCAL_PEERPID +#endif //LOCAL_PEEREPID mDNSlocal void set_peer_pid(request_state *request); mDNSlocal void LogMcastClientInfo(request_state *req); mDNSlocal void GetMcastClients(request_state *req); @@ -284,6 +294,13 @@ static mDNSu32 i_mcount; // sets mcount when McastLogging is enabled(PROF sign static mDNSu32 n_mrecords; // tracks the current active mcast records for McastLogging static mDNSu32 n_mquests; // tracks the current active mcast questions for McastLogging + +#if TARGET_OS_EMBEDDED +mDNSu32 curr_num_regservices = 0; +mDNSu32 max_num_regservices = 0; +#endif + + // Note asymmetry here between registration and browsing. // For service registrations we only automatically register in domains that explicitly appear in local configuration data // (so AutoRegistrationDomains could equally well be called SCPrefRegDomains) @@ -340,9 +357,9 @@ mDNSlocal void my_perror(char *errmsg) mDNSlocal void my_throttled_perror(char *err_msg) { static int uds_throttle_count = 0; - if ((uds_throttle_count++ % 250) == 0) + if ((uds_throttle_count++ % 250) == 0) my_perror(err_msg); -} +} // LogMcastQuestion/LogMcastQ should be called after the DNSQuestion struct is initialized(especially for q->TargetQID) // Hence all calls are made after mDNS_StartQuery()/mDNS_StopQuery()/mDNS_StopBrowse() is called. @@ -360,9 +377,11 @@ mDNSlocal void LogMcastQuestion(mDNS *const m, const DNSQuestion *const q, reque { mcount--; } - LogMcast("%s: %##s (%s) (%s) Client(%d)[%s]", status ? "+Question" : "-Question", q->qname.c, DNSTypeName(q->qtype), - q->InterfaceID == mDNSInterface_LocalOnly ? "lo" : q->InterfaceID == mDNSInterface_P2P ? "p2p" : - q->InterfaceID == mDNSInterface_Any ? "any" : InterfaceNameForID(m, q->InterfaceID), + LogMcast("%s: %##s (%s) (%s) Client(%d)[%s]", status ? "+Question" : "-Question", q->qname.c, DNSTypeName(q->qtype), + q->InterfaceID == mDNSInterface_LocalOnly ? "lo" : + q->InterfaceID == mDNSInterface_P2P ? "p2p" : + q->InterfaceID == mDNSInterface_BLE ? "BLE" : + q->InterfaceID == mDNSInterface_Any ? "any" : InterfaceNameForID(m, q->InterfaceID), req->process_id, req->pid_name); LogMcastStateInfo(m, mflag, mDNSfalse, mDNSfalse); } @@ -386,8 +405,10 @@ mDNSlocal void LogMcastService(mDNS *const m, const AuthRecord *const ar, reques mcount--; } LogMcast("%s: %##s (%s) (%s) Client(%d)[%s]", status ? "+Service" : "-Service", ar->resrec.name->c, DNSTypeName(ar->resrec.rrtype), - ar->resrec.InterfaceID == mDNSInterface_LocalOnly ? "lo" : ar->resrec.InterfaceID == mDNSInterface_P2P ? "p2p" : - ar->resrec.InterfaceID == mDNSInterface_Any ? "all" : InterfaceNameForID(m, ar->resrec.InterfaceID), + ar->resrec.InterfaceID == mDNSInterface_LocalOnly ? "lo" : + ar->resrec.InterfaceID == mDNSInterface_P2P ? "p2p" : + ar->resrec.InterfaceID == mDNSInterface_BLE ? "BLE" : + ar->resrec.InterfaceID == mDNSInterface_Any ? "all" : InterfaceNameForID(m, ar->resrec.InterfaceID), req->process_id, req->pid_name); LogMcastStateInfo(m, mflag, mDNSfalse, mDNSfalse); } @@ -407,13 +428,13 @@ mDNSexport void LogMcastStateInfo(mDNS *const m, mDNSBool mflag, mDNSBool start, { request_state *req, *r; for (req = all_requests; req; req=req->next) - { + { if (req->primary) // If this is a subbordinate operation, check that the parent is in the list - { - for (r = all_requests; r && r != req; r=r->next) - if (r == req->primary) + { + for (r = all_requests; r && r != req; r=r->next) + if (r == req->primary) goto foundpar; - } + } // For non-subbordinate operations, and subbordinate operations that have lost their parent, write out their info GetMcastClients(req); foundpar:; @@ -432,28 +453,28 @@ mDNSexport void LogMcastStateInfo(mDNS *const m, mDNSBool mflag, mDNSBool start, // wrong value if MulticastLogging is disabled and then re-enabled LogMcastNoIdent("--- START MCAST STATE LOG ---"); if (!all_requests) - { + { mcount = 0; LogMcastNoIdent(""); - } - else - { + } + else + { request_state *req, *r; for (req = all_requests; req; req=req->next) - { + { if (req->primary) // If this is a subbordinate operation, check that the parent is in the list - { - for (r = all_requests; r && r != req; r=r->next) - if (r == req->primary) + { + for (r = all_requests; r && r != req; r=r->next) + if (r == req->primary) goto foundparent; LogMcastNoIdent("%3d: Orphan operation; parent not found in request list", req->sd); - } + } // For non-subbordinate operations, and subbordinate operations that have lost their parent, write out their info LogMcastClientInfo(req); foundparent:; } if(!mcount) // To initially set mcount - mcount = i_mcount; + mcount = i_mcount; } if (mcount == 0) { @@ -461,7 +482,7 @@ mDNSexport void LogMcastStateInfo(mDNS *const m, mDNSBool mflag, mDNSBool start, LogMcastNoIdent("--- MCOUNT[%d]: IMPKTNUM[%d] ---", mcount, i_mpktnum); } if (mflag) - LogMcastNoIdent("--- MCOUNT[%d]: CMPKTNUM[%d] - IMPKTNUM[%d] = [%d]PKTS ---", mcount, m->MPktNum, i_mpktnum, (m->MPktNum - i_mpktnum)); + LogMcastNoIdent("--- MCOUNT[%d]: CMPKTNUM[%d] - IMPKTNUM[%d] = [%d]PKTS ---", mcount, m->MPktNum, i_mpktnum, (m->MPktNum - i_mpktnum)); LogMcastNoIdent("--- END MCAST STATE LOG ---"); } } @@ -507,6 +528,24 @@ mDNSlocal void abort_request(request_state *req) req->terminate = (req_termination_fn) ~0; } +#if DEBUG +mDNSexport void SetDebugBoundPath(void) +{ +#if !defined(USE_TCP_LOOPBACK) + boundPath = MDNS_UDS_SERVERPATH_DEBUG; +#endif +} + +mDNSexport int IsDebugSocketInUse(void) +{ +#if !defined(USE_TCP_LOOPBACK) + return !strcmp(boundPath, MDNS_UDS_SERVERPATH_DEBUG); +#else + return mDNSfalse; +#endif +} +#endif + mDNSlocal void AbortUnlinkAndFree(request_state *req) { request_state **p = &all_requests; @@ -611,9 +650,7 @@ mDNSlocal mStatus GenerateNTDResponse(const domainname *const servicename, const } } -// Special support to enable the DNSServiceBrowse call made by Bonjour Browser -// Remove after Bonjour Browser is updated to use DNSServiceQueryRecord instead of DNSServiceBrowse -mDNSlocal void GenerateBonjourBrowserResponse(const domainname *const servicename, const mDNSInterfaceID id, +mDNSlocal void GenerateBrowseReply(const domainname *const servicename, const mDNSInterfaceID id, request_state *const request, reply_state **const rep, reply_op_t op, DNSServiceFlags flags, mStatus err) { char namestr[MAX_DOMAIN_LABEL+1]; @@ -665,7 +702,7 @@ mDNSlocal AuthRecord *read_rr_from_ipc_msg(request_state *request, int GetTTL, i mDNSu16 rdlen = get_uint16(&request->msgptr, request->msgend); const char *rdata = get_rdata (&request->msgptr, request->msgend, rdlen); mDNSu32 ttl = GetTTL ? get_uint32(&request->msgptr, request->msgend) : 0; - int storage_size = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody); + size_t storage_size = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody); AuthRecord *rr; mDNSInterfaceID InterfaceID; AuthRecType artype; @@ -691,7 +728,7 @@ mDNSlocal AuthRecord *read_rr_from_ipc_msg(request_state *request, int GetTTL, i InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex); if (InterfaceID == mDNSInterface_LocalOnly) artype = AuthRecordLocalOnly; - else if (InterfaceID == mDNSInterface_P2P) + else if (InterfaceID == mDNSInterface_P2P || InterfaceID == mDNSInterface_BLE) artype = AuthRecordP2P; else if ((InterfaceID == mDNSInterface_Any) && (flags & kDNSServiceFlagsIncludeP2P) && (flags & kDNSServiceFlagsIncludeAWDL)) @@ -782,12 +819,14 @@ mDNSlocal mDNSBool AuthorizedDomain(const request_state * const request, const d #pragma mark - external helpers #endif -mDNSlocal mDNSBool callExternalHelpers(mDNSInterfaceID InterfaceID, const domainname *const domain, DNSServiceFlags flags) +mDNSexport mDNSBool callExternalHelpers(mDNSInterfaceID InterfaceID, const domainname *const domain, DNSServiceFlags flags) { #if APPLE_OSX_mDNSResponder - if ( ((InterfaceID == mDNSInterface_Any) && (flags & (kDNSServiceFlagsIncludeP2P | kDNSServiceFlagsIncludeAWDL)) && IsLocalDomain(domain)) - || mDNSPlatformInterfaceIsD2D(InterfaceID)) + // Only call D2D layer routines if request applies to a D2D interface and the domain is "local". + if ( (((InterfaceID == mDNSInterface_Any) && (flags & (kDNSServiceFlagsIncludeP2P | kDNSServiceFlagsIncludeAWDL | kDNSServiceFlagsAutoTrigger))) + || mDNSPlatformInterfaceIsD2D(InterfaceID) || (InterfaceID == mDNSInterface_BLE)) + && IsLocalDomain(domain)) { return mDNStrue; } @@ -822,6 +861,14 @@ mDNSlocal void external_start_advertising_helper(service_instance *const instanc external_start_advertising_service(&instance->srs.RR_PTR.resrec, instance->request->flags); external_start_advertising_service(&instance->srs.RR_SRV.resrec, instance->request->flags); + +#if APPLE_OSX_mDNSResponder + if (applyToBLE(instance->srs.RR_SRV.resrec.InterfaceID, instance->request->flags)) + { + start_BLE_advertise(& instance->srs, instance->srs.RR_SRV.resrec.name , instance->srs.RR_SRV.resrec.rrtype, instance->request->flags); + } +#endif // APPLE_OSX_mDNSResponder + external_start_advertising_service(&instance->srs.RR_TXT.resrec, instance->request->flags); for (e = instance->srs.Extras; e; e = e->next) @@ -1014,6 +1061,9 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m } else if (result == mStatus_MemFree) { +#if TARGET_OS_EMBEDDED + curr_num_regservices--; +#endif if (instance->request && instance->renameonmemfree) { external_stop_advertising_helper(instance); @@ -1148,24 +1198,24 @@ mDNSlocal void set_peer_pid(request_state *request) socklen_t len = sizeof(p); request->pid_name[0] = '\0'; request->process_id = -1; -#ifdef LOCAL_PEERPID - if (request->sd < 0) +#ifdef LOCAL_PEEREPID + if (request->sd < 0) return; - // to extract the pid value - if (getsockopt(request->sd, SOL_LOCAL, LOCAL_PEERPID, &p, &len) != 0) + // to extract the effective pid value + if (getsockopt(request->sd, SOL_LOCAL, LOCAL_PEEREPID, &p, &len) != 0) return; // to extract the process name from the pid value if (proc_pidinfo(p, PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) == 0) return; - mDNSPlatformStrCopy(request->pid_name, proc.pbsi_comm); + mDNSPlatformStrLCopy(request->pid_name, proc.pbsi_comm, sizeof(request->pid_name)); request->process_id = p; - debugf("set_peer_pid: Client PEERPID is %d %s", p, request->pid_name); -#else // !LOCAL_PEERPID + debugf("set_peer_pid: Client PEEREPID is %d %s", p, request->pid_name); +#else // !LOCAL_PEEREPID len = 0; LogInfo("set_peer_pid: Not Supported on this version of OS"); if (request->sd < 0) return; -#endif // LOCAL_PEERPID +#endif // LOCAL_PEEREPID } mDNSlocal void connection_termination(request_state *request) @@ -1196,7 +1246,7 @@ mDNSlocal void connection_termination(request_state *request) { registered_record_entry *ptr = request->u.reg_recs; LogOperation("%3d: DNSServiceRegisterRecord(%u %s) STOP PID[%d](%s)", request->sd, ptr->key, RRDisplayString(&mDNSStorage, &ptr->rr->resrec), request->process_id, request->pid_name); - request->u.reg_recs = request->u.reg_recs->next; + request->u.reg_recs = request->u.reg_recs->next; ptr->rr->RecordContext = NULL; if (ptr->external_advertise) { @@ -1248,7 +1298,7 @@ mDNSlocal mStatus handle_regrecord_request(request_state *request) } // allocate registration entry, link into list re = mallocL("registered_record_entry", sizeof(registered_record_entry)); - if (!re) + if (!re) FatalError("ERROR: malloc"); re->key = request->hdr.reg_index; re->rr = rr; @@ -1259,7 +1309,7 @@ mDNSlocal mStatus handle_regrecord_request(request_state *request) rr->RecordCallback = regrecord_callback; re->origInterfaceID = rr->resrec.InterfaceID; - if (rr->resrec.InterfaceID == mDNSInterface_P2P) + if (rr->resrec.InterfaceID == mDNSInterface_P2P) rr->resrec.InterfaceID = mDNSInterface_Any; #if 0 if (!AuthorizedDomain(request, rr->resrec.name, AutoRegistrationDomains)) return (mStatus_NoError); @@ -1267,7 +1317,7 @@ mDNSlocal mStatus handle_regrecord_request(request_state *request) if (rr->resrec.rroriginalttl == 0) rr->resrec.rroriginalttl = DefaultTTLforRRType(rr->resrec.rrtype); - LogOperation("%3d: DNSServiceRegisterRecord(%u %s) START PID[%d](%s)", request->sd, re->key, RRDisplayString(&mDNSStorage, &rr->resrec), + LogOperation("%3d: DNSServiceRegisterRecord(%u %s) START PID[%d](%s)", request->sd, re->key, RRDisplayString(&mDNSStorage, &rr->resrec), request->process_id, request->pid_name); err = mDNS_Register(&mDNSStorage, rr); @@ -1279,7 +1329,7 @@ mDNSlocal mStatus handle_regrecord_request(request_state *request) } else { - LogMcastS(&mDNSStorage, rr, request, reg_start); + LogMcastS(&mDNSStorage, rr, request, reg_start); re->next = request->u.reg_recs; request->u.reg_recs = re; } @@ -1291,17 +1341,17 @@ mDNSlocal void UpdateDeviceInfoRecord(mDNS *const m); mDNSlocal void regservice_termination_callback(request_state *request) { - if (!request) - { - LogMsg("regservice_termination_callback context is NULL"); - return; + if (!request) + { + LogMsg("regservice_termination_callback context is NULL"); + return; } while (request->u.servicereg.instances) { service_instance *p = request->u.servicereg.instances; request->u.servicereg.instances = request->u.servicereg.instances->next; // only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p) - LogOperation("%3d: DNSServiceRegister(%##s, %u) STOP PID[%d](%s)", request->sd, p->srs.RR_SRV.resrec.name->c, + LogOperation("%3d: DNSServiceRegister(%##s, %u) STOP PID[%d](%s)", request->sd, p->srs.RR_SRV.resrec.name->c, mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port), request->process_id, request->pid_name); external_stop_advertising_helper(p); @@ -1320,9 +1370,9 @@ mDNSlocal void regservice_termination_callback(request_state *request) } } if (request->u.servicereg.txtdata) - { - freeL("service_info txtdata", request->u.servicereg.txtdata); - request->u.servicereg.txtdata = NULL; + { + freeL("service_info txtdata", request->u.servicereg.txtdata); + request->u.servicereg.txtdata = NULL; } if (request->u.servicereg.autoname) { @@ -1347,7 +1397,7 @@ mDNSlocal mStatus add_record_to_service(request_state *request, service_instance ServiceRecordSet *srs = &instance->srs; mStatus result; mDNSu32 coreFlags = 0; // translate to corresponding mDNSCore flag definitions - int size = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody); + size_t size = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody); ExtraResourceRecord *extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size); if (!extra) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; } @@ -1363,15 +1413,15 @@ mDNSlocal mStatus add_record_to_service(request_state *request, service_instance coreFlags |= coreFlagIncludeP2P; if (request->flags & kDNSServiceFlagsIncludeAWDL) coreFlags |= coreFlagIncludeAWDL; - + result = mDNS_AddRecordToService(&mDNSStorage, srs, extra, &extra->r.rdatastorage, ttl, coreFlags); - if (result) - { - freeL("ExtraResourceRecord/add_record_to_service", extra); - return result; + if (result) + { + freeL("ExtraResourceRecord/add_record_to_service", extra); + return result; } LogMcastS(&mDNSStorage, &srs->RR_PTR, request, reg_start); - + extra->ClientID = request->hdr.reg_index; if ( instance->external_advertise && callExternalHelpers(request->u.servicereg.InterfaceID, &instance->domain, request->flags)) @@ -1437,14 +1487,7 @@ mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd if (external_advertise) { ResourceRecord ext = rr->resrec; - DNSServiceFlags flags = 0; - - // Since we don't have a copy of the flags value used when the record was registered, - // we'll have to derive it from the ARType field. - if (rr->ARType == AuthRecordAnyIncludeP2P) - flags |= kDNSServiceFlagsIncludeP2P; - else if (rr->ARType == AuthRecordAnyIncludeAWDL) - flags |= kDNSServiceFlagsIncludeAWDL; + DNSServiceFlags flags = deriveD2DFlagsFromAuthRecType(rr->ARType); if (ext.rdlength == oldrdlen && mDNSPlatformMemSame(&ext.rdata->u, &oldrd->u, oldrdlen)) goto exit; SetNewRData(&ext, oldrd, oldrdlen); @@ -1459,7 +1502,7 @@ exit: mDNSlocal mStatus update_record(AuthRecord *rr, mDNSu16 rdlen, const char *rdata, mDNSu32 ttl, const mDNSBool *const external_advertise) { mStatus result; - const int rdsize = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody); + const size_t rdsize = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody); RData *newrd = mallocL("RData/update_record", sizeof(RData) - sizeof(RDataBody) + rdsize); if (!newrd) FatalError("ERROR: malloc"); newrd->MaxRDLength = (mDNSu16) rdsize; @@ -1709,7 +1752,7 @@ mDNSexport mDNSs32 ChopSubTypes(char *regtype, char **AnonData) mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p, char **AnonData) { AuthRecord *st = mDNSNULL; - // + // // "p" is pointing at the regtype e.g., _http._tcp followed by ":" indicated // by AnonData being non-NULL which is in turn follwed by "," indicated by // NumSubTypes being non-zero. We need to skip the initial regtype to get to the actual @@ -1757,7 +1800,7 @@ mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p, char **Ano if (!MakeDomainNameFromDNSNameString(&st[i].namestorage, p)) { freeL("ServiceSubTypes", st); - if (*AnonData) + if (AnonData && *AnonData) freeL("AnonymousData", *AnonData); return(mDNSNULL); } @@ -1771,7 +1814,7 @@ mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p, char **Ano mDNSlocal mStatus register_service_instance(request_state *request, const domainname *domain) { service_instance **ptr, *instance; - const int extra_size = (request->u.servicereg.txtlen > sizeof(RDataBody)) ? (request->u.servicereg.txtlen - sizeof(RDataBody)) : 0; + size_t extra_size = (request->u.servicereg.txtlen > sizeof(RDataBody)) ? (request->u.servicereg.txtlen - sizeof(RDataBody)) : 0; const mDNSBool DomainIsLocal = SameDomainName(domain, &localdomain); mStatus result; mDNSInterfaceID interfaceID = request->u.servicereg.InterfaceID; @@ -1828,14 +1871,14 @@ mDNSlocal mStatus register_service_instance(request_state *request, const domain char *AnonData = mDNSNULL; instance->subtypes = AllocateSubTypes(request->u.servicereg.num_subtypes, request->u.servicereg.type_as_string, &AnonData); if (AnonData) - instance->srs.AnonData = (const mDNSu8 *)AnonData; + instance->srs.AnonData = (const mDNSu8 *)AnonData; } if (request->u.servicereg.num_subtypes && !instance->subtypes) - { - unlink_and_free_service_instance(instance); - instance = NULL; - FatalError("ERROR: malloc"); + { + unlink_and_free_service_instance(instance); + instance = NULL; + FatalError("ERROR: malloc"); } result = mDNS_RegisterService(&mDNSStorage, &instance->srs, @@ -1849,7 +1892,7 @@ mDNSlocal mStatus register_service_instance(request_state *request, const domain if (!result) { *ptr = instance; // Append this to the end of our request->u.servicereg.instances list - LogOperation("%3d: DNSServiceRegister(%##s, %u) ADDED", instance->request->sd, + LogOperation("%3d: DNSServiceRegister(%##s, %u) ADDED", instance->request->sd, instance->srs.RR_SRV.resrec.name->c, mDNSVal16(request->u.servicereg.port)); LogMcastS(&mDNSStorage, &instance->srs.RR_SRV, request, reg_start); } @@ -1867,10 +1910,6 @@ mDNSlocal void udsserver_default_reg_domain_changed(const DNameListElem *const d { request_state *request; -#if APPLE_OSX_mDNSResponder - machserver_automatic_registration_domain_changed(&d->name, add); -#endif // APPLE_OSX_mDNSResponder - LogMsg("%s registration domain %##s", add ? "Adding" : "Removing", d->name.c); for (request = all_requests; request; request = request->next) { @@ -2045,7 +2084,7 @@ mDNSlocal mStatus handle_regservice_request(request_state *request) request->u.servicereg.instances = NULL; request->u.servicereg.txtlen = 0; request->u.servicereg.txtdata = NULL; - mDNSPlatformStrCopy(request->u.servicereg.type_as_string, type_as_string); + mDNSPlatformStrLCopy(request->u.servicereg.type_as_string, type_as_string, sizeof(request->u.servicereg.type_as_string)); if (request->msgptr + 2 > request->msgend) request->msgptr = NULL; else @@ -2148,7 +2187,7 @@ mDNSlocal mStatus handle_regservice_request(request_state *request) } LogOperation("%3d: DNSServiceRegister(%X, %d, \"%s\", \"%s\", \"%s\", \"%s\", %u) START PID[%d](%s)", - request->sd, flags, interfaceIndex, name, request->u.servicereg.type_as_string, domain, host, + request->sd, flags, interfaceIndex, name, request->u.servicereg.type_as_string, domain, host, mDNSVal16(request->u.servicereg.port), request->process_id, request->pid_name); // We need to unconditionally set request->terminate, because even if we didn't successfully @@ -2160,6 +2199,12 @@ mDNSlocal mStatus handle_regservice_request(request_state *request) request->terminate = regservice_termination_callback; err = register_service_instance(request, &d); + +#if TARGET_OS_EMBEDDED + ++curr_num_regservices; + if (curr_num_regservices > max_num_regservices) + max_num_regservices = curr_num_regservices; +#endif #if 0 err = AuthorizedDomain(request, &d, AutoRegistrationDomains) ? register_service_instance(request, &d) : mStatus_NoError; @@ -2179,7 +2224,7 @@ mDNSlocal mStatus handle_regservice_request(request_state *request) } return(err); - + bad_param: freeL("handle_regservice_request (txtdata)", request->u.servicereg.txtdata); request->u.servicereg.txtdata = NULL; @@ -2207,14 +2252,21 @@ mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const Resourc flags |= kDNSServiceFlagsThresholdReached; } + // if returning a negative answer, then use question's name in reply + if (answer->RecordType == kDNSRecordTypePacketNegative) + { + GenerateBrowseReply(&question->qname, answer->InterfaceID, req, &rep, browse_reply_op, flags, kDNSServiceErr_NoSuchRecord); + goto validReply; + } + if (GenerateNTDResponse(&answer->rdata->u.name, answer->InterfaceID, req, &rep, browse_reply_op, flags, mStatus_NoError) != mStatus_NoError) { if (SameDomainName(&req->u.browser.regtype, (const domainname*)"\x09_services\x07_dns-sd\x04_udp")) { // Special support to enable the DNSServiceBrowse call made by Bonjour Browser // Remove after Bonjour Browser is updated to use DNSServiceQueryRecord instead of DNSServiceBrowse - GenerateBonjourBrowserResponse(&answer->rdata->u.name, answer->InterfaceID, req, &rep, browse_reply_op, flags, mStatus_NoError); - goto bonjourbrowserhack; + GenerateBrowseReply(&answer->rdata->u.name, answer->InterfaceID, req, &rep, browse_reply_op, flags, mStatus_NoError); + goto validReply; } LogMsg("%3d: FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer", @@ -2222,7 +2274,7 @@ mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const Resourc return; } -bonjourbrowserhack: +validReply: LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %d: %s", req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", @@ -2231,6 +2283,36 @@ bonjourbrowserhack: append_reply(req, rep); } +mDNSlocal void SetQuestionPolicy(DNSQuestion *q, request_state *req) +{ + int i; + q->euid = req->uid; + // The policy is either based on pid or UUID. Pass a zero pid + // to the "core" if the UUID is valid. If we always pass the pid, + // then the "core" needs to determine whether the uuid is valid + // by examining all the 16 bytes at the time of the policy + // check and also when setting the delegate socket option. Also, it + // requires that we zero out the uuid wherever the question is + // initialized to make sure that it is not interpreted as valid. + // To prevent these intrusive changes, just pass a zero pid to indicate + // that pid is not valid when uuid is valid. In future if we need the + // pid in the question, we will reevaluate this strategy. + if (req->validUUID) + { + for (i = 0; i < UUID_SIZE; i++) + { + q->uuid[i] = req->uuid[i]; + } + q->pid = 0; + } + else + { + q->pid = req->process_id; + } + + //debugf("SetQuestionPolicy: q->euid[%d] q->pid[%d] uuid is valid : %s", q->euid, q->pid, req->validUUID ? "true" : "false"); +} + mDNSlocal mStatus add_domain_to_browser(request_state *info, const domainname *d) { browser_t *b, *p; @@ -2244,8 +2326,10 @@ mDNSlocal mStatus add_domain_to_browser(request_state *info, const domainname *d b = mallocL("browser_t", sizeof(*b)); if (!b) return mStatus_NoMemoryErr; + mDNSPlatformMemZero(b, sizeof(*b)); AssignDomainName(&b->domain, d); - err = mDNS_StartBrowse(&mDNSStorage, &b->q, &info->u.browser.regtype, d, info->u.browser.AnonData, info->u.browser.interface_id, info->flags, + SetQuestionPolicy(&b->q, info); + err = mDNS_StartBrowse(&mDNSStorage, &b->q, &info->u.browser.regtype, d, info->u.browser.AnonData, info->u.browser.interface_id, info->flags, info->u.browser.ForceMCast, (info->flags & kDNSServiceFlagsBackgroundTrafficClass) != 0, FoundInstance, info); if (err) { @@ -2256,7 +2340,7 @@ mDNSlocal mStatus add_domain_to_browser(request_state *info, const domainname *d { b->next = info->u.browser.browsers; info->u.browser.browsers = b; - LogOperation("%3d: DNSServiceBrowse(%##s) START PID[%d](%s)", info->sd, b->q.qname.c, info->process_id, + LogOperation("%3d: DNSServiceBrowse(%##s) START PID[%d](%s)", info->sd, b->q.qname.c, info->process_id, info->pid_name); LogMcastQ(&mDNSStorage, &b->q, info, q_start); if (callExternalHelpers(info->u.browser.interface_id, &b->domain, info->flags)) @@ -2264,7 +2348,7 @@ mDNSlocal mStatus add_domain_to_browser(request_state *info, const domainname *d domainname tmp; ConstructServiceName(&tmp, NULL, &info->u.browser.regtype, &b->domain); LogInfo("add_domain_to_browser: calling external_start_browsing_for_service()"); - external_start_browsing_for_service(info->u.browser.interface_id, &tmp, kDNSType_PTR, info->flags); + external_start_browsing_for_service(info->u.browser.interface_id, &tmp, kDNSType_PTR, info->flags, &b->q); } } return err; @@ -2284,18 +2368,18 @@ mDNSlocal void browse_termination_callback(request_state *info) { browser_t *ptr = info->u.browser.browsers; - if (callExternalHelpers(info->u.browser.interface_id, &ptr->domain, info->flags)) + if (callExternalHelpers(ptr->q.InterfaceID, &ptr->domain, ptr->q.flags)) { domainname tmp; ConstructServiceName(&tmp, NULL, &info->u.browser.regtype, &ptr->domain); LogInfo("browse_termination_callback: calling external_stop_browsing_for_service()"); - external_stop_browsing_for_service(info->u.browser.interface_id, &tmp, kDNSType_PTR, info->flags); + external_stop_browsing_for_service(ptr->q.InterfaceID, &tmp, kDNSType_PTR, ptr->q.flags); } info->u.browser.browsers = ptr->next; LogOperation("%3d: DNSServiceBrowse(%##s) STOP PID[%d](%s)", info->sd, ptr->q.qname.c, info->process_id, info->pid_name); mDNS_StopBrowse(&mDNSStorage, &ptr->q); // no need to error-check result - LogMcastQ(&mDNSStorage, &ptr->q, info, q_stop); + LogMcastQ(&mDNSStorage, &ptr->q, info, q_stop); freeL("browser_t/browse_termination_callback", ptr); } } @@ -2305,10 +2389,6 @@ mDNSlocal void udsserver_automatic_browse_domain_changed(const DNameListElem *co request_state *request; debugf("udsserver_automatic_browse_domain_changed: %s default browse domain %##s", add ? "Adding" : "Removing", d->name.c); -#if APPLE_OSX_mDNSResponder - machserver_automatic_browse_domain_changed(&d->name, add); -#endif // APPLE_OSX_mDNSResponder - for (request = all_requests; request; request = request->next) { if (request->terminate != browse_termination_callback) continue; // Not a browse operation @@ -2665,7 +2745,7 @@ mDNSlocal mStatus handle_browse_request(request_state *request) if (!MakeDomainNameFromDNSNameString(&temp, regtype)) return(mStatus_BadParamErr); // For over-long service types, we only allow domain "local" - if (temp.c[0] > 15 && domain[0] == 0) mDNSPlatformStrCopy(domain, "local."); + if (temp.c[0] > 15 && domain[0] == 0) mDNSPlatformStrLCopy(domain, "local.", sizeof(domain)); // Set up browser info request->u.browser.ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0; @@ -2674,7 +2754,7 @@ mDNSlocal mStatus handle_browse_request(request_state *request) request->u.browser.default_domain = !domain[0]; request->u.browser.browsers = NULL; - LogOperation("%3d: DNSServiceBrowse(%X, %d, \"%##s\", \"%s\") START PID[%d](%s)", + LogOperation("%3d: DNSServiceBrowse(%X, %d, \"%##s\", \"%s\") START PID[%d](%s)", request->sd, request->flags, interfaceIndex, request->u.browser.regtype.c, domain, request->process_id, request->pid_name); if (request->u.browser.default_domain) @@ -2730,10 +2810,12 @@ mDNSlocal mStatus handle_browse_request(request_state *request) mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) { size_t len = 0; - char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME]; + char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME] = "0"; char *data; reply_state *rep; request_state *req = question->QuestionContext; + const DNSServiceErrorType error = + (answer->RecordType == kDNSRecordTypePacketNegative) ? kDNSServiceErr_NoSuchRecord : kDNSServiceErr_NoError; (void)m; // Unused LogOperation("%3d: DNSServiceResolve(%##s) %s %s", req->sd, question->qname.c, AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer)); @@ -2751,7 +2833,9 @@ mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, con if (!req->u.resolve.txt || !req->u.resolve.srv) return; // only deliver result to client if we have both answers ConvertDomainNameToCString(answer->name, fullname); - ConvertDomainNameToCString(&req->u.resolve.srv->rdata->u.srv.target, target); + + if (answer->RecordType != kDNSRecordTypePacketNegative) + ConvertDomainNameToCString(&req->u.resolve.srv->rdata->u.srv.target, target); // calculate reply length len += sizeof(DNSServiceFlags); @@ -2766,7 +2850,7 @@ mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, con rep = create_reply(resolve_reply_op, len, req); rep->rhdr->flags = dnssd_htonl(0); rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse)); - rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError); + rep->rhdr->error = dnssd_htonl(error); data = (char *)&rep->rhdr[1]; @@ -2788,7 +2872,7 @@ mDNSlocal void resolve_termination_callback(request_state *request) mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qtxt); mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv); LogMcastQ(&mDNSStorage, &request->u.resolve.qsrv, request, q_stop); - if (request->u.resolve.external_advertise) + if (request->u.resolve.external_advertise) external_stop_resolving_service(request->u.resolve.qsrv.InterfaceID, &request->u.resolve.qsrv.qname, request->flags); } @@ -2858,8 +2942,6 @@ mDNSlocal mStatus handle_resolve_request(request_state *request) request->u.resolve.qsrv.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0; request->u.resolve.qsrv.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0; request->u.resolve.qsrv.SuppressUnusable = mDNSfalse; - request->u.resolve.qsrv.DenyOnCellInterface = mDNSfalse; - request->u.resolve.qsrv.DenyOnExpInterface = mDNSfalse; request->u.resolve.qsrv.SearchListIndex = 0; request->u.resolve.qsrv.AppendSearchDomains = 0; request->u.resolve.qsrv.RetryWithSearchDomains = mDNSfalse; @@ -2887,8 +2969,6 @@ mDNSlocal mStatus handle_resolve_request(request_state *request) request->u.resolve.qtxt.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0; request->u.resolve.qtxt.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0; request->u.resolve.qtxt.SuppressUnusable = mDNSfalse; - request->u.resolve.qtxt.DenyOnCellInterface = mDNSfalse; - request->u.resolve.qtxt.DenyOnExpInterface = mDNSfalse; request->u.resolve.qtxt.SearchListIndex = 0; request->u.resolve.qtxt.AppendSearchDomains = 0; request->u.resolve.qtxt.RetryWithSearchDomains = mDNSfalse; @@ -2914,15 +2994,15 @@ mDNSlocal mStatus handle_resolve_request(request_state *request) #endif // ask the questions - LogOperation("%3d: DNSServiceResolve(%X %d %##s) START PID[%d](%s)", request->sd, flags, interfaceIndex, - request->u.resolve.qsrv.qname.c, request->process_id, request->pid_name); + LogOperation("%3d: DNSServiceResolve(%X %d %##s) START PID[%d](%s)", request->sd, flags, interfaceIndex, + request->u.resolve.qsrv.qname.c, request->process_id, request->pid_name); err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qsrv); - + if (!err) { err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qtxt); if (err) - { + { mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv); } else @@ -3198,7 +3278,7 @@ mDNSlocal mStatus SendAdditionalQuery(DNSQuestion *q, request_state *request, mS (void) q; (void) request; (void) err; - + return mStatus_NoError; #endif // !UNICAST_DISABLED } @@ -3279,7 +3359,7 @@ mDNSlocal void queryrecord_result_reply(mDNS *const m, request_state *req, DNSQu rep = create_reply(req->hdr.op == query_request ? query_reply_op : addrinfo_reply_op, len, req); if (AddRecord) - flags |= kDNSServiceFlagsAdd; + flags |= kDNSServiceFlagsAdd; if (question->ValidationStatus != 0) { error = kDNSServiceErr_NoError; @@ -3304,7 +3384,7 @@ mDNSlocal void queryrecord_result_reply(mDNS *const m, request_state *req, DNSQu } } } - + rep->rhdr->flags = dnssd_htonl(flags); // Call mDNSPlatformInterfaceIndexfromInterfaceID, but suppressNetworkChange (last argument). Otherwise, if the // InterfaceID is not valid, then it simulates a "NetworkChanged" which in turn makes questions @@ -3622,7 +3702,7 @@ mDNSlocal void queryrecord_result_callback(mDNS *const m, DNSQuestion *question, mDNSlocal void queryrecord_termination_callback(request_state *request) { LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP PID[%d](%s)", - request->sd, request->u.queryrecord.q.qname.c, DNSTypeName(request->u.queryrecord.q.qtype), request->process_id, request->pid_name); + request->sd, request->u.queryrecord.q.qname.c, DNSTypeName(request->u.queryrecord.q.qtype), request->process_id, request->pid_name); if (request->u.queryrecord.q.QuestionContext) { mDNS_StopQuery(&mDNSStorage, &request->u.queryrecord.q); // no need to error check @@ -3686,40 +3766,11 @@ mDNSlocal void queryrecord_termination_callback(request_state *request) #endif // APPLE_OSX_mDNSResponder } -mDNSlocal void SetQuestionPolicy(DNSQuestion *q, request_state *req) -{ - int i; - q->euid = req->uid; - // The policy is either based on pid or UUID. Pass a zero pid - // to the "core" if the UUID is valid. If we always pass the pid, - // then the "core" needs to determine whether the uuid is valid - // by examining all the 16 bytes at the time of the policy - // check and also when setting the delegate socket option. Also, it - // requires that we zero out the uuid wherever the question is - // initialized to make sure that it is not interpreted as valid. - // To prevent these intrusive changes, just pass a zero pid to indicate - // that pid is not valid when uuid is valid. In future if we need the - // pid in the question, we will reevaluate this strategy. - if (req->validUUID) - { - for (i = 0; i < UUID_SIZE; i++) - { - q->uuid[i] = req->uuid[i]; - } - q->pid = 0; - } - else - { - q->pid = req->process_id; - } - - //debugf("SetQuestionPolicy: q->euid[%d] q->pid[%d] uuid is valid : %s", q->euid, q->pid, req->validUUID ? "true" : "false"); -} - mDNSlocal mStatus handle_queryrecord_request(request_state *request) { DNSQuestion *const q = &request->u.queryrecord.q; char name[256]; + size_t nameLen; mDNSu16 rrtype, rrclass; mStatus err; @@ -3731,6 +3782,9 @@ mDNSlocal mStatus handle_queryrecord_request(request_state *request) // interface is not currently in our list. if (interfaceIndex && !InterfaceID) { + if (interfaceIndex > 1) + LogMsg("handle_queryrecord_request: interfaceIndex %d is currently inactive requested by client[%d][%s]", + interfaceIndex, request->process_id, request->pid_name); // If it's one of the specially defined inteface index values, just return an error. // Also, caller should return an error immediately if lo0 (index 1) is not configured // into the current active interfaces. See background in Radar 21967160. @@ -3774,8 +3828,6 @@ mDNSlocal mStatus handle_queryrecord_request(request_state *request) q->TimeoutQuestion = (flags & kDNSServiceFlagsTimeout ) != 0; q->WakeOnResolve = 0; q->UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0; - q->DenyOnCellInterface = (flags & kDNSServiceFlagsDenyCellular) != 0; - q->DenyOnExpInterface = (flags & kDNSServiceFlagsDenyExpensive) != 0; if ((flags & kDNSServiceFlagsValidate) != 0) q->ValidationRequired = DNSSEC_VALIDATION_SECURE; else if ((flags & kDNSServiceFlagsValidateOptional) != 0) @@ -3793,7 +3845,7 @@ mDNSlocal mStatus handle_queryrecord_request(request_state *request) //Turn off dnssec validation for local domains and Question Types: RRSIG/ANY(ANY Type is not supported yet) if ((IsLocalDomain(&q->qname)) || (q->qtype == kDNSServiceType_RRSIG) || (q->qtype == kDNSServiceType_ANY)) q->ValidationRequired = 0; - + // Don't append search domains for fully qualified domain names including queries // such as e.g., "abc." that has only one label. We convert all names to FQDNs as internally // we only deal with FQDNs. Hence, we cannot look at qname to figure out whether we should @@ -3803,9 +3855,10 @@ mDNSlocal mStatus handle_queryrecord_request(request_state *request) // argument "AlwaysAppendSearchDomains", then we do it for any query which is not fully qualified. // For DNSSEC questions, append search domains only if kDNSServiceFlagsValidateOptional is set. - if ((!(q->ValidationRequired == DNSSEC_VALIDATION_SECURE)) && (!(q->ValidationRequired == DNSSEC_VALIDATION_INSECURE)) - && (rrtype == kDNSType_A || rrtype == kDNSType_AAAA) && name[strlen(name) - 1] != '.' && - (AlwaysAppendSearchDomains || CountLabels(&q->qname) == 1)) + nameLen = strlen(name); + if ((!(q->ValidationRequired == DNSSEC_VALIDATION_SECURE)) && (!(q->ValidationRequired == DNSSEC_VALIDATION_INSECURE)) + && (rrtype == kDNSType_A || rrtype == kDNSType_AAAA) && ((nameLen == 0) || (name[nameLen - 1] != '.')) && + (AlwaysAppendSearchDomains || CountLabels(&q->qname) == 1)) { q->AppendSearchDomains = 1; q->AppendLocalSearchDomains = 1; @@ -3825,13 +3878,13 @@ mDNSlocal mStatus handle_queryrecord_request(request_state *request) SetQuestionPolicy(q, request); LogOperation("%3d: DNSServiceQueryRecord(%X, %d, %##s, %s) START PID[%d](%s)", - request->sd, flags, interfaceIndex, q->qname.c, DNSTypeName(q->qtype), request->process_id, request->pid_name); + request->sd, flags, interfaceIndex, q->qname.c, DNSTypeName(q->qtype), request->process_id, request->pid_name); err = mDNS_StartQuery(&mDNSStorage, q); - + if (err) - { + { LogMsg("%3d: ERROR: DNSServiceQueryRecord %##s %s mDNS_StartQuery: %d", request->sd, q->qname.c, DNSTypeName(q->qtype), (int)err); - } + } else { request->terminate = queryrecord_termination_callback; @@ -3839,7 +3892,7 @@ mDNSlocal mStatus handle_queryrecord_request(request_state *request) if (callExternalHelpers(q->InterfaceID, &q->qname, flags)) { LogInfo("handle_queryrecord_request: calling external_start_browsing_for_service()"); - external_start_browsing_for_service(q->InterfaceID, &q->qname, q->qtype, flags); + external_start_browsing_for_service(q->InterfaceID, &q->qname, q->qtype, flags, q); } } @@ -3888,7 +3941,8 @@ mDNSlocal void enum_termination_callback(request_state *request) else { LogInfo("%3d: DNSServiceEnumeration Cancel WAB Browse PID[%d](%s)", request->sd, request->process_id, request->pid_name); - uDNS_StopWABQueries(&mDNSStorage, UDNS_WAB_BROWSE_QUERY); + uDNS_StopWABQueries(&mDNSStorage, UDNS_WAB_BROWSE_QUERY | UDNS_WAB_LBROWSE_QUERY); + mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_autoall); } mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_all); mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_default); @@ -3955,6 +4009,7 @@ mDNSlocal mStatus handle_enum_request(request_state *request) // necessary context can be reached from the callbacks request->u.enumeration.q_all.QuestionContext = request; request->u.enumeration.q_default.QuestionContext = request; + if (!reg) request->u.enumeration.q_autoall.QuestionContext = request; // if the caller hasn't specified an explicit interface, we use local-only to get the system-wide list. if (!InterfaceID) InterfaceID = mDNSInterface_LocalOnly; @@ -3968,7 +4023,16 @@ mDNSlocal mStatus handle_enum_request(request_state *request) { err = mDNS_GetDomains(&mDNSStorage, &request->u.enumeration.q_default, t_default, NULL, InterfaceID, enum_result_callback, request); if (err) mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_all); - else request->terminate = enum_termination_callback; + else if (!reg) + { + err = mDNS_GetDomains(&mDNSStorage, &request->u.enumeration.q_autoall, mDNS_DomainTypeBrowseAutomatic, NULL, InterfaceID, enum_result_callback, request); + if (err) + { + mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_all); + mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_default); + } + } + if (!err) request->terminate = enum_termination_callback; } if (!err) { @@ -3978,10 +4042,10 @@ mDNSlocal mStatus handle_enum_request(request_state *request) LogInfo("%3d: DNSServiceEnumerateDomains Start WAB Registration PID[%d](%s)", request->sd, request->process_id, request->pid_name); uDNS_StartWABQueries(&mDNSStorage, UDNS_WAB_REG_QUERY); } - else + else { LogInfo("%3d: DNSServiceEnumerateDomains Start WAB Browse PID[%d](%s)", request->sd, request->process_id, request->pid_name); - uDNS_StartWABQueries(&mDNSStorage, UDNS_WAB_BROWSE_QUERY); + uDNS_StartWABQueries(&mDNSStorage, UDNS_WAB_BROWSE_QUERY | UDNS_WAB_LBROWSE_QUERY); } } @@ -4045,7 +4109,7 @@ mDNSlocal mStatus handle_release_request(request_state *request) LogOperation("%3d: PeerConnectionRelease(%X %##s) START PID[%d](%s)", request->sd, flags, instance.c, request->process_id, request->pid_name); - + external_connection_release(&instance); return(err); } @@ -4054,7 +4118,7 @@ mDNSlocal mStatus handle_release_request(request_state *request) mDNSlocal mStatus handle_release_request(request_state *request) { - (void) request; + (void) request; return mStatus_UnsupportedErr; } @@ -4116,11 +4180,14 @@ mDNSlocal void handle_connection_delegate_request(request_state *request) { len = sizeof(pid); if (getsockopt(request->sd, SOL_LOCAL, LOCAL_PEEREPID, &request->process_id, &len) != 0) + { + LogMsg("handle_connection_delegate_request: getsockopt for LOCAL_PEEREPID failed errno:%d / %s", errno, strerror(errno)); return; + } // to extract the process name from the pid value if (proc_pidinfo(request->process_id, PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) == 0) return; - mDNSPlatformStrCopy(request->pid_name, proc.pbsi_comm); + mDNSPlatformStrLCopy(request->pid_name, proc.pbsi_comm, sizeof(request->pid_name)); debugf("handle_connection_delegate_request: process id %d, name %s", request->process_id, request->pid_name); } #endif @@ -4129,7 +4196,10 @@ mDNSlocal void handle_connection_delegate_request(request_state *request) { len = UUID_SIZE; if (getsockopt(request->sd, SOL_LOCAL, LOCAL_PEEREUUID, request->uuid, &len) != 0) + { + LogMsg("handle_connection_delegate_request: getsockopt for LOCAL_PEEREUUID failed errno:%d / %s", errno, strerror(errno)); return; + } request->validUUID = mDNStrue; } #endif @@ -4197,7 +4267,7 @@ mDNSlocal void handle_getpid_request(request_state *request) } } } - + pi.err = 0; pi.pid = pid; send_all(request->sd, (const char *)&pi, sizeof(PIDInfo)); @@ -4216,8 +4286,8 @@ mDNSlocal void port_mapping_termination_callback(request_state *request) { LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) STOP PID[%d](%s)", request->sd, DNSServiceProtocol(request->u.pm.NATinfo.Protocol), - mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease, - request->process_id, request->pid_name); + mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease, + request->process_id, request->pid_name); mDNS_StopNATOperation(&mDNSStorage, &request->u.pm.NATinfo); } @@ -4309,8 +4379,8 @@ mDNSlocal mStatus handle_port_mapping_request(request_state *request) request->u.pm.NATinfo.clientContext = request; LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) START PID[%d](%s)", request->sd, - protocol, mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease, - request->process_id, request->pid_name); + protocol, mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease, + request->process_id, request->pid_name); err = mDNS_StartNATOperation(&mDNSStorage, &request->u.pm.NATinfo); if (err) LogMsg("ERROR: mDNS_StartNATOperation: %d", (int)err); else request->terminate = port_mapping_termination_callback; @@ -4327,13 +4397,19 @@ mDNSlocal mStatus handle_port_mapping_request(request_state *request) mDNSlocal void addrinfo_termination_callback(request_state *request) { LogOperation("%3d: DNSServiceGetAddrInfo(%##s) STOP PID[%d](%s)", request->sd, request->u.addrinfo.q4.qname.c, - request->process_id, request->pid_name); + request->process_id, request->pid_name); if (request->u.addrinfo.q4.QuestionContext) { mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q4); LogMcastQ(&mDNSStorage, &request->u.addrinfo.q4, request, q_stop); request->u.addrinfo.q4.QuestionContext = mDNSNULL; + + if (callExternalHelpers(request->u.addrinfo.interface_id, &request->u.addrinfo.q4.qname, request->flags)) + { + LogInfo("addrinfo_termination_callback: calling external_stop_browsing_for_service() for kDNSServiceType_A record"); + external_stop_browsing_for_service(request->u.addrinfo.interface_id, &request->u.addrinfo.q4.qname, kDNSServiceType_A, request->flags); + } } if (request->u.addrinfo.q4.qnameOrig) { @@ -4363,6 +4439,12 @@ mDNSlocal void addrinfo_termination_callback(request_state *request) mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q6); LogMcastQ(&mDNSStorage, &request->u.addrinfo.q6, request, q_stop); request->u.addrinfo.q6.QuestionContext = mDNSNULL; + + if (callExternalHelpers(request->u.addrinfo.interface_id, &request->u.addrinfo.q6.qname, request->flags)) + { + LogInfo("addrinfo_termination_callback: calling external_stop_browsing_for_service() for kDNSServiceType_AAAA record"); + external_stop_browsing_for_service(request->u.addrinfo.interface_id, &request->u.addrinfo.q6.qname, kDNSServiceType_AAAA, request->flags); + } } if (request->u.addrinfo.q6.qnameOrig) { @@ -4421,13 +4503,14 @@ mDNSlocal void addrinfo_termination_callback(request_state *request) mDNSlocal mStatus handle_addrinfo_request(request_state *request) { char hostname[256]; + size_t hostnameLen; domainname d; mStatus err = 0; mDNSs32 serviceIndex = -1; // default unscoped value for ServiceID is -1 mDNSInterfaceID InterfaceID; - + DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend); - + mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend); if (flags & kDNSServiceFlagsServiceIndex) @@ -4439,7 +4522,7 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request) serviceIndex = interfaceIndex; interfaceIndex = 0; } - + mDNSPlatformMemZero(&request->u.addrinfo, sizeof(request->u.addrinfo)); InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex); @@ -4448,6 +4531,9 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request) // interface is not currently in our list. if (interfaceIndex && !InterfaceID) { + if (interfaceIndex > 1) + LogMsg("handle_addrinfo_request: interfaceIndex %d is currently inactive requested by client[%d][%s]", + interfaceIndex, request->process_id, request->pid_name); // If it's one of the specially defined inteface index values, just return an error. if (PreDefinedInterfaceIndex(interfaceIndex)) { @@ -4455,7 +4541,7 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request) return(mStatus_BadParamErr); } - // Otherwise, use the specified interface index value and the registration will + // Otherwise, use the specified interface index value and the request will // be applied to that interface when it comes up. InterfaceID = (mDNSInterfaceID)(uintptr_t)interfaceIndex; LogInfo("handle_addrinfo_request: query pending for interface index %d", interfaceIndex); @@ -4500,8 +4586,6 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request) request->u.addrinfo.q4.TimeoutQuestion = request->u.addrinfo.q6.TimeoutQuestion = (flags & kDNSServiceFlagsTimeout ) != 0; request->u.addrinfo.q4.WakeOnResolve = request->u.addrinfo.q6.WakeOnResolve = 0; request->u.addrinfo.q4.UseBackgroundTrafficClass = request->u.addrinfo.q6.UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0; - request->u.addrinfo.q4.DenyOnCellInterface = request->u.addrinfo.q6.DenyOnCellInterface = (flags & kDNSServiceFlagsDenyCellular) != 0; - request->u.addrinfo.q4.DenyOnExpInterface = request->u.addrinfo.q6.DenyOnExpInterface = (flags & kDNSServiceFlagsDenyExpensive) != 0; if ((flags & kDNSServiceFlagsValidate) != 0) request->u.addrinfo.q4.ValidationRequired = request->u.addrinfo.q6.ValidationRequired = DNSSEC_VALIDATION_SECURE; else if ((flags & kDNSServiceFlagsValidateOptional) != 0) @@ -4521,13 +4605,18 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request) if (IsLocalDomain(&d)) request->u.addrinfo.q4.ValidationRequired = request->u.addrinfo.q6.ValidationRequired = 0; + hostnameLen = strlen(hostname); + + LogOperation("%3d: DNSServiceGetAddrInfo(%X, %d, %d, %##s) START PID[%d](%s)", + request->sd, flags, interfaceIndex, request->u.addrinfo.protocol, d.c, request->process_id, request->pid_name); + if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv6) { request->u.addrinfo.q6.qtype = kDNSServiceType_AAAA; request->u.addrinfo.q6.SearchListIndex = 0; // For DNSSEC questions, append search domains only if kDNSServiceFlagsValidateOptional is set - if ((!(request->u.addrinfo.q6.ValidationRequired == DNSSEC_VALIDATION_SECURE)) && (!(request->u.addrinfo.q6.ValidationRequired == DNSSEC_VALIDATION_INSECURE)) - && hostname[strlen(hostname) - 1] != '.' && (AlwaysAppendSearchDomains || CountLabels(&d) == 1)) + if ((!(request->u.addrinfo.q6.ValidationRequired == DNSSEC_VALIDATION_SECURE)) && (!(request->u.addrinfo.q6.ValidationRequired == DNSSEC_VALIDATION_INSECURE)) + && ((hostnameLen == 0) || (hostname[hostnameLen - 1] != '.')) && (AlwaysAppendSearchDomains || CountLabels(&d) == 1)) { request->u.addrinfo.q6.AppendSearchDomains = 1; request->u.addrinfo.q6.AppendLocalSearchDomains = 1; @@ -4550,9 +4639,14 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request) err = SendAdditionalQuery(&request->u.addrinfo.q6, request, err); #endif // APPLE_OSX_mDNSResponder if (!err) - { + { request->terminate = addrinfo_termination_callback; LogMcastQ(&mDNSStorage, &request->u.addrinfo.q6, request, q_start); + if (callExternalHelpers(InterfaceID, &d, flags)) + { + LogInfo("handle_addrinfo_request: calling external_start_browsing_for_service() for kDNSServiceType_AAAA record"); + external_start_browsing_for_service(InterfaceID, &d, kDNSServiceType_AAAA, flags, &request->u.addrinfo.q6); + } } } @@ -4565,8 +4659,8 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request) // "AlwaysAppendSearchDomains", then we do it for any query which is not fully qualified. // For DNSSEC questions, append search domains only if kDNSServiceFlagsValidateOptional is set. - if ((!(request->u.addrinfo.q4.ValidationRequired == DNSSEC_VALIDATION_SECURE)) && (!(request->u.addrinfo.q4.ValidationRequired == DNSSEC_VALIDATION_INSECURE)) - && hostname[strlen(hostname) - 1] != '.' && (AlwaysAppendSearchDomains || CountLabels(&d) == 1)) + if ((!(request->u.addrinfo.q4.ValidationRequired == DNSSEC_VALIDATION_SECURE)) && (!(request->u.addrinfo.q4.ValidationRequired == DNSSEC_VALIDATION_INSECURE)) + && ((hostnameLen == 0) || (hostname[hostnameLen - 1] != '.')) && (AlwaysAppendSearchDomains || CountLabels(&d) == 1)) { request->u.addrinfo.q4.AppendSearchDomains = 1; request->u.addrinfo.q4.AppendLocalSearchDomains = 1; @@ -4585,11 +4679,17 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request) LogMsg("ERROR: mDNS_StartQuery: %d", (int)err); request->u.addrinfo.q4.QuestionContext = mDNSNULL; if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv6) - { - // If we started a query for IPv6, we need to cancel it + { + // If we started a query for IPv6, we need to cancel it mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q6); request->u.addrinfo.q6.QuestionContext = mDNSNULL; - } + + if (callExternalHelpers(InterfaceID, &d, flags)) + { + LogInfo("addrinfo_termination_callback: calling external_stop_browsing_for_service() for kDNSServiceType_AAAA record"); + external_stop_browsing_for_service(InterfaceID, &d, kDNSServiceType_AAAA, flags); + } + } } #if APPLE_OSX_mDNSResponder err = SendAdditionalQuery(&request->u.addrinfo.q4, request, err); @@ -4598,10 +4698,14 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request) { request->terminate = addrinfo_termination_callback; LogMcastQ(&mDNSStorage, &request->u.addrinfo.q4, request, q_start); - } + if (callExternalHelpers(InterfaceID, &d, flags)) + { + LogInfo("handle_addrinfo_request: calling external_start_browsing_for_service() for kDNSServiceType_A record"); + external_start_browsing_for_service(InterfaceID, &d, kDNSServiceType_A, flags, &request->u.addrinfo.q4); + } + } } - LogOperation("%3d: DNSServiceGetAddrInfo(%X, %d, %d, %##s) START PID[%d](%s)", request->sd, flags, interfaceIndex, request->u.addrinfo.protocol, d.c, request->process_id, request->pid_name); return(err); } @@ -4614,10 +4718,10 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request) mDNSlocal request_state *NewRequest(void) { request_state **p = &all_requests; - while (*p) + while (*p) p=&(*p)->next; *p = mallocL("request_state", sizeof(request_state)); - if (!*p) + if (!*p) FatalError("ERROR: malloc"); mDNSPlatformMemZero(*p, sizeof(request_state)); return(*p); @@ -4758,7 +4862,7 @@ mDNSlocal void read_msg(request_state *req) get_string(&req->msgptr, req->msgend, ctrl_path, MAX_CTLPATH); // path is first element in message buffer mDNSPlatformMemZero(&cliaddr, sizeof(cliaddr)); cliaddr.sun_family = AF_LOCAL; - mDNSPlatformStrCopy(cliaddr.sun_path, ctrl_path); + mDNSPlatformStrLCopy(cliaddr.sun_path, ctrl_path, sizeof(cliaddr.sun_path)); // If the error return path UDS name is empty string, that tells us // that this is a new version of the library that's going to pass us // the error return path socket via sendmsg/recvmsg @@ -4771,8 +4875,8 @@ mDNSlocal void read_msg(request_state *req) #endif req->errsd = socket(AF_DNSSD, SOCK_STREAM, 0); - if (!dnssd_SocketValid(req->errsd)) - { + if (!dnssd_SocketValid(req->errsd)) + { my_throttled_perror("ERROR: socket"); req->ts = t_error; return; @@ -4838,22 +4942,22 @@ mDNSlocal void request_callback(int fd, short filter, void *info) for (;;) { read_msg(req); - if (req->ts == t_morecoming) + if (req->ts == t_morecoming) + return; + if (req->ts == t_terminated || req->ts == t_error) + { + AbortUnlinkAndFree(req); return; - if (req->ts == t_terminated || req->ts == t_error) - { - AbortUnlinkAndFree(req); - return; } - if (req->ts != t_complete) - { - LogMsg("request_callback: req->ts %d != t_complete PID[%d][%s]", req->ts, req->process_id, req->pid_name); - AbortUnlinkAndFree(req); - return; + if (req->ts != t_complete) + { + LogMsg("request_callback: req->ts %d != t_complete PID[%d][%s]", req->ts, req->process_id, req->pid_name); + AbortUnlinkAndFree(req); + return; } if (req->hdr.version != VERSION) { - LogMsg("request_callback: ERROR: client IPC version %d incompatible with daemon IPC version %d PID[%d][%s]", + LogMsg("request_callback: ERROR: client IPC version %d incompatible with daemon IPC version %d PID[%d][%s]", req->hdr.version, VERSION, req->process_id, req->pid_name); AbortUnlinkAndFree(req); return; @@ -4881,24 +4985,24 @@ mDNSlocal void request_callback(int fd, short filter, void *info) case send_bpf: // Same as cancel_request below case cancel_request: min_size = 0; break; case release_request: min_size += sizeof(mDNSu32) + 3 /* type, type, domain */; break; - default: LogMsg("request_callback: ERROR: validate_message - unsupported req type: %d PID[%d][%s]", - req->hdr.op, req->process_id, req->pid_name); + default: LogMsg("request_callback: ERROR: validate_message - unsupported req type: %d PID[%d][%s]", + req->hdr.op, req->process_id, req->pid_name); min_size = -1; break; } if ((mDNSs32)req->data_bytes < min_size) - { - LogMsg("request_callback: Invalid message %d bytes; min for %d is %d PID[%d][%s]", - req->data_bytes, req->hdr.op, min_size, req->process_id, req->pid_name); - AbortUnlinkAndFree(req); - return; + { + LogMsg("request_callback: Invalid message %d bytes; min for %d is %d PID[%d][%s]", + req->data_bytes, req->hdr.op, min_size, req->process_id, req->pid_name); + AbortUnlinkAndFree(req); + return; } if (LightweightOp(req->hdr.op) && !req->terminate) - { - LogMsg("request_callback: Reg/Add/Update/Remove %d require existing connection PID[%d][%s]", - req->hdr.op, req->process_id, req->pid_name); - AbortUnlinkAndFree(req); - return; + { + LogMsg("request_callback: Reg/Add/Update/Remove %d require existing connection PID[%d][%s]", + req->hdr.op, req->process_id, req->pid_name); + AbortUnlinkAndFree(req); + return; } // If req->terminate is already set, this means this operation is sharing an existing connection @@ -4929,6 +5033,7 @@ mDNSlocal void request_callback(int fd, short filter, void *info) if (req->process_id) { newreq->process_id = req->process_id; + mDNSPlatformStrLCopy(newreq->pid_name, req->pid_name, (mDNSu32)sizeof(newreq->pid_name)); } else { @@ -4948,7 +5053,7 @@ mDNSlocal void request_callback(int fd, short filter, void *info) err = mStatus_ServiceNotRunning; } else - { + { switch(req->hdr.op) { // These are all operations that have their own first-class request_state object @@ -4983,7 +5088,7 @@ mDNSlocal void request_callback(int fd, short filter, void *info) case remove_record_request: err = handle_removerecord_request(req); break; case cancel_request: handle_cancel_request (req); break; case release_request: err = handle_release_request (req); break; - default: LogMsg("request_callback: %3d:ERROR: Unsupported UDS req:%d PID[%d][%s]", + default: LogMsg("request_callback: %3d:ERROR: Unsupported UDS req:%d PID[%d][%s]", req->sd, req->hdr.op, req->process_id, req->pid_name); break; } } @@ -5032,7 +5137,7 @@ mDNSlocal void connect_callback(int fd, short filter, void *info) if (!dnssd_SocketValid(sd)) { - if (dnssd_errno != dnssd_EWOULDBLOCK) + if (dnssd_errno != dnssd_EWOULDBLOCK) my_throttled_perror("ERROR: accept"); return; } @@ -5063,9 +5168,9 @@ mDNSlocal void connect_callback(int fd, short filter, void *info) #if APPLE_OSX_mDNSResponder struct xucred x; socklen_t xucredlen = sizeof(x); - if (getsockopt(sd, 0, LOCAL_PEERCRED, &x, &xucredlen) >= 0 && x.cr_version == XUCRED_VERSION) + if (getsockopt(sd, 0, LOCAL_PEERCRED, &x, &xucredlen) >= 0 && x.cr_version == XUCRED_VERSION) request->uid = x.cr_uid; // save the effective userid of the client - else + else my_perror("ERROR: getsockopt, LOCAL_PEERCRED"); debugf("LOCAL_PEERCRED %d %u %u %d", xucredlen, x.cr_version, x.cr_uid, x.cr_ngroups); @@ -5110,7 +5215,7 @@ mDNSlocal mDNSBool uds_socket_setup(dnssd_sock_t skt) return mDNSfalse; } else - { + { LogOperation("%3d: Listening for incoming Unix Domain Socket client requests", skt); mDNSStorage.uds_listener_skt = skt; } @@ -5168,19 +5273,19 @@ mDNSexport int udsserver_init(dnssd_sock_t skts[], mDNSu32 count) #else { mode_t mask = umask(0); - unlink(MDNS_UDS_SERVERPATH); // OK if this fails + unlink(boundPath); // OK if this fails laddr.sun_family = AF_LOCAL; #ifndef NOT_HAVE_SA_LEN // According to Stevens (section 3.2), there is no portable way to // determine whether sa_len is defined on a particular platform. laddr.sun_len = sizeof(struct sockaddr_un); #endif - if (strlen(MDNS_UDS_SERVERPATH) >= sizeof(laddr.sun_path)) + if (strlen(boundPath) >= sizeof(laddr.sun_path)) { LogMsg("ERROR: MDNS_UDS_SERVERPATH must be < %d characters", (int)sizeof(laddr.sun_path)); goto error; } - mDNSPlatformStrCopy(laddr.sun_path, MDNS_UDS_SERVERPATH); + mDNSPlatformStrLCopy(laddr.sun_path, boundPath, sizeof(laddr.sun_path)); ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); umask(mask); if (ret < 0) @@ -5260,7 +5365,7 @@ mDNSexport int udsserver_exit(void) // Currently, we're unable to remove /var/run/mdnsd because we've changed to userid "nobody" // to give up unnecessary privilege, but we need to be root to remove this Unix Domain Socket. // It would be nice if we could find a solution to this problem - if (unlink(MDNS_UDS_SERVERPATH)) + if (unlink(boundPath)) debugf("Unable to remove %s", MDNS_UDS_SERVERPATH); #endif } @@ -5273,9 +5378,9 @@ mDNSexport int udsserver_exit(void) mDNSlocal void LogClientInfo(mDNS *const m, request_state *req) { char prefix[16]; - if (req->primary) + if (req->primary) mDNS_snprintf(prefix, sizeof(prefix), " -> "); - else + else mDNS_snprintf(prefix, sizeof(prefix), "%3d:", req->sd); if (!req->terminate) @@ -5287,8 +5392,8 @@ mDNSlocal void LogClientInfo(mDNS *const m, request_state *req) request_state *r; for (p = req->u.reg_recs; p; p=p->next) num_records++; for (r = req->next; r; r=r->next) if (r->primary == req) num_ops++; - LogMsgNoIdent("%s DNSServiceCreateConnection: %d registered record%s, %d kDNSServiceFlagsShareConnection operation%s PID[%d](%s)", - prefix, num_records, num_records != 1 ? "s" : "", num_ops, num_ops != 1 ? "s" : "", + LogMsgNoIdent("%s DNSServiceCreateConnection: %d registered record%s, %d kDNSServiceFlagsShareConnection operation%s PID[%d](%s)", + prefix, num_records, num_records != 1 ? "s" : "", num_ops, num_ops != 1 ? "s" : "", req->process_id, req->pid_name); for (p = req->u.reg_recs; p; p=p->next) LogMsgNoIdent(" -> DNSServiceRegisterRecord 0x%08X %2d %3d %s PID[%d](%s)", @@ -5336,7 +5441,7 @@ mDNSlocal void LogClientInfo(mDNS *const m, request_state *req) mDNSVal16(req->u.pm.NATinfo.ExternalPort), req->u.pm.NATinfo.NATLease, req->u.pm.NATinfo.Lifetime, - req->process_id, req->pid_name); + req->process_id, req->pid_name); else if (req->terminate == addrinfo_termination_callback) LogMsgNoIdent("%s DNSServiceGetAddrInfo 0x%08X %2d %s%s %##s PID[%d](%s)", prefix, req->flags, req->interfaceIndex, @@ -5354,18 +5459,18 @@ mDNSlocal void GetMcastClients(request_state *req) int num_records = 0, num_ops = 0; const registered_record_entry *p; request_state *r; - for (p = req->u.reg_recs; p; p=p->next) + for (p = req->u.reg_recs; p; p=p->next) num_records++; - for (r = req->next; r; r=r->next) - if (r->primary == req) + for (r = req->next; r; r=r->next) + if (r->primary == req) num_ops++; for (p = req->u.reg_recs; p; p=p->next) { if (!AuthRecord_uDNS(p->rr)) n_mrecords++; } - for (r = req->next; r; r=r->next) - if (r->primary == req) + for (r = req->next; r; r=r->next) + if (r->primary == req) GetMcastClients(r); } else if (req->terminate == regservice_termination_callback) @@ -5374,7 +5479,7 @@ mDNSlocal void GetMcastClients(request_state *req) for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next) { if (!AuthRecord_uDNS(&ptr->srs.RR_SRV)) - n_mrecords++; + n_mrecords++; } } else if (req->terminate == browse_termination_callback) @@ -5417,19 +5522,19 @@ mDNSlocal void LogMcastClientInfo(request_state *req) int num_records = 0, num_ops = 0; const registered_record_entry *p; request_state *r; - for (p = req->u.reg_recs; p; p=p->next) + for (p = req->u.reg_recs; p; p=p->next) num_records++; - for (r = req->next; r; r=r->next) - if (r->primary == req) + for (r = req->next; r; r=r->next) + if (r->primary == req) num_ops++; for (p = req->u.reg_recs; p; p=p->next) { if (!AuthRecord_uDNS(p->rr)) - LogMcastNoIdent("R: -> DNSServiceRegisterRecord: %##s %s PID[%d](%s)", p->rr->resrec.name->c, + LogMcastNoIdent("R: -> DNSServiceRegisterRecord: %##s %s PID[%d](%s)", p->rr->resrec.name->c, DNSTypeName(p->rr->resrec.rrtype), req->process_id, req->pid_name, i_mcount++); } - for (r = req->next; r; r=r->next) - if (r->primary == req) + for (r = req->next; r; r=r->next) + if (r->primary == req) LogMcastClientInfo(r); } else if (req->terminate == regservice_termination_callback) @@ -5437,8 +5542,8 @@ mDNSlocal void LogMcastClientInfo(request_state *req) service_instance *ptr; for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next) { - if (!AuthRecord_uDNS(&ptr->srs.RR_SRV)) - LogMcastNoIdent("R: DNSServiceRegister: %##s %u/%u PID[%d](%s)", ptr->srs.RR_SRV.resrec.name->c, mDNSVal16(req->u.servicereg.port), + if (!AuthRecord_uDNS(&ptr->srs.RR_SRV)) + LogMcastNoIdent("R: DNSServiceRegister: %##s %u/%u PID[%d](%s)", ptr->srs.RR_SRV.resrec.name->c, mDNSVal16(req->u.servicereg.port), SRS_PORT(&ptr->srs), req->process_id, req->pid_name, i_mcount++); } } @@ -5461,7 +5566,7 @@ mDNSlocal void LogMcastClientInfo(request_state *req) else if (req->terminate == queryrecord_termination_callback) { if ((mDNSOpaque16IsZero(req->u.queryrecord.q.TargetQID)) && (req->u.queryrecord.q.ThisQInterval > 0)) - LogMcastNoIdent("Q: DNSServiceQueryRecord %##s %s PID[%d](%s)", req->u.queryrecord.q.qname.c, DNSTypeName(req->u.queryrecord.q.qtype), + LogMcastNoIdent("Q: DNSServiceQueryRecord %##s %s PID[%d](%s)", req->u.queryrecord.q.qname.c, DNSTypeName(req->u.queryrecord.q.qtype), req->process_id, req->pid_name, i_mcount++); } else if (req->terminate == addrinfo_termination_callback) @@ -5476,7 +5581,7 @@ mDNSlocal void LogMcastClientInfo(request_state *req) { return; } - + } mDNSlocal char *RecordTypeName(mDNSu8 rtype) @@ -5549,9 +5654,14 @@ mDNSlocal void LogLocalOnlyAuthRecords(mDNS *const m) // Print a maximum of 400 records if (ar->ARType == AuthRecordLocalOnly) - LogMsgNoIdent(" %s LO %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar)); + LogMsgNoIdent(" %s LO %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar)); else if (ar->ARType == AuthRecordP2P) - LogMsgNoIdent(" %s PP %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar)); + { + if (ar->resrec.InterfaceID == mDNSInterface_BLE) + LogMsgNoIdent(" %s BLE %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar)); + else + LogMsgNoIdent(" %s PP %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar)); + } } } @@ -5573,21 +5683,23 @@ mDNSlocal void LogOneAuthRecord(mDNS *const m, const AuthRecord *ar, mDNSs32 now char anstr[256]; if (AuthRecord_uDNS(ar)) { - LogMsgNoIdent("%7d %7d %7d %7d %s %s", + LogMsgNoIdent("%7d %7d %7d %-7s %4d %s %s", ar->ThisAPInterval / mDNSPlatformOneSecond, (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond, ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0, + "-U-", ar->state, ar->AllowRemoteQuery ? "☠" : " ", ARDisplayString(m, ar)); } else { - LogMsgNoIdent("%7d %7d %7d %7s %s %s%s", + LogMsgNoIdent("%7d %7d %7d %-7s 0x%02X %s %s%s", ar->ThisAPInterval / mDNSPlatformOneSecond, ar->AnnounceCount ? (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond : 0, ar->TimeExpire ? (ar->TimeExpire - now) / mDNSPlatformOneSecond : 0, ifname ? ifname : "ALL", + ar->resrec.RecordType, ar->AllowRemoteQuery ? "☠" : " ", ARDisplayString(m, ar), AnonInfoToString(ar->resrec.AnonInfo, anstr, sizeof(anstr))); } @@ -5603,7 +5715,7 @@ mDNSlocal void LogAuthRecords(mDNS *const m, const mDNSs32 now, AuthRecord *Reso const char *const ifname = InterfaceNameForID(m, ar->resrec.InterfaceID); if ((ar->WakeUp.HMAC.l[0] != 0) == (proxy != mDNSNULL)) { - if (showheader) { showheader = mDNSfalse; LogMsgNoIdent(" Int Next Expire State"); } + if (showheader) { showheader = mDNSfalse; LogMsgNoIdent(" Int Next Expire if State"); } if (proxy) (*proxy)++; if (!mDNSPlatformMemSame(&owner, &ar->WakeUp, sizeof(owner))) { @@ -5625,7 +5737,10 @@ mDNSlocal void LogAuthRecords(mDNS *const m, const mDNSs32 now, AuthRecord *Reso } else if (ar->ARType == AuthRecordP2P) { - LogMsgNoIdent(" PP %s", ARDisplayString(m, ar)); + if (ar->resrec.InterfaceID == mDNSInterface_BLE) + LogMsgNoIdent(" BLE %s", ARDisplayString(m, ar)); + else + LogMsgNoIdent(" PP %s", ARDisplayString(m, ar)); } else { @@ -5731,7 +5846,7 @@ mDNSlocal char *AnonDataToString(const mDNSu8 *ad, int adlen, char *adstr, int a mDNSexport void LogMDNSStatistics(mDNS *const m) { LogMsgNoIdent("--- MDNS Statistics ---"); - + LogMsgNoIdent("Name Conflicts %u", m->mDNSStats.NameConflicts); LogMsgNoIdent("KnownUnique Name Conflicts %u", m->mDNSStats.KnownUniqueNameConflicts); LogMsgNoIdent("Duplicate Query Suppressions %u", m->mDNSStats.DupQuerySuppressions); @@ -5849,10 +5964,11 @@ mDNSexport void udsserver_info(mDNS *const m) LogMsgNoIdent("%lu question%s; %lu active", CacheUsed, CacheUsed > 1 ? "s" : "", CacheActive); } - LogMsgNoIdent("----- Local-Only Questions -----"); + LogMsgNoIdent("----- LocalOnly, P2P Questions -----"); if (!m->LocalOnlyQuestions) LogMsgNoIdent(""); else for (q = m->LocalOnlyQuestions; q; q=q->next) - LogMsgNoIdent(" %5d %-6s%##s%s", + LogMsgNoIdent(" %3s %5d %-6s%##s%s", + q->InterfaceID == mDNSInterface_LocalOnly ? "LO ": q->InterfaceID == mDNSInterface_BLE ? "BLE": "P2P", q->CurrentAnswers, DNSTypeName(q->qtype), q->qname.c, q->DuplicateOf ? " (dup)" : ""); LogMsgNoIdent("---- Active UDS Client Requests ----"); @@ -5872,7 +5988,7 @@ mDNSexport void udsserver_info(mDNS *const m) foundparent:; } } - + LogMsgNoIdent("-------- NAT Traversals --------"); LogMsgNoIdent("ExtAddress %.4a Retry %d Interval %d", &m->ExtAddress, @@ -5965,7 +6081,7 @@ foundparent:; } } LogInfo("--- Trust Anchors ---"); - if (!m->TrustAnchors) + if (!m->TrustAnchors) { LogInfo(""); } @@ -6017,6 +6133,14 @@ foundparent:; LogMsgNoIdent("---- Task Scheduling Timers ----"); +#if BONJOUR_ON_DEMAND + LogMsgNoIdent("BonjourEnabled %d", m->BonjourEnabled); +#endif // BONJOUR_ON_DEMAND + +#if APPLE_OSX_mDNSResponder + LogMsgNoIdent("EnableBLEBasedDiscovery %d", EnableBLEBasedDiscovery); +#endif // APPLE_OSX_mDNSResponder + if (!m->NewQuestions) LogMsgNoIdent("NewQuestion "); else @@ -6058,6 +6182,11 @@ foundparent:; LogTimer("m->NextCacheCheck ", m->NextCacheCheck); LogTimer("m->NextScheduledSPS ", m->NextScheduledSPS); LogTimer("m->NextScheduledKA ", m->NextScheduledKA); + +#if BONJOUR_ON_DEMAND + LogTimer("m->NextBonjourDisableTime ", m->NextBonjourDisableTime); +#endif // BONJOUR_ON_DEMAND + LogTimer("m->NextScheduledSPRetry ", m->NextScheduledSPRetry); LogTimer("m->DelaySleep ", m->DelaySleep); @@ -6186,15 +6315,16 @@ mDNSexport mDNSs32 udsserver_idle(mDNSs32 nextevent) if (r->u.resolve.ReportTime && now - r->u.resolve.ReportTime >= 0) { r->u.resolve.ReportTime = 0; - LogMsgNoIdent("Client application bug PID[%d](%s) : DNSServiceResolve(%##s) active for over two minutes. " - "This places considerable burden on the network.", r->process_id, r->pid_name, r->u.resolve.qsrv.qname.c); + // if client received results and resolve still active + if (r->u.resolve.txt && r->u.resolve.srv) + LogMsgNoIdent("Client application PID[%d](%s) has received results for DNSServiceResolve(%##s) yet remains active over two minutes.", r->process_id, r->pid_name, r->u.resolve.qsrv.qname.c); } // Note: Only primary req's have reply lists, not subordinate req's. while (r->replies) // Send queued replies { transfer_state result; - if (r->replies->next) + if (r->replies->next) r->replies->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsMoreComing); result = send_msg(r); // Returns t_morecoming if buffer full because client is not reading if (result == t_complete) @@ -6206,7 +6336,12 @@ mDNSexport mDNSs32 udsserver_idle(mDNSs32 nextevent) r->unresponsiveness_reports = 0; continue; } - else if (result == t_terminated || result == t_error) + else if (result == t_terminated) + { + LogInfo("%3d: Could not write data to client PID[%d](%s) because connection is terminated by the client", r->sd, r->process_id, r->pid_name); + abort_request(r); + } + else if (result == t_error) { LogMsg("%3d: Could not write data to client PID[%d](%s) because of error - aborting connection", r->sd, r->process_id, r->pid_name); LogClientInfo(&mDNSStorage, r); @@ -6217,21 +6352,21 @@ mDNSexport mDNSs32 udsserver_idle(mDNSs32 nextevent) if (r->replies) // If we failed to send everything, check our time_blocked timer { - if (nextevent - now > mDNSPlatformOneSecond) + if (nextevent - now > mDNSPlatformOneSecond) nextevent = now + mDNSPlatformOneSecond; - if (mDNSStorage.SleepState != SleepState_Awake) + if (mDNSStorage.SleepState != SleepState_Awake) r->time_blocked = 0; - else if (!r->time_blocked) + else if (!r->time_blocked) r->time_blocked = NonZeroTime(now); else if (now - r->time_blocked >= 10 * mDNSPlatformOneSecond * (r->unresponsiveness_reports+1)) { int num = 0; struct reply_state *x = r->replies; - while (x) - { - num++; - x=x->next; + while (x) + { + num++; + x=x->next; } LogMsg("%3d: Could not write data to client PID[%d](%s) after %ld seconds, %d repl%s waiting", r->sd, r->process_id, r->pid_name, (now - r->time_blocked) / mDNSPlatformOneSecond, num, num == 1 ? "y" : "ies"); @@ -6261,10 +6396,10 @@ struct CompileTimeAssertionChecks_uds_daemon // Check our structures are reasonable sizes. Including overly-large buffers, or embedding // other overly-large structures instead of having a pointer to them, can inadvertently // cause structure sizes (and therefore memory usage) to balloon unreasonably. - char sizecheck_request_state [(sizeof(request_state) <= 2000) ? 1 : -1]; + char sizecheck_request_state [(sizeof(request_state) <= 2954) ? 1 : -1]; char sizecheck_registered_record_entry[(sizeof(registered_record_entry) <= 60) ? 1 : -1]; char sizecheck_service_instance [(sizeof(service_instance) <= 6552) ? 1 : -1]; - char sizecheck_browser_t [(sizeof(browser_t) <= 1128) ? 1 : -1]; + char sizecheck_browser_t [(sizeof(browser_t) <= 1150) ? 1 : -1]; char sizecheck_reply_hdr [(sizeof(reply_hdr) <= 12) ? 1 : -1]; char sizecheck_reply_state [(sizeof(reply_state) <= 64) ? 1 : -1]; }; diff --git a/mDNSResponder/mDNSShared/uds_daemon.h b/mDNSResponder/mDNSShared/uds_daemon.h index 6cc9197d..ef98450b 100644 --- a/mDNSResponder/mDNSShared/uds_daemon.h +++ b/mDNSResponder/mDNSShared/uds_daemon.h @@ -53,15 +53,14 @@ extern DNameListElem *AutoBrowseDomains; extern mDNSs32 ChopSubTypes(char *regtype, char **AnonData); extern AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p, char **AnonData); extern int CountExistingRegistrations(domainname *srv, mDNSIPPort port); +extern mDNSBool callExternalHelpers(mDNSInterfaceID InterfaceID, const domainname *const domain, DNSServiceFlags flags); extern void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result); extern int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs); #if APPLE_OSX_mDNSResponder -extern void machserver_automatic_browse_domain_changed(const domainname *d, mDNSBool add); -extern void machserver_automatic_registration_domain_changed(const domainname *d, mDNSBool add); // D2D interface support -extern void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags); +extern void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags, DNSQuestion * q); extern void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags); extern void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags); extern void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags); @@ -69,12 +68,17 @@ extern void external_start_resolving_service(mDNSInterfaceID InterfaceID, const extern void external_stop_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags); extern void external_connection_release(const domainname *instance); +extern void internal_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags); +extern void internal_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags); +extern void internal_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags); +extern void internal_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags); + #else // APPLE_OSX_mDNSResponder -#define external_start_browsing_for_service(A,B,C,D) (void)(A) +#define external_start_browsing_for_service(A,B,C,D,E) (void)(A) #define external_stop_browsing_for_service(A,B,C,D) (void)(A) #define external_start_advertising_service(A,B) (void)(A) -#define external_stop_advertising_service(A,B) (void)(A) +#define external_stop_advertising_service(A,B) do { (void)(A); (void)(B); } while (0) #define external_start_resolving_service(A,B,C) (void)(A) #define external_stop_resolving_service(A,B,C) (void)(A) #define external_connection_release(A) (void)(A) @@ -83,3 +87,8 @@ extern void external_connection_release(const domainname *instance); extern const char mDNSResponderVersionString_SCCS[]; #define mDNSResponderVersionString (mDNSResponderVersionString_SCCS+5) + +#if DEBUG +extern void SetDebugBoundPath(void); +extern int IsDebugSocketInUse(void); +#endif diff --git a/mDNSResponder/mDNSWindows/ControlPanel/ConfigPropertySheet.cpp b/mDNSResponder/mDNSWindows/ControlPanel/ConfigPropertySheet.cpp index 5fae9555..34c418e3 100755 --- a/mDNSResponder/mDNSWindows/ControlPanel/ConfigPropertySheet.cpp +++ b/mDNSResponder/mDNSWindows/ControlPanel/ConfigPropertySheet.cpp @@ -227,8 +227,8 @@ CConfigPropertySheet::DecodeDomainName( const char * raw, CString & decoded ) for (i = 0; i < labels; i++) { buffer = (char *)GetNextLabel(buffer, nextLabel); - strcat(decodedDomainString, nextLabel); - strcat(decodedDomainString, "."); + strcat_s(decodedDomainString, sizeof(decodedDomainString), nextLabel); + strcat_s(decodedDomainString, sizeof(decodedDomainString), "."); } // Remove trailing dot from domain name. diff --git a/mDNSResponder/mDNSWindows/ControlPanel/ControlPanelExe.cpp b/mDNSResponder/mDNSWindows/ControlPanel/ControlPanelExe.cpp index 36447d11..94de794b 100755 --- a/mDNSResponder/mDNSWindows/ControlPanel/ControlPanelExe.cpp +++ b/mDNSResponder/mDNSWindows/ControlPanel/ControlPanelExe.cpp @@ -23,6 +23,7 @@ #include #include "loclibrary.h" +#include #ifdef _DEBUG @@ -205,7 +206,7 @@ CCPApp::Register( LPCTSTR inClsidString, LPCTSTR inName, LPCTSTR inCanonicalName n = sizeof_array( entries ); for( i = 0; i < n; ++i ) { - wsprintf( keyName, entries[ i ].subKey, inClsidString ); + StringCbPrintf( keyName, sizeof( keyName ), entries[ i ].subKey, inClsidString ); err = RegCreateKeyEx( entries[ i ].rootKey, keyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, NULL ); require_noerr( err, exit ); @@ -232,10 +233,10 @@ CCPApp::Unregister( LPCTSTR clsidString ) { TCHAR keyName[ MAX_PATH * 2 ]; - wsprintf( keyName, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace\\%s", clsidString ); + StringCbPrintf( keyName, sizeof( keyName ), L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace\\%s", clsidString ); MyRegDeleteKey( HKEY_LOCAL_MACHINE, keyName ); - wsprintf( keyName, L"CLSID\\%s", clsidString ); + StringCbPrintf( keyName, sizeof( keyName ), L"CLSID\\%s", clsidString ); MyRegDeleteKey( HKEY_CLASSES_ROOT, keyName ); } @@ -313,7 +314,7 @@ CCPApp::InitInstance() require_noerr( err, exit ); - wsprintf( iconPath, L"%s,-%d", exePath, IDR_APPLET ); + StringCbPrintf( iconPath, sizeof( iconPath ), L"%s,-%d", exePath, IDR_APPLET ); localizedName.LoadString( IDS_APPLET_NAME ); toolTip.LoadString( IDS_APPLET_TOOLTIP ); diff --git a/mDNSResponder/mDNSWindows/ControlPanel/FourthPage.cpp b/mDNSResponder/mDNSWindows/ControlPanel/FourthPage.cpp index b6c8d15d..7ded08fc 100755 --- a/mDNSResponder/mDNSWindows/ControlPanel/FourthPage.cpp +++ b/mDNSResponder/mDNSWindows/ControlPanel/FourthPage.cpp @@ -183,7 +183,7 @@ void CFourthPage::OnBnClickedPowerManagement() - sprintf( buf, "check box: %d", m_checkBox.GetCheck() ); + snprintf( buf, sizeof( buf ), "check box: %d", m_checkBox.GetCheck() ); OutputDebugStringA( buf ); diff --git a/mDNSResponder/mDNSWindows/DLLStub/DLLStub.cpp b/mDNSResponder/mDNSWindows/DLLStub/DLLStub.cpp index 503465f2..38fd5e0a 100755 --- a/mDNSResponder/mDNSWindows/DLLStub/DLLStub.cpp +++ b/mDNSResponder/mDNSWindows/DLLStub/DLLStub.cpp @@ -80,12 +80,12 @@ DLLStub::GetProcAddress( FARPROC * func, LPCSTR lpProcName ) } -int DNSSD_API +dnssd_sock_t DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef) { typedef int (DNSSD_API * Func)(DNSServiceRef sdRef); static Func func = NULL; - int ret = -1; + int ret = INVALID_SOCKET; if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) { diff --git a/mDNSResponder/mDNSWindows/DLLX/DNSSD.cpp b/mDNSResponder/mDNSWindows/DLLX/DNSSD.cpp index 8813d2df..f011dd14 100755 --- a/mDNSResponder/mDNSWindows/DLLX/DNSSD.cpp +++ b/mDNSResponder/mDNSWindows/DLLX/DNSSD.cpp @@ -643,7 +643,7 @@ CDNSSD::ResolveReply record->AddRef(); char buf[ 64 ]; - sprintf( buf, "txtLen = %d", txtLen ); + snprintf( buf, sizeof( buf ), "txtLen = %d", txtLen ); OutputDebugStringA( buf ); if ( txtLen > 0 ) diff --git a/mDNSResponder/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp b/mDNSResponder/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp index 9e4db65b..fe46be08 100644 --- a/mDNSResponder/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp +++ b/mDNSResponder/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp @@ -269,7 +269,7 @@ static void DNSStatus inStatusCode, const DNSBrowserEvent * inEvent ); -static char * DNSNetworkAddressToString( const DNSNetworkAddress *inAddr, char *outString ); +static char * DNSNetworkAddressToString( const DNSNetworkAddress *inAddr, size_t inLen, char *outString ); static DWORD UTF8StringToStringObject( const char *inUTF8, CString &inObject ); static DWORD StringObjectToUTF8String( CString &inObject, std::string &outUTF8 ); @@ -1273,8 +1273,8 @@ static void serviceInstance->name = inEvent->data.resolved->name; serviceInstance->type = inEvent->data.resolved->type; serviceInstance->domain = inEvent->data.resolved->domain; - serviceInstance->ip = DNSNetworkAddressToString( &inEvent->data.resolved->address, s ); - serviceInstance->ifIP = DNSNetworkAddressToString( &inEvent->data.resolved->interfaceIP, s ); + serviceInstance->ip = DNSNetworkAddressToString( &inEvent->data.resolved->address, sizeof( s ), s ); + serviceInstance->ifIP = DNSNetworkAddressToString( &inEvent->data.resolved->interfaceIP, sizeof( s ), s ); serviceInstance->text = inEvent->data.resolved->textRecord; serviceInstance->hostName = inEvent->data.resolved->hostName; @@ -1303,7 +1303,7 @@ static void // Note: Currently only supports IPv4 network addresses. //=========================================================================================================================== -static char * DNSNetworkAddressToString( const DNSNetworkAddress *inAddr, char *outString ) +static char * DNSNetworkAddressToString( const DNSNetworkAddress *inAddr, size_t inLen, char *outString ) { const DNSUInt8 * p; DNSUInt16 port; @@ -1312,11 +1312,11 @@ static char * DNSNetworkAddressToString( const DNSNetworkAddress *inAddr, char * port = ntohs( inAddr->u.ipv4.port.v16 ); if( port != kDNSPortInvalid ) { - sprintf( outString, "%u.%u.%u.%u:%u", p[ 0 ], p[ 1 ], p[ 2 ], p[ 3 ], port ); + snprintf( outString, inLen, "%u.%u.%u.%u:%u", p[ 0 ], p[ 1 ], p[ 2 ], p[ 3 ], port ); } else { - sprintf( outString, "%u.%u.%u.%u", p[ 0 ], p[ 1 ], p[ 2 ], p[ 3 ] ); + snprintf( outString, inLen, "%u.%u.%u.%u", p[ 0 ], p[ 1 ], p[ 2 ], p[ 3 ] ); } return( outString ); } diff --git a/mDNSResponder/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp b/mDNSResponder/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp index 92cdeb30..67b9cb85 100644 --- a/mDNSResponder/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp +++ b/mDNSResponder/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp @@ -204,7 +204,7 @@ void { char ip[ 64 ]; - sprintf( ip, "%u.%u.%u.%u:%u", + snprintf( ip, sizeof( ip ), "%u.%u.%u.%u:%u", inEvent->data.resolved->address.u.ipv4.addr.v8[ 0 ], inEvent->data.resolved->address.u.ipv4.addr.v8[ 1 ], inEvent->data.resolved->address.u.ipv4.addr.v8[ 2 ], diff --git a/mDNSResponder/mDNSWindows/Java/makefile b/mDNSResponder/mDNSWindows/Java/makefile index 2e4b6bd0..da237976 100644 --- a/mDNSResponder/mDNSWindows/Java/makefile +++ b/mDNSResponder/mDNSWindows/Java/makefile @@ -34,7 +34,7 @@ COREDIR = ..\..\mDNSCore SHAREDDIR = ..\..\mDNSShared -JDK = $(JAVA_HOME) +JDK = "$(JAVA_HOME)" CC = cl RC = rc diff --git a/mDNSResponder/mDNSWindows/Java/makefile64 b/mDNSResponder/mDNSWindows/Java/makefile64 index fb0ff9ce..5845ab5e 100644 --- a/mDNSResponder/mDNSWindows/Java/makefile64 +++ b/mDNSResponder/mDNSWindows/Java/makefile64 @@ -34,7 +34,7 @@ COREDIR = ..\..\mDNSCore SHAREDDIR = ..\..\mDNSShared -JDK = $(JAVA_HOME) +JDK = "$(JAVA_HOME)" CC = cl RC = rc diff --git a/mDNSResponder/mDNSWindows/NSPTool/NSPTool.c b/mDNSResponder/mDNSWindows/NSPTool/NSPTool.c index f3052d16..0be174df 100644 --- a/mDNSResponder/mDNSWindows/NSPTool/NSPTool.c +++ b/mDNSResponder/mDNSWindows/NSPTool/NSPTool.c @@ -38,7 +38,7 @@ DEBUG_LOCAL OSStatus ListNameSpaces( void ); DEBUG_LOCAL OSStatus ReorderNameSpaces( void ); DEBUG_LOCAL WCHAR * CharToWCharString( const char *inCharString, WCHAR *outWCharString ); -DEBUG_LOCAL char * GUIDtoString( const GUID *inGUID, char *outString ); +DEBUG_LOCAL char * GUIDtoString( const GUID *inGUID, size_t inLen, char *outString ); DEBUG_LOCAL OSStatus StringToGUID( const char *inCharString, GUID *outGUID ); DEBUG_LOCAL BOOL gToolQuietMode = FALSE; @@ -390,7 +390,7 @@ DEBUG_LOCAL OSStatus ListNameSpaces( void ) for( i = 0; i < n; ++i ) { fprintf( stdout, "Name Space %d\n", i + 1 ); - fprintf( stdout, " NSProviderId: %s\n", GUIDtoString( &array[ i ].NSProviderId, s ) ); + fprintf( stdout, " NSProviderId: %s\n", GUIDtoString( &array[ i ].NSProviderId, sizeof( s ), s ) ); fprintf( stdout, " dwNameSpace: %d\n", array[ i ].dwNameSpace ); fprintf( stdout, " fActive: %s\n", array[ i ].fActive ? "YES" : "NO" ); fprintf( stdout, " dwVersion: %d\n", array[ i ].dwVersion ); @@ -536,12 +536,12 @@ DEBUG_LOCAL WCHAR * CharToWCharString( const char *inCharString, WCHAR *outWChar // GUIDtoString //=========================================================================================================================== -DEBUG_LOCAL char * GUIDtoString( const GUID *inGUID, char *outString ) +DEBUG_LOCAL char * GUIDtoString( const GUID *inGUID, size_t inLen, char *outString ) { check( inGUID ); check( outString ); - sprintf( outString, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + _snprintf( outString, inLen, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", inGUID->Data1, inGUID->Data2, inGUID->Data3, inGUID->Data4[ 0 ], inGUID->Data4[ 1 ], inGUID->Data4[ 2 ], inGUID->Data4[ 3 ], inGUID->Data4[ 4 ], inGUID->Data4[ 5 ], inGUID->Data4[ 6 ], inGUID->Data4[ 7 ] ); diff --git a/mDNSResponder/mDNSWindows/SystemService/Service.c b/mDNSResponder/mDNSWindows/SystemService/Service.c index d175326f..1dea5c79 100644 --- a/mDNSResponder/mDNSWindows/SystemService/Service.c +++ b/mDNSResponder/mDNSWindows/SystemService/Service.c @@ -786,7 +786,7 @@ static void ReportStatus( int inType, const char *inFormat, ... ) BOOL ok; const char * array[ 1 ]; - vsprintf( s, inFormat, args ); + vsnprintf( s, sizeof( s ), inFormat, args ); array[ 0 ] = s; ok = ReportEventA( gServiceEventSource, (WORD) inType, 0, MDNSRESPONDER_LOG, NULL, 1, 0, array, NULL ); check_translated_errno( ok, GetLastError(), kUnknownErr ); diff --git a/mDNSResponder/mDNSWindows/mDNSWin32.c b/mDNSResponder/mDNSWindows/mDNSWin32.c index 0789cf4d..011125b9 100755 --- a/mDNSResponder/mDNSWindows/mDNSWin32.c +++ b/mDNSResponder/mDNSWindows/mDNSWin32.c @@ -106,7 +106,6 @@ mDNSlocal int getifaddrs( struct ifaddrs **outAddrs ); mDNSlocal void freeifaddrs( struct ifaddrs *inAddrs ); - // Platform Accessors #ifdef __cplusplus @@ -127,8 +126,6 @@ mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInter // Wakeup Structs -#define kUnicastWakeupNumTries ( 1 ) -#define kUnicastWakeupSleepBetweenTries ( 0 ) #define kMulticastWakeupNumTries ( 18 ) #define kMulticastWakeupSleepBetweenTries ( 100 ) @@ -152,7 +149,6 @@ typedef struct MulticastWakeupStruct mDNSlocal int getifaddrs_ipv4( struct ifaddrs **outAddrs ); - mDNSlocal DWORD GetPrimaryInterface(); mDNSlocal mStatus AddressToIndexAndMask( struct sockaddr * address, uint32_t * index, struct sockaddr * mask ); mDNSlocal mDNSBool CanReceiveUnicast( void ); @@ -216,12 +212,10 @@ mDNSlocal BOOL gEnableIPv6 = TRUE; #endif - #ifndef HCRYPTPROV typedef ULONG_PTR HCRYPTPROV; // WinCrypt.h, line 249 #endif - #ifndef CRYPT_MACHINE_KEYSET # define CRYPT_MACHINE_KEYSET 0x00000020 #endif @@ -277,7 +271,6 @@ mDNSlocal HANDLE gSMBThreadQuitEvent = NULL; #define kSMBRegisterEvent ( WAIT_OBJECT_0 + 1 ) #define kSMBDeregisterEvent ( WAIT_OBJECT_0 + 2 ) - #if 0 #pragma mark - #pragma mark == Platform Support == @@ -570,7 +563,6 @@ mDNSexport void mDNSPlatformClose( mDNS * const inMDNS ) dlog( kDebugLevelTrace, DEBUG_NAME "platform close done\n" ); } - //=========================================================================================================================== // mDNSPlatformLock //=========================================================================================================================== @@ -601,6 +593,39 @@ mDNSexport void mDNSPlatformStrCopy( void *inDst, const void *inSrc ) strcpy( (char *) inDst, (const char*) inSrc ); } +//=========================================================================================================================== +// mDNSPlatformStrLCopy +//=========================================================================================================================== + +mDNSexport mDNSu32 mDNSPlatformStrLCopy( void *inDst, const void *inSrc, mDNSu32 inSize ) +{ + const char * src = (const char *) inSrc; + + if( inSize > 0 ) + { + size_t n; + char * dst = (char *) inDst; + + for( n = inSize - 1; n > 0; --n ) + { + if( ( *dst++ = *src++ ) == '\0' ) + { + // Null terminator encountered, so exit. + goto exit; + } + } + *dst = '\0'; + } + + while( *src++ != '\0' ) + { + // Stop at null terminator. + } + +exit: + return( (mDNSu32)( src - (const char *) inSrc ) - 1 ); +} + //=========================================================================================================================== // mDNSPlatformStrLen //=========================================================================================================================== @@ -940,7 +965,6 @@ mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID( mDNS * const inMDN return( index ); } - //=========================================================================================================================== // mDNSPlatformTCPSocket //=========================================================================================================================== @@ -1077,12 +1101,10 @@ exit: return err; } - //=========================================================================================================================== // mDNSPlatformTCPAccept //=========================================================================================================================== -mDNSexport mDNSexport TCPSocket *mDNSPlatformTCPAccept( TCPSocketFlags flags, int fd ) { TCPSocket * sock = NULL; @@ -1109,7 +1131,6 @@ exit: return sock; } - //=========================================================================================================================== // mDNSPlatformTCPCloseConnection //=========================================================================================================================== @@ -1133,7 +1154,6 @@ mDNSexport void mDNSPlatformTCPCloseConnection( TCPSocket *sock ) } } - //=========================================================================================================================== // mDNSPlatformReadTCP //=========================================================================================================================== @@ -1173,7 +1193,6 @@ mDNSexport long mDNSPlatformReadTCP( TCPSocket *sock, void *inBuffer, unsigned l return nread; } - //=========================================================================================================================== // mDNSPlatformWriteTCP //=========================================================================================================================== @@ -1207,8 +1226,6 @@ mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock ) return ( int ) sock->fd; } - - //=========================================================================================================================== // TCPSocketNotification //=========================================================================================================================== @@ -1248,8 +1265,6 @@ exit: return; } - - //=========================================================================================================================== // mDNSPlatformUDPSocket //=========================================================================================================================== @@ -1362,7 +1377,6 @@ mDNSexport void mDNSPlatformUDPClose( UDPSocket *sock ) } } - //=========================================================================================================================== // mDNSPlatformSendUDP //=========================================================================================================================== @@ -1450,21 +1464,12 @@ exit: return( err ); } - -mDNSexport mDNSBool mDNSPlatformPeekUDP(mDNS *const m, UDPSocket *src) -{ - DEBUG_UNUSED( m ); - DEBUG_UNUSED( src ); - return mDNSfalse; -} - mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID) { DEBUG_UNUSED( m ); DEBUG_UNUSED( InterfaceID ); } - mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason) { DEBUG_UNUSED( m ); @@ -1482,14 +1487,13 @@ mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID Inte unsigned char buf[ 102 ]; char hex[ 3 ] = { 0 }; unsigned char *bufPtr = buf; - struct sockaddr_storage saddr; - INT len = sizeof( saddr ); - mDNSBool unicast = mDNSfalse; MulticastWakeupStruct *info; int i; mStatus err; - (void) InterfaceID; + (void) InterfaceID; // unused + (void) ipaddr; // unused + (void) iteration; // unused require_action( ethaddr, exit, err = mStatus_BadParamErr ); @@ -1512,44 +1516,6 @@ mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID Inte bufPtr += sizeof( mac ); } - if ( ipaddr ) - { - if ( WSAStringToAddressA( ipaddr, AF_INET, NULL, ( LPSOCKADDR ) &saddr, &len ) == 0 ) - { - struct sockaddr_in * saddr4 = ( struct sockaddr_in* ) &saddr; - saddr4->sin_port = htons( 9 ); - len = sizeof( *saddr4 ); - - if ( saddr4->sin_addr.s_addr != htonl( INADDR_ANY ) ) - { - unicast = mDNStrue; - } - } - else if ( WSAStringToAddressA( ipaddr, AF_INET6, NULL, ( LPSOCKADDR ) &saddr, &len ) == 0 ) - { - mDNSInterfaceData *ifd = ( mDNSInterfaceData* ) InterfaceID; - struct sockaddr_in6 * saddr6 = ( struct sockaddr_in6* ) &saddr; - saddr6->sin6_port = htons( 9 ); - - if ( ifd != NULL ) - { - saddr6->sin6_scope_id = ifd->scopeID; - } - - len = sizeof( *saddr6 ); - - if ( memcmp( &saddr6->sin6_addr, &in6addr_any, sizeof( IN6_ADDR ) ) != 0 ) - { - unicast = mDNStrue; - } - } - } - - if ( ( iteration < 2 ) && ( unicast ) ) - { - SendWakeupPacket( m, ( LPSOCKADDR ) &saddr, len, ( const char* ) buf, sizeof( buf ), kUnicastWakeupNumTries, kUnicastWakeupSleepBetweenTries ); - } - info = ( MulticastWakeupStruct* ) malloc( sizeof( MulticastWakeupStruct ) ); require_action( info, exit, err = mStatus_NoMemoryErr ); info->inMDNS = m; @@ -1570,11 +1536,10 @@ exit: return; } - -mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const NetworkInterfaceInfo *intf) +mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID) { DEBUG_UNUSED( rr ); - DEBUG_UNUSED( intf ); + DEBUG_UNUSED( InterfaceID ); return mDNStrue; } @@ -1601,7 +1566,6 @@ mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsiz if (bufsize) buf[0] = 0; } - mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID) { DEBUG_UNUSED( m ); @@ -1610,7 +1574,6 @@ mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSA DEBUG_UNUSED( InterfaceID ); } - mDNSexport void mDNSPlatformReceiveRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID) { DEBUG_UNUSED( msg ); @@ -1711,7 +1674,6 @@ mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, return mDNStrue; } - //=========================================================================================================================== // mDNSPlatformDynDNSHostNameStatusChanged //=========================================================================================================================== @@ -1756,7 +1718,6 @@ exit: return; } - //=========================================================================================================================== // SetDomainSecrets //=========================================================================================================================== @@ -1798,7 +1759,6 @@ SetDomainSecrets( mDNS * const m ) } } - //=========================================================================================================================== // SetSearchDomainList //=========================================================================================================================== @@ -1849,7 +1809,6 @@ exit: SetReverseMapSearchDomainList(); } - //=========================================================================================================================== // SetReverseMapSearchDomainList //=========================================================================================================================== @@ -1871,10 +1830,10 @@ SetReverseMapSearchDomainList( void ) if (!SetupAddr(&netmask, ifa->ifa_netmask)) { - sprintf(buffer, "%d.%d.%d.%d.in-addr.arpa.", addr.ip.v4.b[3] & netmask.ip.v4.b[3], - addr.ip.v4.b[2] & netmask.ip.v4.b[2], - addr.ip.v4.b[1] & netmask.ip.v4.b[1], - addr.ip.v4.b[0] & netmask.ip.v4.b[0]); + _snprintf(buffer, sizeof( buffer ), "%d.%d.%d.%d.in-addr.arpa.", addr.ip.v4.b[3] & netmask.ip.v4.b[3], + addr.ip.v4.b[2] & netmask.ip.v4.b[2], + addr.ip.v4.b[1] & netmask.ip.v4.b[1], + addr.ip.v4.b[0] & netmask.ip.v4.b[0]); mDNS_AddSearchDomain_CString(buffer, mDNSNULL); } } @@ -1885,7 +1844,6 @@ SetReverseMapSearchDomainList( void ) return; } - //=========================================================================================================================== // SetDNSServers //=========================================================================================================================== @@ -1978,7 +1936,6 @@ exit: } } - //=========================================================================================================================== // SetDomainFromDHCP //=========================================================================================================================== @@ -2071,7 +2028,6 @@ exit: } } - //=========================================================================================================================== // mDNSPlatformGetPrimaryInterface //=========================================================================================================================== @@ -2171,8 +2127,16 @@ mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifna return mStatus_UnsupportedErr; } -mDNSexport mStatus mDNSPlatformClearSPSMACAddr(void) +mDNSexport mStatus mDNSPlatformClearSPSData(void) +{ + return mStatus_UnsupportedErr; +} + +mDNSexport mStatus mDNSPlatformStoreOwnerOptRecord(char *ifname, DNSMessage *msg, int length) { + (void) ifname; // Unused + (void) msg; // Unused + (void) length; // Unused return mStatus_UnsupportedErr; } @@ -2188,18 +2152,11 @@ mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNS *const m, mDNSAddr *laddr, m return mStatus_UnsupportedErr; } -mDNSexport void mDNSPlatformGetDNSRoutePolicy(mDNS *const m, DNSQuestion *q, mDNSBool *isCellBlocked) -{ - (void) m; - - q->ServiceID = -1; - *isCellBlocked = mDNSfalse; -} - -mDNSexport void mDNSPlatformSetuDNSSocktOpt(UDPSocket *src, const mDNSAddr *dst, DNSQuestion *q) +mDNSexport void mDNSPlatformSetSocktOpt(void *sock, mDNSTransport_Type transType, mDNSAddr_Type addrType, DNSQuestion *q) { - (void) src; - (void) dst; + (void) sock; + (void) transType; + (void) addrType; (void) q; } @@ -2263,13 +2220,11 @@ mDNSexport void verbosedebugf_( const char *inFormat, ... ) } #endif - #if 0 #pragma mark - #pragma mark == Platform Internals == #endif - //=========================================================================================================================== // SetupNiceName //=========================================================================================================================== @@ -2341,7 +2296,7 @@ mStatus SetupNiceName( mDNS * const inMDNS ) { // Invalidate name so fall back to a default name. - strcpy( utf8, kMDNSDefaultName ); + strcpy_s( utf8, sizeof( utf8 ), kMDNSDefaultName ); } utf8[ sizeof( utf8 ) - 1 ] = '\0'; @@ -2411,7 +2366,7 @@ mDNSlocal mStatus SetupHostName( mDNS * const inMDNS ) { // Invalidate name so fall back to a default name. - strcpy( tempString, kMDNSDefaultName ); + strcpy_s( tempString, sizeof( tempString ), kMDNSDefaultName ); } tempString[ sizeof( tempString ) - 1 ] = '\0'; @@ -2456,7 +2411,6 @@ mDNSlocal mStatus SetupName( mDNS * const inMDNS ) return err; } - //=========================================================================================================================== // SetupInterfaceList //=========================================================================================================================== @@ -3209,7 +3163,6 @@ mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAd return( err ); } - #if 0 #pragma mark - #endif @@ -3404,7 +3357,6 @@ exit: return; } - //=========================================================================================================================== // InterfaceListDidChange //=========================================================================================================================== @@ -3435,7 +3387,6 @@ void InterfaceListDidChange( mDNS * const inMDNS ) mDNSCoreMachineSleep( inMDNS, mDNSfalse ); // What is this for? Mac OS X does not do this } - //=========================================================================================================================== // ComputerDescriptionDidChange //=========================================================================================================================== @@ -3448,7 +3399,6 @@ void ComputerDescriptionDidChange( mDNS * const inMDNS ) SetupNiceName( inMDNS ); } - //=========================================================================================================================== // TCPIPConfigDidChange //=========================================================================================================================== @@ -3463,7 +3413,6 @@ void TCPIPConfigDidChange( mDNS * const inMDNS ) check_noerr( err ); } - //=========================================================================================================================== // DynDNSConfigDidChange //=========================================================================================================================== @@ -3480,7 +3429,6 @@ void DynDNSConfigDidChange( mDNS * const inMDNS ) check_noerr( err ); } - //=========================================================================================================================== // FileSharingDidChange //=========================================================================================================================== @@ -3492,7 +3440,6 @@ void FileSharingDidChange( mDNS * const inMDNS ) CheckFileShares( inMDNS ); } - //=========================================================================================================================== // FilewallDidChange //=========================================================================================================================== @@ -3504,7 +3451,6 @@ void FirewallDidChange( mDNS * const inMDNS ) CheckFileShares( inMDNS ); } - #if 0 #pragma mark - #pragma mark == Utilities == @@ -3982,7 +3928,7 @@ mDNSlocal int getifaddrs_ipv4( struct ifaddrs **outAddrs ) ifa->ifa_name = (char *) malloc( 16 ); require_action( ifa->ifa_name, exit, err = WSAENOBUFS ); - sprintf( ifa->ifa_name, "%d", i + 1 ); + _snprintf( ifa->ifa_name, 16, "%d", i + 1 ); // Get interface flags. @@ -4092,7 +4038,6 @@ mDNSlocal void freeifaddrs( struct ifaddrs *inIFAs ) } } - //=========================================================================================================================== // GetPrimaryInterface //=========================================================================================================================== @@ -4123,7 +4068,6 @@ GetPrimaryInterface() err = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder); require_noerr( err, exit ); - // Search for the row in the table we want. for ( i = 0; i < pIpForwardTable->dwNumEntries; i++) @@ -4152,7 +4096,6 @@ exit: return index; } - //=========================================================================================================================== // AddressToIndexAndMask //=========================================================================================================================== @@ -4213,7 +4156,6 @@ exit: return err; } - //=========================================================================================================================== // CanReceiveUnicast //=========================================================================================================================== @@ -4244,7 +4186,6 @@ mDNSlocal mDNSBool CanReceiveUnicast( void ) return( ok ); } - //=========================================================================================================================== // IsPointToPoint //=========================================================================================================================== @@ -4286,7 +4227,6 @@ exit: return ret; } - //=========================================================================================================================== // GetWindowsVersionString //=========================================================================================================================== @@ -4387,7 +4327,6 @@ exit: return( err ); } - //=========================================================================================================================== // RegQueryString //=========================================================================================================================== @@ -4436,7 +4375,6 @@ exit: return err; } - //=========================================================================================================================== // StringToAddress //=========================================================================================================================== @@ -4476,7 +4414,6 @@ exit: return err; } - //=========================================================================================================================== // myGetIfAddrs //=========================================================================================================================== @@ -4500,7 +4437,6 @@ myGetIfAddrs(int refresh) return ifa; } - //=========================================================================================================================== // TCHARtoUTF8 //=========================================================================================================================== @@ -4523,7 +4459,6 @@ exit: #endif } - //=========================================================================================================================== // WindowsLatin1toUTF8 //=========================================================================================================================== @@ -4561,7 +4496,6 @@ exit: return( err ); } - //=========================================================================================================================== // TCPCloseSocket //=========================================================================================================================== @@ -4578,7 +4512,6 @@ TCPCloseSocket( TCPSocket * sock ) } } - //=========================================================================================================================== // UDPCloseSocket //=========================================================================================================================== @@ -4596,7 +4529,6 @@ UDPCloseSocket( UDPSocket * sock ) } } - //=========================================================================================================================== // SetupAddr //=========================================================================================================================== @@ -4626,7 +4558,6 @@ mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa) return(mStatus_Invalid); } - mDNSlocal void GetDDNSFQDN( domainname *const fqdn ) { LPSTR name = NULL; @@ -4670,7 +4601,6 @@ exit: } } - #ifdef UNICODE mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCWSTR lpSubKey ) #else @@ -4754,7 +4684,6 @@ exit: } } - mDNSlocal void SetDomainSecret( mDNS * const m, const domainname * inDomain ) { char domainUTF8[ 256 ]; @@ -4801,7 +4730,6 @@ exit: return; } - mDNSlocal VOID CALLBACK CheckFileSharesProc( LPVOID arg, DWORD dwTimerLowValue, DWORD dwTimerHighValue ) { @@ -4813,7 +4741,6 @@ CheckFileSharesProc( LPVOID arg, DWORD dwTimerLowValue, DWORD dwTimerHighValue ) CheckFileShares( m ); } - mDNSlocal unsigned __stdcall SMBRegistrationThread( void * arg ) { @@ -4902,7 +4829,6 @@ exit: return 0; } - mDNSlocal void CheckFileShares( mDNS * const m ) { @@ -5056,7 +4982,6 @@ exit: } } - BOOL IsWOMPEnabled( mDNS * const m ) { @@ -5078,7 +5003,6 @@ IsWOMPEnabled( mDNS * const m ) return enabled; } - mDNSlocal mDNSu8 IsWOMPEnabledForAdapter( const char * adapterName ) { @@ -5128,7 +5052,6 @@ exit: return ( mDNSu8 ) ok; } - mDNSlocal void SendWakeupPacket( mDNS * const inMDNS, LPSOCKADDR addr, INT addrlen, const char * buf, INT buflen, INT numTries, INT msecSleep ) { @@ -5175,7 +5098,6 @@ exit: } } - mDNSlocal void _cdecl SendMulticastWakeupPacket( void *arg ) { @@ -5190,7 +5112,6 @@ SendMulticastWakeupPacket( void *arg ) _endthread(); } - mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result) { DEBUG_UNUSED( m ); diff --git a/mDNSResponder/mDNSWindows/mdnsNSP/mdnsNSP.c b/mDNSResponder/mDNSWindows/mdnsNSP/mdnsNSP.c index 2cd01eff..21baa866 100644 --- a/mDNSResponder/mDNSWindows/mdnsNSP/mdnsNSP.c +++ b/mDNSResponder/mDNSWindows/mdnsNSP/mdnsNSP.c @@ -1847,7 +1847,7 @@ InHostsTable( const char * name ) HostsFile * hFile; GetSystemDirectory( systemDirectory, sizeof( systemDirectory ) ); - sprintf( hFileName, "%s\\drivers\\etc\\hosts", systemDirectory ); + snprintf( hFileName, sizeof( hFileName ), "%s\\drivers\\etc\\hosts", systemDirectory ); err = HostsFileOpen( &hFile, hFileName ); require_noerr( err, exit ); @@ -2072,6 +2072,7 @@ HostsFileNext( HostsFile * self, HostsFileInfo ** hInfo ) int idx; int i; short family; + size_t len; OSStatus err = kNoErr; check( self ); @@ -2146,9 +2147,10 @@ HostsFileNext( HostsFile * self, HostsFileInfo ** hInfo ) // Now we have the name - (*hInfo)->m_host.h_name = (char*) malloc( strlen( tok ) + 1 ); + len = strlen( tok ) + 1; + (*hInfo)->m_host.h_name = (char*) malloc( len ); require_action( (*hInfo)->m_host.h_name, exit, err = kNoMemoryErr ); - strcpy( (*hInfo)->m_host.h_name, tok ); + strcpy_s( (*hInfo)->m_host.h_name, len, tok ); // Now create the address (IPv6/IPv4) @@ -2220,10 +2222,11 @@ HostsFileNext( HostsFile * self, HostsFileInfo ** hInfo ) require_action( (*hInfo)->m_host.h_aliases, exit, err = kNoMemoryErr ); } - (*hInfo)->m_host.h_aliases[i] = (char*) malloc( strlen( tok ) + 1 ); + len = strlen( tok ) + 1; + (*hInfo)->m_host.h_aliases[i] = (char*) malloc( len ); require_action( (*hInfo)->m_host.h_aliases[i], exit, err = kNoMemoryErr ); - strcpy( (*hInfo)->m_host.h_aliases[i], tok ); + strcpy_s( (*hInfo)->m_host.h_aliases[i], len, tok ); if (( tok = strpbrk( tok, " \t")) != NULL ) { diff --git a/mDNSResponder/unittests/DNSMessageTest.c b/mDNSResponder/unittests/DNSMessageTest.c new file mode 100644 index 00000000..fedfed3b --- /dev/null +++ b/mDNSResponder/unittests/DNSMessageTest.c @@ -0,0 +1,50 @@ +#include "mDNSEmbeddedAPI.h" +#include "DNSMessageTest.h" +#include "../mDNSCore/DNSCommon.h" + +int SizeTest(void); +int InitializeTest(void); +int PutDomainNameAsLabels(void); +int PutRData(void); +int Finalize(void); + + +DNSMessage *msg; + + +UNITTEST_HEADER(DNSMessageTest) + UNITTEST_TEST(SizeTest) + UNITTEST_TEST(InitializeTest) + UNITTEST_TEST(Finalize) +UNITTEST_FOOTER + + +UNITTEST_HEADER(SizeTest) + msg = (DNSMessage *)malloc (sizeof(DNSMessage)); + UNITTEST_ASSERT_RETURN(msg != NULL); + + // message header should be 12 bytes + UNITTEST_ASSERT(sizeof(msg->h) == 12); +UNITTEST_FOOTER + + +UNITTEST_HEADER(InitializeTest) + // Initialize the message + InitializeDNSMessage(&msg->h, onesID, QueryFlags); + + // Check that the message is initialized properly + UNITTEST_ASSERT(msg->h.numAdditionals == 0); + UNITTEST_ASSERT(msg->h.numAnswers == 0); + UNITTEST_ASSERT(msg->h.numQuestions == 0); + UNITTEST_ASSERT(msg->h.numAuthorities == 0); +UNITTEST_FOOTER + + +UNITTEST_HEADER(PutDomainNameAsLabels) + +UNITTEST_FOOTER + +UNITTEST_HEADER(Finalize) + UNITTEST_ASSERT_RETURN(msg != NULL) + free(msg); +UNITTEST_FOOTER \ No newline at end of file diff --git a/mDNSResponder/unittests/DNSMessageTest.h b/mDNSResponder/unittests/DNSMessageTest.h new file mode 100644 index 00000000..147175f7 --- /dev/null +++ b/mDNSResponder/unittests/DNSMessageTest.h @@ -0,0 +1,8 @@ +#ifndef DNSMessageTest_h +#define DNSMessageTest_h + +#include "unittest.h" + +int DNSMessageTest(void); + +#endif /* DNSMessageTest_h */ \ No newline at end of file diff --git a/mDNSResponder/unittests/DomainNameTest.c b/mDNSResponder/unittests/DomainNameTest.c new file mode 100644 index 00000000..571725a5 --- /dev/null +++ b/mDNSResponder/unittests/DomainNameTest.c @@ -0,0 +1,28 @@ +#include "DomainNameTest.h" +#include "mDNSEmbeddedAPI.h" +#include "../mDNSCore/DNSCommon.h" + +int SameDomainNameTest(void); +int SameDomainLabelTest(void); +int LocalDomainTest(void); + + +UNITTEST_HEADER(DomainNameTest) + UNITTEST_TEST(SameDomainLabelTest) + UNITTEST_TEST(SameDomainNameTest) + UNITTEST_TEST(LocalDomainTest) +UNITTEST_FOOTER + + + + +UNITTEST_HEADER(SameDomainLabelTest) +UNITTEST_FOOTER + + +UNITTEST_HEADER(SameDomainNameTest) +UNITTEST_FOOTER + + +UNITTEST_HEADER(LocalDomainTest) +UNITTEST_FOOTER \ No newline at end of file diff --git a/mDNSResponder/unittests/DomainNameTest.h b/mDNSResponder/unittests/DomainNameTest.h new file mode 100644 index 00000000..1c429c20 --- /dev/null +++ b/mDNSResponder/unittests/DomainNameTest.h @@ -0,0 +1,7 @@ +#ifndef DomainNameTest_h +#define DomainNameTest_h + +#include "unittest.h" +int DomainNameTest(void); + +#endif /* DomainNameTest_h */ diff --git a/mDNSResponder/unittests/InterfaceTest.c b/mDNSResponder/unittests/InterfaceTest.c new file mode 100644 index 00000000..a9738141 --- /dev/null +++ b/mDNSResponder/unittests/InterfaceTest.c @@ -0,0 +1,19 @@ +#include "InterfaceTest.h" +#include "mDNSEmbeddedAPI.h" + + +NetworkInterfaceInfo *intf; +mDNS *m; + +int LocalSubnetTest(void); + +UNITTEST_HEADER(InterfaceTest) + UNITTEST_TEST(LocalSubnetTest) +UNITTEST_FOOTER + +UNITTEST_HEADER(LocalSubnetTest) + // need a way to initialize m before we call into the class of APIs that use a ptr to mDNS + // should that pointer be common to all tests? + // mDNS_AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr) + // TEST_ASSERT_RETURN (for IPv4/IPv6 local subnet) +UNITTEST_FOOTER diff --git a/mDNSResponder/unittests/InterfaceTest.h b/mDNSResponder/unittests/InterfaceTest.h new file mode 100644 index 00000000..f94b3da1 --- /dev/null +++ b/mDNSResponder/unittests/InterfaceTest.h @@ -0,0 +1,9 @@ + +#ifndef InterfaceTest_h +#define InterfaceTest_h + +#include "unittest.h" + +int InterfaceTest(void); + +#endif /* InterfaceTest_h */ diff --git a/mDNSResponder/unittests/ResourceRecordTest.c b/mDNSResponder/unittests/ResourceRecordTest.c new file mode 100644 index 00000000..d0530086 --- /dev/null +++ b/mDNSResponder/unittests/ResourceRecordTest.c @@ -0,0 +1,60 @@ +#include "mDNSEmbeddedAPI.h" +#include "../mDNSCore/DNSCommon.h" +#include "ResourceRecordTest.h" + +int TXTSetupTest(void); +int ASetupTest(void); +int OPTSetupTest(void); + + +UNITTEST_HEADER(ResourceRecordTest) + UNITTEST_TEST(TXTSetupTest) + UNITTEST_TEST(ASetupTest) + UNITTEST_TEST(OPTSetupTest) +UNITTEST_FOOTER + + +UNITTEST_HEADER(TXTSetupTest) + + AuthRecord authRec; + mDNS_SetupResourceRecord(&authRec, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeShared, AuthRecordAny,mDNSNULL, mDNSNULL); + UNITTEST_ASSERT_RETURN(authRec.resrec.RecordType == kDNSType_TXT); + UNITTEST_ASSERT_RETURN(authRec.resrec.rdata->MaxRDLength == sizeof(RDataBody)); + + // Retest with a RDataStorage set to a a buffer +UNITTEST_FOOTER + + +UNITTEST_HEADER(ASetupTest) + AuthRecord authRec; + mDNS_SetupResourceRecord(&authRec, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnique, AuthRecordAny, mDNSNULL, mDNSNULL); + UNITTEST_ASSERT_RETURN(authRec.resrec.RecordType == kDNSType_A); + // Add more verifications + +UNITTEST_FOOTER + + +UNITTEST_HEADER(OPTSetupTest) + AuthRecord opt; + mDNSu32 updatelease = 7200; +/* mDNSu8 data[AbsoluteMaxDNSMessageData]; + mDNSu8 *p = data; + mDNSu16 numAdditionals; +*/ + // Setup the OPT Record + mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL); + + // Verify the basic initialization is all ok + + opt.resrec.rrclass = NormalMaxDNSMessageData; + opt.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record + opt.resrec.rdestimate = sizeof(rdataOPT); + opt.resrec.rdata->u.opt[0].opt = kDNSOpt_Lease; + opt.resrec.rdata->u.opt[0].u.updatelease = updatelease; + + // Put the resource record in and verify everything is fine + // p = PutResourceRecordTTLWithLimit(&data, p, &numAdditionals, &opt.resrec, opt.resrec.rroriginalttl, data + AbsoluteMaxDNSMessageData); + + + // Repeat with bad data to make sure it bails out cleanly +UNITTEST_FOOTER \ No newline at end of file diff --git a/mDNSResponder/unittests/ResourceRecordTest.h b/mDNSResponder/unittests/ResourceRecordTest.h new file mode 100644 index 00000000..d762d016 --- /dev/null +++ b/mDNSResponder/unittests/ResourceRecordTest.h @@ -0,0 +1,10 @@ + + +#ifndef ResourceRecordTest_h +#define ResourceRecordTest_h + +#include "unittest.h" + +int ResourceRecordTest(void); + +#endif /* ResourceRecordTest_h */ diff --git a/mDNSResponder/unittests/main.c b/mDNSResponder/unittests/main.c new file mode 100644 index 00000000..752fffb7 --- /dev/null +++ b/mDNSResponder/unittests/main.c @@ -0,0 +1,33 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2015 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 "unittest.h" +#include "DNSMessageTest.h" + +const char *HWVersionString = "unittestMac1,1"; +const char *OSVersionString = "unittest 1.1.1 (1A111)"; +const char *BinaryNameString = "unittest"; +const char *VersionString = "unittest mDNSResponer-00 (Jan 1 1970 00:00:00)"; + +int run_tests(void); + +UNITTEST_HEADER(run_tests) +UNITTEST_GROUP(DNSMessageTest) +UNITTEST_FOOTER + +UNITTEST_MAIN diff --git a/mDNSResponder/unittests/unittest.c b/mDNSResponder/unittests/unittest.c new file mode 100644 index 00000000..1ad4b030 --- /dev/null +++ b/mDNSResponder/unittests/unittest.c @@ -0,0 +1,105 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2015 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 "unittest.h" + +int _unittest_assert_i(const int condition, const int i, const char * const conditionStr, + const char * const filename, const unsigned int linenum, + const char * const functionname, __test_item ** __i, int * const __success) +{ + if (!condition) + { + __test_item* tba = malloc(sizeof(__test_item)); + tba->next = *__i; + tba->file = filename; + tba->line = linenum; + tba->func = functionname; + tba->s = conditionStr; + tba->iter_count = i; + *__i = tba; + *__success = 0; + printf("F"); + } + else + { + printf("."); + } + + fflush(NULL); + return condition; +} + +void _unittest_print_list(__test_item* __i) +{ + __test_item* __tmp = NULL; + while (__i) + { + __test_item* __o = __i->next; + __i->next = __tmp; + __tmp = __i; + __i = __o; + } + __i = __tmp; + + while(__i) + { + printf("%s: In function `%s':\n%s:%d: error: failed UNITTEST_ASSERT", __i->file, __i->func, __i->file, __i->line); + if (__i->iter_count != -1) printf(" at iteration %d", __i->iter_count); + printf(": %s\n", __i->s); + __test_item* tbd = __i; + __i = __i->next; + free(tbd); + } +} + +// test by building like: +// gcc -g -Wall -Werror -DTEST_UNITTEST_SCAFFOLD unittest.c +// #define TEST_UNITTEST_SCAFFOLD 1 +#if TEST_UNITTEST_SCAFFOLD + +// modify this test as necessary to test the scaffold +UNITTEST_HEADER(test1) + int i = 0; + int j = 1; + int k = 2; + + UNITTEST_ASSERT(i==j); + UNITTEST_ASSERTI(j==i, k); + UNITTEST_ASSERT(i==i); + UNITTEST_ASSERTI(j==j, k); + UNITTEST_ASSERT_RETURN(j==j); + UNITTEST_ASSERTI_RETURN(j==j, k); +UNITTEST_FOOTER + +UNITTEST_HEADER(test2) + UNITTEST_ASSERT(1); + UNITTEST_ASSERT(0); + UNITTEST_ASSERT(1); +UNITTEST_FOOTER + +UNITTEST_HEADER(unittest_tests) +UNITTEST_TEST(test1) +UNITTEST_TEST(test2) +UNITTEST_FOOTER + +UNITTEST_HEADER(run_tests) +UNITTEST_GROUP(unittest_tests) +UNITTEST_FOOTER + +UNITTEST_MAIN + +#endif // TEST_UNITTEST_SCAFFOLD diff --git a/mDNSResponder/unittests/unittest.h b/mDNSResponder/unittests/unittest.h new file mode 100644 index 00000000..a219aa86 --- /dev/null +++ b/mDNSResponder/unittests/unittest.h @@ -0,0 +1,84 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2015 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 + +#ifndef _UNITTEST_H_ +#define _UNITTEST_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct __test_item_ +{ + struct __test_item_* next; + const char* file; + unsigned int line; + const char* func; + const char* s; + int iter_count; +} __test_item; + + +#define UNITTEST_HEADER(X) int X() { int __success = 1; __test_item* __i = NULL; + +#define UNITTEST_GROUP(X) { printf("== %s ==\n", #X); __success = X() && __success; } +#define UNITTEST_TEST(X) { printf("%s: ", #X); fflush(NULL); __success = X() && __success; } + +int _unittest_assert_i(const int condition, const int i, const char * const conditionStr, + const char * const filename, const unsigned int linenum, + const char * const functionname, __test_item ** __i, int * const __success); +#define UNITTEST_ASSERTI(X,I) (_unittest_assert_i((X)!=0, (I), #X, __FILE__, __LINE__, __func__, &__i, &__success)) +#define UNITTEST_ASSERT(X) UNITTEST_ASSERTI(X, -1) +#define UNITTEST_ASSERTI_RETURN(X,I) { if (!UNITTEST_ASSERTI(X,I)) goto __unittest_footer__; } +#define UNITTEST_ASSERT_RETURN(X) UNITTEST_ASSERTI_RETURN(X, -1) + +void _unittest_print_list(__test_item* __i); +#define UNITTEST_FOOTER goto __unittest_footer__; __unittest_footer__: printf("\n"); fflush(NULL); _unittest_print_list(__i); return __success; } + +#define UNITTEST_MAIN int main (int argc, char** argv) \ + { \ + (void)(argv); \ + signal(SIGPIPE, SIG_IGN); \ + FILE* fp; \ + unlink("unittest_success"); \ + if (!run_tests()) return -1; \ + fp = fopen("unittest_success", "w"); \ + if (!fp) return -2; \ + fclose(fp); \ + printf("unit test SUCCESS\n"); \ + if (argc != 1) \ + { \ + char c; \ + printf("run leaks now\n"); \ + read(STDIN_FILENO, &c, 1); \ + } \ + return 0; \ + } + +#define UNITTEST_FAIL_ASSERT { assert(((void*)__func__) == 0); } + +#ifdef __cplusplus +} +#endif + +#endif // ndef _UNITTEST_H_ -- cgit v1.2.3