X-Git-Url: https://git.saurik.com/apple/mdnsresponder.git/blobdiff_plain/c9d2d929f6ad52e6996754033ee77c725b90d1d4..95d7a4a31d5b4557b29fba1e0cdd09f1216ada8c:/mDNSCore/mDNSEmbeddedAPI.h diff --git a/mDNSCore/mDNSEmbeddedAPI.h b/mDNSCore/mDNSEmbeddedAPI.h index e2d402d..81b4192 100755 --- a/mDNSCore/mDNSEmbeddedAPI.h +++ b/mDNSCore/mDNSEmbeddedAPI.h @@ -1,25 +1,18 @@ -/* - * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. +/* -*- Mode: C; tab-width: 4 -*- * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * Copyright (c) 2002-2013 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. - * - * @APPLE_LICENSE_HEADER_END@ - NOTE: If you're building an application that uses DNS Service Discovery @@ -39,13 +32,13 @@ This is primarily for devices that need to have precisely known fixed memory requirements, with absolutely no uncertainty or run-time variation, but that certainty comes at a cost of more difficult programming. - + For applications running on general-purpose desktop operating systems (Mac OS, Linux, Solaris, Windows, etc.) the API you should use is /usr/include/dns_sd.h, which defines the API by which multiple independent client processes communicate their DNS Service Discovery requests to a single "mdnsd" daemon running in the background. - + Even on platforms that don't run multiple independent processes in multiple independent address spaces, you can still use the preferred dns_sd.h APIs by linking in "dnssd_clientshim.c", which implements @@ -56,953 +49,61 @@ you can still use the exact same client C code as you'd use on a general-purpose desktop system. + */ - Change History (most recent first): - -$Log: mDNSEmbeddedAPI.h,v $ -Revision 1.287 2005/10/20 00:10:33 cheshire - Add check to avoid crashing NAT gateways that have buggy DNS relay code - -Revision 1.286 2005/09/24 01:09:40 cheshire -Fix comment typos - -Revision 1.285 2005/09/16 20:57:47 cheshire -Add macro mDNS_TimeNow_NoLock(m) to get properly adjusted time without also acquiring lock - -Revision 1.284 2005/07/29 18:04:22 ksekar - Hostname registration should register IPv6 AAAA record with DNS Update - -Revision 1.283 2005/05/13 20:45:09 ksekar - Rapid wide-area txt record updates don't work - -Revision 1.282 2005/03/16 00:42:32 ksekar - Long-lived queries not working on Windows - -Revision 1.281 2005/02/25 17:47:44 ksekar - SendServiceRegistration fails on wake from sleep - -Revision 1.280 2005/02/25 04:21:00 cheshire - mDNS -F returns the same domain multiple times with different casing - -Revision 1.279 2005/02/17 01:56:14 cheshire -Increase ifname field to 64 bytes - -Revision 1.278 2005/02/09 23:38:51 ksekar - Reregister hostname when DNS server changes but IP address does not - -Revision 1.277 2005/02/09 23:31:12 ksekar - NAT-PMP response callback should return a boolean indicating if the packet matched the request - -Revision 1.276 2005/02/01 19:33:29 ksekar - Keychain format too restrictive - -Revision 1.275 2005/01/27 22:57:55 cheshire -Fix compile errors on gcc4 - -Revision 1.274 2005/01/19 21:01:54 ksekar - uDNS needs to support subtype registration and browsing - -Revision 1.273 2005/01/19 19:15:31 ksekar -Refinement to - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer - -Revision 1.272 2005/01/18 18:10:55 ksekar - Use 10.4 resolver API to get search domains - -Revision 1.271 2005/01/15 00:56:41 ksekar - Unicast services don't disappear when logging -out of VPN - -Revision 1.270 2005/01/14 18:34:22 ksekar - Services registered outside of firewall don't succeed after location change - -Revision 1.269 2005/01/11 22:50:52 ksekar -Fixed constant naming (was using kLLQ_DefLease for update leases) - -Revision 1.268 2004/12/22 22:25:47 ksekar - NATPMP: handle location changes - -Revision 1.267 2004/12/22 00:13:49 ksekar - Change version, port, and polling interval for LLQ - -Revision 1.266 2004/12/18 03:13:45 cheshire - kDNSServiceInterfaceIndexLocalOnly should return all local records - -Revision 1.265 2004/12/17 23:37:45 cheshire - Guard against repeating wireless dissociation/re-association -(and other repetitive configuration changes) - -Revision 1.264 2004/12/17 05:25:46 cheshire - Shorten DNS-SD queries to avoid NAT bugs - -Revision 1.263 2004/12/16 20:40:25 cheshire -Fix compile warnings - -Revision 1.262 2004/12/16 20:13:00 cheshire - Cache memory management improvements - -Revision 1.261 2004/12/14 21:21:20 ksekar - NAT-PMP: Update response format to contain "Seconds Since Boot" - -Revision 1.260 2004/12/12 23:51:42 ksekar - Wide-area registrations should fallback to using DHCP hostname as target - -Revision 1.259 2004/12/11 20:55:29 ksekar - Clean up registration state machines - -Revision 1.258 2004/12/10 20:48:32 cheshire - Need to pick final EDNS numbers for LLQ and GC - -Revision 1.257 2004/12/10 02:09:23 cheshire - Modify default TTLs - -Revision 1.256 2004/12/09 03:15:40 ksekar - use _legacy instead of _default to find "empty string" browse domains - -Revision 1.255 2004/12/07 22:48:37 cheshire -Tidying - -Revision 1.254 2004/12/07 21:26:04 ksekar - DNSServiceRegisterRecord() can crash on deregistration - -Revision 1.253 2004/12/07 20:42:33 cheshire -Add explicit context parameter to mDNS_RemoveRecordFromService() - -Revision 1.252 2004/12/07 03:02:12 ksekar -Fixed comments, grouped unicast-specific routines together - -Revision 1.251 2004/12/06 21:15:22 ksekar - mDNSResponder crashed in CheckServiceRegistrations - -Revision 1.250 2004/12/04 02:12:45 cheshire - mDNSResponder puts LargeCacheRecord on the stack - -Revision 1.249 2004/12/03 05:18:33 ksekar - mDNSResponder needs to return more specific TSIG errors - -Revision 1.248 2004/12/02 20:03:48 ksekar - Still publishes wide-area domains even after switching to a local subnet - -Revision 1.247 2004/12/01 20:57:19 ksekar - Wide Area Service Discovery must be split-DNS aware - -Revision 1.246 2004/11/29 23:26:32 cheshire -Added NonZeroTime() function, which usually returns the value given, with the exception -that if the value given is zero, it returns one instead. For timer values where zero is -used to mean "not set", this can be used to ensure that setting them to the result of an -interval computation (e.g. "now+interval") does not inadvertently result in a zero value. - -Revision 1.245 2004/11/25 01:28:09 cheshire - Need to implement random delay for 'QU' unicast replies (and set cache flush bit too) - -Revision 1.244 2004/11/24 22:00:59 cheshire -Move definition of mDNSAddressIsAllDNSLinkGroup() from mDNSMacOSX.c to mDNSEmbeddedAPI.h - -Revision 1.243 2004/11/23 22:43:53 cheshire -Tidy up code alignment - -Revision 1.242 2004/11/23 03:39:46 cheshire -Let interface name/index mapping capability live directly in JNISupport.c, -instead of having to call through to the daemon via IPC to get this information. - -Revision 1.241 2004/11/22 17:16:19 ksekar - Unicast services don't disappear when you disable all networking - -Revision 1.240 2004/11/19 02:32:43 ksekar -Wide-Area Security: Add LLQ-ID to events - -Revision 1.239 2004/11/15 20:09:23 ksekar - Wide Area support for Add/Remove record - -Revision 1.238 2004/11/12 03:16:48 rpantos -rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName - -Revision 1.237 2004/11/10 20:40:53 ksekar - LLQ mobility fragile on non-primary interface - -Revision 1.236 2004/11/01 20:36:11 ksekar - mDNSResponder should not receive Keychain Notifications - -Revision 1.235 2004/11/01 17:48:14 cheshire -Changed SOA serial number back to signed. RFC 1035 may describe it as "unsigned", but -it's wrong. The SOA serial is a modular counter, as explained in "DNS & BIND", page -137. Since C doesn't have a modular type, we used signed, C's closest approximation. - -Revision 1.234 2004/10/29 21:59:02 ksekar -SOA serial should be a unsigned integer, as per RFC 1035 - -Revision 1.233 2004/10/28 03:24:41 cheshire -Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353 - -Revision 1.232 2004/10/26 06:20:23 cheshire -Add mDNSAddressIsValidNonZero() macro - -Revision 1.231 2004/10/26 06:11:41 cheshire -Add improved logging to aid in diagnosis of mDNSResponder crashed - -Revision 1.230 2004/10/26 03:52:02 cheshire -Update checkin comments - -Revision 1.229 2004/10/25 19:30:52 ksekar - Simplify dynamic host name structures - -Revision 1.228 2004/10/23 01:16:00 cheshire - uDNS operations not always reliable on multi-homed hosts - -Revision 1.227 2004/10/22 20:52:07 ksekar - Create NAT port mappings for Long Lived Queries - -Revision 1.226 2004/10/20 01:50:40 cheshire - Cannot resolve non-local registrations using the mach API -Implemented ForceMCast mode for AuthRecords as well as for Questions - -Revision 1.225 2004/10/19 21:33:17 cheshire - Cannot resolve non-local registrations using the mach API -Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name -doesn't force multicast unless you set this flag to indicate explicitly that this is what you want - -Revision 1.224 2004/10/16 00:16:59 cheshire - Replace IP TTL 255 check with local subnet source address check - -Revision 1.223 2004/10/15 23:00:17 ksekar - Need to update LLQs on location changes - -Revision 1.222 2004/10/12 02:49:20 ksekar - Clean up LLQ sleep/wake, error handling - -Revision 1.221 2004/10/10 06:57:15 cheshire -Change definition of "localdomain" to make code compile a little smaller - -Revision 1.220 2004/10/06 01:44:19 cheshire - Resolving too quickly sometimes returns stale TXT record - -Revision 1.219 2004/10/03 23:18:58 cheshire -Move address comparison macros from DNSCommon.h to mDNSEmbeddedAPI.h - -Revision 1.218 2004/10/03 23:14:12 cheshire -Add "mDNSEthAddr" type and "zeroEthAddr" constant - -Revision 1.217 2004/09/30 00:24:56 ksekar - Dynamically update default registration domains on config change - -Revision 1.216 2004/09/27 23:24:32 cheshire -Fix typo: SOA refresh interval is supposed to be unsigned - -Revision 1.215 2004/09/26 23:20:35 ksekar - Allow default registrations in multiple wide-area domains - -Revision 1.214 2004/09/25 02:41:39 cheshire - Deliver near-pending "remove" events before new "add" events - -Revision 1.213 2004/09/25 02:24:27 cheshire -Removed unused rr->UseCount - -Revision 1.212 2004/09/24 20:57:39 cheshire - Eliminate inappropriate casts that cause misaligned-address errors - -Revision 1.211 2004/09/24 20:33:22 cheshire -Remove unused DNSDigest_MD5 declaration - -Revision 1.210 2004/09/23 20:21:07 cheshire - Refine "immediate answer burst; restarting exponential backoff sequence" logic -Associate a unique sequence number with each received packet, and only increment the count of recent answer -packets if the packet sequence number for this answer record is not one we've already seen and counted. - -Revision 1.209 2004/09/23 20:14:39 cheshire -Rename "question->RecentAnswers" to "question->RecentAnswerPkts" - -Revision 1.208 2004/09/23 00:50:53 cheshire - Don't send a (DE) if a service is unregistered after wake from sleep - -Revision 1.207 2004/09/22 02:34:46 cheshire -Move definitions of default TTL times from mDNS.c to mDNSEmbeddedAPI.h - -Revision 1.206 2004/09/22 00:41:59 cheshire -Move tcp connection status codes into the legal range allocated for mDNS use - -Revision 1.205 2004/09/21 23:40:11 ksekar - mDNSResponder to return errors on NAT traversal failure - -Revision 1.204 2004/09/21 23:29:50 cheshire - DNSServiceResolve should delay sending packets - -Revision 1.203 2004/09/21 20:58:22 cheshire -Add ifname field to NetworkInterfaceInfo_struct - -Revision 1.202 2004/09/17 00:46:34 cheshire -mDNS_TimeNow should take const mDNS parameter - -Revision 1.201 2004/09/17 00:31:51 cheshire -For consistency with ipv6, renamed rdata field 'ip' to 'ipv4' - -Revision 1.200 2004/09/17 00:19:10 cheshire -For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4 - -Revision 1.199 2004/09/16 21:59:16 cheshire -For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr - -Revision 1.198 2004/09/16 21:36:36 cheshire - Fix unsafe use of mDNSPlatformTimeNow() -Changes to add necessary locking calls around unicast DNS operations - -Revision 1.197 2004/09/16 00:24:48 cheshire - Fix unsafe use of mDNSPlatformTimeNow() - -Revision 1.196 2004/09/14 23:42:35 cheshire - Need to seed random number generator from platform-layer data - -Revision 1.195 2004/09/14 23:27:46 cheshire -Fix compile errors - -Revision 1.194 2004/09/10 00:49:57 cheshire - Add error code kDNSServiceErr_Firewall, for future use - -Revision 1.193 2004/09/03 19:23:05 ksekar -: Need retransmission mechanism for wide-area service registrations - -Revision 1.192 2004/09/02 03:48:47 cheshire - Disable targeted unicast query support by default -1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record -2. New field AllowRemoteQuery in AuthRecord structure -3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set -4. mDNS.c only answers remote queries if AllowRemoteQuery is set - -Revision 1.191 2004/08/25 00:37:27 ksekar -: Cleanup DynDNS hostname registration code - -Revision 1.190 2004/08/18 17:35:41 ksekar -: Feature #9586: Need support for Legacy NAT gateways - -Revision 1.189 2004/08/14 03:22:41 cheshire - Dynamic DNS UI <-> mDNSResponder glue -Add GetUserSpecifiedDDNSName() routine -Convert ServiceRegDomain to domainname instead of C string -Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs - -Revision 1.188 2004/08/13 23:46:58 cheshire -"asyncronous" -> "asynchronous" - -Revision 1.187 2004/08/13 23:37:02 cheshire -Now that we do both uDNS and mDNS, global replace "uDNS_info.hostname" with -"uDNS_info.UnicastHostname" for clarity - -Revision 1.186 2004/08/13 23:25:00 cheshire -Now that we do both uDNS and mDNS, global replace "m->hostname" with -"m->MulticastHostname" for clarity - -Revision 1.185 2004/08/12 00:32:36 ksekar -: LLQ Refreshes never terminate if unanswered - -Revision 1.184 2004/08/11 17:09:31 cheshire -Add comment clarifying the applicability of these APIs - -Revision 1.183 2004/08/10 23:19:14 ksekar -: DNS Extension daemon for Wide Area Service Discovery -Moved routines/constants to allow extern access for garbage collection daemon - -Revision 1.182 2004/07/30 17:40:06 ksekar -: TXT Record updates not available for wide-area services - -Revision 1.181 2004/07/29 19:27:15 ksekar -NATPMP Support - minor fixes and cleanup - -Revision 1.180 2004/07/29 02:03:35 ksekar -Delete unused #define and structure field - -Revision 1.179 2004/07/26 22:49:30 ksekar -: Feature #9516: Need support for NATPMP in client - -Revision 1.178 2004/07/13 21:24:24 rpantos -Fix for . - -Revision 1.177 2004/06/05 00:04:26 cheshire -: wide-area domains should be returned in reg. domain enumeration - -Revision 1.176 2004/06/04 08:58:29 ksekar -: Keychain integration for secure dynamic update - -Revision 1.175 2004/06/04 00:15:06 cheshire -Move misplaced brackets - -Revision 1.174 2004/06/03 23:30:16 cheshire -Remove extraneous blank lines and white space - -Revision 1.173 2004/06/03 03:09:58 ksekar -: Garbage Collection for Dynamic Updates - -Revision 1.172 2004/06/01 23:46:50 ksekar -: DynDNS: dynamically look up LLQ/Update ports - -Revision 1.171 2004/05/28 23:42:37 ksekar -: Feature: DNS server->client notification on record changes (#7805) - -Revision 1.170 2004/05/18 23:51:25 cheshire -Tidy up all checkin comments to use consistent "" format for bug numbers - -Revision 1.169 2004/05/13 04:54:20 ksekar -Unified list copy/free code. Added symetric list for - -Revision 1.168 2004/05/12 22:03:09 ksekar -Made GetSearchDomainList a true platform-layer call (declaration moved -from mDNSMacOSX.h to mDNSEmbeddedAPI.h), implemented to return "local" -only on non-OSX platforms. Changed call to return a copy of the list -to avoid shared memory issues. Added a routine to free the list. - -Revision 1.167 2004/04/22 04:07:01 cheshire -Fix from Bob Bradley: Don't try to do inline functions on compilers that don't support it - -Revision 1.166 2004/04/22 03:15:56 cheshire -Fix use of "struct __attribute__((__packed__))" so it only applies on GCC >= 2.9 - -Revision 1.165 2004/04/22 03:05:28 cheshire -kDNSClass_ANY should be kDNSQClass_ANY - -Revision 1.164 2004/04/21 02:55:03 cheshire -Update comments describing 'InterfaceActive' field - -Revision 1.163 2004/04/21 02:49:11 cheshire -To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx' - -Revision 1.162 2004/04/15 00:51:28 bradley -Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers. -Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers. - -Revision 1.161 2004/04/14 23:09:28 ksekar -Support for TSIG signed dynamic updates. - -Revision 1.160 2004/04/09 17:40:26 cheshire -Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field - -Revision 1.159 2004/04/09 16:37:15 cheshire -Suggestion from Bob Bradley: -Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers - -Revision 1.158 2004/04/02 19:38:33 cheshire -Update comment about typical RR TTLs - -Revision 1.157 2004/04/02 19:35:53 cheshire -Add clarifying comments about legal mDNSInterfaceID values - -Revision 1.156 2004/04/02 19:19:48 cheshire -Add code to do optional logging of multi-packet KA list time intervals - -Revision 1.155 2004/03/24 00:29:45 ksekar -Make it safe to call StopQuery in a unicast question callback - -Revision 1.154 2004/03/20 01:05:49 cheshire -Test __LP64__ and __ILP64__ to compile properly on a wider range of 64-bit architectures - -Revision 1.153 2004/03/13 01:57:33 ksekar -: DynDNS: Dynamic update of service records - -Revision 1.152 2004/03/09 02:27:16 cheshire -Remove erroneous underscore in 'packed_struct' (makes no difference now, but might in future) - -Revision 1.151 2004/03/02 03:21:56 cheshire - Properly support "_services._dns-sd._udp" meta-queries - -Revision 1.150 2004/02/21 02:06:24 cheshire -Can't use anonymous unions -- they're non-standard and don't work on all compilers - -Revision 1.149 2004/02/06 23:04:19 ksekar -Basic Dynamic Update support via mDNS_Register (dissabled via -UNICAST_REGISTRATION #define) - -Revision 1.148 2004/02/03 19:47:36 ksekar -Added an asynchronous state machine mechanism to uDNS.c, including -calls to find the parent zone for a domain name. Changes include code -in repository previously dissabled via "#if 0 incomplete". Codepath -is currently unused, and will be called to create update records, etc. - -Revision 1.147 2004/02/03 18:57:35 cheshire -Update comment for "IsLocalDomain()" - -Revision 1.146 2004/01/30 02:20:24 bradley -Map inline to __inline when building with Microsoft C compilers since they do not support C99 inline. - -Revision 1.145 2004/01/29 02:59:17 ksekar -Unicast DNS: Changed from a resource record oriented question/response -matching to packet based matching. New callback architecture allows -collections of records in a response to be processed differently -depending on the nature of the request, and allows the same structure -to be used for internal and client-driven queries with different processing needs. - -Revision 1.144 2004/01/28 20:20:45 ksekar -Unified ActiveQueries and ActiveInternalQueries lists, using a flag to -demux them. Check-in includes work-in-progress code, #ifdef'd out. - -Revision 1.143 2004/01/28 03:41:00 cheshire -: Need ability to do targeted queries as well as multicast queries - -Revision 1.142 2004/01/28 02:30:07 ksekar -Added default Search Domains to unicast browsing, controlled via -Networking sharing prefs pane. Stopped sending unicast messages on -every interface. Fixed unicast resolving via mach-port API. - -Revision 1.141 2004/01/27 20:15:22 cheshire -: Time to prune obsolete code for listening on port 53 - -Revision 1.140 2004/01/24 23:37:08 cheshire -At Kiren's suggestion, made functions to convert mDNSOpaque16s to/from integer values - -Revision 1.139 2004/01/24 08:46:26 bradley -Added InterfaceID<->Index platform interfaces since they are now used by all platforms for the DNS-SD APIs. - -Revision 1.138 2004/01/24 04:59:15 cheshire -Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again - -Revision 1.137 2004/01/24 03:40:56 cheshire -Move mDNSAddrIsDNSMulticast() from DNSCommon.h to mDNSEmbeddedAPI.h so clients can use it - -Revision 1.136 2004/01/24 03:38:27 cheshire -Fix minor syntactic error: Headers should use "extern" declarations, not "mDNSexport" - -Revision 1.135 2004/01/23 23:23:15 ksekar -Added TCP support for truncated unicast messages. - -Revision 1.134 2004/01/22 03:54:11 cheshire -Create special meta-interface 'mDNSInterface_ForceMCast' (-2), -which means "do this query via multicast, even if it's apparently a unicast domain" - -Revision 1.133 2004/01/22 03:48:41 cheshire -Make sure uDNS client doesn't accidentally use query ID zero - -Revision 1.132 2004/01/22 03:43:08 cheshire -Export constants like mDNSInterface_LocalOnly so that the client layers can use them - -Revision 1.131 2004/01/21 21:53:18 cheshire -: Don't try to receive unicast responses if we're not the first to bind to the UDP port - -Revision 1.130 2003/12/14 05:05:29 cheshire -Add comments explaining mDNS_Init_NoCache and mDNS_Init_ZeroCacheSize - -Revision 1.129 2003/12/13 03:05:27 ksekar -: DynDNS: Unicast query of service records - -Revision 1.128 2003/12/01 21:44:23 cheshire -Add mStatus_BadInterfaceErr = -65552 for consistency with dns_sd.h - -Revision 1.127 2003/12/01 18:26:37 cheshire -Also pack the OpaqueXX union types. Otherwise, on some systems, mDNSOpaque16 is four bytes! - -Revision 1.126 2003/12/01 18:23:48 cheshire -: Scalar size problem in mDNS code on some 64-bit architectures - -Revision 1.125 2003/11/22 00:18:27 cheshire -Add compile-time asserts to verify correct sizes of mDNSu32, mDNSOpaque16, etc. - -Revision 1.124 2003/11/20 22:59:54 cheshire -Changed runtime checks in mDNS.c to be compile-time checks in mDNSEmbeddedAPI.h -Thanks to Bob Bradley for suggesting the ingenious compiler trick to make this work. - -Revision 1.123 2003/11/20 22:53:01 cheshire -Add comment about MAX_ESCAPED_DOMAIN_LABEL - -Revision 1.122 2003/11/20 20:49:53 cheshire -Another fix from HP: Use packedstruct macro to ensure proper packing for on-the-wire packet structures - -Revision 1.121 2003/11/20 05:01:38 cheshire -Update comments; add explanation of Advertise/DontAdvertiseLocalAddresses - -Revision 1.120 2003/11/14 20:59:08 cheshire -Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h. -Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file. - -Revision 1.119 2003/11/14 19:47:52 cheshire -Define symbol MAX_ESCAPED_DOMAIN_NAME to indicate recommended buffer size for ConvertDomainNameToCString - -Revision 1.118 2003/11/14 19:18:34 cheshire -Move AssignDomainName macro to mDNSEmbeddedAPI.h to that client layers can use it too - -Revision 1.117 2003/11/08 23:32:24 cheshire -Gave name to anonymous struct, to avoid errors on certain compilers. -(Thanks to ramaprasad.kr@hp.com for reporting this.) - -Revision 1.116 2003/11/07 03:32:56 cheshire - mDNSResponder delivers answers in inconsistent order -This is the real fix. Checkin 1.312 was overly simplistic; Calling GetFreeCacheRR() can sometimes -purge records from the cache, causing tail pointer *rp to be stale on return. The correct fix is -to maintain a system-wide tail pointer for each cache slot, and then if neccesary GetFreeCacheRR() -can update this pointer, so that mDNSCoreReceiveResponse() appends records in the right place. - -Revision 1.115 2003/09/23 00:53:54 cheshire -NumFailedProbes should be unsigned - -Revision 1.114 2003/08/29 19:44:15 cheshire - Traffic reduction: Eliminate synchronized QUs when a new service appears -1. Use m->RandomQueryDelay to impose a random delay in the range 0-500ms on queries - that already have at least one unique answer in the cache -2. For these queries, go straight to QM, skipping QU - -Revision 1.113 2003/08/21 19:31:58 cheshire -Cosmetic: Swap order of fields - -Revision 1.112 2003/08/21 19:27:36 cheshire - Traffic reduction: No need to announce record for longer than TTL - -Revision 1.111 2003/08/21 02:21:50 cheshire - Efficiency: Reduce repeated queries - -Revision 1.110 2003/08/20 23:39:31 cheshire - Review syslog messages, and remove as appropriate - -Revision 1.109 2003/08/19 22:24:10 cheshire -Comment change - -Revision 1.108 2003/08/19 22:20:00 cheshire - Don't use IPv6 on interfaces that have a routable IPv4 address configured -More minor refinements - -Revision 1.107 2003/08/19 06:48:25 cheshire - Guard against excessive record updates -Each record starts with 10 UpdateCredits. -Every update consumes one UpdateCredit. -UpdateCredits are replenished at a rate of one one per minute, up to a maximum of 10. -As the number of UpdateCredits declines, the number of announcements is similarly scaled back. -When fewer than 5 UpdateCredits remain, the first announcement is also delayed by an increasing amount. - -Revision 1.106 2003/08/19 04:49:28 cheshire - Interaction between v4, v6 and dual-stack hosts not working quite right -1. A dual-stack host should only suppress its own query if it sees the same query from other hosts on BOTH IPv4 and IPv6. -2. When we see the first v4 (or first v6) member of a group, we re-trigger questions and probes on that interface. -3. When we see the last v4 (or v6) member of a group go away, we revalidate all the records received on that interface. - -Revision 1.105 2003/08/19 02:33:37 cheshire -Update comments - -Revision 1.104 2003/08/19 02:31:11 cheshire - mDNSResponder overenthusiastic with final expiration queries -Final expiration queries now only mark the question for sending on the particular interface -pertaining to the record that's expiring. - -Revision 1.103 2003/08/18 19:05:44 cheshire - UpdateRecord not working right -Added "newrdlength" field to hold new length of updated rdata - -Revision 1.102 2003/08/16 03:39:00 cheshire - InterfaceID -1 indicates "local only" - -Revision 1.101 2003/08/15 20:16:02 cheshire - mDNSResponder takes too much RPRVT -We want to avoid touching the rdata pages, so we don't page them in. -1. RDLength was stored with the rdata, which meant touching the page just to find the length. - Moved this from the RData to the ResourceRecord object. -2. To avoid unnecessarily touching the rdata just to compare it, - compute a hash of the rdata and store the hash in the ResourceRecord object. - -Revision 1.100 2003/08/14 19:29:04 cheshire - Include cache records in SIGINFO output -Moved declarations of DNSTypeName() and GetRRDisplayString to mDNSEmbeddedAPI.h so daemon.c can use them - -Revision 1.99 2003/08/14 02:17:05 cheshire - Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord - -Revision 1.98 2003/08/12 19:56:23 cheshire -Update to APSL 2.0 - -Revision 1.97 2003/08/12 14:59:27 cheshire - Rate-limiting blocks some legitimate responses -When setting LastMCTime also record LastMCInterface. When checking LastMCTime to determine -whether to suppress the response, also check LastMCInterface to see if it matches. - -Revision 1.96 2003/08/12 13:57:04 cheshire - Improve cache performance -Changed the number of hash table slots from 37 to 499 - -Revision 1.95 2003/08/09 00:55:02 cheshire - mDNSResponder is taking 20-30% of the CPU -Don't scan the whole cache after every packet. - -Revision 1.94 2003/08/09 00:35:29 cheshire - -Revision 1.93 2003/08/08 18:55:48 cheshire - Guard against time going backwards - -Revision 1.92 2003/08/08 18:36:04 cheshire - Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug - -Revision 1.91 2003/08/06 21:33:39 cheshire -Fix compiler warnings on PocketPC 2003 (Windows CE) - -Revision 1.90 2003/08/06 20:30:17 cheshire -Add structure definition for rdataMX (not currently used, but good to have it for completeness) - -Revision 1.89 2003/08/06 18:58:19 cheshire -Update comments - -Revision 1.88 2003/07/24 23:45:44 cheshire -To eliminate compiler warnings, changed definition of mDNSBool from -"unsigned char" to "int", since "int" is in fact truly the type that C uses -for the result of comparison operators (a: Feature: New DNS-SD APIs (#7875) (mDNSResponder component) -Added error type for incompatibility between daemon and client versions - -Revision 1.85 2003/07/19 03:23:13 cheshire - mDNSResponder needs to receive and cache larger records - -Revision 1.84 2003/07/18 23:52:12 cheshire -To improve consistency of field naming, global search-and-replace: -NextProbeTime -> NextScheduledProbe -NextResponseTime -> NextScheduledResponse - -Revision 1.83 2003/07/18 00:29:59 cheshire - Remove mDNSResponder version from packet header and use HINFO record instead - -Revision 1.82 2003/07/17 17:35:04 cheshire - Rate-limit responses, to guard against packet flooding - -Revision 1.81 2003/07/16 05:01:36 cheshire -Add fields 'LargeAnswers' and 'ExpectUnicastResponse' in preparation for - Need to implement "unicast response" request, using top bit of qclass - -Revision 1.80 2003/07/15 01:55:12 cheshire - Need to implement service registration with subtypes - -Revision 1.79 2003/07/13 02:28:00 cheshire - SendResponses didn't all its responses -Delete all references to RRInterfaceActive -- it's now superfluous - -Revision 1.78 2003/07/13 01:47:53 cheshire -Fix one error and one warning in the Windows build - -Revision 1.77 2003/07/11 01:32:38 cheshire -Syntactic cleanup (no change to funcationality): Now that we only have one host name, -rename field "hostname1" to "hostname", and field "RR_A1" to "RR_A". +#ifndef __mDNSEmbeddedAPI_h +#define __mDNSEmbeddedAPI_h -Revision 1.76 2003/07/11 01:28:00 cheshire - No more local.arpa - -Revision 1.75 2003/07/02 21:19:45 cheshire - Update copyright notices, etc., in source code comments - -Revision 1.74 2003/07/02 02:41:23 cheshire - mDNSResponder needs to start with a smaller cache and then grow it as needed - -Revision 1.73 2003/06/10 04:24:39 cheshire - React when we observe other people query unsuccessfully for a record that's in our cache -Some additional refinements: -Don't try to do this for unicast-response queries -better tracking of Qs and KAs in multi-packet KA lists - -Revision 1.72 2003/06/10 01:46:27 cheshire -Add better comments explaining how these data structures are intended to be used from the client layer - -Revision 1.71 2003/06/07 06:45:05 cheshire - No need for multiple machines to all be sending the same queries - -Revision 1.70 2003/06/07 04:50:53 cheshire - React when we observe other people query unsuccessfully for a record that's in our cache - -Revision 1.69 2003/06/07 04:22:17 cheshire -Add MsgBuffer for error log and debug messages - -Revision 1.68 2003/06/07 01:46:38 cheshire - When query produces zero results, call mDNS_Reconfirm() on any antecedent records - -Revision 1.67 2003/06/07 01:22:14 cheshire - mDNSResponder needs an mDNS_Reconfirm() function - -Revision 1.66 2003/06/07 00:59:43 cheshire - Need some randomness to spread queries on the network - -Revision 1.65 2003/06/06 21:41:11 cheshire -For consistency, mDNS_StopQuery() should return an mStatus result, just like all the other mDNSCore routines - -Revision 1.64 2003/06/06 21:38:55 cheshire -Renamed 'NewData' as 'FreshData' (The data may not be new data, just a refresh of data that we -already had in our cache. This refreshes our TTL on the data, but the data itself stays the same.) - -Revision 1.63 2003/06/06 17:20:14 cheshire -For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass -(Global search-and-replace; no functional change to code execution.) - -Revision 1.62 2003/06/04 01:25:33 cheshire - Cannot perform multi-packet known-answer suppression messages -Display time interval between first and subsequent queries - -Revision 1.61 2003/06/03 05:02:16 cheshire - Duplicate registrations not handled as efficiently as they should be - -Revision 1.60 2003/05/31 00:09:49 cheshire - Add ability to discover what services are on a network - -Revision 1.59 2003/05/29 06:11:35 cheshire -: Report if there appear to be too many "Resolve" callbacks - -Revision 1.58 2003/05/29 05:48:06 cheshire -Minor fix for when generating printf warnings: mDNS_snprintf arguments are now 3,4 - -Revision 1.57 2003/05/26 03:21:27 cheshire -Tidy up address structure naming: -mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr) -mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4 -mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6 - -Revision 1.56 2003/05/26 03:01:27 cheshire - sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead - -Revision 1.55 2003/05/26 00:47:30 cheshire -Comment clarification - -Revision 1.54 2003/05/24 16:39:48 cheshire - SendResponses also needs to handle multihoming better - -Revision 1.53 2003/05/23 02:15:37 cheshire -Fixed misleading use of the term "duplicate suppression" where it should have -said "known answer suppression". (Duplicate answer suppression is something -different, and duplicate question suppression is yet another thing, so the use -of the completely vague term "duplicate suppression" was particularly bad.) - -Revision 1.52 2003/05/22 02:29:22 cheshire - SendQueries needs to handle multihoming better -Complete rewrite of SendQueries. Works much better now :-) - -Revision 1.51 2003/05/21 20:14:55 cheshire -Fix comments and warnings - -Revision 1.50 2003/05/14 07:08:36 cheshire - mDNSResponder should be smarter about reconfigurations -Previously, when there was any network configuration change, mDNSResponder -would tear down the entire list of active interfaces and start again. -That was very disruptive, and caused the entire cache to be flushed, -and caused lots of extra network traffic. Now it only removes interfaces -that have really gone, and only adds new ones that weren't there before. - -Revision 1.49 2003/05/07 01:49:36 cheshire -Remove "const" in ConstructServiceName prototype - -Revision 1.48 2003/05/07 00:18:44 cheshire -Fix typo: "kDNSQClass_Mask" should be "kDNSClass_Mask" - -Revision 1.47 2003/05/06 00:00:46 cheshire - Rationalize naming of domainname manipulation functions - -Revision 1.46 2003/04/30 20:39:09 cheshire -Add comment - -Revision 1.45 2003/04/29 00:40:50 cheshire -Fix compiler warnings - -Revision 1.44 2003/04/26 02:41:56 cheshire - Change timenow from a local variable to a structure member - -Revision 1.43 2003/04/25 01:45:56 cheshire - mDNS_RegisterNoSuchService needs to include a host name - -Revision 1.42 2003/04/15 20:58:31 jgraessl - - Added a hash to lookup records in the cache. - -Revision 1.41 2003/04/15 18:09:13 jgraessl - - -Reviewed by: Stuart Cheshire -Added code to keep track of when the next cache item will expire so we can -call TidyRRCache only when necessary. - -Revision 1.40 2003/03/29 01:55:19 cheshire - mDNSResponder sometimes suffers false self-conflicts when it sees its own packets -Solution: Major cleanup of packet timing and conflict handling rules - -Revision 1.39 2003/03/27 03:30:55 cheshire - Name conflicts not handled properly, resulting in memory corruption, and eventual crash -Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback -Fixes: -1. Make mDNS_DeregisterInterface() safe to call from a callback -2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead - (it never really needed to deregister the interface at all) - -Revision 1.38 2003/03/15 04:40:36 cheshire -Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID" - -Revision 1.37 2003/03/14 21:34:11 cheshire - Can't setup and print to Lexmark PS printers via Airport Extreme -Increase size of cache rdata from 512 to 768 - -Revision 1.36 2003/03/05 03:38:35 cheshire - Bogus error message in console: died or deallocated, but no record of client can be found! -Fixed by leaving client in list after conflict, until client explicitly deallocates - -Revision 1.35 2003/02/21 02:47:54 cheshire - mDNSResponder needs performance improvements -Several places in the code were calling CacheRRActive(), which searched the entire -question list every time, to see if this cache resource record answers any question. -Instead, we now have a field "CRActiveQuestion" in the resource record structure - -Revision 1.34 2003/02/21 01:54:08 cheshire - mDNSResponder needs performance improvements -Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt") - -Revision 1.33 2003/02/20 06:48:32 cheshire - Xserve RAID needs to do interface-specific registrations -Reviewed by: Josh Graessley, Bob Bradley - -Revision 1.32 2003/01/31 03:35:59 cheshire - mDNSResponder sometimes fails to find the correct results -When there were *two* active questions in the list, they were incorrectly -finding *each other* and *both* being marked as duplicates of another question - -Revision 1.31 2003/01/29 02:46:37 cheshire -Fix for IPv6: -A physical interface is identified solely by its InterfaceID (not by IP and type). -On a given InterfaceID, mDNSCore may send both v4 and v6 multicasts. -In cases where the requested outbound protocol (v4 or v6) is not supported on -that InterfaceID, the platform support layer should simply discard that packet. - -Revision 1.30 2003/01/29 01:47:08 cheshire -Rename 'Active' to 'CRActive' or 'InterfaceActive' for improved clarity - -Revision 1.29 2003/01/28 05:23:43 cheshire - mDNSResponder sometimes fails to find the correct results -Add 'Active' flag for interfaces - -Revision 1.28 2003/01/28 01:35:56 cheshire -Revise comment about ThisQInterval to reflect new semantics - -Revision 1.27 2003/01/13 23:49:42 jgraessl -Merged changes for the following fixes in to top of tree: - computer name changes not handled properly - service name changes are not properly handled - announcements sent in pairs, failing chattiness test - -Revision 1.26 2002/12/23 22:13:28 jgraessl - -Reviewed by: Stuart Cheshire -Initial IPv6 support for mDNSResponder. - -Revision 1.25 2002/09/21 20:44:49 zarzycki -Added APSL info +#if defined(EFI32) || defined(EFI64) || defined(EFIX64) +// EFI doesn't have stdarg.h unless it's building with GCC. +#include "Tiano.h" +#if !defined(__GNUC__) +#define va_list VA_LIST +#define va_start(a, b) VA_START(a, b) +#define va_end(a) VA_END(a) +#define va_arg(a, b) VA_ARG(a, b) +#endif +#else +#include // stdarg.h is required for for va_list support for the mDNS_vsnprintf declaration +#endif -Revision 1.24 2002/09/19 23:47:35 cheshire -Added mDNS_RegisterNoSuchService() function for assertion of non-existence -of a particular named service +#include "mDNSDebug.h" +#if APPLE_OSX_mDNSResponder +#include +#endif -Revision 1.23 2002/09/19 21:25:34 cheshire -mDNS_snprintf() doesn't need to be in a separate file +#ifdef __cplusplus +extern "C" { +#endif -Revision 1.22 2002/09/19 04:20:43 cheshire -Remove high-ascii characters that confuse some systems +// *************************************************************************** +// Feature removal compile options & limited resource targets -Revision 1.21 2002/09/17 01:06:35 cheshire -Change mDNS_AdvertiseLocalAddresses to be a parameter to mDNS_Init() +// The following compile options are responsible for removing certain features from mDNSCore to reduce the +// memory footprint for use in embedded systems with limited resources. -Revision 1.20 2002/09/16 18:41:41 cheshire -Merge in license terms from Quinn's copy, in preparation for Darwin release +// UNICAST_DISABLED - disables unicast DNS functionality, including Wide Area Bonjour +// ANONYMOUS_DISABLED - disables anonymous functionality +// DNSSEC_DISABLED - disables DNSSEC functionality +// SPC_DISABLED - disables Bonjour Sleep Proxy client +// IDLESLEEPCONTROL_DISABLED - disables sleep control for Bonjour Sleep Proxy clients -*/ +// In order to disable the above features pass the option to your compiler, e.g. -D UNICAST_DISABLED -#ifndef __mDNSClientAPI_h -#define __mDNSClientAPI_h +// Additionally, the LIMITED_RESOURCES_TARGET compile option will eliminate caching and +// and reduce the maximum DNS message sizes. -#include // stdarg.h is required for for va_list support for the mDNS_vsnprintf declaration -#include "mDNSDebug.h" +#ifdef LIMITED_RESOURCES_TARGET +// Don't support jumbo frames +#define AbsoluteMaxDNSMessageData 1500 +// By the time you add IPv6 header (40 bytes) UDP header (8 bytes) and DNS message header (12 bytes) +// this makes 1560 which is 60 bytes over the standard Ethernet MTU. D'oh! -#ifdef __cplusplus - extern "C" { +// StandardAuthRDSize is 264 (256+8), which is large enough to hold a maximum-sized SRV record (6 + 256 bytes) +#define MaximumRDSize 264 +// Don't cache anything +#define AUTH_HASH_SLOTS 1 +#define CACHE_HASH_SLOTS 1 #endif // *************************************************************************** @@ -1020,6 +121,19 @@ Merge in license terms from Quinn's copy, in preparation for Darwin release #define mDNSexport #endif +// Explanation: These local/export markers are a little habit of mine for signaling the programmers' intentions. +// When "mDNSlocal" is just a synonym for "static", and "mDNSexport" is a complete no-op, you could be +// forgiven for asking what purpose they serve. The idea is that if you see "mDNSexport" in front of a +// function definition it means the programmer intended it to be exported and callable from other files +// in the project. If you see "mDNSlocal" in front of a function definition it means the programmer +// intended it to be private to that file. If you see neither in front of a function definition it +// means the programmer forgot (so you should work out which it is supposed to be, and fix it). +// Using "mDNSlocal" instead of "static" makes it easier to do a textual searches for one or the other. +// For example you can do a search for "static" to find if any functions declare any local variables as "static" +// (generally a bad idea unless it's also "const", because static storage usually risks being non-thread-safe) +// without the results being cluttered with hundreds of matches for functions declared static. +// - Stuart Cheshire + // *************************************************************************** // Structure packing macro @@ -1042,78 +156,115 @@ Merge in license terms from Quinn's copy, in preparation for Darwin release #pragma mark - DNS Resource Record class and type constants #endif -typedef enum // From RFC 1035 - { - kDNSClass_IN = 1, // Internet - kDNSClass_CS = 2, // CSNET - kDNSClass_CH = 3, // CHAOS - kDNSClass_HS = 4, // Hesiod - kDNSClass_NONE = 254, // Used in DNS UPDATE [RFC 2136] - - kDNSClass_Mask = 0x7FFF,// Multicast DNS uses the bottom 15 bits to identify the record class... - kDNSClass_UniqueRRSet = 0x8000,// ... and the top bit indicates that all other cached records are now invalid - - kDNSQClass_ANY = 255, // Not a DNS class, but a DNS query class, meaning "all classes" - kDNSQClass_UnicastResponse = 0x8000 // Top bit set in a question means "unicast response acceptable" - } DNS_ClassValues; - -typedef enum // From RFC 1035 - { - kDNSType_A = 1, // 1 Address - kDNSType_NS, // 2 Name Server - kDNSType_MD, // 3 Mail Destination - kDNSType_MF, // 4 Mail Forwarder - kDNSType_CNAME, // 5 Canonical Name - kDNSType_SOA, // 6 Start of Authority - kDNSType_MB, // 7 Mailbox - kDNSType_MG, // 8 Mail Group - kDNSType_MR, // 9 Mail Rename - kDNSType_NULL, // 10 NULL RR - kDNSType_WKS, // 11 Well-known-service - kDNSType_PTR, // 12 Domain name pointer - kDNSType_HINFO, // 13 Host information - kDNSType_MINFO, // 14 Mailbox information - kDNSType_MX, // 15 Mail Exchanger - kDNSType_TXT, // 16 Arbitrary text string - - kDNSType_AAAA = 28, // 28 IPv6 address - kDNSType_SRV = 33, // 33 Service record - kDNSType_OPT = 41, // EDNS0 OPT record - kDNSType_TSIG = 250, // 250 Transaction Signature - - kDNSQType_ANY = 255 // Not a DNS type, but a DNS query type, meaning "all types" - } DNS_TypeValues; +typedef enum // From RFC 1035 +{ + kDNSClass_IN = 1, // Internet + kDNSClass_CS = 2, // CSNET + kDNSClass_CH = 3, // CHAOS + kDNSClass_HS = 4, // Hesiod + kDNSClass_NONE = 254, // Used in DNS UPDATE [RFC 2136] + + kDNSClass_Mask = 0x7FFF, // Multicast DNS uses the bottom 15 bits to identify the record class... + kDNSClass_UniqueRRSet = 0x8000, // ... and the top bit indicates that all other cached records are now invalid + + kDNSQClass_ANY = 255, // Not a DNS class, but a DNS query class, meaning "all classes" + kDNSQClass_UnicastResponse = 0x8000 // Top bit set in a question means "unicast response acceptable" +} DNS_ClassValues; + +typedef enum // From RFC 1035 +{ + kDNSType_A = 1, // 1 Address + kDNSType_NS, // 2 Name Server + kDNSType_MD, // 3 Mail Destination + kDNSType_MF, // 4 Mail Forwarder + kDNSType_CNAME, // 5 Canonical Name + kDNSType_SOA, // 6 Start of Authority + kDNSType_MB, // 7 Mailbox + kDNSType_MG, // 8 Mail Group + kDNSType_MR, // 9 Mail Rename + kDNSType_NULL, // 10 NULL RR + kDNSType_WKS, // 11 Well-known-service + kDNSType_PTR, // 12 Domain name pointer + kDNSType_HINFO, // 13 Host information + kDNSType_MINFO, // 14 Mailbox information + kDNSType_MX, // 15 Mail Exchanger + kDNSType_TXT, // 16 Arbitrary text string + kDNSType_RP, // 17 Responsible person + kDNSType_AFSDB, // 18 AFS cell database + kDNSType_X25, // 19 X_25 calling address + kDNSType_ISDN, // 20 ISDN calling address + kDNSType_RT, // 21 Router + kDNSType_NSAP, // 22 NSAP address + kDNSType_NSAP_PTR, // 23 Reverse NSAP lookup (deprecated) + kDNSType_SIG, // 24 Security signature + kDNSType_KEY, // 25 Security key + kDNSType_PX, // 26 X.400 mail mapping + kDNSType_GPOS, // 27 Geographical position (withdrawn) + kDNSType_AAAA, // 28 IPv6 Address + kDNSType_LOC, // 29 Location Information + kDNSType_NXT, // 30 Next domain (security) + kDNSType_EID, // 31 Endpoint identifier + kDNSType_NIMLOC, // 32 Nimrod Locator + kDNSType_SRV, // 33 Service record + kDNSType_ATMA, // 34 ATM Address + kDNSType_NAPTR, // 35 Naming Authority PoinTeR + kDNSType_KX, // 36 Key Exchange + kDNSType_CERT, // 37 Certification record + kDNSType_A6, // 38 IPv6 Address (deprecated) + kDNSType_DNAME, // 39 Non-terminal DNAME (for IPv6) + kDNSType_SINK, // 40 Kitchen sink (experimental) + kDNSType_OPT, // 41 EDNS0 option (meta-RR) + kDNSType_APL, // 42 Address Prefix List + kDNSType_DS, // 43 Delegation Signer + kDNSType_SSHFP, // 44 SSH Key Fingerprint + kDNSType_IPSECKEY, // 45 IPSECKEY + kDNSType_RRSIG, // 46 RRSIG + kDNSType_NSEC, // 47 Denial of Existence + kDNSType_DNSKEY, // 48 DNSKEY + kDNSType_DHCID, // 49 DHCP Client Identifier + kDNSType_NSEC3, // 50 Hashed Authenticated Denial of Existence + kDNSType_NSEC3PARAM, // 51 Hashed Authenticated Denial of Existence + + kDNSType_HIP = 55, // 55 Host Identity Protocol + + kDNSType_SPF = 99, // 99 Sender Policy Framework for E-Mail + kDNSType_UINFO, // 100 IANA-Reserved + kDNSType_UID, // 101 IANA-Reserved + kDNSType_GID, // 102 IANA-Reserved + kDNSType_UNSPEC, // 103 IANA-Reserved + + kDNSType_TKEY = 249, // 249 Transaction key + kDNSType_TSIG, // 250 Transaction signature + kDNSType_IXFR, // 251 Incremental zone transfer + kDNSType_AXFR, // 252 Transfer zone of authority + kDNSType_MAILB, // 253 Transfer mailbox records + kDNSType_MAILA, // 254 Transfer mail agent records + kDNSQType_ANY // Not a DNS type, but a DNS query type, meaning "all types" +} DNS_TypeValues; // *************************************************************************** #if 0 +#pragma mark - #pragma mark - Simple types #endif // mDNS defines its own names for these common types to simplify portability across // multiple platforms that may each have their own (different) names for these types. -typedef int mDNSBool; -typedef signed char mDNSs8; -typedef unsigned char mDNSu8; +typedef unsigned char mDNSBool; +typedef signed char mDNSs8; +typedef unsigned char mDNSu8; typedef signed short mDNSs16; typedef unsigned short mDNSu16; -// says -// __LP64__ _LP64 -// These macros are defined, with value 1, if (and only if) the compilation is -// for a target where long int and pointer both use 64-bits and int uses 32-bit. -// says -// Macro Name __LP64__ Value 1 -// A quick Google search for "defined(__LP64__)" OR "#ifdef __LP64__" gives 2590 hits and -// a search for "#if __LP64__" gives only 12, so I think we'll go with the majority and use defined() -#if defined(_LP64) || defined(__LP64__) -typedef signed int mDNSs32; -typedef unsigned int mDNSu32; -#elif defined(_ILP64) || defined(__ILP64__) +// Source: http://www.unix.org/version2/whatsnew/lp64_wp.html +// http://software.intel.com/sites/products/documentation/hpc/mkl/lin/MKL_UG_structure/Support_for_ILP64_Programming.htm +// It can be safely assumed that int is 32bits on the platform +#if defined(_ILP64) || defined(__ILP64__) typedef signed int32 mDNSs32; typedef unsigned int32 mDNSu32; #else -typedef signed long mDNSs32; -typedef unsigned long mDNSu32; +typedef signed int mDNSs32; +typedef unsigned int mDNSu32; #endif // To enforce useful type checking, we make mDNSInterfaceID be a pointer to a dummy struct @@ -1128,128 +279,206 @@ typedef struct mDNSInterfaceID_dummystruct { void *dummy; } *mDNSInterfaceID; // less than, add, multiply, increment, decrement, etc., are undefined for opaque identifiers, // and if you make the mistake of trying to do those using the NotAnInteger field, then you'll // find you get code that doesn't work consistently on big-endian and little-endian machines. -typedef packedunion { mDNSu8 b[ 2]; mDNSu16 NotAnInteger; } mDNSOpaque16; -typedef packedunion { mDNSu8 b[ 4]; mDNSu32 NotAnInteger; } mDNSOpaque32; +#if defined(_WIN32) + #pragma pack(push,2) +#endif +typedef union { mDNSu8 b[ 2]; mDNSu16 NotAnInteger; } mDNSOpaque16; +typedef union { mDNSu8 b[ 4]; mDNSu32 NotAnInteger; } mDNSOpaque32; typedef packedunion { mDNSu8 b[ 6]; mDNSu16 w[3]; mDNSu32 l[1]; } mDNSOpaque48; -typedef packedunion { mDNSu8 b[16]; mDNSu16 w[8]; mDNSu32 l[4]; } mDNSOpaque128; +typedef union { mDNSu8 b[ 8]; mDNSu16 w[4]; mDNSu32 l[2]; } mDNSOpaque64; +typedef union { mDNSu8 b[16]; mDNSu16 w[8]; mDNSu32 l[4]; } mDNSOpaque128; +#if defined(_WIN32) + #pragma pack(pop) +#endif + +typedef mDNSOpaque16 mDNSIPPort; // An IP port is a two-byte opaque identifier (not an integer) +typedef mDNSOpaque32 mDNSv4Addr; // An IP address is a four-byte opaque identifier (not an integer) +typedef mDNSOpaque128 mDNSv6Addr; // An IPv6 address is a 16-byte opaque identifier (not an integer) +typedef mDNSOpaque48 mDNSEthAddr; // An Ethernet address is a six-byte opaque identifier (not an integer) -typedef mDNSOpaque16 mDNSIPPort; // An IP port is a two-byte opaque identifier (not an integer) -typedef mDNSOpaque32 mDNSv4Addr; // An IP address is a four-byte opaque identifier (not an integer) -typedef mDNSOpaque128 mDNSv6Addr; // An IPv6 address is a 16-byte opaque identifier (not an integer) -typedef mDNSOpaque48 mDNSEthAddr; // An Ethernet address is a six-byte opaque identifier (not an integer) +// Bit operations for opaque 64 bit quantity. Uses the 32 bit quantity(l[2]) to set and clear bits +#define mDNSNBBY 8 +#define bit_set_opaque64(op64, index) (op64.l[((index))/(sizeof(mDNSu32) * mDNSNBBY)] |= (1 << ((index) % (sizeof(mDNSu32) * mDNSNBBY)))) +#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 - { - mDNSAddrType_None = 0, - mDNSAddrType_IPv4 = 4, - mDNSAddrType_IPv6 = 6, - mDNSAddrType_Unknown = ~0 // Special marker value used in known answer list recording - }; +{ + mDNSAddrType_None = 0, + mDNSAddrType_IPv4 = 4, + mDNSAddrType_IPv6 = 6, + mDNSAddrType_Unknown = ~0 // Special marker value used in known answer list recording +}; + +enum +{ + mDNSTransport_None = 0, + mDNSTransport_UDP = 1, + mDNSTransport_TCP = 2 +}; typedef struct - { - mDNSs32 type; - union { mDNSv6Addr v6; mDNSv4Addr v4; } ip; - } mDNSAddr; +{ + mDNSs32 type; + union { mDNSv6Addr v6; mDNSv4Addr v4; } ip; +} mDNSAddr; enum { mDNSfalse = 0, mDNStrue = 1 }; #define mDNSNULL 0L enum - { - mStatus_Waiting = 1, - mStatus_NoError = 0, - - // mDNS return values are in the range FFFE FF00 (-65792) to FFFE FFFF (-65537) - // The top end of the range (FFFE FFFF) is used for error codes; - // the bottom end of the range (FFFE FF00) is used for non-error values; - - // Error codes: - mStatus_UnknownErr = -65537, // First value: 0xFFFE FFFF - mStatus_NoSuchNameErr = -65538, - mStatus_NoMemoryErr = -65539, - mStatus_BadParamErr = -65540, - mStatus_BadReferenceErr = -65541, - mStatus_BadStateErr = -65542, - mStatus_BadFlagsErr = -65543, - mStatus_UnsupportedErr = -65544, - mStatus_NotInitializedErr = -65545, - mStatus_NoCache = -65546, - mStatus_AlreadyRegistered = -65547, - mStatus_NameConflict = -65548, - mStatus_Invalid = -65549, - mStatus_Firewall = -65550, - mStatus_Incompatible = -65551, - mStatus_BadInterfaceErr = -65552, - mStatus_Refused = -65553, - mStatus_NoSuchRecord = -65554, - mStatus_NoAuth = -65555, - mStatus_NoSuchKey = -65556, - mStatus_NATTraversal = -65557, - mStatus_DoubleNAT = -65558, - mStatus_BadTime = -65559, - mStatus_BadSig = -65560, // while we define this per RFC 2845, BIND 9 returns Refused for bad/missing signatures - mStatus_BadKey = -65561, - mStatus_TransientErr = -65562, // transient failures, e.g. sending packets shortly after a network transition or wake from sleep - // -65563 to -65786 currently unused; available for allocation - - // tcp connection status - mStatus_ConnPending = -65787, - mStatus_ConnFailed = -65788, - mStatus_ConnEstablished = -65789, - - // Non-error values: - mStatus_GrowCache = -65790, - mStatus_ConfigChanged = -65791, - mStatus_MemFree = -65792 // Last value: 0xFFFE FF00 - - // mStatus_MemFree is the last legal mDNS error code, at the end of the range allocated for mDNS - }; +{ + mStatus_Waiting = 1, + mStatus_NoError = 0, + + // mDNS return values are in the range FFFE FF00 (-65792) to FFFE FFFF (-65537) + // The top end of the range (FFFE FFFF) is used for error codes; + // the bottom end of the range (FFFE FF00) is used for non-error values; + + // Error codes: + mStatus_UnknownErr = -65537, // First value: 0xFFFE FFFF + mStatus_NoSuchNameErr = -65538, + mStatus_NoMemoryErr = -65539, + mStatus_BadParamErr = -65540, + mStatus_BadReferenceErr = -65541, + mStatus_BadStateErr = -65542, + mStatus_BadFlagsErr = -65543, + mStatus_UnsupportedErr = -65544, + mStatus_NotInitializedErr = -65545, + mStatus_NoCache = -65546, + mStatus_AlreadyRegistered = -65547, + mStatus_NameConflict = -65548, + mStatus_Invalid = -65549, + mStatus_Firewall = -65550, + mStatus_Incompatible = -65551, + mStatus_BadInterfaceErr = -65552, + mStatus_Refused = -65553, + mStatus_NoSuchRecord = -65554, + mStatus_NoAuth = -65555, + mStatus_NoSuchKey = -65556, + mStatus_NATTraversal = -65557, + mStatus_DoubleNAT = -65558, + mStatus_BadTime = -65559, + mStatus_BadSig = -65560, // while we define this per RFC 2845, BIND 9 returns Refused for bad/missing signatures + mStatus_BadKey = -65561, + mStatus_TransientErr = -65562, // transient failures, e.g. sending packets shortly after a network transition or wake from sleep + mStatus_ServiceNotRunning = -65563, // Background daemon not running + mStatus_NATPortMappingUnsupported = -65564, // NAT doesn't support PCP, NAT-PMP or UPnP + mStatus_NATPortMappingDisabled = -65565, // NAT supports PCP, NAT-PMP or UPnP, but it's disabled by the administrator + mStatus_NoRouter = -65566, + mStatus_PollingMode = -65567, + mStatus_Timeout = -65568, + // -65568 to -65786 currently unused; available for allocation + + // tcp connection status + mStatus_ConnPending = -65787, + mStatus_ConnFailed = -65788, + mStatus_ConnEstablished = -65789, + + // Non-error values: + mStatus_GrowCache = -65790, + mStatus_ConfigChanged = -65791, + mStatus_MemFree = -65792 // Last value: 0xFFFE FF00 + // mStatus_MemFree is the last legal mDNS error code, at the end of the range allocated for mDNS +}; typedef mDNSs32 mStatus; +#define MaxIp 5 // Needs to be consistent with MaxInputIf in dns_services.h + +typedef enum { q_stop = 0, q_start } q_state; +typedef enum { reg_stop = 0, reg_start } reg_state; // RFC 1034/1035 specify that a domain label consists of a length byte plus up to 63 characters #define MAX_DOMAIN_LABEL 63 -typedef struct { mDNSu8 c[ 64]; } domainlabel; // One label: length byte and up to 63 characters +typedef struct { mDNSu8 c[ 64]; } domainlabel; // One label: length byte and up to 63 characters -// RFC 1034/1035 specify that a domain name, including length bytes, data bytes, and terminating zero, may be up to 255 bytes long -#define MAX_DOMAIN_NAME 255 -typedef struct { mDNSu8 c[256]; } domainname; // Up to 255 bytes of length-prefixed domainlabels +// RFC 1034/1035/2181 specify that a domain name (length bytes and data bytes) may be up to 255 bytes long, +// plus the terminating zero at the end makes 256 bytes total in the on-the-wire format. +#define MAX_DOMAIN_NAME 256 +typedef struct { mDNSu8 c[256]; } domainname; // Up to 256 bytes of length-prefixed domainlabels -typedef struct { mDNSu8 c[256]; } UTF8str255; // Null-terminated C string +typedef struct { mDNSu8 c[256]; } UTF8str255; // Null-terminated C string -// The longest legal textual form of a DNS name is 1005 bytes, including the C-string terminating NULL at the end. +// The longest legal textual form of a DNS name is 1009 bytes, including the C-string terminating NULL at the end. // Explanation: // When a native domainname object is converted to printable textual form using ConvertDomainNameToCString(), // non-printing characters are represented in the conventional DNS way, as '\ddd', where ddd is a three-digit decimal number. -// The longest legal domain name is 255 bytes, in the form of four labels as shown below: -// Length byte, 63 data bytes, length byte, 63 data bytes, length byte, 63 data bytes, length byte, 61 data bytes, zero byte. +// The longest legal domain name is 256 bytes, in the form of four labels as shown below: +// Length byte, 63 data bytes, length byte, 63 data bytes, length byte, 63 data bytes, length byte, 62 data bytes, zero byte. // Each label is encoded textually as characters followed by a trailing dot. // If every character has to be represented as a four-byte escape sequence, then this makes the maximum textual form four labels // plus the C-string terminating NULL as shown below: -// 63*4+1 + 63*4+1 + 63*4+1 + 61*4+1 + 1 = 1005. +// 63*4+1 + 63*4+1 + 63*4+1 + 62*4+1 + 1 = 1009. // Note that MAX_ESCAPED_DOMAIN_LABEL is not normally used: If you're only decoding a single label, escaping is usually not required. // It is for domain names, where dots are used as label separators, that proper escaping is vital. #define MAX_ESCAPED_DOMAIN_LABEL 254 -#define MAX_ESCAPED_DOMAIN_NAME 1005 +#define MAX_ESCAPED_DOMAIN_NAME 1009 + +// MAX_REVERSE_MAPPING_NAME +// For IPv4: "123.123.123.123.in-addr.arpa." 30 bytes including terminating NUL +// For IPv6: "x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.ip6.arpa." 74 bytes including terminating NUL + +#define MAX_REVERSE_MAPPING_NAME_V4 30 +#define MAX_REVERSE_MAPPING_NAME_V6 74 +#define MAX_REVERSE_MAPPING_NAME 74 // Most records have a TTL of 75 minutes, so that their 80% cache-renewal query occurs once per hour. // For records containing a hostname (in the name on the left, or in the rdata on the right), // like A, AAAA, reverse-mapping PTR, and SRV, we use a two-minute TTL by default, because we don't want // them to hang around for too long in the cache if the host in question crashes or otherwise goes away. -// Wide-area service discovery records have a very short TTL to avoid poluting intermediate caches with -// dynamic records. When discovered via Long Lived Queries (with change notifications), resource record -// TTLs can be safely ignored. - + #define kStandardTTL (3600UL * 100 / 80) #define kHostNameTTL 120UL -#define kWideAreaTTL 3 + +// Some applications want to register their SRV records with a lower ttl so that in case the server +// using a dynamic port number restarts, the clients will not have stale information for more than +// 10 seconds + +#define kHostNameSmallTTL 10UL + + +// Multicast DNS uses announcements (gratuitous responses) to update peer caches. +// This means it is feasible to use relatively larger TTL values than we might otherwise +// use, because we have a cache coherency protocol to keep the peer caches up to date. +// With Unicast DNS, once an authoritative server gives a record with a certain TTL value to a client +// or caching server, that client or caching server is entitled to hold onto the record until its TTL +// expires, and has no obligation to contact the authoritative server again until that time arrives. +// This means that whereas Multicast DNS can use announcements to pre-emptively update stale data +// before it would otherwise have expired, standard Unicast DNS (not using LLQs) has no equivalent +// mechanism, and TTL expiry is the *only* mechanism by which stale data gets deleted. Because of this, +// we currently limit the TTL to ten seconds in such cases where no dynamic cache updating is possible. +#define kStaticCacheTTL 10 #define DefaultTTLforRRType(X) (((X) == kDNSType_A || (X) == kDNSType_AAAA || (X) == kDNSType_SRV) ? kHostNameTTL : kStandardTTL) +#define mDNS_KeepaliveRecord(rr) ((rr)->rrtype == kDNSType_NULL && SameDomainLabel(SecondLabel((rr)->name)->c, (mDNSu8 *)"\x0A_keepalive")) + +// Number of times keepalives are sent if no ACK is received before waking up the system +// this is analogous to net.inet.tcp.keepcnt +#define kKeepaliveRetryCount 10 +// The frequency at which keepalives are retried if no ACK is received +#define kKeepaliveRetryInterval 30 + +typedef struct AuthRecord_struct AuthRecord; +typedef struct ServiceRecordSet_struct ServiceRecordSet; +typedef struct CacheRecord_struct CacheRecord; +typedef struct CacheGroup_struct CacheGroup; +typedef struct AuthGroup_struct AuthGroup; +typedef struct DNSQuestion_struct DNSQuestion; +typedef struct ZoneData_struct ZoneData; +typedef struct mDNS_struct mDNS; +typedef struct mDNS_PlatformSupport_struct mDNS_PlatformSupport; +typedef struct NATTraversalInfo_struct NATTraversalInfo; +typedef struct ResourceRecord_struct ResourceRecord; + +// Structure to abstract away the differences between TCP/SSL sockets, and one for UDP sockets +// The actual definition of these structures appear in the appropriate platform support code +typedef struct TCPSocket_struct TCPSocket; +typedef struct UDPSocket_struct UDPSocket; // *************************************************************************** #if 0 +#pragma mark - #pragma mark - DNS Message structures #endif @@ -1258,28 +487,189 @@ typedef struct { mDNSu8 c[256]; } UTF8str255; // Null-terminated C string #define mDNS_numUpdates numAuthorities typedef packedstruct - { - mDNSOpaque16 id; - mDNSOpaque16 flags; - mDNSu16 numQuestions; - mDNSu16 numAnswers; - mDNSu16 numAuthorities; - mDNSu16 numAdditionals; - } DNSMessageHeader; +{ + mDNSOpaque16 id; + mDNSOpaque16 flags; + mDNSu16 numQuestions; + mDNSu16 numAnswers; + mDNSu16 numAuthorities; + mDNSu16 numAdditionals; +} DNSMessageHeader; // We can send and receive packets up to 9000 bytes (Ethernet Jumbo Frame size, if that ever becomes widely used) // However, in the normal case we try to limit packets to 1500 bytes so that we don't get IP fragmentation on standard Ethernet // 40 (IPv6 header) + 8 (UDP header) + 12 (DNS message header) + 1440 (DNS message body) = 1500 total +#ifndef AbsoluteMaxDNSMessageData #define AbsoluteMaxDNSMessageData 8940 +#endif #define NormalMaxDNSMessageData 1440 typedef packedstruct - { - DNSMessageHeader h; // Note: Size 12 bytes - mDNSu8 data[AbsoluteMaxDNSMessageData]; // 40 (IPv6) + 8 (UDP) + 12 (DNS header) + 8940 (data) = 9000 - } DNSMessage; +{ + DNSMessageHeader h; // Note: Size 12 bytes + mDNSu8 data[AbsoluteMaxDNSMessageData]; // 40 (IPv6) + 8 (UDP) + 12 (DNS header) + 8940 (data) = 9000 +} DNSMessage; + +typedef struct tcpInfo_t +{ + mDNS *m; + TCPSocket *sock; + DNSMessage request; + int requestLen; + DNSQuestion *question; // For queries + AuthRecord *rr; // For record updates + mDNSAddr Addr; + mDNSIPPort Port; + mDNSIPPort SrcPort; + DNSMessage *reply; + mDNSu16 replylen; + unsigned long nread; + int numReplies; +} tcpInfo_t; // *************************************************************************** #if 0 +#pragma mark - +#pragma mark - Other Packet Format Structures +#endif + +typedef packedstruct +{ + mDNSEthAddr dst; + mDNSEthAddr src; + mDNSOpaque16 ethertype; +} EthernetHeader; // 14 bytes + +typedef packedstruct +{ + mDNSOpaque16 hrd; + mDNSOpaque16 pro; + mDNSu8 hln; + mDNSu8 pln; + mDNSOpaque16 op; + mDNSEthAddr sha; + mDNSv4Addr spa; + mDNSEthAddr tha; + mDNSv4Addr tpa; +} ARP_EthIP; // 28 bytes + +typedef packedstruct +{ + mDNSu8 vlen; + mDNSu8 tos; + mDNSu16 totlen; + mDNSOpaque16 id; + mDNSOpaque16 flagsfrags; + mDNSu8 ttl; + mDNSu8 protocol; // Payload type: 0x06 = TCP, 0x11 = UDP + mDNSu16 checksum; + mDNSv4Addr src; + mDNSv4Addr dst; +} IPv4Header; // 20 bytes + +typedef packedstruct +{ + mDNSu32 vcf; // Version, Traffic Class, Flow Label + mDNSu16 len; // Payload Length + mDNSu8 pro; // Type of next header: 0x06 = TCP, 0x11 = UDP, 0x3A = ICMPv6 + mDNSu8 ttl; // Hop Limit + mDNSv6Addr src; + mDNSv6Addr dst; +} IPv6Header; // 40 bytes + +typedef packedstruct +{ + mDNSv6Addr src; + mDNSv6Addr dst; + mDNSOpaque32 len; + mDNSOpaque32 pro; +} IPv6PseudoHeader; // 40 bytes + +typedef union +{ + mDNSu8 bytes[20]; + ARP_EthIP arp; + IPv4Header v4; + IPv6Header v6; +} NetworkLayerPacket; + +typedef packedstruct +{ + mDNSIPPort src; + mDNSIPPort dst; + mDNSu32 seq; + mDNSu32 ack; + mDNSu8 offset; + mDNSu8 flags; + mDNSu16 window; + mDNSu16 checksum; + mDNSu16 urgent; +} TCPHeader; // 20 bytes; IP protocol type 0x06 + +typedef struct +{ + mDNSInterfaceID IntfId; + mDNSu32 seq; + mDNSu32 ack; + mDNSu16 window; +} mDNSTCPInfo; + +typedef packedstruct +{ + mDNSIPPort src; + mDNSIPPort dst; + mDNSu16 len; // Length including UDP header (i.e. minimum value is 8 bytes) + mDNSu16 checksum; +} UDPHeader; // 8 bytes; IP protocol type 0x11 + +typedef packedstruct +{ + mDNSu8 type; // 0x87 == Neighbor Solicitation, 0x88 == Neighbor Advertisement + mDNSu8 code; + mDNSu16 checksum; + mDNSu32 flags_res; // R/S/O flags and reserved bits + mDNSv6Addr target; + // Typically 8 bytes of options are also present +} IPv6NDP; // 24 bytes or more; IP protocol type 0x3A + +typedef struct +{ + mDNSAddr ipaddr; + char ethaddr[18]; +} IPAddressMACMapping; + +#define NDP_Sol 0x87 +#define NDP_Adv 0x88 + +#define NDP_Router 0x80 +#define NDP_Solicited 0x40 +#define NDP_Override 0x20 + +#define NDP_SrcLL 1 +#define NDP_TgtLL 2 + +typedef union +{ + mDNSu8 bytes[20]; + TCPHeader tcp; + UDPHeader udp; + IPv6NDP ndp; +} TransportLayerPacket; + +typedef packedstruct +{ + mDNSOpaque64 InitiatorCookie; + mDNSOpaque64 ResponderCookie; + mDNSu8 NextPayload; + mDNSu8 Version; + mDNSu8 ExchangeType; + mDNSu8 Flags; + mDNSOpaque32 MessageID; + mDNSu32 Length; +} IKEHeader; // 28 bytes + +// *************************************************************************** +#if 0 +#pragma mark - #pragma mark - Resource Record structures #endif @@ -1330,867 +720,1837 @@ typedef packedstruct // Each Authoritative kDNSRecordType has only one bit set. This makes it easy to quickly see if a record // is one of a particular set of types simply by performing the appropriate bitwise masking operation. -// Cache Resource Records (received from the network): -// There are four basic types: Answer, Unique Answer, Additional, Unique Additional -// Bit 7 (the top bit) of kDNSRecordType is always set for Cache Resource Records; always clear for Authoritative Resource Records -// Bit 6 (value 0x40) is set for answer records; clear for additional records -// Bit 5 (value 0x20) is set for records received with the kDNSClass_UniqueRRSet +// Cache Resource Records (received from the network): +// There are four basic types: Answer, Unique Answer, Additional, Unique Additional +// Bit 7 (the top bit) of kDNSRecordType is always set for Cache Resource Records; always clear for Authoritative Resource Records +// Bit 6 (value 0x40) is set for answer records; clear for authority/additional records +// Bit 5 (value 0x20) is set for records received with the kDNSClass_UniqueRRSet + +enum +{ + kDNSRecordTypeUnregistered = 0x00, // Not currently in any list + kDNSRecordTypeDeregistering = 0x01, // Shared record about to announce its departure and leave the list + + kDNSRecordTypeUnique = 0x02, // Will become a kDNSRecordTypeVerified when probing is complete + + kDNSRecordTypeAdvisory = 0x04, // Like Shared, but no goodbye packet + kDNSRecordTypeShared = 0x08, // Shared means record name does not have to be unique -- use random delay on responses + + kDNSRecordTypeVerified = 0x10, // Unique means mDNS should check that name is unique (and then send immediate responses) + kDNSRecordTypeKnownUnique = 0x20, // Known Unique means mDNS can assume name is unique without checking + // For Dynamic Update records, Known Unique means the record must already exist on the server. + kDNSRecordTypeUniqueMask = (kDNSRecordTypeUnique | kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique), + kDNSRecordTypeActiveSharedMask = (kDNSRecordTypeAdvisory | kDNSRecordTypeShared), + kDNSRecordTypeActiveUniqueMask = (kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique), + kDNSRecordTypeActiveMask = (kDNSRecordTypeActiveSharedMask | kDNSRecordTypeActiveUniqueMask), + + kDNSRecordTypePacketAdd = 0x80, // Received in the Additional Section of a DNS Response + kDNSRecordTypePacketAddUnique = 0x90, // Received in the Additional Section of a DNS Response with kDNSClass_UniqueRRSet set + kDNSRecordTypePacketAuth = 0xA0, // Received in the Authorities Section of a DNS Response + kDNSRecordTypePacketAuthUnique = 0xB0, // Received in the Authorities Section of a DNS Response with kDNSClass_UniqueRRSet set + kDNSRecordTypePacketAns = 0xC0, // Received in the Answer Section of a DNS Response + kDNSRecordTypePacketAnsUnique = 0xD0, // Received in the Answer Section of a DNS Response with kDNSClass_UniqueRRSet set + + kDNSRecordTypePacketNegative = 0xF0, // Pseudo-RR generated to cache non-existence results like NXDomain + + kDNSRecordTypePacketUniqueMask = 0x10 // True for PacketAddUnique, PacketAnsUnique, PacketAuthUnique, kDNSRecordTypePacketNegative +}; + +typedef packedstruct { mDNSu16 priority; mDNSu16 weight; mDNSIPPort port; domainname target; } rdataSRV; +typedef packedstruct { mDNSu16 preference; domainname exchange; } rdataMX; +typedef packedstruct { domainname mbox; domainname txt; } rdataRP; +typedef packedstruct { mDNSu16 preference; domainname map822; domainname mapx400; } rdataPX; + +typedef packedstruct +{ + domainname mname; + domainname rname; + mDNSs32 serial; // Modular counter; increases when zone changes + mDNSu32 refresh; // Time in seconds that a slave waits after successful replication of the database before it attempts replication again + mDNSu32 retry; // Time in seconds that a slave waits after an unsuccessful replication attempt before it attempts replication again + mDNSu32 expire; // Time in seconds that a slave holds on to old data while replication attempts remain unsuccessful + mDNSu32 min; // Nominally the minimum record TTL for this zone, in seconds; also used for negative caching. +} rdataSOA; + +// http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml +// Algorithm used for RRSIG, DS and DNS KEY +#define CRYPTO_RSA_SHA1 0x05 +#define CRYPTO_DSA_NSEC3_SHA1 0x06 +#define CRYPTO_RSA_NSEC3_SHA1 0x07 +#define CRYPTO_RSA_SHA256 0x08 +#define CRYPTO_RSA_SHA512 0x0A + +#define CRYPTO_ALG_MAX 0x0B + +// alg - same as in RRSIG, DNS KEY or DS. +// RFC 4034 defines SHA1 +// RFC 4509 defines SHA256 +// Note: NSEC3 also uses 1 for SHA1 and hence we will reuse for now till a new +// value is assigned. +// +#define SHA1_DIGEST_TYPE 1 +#define SHA256_DIGEST_TYPE 2 +#define DIGEST_TYPE_MAX 3 + +// We need support for base64 and base32 encoding for displaying KEY, NSEC3 +// To make this platform agnostic, we define two types which the platform +// needs to support +#define ENC_BASE32 1 +#define ENC_BASE64 2 +#define ENC_ALG_MAX 3 + +#define DS_FIXED_SIZE 4 +typedef packedstruct +{ + mDNSu16 keyTag; + mDNSu8 alg; + mDNSu8 digestType; + mDNSu8 *digest; +} rdataDS; + +typedef struct TrustAnchor +{ + struct TrustAnchor *next; + int digestLen; + mDNSu32 validFrom; + mDNSu32 validUntil; + domainname zone; + rdataDS rds; +} TrustAnchor; + +//size of rdataRRSIG excluding signerName and signature (which are variable fields) +#define RRSIG_FIXED_SIZE 18 +typedef packedstruct +{ + mDNSu16 typeCovered; + mDNSu8 alg; + mDNSu8 labels; + mDNSu32 origTTL; + mDNSu32 sigExpireTime; + mDNSu32 sigInceptTime; + mDNSu16 keyTag; + mDNSu8 *signerName; + // mDNSu8 *signature +} rdataRRSig; + +// RFC 4034: For DNS Key RR +// flags - the valid value for DNSSEC is 256 (Zone signing key - ZSK) and 257 (Secure Entry Point) which also +// includes the ZSK bit +// +#define DNSKEY_ZONE_SIGN_KEY 0x100 +#define DNSKEY_SECURE_ENTRY_POINT 0x101 + +// proto - the only valid value for protocol is 3 (See RFC 4034) +#define DNSKEY_VALID_PROTO_VALUE 0x003 + +// alg - The only mandatory algorithm that we support is RSA/SHA-1 +// DNSSEC_RSA_SHA1_ALG + +#define DNSKEY_FIXED_SIZE 4 +typedef packedstruct +{ + mDNSu16 flags; + mDNSu8 proto; + mDNSu8 alg; + mDNSu8 *data; +} rdataDNSKey; + +#define NSEC3_FIXED_SIZE 5 +#define NSEC3_FLAGS_OPTOUT 1 +#define NSEC3_MAX_ITERATIONS 2500 +typedef packedstruct +{ + mDNSu8 alg; + mDNSu8 flags; + mDNSu16 iterations; + mDNSu8 saltLength; + mDNSu8 *salt; + // hashLength, nxt, bitmap +} rdataNSEC3; + +// In the multicast usage of NSEC3, we know the actual size of RData +// 4 bytes : HashAlg, Flags,Iterations +// 5 bytes : Salt Length 1 byte, Salt 4 bytes +// 21 bytes : HashLength 1 byte, Hash 20 bytes +// 34 bytes : Window number, Bitmap length, Type bit map to include the first 256 types +#define MCAST_NSEC3_RDLENGTH (4 + 5 + 21 + 34) +#define SHA1_HASH_LENGTH 20 + +// Base32 encoding takes 5 bytes of the input and encodes as 8 bytes of output. +// 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 +// 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 + +// 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. +typedef enum +{ + DNSSEC_Secure = 1, // Securely validated and has a chain up to the trust anchor + DNSSEC_Insecure, // Cannot build a chain up to the trust anchor + DNSSEC_Indeterminate, // Not used currently + DNSSEC_Bogus, // failed to validate signatures + DNSSEC_NoResponse // No DNSSEC records to start with +} DNSSECStatus; + +#define DNSSECRecordType(rrtype) (((rrtype) == kDNSType_RRSIG) || ((rrtype) == kDNSType_NSEC) || ((rrtype) == kDNSType_DNSKEY) || ((rrtype) == kDNSType_DS) || \ + ((rrtype) == kDNSType_NSEC3)) + +typedef enum +{ + platform_OSX = 1, // OSX Platform + platform_iOS, // iOS Platform + platform_Atv, // Atv Platform + platform_NonApple // Non-Apple (Windows, POSIX) Platform +} Platform_t; + +// EDNS Option Code registrations are recorded in the "DNS EDNS0 Options" section of +// + +#define kDNSOpt_LLQ 1 +#define kDNSOpt_Lease 2 +#define kDNSOpt_NSID 3 +#define kDNSOpt_Owner 4 +#define kDNSOpt_Trace 65001 // 65001-65534 Reserved for Local/Experimental Use + +typedef struct +{ + mDNSu16 vers; + mDNSu16 llqOp; + mDNSu16 err; // Or UDP reply port, in setup request + // Note: In the in-memory form, there's typically a two-byte space here, so that the following 64-bit id is word-aligned + mDNSOpaque64 id; + mDNSu32 llqlease; +} LLQOptData; + +typedef struct +{ + mDNSu8 vers; // Version number of this Owner OPT record + mDNSs8 seq; // Sleep/wake epoch + mDNSEthAddr HMAC; // Host's primary identifier (e.g. MAC of on-board Ethernet) + mDNSEthAddr IMAC; // Interface's MAC address (if different to primary MAC) + mDNSOpaque48 password; // Optional password +} OwnerOptData; + +typedef struct +{ + mDNSu8 platf; // Running platform (see enum Platform_t) + mDNSu32 mDNSv; // mDNSResponder Version (DNS_SD_H defined in dns_sd.h) +} TracerOptData; + +// Note: rdataOPT format may be repeated an arbitrary number of times in a single resource record +typedef packedstruct +{ + mDNSu16 opt; + mDNSu16 optlen; + union { LLQOptData llq; mDNSu32 updatelease; OwnerOptData owner; TracerOptData tracer; } u; +} rdataOPT; + +// Space needed to put OPT records into a packet: +// Header 11 bytes (name 1, type 2, class 2, TTL 4, length 2) +// LLQ rdata 18 bytes (opt 2, len 2, vers 2, op 2, err 2, id 8, lease 4) +// Lease rdata 8 bytes (opt 2, len 2, lease 4) +// Owner rdata 12-24 bytes (opt 2, len 2, owner 8-20) +// Trace rdata 9 bytes (opt 2, len 2, platf 1, mDNSv 4) + + +#define DNSOpt_Header_Space 11 +#define DNSOpt_LLQData_Space (4 + 2 + 2 + 2 + 8 + 4) +#define DNSOpt_LeaseData_Space (4 + 4) +#define DNSOpt_OwnerData_ID_Space (4 + 2 + 6) +#define DNSOpt_OwnerData_ID_Wake_Space (4 + 2 + 6 + 6) +#define DNSOpt_OwnerData_ID_Wake_PW4_Space (4 + 2 + 6 + 6 + 4) +#define DNSOpt_OwnerData_ID_Wake_PW6_Space (4 + 2 + 6 + 6 + 6) +#define DNSOpt_TraceData_Space (4 + 1 + 4) + +#define ValidOwnerLength(X) ( (X) == DNSOpt_OwnerData_ID_Space - 4 || \ + (X) == DNSOpt_OwnerData_ID_Wake_Space - 4 || \ + (X) == DNSOpt_OwnerData_ID_Wake_PW4_Space - 4 || \ + (X) == DNSOpt_OwnerData_ID_Wake_PW6_Space - 4 ) + +#define DNSOpt_Owner_Space(A,B) (mDNSSameEthAddress((A),(B)) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space) + +#define DNSOpt_Data_Space(O) ( \ + (O)->opt == kDNSOpt_LLQ ? DNSOpt_LLQData_Space : \ + (O)->opt == kDNSOpt_Lease ? DNSOpt_LeaseData_Space : \ + (O)->opt == kDNSOpt_Trace ? DNSOpt_TraceData_Space : \ + (O)->opt == kDNSOpt_Owner ? DNSOpt_Owner_Space(&(O)->u.owner.HMAC, &(O)->u.owner.IMAC) : 0x10000) + +// NSEC record is defined in RFC 4034. +// 16 bit RRTYPE space is split into 256 windows and each window has 256 bits (32 bytes). +// If we create a structure for NSEC, it's size would be: +// +// 256 bytes domainname 'nextname' +// + 256 * 34 = 8704 bytes of bitmap data +// = 8960 bytes total +// +// This would be a waste, as types about 256 are not very common. But it would be odd, if we receive +// a type above 256 (.US zone had TYPE65534 when this code was written) and not able to handle it. +// Hence, we handle any size by not fixing a strucure in place. The following is just a placeholder +// and never used anywhere. +// +#define NSEC_MCAST_WINDOW_SIZE 32 +typedef struct +{ + domainname *next; //placeholders are uncommented because C89 in Windows requires that a struct has at least a member. + char bitmap[32]; +} rdataNSEC; + +// StandardAuthRDSize is 264 (256+8), which is large enough to hold a maximum-sized SRV record (6 + 256 bytes) +// MaximumRDSize is 8K the absolute maximum we support (at least for now) +#define StandardAuthRDSize 264 +#ifndef MaximumRDSize +#define MaximumRDSize 8192 +#endif + +// InlineCacheRDSize is 68 +// Records received from the network with rdata this size or less have their rdata stored right in the CacheRecord object +// Records received from the network with rdata larger than this have additional storage allocated for the rdata +// A quick unscientific sample from a busy network at Apple with lots of machines revealed this: +// 1461 records in cache +// 292 were one-byte TXT records +// 136 were four-byte A records +// 184 were sixteen-byte AAAA records +// 780 were various PTR, TXT and SRV records from 12-64 bytes +// Only 69 records had rdata bigger than 64 bytes +// Note that since CacheRecord object and a CacheGroup object are allocated out of the same pool, it's sensible to +// have them both be the same size. Making one smaller without making the other smaller won't actually save any memory. +#define InlineCacheRDSize 68 + +// The RDataBody union defines the common rdata types that fit into our 264-byte limit +typedef union +{ + mDNSu8 data[StandardAuthRDSize]; + mDNSv4Addr ipv4; // For 'A' record + domainname name; // For PTR, NS, CNAME, DNAME + UTF8str255 txt; + rdataMX mx; + mDNSv6Addr ipv6; // For 'AAAA' record + rdataSRV srv; + rdataOPT opt[2]; // For EDNS0 OPT record; RDataBody may contain multiple variable-length rdataOPT objects packed together +} RDataBody; + +// The RDataBody2 union is the same as above, except it includes fields for the larger types like soa, rp, px +typedef union +{ + mDNSu8 data[StandardAuthRDSize]; + mDNSv4Addr ipv4; // For 'A' record + domainname name; // For PTR, NS, CNAME, DNAME + rdataSOA soa; // This is large; not included in the normal RDataBody definition + UTF8str255 txt; + rdataMX mx; + rdataRP rp; // This is large; not included in the normal RDataBody definition + rdataPX px; // This is large; not included in the normal RDataBody definition + mDNSv6Addr ipv6; // For 'AAAA' record + rdataSRV srv; + rdataOPT opt[2]; // For EDNS0 OPT record; RDataBody may contain multiple variable-length rdataOPT objects packed together + rdataDS ds; + rdataDNSKey key; + rdataRRSig rrsig; +} RDataBody2; + +typedef struct +{ + mDNSu16 MaxRDLength; // Amount of storage allocated for rdata (usually sizeof(RDataBody)) + mDNSu16 padding; // So that RDataBody is aligned on 32-bit boundary + RDataBody u; +} RData; + +// sizeofRDataHeader should be 4 bytes +#define sizeofRDataHeader (sizeof(RData) - sizeof(RDataBody)) + +// RData_small is a smaller version of the RData object, used for inline data storage embedded in a CacheRecord_struct +typedef struct +{ + mDNSu16 MaxRDLength; // Storage allocated for data (may be greater than InlineCacheRDSize if additional storage follows this object) + mDNSu16 padding; // So that data is aligned on 32-bit boundary + mDNSu8 data[InlineCacheRDSize]; +} RData_small; + +// Note: Within an mDNSRecordCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute() +typedef void mDNSRecordCallback (mDNS *const m, AuthRecord *const rr, mStatus result); + +// Note: +// Restrictions: An mDNSRecordUpdateCallback may not make any mDNS API calls. +// The intent of this callback is to allow the client to free memory, if necessary. +// The internal data structures of the mDNS code may not be in a state where mDNS API calls may be made safely. +typedef void mDNSRecordUpdateCallback (mDNS *const m, AuthRecord *const rr, RData *OldRData, mDNSu16 OldRDLen); + +// *************************************************************************** +#if 0 +#pragma mark - +#pragma mark - NAT Traversal structures and constants +#endif + +#define NATMAP_MAX_RETRY_INTERVAL ((mDNSPlatformOneSecond * 60) * 15) // Max retry interval is 15 minutes +#define NATMAP_MIN_RETRY_INTERVAL (mDNSPlatformOneSecond * 2) // Min retry interval is 2 seconds +#define NATMAP_INIT_RETRY (mDNSPlatformOneSecond / 4) // start at 250ms w/ exponential decay +#define NATMAP_DEFAULT_LEASE (60 * 60 * 2) // 2 hour lease life in seconds +#define NATMAP_VERS 0 + +typedef enum +{ + NATOp_AddrRequest = 0, + NATOp_MapUDP = 1, + NATOp_MapTCP = 2, + + NATOp_AddrResponse = 0x80 | 0, + NATOp_MapUDPResponse = 0x80 | 1, + NATOp_MapTCPResponse = 0x80 | 2, +} NATOp_t; + +enum +{ + NATErr_None = 0, + NATErr_Vers = 1, + NATErr_Refused = 2, + NATErr_NetFail = 3, + NATErr_Res = 4, + NATErr_Opcode = 5 +}; + +typedef mDNSu16 NATErr_t; + +typedef packedstruct +{ + mDNSu8 vers; + mDNSu8 opcode; +} NATAddrRequest; + +typedef packedstruct +{ + mDNSu8 vers; + mDNSu8 opcode; + mDNSu16 err; + mDNSu32 upseconds; // Time since last NAT engine reboot, in seconds + mDNSv4Addr ExtAddr; +} NATAddrReply; + +typedef packedstruct +{ + mDNSu8 vers; + mDNSu8 opcode; + mDNSOpaque16 unused; + mDNSIPPort intport; + mDNSIPPort extport; + mDNSu32 NATReq_lease; +} NATPortMapRequest; -enum - { - kDNSRecordTypeUnregistered = 0x00, // Not currently in any list - kDNSRecordTypeDeregistering = 0x01, // Shared record about to announce its departure and leave the list +typedef packedstruct +{ + mDNSu8 vers; + mDNSu8 opcode; + mDNSu16 err; + mDNSu32 upseconds; // Time since last NAT engine reboot, in seconds + mDNSIPPort intport; + mDNSIPPort extport; + mDNSu32 NATRep_lease; +} NATPortMapReply; - kDNSRecordTypeUnique = 0x02, // Will become a kDNSRecordTypeVerified when probing is complete +// PCP Support for IPv4 mappings - kDNSRecordTypeAdvisory = 0x04, // Like Shared, but no goodbye packet - kDNSRecordTypeShared = 0x08, // Shared means record name does not have to be unique -- use random delay on responses +#define PCP_VERS 0x02 +#define PCP_WAITSECS_AFTER_EPOCH_INVALID 5 - kDNSRecordTypeVerified = 0x10, // Unique means mDNS should check that name is unique (and then send immediate responses) - kDNSRecordTypeKnownUnique = 0x20, // Known Unique means mDNS can assume name is unique without checking - // For Dynamic Update records, Known Unique means the record must already exist on the server. - kDNSRecordTypeUniqueMask = (kDNSRecordTypeUnique | kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique), - kDNSRecordTypeActiveMask = (kDNSRecordTypeAdvisory | kDNSRecordTypeShared | kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique), +typedef enum +{ + PCPOp_Announce = 0, + PCPOp_Map = 1 +} PCPOp_t; - kDNSRecordTypePacketAdd = 0x80, // Received in the Additional Section of a DNS Response - kDNSRecordTypePacketAddUnique = 0x90, // Received in the Additional Section of a DNS Response with kDNSClass_UniqueRRSet set - kDNSRecordTypePacketAuth = 0xA0, // Received in the Authorities Section of a DNS Response - kDNSRecordTypePacketAuthUnique = 0xB0, // Received in the Authorities Section of a DNS Response with kDNSClass_UniqueRRSet set - kDNSRecordTypePacketAns = 0xC0, // Received in the Answer Section of a DNS Response - kDNSRecordTypePacketAnsUnique = 0xD0, // Received in the Answer Section of a DNS Response with kDNSClass_UniqueRRSet set +typedef enum +{ + PCPProto_All = 0, + PCPProto_TCP = 6, + PCPProto_UDP = 17 +} PCPProto_t; - kDNSRecordTypePacketAnsMask = 0x40, // True for PacketAns and PacketAnsUnique - kDNSRecordTypePacketUniqueMask = 0x10 // True for PacketAddUnique, PacketAnsUnique, PacketAuthUnique - }; +typedef enum +{ + PCPResult_Success = 0, + PCPResult_UnsuppVersion = 1, + PCPResult_NotAuthorized = 2, + PCPResult_MalformedReq = 3, + PCPResult_UnsuppOpcode = 4, + PCPResult_UnsuppOption = 5, + PCPResult_MalformedOption = 6, + PCPResult_NetworkFailure = 7, + PCPResult_NoResources = 8, + PCPResult_UnsuppProtocol = 9, + PCPResult_UserExQuota = 10, + PCPResult_CantProvideExt = 11, + PCPResult_AddrMismatch = 12, + PCPResult_ExcesRemotePeer = 13 +} PCPResult_t; -typedef packedstruct { mDNSu16 priority; mDNSu16 weight; mDNSIPPort port; domainname target; } rdataSRV; -typedef packedstruct { mDNSu16 preference; domainname exchange; } rdataMX; typedef packedstruct - { - domainname mname; - domainname rname; - mDNSs32 serial; // Modular counter; increases when zone changes - mDNSu32 refresh; // Time in seconds that a slave waits after successful replication of the database before it attempts replication again - mDNSu32 retry; // Time in seconds that a slave waits after an unsuccessful replication attempt before it attempts replication again - mDNSu32 expire; // Time in seconds that a slave holds on to old data while replication attempts remain unsuccessful - mDNSu32 min; // Nominally the minimum record TTL for this zone, in seconds; also used for negative caching. - } rdataSOA; +{ + mDNSu8 version; + mDNSu8 opCode; + mDNSOpaque16 reserved; + mDNSu32 lifetime; + mDNSv6Addr clientAddr; + mDNSu32 nonce[3]; + mDNSu8 protocol; + mDNSu8 reservedMapOp[3]; + mDNSIPPort intPort; + mDNSIPPort extPort; + mDNSv6Addr extAddress; +} PCPMapRequest; typedef packedstruct - { - mDNSu16 vers; - mDNSu16 llqOp; - mDNSu16 err; - mDNSu8 id[8]; - mDNSu32 lease; - } LLQOptData; - -#define LLQ_OPTLEN ((3 * sizeof(mDNSu16)) + 8 + sizeof(mDNSu32)) -// Windows adds pad bytes to sizeof(LLQOptData). Use this macro when setting length fields or validating option rdata from -// off the wire. Use sizeof(LLQOptData) when dealing with structures (e.g. memcpy). Never memcpy between on-the-wire -// representation and a structure - -// NOTE: rdataOpt format may be repeated an arbitrary number of times in a single resource record -typedef packedstruct - { - mDNSu16 opt; - mDNSu16 optlen; - union { LLQOptData llq; mDNSu32 lease; } OptData; - } rdataOpt; +{ + mDNSu8 version; + mDNSu8 opCode; + mDNSu8 reserved; + mDNSu8 result; + mDNSu32 lifetime; + mDNSu32 epoch; + mDNSu32 clientAddrParts[3]; + mDNSu32 nonce[3]; + mDNSu8 protocol; + mDNSu8 reservedMapOp[3]; + mDNSIPPort intPort; + mDNSIPPort extPort; + mDNSv6Addr extAddress; +} PCPMapReply; + +// LNT Support -// StandardAuthRDSize is 264 (256+8), which is large enough to hold a maximum-sized SRV record -// MaximumRDSize is 8K the absolute maximum we support (at least for now) -#define StandardAuthRDSize 264 -#define MaximumRDSize 8192 +typedef enum +{ + LNTDiscoveryOp = 1, + LNTExternalAddrOp = 2, + LNTPortMapOp = 3, + LNTPortMapDeleteOp = 4 +} LNTOp_t; + +#define LNT_MAXBUFSIZE 8192 +typedef struct tcpLNTInfo_struct tcpLNTInfo; +struct tcpLNTInfo_struct +{ + tcpLNTInfo *next; + mDNS *m; + NATTraversalInfo *parentNATInfo; // pointer back to the parent NATTraversalInfo + TCPSocket *sock; + LNTOp_t op; // operation performed using this connection + mDNSAddr Address; // router address + mDNSIPPort Port; // router port + mDNSu8 *Request; // xml request to router + int requestLen; + mDNSu8 *Reply; // xml reply from router + int replyLen; + unsigned long nread; // number of bytes read so far + int retries; // number of times we've tried to do this port mapping +}; + +typedef void (*NATTraversalClientCallback)(mDNS *m, NATTraversalInfo *n); + +// if m->timenow < ExpiryTime then we have an active mapping, and we'll renew halfway to expiry +// if m->timenow >= ExpiryTime then our mapping has expired, and we're trying to create one -// InlineCacheRDSize is 68 -// Records received from the network with rdata this size or less have their rdata stored right in the CacheRecord object -// Records received from the network with rdata larger than this have additional storage allocated for the rdata -// A quick unscientific sample from a busy network at Apple with lots of machines revealed this: -// 1461 records in cache -// 292 were one-byte TXT records -// 136 were four-byte A records -// 184 were sixteen-byte AAAA records -// 780 were various PTR, TXT and SRV records from 12-64 bytes -// Only 69 records had rdata bigger than 64 bytes -// Note that since CacheRecord object and a CacheGroup object are allocated out of the same pool, it's sensible to -// have them both be the same size. Making one smaller without making the other smaller won't actually save any memory. -#define InlineCacheRDSize 68 +typedef enum +{ + NATTProtocolNone = 0, + NATTProtocolNATPMP = 1, + NATTProtocolUPNPIGD = 2, + NATTProtocolPCP = 3, +} NATTProtocol; -#define InlineCacheGroupNameSize 144 +struct NATTraversalInfo_struct +{ + // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them. + NATTraversalInfo *next; + + mDNSs32 ExpiryTime; // Time this mapping expires, or zero if no mapping + mDNSs32 retryInterval; // Current interval, between last packet we sent and the next one + mDNSs32 retryPortMap; // If Protocol is nonzero, time to send our next mapping packet + mStatus NewResult; // New error code; will be copied to Result just prior to invoking callback + NATTProtocol lastSuccessfulProtocol; // To send correct deletion request & update non-PCP external address operations + mDNSBool sentNATPMP; // Whether we just sent a NAT-PMP packet, so we won't send another if + // we receive another NAT-PMP "Unsupported Version" packet -typedef union - { - mDNSu8 data[StandardAuthRDSize]; - mDNSv4Addr ipv4; // For 'A' record - mDNSv6Addr ipv6; // For 'AAAA' record - domainname name; // For PTR, NS, and CNAME records - UTF8str255 txt; // For TXT record - rdataSRV srv; // For SRV record - rdataMX mx; // For MX record - rdataSOA soa; // For SOA record - rdataOpt opt; // For eDNS0 opt record - } RDataBody; +#ifdef _LEGACY_NAT_TRAVERSAL_ + tcpLNTInfo tcpInfo; // Legacy NAT traversal (UPnP) TCP connection +#endif -typedef struct - { - mDNSu16 MaxRDLength; // Amount of storage allocated for rdata (usually sizeof(RDataBody)) - RDataBody u; - } RData; -#define sizeofRDataHeader (sizeof(RData) - sizeof(RDataBody)) + // Result fields: When the callback is invoked these fields contain the answers the client is looking for + // When the callback is invoked ExternalPort is *usually* set to be the same the same as RequestedPort, except: + // (a) When we're behind a NAT gateway with port mapping disabled, ExternalPort is reported as zero to + // indicate that we don't currently have a working mapping (but RequestedPort retains the external port + // we'd like to get, the next time we meet an accomodating NAT gateway willing to give us one). + // (b) When we have a routable non-RFC1918 address, we don't *need* a port mapping, so ExternalPort + // is reported as the same as our InternalPort, since that is effectively our externally-visible port too. + // Again, RequestedPort retains the external port we'd like to get the next time we find ourself behind a NAT gateway. + // To improve stability of port mappings, RequestedPort is updated any time we get a successful + // mapping response from the PCP, NAT-PMP or UPnP gateway. For example, if we ask for port 80, and + // get assigned port 81, then thereafter we'll contine asking for port 81. + mDNSInterfaceID InterfaceID; + mDNSv4Addr ExternalAddress; // Initially set to onesIPv4Addr, until first callback + mDNSv4Addr NewAddress; // May be updated with actual value assigned by gateway + mDNSIPPort ExternalPort; + mDNSu32 Lifetime; + mStatus Result; + + // Client API fields: The client must set up these fields *before* making any NAT traversal API calls + mDNSu8 Protocol; // NATOp_MapUDP or NATOp_MapTCP, or zero if just requesting the external IP address + mDNSIPPort IntPort; // Client's internal port number (doesn't change) + mDNSIPPort RequestedPort; // Requested external port; may be updated with actual value assigned by gateway + mDNSu32 NATLease; // Requested lifetime in seconds (doesn't change) + NATTraversalClientCallback clientCallback; + void *clientContext; +}; -typedef struct AuthRecord_struct AuthRecord; -typedef struct CacheRecord_struct CacheRecord; -typedef struct CacheGroup_struct CacheGroup; -typedef struct DNSQuestion_struct DNSQuestion; -typedef struct mDNS_struct mDNS; -typedef struct mDNS_PlatformSupport_struct mDNS_PlatformSupport; -typedef struct NATTraversalInfo_struct NATTraversalInfo; +// *************************************************************************** +#if 0 +#pragma mark - +#pragma mark - DNSServer & McastResolver structures and constants +#endif -// Note: Within an mDNSRecordCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute() -typedef void mDNSRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result); +enum +{ + DNSServer_Untested = 0, + DNSServer_Passed = 1, + DNSServer_Failed = 2, + DNSServer_Disabled = 3 +}; -// Note: -// Restrictions: An mDNSRecordUpdateCallback may not make any mDNS API calls. -// The intent of this callback is to allow the client to free memory, if necessary. -// The internal data structures of the mDNS code may not be in a state where mDNS API calls may be made safely. -typedef void mDNSRecordUpdateCallback(mDNS *const m, AuthRecord *const rr, RData *OldRData); +enum +{ + DNSServer_FlagDelete = 1, + DNSServer_FlagNew = 2 +}; + +enum +{ + McastResolver_FlagDelete = 1, + McastResolver_FlagNew = 2 +}; + +typedef struct McastResolver +{ + struct McastResolver *next; + mDNSInterfaceID interface; + mDNSu32 flags; // Set when we're planning to delete this from the list + domainname domain; + mDNSu32 timeout; // timeout value for questions +} McastResolver; + +// scoped values for DNSServer matching +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 + // have a matching serviceID +}; + +// Note: DNSSECAware is set if we are able to get a valid response to +// a DNSSEC question. In some cases it is possible that the proxy +// strips the EDNS0 option and we just get a plain response with no +// signatures. But we still mark DNSSECAware in that case. As DNSSECAware +// is only used to determine whether DNSSEC_VALIDATION_SECURE_OPTIONAL +// should be turned off or not, it is sufficient that we are getting +// responses back. +typedef struct DNSServer +{ + struct DNSServer *next; + mDNSInterfaceID interface; // DNS requests should be sent on this interface + 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 + mDNSu32 timeout; // timeout value for questions + mDNSBool cellIntf; // Resolver from Cellular Interface ? + mDNSu16 resGroupID; // ID of the resolver group that contains this DNSServer + mDNSBool req_A; // If set, send v4 query (DNSConfig allows A queries) + mDNSBool req_AAAA; // If set, send v6 query (DNSConfig allows AAAA queries) + mDNSBool req_DO; // If set, okay to send DNSSEC queries (EDNS DO bit is supported) + mDNSBool retransDO; // Total Retransmissions for queries sent with DO option + mDNSBool DNSSECAware; // set if we are able to receive a response to a request + // sent with DO option. +} DNSServer; typedef struct - { - mDNSu8 RecordType; // See enum above - mDNSInterfaceID InterfaceID; // Set if this RR is specific to one interface - // For records received off the wire, InterfaceID is *always* set to the receiving interface - // For our authoritative records, InterfaceID is usually zero, except for those few records - // that are interface-specific (e.g. address records, especially linklocal addresses) - domainname *name; - mDNSu16 rrtype; - mDNSu16 rrclass; - mDNSu32 rroriginalttl; // In seconds - mDNSu16 rdlength; // Size of the raw rdata, in bytes - mDNSu16 rdestimate; // Upper bound on size of rdata after name compression - mDNSu32 namehash; // Name-based (i.e. case-insensitive) hash of name - mDNSu32 rdatahash; // For rdata containing domain name (e.g. PTR, SRV, CNAME etc.), case-insensitive name hash - // else, for all other rdata, 32-bit hash of the raw rdata - // Note: This requirement is important. Various routines like AddAdditionalsToResponseList(), - // ReconfirmAntecedents(), etc., use rdatahash as a pre-flight check to see - // whether it's worth doing a full SameDomainName() call. If the rdatahash - // is not a correct case-insensitive name hash, they'll get false negatives. - RData *rdata; // Pointer to storage for this rdata - } ResourceRecord; - -// Unless otherwise noted, states may apply to either independent record registrations or service registrations +{ + mDNSu8 *AnonData; + int AnonDataLen; + mDNSu32 salt; + ResourceRecord *nsec3RR; + mDNSInterfaceID SendNow; // The interface ID that this record should be sent on +} AnonymousInfo; + +struct ResourceRecord_struct +{ + mDNSu8 RecordType; // See enum above + mDNSu16 rrtype; + mDNSu16 rrclass; + mDNSu32 rroriginalttl; // In seconds + mDNSu16 rdlength; // Size of the raw rdata, in bytes, in the on-the-wire format + // (In-memory storage may be larger, for structures containing 'holes', like SOA) + mDNSu16 rdestimate; // Upper bound on on-the-wire size of rdata after name compression + mDNSu32 namehash; // Name-based (i.e. case-insensitive) hash of name + mDNSu32 rdatahash; // For rdata containing domain name (e.g. PTR, SRV, CNAME etc.), case-insensitive name hash + // else, for all other rdata, 32-bit hash of the raw rdata + // Note: This requirement is important. Various routines like AddAdditionalsToResponseList(), + // ReconfirmAntecedents(), etc., use rdatahash as a pre-flight check to see + // whether it's worth doing a full SameDomainName() call. If the rdatahash + // is not a correct case-insensitive name hash, they'll get false negatives. + + // Grouping pointers together at the end of the structure improves the memory layout efficiency + mDNSInterfaceID InterfaceID; // Set if this RR is specific to one interface + // For records received off the wire, InterfaceID is *always* set to the receiving interface + // For our authoritative records, InterfaceID is usually zero, except for those few records + // that are interface-specific (e.g. address records, especially linklocal addresses) + const domainname *name; + RData *rdata; // Pointer to storage for this rdata + DNSServer *rDNSServer; // Unicast DNS server authoritative for this entry;null for multicast + AnonymousInfo *AnonInfo; // Anonymous Information +}; + + +// Unless otherwise noted, states may apply to either independent record registrations or service registrations typedef enum - { - regState_FetchingZoneData = 1, // getting info - update not sent - regState_Pending = 2, // update sent, reply not received - regState_Registered = 3, // update sent, reply received - regState_DeregPending = 4, // dereg sent, reply not received - regState_DeregDeferred = 5, // dereg requested while in Pending state - send dereg AFTER registration is confirmed - regState_Cancelled = 6, // update not sent, reg. cancelled by client - regState_Unregistered = 8, // not in any list - regState_Refresh = 9, // outstanding refresh (or target change) message - regState_NATMap = 10, // establishing NAT port mapping or learning public address - regState_UpdatePending = 11, // update in flight as result of mDNS_Update call - regState_NoTarget = 12, // service registration pending registration of hostname (ServiceRegistrations only) - regState_ExtraQueued = 13, // extra record to be registered upon completion of service registration (RecordRegistrations only) - regState_NATError = 14 // unable to complete NAT traversal - } regState_t; - -// context for both ServiceRecordSet and individual AuthRec structs -typedef struct - { - // registration/lease state - regState_t state; - mDNSBool lease; // dynamic update contains (should contain) lease option - mDNSs32 expire; // expiration of lease (-1 for static) - mDNSBool TestForSelfConflict; // on name conflict, check if we're just seeing our own orphaned records - - // identifier to match update request and response - mDNSOpaque16 id; - - // server info - domainname zone; // the zone that is updated - mDNSAddr ns; // primary name server for the record's zone !!!KRS not technically correct to cache longer than TTL - mDNSIPPort port; // port on which server accepts dynamic updates - - // NAT traversal context - NATTraversalInfo *NATinfo; // may be NULL - - // state for deferred operations - mDNSBool ClientCallbackDeferred; // invoke client callback on completion of pending operation(s) - mStatus DeferredStatus; // status to deliver when above flag is set - mDNSBool SRVUpdateDeferred; // do we need to change target or port once current operation completes? - mDNSBool SRVChanged; // temporarily deregistered service because its SRV target or port changed +{ + regState_Zero = 0, + regState_Pending = 1, // update sent, reply not received + regState_Registered = 2, // update sent, reply received + regState_DeregPending = 3, // dereg sent, reply not received + regState_Unregistered = 4, // not in any list + regState_Refresh = 5, // outstanding refresh (or target change) message + regState_NATMap = 6, // establishing NAT port mapping + regState_UpdatePending = 7, // update in flight as result of mDNS_Update call + regState_NoTarget = 8, // SRV Record registration pending registration of hostname + regState_NATError = 9 // unable to complete NAT traversal +} regState_t; - // uDNS_UpdateRecord support fields - RData *OrigRData; mDNSu16 OrigRDLen; // previously registered, being deleted - RData *InFlightRData; mDNSu16 InFlightRDLen; // currently being registered - RData *QueuedRData; mDNSu16 QueuedRDLen; // if the client call Update while an update is in flight, we must finish the - // pending operation (re-transmitting if necessary) THEN register the queued update - mDNSRecordUpdateCallback *UpdateRDCallback; // client callback to free old rdata - } uDNS_RegInfo; +enum +{ + Target_Manual = 0, + Target_AutoHost = 1, + Target_AutoHostAndNATMAP = 2 +}; + +typedef enum +{ + mergeState_Zero = 0, + mergeState_DontMerge = 1 // Set on fatal error conditions to disable merging +} mergeState_t; + +#define AUTH_GROUP_NAME_SIZE 128 +struct AuthGroup_struct // Header object for a list of AuthRecords with the same name +{ + AuthGroup *next; // Next AuthGroup object in this hash table bucket + mDNSu32 namehash; // Name-based (i.e. case insensitive) hash of name + AuthRecord *members; // List of CacheRecords with this same name + AuthRecord **rrauth_tail; // Tail end of that list + domainname *name; // Common name for all AuthRecords in this list + AuthRecord *NewLocalOnlyRecords; + mDNSu8 namestorage[AUTH_GROUP_NAME_SIZE]; +}; + +#ifndef AUTH_HASH_SLOTS +#define AUTH_HASH_SLOTS 499 +#endif +#define FORALL_AUTHRECORDS(SLOT,AG,AR) \ + for ((SLOT) = 0; (SLOT) < AUTH_HASH_SLOTS; (SLOT)++) \ + for ((AG)=m->rrauth.rrauth_hash[(SLOT)]; (AG); (AG)=(AG)->next) \ + for ((AR) = (AG)->members; (AR); (AR)=(AR)->next) + +typedef union AuthEntity_union AuthEntity; +union AuthEntity_union { AuthEntity *next; AuthGroup ag; }; +typedef struct { + mDNSu32 rrauth_size; // Total number of available auth entries + mDNSu32 rrauth_totalused; // Number of auth entries currently occupied + mDNSu32 rrauth_report; + mDNSu8 rrauth_lock; // For debugging: Set at times when these lists may not be modified + AuthEntity *rrauth_free; + AuthGroup *rrauth_hash[AUTH_HASH_SLOTS]; +}AuthHash; + +// AuthRecordAny includes mDNSInterface_Any and interface specific auth records. +typedef enum +{ + AuthRecordAny, // registered for *Any, NOT including P2P interfaces + AuthRecordAnyIncludeP2P, // registered for *Any, including P2P interfaces + AuthRecordAnyIncludeAWDL, // registered for *Any, including AWDL interface + AuthRecordAnyIncludeAWDLandP2P, // registered for *Any, including AWDL and P2P interfaces + AuthRecordLocalOnly, + AuthRecordP2P // discovered over D2D/P2P framework +} AuthRecType; + +typedef enum +{ + AuthFlagsWakeOnly = 0x1 // WakeOnly service +} AuthRecordFlags; struct AuthRecord_struct - { - // For examples of how to set up this structure for use in mDNS_Register(), - // see mDNS_AdvertiseInterface() or mDNS_RegisterService(). - // Basically, resrec and persistent metadata need to be set up before calling mDNS_Register(). - // mDNS_SetupResourceRecord() is avaliable as a helper routine to set up most fields to sensible default values for you - - AuthRecord *next; // Next in list; first element of structure for efficiency reasons - // Field Group 1: Common ResourceRecord fields - ResourceRecord resrec; - uDNS_RegInfo uDNS_info; - - // Field Group 2: Persistent metadata for Authoritative Records - AuthRecord *Additional1; // Recommended additional record to include in response - AuthRecord *Additional2; // Another additional - AuthRecord *DependentOn; // This record depends on another for its uniqueness checking - AuthRecord *RRSet; // This unique record is part of an RRSet - mDNSRecordCallback *RecordCallback; // Callback function to call for state changes, and to free memory asynchronously on deregistration - void *RecordContext; // Context parameter for the callback function - mDNSu8 HostTarget; // Set if the target of this record (PTR, CNAME, SRV, etc.) is our host name - mDNSu8 AllowRemoteQuery; // Set if we allow hosts not on the local link to query this record - mDNSu8 ForceMCast; // Set by client to advertise solely via multicast, even for apparently unicast names - - // Field Group 3: Transient state for Authoritative Records - mDNSu8 Acknowledged; // Set if we've given the success callback to the client - mDNSu8 ProbeCount; // Number of probes remaining before this record is valid (kDNSRecordTypeUnique) - mDNSu8 AnnounceCount; // Number of announcements remaining (kDNSRecordTypeShared) - mDNSu8 RequireGoodbye; // Set if this RR has been announced on the wire and will require a goodbye packet - mDNSu8 LocalAnswer; // Set if this RR has been delivered to LocalOnly questions - mDNSu8 IncludeInProbe; // Set if this RR is being put into a probe right now - mDNSInterfaceID ImmedAnswer; // Someone on this interface issued a query we need to answer (all-ones for all interfaces) - mDNSu8 ImmedUnicast; // Set if we may send our response directly via unicast to the requester +{ + // For examples of how to set up this structure for use in mDNS_Register(), + // see mDNS_AdvertiseInterface() or mDNS_RegisterService(). + // Basically, resrec and persistent metadata need to be set up before calling mDNS_Register(). + // mDNS_SetupResourceRecord() is avaliable as a helper routine to set up most fields to sensible default values for you + + AuthRecord *next; // Next in list; first element of structure for efficiency reasons + // Field Group 1: Common ResourceRecord fields + ResourceRecord resrec; // 36 bytes when compiling for 32-bit; 48 when compiling for 64-bit + + // Field Group 2: Persistent metadata for Authoritative Records + AuthRecord *Additional1; // Recommended additional record to include in response (e.g. SRV for PTR record) + AuthRecord *Additional2; // Another additional (e.g. TXT for PTR record) + AuthRecord *DependentOn; // This record depends on another for its uniqueness checking + AuthRecord *RRSet; // This unique record is part of an RRSet + mDNSRecordCallback *RecordCallback; // Callback function to call for state changes, and to free memory asynchronously on deregistration + void *RecordContext; // Context parameter for the callback function + mDNSu8 AutoTarget; // Set if the target of this record (PTR, CNAME, SRV, etc.) is our host name + mDNSu8 AllowRemoteQuery; // Set if we allow hosts not on the local link to query this record + mDNSu8 ForceMCast; // Set by client to advertise solely via multicast, even for apparently unicast names + mDNSu8 AuthFlags; + + OwnerOptData WakeUp; // WakeUp.HMAC.l[0] nonzero indicates that this is a Sleep Proxy record + mDNSAddr AddressProxy; // For reverse-mapping Sleep Proxy PTR records, address in question + mDNSs32 TimeRcvd; // In platform time units + mDNSs32 TimeExpire; // In platform time units + AuthRecType ARType; // LocalOnly, P2P or Normal ? + mDNSs32 KATimeExpire; // In platform time units: time to send keepalive packet for the proxy record + + // Field Group 3: Transient state for Authoritative Records + mDNSu8 Acknowledged; // Set if we've given the success callback to the client + mDNSu8 ProbeRestartCount; // Number of times we have restarted probing + mDNSu8 ProbeCount; // Number of probes remaining before this record is valid (kDNSRecordTypeUnique) + mDNSu8 AnnounceCount; // Number of announcements remaining (kDNSRecordTypeShared) + mDNSu8 RequireGoodbye; // Set if this RR has been announced on the wire and will require a goodbye packet + mDNSu8 AnsweredLocalQ; // Set if this AuthRecord has been delivered to any local question (LocalOnly or mDNSInterface_Any) + mDNSu8 IncludeInProbe; // Set if this RR is being put into a probe right now + mDNSu8 ImmedUnicast; // Set if we may send our response directly via unicast to the requester + mDNSInterfaceID SendNSECNow; // Set if we need to generate associated NSEC data for this rrname + mDNSInterfaceID ImmedAnswer; // Someone on this interface issued a query we need to answer (all-ones for all interfaces) #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES - mDNSs32 ImmedAnswerMarkTime; + mDNSs32 ImmedAnswerMarkTime; #endif - mDNSInterfaceID ImmedAdditional; // Hint that we might want to also send this record, just to be helpful - mDNSInterfaceID SendRNow; // The interface this query is being sent on right now - mDNSv4Addr v4Requester; // Recent v4 query for this record, or all-ones if more than one recent query - mDNSv6Addr v6Requester; // Recent v6 query for this record, or all-ones if more than one recent query - AuthRecord *NextResponse; // Link to the next element in the chain of responses to generate - const mDNSu8 *NR_AnswerTo; // Set if this record was selected by virtue of being a direct answer to a question - AuthRecord *NR_AdditionalTo; // Set if this record was selected by virtue of being additional to another - mDNSs32 ThisAPInterval; // In platform time units: Current interval for announce/probe - mDNSs32 AnnounceUntil; // In platform time units: Creation time + TTL - mDNSs32 LastAPTime; // In platform time units: Last time we sent announcement/probe - mDNSs32 LastMCTime; // Last time we multicast this record (used to guard against packet-storm attacks) - mDNSInterfaceID LastMCInterface; // Interface this record was multicast on at the time LastMCTime was recorded - RData *NewRData; // Set if we are updating this record with new rdata - mDNSu16 newrdlength; // ... and the length of the new RData - mDNSRecordUpdateCallback *UpdateCallback; - mDNSu32 UpdateCredits; // Token-bucket rate limiting of excessive updates - mDNSs32 NextUpdateCredit; // Time next token is added to bucket - mDNSs32 UpdateBlocked; // Set if update delaying is in effect - - domainname namestorage; - RData rdatastorage; // Normally the storage is right here, except for oversized records - // rdatastorage MUST be the last thing in the structure -- when using oversized AuthRecords, extra bytes - // are appended after the end of the AuthRecord, logically augmenting the size of the rdatastorage - // DO NOT ADD ANY MORE FIELDS HERE - }; + mDNSInterfaceID ImmedAdditional; // Hint that we might want to also send this record, just to be helpful + mDNSInterfaceID SendRNow; // The interface this query is being sent on right now + mDNSv4Addr v4Requester; // Recent v4 query for this record, or all-ones if more than one recent query + mDNSv6Addr v6Requester; // Recent v6 query for this record, or all-ones if more than one recent query + AuthRecord *NextResponse; // Link to the next element in the chain of responses to generate + const mDNSu8 *NR_AnswerTo; // Set if this record was selected by virtue of being a direct answer to a question + AuthRecord *NR_AdditionalTo; // Set if this record was selected by virtue of being additional to another + mDNSs32 ThisAPInterval; // In platform time units: Current interval for announce/probe + mDNSs32 LastAPTime; // In platform time units: Last time we sent announcement/probe + mDNSs32 LastMCTime; // Last time we multicast this record (used to guard against packet-storm attacks) + mDNSInterfaceID LastMCInterface; // Interface this record was multicast on at the time LastMCTime was recorded + RData *NewRData; // Set if we are updating this record with new rdata + mDNSu16 newrdlength; // ... and the length of the new RData + mDNSRecordUpdateCallback *UpdateCallback; + mDNSu32 UpdateCredits; // Token-bucket rate limiting of excessive updates + mDNSs32 NextUpdateCredit; // Time next token is added to bucket + mDNSs32 UpdateBlocked; // Set if update delaying is in effect + + // Field Group 4: Transient uDNS state for Authoritative Records + regState_t state; // Maybe combine this with resrec.RecordType state? Right now it's ambiguous and confusing. + // e.g. rr->resrec.RecordType can be kDNSRecordTypeUnregistered, + // and rr->state can be regState_Unregistered + // What if we find one of those statements is true and the other false? What does that mean? + mDNSBool uselease; // dynamic update contains (should contain) lease option + mDNSs32 expire; // In platform time units: expiration of lease (-1 for static) + mDNSBool Private; // If zone is private, DNS updates may have to be encrypted to prevent eavesdropping + mDNSOpaque16 updateid; // Identifier to match update request and response -- also used when transferring records to Sleep Proxy + mDNSOpaque64 updateIntID; // Interface IDs (one bit per interface index)to which updates have been sent + const domainname *zone; // the zone that is updated + ZoneData *nta; + struct tcpInfo_t *tcp; + NATTraversalInfo NATinfo; + mDNSBool SRVChanged; // temporarily deregistered service because its SRV target or port changed + mergeState_t mState; // Unicast Record Registrations merge state + mDNSu8 refreshCount; // Number of refreshes to the server + mStatus updateError; // Record update resulted in Error ? + + // uDNS_UpdateRecord support fields + // Do we really need all these in *addition* to NewRData and newrdlength above? + void *UpdateContext; // Context parameter for the update callback function + mDNSu16 OrigRDLen; // previously registered, being deleted + mDNSu16 InFlightRDLen; // currently being registered + mDNSu16 QueuedRDLen; // pending operation (re-transmitting if necessary) THEN register the queued update + RData *OrigRData; + RData *InFlightRData; + RData *QueuedRData; + + // Field Group 5: Large data objects go at the end + domainname namestorage; + RData rdatastorage; // Normally the storage is right here, except for oversized records + // rdatastorage MUST be the last thing in the structure -- when using oversized AuthRecords, extra bytes + // are appended after the end of the AuthRecord, logically augmenting the size of the rdatastorage + // DO NOT ADD ANY MORE FIELDS HERE +}; + +// IsLocalDomain alone is not sufficient to determine that a record is mDNS or uDNS. By default domain names within +// the "local" pseudo-TLD (and within the IPv4 and IPv6 link-local reverse mapping domains) are automatically treated +// as mDNS records, but it is also possible to force any record (even those not within one of the inherently local +// domains) to be handled as an mDNS record by setting the ForceMCast flag, or by setting a non-zero InterfaceID. +// For example, the reverse-mapping PTR record created in AdvertiseInterface sets the ForceMCast flag, since it points to +// a dot-local hostname, and therefore it would make no sense to register this record with a wide-area Unicast DNS server. +// The same applies to Sleep Proxy records, which we will answer for when queried via mDNS, but we never want to try +// to register them with a wide-area Unicast DNS server -- and we probably don't have the required credentials anyway. +// Currently we have no concept of a wide-area uDNS record scoped to a particular interface, so if the InterfaceID is +// nonzero we treat this the same as ForceMCast. +// Note: Question_uDNS(Q) is used in *only* one place -- on entry to mDNS_StartQuery_internal, to decide whether to set TargetQID. +// Everywhere else in the code, the determination of whether a question is unicast is made by checking to see if TargetQID is nonzero. +#define AuthRecord_uDNS(R) ((R)->resrec.InterfaceID == mDNSInterface_Any && !(R)->ForceMCast && !IsLocalDomain((R)->resrec.name)) +#define Question_uDNS(Q) ((Q)->InterfaceID == mDNSInterface_Unicast || (Q)->ProxyQuestion || \ + ((Q)->InterfaceID != mDNSInterface_LocalOnly && (Q)->InterfaceID != mDNSInterface_P2P && !(Q)->ForceMCast && !IsLocalDomain(&(Q)->qname))) + +#define RRLocalOnly(rr) ((rr)->ARType == AuthRecordLocalOnly || (rr)->ARType == AuthRecordP2P) + +#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 +// is not available locally for A or AAAA question respectively. Also, if the +// query is disallowed for the "pid" that we are sending on behalf of, suppress it. +#define QuerySuppressed(Q) (((Q)->SuppressUnusable && (Q)->SuppressQuery) || ((Q)->DisallowPID)) + +#define PrivateQuery(Q) ((Q)->AuthInfo && (Q)->AuthInfo->AutoTunnel) + +// Normally we always lookup the cache and /etc/hosts before sending the query on the wire. For single label +// queries (A and AAAA) that are unqualified (indicated by AppendSearchDomains), we want to append search +// domains before we try them as such +#define ApplySearchDomainsFirst(q) ((q)->AppendSearchDomains && (CountLabels(&((q)->qname))) == 1) // Wrapper struct for Auth Records for higher-level code that cannot use the AuthRecord's ->next pointer field typedef struct ARListElem - { - struct ARListElem *next; - AuthRecord ar; // Note: Must be last struct in field to accomodate oversized AuthRecords - } ARListElem; - -struct CacheGroup_struct // Header object for a list of CacheRecords with the same name - { - CacheGroup *next; // Next CacheGroup object in this hash table bucket - mDNSu32 namehash; // Name-based (i.e. case insensitive) hash of name - CacheRecord *members; // List of CacheRecords with this same name - CacheRecord **rrcache_tail; // Tail end of that list - domainname *name; // Common name for all CacheRecords in this list - mDNSu8 namestorage[InlineCacheGroupNameSize]; - }; +{ + struct ARListElem *next; + AuthRecord ar; // Note: Must be last element of structure, to accomodate oversized AuthRecords +} ARListElem; struct CacheRecord_struct - { - CacheRecord *next; // Next in list; first element of structure for efficiency reasons - ResourceRecord resrec; - - // Transient state for Cache Records - CacheRecord *NextInKAList; // Link to the next element in the chain of known answers to send - mDNSs32 TimeRcvd; // In platform time units - mDNSs32 DelayDelivery; // Set if we want to defer delivery of this answer to local clients - mDNSs32 NextRequiredQuery; // In platform time units - mDNSs32 LastUsed; // In platform time units - DNSQuestion *CRActiveQuestion; // Points to an active question referencing this answer - mDNSu32 UnansweredQueries; // Number of times we've issued a query for this record without getting an answer - mDNSs32 LastUnansweredTime; // In platform time units; last time we incremented UnansweredQueries - mDNSu32 MPUnansweredQ; // Multi-packet query handling: Number of times we've seen a query for this record - mDNSs32 MPLastUnansweredQT; // Multi-packet query handling: Last time we incremented MPUnansweredQ - mDNSu32 MPUnansweredKA; // Multi-packet query handling: Number of times we've seen this record in a KA list - mDNSBool MPExpectingKA; // Multi-packet query handling: Set when we increment MPUnansweredQ; allows one KA - CacheRecord *NextInCFList; // Set if this is in the list of records we just received with the cache flush bit set - - struct { mDNSu16 MaxRDLength; mDNSu8 data[InlineCacheRDSize]; } rdatastorage; // Storage for small records is right here - }; +{ + CacheRecord *next; // Next in list; first element of structure for efficiency reasons + ResourceRecord resrec; // 36 bytes when compiling for 32-bit; 48 when compiling for 64-bit + + // Transient state for Cache Records + CacheRecord *NextInKAList; // Link to the next element in the chain of known answers to send + mDNSs32 TimeRcvd; // In platform time units + mDNSs32 DelayDelivery; // Set if we want to defer delivery of this answer to local clients + mDNSs32 NextRequiredQuery; // In platform time units + mDNSs32 LastUsed; // In platform time units + DNSQuestion *CRActiveQuestion; // Points to an active question referencing this answer. Can never point to a NewQuestion. + mDNSs32 LastUnansweredTime; // In platform time units; last time we incremented UnansweredQueries + mDNSu8 UnansweredQueries; // Number of times we've issued a query for this record without getting an answer + mDNSu8 CRDNSSECQuestion; // Set to 1 if this was created in response to a DNSSEC question + mDNSOpaque16 responseFlags; // Second 16 bit in the DNS response +#if ENABLE_MULTI_PACKET_QUERY_SNOOPING + mDNSu32 MPUnansweredQ; // Multi-packet query handling: Number of times we've seen a query for this record + mDNSs32 MPLastUnansweredQT; // Multi-packet query handling: Last time we incremented MPUnansweredQ + mDNSu32 MPUnansweredKA; // Multi-packet query handling: Number of times we've seen this record in a KA list + mDNSBool MPExpectingKA; // Multi-packet query handling: Set when we increment MPUnansweredQ; allows one KA +#endif + CacheRecord *NextInCFList; // Set if this is in the list of records we just received with the cache flush bit set + CacheRecord *nsec; // NSEC records needed for non-existence proofs + CacheRecord *soa; // SOA record to return for proxy questions + + mDNSAddr sourceAddress; // node from which we received this record + // Size to here is 76 bytes when compiling 32-bit; 104 bytes when compiling 64-bit + RData_small smallrdatastorage; // Storage for small records is right here (4 bytes header + 68 bytes data = 72 bytes) +}; + +// Should match the CacheGroup_struct members, except namestorage[]. Only used to calculate +// the size of the namestorage array in CacheGroup_struct so that +// sizeof(CacheGroup) == sizeof(CacheRecord) +struct CacheGroup_base +{ + CacheGroup *next; + mDNSu32 namehash; + CacheRecord *members; + CacheRecord **rrcache_tail; + domainname *name; +}; + +struct CacheGroup_struct // Header object for a list of CacheRecords with the same name +{ + CacheGroup *next; // Next CacheGroup object in this hash table bucket + mDNSu32 namehash; // Name-based (i.e. case insensitive) hash of name + CacheRecord *members; // List of CacheRecords with this same name + CacheRecord **rrcache_tail; // Tail end of that list + domainname *name; // Common name for all CacheRecords in this list + mDNSu8 namestorage[sizeof(CacheRecord) - sizeof(struct CacheGroup_base)]; // match sizeof(CacheRecord) +}; // Storage sufficient to hold either a CacheGroup header or a CacheRecord +// -- for best efficiency (to avoid wasted unused storage) they should be the same size typedef union CacheEntity_union CacheEntity; union CacheEntity_union { CacheEntity *next; CacheGroup cg; CacheRecord cr; }; typedef struct - { - CacheRecord r; - mDNSu8 _extradata[MaximumRDSize-InlineCacheRDSize]; // Glue on the necessary number of extra bytes - domainname namestorage; // Needs to go *after* the extra rdata bytes - } LargeCacheRecord; - -typedef struct uDNS_HostnameInfo - { - struct uDNS_HostnameInfo *next; +{ + CacheRecord r; + mDNSu8 _extradata[MaximumRDSize-InlineCacheRDSize]; // Glue on the necessary number of extra bytes + domainname namestorage; // Needs to go *after* the extra rdata bytes +} LargeCacheRecord; + +typedef struct HostnameInfo +{ + struct HostnameInfo *next; + NATTraversalInfo natinfo; domainname fqdn; - AuthRecord *arv4; // registered IPv4 address record - AuthRecord *arv6; // registered IPv6 address record - mDNSRecordCallback *StatusCallback; // callback to deliver success or error code to client layer - const void *StatusContext; // Client Context - } uDNS_HostnameInfo; - -enum - { - DNSServer_Untested = 0, - DNSServer_Failed = 1, - DNSServer_Passed = 2 - }; - -typedef struct DNSServer - { - struct DNSServer *next; - mDNSAddr addr; - mDNSBool del; // Set when we're planning to delete this from the list - mDNSu32 teststate; // Have we sent bug-detection query to this server? - domainname domain; // name->server matching for "split dns" - } DNSServer; - -typedef struct NetworkInterfaceInfo_struct NetworkInterfaceInfo; - -// A NetworkInterfaceInfo_struct serves two purposes: -// 1. It holds the address, PTR and HINFO records to advertise a given IP address on a given physical interface -// 2. It tells mDNSCore which physical interfaces are available; each physical interface has its own unique InterfaceID. -// Since there may be multiple IP addresses on a single physical interface, -// there may be multiple NetworkInterfaceInfo_structs with the same InterfaceID. -// In this case, to avoid sending the same packet n times, when there's more than one -// struct with the same InterfaceID, mDNSCore picks one member of the set to be the -// active representative of the set; all others have the 'InterfaceActive' flag unset. - -struct NetworkInterfaceInfo_struct - { - // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them. - NetworkInterfaceInfo *next; - - mDNSBool InterfaceActive; // Set if interface is sending & receiving packets (see comment above) - mDNSBool IPv4Available; // If InterfaceActive, set if v4 available on this InterfaceID - mDNSBool IPv6Available; // If InterfaceActive, set if v6 available on this InterfaceID - - // Standard AuthRecords that every Responder host should have (one per active IP address) - AuthRecord RR_A; // 'A' or 'AAAA' (address) record for our ".local" name - AuthRecord RR_PTR; // PTR (reverse lookup) record - AuthRecord RR_HINFO; - - // Client API fields: The client must set up these fields *before* calling mDNS_RegisterInterface() - mDNSInterfaceID InterfaceID; // Identifies physical interface; MUST NOT be 0, -1, or -2 - mDNSAddr ip; // The IPv4 or IPv6 address to advertise - mDNSAddr mask; - char ifname[64]; // Windows uses a GUID string for the interface name, which doesn't fit in 16 bytes - mDNSBool Advertise; // False if you are only searching on this interface - mDNSBool McastTxRx; // Send/Receive multicast on this { InterfaceID, address family } ? - }; + AuthRecord arv4; // registered IPv4 address record + AuthRecord arv6; // registered IPv6 address record + mDNSRecordCallback *StatusCallback; // callback to deliver success or error code to client layer + const void *StatusContext; // Client Context +} HostnameInfo; typedef struct ExtraResourceRecord_struct ExtraResourceRecord; struct ExtraResourceRecord_struct - { - ExtraResourceRecord *next; +{ + ExtraResourceRecord *next; mDNSu32 ClientID; // Opaque ID field to be used by client to map an AddRecord call to a set of Extra records - AuthRecord r; - // Note: Add any additional fields *before* the AuthRecord in this structure, not at the end. - // In some cases clients can allocate larger chunks of memory and set r->rdata->MaxRDLength to indicate - // that this extra memory is available, which would result in any fields after the AuthRecord getting smashed - }; + AuthRecord r; + // Note: Add any additional fields *before* the AuthRecord in this structure, not at the end. + // In some cases clients can allocate larger chunks of memory and set r->rdata->MaxRDLength to indicate + // that this extra memory is available, which would result in any fields after the AuthRecord getting smashed +}; + +// Note: Within an mDNSServiceCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute() +typedef void mDNSServiceCallback (mDNS *const m, ServiceRecordSet *const sr, mStatus result); + +// A ServiceRecordSet has no special meaning to the core code of the Multicast DNS protocol engine; +// it is just a convenience structure to group together the records that make up a standard service +// registration so that they can be allocted and deallocted together as a single memory object. +// It contains its own ServiceCallback+ServiceContext to report aggregate results up to the next layer of software above. +// It also contains: +// * the basic PTR/SRV/TXT triplet used to represent any DNS-SD service +// * the "_services" PTR record for service enumeration +// * the optional list of SubType PTR records +// * the optional list of additional records attached to the service set (e.g. iChat pictures) -// Note: Within an mDNSServiceCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute() -typedef struct ServiceRecordSet_struct ServiceRecordSet; -typedef void mDNSServiceCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result); struct ServiceRecordSet_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_RegisterService(); - // all required data is passed as parameters to that function. - ServiceRecordSet *next; - uDNS_RegInfo uDNS_info; - mDNSServiceCallback *ServiceCallback; - void *ServiceContext; - ExtraResourceRecord *Extras; // Optional list of extra AuthRecords attached to this service registration - mDNSu32 NumSubTypes; - AuthRecord *SubTypes; - mDNSBool Conflict; // Set if this record set was forcibly deregistered because of a conflict - domainname Host; // Set if this service record does not use the standard target host name - AuthRecord RR_ADV; // e.g. _services._dns-sd._udp.local. PTR _printer._tcp.local. - AuthRecord RR_PTR; // e.g. _printer._tcp.local. PTR Name._printer._tcp.local. - AuthRecord RR_SRV; // e.g. Name._printer._tcp.local. SRV 0 0 port target - AuthRecord RR_TXT; // e.g. Name._printer._tcp.local. TXT PrintQueueName - // Don't add any fields after AuthRecord RR_TXT. - // This is where the implicit extra space goes if we allocate a ServiceRecordSet containing an oversized RR_TXT record - }; +{ + // These internal state fields 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_RegisterService(); + // all required data is passed as parameters to that function. + mDNSServiceCallback *ServiceCallback; + void *ServiceContext; + mDNSBool Conflict; // Set if this record set was forcibly deregistered because of a conflict + + ExtraResourceRecord *Extras; // Optional list of extra AuthRecords attached to this service registration + mDNSu32 NumSubTypes; + AuthRecord *SubTypes; + const mDNSu8 *AnonData; + mDNSu32 flags; // saved for subsequent calls to mDNS_RegisterService() if records + // need to be re-registered. + AuthRecord RR_ADV; // e.g. _services._dns-sd._udp.local. PTR _printer._tcp.local. + AuthRecord RR_PTR; // e.g. _printer._tcp.local. PTR Name._printer._tcp.local. + AuthRecord RR_SRV; // e.g. Name._printer._tcp.local. SRV 0 0 port target + AuthRecord RR_TXT; // e.g. Name._printer._tcp.local. TXT PrintQueueName + // Don't add any fields after AuthRecord RR_TXT. + // This is where the implicit extra space goes if we allocate a ServiceRecordSet containing an oversized RR_TXT record +}; // *************************************************************************** #if 0 +#pragma mark - #pragma mark - Question structures #endif // We record the last eight instances of each duplicate query -// This gives us v4/v6 on each of Ethernet/AirPort and Firewire, and two free slots "for future expansion" +// This gives us v4/v6 on each of Ethernet, AirPort and Firewire, and two free slots "for future expansion" // If the host has more active interfaces that this it is not fatal -- duplicate question suppression will degrade gracefully. // Since we will still remember the last eight, the busiest interfaces will still get the effective duplicate question suppression. #define DupSuppressInfoSize 8 typedef struct - { - mDNSs32 Time; - mDNSInterfaceID InterfaceID; - mDNSs32 Type; // v4 or v6? - } DupSuppressInfo; +{ + mDNSs32 Time; + mDNSInterfaceID InterfaceID; + mDNSs32 Type; // v4 or v6? +} DupSuppressInfo; typedef enum - { - // Setup states - LLQ_UnInit = 0, - LLQ_GetZoneInfo = 1, - LLQ_InitialRequest = 2, - LLQ_SecondaryRequest = 3, - LLQ_Refresh = 4, - LLQ_Retry = 5, - LLQ_Established = 6, - LLQ_Suspended = 7, - LLQ_SuspendDeferred = 8, // suspend once we get zone info - LLQ_SuspendedPoll = 9, // suspended from polling state - LLQ_NatMapWait = 10, - - // Established/error states - LLQ_Static = 16, - LLQ_Poll = 17, - LLQ_Error = 18, - LLQ_Cancelled = 19 - } LLQ_State; - -typedef struct - { - LLQ_State state; - mDNSAddr servAddr; - mDNSIPPort servPort; - DNSQuestion *question; - mDNSu32 origLease; // seconds (relative) - mDNSs32 retry; // ticks (absolute) - mDNSs32 expire; // ticks (absolute) - mDNSs16 ntries; - mDNSu8 id[8]; - mDNSBool deriveRemovesOnResume; - mDNSBool NATMap; // does this LLQ use the global LLQ NAT mapping? - } LLQ_Info; +{ + LLQ_InitialRequest = 1, + LLQ_SecondaryRequest = 2, + LLQ_Established = 3, + LLQ_Poll = 4 +} LLQ_State; // LLQ constants -#define kDNSOpt_LLQ 1 -#define kDNSOpt_Lease 2 #define kLLQ_Vers 1 #define kLLQ_DefLease 7200 // 2 hours #define kLLQ_MAX_TRIES 3 // retry an operation 3 times max #define kLLQ_INIT_RESEND 2 // resend an un-ack'd packet after 2 seconds, then double for each additional -#define kLLQ_DEF_RETRY 1800 // retry a failed operation after 30 minutes // LLQ Operation Codes #define kLLQOp_Setup 1 #define kLLQOp_Refresh 2 #define kLLQOp_Event 3 -#define LLQ_OPT_RDLEN ((2 * sizeof(mDNSu16)) + LLQ_OPTLEN) -#define LEASE_OPT_RDLEN (2 * sizeof(mDNSu16)) + sizeof(mDNSs32) - // LLQ Errror Codes enum - { - LLQErr_NoError = 0, - LLQErr_ServFull = 1, - LLQErr_Static = 2, - LLQErr_FormErr = 3, - LLQErr_NoSuchLLQ = 4, - LLQErr_BadVers = 5, - LLQErr_UnknownErr = 6 - }; - -typedef void (*InternalResponseHndlr)(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *internalContext); -typedef struct - { - mDNSOpaque16 id; - mDNSBool internal; - InternalResponseHndlr responseCallback; // NULL if internal field is false - LLQ_Info *llq; // NULL for 1-shot queries - mDNSBool Answered; // have we received an answer (including NXDOMAIN) for this question? - CacheRecord *knownAnswers; - mDNSs32 RestartTime; // Mark when we restart a suspended query - void *context; - } uDNS_QuestionInfo; - -// Note: Within an mDNSQuestionCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute() -typedef void mDNSQuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord); +{ + LLQErr_NoError = 0, + LLQErr_ServFull = 1, + LLQErr_Static = 2, + LLQErr_FormErr = 3, + LLQErr_NoSuchLLQ = 4, + LLQErr_BadVers = 5, + LLQErr_UnknownErr = 6 +}; + +enum { NoAnswer_Normal = 0, NoAnswer_Suspended = 1, NoAnswer_Fail = 2 }; + +#define HMAC_LEN 64 +#define HMAC_IPAD 0x36 +#define HMAC_OPAD 0x5c +#define MD5_LEN 16 + +#define AutoTunnelUnregistered(X) ( \ + (X)->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered && \ + (X)->AutoTunnelTarget.resrec.RecordType == kDNSRecordTypeUnregistered && \ + (X)->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered && \ + (X)->AutoTunnelService.resrec.RecordType == kDNSRecordTypeUnregistered && \ + (X)->AutoTunnel6Record.resrec.RecordType == kDNSRecordTypeUnregistered ) + +// Internal data structure to maintain authentication information +typedef struct DomainAuthInfo +{ + struct DomainAuthInfo *next; + mDNSs32 deltime; // If we're planning to delete this DomainAuthInfo, the time we want it deleted + mDNSBool AutoTunnel; // Whether this is AutoTunnel + AuthRecord AutoTunnelHostRecord; // User-visible hostname; used as SRV target for AutoTunnel services + AuthRecord AutoTunnelTarget; // Opaque hostname of tunnel endpoint; used as SRV target for AutoTunnelService record + AuthRecord AutoTunnelDeviceInfo; // Device info of tunnel endpoint + AuthRecord AutoTunnelService; // Service record (possibly NAT-Mapped) of IKE daemon implementing tunnel endpoint + AuthRecord AutoTunnel6Record; // AutoTunnel AAAA Record obtained from awacsd + mDNSBool AutoTunnelServiceStarted; // Whether a service has been registered in this domain + mDNSv6Addr AutoTunnelInnerAddress; + domainname domain; + domainname keyname; + domainname hostname; + mDNSIPPort port; + char b64keydata[32]; + mDNSu8 keydata_ipad[HMAC_LEN]; // padded key for inner hash rounds + mDNSu8 keydata_opad[HMAC_LEN]; // padded key for outer hash rounds +} DomainAuthInfo; + +// Note: Within an mDNSQuestionCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute() +// Note: Any value other than QC_rmv i.e., any non-zero value will result in kDNSServiceFlagsAdd to the application +// layer. These values are used within mDNSResponder and not sent across to the application. QC_addnocache is for +// delivering a response without adding to the cache. QC_forceresponse is superset of QC_addnocache where in +// addition to not entering in the cache, it also forces the negative response through. +typedef enum { QC_rmv = 0, QC_add, QC_addnocache, QC_forceresponse, QC_dnssec , QC_nodnssec, QC_suppressed } QC_result; +typedef void mDNSQuestionCallback (mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord); +typedef void AsyncDispatchFunc(mDNS *const m, void *context); +typedef void DNSSECAuthInfoFreeCallback(mDNS *const m, void *context); +extern void mDNSPlatformDispatchAsync(mDNS *const m, void *context, AsyncDispatchFunc func); + +#define NextQSendTime(Q) ((Q)->LastQTime + (Q)->ThisQInterval) +#define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf) +#define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - NextQSendTime(Q) >= 0) + +// q->ValidationStatus is either DNSSECValNotRequired or DNSSECValRequired and then moves onto DNSSECValInProgress. +// When Validation is done, we mark all "DNSSECValInProgress" questions "DNSSECValDone". If we are answering +// questions from /etc/hosts, then we go straight to DNSSECValDone from the initial state. +typedef enum { DNSSECValNotRequired = 0, DNSSECValRequired, DNSSECValInProgress, DNSSECValDone } DNSSECValState; + +// ValidationRequired can be set to the following values: +// +// SECURE validation is set to determine whether something is secure or bogus +// INSECURE validation is set internally by dnssec code to indicate that it is currently proving something +// is insecure +#define DNSSEC_VALIDATION_NONE 0x00 +#define DNSSEC_VALIDATION_SECURE 0x01 +#define DNSSEC_VALIDATION_SECURE_OPTIONAL 0x02 +#define DNSSEC_VALIDATION_INSECURE 0x03 + +// For both ValidationRequired and ValidatingResponse question, we validate DNSSEC responses. +// For ProxyQuestion with DNSSECOK, we just receive the DNSSEC records to pass them along without +// validation and if the CD bit is not set, we also validate. +#define DNSSECQuestion(q) ((q)->ValidationRequired || (q)->ValidatingResponse || ((q)->ProxyQuestion && (q)->ProxyDNSSECOK)) + +// ValidatingQuestion is used when we need to know whether we are validating the DNSSEC responses for a question +#define ValidatingQuestion(q) ((q)->ValidationRequired || (q)->ValidatingResponse) + +#define DNSSECOptionalQuestion(q) ((q)->ValidationRequired == DNSSEC_VALIDATION_SECURE_OPTIONAL) + +// Given the resource record and the question, should we follow the CNAME ? +#define FollowCNAME(q, rr, AddRecord) (AddRecord && (q)->qtype != kDNSType_CNAME && \ + (rr)->RecordType != kDNSRecordTypePacketNegative && \ + (rr)->rrtype == kDNSType_CNAME) + +// RFC 4122 defines it to be 16 bytes +#define UUID_SIZE 16 + struct DNSQuestion_struct - { - // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them. - DNSQuestion *next; - mDNSu32 qnamehash; - mDNSs32 DelayAnswering; // Set if we want to defer answering this question until the cache settles - mDNSs32 LastQTime; // Last scheduled transmission of this Q on *all* applicable interfaces - mDNSs32 ThisQInterval; // LastQTime + ThisQInterval is the next scheduled transmission of this Q - // ThisQInterval > 0 for an active question; - // ThisQInterval = 0 for a suspended question that's still in the list - // ThisQInterval = -1 for a cancelled question that's been removed from the list - mDNSs32 LastAnswerPktNum; // The sequence number of the last response packet containing an answer to this Q - mDNSu32 RecentAnswerPkts; // Number of answers since the last time we sent this query - mDNSu32 CurrentAnswers; // Number of records currently in the cache that answer this question - mDNSu32 LargeAnswers; // Number of answers with rdata > 1024 bytes - mDNSu32 UniqueAnswers; // Number of answers received with kDNSClass_UniqueRRSet bit set - DNSQuestion *DuplicateOf; - DNSQuestion *NextInDQList; - DupSuppressInfo DupSuppress[DupSuppressInfoSize]; - mDNSInterfaceID SendQNow; // The interface this query is being sent on right now - mDNSBool SendOnAll; // Set if we're sending this question on all active interfaces - mDNSu32 RequestUnicast; // Non-zero if we want to send query with kDNSQClass_UnicastResponse bit set - mDNSs32 LastQTxTime; // Last time this Q was sent on one (but not necessarily all) interfaces - uDNS_QuestionInfo uDNS_info; - - // 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 - mDNSAddr Target; // Non-zero if you want to direct queries to a specific unicast target address - mDNSIPPort TargetPort; // Must be set if Target is set - mDNSOpaque16 TargetQID; // Must be set if Target is set - domainname qname; - mDNSu16 qtype; - mDNSu16 qclass; - mDNSBool LongLived; // Set by client for calls to mDNS_StartQuery to indicate LLQs to unicast layer. - mDNSBool ExpectUnique; // Set by client if it's expecting unique RR(s) for this question, not shared RRs - mDNSBool ForceMCast; // Set by client to force mDNS query, even for apparently uDNS names - mDNSQuestionCallback *QuestionCallback; - void *QuestionContext; - }; +{ + // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them. + DNSQuestion *next; + mDNSu32 qnamehash; + mDNSs32 DelayAnswering; // Set if we want to defer answering this question until the cache settles + mDNSs32 LastQTime; // Last scheduled transmission of this Q on *all* applicable interfaces + mDNSs32 ThisQInterval; // LastQTime + ThisQInterval is the next scheduled transmission of this Q + // ThisQInterval > 0 for an active question; + // ThisQInterval = 0 for a suspended question that's still in the list + // ThisQInterval = -1 for a cancelled question (should not still be in list) + mDNSs32 ExpectUnicastResp; // Set when we send a query with the kDNSQClass_UnicastResponse bit set + mDNSs32 LastAnswerPktNum; // The sequence number of the last response packet containing an answer to this Q + mDNSu32 RecentAnswerPkts; // Number of answers since the last time we sent this query + mDNSu32 CurrentAnswers; // Number of records currently in the cache that answer this question + mDNSu32 BrowseThreshold; // If we have received at least this number of answers, + // set the next question interval to MaxQuestionInterval + mDNSu32 LargeAnswers; // Number of answers with rdata > 1024 bytes + mDNSu32 UniqueAnswers; // Number of answers received with kDNSClass_UniqueRRSet bit set + mDNSInterfaceID FlappingInterface1; // Set when an interface goes away, to flag if remove events are delivered for this Q + mDNSInterfaceID FlappingInterface2; // Set when an interface goes away, to flag if remove events are delivered for this Q + DomainAuthInfo *AuthInfo; // Non-NULL if query is currently being done using Private DNS + DNSQuestion *DuplicateOf; + DNSQuestion *NextInDQList; + AnonymousInfo *AnonInfo; // Anonymous Information + DupSuppressInfo DupSuppress[DupSuppressInfoSize]; + mDNSInterfaceID SendQNow; // The interface this query is being sent on right now + mDNSBool SendOnAll; // Set if we're sending this question on all active interfaces + mDNSBool CachedAnswerNeedsUpdate; // See SendQueries(). Set if we're sending this question + // because a cached answer needs to be refreshed. + mDNSu32 RequestUnicast; // Non-zero if we want to send query with kDNSQClass_UnicastResponse bit set + mDNSs32 LastQTxTime; // Last time this Q was sent on one (but not necessarily all) interfaces + mDNSu32 CNAMEReferrals; // Count of how many CNAME redirections we've done + mDNSBool SuppressQuery; // This query should be suppressed and not sent on the wire + mDNSu8 LOAddressAnswers; // Number of answers from the local only auth records that are + // answering A, AAAA, CNAME, or PTR (/etc/hosts) + mDNSu8 WakeOnResolveCount; // Number of wakes that should be sent on resolve + mDNSs32 StopTime; // Time this question should be stopped by giving them a negative answer + + // DNSSEC fields + DNSSECValState ValidationState; // Current state of the Validation process + DNSSECStatus ValidationStatus; // Validation status for "ValidationRequired" questions (dnssec) + mDNSu8 ValidatingResponse; // Question trying to validate a response (dnssec) on behalf of + // ValidationRequired question + void *DNSSECAuthInfo; + DNSSECAuthInfoFreeCallback *DAIFreeCallback; + + // Wide Area fields. These are used internally by the uDNS core (Unicast) + UDPSocket *LocalSocket; + + // |-> DNS Configuration related fields used in uDNS (Subset of Wide Area/Unicast fields) + DNSServer *qDNSServer; // Caching server for this query (in the absence of an SRV saying otherwise) + mDNSOpaque64 validDNSServers; // Valid DNSServers for this question + mDNSu16 noServerResponse; // At least one server did not respond. + mDNSu16 triedAllServersOnce; // Tried all DNS servers once + mDNSu8 unansweredQueries; // The number of unanswered queries to this server + + ZoneData *nta; // Used for getting zone data for private or LLQ query + mDNSAddr servAddr; // Address and port learned from _dns-llq, _dns-llq-tls or _dns-query-tls SRV query + mDNSIPPort servPort; + struct tcpInfo_t *tcp; + mDNSIPPort tcpSrcPort; // Local Port TCP packet received on;need this as tcp struct is disposed + // by tcpCallback before calling into mDNSCoreReceive + mDNSu8 NoAnswer; // Set if we want to suppress answers until tunnel setup has completed + mDNSu8 Restart; // This question should be restarted soon + + // LLQ-specific fields. These fields are only meaningful when LongLived flag is set + LLQ_State state; + mDNSu32 ReqLease; // seconds (relative) + mDNSs32 expire; // ticks (absolute) + mDNSs16 ntries; // for UDP: the number of packets sent for this LLQ state + // 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 + mDNSOpaque64 id; + + // DNS Proxy fields + mDNSOpaque16 responseFlags; // Temporary place holder for the error we get back from the DNS server + // 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. + mDNSAddr Target; // Non-zero if you want to direct queries to a specific unicast target address + mDNSIPPort TargetPort; // Must be set if Target is set + mDNSOpaque16 TargetQID; // Must be set if Target is set + domainname qname; + mDNSu16 qtype; + mDNSu16 qclass; + mDNSBool LongLived; // Set by client for calls to mDNS_StartQuery to indicate LLQs to unicast layer. + mDNSBool ExpectUnique; // Set by client if it's expecting unique RR(s) for this question, not shared RRs + 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 + 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 + mDNSu8 UseBackgroundTrafficClass; // Use background traffic class for request + mDNSs8 SearchListIndex; // Index into SearchList; Used by the client layer but not touched by core + mDNSs8 AppendSearchDomains; // Search domains can be appended for this query + mDNSs8 AppendLocalSearchDomains; // Search domains ending in .local can be appended for this query + mDNSu8 ValidationRequired; // Requires DNSSEC validation. + mDNSu8 ProxyQuestion; // Proxy Question + mDNSu8 ProxyDNSSECOK; // Proxy Question with EDNS0 DNSSEC OK bit set + mDNSs32 pid; // Process ID of the client that is requesting the question + mDNSu8 uuid[UUID_SIZE]; // Unique ID of the client that is requesting the question (valid only if pid is zero) + domainname *qnameOrig; // Copy of the original question name if it is not fully qualified + mDNSQuestionCallback *QuestionCallback; + void *QuestionContext; +}; 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_Close(), mDNS_Execute() +{ + // 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); +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; - }; +{ + // 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 void ZoneDataCallback (mDNS *const m, mStatus err, const ZoneData *result); + +struct ZoneData_struct +{ + domainname ChildName; // Name for which we're trying to find the responsible server + ZoneService ZoneService; // Which service we're seeking for this zone (update, query, or LLQ) + domainname *CurrentSOA; // Points to somewhere within ChildName + domainname ZoneName; // Discovered result: Left-hand-side of SOA record + mDNSu16 ZoneClass; // Discovered result: DNS Class from SOA record + domainname Host; // Discovered result: Target host from SRV record + mDNSIPPort Port; // Discovered result: Update port, query port, or LLQ port from SRV record + mDNSAddr Addr; // Discovered result: Address of Target host from SRV record + mDNSBool ZonePrivate; // Discovered result: Does zone require encrypted queries? + ZoneDataCallback *ZoneDataCallback; // Caller-specified function to be called upon completion + void *ZoneDataContext; + DNSQuestion question; // Storage for any active question +}; + +extern ZoneData *StartGetZoneData(mDNS *const m, const domainname *const name, const ZoneService target, ZoneDataCallback callback, void *callbackInfo); +extern void CancelGetZoneData(mDNS *const m, ZoneData *nta); +extern mDNSBool IsGetZoneDataQuestion(DNSQuestion *q); + +typedef struct DNameListElem +{ + struct DNameListElem *next; + mDNSu32 uid; + domainname name; +} DNameListElem; + +#if APPLE_OSX_mDNSResponder +// Different states that we go through locating the peer +#define TC_STATE_AAAA_PEER 0x000000001 /* Peer's BTMM IPv6 address */ +#define TC_STATE_AAAA_PEER_RELAY 0x000000002 /* Peer's IPv6 Relay address */ +#define TC_STATE_SRV_PEER 0x000000003 /* Peer's SRV Record corresponding to IPv4 address */ +#define TC_STATE_ADDR_PEER 0x000000004 /* Peer's IPv4 address */ + +typedef struct ClientTunnel +{ + struct ClientTunnel *next; + domainname dstname; + mDNSBool MarkedForDeletion; + mDNSv6Addr loc_inner; + mDNSv4Addr loc_outer; + mDNSv6Addr loc_outer6; + mDNSv6Addr rmt_inner; + mDNSv4Addr rmt_outer; + mDNSv6Addr rmt_outer6; + mDNSIPPort rmt_outer_port; + mDNSu16 tc_state; + DNSQuestion q; +} ClientTunnel; +#endif // *************************************************************************** #if 0 -#pragma mark - NAT Traversal structures and constants +#pragma mark - +#pragma mark - NetworkInterfaceInfo_struct #endif -#define NATMAP_INIT_RETRY (mDNSPlatformOneSecond / 4) // start at 250ms w/ exponential decay -#define NATMAP_MAX_RETRY mDNSPlatformOneSecond // back off to once per second -#define NATMAP_MAX_TRIES 3 // for max 3 tries -#define NATMAP_DEFAULT_LEASE (60 * 60) // lease life in seconds -#define NATMAP_VERS 0 -#define NATMAP_PORT 5351 -#define NATMAP_RESPONSE_MASK 0x80 - -typedef enum - { - NATOp_AddrRequest = 0, - NATOp_MapUDP = 1, - NATOp_MapTCP = 2 - } NATOp_t; - -enum - { - NATErr_None = 0, - NATErr_Vers = 1, - NATErr_Refused = 2, - NATErr_NetFail = 3, - NATErr_Res = 4, - NATErr_Opcode = 5 - }; - -typedef mDNSu16 NATErr_t; - -typedef enum - { - NATState_Init = 0, - NATState_Request = 1, - NATState_Established = 2, - NATState_Legacy = 3, - NATState_Error = 4, - NATState_Refresh = 5, - NATState_Deleted = 6 - } NATState_t; -// Note: we have no explicit "cancelled" state, where a service/interface is deregistered while we - // have an outstanding NAT request. This is conveyed by the "reg" pointer being set to NULL - -typedef packedstruct - { - mDNSu8 vers; - mDNSu8 opcode; - } NATAddrRequest; - -typedef packedstruct - { - mDNSu8 vers; - mDNSu8 opcode; - mDNSOpaque16 err; - mDNSOpaque32 uptime; - mDNSv4Addr PubAddr; - } NATAddrReply; +typedef struct NetworkInterfaceInfo_struct NetworkInterfaceInfo; -typedef packedstruct - { - mDNSu8 vers; - mDNSu8 opcode; - mDNSOpaque16 unused; - mDNSIPPort priv; - mDNSIPPort pub; - mDNSOpaque32 lease; - } NATPortMapRequest; - -typedef packedstruct - { - mDNSu8 vers; - mDNSu8 opcode; - mDNSOpaque16 err; - mDNSOpaque32 uptime; - mDNSIPPort priv; - mDNSIPPort pub; - mDNSOpaque32 lease; - } NATPortMapReply; - -// Pass NULL for pkt on error (including timeout) -typedef mDNSBool (*NATResponseHndlr)(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len); +// A NetworkInterfaceInfo_struct serves two purposes: +// 1. It holds the address, PTR and HINFO records to advertise a given IP address on a given physical interface +// 2. It tells mDNSCore which physical interfaces are available; each physical interface has its own unique InterfaceID. +// Since there may be multiple IP addresses on a single physical interface, +// there may be multiple NetworkInterfaceInfo_structs with the same InterfaceID. +// In this case, to avoid sending the same packet n times, when there's more than one +// struct with the same InterfaceID, mDNSCore picks one member of the set to be the +// active representative of the set; all others have the 'InterfaceActive' flag unset. -struct NATTraversalInfo_struct - { - NATOp_t op; - NATResponseHndlr ReceiveResponse; - union { AuthRecord *RecordRegistration; ServiceRecordSet *ServiceRegistration; } reg; - mDNSAddr Router; - mDNSIPPort PublicPort; - union { NATAddrRequest AddrReq; NATPortMapRequest PortReq; } request; - mDNSs32 retry; // absolute time when we retry - mDNSs32 RetryInterval; // delta between time sent and retry - int ntries; - NATState_t state; - NATTraversalInfo *next; - }; +struct NetworkInterfaceInfo_struct +{ + // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them. + NetworkInterfaceInfo *next; + + mDNSu8 InterfaceActive; // Set if interface is sending & receiving packets (see comment above) + mDNSu8 IPv4Available; // If InterfaceActive, set if v4 available on this InterfaceID + mDNSu8 IPv6Available; // If InterfaceActive, set if v6 available on this InterfaceID + + DNSQuestion NetWakeBrowse; + DNSQuestion NetWakeResolve[3]; // For fault-tolerance, we try up to three Sleep Proxies + mDNSAddr SPSAddr[3]; + mDNSIPPort SPSPort[3]; + mDNSs32 NextSPSAttempt; // -1 if we're not currently attempting to register with any Sleep Proxy + mDNSs32 NextSPSAttemptTime; + + // Standard AuthRecords that every Responder host should have (one per active IP address) + AuthRecord RR_A; // 'A' or 'AAAA' (address) record for our ".local" name + AuthRecord RR_PTR; // PTR (reverse lookup) record + AuthRecord RR_HINFO; + + // Client API fields: The client must set up these fields *before* calling mDNS_RegisterInterface() + mDNSInterfaceID InterfaceID; // Identifies physical interface; MUST NOT be 0, -1, or -2 + mDNSAddr ip; // The IPv4 or IPv6 address to advertise + mDNSAddr mask; + mDNSEthAddr MAC; + char ifname[64]; // Windows uses a GUID string for the interface name, which doesn't fit in 16 bytes + mDNSu8 Advertise; // False if you are only searching on this interface + mDNSu8 McastTxRx; // Send/Receive multicast on this { InterfaceID, address family } ? + mDNSu8 NetWake; // Set if Wake-On-Magic-Packet is enabled on this interface + mDNSu8 Loopback; // Set if this is the loopback interface + mDNSu8 IgnoreIPv4LL; // Set if IPv4 Link-Local addresses have to be ignored. + mDNSu8 SendGoodbyes; // Send goodbyes on this interface while sleeping + mDNSBool DirectLink; // a direct link, indicating we can skip the probe for + // address records +}; + +#define SLE_DELETE 0x00000001 +#define SLE_WAB_BROWSE_QUERY_STARTED 0x00000002 +#define SLE_WAB_LBROWSE_QUERY_STARTED 0x00000004 +#define SLE_WAB_REG_QUERY_STARTED 0x00000008 + +typedef struct SearchListElem +{ + struct SearchListElem *next; + domainname domain; + int flag; + mDNSInterfaceID InterfaceID; + DNSQuestion BrowseQ; + DNSQuestion DefBrowseQ; + DNSQuestion AutomaticBrowseQ; + DNSQuestion RegisterQ; + DNSQuestion DefRegisterQ; + int numCfAnswers; + ARListElem *AuthRecs; +} SearchListElem; + +// For domain enumeration and automatic browsing +// This is the user's DNS search list. +// In each of these domains we search for our special pointer records (lb._dns-sd._udp., etc.) +// to discover recommended domains for domain enumeration (browse, default browse, registration, +// default registration) and possibly one or more recommended automatic browsing domains. +extern SearchListElem *SearchList; // This really ought to be part of mDNS_struct -- SC // *************************************************************************** #if 0 +#pragma mark - #pragma mark - Main mDNS object, used to hold all the mDNS state #endif -typedef void mDNSCallback(mDNS *const m, mStatus result); +typedef void mDNSCallback (mDNS *const m, mStatus result); +#ifndef CACHE_HASH_SLOTS #define CACHE_HASH_SLOTS 499 +#endif enum - { - mDNS_KnownBug_PhantomInterfaces = 1 - }; +{ + SleepState_Awake = 0, + SleepState_Transferring = 1, + SleepState_Sleeping = 2 +}; + +typedef enum +{ + kStatsActionIncrement, + kStatsActionDecrement, + kStatsActionClear, + kStatsActionSet +} DNSSECStatsAction; + +typedef enum +{ + kStatsTypeMemoryUsage, + kStatsTypeLatency, + kStatsTypeExtraPackets, + kStatsTypeStatus, + kStatsTypeProbe, + kStatsTypeMsgSize +} DNSSECStatsType; + +typedef struct +{ + mDNSu32 TotalMemUsed; + mDNSu32 Latency0; // 0 to 4 ms + mDNSu32 Latency5; // 5 to 9 ms + mDNSu32 Latency10; // 10 to 19 ms + mDNSu32 Latency20; // 20 to 49 ms + mDNSu32 Latency50; // 50 to 99 ms + mDNSu32 Latency100; // >= 100 ms + mDNSu32 ExtraPackets0; // 0 to 2 packets + mDNSu32 ExtraPackets3; // 3 to 6 packets + mDNSu32 ExtraPackets7; // 7 to 9 packets + mDNSu32 ExtraPackets10; // >= 10 packets + mDNSu32 SecureStatus; + mDNSu32 InsecureStatus; + mDNSu32 IndeterminateStatus; + mDNSu32 BogusStatus; + mDNSu32 NoResponseStatus; + mDNSu32 NumProbesSent; // Number of probes sent + mDNSu32 MsgSize0; // DNSSEC message size <= 1024 + mDNSu32 MsgSize1; // DNSSEC message size <= 2048 + mDNSu32 MsgSize2; // DNSSEC message size > 2048 +} DNSSECStatistics; typedef struct - { - mDNSs32 nextevent; - DNSQuestion *ActiveQueries; //!!!KRS this should be a hashtable (hash on messageID) - DNSQuestion *CurrentQuery; // pointer to ActiveQueries list being examined in a loop. Functions that remove - // elements from the ActiveQueries list must update this pointer (if non-NULL) as necessary. - //!!!KRS do the same for registration lists - ServiceRecordSet *ServiceRegistrations; - AuthRecord *RecordRegistrations; - NATTraversalInfo *NATTraversals; - mDNSu16 NextMessageID; - DNSServer *Servers; // list of DNS servers - mDNSAddr Router; - mDNSAddr AdvertisedV4; // IPv4 address pointed to by hostname - mDNSAddr MappedV4; // Cache of public address if PrimaryIP is behind a NAT - mDNSAddr AdvertisedV6; // IPv6 address pointed to by hostname - NATTraversalInfo *LLQNatInfo; // Nat port mapping to receive LLQ events - domainname ServiceRegDomain; // (going away w/ multi-user support) - struct uDNS_AuthInfo *AuthInfoList; // list of domains requiring authentication for updates. - uDNS_HostnameInfo *Hostnames; // List of registered hostnames + hostname metadata - DNSQuestion ReverseMap; // Reverse-map query to find static hostname for service target - mDNSBool ReverseMapActive; // Is above query active? - domainname StaticHostname; // Current answer to reverse-map query (above) - mDNSBool DelaySRVUpdate; // Delay SRV target/port update to avoid "flap" - mDNSs32 NextSRVUpdate; // Time to perform delayed update - } uDNS_GlobalInfo; +{ + mDNSu32 NameConflicts; // Normal Name conflicts + mDNSu32 KnownUniqueNameConflicts; // Name Conflicts for KnownUnique Records + mDNSu32 DupQuerySuppressions; // Duplicate query suppressions + mDNSu32 KnownAnswerSuppressions; // Known Answer suppressions + mDNSu32 KnownAnswerMultiplePkts; // Known Answer in queries spannign multiple packets + mDNSu32 PoofCacheDeletions; // Number of times the cache was deleted due to POOF + mDNSu32 UnicastBitInQueries; // Queries with QU bit set + mDNSu32 NormalQueries; // Queries with QU bit not set + mDNSu32 MatchingAnswersForQueries; // Queries for which we had a response + mDNSu32 UnicastResponses; // Unicast responses to queries + mDNSu32 MulticastResponses; // Multicast responses to queries + mDNSu32 UnicastDemotedToMulticast; // Number of times unicast demoted to multicast + mDNSu32 Sleeps; // Total sleeps + mDNSu32 Wakes; // Total wakes + mDNSu32 InterfaceUp; // Total Interface UP events + mDNSu32 InterfaceUpFlap; // Total Interface UP events with flaps + mDNSu32 InterfaceDown; // Total Interface Down events + mDNSu32 InterfaceDownFlap; // Total Interface Down events with flaps + mDNSu32 CacheRefreshQueries; // Number of queries that we sent for refreshing cache + mDNSu32 CacheRefreshed; // Number of times the cache was refreshed due to a response + mDNSu32 WakeOnResolves; // Number of times we did a wake on resolve +} mDNSStatistics; +extern void LogMDNSStatistics(mDNS *const m); struct mDNS_struct - { - // Internal state fields. These hold the main internal state of mDNSCore; - // the client layer needn't be concerned with them. - // No fields need to be set up by the client prior to calling mDNS_Init(); - // all required data is passed as parameters to that function. - - mDNS_PlatformSupport *p; // Pointer to platform-specific data of indeterminite size - mDNSu32 KnownBugs; - mDNSBool CanReceiveUnicastOn5353; - mDNSBool AdvertiseLocalAddresses; - mStatus mDNSPlatformStatus; - mDNSIPPort UnicastPort4; - mDNSIPPort UnicastPort6; - mDNSCallback *MainCallback; - void *MainContext; - - // For debugging: To catch and report locking failures - mDNSu32 mDNS_busy; // Incremented between mDNS_Lock/mDNS_Unlock section - mDNSu32 mDNS_reentrancy; // Incremented when calling a client callback - mDNSu8 mDNS_shutdown; // Set when we're shutting down, allows us to skip some unnecessary steps - mDNSu8 lock_rrcache; // For debugging: Set at times when these lists may not be modified - mDNSu8 lock_Questions; - mDNSu8 lock_Records; - char MsgBuffer[80]; // Temp storage used while building error log messages - - // Task Scheduling variables - mDNSs32 timenow_adjust; // Correction applied if we ever discover time went backwards - mDNSs32 timenow; // The time that this particular activation of the mDNS code started - mDNSs32 timenow_last; // The time the last time we ran - mDNSs32 NextScheduledEvent; // Derived from values below - mDNSs32 SuppressSending; // Don't send *any* packets during this time - mDNSs32 NextCacheCheck; // Next time to refresh cache record before it expires - mDNSs32 NextScheduledQuery; // Next time to send query in its exponential backoff sequence - mDNSs32 NextScheduledProbe; // Next time to probe for new authoritative record - mDNSs32 NextScheduledResponse; // Next time to send authoritative record(s) in responses - mDNSs32 ExpectUnicastResponse; // Set when we send a query with the kDNSQClass_UnicastResponse bit set - mDNSs32 RandomQueryDelay; // For de-synchronization of query packets on the wire - mDNSs32 PktNum; // Unique sequence number assigned to each received packet - mDNSBool SendDeregistrations; // Set if we need to send deregistrations (immediately) - mDNSBool SendImmediateAnswers; // Set if we need to send answers (immediately -- or as soon as SuppressSending clears) - mDNSBool SleepState; // Set if we're sleeping (send no more packets) - - // These fields only required for mDNS Searcher... - DNSQuestion *Questions; // List of all registered questions, active and inactive - DNSQuestion *NewQuestions; // Fresh questions not yet answered from cache - DNSQuestion *CurrentQuestion; // Next question about to be examined in AnswerLocalQuestions() - DNSQuestion *LocalOnlyQuestions; // Questions with InterfaceID set to mDNSInterface_LocalOnly - DNSQuestion *NewLocalOnlyQuestions; // Fresh local-only questions not yet answered - mDNSu32 rrcache_size; // Total number of available cache entries - mDNSu32 rrcache_totalused; // Number of cache entries currently occupied - mDNSu32 rrcache_active; // Number of cache entries currently occupied by records that answer active questions - mDNSu32 rrcache_report; - CacheEntity *rrcache_free; - CacheGroup *rrcache_hash[CACHE_HASH_SLOTS]; - - // Fields below only required for mDNS Responder... - domainlabel nicelabel; // Rich text label encoded using canonically precomposed UTF-8 - domainlabel hostlabel; // Conforms to RFC 1034 "letter-digit-hyphen" ARPANET host name rules - domainname MulticastHostname; // Fully Qualified "dot-local" Host Name, e.g. "Foo.local." - UTF8str255 HIHardware; - UTF8str255 HISoftware; - AuthRecord *ResourceRecords; - AuthRecord *DuplicateRecords; // Records currently 'on hold' because they are duplicates of existing records - AuthRecord *NewLocalRecords; // Fresh local-only records not yet delivered to local-only questions - AuthRecord *CurrentRecord; // Next AuthRecord about to be examined - NetworkInterfaceInfo *HostInterfaces; - mDNSs32 ProbeFailTime; - mDNSu32 NumFailedProbes; - mDNSs32 SuppressProbes; - - // unicast-specific data - uDNS_GlobalInfo uDNS_info; - mDNSs32 SuppressStdPort53Queries; // Wait before allowing the next standard unicast query to the user's configured DNS server - - // Fixed storage, to avoid creating large objects on the stack - DNSMessage imsg; // Incoming message received from wire - DNSMessage omsg; // Outgoing message we're building - LargeCacheRecord rec; // Resource Record extracted from received message - }; - -#define FORALL_CACHERECORDS(SLOT,CG,CR) \ - for ((SLOT) = 0; (SLOT) < CACHE_HASH_SLOTS; (SLOT)++) \ - for((CG)=m->rrcache_hash[(SLOT)]; (CG); (CG)=(CG)->next) \ - for ((CR) = (CG)->members; (CR); (CR)=(CR)->next) +{ + // Internal state fields. These hold the main internal state of mDNSCore; + // the client layer needn't be concerned with them. + // No fields need to be set up by the client prior to calling mDNS_Init(); + // all required data is passed as parameters to that function. + + mDNS_PlatformSupport *p; // Pointer to platform-specific data of indeterminite size + mDNSBool CanReceiveUnicastOn5353; + mDNSBool AdvertiseLocalAddresses; + mDNSBool DivertMulticastAdvertisements; // from interfaces that do not advertise local addresses to local-only + mStatus mDNSPlatformStatus; + mDNSIPPort UnicastPort4; + mDNSIPPort UnicastPort6; + mDNSEthAddr PrimaryMAC; // Used as unique host ID + mDNSCallback *MainCallback; + void *MainContext; + + // For debugging: To catch and report locking failures + mDNSu32 mDNS_busy; // Incremented between mDNS_Lock/mDNS_Unlock section + mDNSu32 mDNS_reentrancy; // Incremented when calling a client callback + mDNSu8 lock_rrcache; // For debugging: Set at times when these lists may not be modified + mDNSu8 lock_Questions; + mDNSu8 lock_Records; +#ifndef MaxMsg + #define MaxMsg 512 +#endif + char MsgBuffer[MaxMsg]; // Temp storage used while building error log messages + + // Task Scheduling variables + mDNSs32 timenow_adjust; // Correction applied if we ever discover time went backwards + mDNSs32 timenow; // The time that this particular activation of the mDNS code started + mDNSs32 timenow_last; // The time the last time we ran + mDNSs32 NextScheduledEvent; // Derived from values below + mDNSs32 ShutdownTime; // Set when we're shutting down; allows us to skip some unnecessary steps + mDNSs32 SuppressSending; // Don't send local-link mDNS packets during this time + mDNSs32 NextCacheCheck; // Next time to refresh cache record before it expires + mDNSs32 NextScheduledQuery; // Next time to send query in its exponential backoff sequence + mDNSs32 NextScheduledProbe; // Next time to probe for new authoritative record + mDNSs32 NextScheduledResponse; // Next time to send authoritative record(s) in responses + 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) + 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 + mDNSs32 MPktNum; // Unique sequence number assigned to each received Multicast packet + mDNSu8 LocalRemoveEvents; // Set if we may need to deliver remove events for local-only questions and/or local-only records + mDNSu8 SleepState; // Set if we're sleeping + mDNSu8 SleepSeqNum; // "Epoch number" of our current period of wakefulness + mDNSu8 SystemWakeOnLANEnabled; // Set if we want to register with a Sleep Proxy before going to sleep + mDNSu8 SentSleepProxyRegistration; // Set if we registered (or tried to register) with a Sleep Proxy + mDNSu8 SystemSleepOnlyIfWakeOnLAN; // Set if we may only sleep if we managed to register with a Sleep Proxy + mDNSs32 AnnounceOwner; // After waking from sleep, include OWNER option in packets until this time + mDNSs32 DelaySleep; // To inhibit re-sleeping too quickly right after wake + mDNSs32 SleepLimit; // Time window to allow deregistrations, etc., + // during which underying platform layer should inhibit system sleep + mDNSs32 TimeSlept; // Time we went to sleep. + + mDNSs32 StatStartTime; // Time we started gathering statistics during this interval. + mDNSs32 NextStatLogTime; // Next time to log statistics. + mDNSs32 ActiveStatTime; // Total time awake/gathering statistics for this log period. + mDNSs32 UnicastPacketsSent; // Number of unicast packets sent. + mDNSs32 MulticastPacketsSent; // Number of multicast packets sent. + mDNSs32 RemoteSubnet; // Multicast packets received from outside our subnet. + + mDNSs32 NextScheduledSPRetry; // Time next sleep proxy registration action is required. + // Only valid if SleepLimit is nonzero and DelaySleep is zero. + + mDNSs32 NextScheduledStopTime; // Next time to stop a question + + + // These fields only required for mDNS Searcher... + DNSQuestion *Questions; // List of all registered questions, active and inactive + DNSQuestion *NewQuestions; // Fresh questions not yet answered from cache + DNSQuestion *CurrentQuestion; // Next question about to be examined in AnswerLocalQuestions() + DNSQuestion *LocalOnlyQuestions; // Questions with InterfaceID set to mDNSInterface_LocalOnly or mDNSInterface_P2P + DNSQuestion *NewLocalOnlyQuestions; // Fresh local-only or P2P questions not yet answered + DNSQuestion *RestartQuestion; // Questions that are being restarted (stop followed by start) + DNSQuestion *ValidationQuestion; // Questions that are being validated (dnssec) + mDNSu32 rrcache_size; // Total number of available cache entries + mDNSu32 rrcache_totalused; // Number of cache entries currently occupied + mDNSu32 rrcache_totalused_unicast; // Number of cache entries currently occupied by unicast + mDNSu32 rrcache_active; // Number of cache entries currently occupied by records that answer active questions + mDNSu32 rrcache_report; + CacheEntity *rrcache_free; + CacheGroup *rrcache_hash[CACHE_HASH_SLOTS]; + mDNSs32 rrcache_nextcheck[CACHE_HASH_SLOTS]; + + AuthHash rrauth; + + // Fields below only required for mDNS Responder... + domainlabel nicelabel; // Rich text label encoded using canonically precomposed UTF-8 + domainlabel hostlabel; // Conforms to RFC 1034 "letter-digit-hyphen" ARPANET host name rules + domainname MulticastHostname; // Fully Qualified "dot-local" Host Name, e.g. "Foo.local." + UTF8str255 HIHardware; + UTF8str255 HISoftware; + AuthRecord DeviceInfo; + AuthRecord *ResourceRecords; + AuthRecord *DuplicateRecords; // Records currently 'on hold' because they are duplicates of existing records + AuthRecord *NewLocalRecords; // Fresh AuthRecords (public) not yet delivered to our local-only questions + AuthRecord *CurrentRecord; // Next AuthRecord about to be examined + mDNSBool NewLocalOnlyRecords; // Fresh AuthRecords (local only) not yet delivered to our local questions + NetworkInterfaceInfo *HostInterfaces; + mDNSs32 ProbeFailTime; + mDNSu32 NumFailedProbes; + mDNSs32 SuppressProbes; + Platform_t mDNS_plat; + + // Unicast-specific data + mDNSs32 NextuDNSEvent; // uDNS next event + mDNSs32 NextSRVUpdate; // Time to perform delayed update + + DNSServer *DNSServers; // list of DNS servers + McastResolver *McastResolvers; // list of Mcast Resolvers + + mDNSAddr Router; + mDNSAddr AdvertisedV4; // IPv4 address pointed to by hostname + mDNSAddr AdvertisedV6; // IPv6 address pointed to by hostname + + DomainAuthInfo *AuthInfoList; // list of domains requiring authentication for updates + + DNSQuestion ReverseMap; // Reverse-map query to find static hostname for service target + DNSQuestion AutomaticBrowseDomainQ; + domainname StaticHostname; // Current answer to reverse-map query + domainname FQDN; + HostnameInfo *Hostnames; // List of registered hostnames + hostname metadata + NATTraversalInfo AutoTunnelNAT; // Shared between all AutoTunnel DomainAuthInfo structs + mDNSv6Addr AutoTunnelRelayAddr; + + mDNSu32 WABBrowseQueriesCount; // Number of WAB Browse domain enumeration queries (b, db) callers + mDNSu32 WABLBrowseQueriesCount; // Number of legacy WAB Browse domain enumeration queries (lb) callers + mDNSu32 WABRegQueriesCount; // Number of WAB Registration domain enumeration queries (r, dr) callers + mDNSu8 SearchDomainsHash[MD5_LEN]; + + // NAT-Traversal fields + NATTraversalInfo LLQNAT; // Single shared NAT Traversal to receive inbound LLQ notifications + NATTraversalInfo *NATTraversals; + NATTraversalInfo *CurrentNATTraversal; + mDNSs32 retryIntervalGetAddr; // delta between time sent and retry for NAT-PMP & UPnP/IGD external address request + mDNSs32 retryGetAddr; // absolute time when we retry for NAT-PMP & UPnP/IGD external address request + mDNSv4Addr ExtAddress; // the external address discovered via NAT-PMP or UPnP/IGD + mDNSu32 PCPNonce[3]; // the nonce if using PCP + + UDPSocket *NATMcastRecvskt; // For receiving PCP & NAT-PMP announcement multicasts from router on port 5350 + mDNSu32 LastNATupseconds; // NAT engine uptime in seconds, from most recent NAT packet + mDNSs32 LastNATReplyLocalTime; // Local time in ticks when most recent NAT packet was received + mDNSu16 LastNATMapResultCode; // Most recent error code for mappings + + tcpLNTInfo tcpAddrInfo; // legacy NAT traversal TCP connection info for external address + tcpLNTInfo tcpDeviceInfo; // legacy NAT traversal TCP connection info for device info + tcpLNTInfo *tcpInfoUnmapList; // list of pending unmap requests + mDNSInterfaceID UPnPInterfaceID; + UDPSocket *SSDPSocket; // For SSDP request/response + mDNSBool SSDPWANPPPConnection; // whether we should send the SSDP query for WANIPConnection or WANPPPConnection + mDNSIPPort UPnPRouterPort; // port we send discovery messages to + mDNSIPPort UPnPSOAPPort; // port we send SOAP messages to + mDNSu8 *UPnPRouterURL; // router's URL string + mDNSBool UPnPWANPPPConnection; // whether we're using WANIPConnection or WANPPPConnection + mDNSu8 *UPnPSOAPURL; // router's SOAP control URL string + mDNSu8 *UPnPRouterAddressString; // holds both the router's address and port + mDNSu8 *UPnPSOAPAddressString; // holds both address and port for SOAP messages + + // Sleep Proxy client fields + AuthRecord *SPSRRSet; // To help the client keep track of the records registered with the sleep proxy + + // Sleep Proxy Server fields + mDNSu8 SPSType; // 0 = off, 10-99 encodes desirability metric + mDNSu8 SPSPortability; // 10-99 + mDNSu8 SPSMarginalPower; // 10-99 + mDNSu8 SPSTotalPower; // 10-99 + mDNSu8 SPSFeatureFlags; // Features supported. Currently 1 = TCP KeepAlive supported. + mDNSu8 SPSState; // 0 = off, 1 = running, 2 = shutting down, 3 = suspended during sleep + mDNSInterfaceID SPSProxyListChanged; + UDPSocket *SPSSocket; +#ifndef SPC_DISABLED + ServiceRecordSet SPSRecords; +#endif + mDNSQuestionCallback *SPSBrowseCallback; // So the platform layer can do something useful with SPS browse results + int ProxyRecords; // Total number of records we're holding as proxy + #define MAX_PROXY_RECORDS 10000 /* DOS protection: 400 machines at 25 records each */ + +#if APPLE_OSX_mDNSResponder + ClientTunnel *TunnelClients; + uuid_t asl_uuid; // uuid for ASL logging + void *WCF; +#endif + // DNS Proxy fields + mDNSu32 dp_ipintf[MaxIp]; // input interface index list from the DNS Proxy Client + mDNSu32 dp_opintf; // output interface index from the DNS Proxy Client + + TrustAnchor *TrustAnchors; + int notifyToken; + int uds_listener_skt; // Listening socket for incoming UDS clients + mDNSBool mDNSOppCaching; // Opportunistic Caching + mDNSu32 AutoTargetServices; // # of services that have AutoTarget set + DNSSECStatistics DNSSECStats; + mDNSStatistics mDNSStats; + + // Fixed storage, to avoid creating large objects on the stack + // The imsg is declared as a union with a pointer type to enforce CPU-appropriate alignment + union { DNSMessage m; void *p; } imsg; // Incoming message received from wire + DNSMessage omsg; // Outgoing message we're building + LargeCacheRecord rec; // Resource Record extracted from received message +}; + +#define FORALL_CACHERECORDS(SLOT,CG,CR) \ + for ((SLOT) = 0; (SLOT) < CACHE_HASH_SLOTS; (SLOT)++) \ + for ((CG)=m->rrcache_hash[(SLOT)]; (CG); (CG)=(CG)->next) \ + for ((CR) = (CG)->members; (CR); (CR)=(CR)->next) // *************************************************************************** #if 0 +#pragma mark - #pragma mark - Useful Static Constants #endif -extern const mDNSIPPort zeroIPPort; -extern const mDNSv4Addr zerov4Addr; -extern const mDNSv6Addr zerov6Addr; -extern const mDNSEthAddr zeroEthAddr; -extern const mDNSv4Addr onesIPv4Addr; -extern const mDNSv6Addr onesIPv6Addr; -extern const mDNSAddr zeroAddr; - -extern const mDNSInterfaceID mDNSInterface_Any; // Zero -extern const mDNSInterfaceID mDNSInterface_LocalOnly; // Special value - -extern const mDNSIPPort UnicastDNSPort; -extern const mDNSIPPort MulticastDNSPort; -extern const mDNSv4Addr AllDNSAdminGroup; -extern const mDNSv4Addr AllDNSLinkGroupv4; -extern const mDNSv6Addr AllDNSLinkGroupv6; -extern const mDNSAddr AllDNSLinkGroup_v4; -extern const mDNSAddr AllDNSLinkGroup_v6; +extern const mDNSInterfaceID mDNSInterface_Any; // Zero +extern const mDNSInterfaceID mDNSInterface_LocalOnly; // Special value +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 mDNSIPPort DiscardPort; +extern const mDNSIPPort SSHPort; +extern const mDNSIPPort UnicastDNSPort; +extern const mDNSIPPort SSDPPort; +extern const mDNSIPPort IPSECPort; +extern const mDNSIPPort NSIPCPort; +extern const mDNSIPPort NATPMPAnnouncementPort; +extern const mDNSIPPort NATPMPPort; +extern const mDNSIPPort DNSEXTPort; +extern const mDNSIPPort MulticastDNSPort; +extern const mDNSIPPort LoopbackIPCPort; +extern const mDNSIPPort PrivateDNSPort; + +extern const OwnerOptData zeroOwner; + +extern const mDNSIPPort zeroIPPort; +extern const mDNSv4Addr zerov4Addr; +extern const mDNSv6Addr zerov6Addr; +extern const mDNSEthAddr zeroEthAddr; +extern const mDNSv4Addr onesIPv4Addr; +extern const mDNSv6Addr onesIPv6Addr; +extern const mDNSEthAddr onesEthAddr; +extern const mDNSAddr zeroAddr; + +extern const mDNSv4Addr AllDNSAdminGroup; +extern const mDNSv4Addr AllHosts_v4; +extern const mDNSv6Addr AllHosts_v6; +extern const mDNSv6Addr NDP_prefix; +extern const mDNSEthAddr AllHosts_v6_Eth; +extern const mDNSAddr AllDNSLinkGroup_v4; +extern const mDNSAddr AllDNSLinkGroup_v6; extern const mDNSOpaque16 zeroID; +extern const mDNSOpaque16 onesID; extern const mDNSOpaque16 QueryFlags; extern const mDNSOpaque16 uQueryFlags; +extern const mDNSOpaque16 DNSSecQFlags; extern const mDNSOpaque16 ResponseFlags; extern const mDNSOpaque16 UpdateReqFlags; extern const mDNSOpaque16 UpdateRespFlags; -#define localdomain (*(const domainname *)"\x5local") -#define LocalReverseMapomain (*(const domainname *)"\x3" "254" "\x3" "169" "\x7" "in-addr" "\x4" "arpa") - +extern const mDNSOpaque64 zeroOpaque64; + +extern mDNSBool StrictUnicastOrdering; +extern mDNSu8 NumUnicastDNSServers; + +#define localdomain (*(const domainname *)"\x5" "local") +#define DeviceInfoName (*(const domainname *)"\xC" "_device-info" "\x4" "_tcp") +#define LocalDeviceInfoName (*(const domainname *)"\xC" "_device-info" "\x4" "_tcp" "\x5" "local") +#define SleepProxyServiceType (*(const domainname *)"\xC" "_sleep-proxy" "\x4" "_udp") + // *************************************************************************** #if 0 +#pragma mark - #pragma mark - Inline functions #endif #if (defined(_MSC_VER)) - #define mDNSinline static __inline + #define mDNSinline static __inline #elif ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 9))) - #define mDNSinline static inline + #define mDNSinline static inline #endif // If we're not doing inline functions, then this header needs to have the extern declarations #if !defined(mDNSinline) extern mDNSs32 NonZeroTime(mDNSs32 t); extern mDNSu16 mDNSVal16(mDNSOpaque16 x); -extern mDNSu32 mDNSVal32(mDNSOpaque32 x); extern mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v); -extern mDNSOpaque32 mDNSOpaque32fromIntVal(mDNSu32 v); #endif // If we're compiling the particular C file that instantiates our inlines, then we @@ -2201,33 +2561,23 @@ extern mDNSOpaque32 mDNSOpaque32fromIntVal(mDNSu32 v); #ifdef mDNSinline -mDNSinline mDNSs32 NonZeroTime(mDNSs32 t) { if (t) return(t); else return(1); } +mDNSinline mDNSs32 NonZeroTime(mDNSs32 t) { if (t) return(t);else return(1);} mDNSinline mDNSu16 mDNSVal16(mDNSOpaque16 x) { return((mDNSu16)((mDNSu16)x.b[0] << 8 | (mDNSu16)x.b[1])); } -mDNSinline mDNSu32 mDNSVal32(mDNSOpaque32 x) { return((mDNSu32)((mDNSu32)x.b[0] << 24 | (mDNSu32)x.b[1] << 16 | (mDNSu32)x.b[2] << 8 | (mDNSu32)x.b[3])); } mDNSinline mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v) - { - mDNSOpaque16 x; - x.b[0] = (mDNSu8)(v >> 8); - x.b[1] = (mDNSu8)(v & 0xFF); - return(x); - } - -mDNSinline mDNSOpaque32 mDNSOpaque32fromIntVal(mDNSu32 v) - { - mDNSOpaque32 x; - x.b[0] = (mDNSu8) (v >> 24) ; - x.b[1] = (mDNSu8)((v >> 16) & 0xFF); - x.b[2] = (mDNSu8)((v >> 8 ) & 0xFF); - x.b[3] = (mDNSu8)((v ) & 0xFF); - return x; - } +{ + mDNSOpaque16 x; + x.b[0] = (mDNSu8)(v >> 8); + x.b[1] = (mDNSu8)(v & 0xFF); + return(x); +} #endif // *************************************************************************** #if 0 +#pragma mark - #pragma mark - Main Client Functions #endif @@ -2252,10 +2602,16 @@ mDNSinline mDNSOpaque32 mDNSOpaque32fromIntVal(mDNSu32 v) // In principle, a proxy-like registration service could manually create address records for its own machine too, // but this would be pointless extra effort when using mDNS_Init_AdvertiseLocalAddresses does that for you. // +// Note that a client-only device that wishes to prohibit multicast advertisements (e.g. from +// higher-layer API calls) must also set DivertMulticastAdvertisements in the mDNS structure and +// advertise local address(es) on a loopback interface. +// // When mDNS has finished setting up the client's callback is called // A client can also spin and poll the mDNSPlatformStatus field to see when it changes from mStatus_Waiting to mStatus_NoError // -// Call mDNS_Close to tidy up before exiting +// Call mDNS_StartExit to tidy up before exiting +// Because exiting may be an asynchronous process (e.g. if unicast records need to be deregistered) +// client layer may choose to wait until mDNS_ExitNow() returns true before calling mDNS_FinalExit(). // // Call mDNS_Register with a completed AuthRecord object to register a resource record // If the resource record type is kDNSRecordTypeUnique (or kDNSknownunique) then if a conflicting resource record is discovered, @@ -2276,9 +2632,9 @@ mDNSinline mDNSOpaque32 mDNSOpaque32fromIntVal(mDNSu32 v) // code is not entered by an interrupt-time timer callback while in the middle of processing a client call. extern mStatus mDNS_Init (mDNS *const m, mDNS_PlatformSupport *const p, - CacheEntity *rrcachestorage, mDNSu32 rrcachesize, - mDNSBool AdvertiseLocalAddresses, - mDNSCallback *Callback, void *Context); + CacheEntity *rrcachestorage, mDNSu32 rrcachesize, + mDNSBool AdvertiseLocalAddresses, + mDNSCallback *Callback, void *Context); // See notes above on use of NoCache/ZeroCacheSize #define mDNS_Init_NoCache mDNSNULL #define mDNS_Init_ZeroCacheSize 0 @@ -2288,33 +2644,58 @@ extern mStatus mDNS_Init (mDNS *const m, mDNS_PlatformSupport *const p, #define mDNS_Init_NoInitCallback mDNSNULL #define mDNS_Init_NoInitCallbackContext mDNSNULL +extern void mDNS_ConfigChanged(mDNS *const m); extern void mDNS_GrowCache (mDNS *const m, CacheEntity *storage, mDNSu32 numrecords); -extern void mDNS_Close (mDNS *const m); +extern void mDNS_GrowAuth (mDNS *const m, AuthEntity *storage, mDNSu32 numrecords); +extern void mDNS_StartExit (mDNS *const m); +extern void mDNS_FinalExit (mDNS *const m); +#define mDNS_Close(m) do { mDNS_StartExit(m); mDNS_FinalExit(m); } while(0) +#define mDNS_ExitNow(m, now) ((now) - (m)->ShutdownTime >= 0 || (!(m)->ResourceRecords)) + extern mDNSs32 mDNS_Execute (mDNS *const m); extern mStatus mDNS_Register (mDNS *const m, AuthRecord *const rr); extern mStatus mDNS_Update (mDNS *const m, AuthRecord *const rr, mDNSu32 newttl, - const mDNSu16 newrdlength, RData *const newrdata, mDNSRecordUpdateCallback *Callback); + const mDNSu16 newrdlength, RData *const newrdata, mDNSRecordUpdateCallback *Callback); extern mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr); extern mStatus mDNS_StartQuery(mDNS *const m, DNSQuestion *const question); extern mStatus mDNS_StopQuery (mDNS *const m, DNSQuestion *const question); +extern mStatus mDNS_StopQueryWithRemoves(mDNS *const m, DNSQuestion *const question); extern mStatus mDNS_Reconfirm (mDNS *const m, CacheRecord *const cacherr); +extern mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr, mDNSu32 interval); extern mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr); +extern void mDNS_PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr); extern mDNSs32 mDNS_TimeNow(const mDNS *const m); +extern mStatus mDNS_StartNATOperation(mDNS *const m, NATTraversalInfo *traversal); +extern mStatus mDNS_StopNATOperation(mDNS *const m, NATTraversalInfo *traversal); +extern mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *traversal); + +extern DomainAuthInfo *GetAuthInfoForName(mDNS *m, const domainname *const name); + +extern void mDNS_UpdateAllowSleep(mDNS *const m); + // *************************************************************************** #if 0 +#pragma mark - #pragma mark - Platform support functions that are accessible to the client layer too #endif -extern mDNSs32 mDNSPlatformOneSecond; +extern mDNSs32 mDNSPlatformOneSecond; // *************************************************************************** #if 0 +#pragma mark - #pragma mark - General utility and helper functions #endif +// mDNS_Dereg_normal is used for most calls to mDNS_Deregister_internal +// mDNS_Dereg_rapid is used to send one goodbye instead of three, when we want the memory available for reuse sooner +// mDNS_Dereg_conflict is used to indicate that this record is being forcibly deregistered because of a conflict +// mDNS_Dereg_repeat is used when cleaning up, for records that may have already been forcibly deregistered +typedef enum { mDNS_Dereg_normal, mDNS_Dereg_rapid, mDNS_Dereg_conflict, mDNS_Dereg_repeat } mDNS_Dereg_type; + // 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, @@ -2327,7 +2708,7 @@ extern mDNSs32 mDNSPlatformOneSecond; // via mDNS_RemoveRecordFromService, or by deregistering the service. mDNS_RemoveRecordFromService is passed a // callback to free the memory associated with the extra RR when it is safe to do so. The ExtraResourceRecord // object can be found in the record's context pointer. - + // mDNS_GetBrowseDomains is a special case of the mDNS_StartQuery call, where the resulting answers // are a list of PTR records indicating (in the rdata) domains that are recommended for browsing. // After getting the list of domains to browse, call mDNS_StopQuery to end the search. @@ -2338,53 +2719,77 @@ extern mDNSs32 mDNSPlatformOneSecond; // and the default domain in which to register in the case where the user has made no selection. extern void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID, - mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, mDNSRecordCallback Callback, void *Context); + mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, AuthRecType artype, mDNSRecordCallback Callback, void *Context); + +// mDNS_RegisterService() flags parameter bit definitions. +// Note these are only defined to transfer the corresponding DNSServiceFlags settings into mDNSCore routines, +// since code in mDNSCore does not include the DNSServiceFlags definitions in dns_sd.h. +enum +{ + coreFlagIncludeP2P = 0x1, // include P2P interfaces when using mDNSInterface_Any + coreFlagIncludeAWDL = 0x2, // include AWDL interface when using mDNSInterface_Any + coreFlagKnownUnique = 0x4, // client guarantees that SRV and TXT record names are unique + coreFlagWakeOnly = 0x8 // Service won't be registered with sleep proxy +}; 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, - AuthRecord *SubTypes, mDNSu32 NumSubTypes, - const mDNSInterfaceID InterfaceID, mDNSServiceCallback Callback, void *Context); -extern mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl); + const domainlabel *const name, const domainname *const type, const domainname *const domain, + const domainname *const host, mDNSIPPort port, const mDNSu8 txtinfo[], mDNSu16 txtlen, + AuthRecord *SubTypes, mDNSu32 NumSubTypes, + mDNSInterfaceID InterfaceID, mDNSServiceCallback Callback, void *Context, mDNSu32 flags); +extern mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl, mDNSu32 flags); extern mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, mDNSRecordCallback MemFreeCallback, void *Context); extern mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr, const domainlabel *newname); -extern mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr); +extern mStatus mDNS_DeregisterService_drt(mDNS *const m, ServiceRecordSet *sr, mDNS_Dereg_type drt); +#define mDNS_DeregisterService(M,S) mDNS_DeregisterService_drt((M), (S), mDNS_Dereg_normal) extern mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const rr, - const domainlabel *const name, const domainname *const type, const domainname *const domain, - const domainname *const host, - const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context); + const domainlabel *const name, const domainname *const type, const domainname *const domain, + const domainname *const host, + const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context, mDNSu32 flags); #define mDNS_DeregisterNoSuchService mDNS_Deregister +extern void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID InterfaceID, const domainname *const name, + const mDNSu16 qtype, mDNSQuestionCallback *const callback, void *const context); + extern mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question, - const domainname *const srv, const domainname *const domain, - const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context); + const domainname *const srv, const domainname *const domain, const mDNSu8 *anondata, + const mDNSInterfaceID InterfaceID, mDNSu32 flags, + mDNSBool ForceMCast, mDNSBool useBackgroundTrafficClass, + 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 - { - mDNS_DomainTypeBrowse = 0, - mDNS_DomainTypeBrowseDefault = 1, - mDNS_DomainTypeBrowseLegacy = 2, - mDNS_DomainTypeRegistration = 3, - mDNS_DomainTypeRegistrationDefault = 4, - - mDNS_DomainTypeMax = 4 - } mDNS_DomainType; +{ + mDNS_DomainTypeBrowse = 0, + mDNS_DomainTypeBrowseDefault = 1, + mDNS_DomainTypeBrowseAutomatic = 2, + mDNS_DomainTypeRegistration = 3, + mDNS_DomainTypeRegistrationDefault = 4, + + mDNS_DomainTypeMax = 4 +} mDNS_DomainType; extern const char *const mDNS_DomainTypeNames[]; extern mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom, - const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context); + const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context); #define mDNS_StopGetDomains mDNS_StopQuery extern mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, char *domname); #define mDNS_StopAdvertiseDomains mDNS_Deregister +extern mDNSOpaque16 mDNS_NewMessageID(mDNS *const m); +extern mDNSBool mDNS_AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr, mDNSBool *myself); + +extern DNSServer *GetServerForQuestion(mDNS *m, DNSQuestion *question); +extern mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question); + // *************************************************************************** #if 0 +#pragma mark - #pragma mark - DNS name utility functions #endif @@ -2397,16 +2802,29 @@ extern mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, mDNS_DomainT // A simple C structure assignment of a domainname can cause a protection fault by accessing unmapped memory, // 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) mDNSPlatformMemCopy((SRC)->c, (DST)->c, DomainNameLength((SRC))) +#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) // Comparison functions +#define SameDomainLabelCS(A,B) ((A)[0] == (B)[0] && mDNSPlatformMemSame((A)+1, (B)+1, (A)[0])) extern mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b); extern mDNSBool SameDomainName(const domainname *const d1, const domainname *const d2); +extern mDNSBool SameDomainNameCS(const domainname *const d1, const domainname *const d2); +typedef mDNSBool DomainNameComparisonFn (const domainname *const d1, const domainname *const d2); extern mDNSBool IsLocalDomain(const domainname *d); // returns true for domains that by default should be looked up using link-local multicast +#define StripFirstLabel(X) ((const domainname *)& (X)->c[(X)->c[0] ? 1 + (X)->c[0] : 0]) + +#define FirstLabel(X) ((const domainlabel *)(X)) +#define SecondLabel(X) ((const domainlabel *)StripFirstLabel(X)) +#define ThirdLabel(X) ((const domainlabel *)StripFirstLabel(StripFirstLabel(X))) + +extern const mDNSu8 *LastLabel(const domainname *d); + // Get total length of domain name, in native DNS format, including terminal root label // (e.g. length of "com." is 5 (length byte, three data bytes, final zero) -extern mDNSu16 DomainNameLength(const domainname *const name); +extern mDNSu16 DomainNameLengthLimit(const domainname *const name, const mDNSu8 *limit); +#define DomainNameLength(name) DomainNameLengthLimit((name), (name)->c + MAX_DOMAIN_NAME) // Append functions to append one or more labels to an existing native format domain name: // AppendLiteralLabelString adds a single label from a literal C string, with no escape character interpretation. @@ -2431,7 +2849,7 @@ extern mDNSu8 *MakeDomainNameFromDNSNameString (domainname *const name, const // When using ConvertDomainLabelToCString, the target buffer must be MAX_ESCAPED_DOMAIN_LABEL (254) bytes long // to guarantee there will be no buffer overrun. It is only safe to use a buffer shorter than this in rare cases // where the label is known to be constrained somehow (for example, if the label is known to be either "_tcp" or "_udp"). -// Similarly, when using ConvertDomainNameToCString, the target buffer must be MAX_ESCAPED_DOMAIN_NAME (1005) bytes long. +// Similarly, when using ConvertDomainNameToCString, the target buffer must be MAX_ESCAPED_DOMAIN_NAME (1009) bytes long. // See definitions of MAX_ESCAPED_DOMAIN_LABEL and MAX_ESCAPED_DOMAIN_NAME for more detailed explanation. extern char *ConvertDomainLabelToCString_withescape(const domainlabel *const name, char *cstr, char esc); #define ConvertDomainLabelToCString_unescaped(D,C) ConvertDomainLabelToCString_withescape((D), (C), 0) @@ -2458,6 +2876,7 @@ extern mDNSBool DeconstructServiceName(const domainname *const fqdn, domainlabel // *************************************************************************** #if 0 +#pragma mark - #pragma mark - Other utility functions and macros #endif @@ -2470,87 +2889,99 @@ extern mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va 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); -extern char *GetRRDisplayString_rdb(const ResourceRecord *rr, RDataBody *rd, char *buffer); +extern char *GetRRDisplayString_rdb(const ResourceRecord *const rr, const RDataBody *const rd1, char *const buffer); #define RRDisplayString(m, rr) GetRRDisplayString_rdb(rr, &(rr)->rdata->u, (m)->MsgBuffer) #define ARDisplayString(m, rr) GetRRDisplayString_rdb(&(rr)->resrec, &(rr)->resrec.rdata->u, (m)->MsgBuffer) #define CRDisplayString(m, rr) GetRRDisplayString_rdb(&(rr)->resrec, &(rr)->resrec.rdata->u, (m)->MsgBuffer) extern mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2); extern void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText); -extern mDNSBool IsPrivateV4Addr(mDNSAddr *addr); // returns true for RFC1918 private addresses +extern mDNSBool mDNSv4AddrIsRFC1918(const mDNSv4Addr * const addr); // returns true for RFC1918 private addresses +#define mDNSAddrIsRFC1918(X) ((X)->type == mDNSAddrType_IPv4 && mDNSv4AddrIsRFC1918(&(X)->ip.v4)) + +// For PCP +extern void mDNSAddrMapIPv4toIPv6(mDNSv4Addr* in, mDNSv6Addr* out); +extern mDNSBool mDNSAddrIPv4FromMappedIPv6(mDNSv6Addr *in, mDNSv4Addr *out); + +#define mDNSSameIPPort(A,B) ((A).NotAnInteger == (B).NotAnInteger) +#define mDNSSameOpaque16(A,B) ((A).NotAnInteger == (B).NotAnInteger) +#define mDNSSameOpaque32(A,B) ((A).NotAnInteger == (B).NotAnInteger) +#define mDNSSameOpaque64(A,B) ((A)->l[0] == (B)->l[0] && (A)->l[1] == (B)->l[1]) #define mDNSSameIPv4Address(A,B) ((A).NotAnInteger == (B).NotAnInteger) #define mDNSSameIPv6Address(A,B) ((A).l[0] == (B).l[0] && (A).l[1] == (B).l[1] && (A).l[2] == (B).l[2] && (A).l[3] == (B).l[3]) +#define mDNSSameIPv6NetworkPart(A,B) ((A).l[0] == (B).l[0] && (A).l[1] == (B).l[1]) #define mDNSSameEthAddress(A,B) ((A)->w[0] == (B)->w[0] && (A)->w[1] == (B)->w[1] && (A)->w[2] == (B)->w[2]) -#define mDNSIPv4AddressIsZero(A) mDNSSameIPv4Address((A), zerov4Addr) -#define mDNSIPv6AddressIsZero(A) mDNSSameIPv6Address((A), zerov6Addr) +#define mDNSIPPortIsZero(A) ((A).NotAnInteger == 0) +#define mDNSOpaque16IsZero(A) ((A).NotAnInteger == 0) +#define mDNSOpaque64IsZero(A) (((A)->l[0] | (A)->l[1] ) == 0) +#define mDNSIPv4AddressIsZero(A) ((A).NotAnInteger == 0) +#define mDNSIPv6AddressIsZero(A) (((A).l[0] | (A).l[1] | (A).l[2] | (A).l[3]) == 0) +#define mDNSEthAddressIsZero(A) (((A).w[0] | (A).w[1] | (A).w[2] ) == 0) -#define mDNSIPv4AddressIsOnes(A) mDNSSameIPv4Address((A), onesIPv4Addr) -#define mDNSIPv6AddressIsOnes(A) mDNSSameIPv6Address((A), onesIPv6Addr) +#define mDNSIPv4AddressIsOnes(A) ((A).NotAnInteger == 0xFFFFFFFF) +#define mDNSIPv6AddressIsOnes(A) (((A).l[0] & (A).l[1] & (A).l[2] & (A).l[3]) == 0xFFFFFFFF) -#define mDNSAddressIsAllDNSLinkGroup(X) ( \ - ((X)->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address((X)->ip.v4, AllDNSLinkGroupv4)) || \ - ((X)->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address((X)->ip.v6, AllDNSLinkGroupv6)) ) +#define mDNSAddressIsAllDNSLinkGroup(X) ( \ + ((X)->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address((X)->ip.v4, AllDNSLinkGroup_v4.ip.v4)) || \ + ((X)->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address((X)->ip.v6, AllDNSLinkGroup_v6.ip.v6)) ) #define mDNSAddressIsZero(X) ( \ - ((X)->type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero((X)->ip.v4)) || \ - ((X)->type == mDNSAddrType_IPv6 && mDNSIPv6AddressIsZero((X)->ip.v6)) ) + ((X)->type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero((X)->ip.v4)) || \ + ((X)->type == mDNSAddrType_IPv6 && mDNSIPv6AddressIsZero((X)->ip.v6)) ) #define mDNSAddressIsValidNonZero(X) ( \ - ((X)->type == mDNSAddrType_IPv4 && !mDNSIPv4AddressIsZero((X)->ip.v4)) || \ - ((X)->type == mDNSAddrType_IPv6 && !mDNSIPv6AddressIsZero((X)->ip.v6)) ) + ((X)->type == mDNSAddrType_IPv4 && !mDNSIPv4AddressIsZero((X)->ip.v4)) || \ + ((X)->type == mDNSAddrType_IPv6 && !mDNSIPv6AddressIsZero((X)->ip.v6)) ) #define mDNSAddressIsOnes(X) ( \ - ((X)->type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes((X)->ip.v4)) || \ - ((X)->type == mDNSAddrType_IPv6 && mDNSIPv6AddressIsOnes((X)->ip.v6)) ) + ((X)->type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes((X)->ip.v4)) || \ + ((X)->type == mDNSAddrType_IPv6 && mDNSIPv6AddressIsOnes((X)->ip.v6)) ) #define mDNSAddressIsValid(X) ( \ - ((X)->type == mDNSAddrType_IPv4) ? !(mDNSIPv4AddressIsZero((X)->ip.v4) || mDNSIPv4AddressIsOnes((X)->ip.v4)) : \ - ((X)->type == mDNSAddrType_IPv6) ? !(mDNSIPv6AddressIsZero((X)->ip.v6) || mDNSIPv6AddressIsOnes((X)->ip.v6)) : mDNSfalse) + ((X)->type == mDNSAddrType_IPv4) ? !(mDNSIPv4AddressIsZero((X)->ip.v4) || mDNSIPv4AddressIsOnes((X)->ip.v4)) : \ + ((X)->type == mDNSAddrType_IPv6) ? !(mDNSIPv6AddressIsZero((X)->ip.v6) || mDNSIPv6AddressIsOnes((X)->ip.v6)) : mDNSfalse) + +#define mDNSv4AddressIsLinkLocal(X) ((X)->b[0] == 169 && (X)->b[1] == 254) +#define mDNSv6AddressIsLinkLocal(X) ((X)->b[0] == 0xFE && ((X)->b[1] & 0xC0) == 0x80) + +#define mDNSAddressIsLinkLocal(X) ( \ + ((X)->type == mDNSAddrType_IPv4) ? mDNSv4AddressIsLinkLocal(&(X)->ip.v4) : \ + ((X)->type == mDNSAddrType_IPv6) ? mDNSv6AddressIsLinkLocal(&(X)->ip.v6) : mDNSfalse) +#define mDNSv4AddressIsLoopback(X) ((X)->b[0] == 127 && (X)->b[1] == 0 && (X)->b[2] == 0 && (X)->b[3] == 1) +#define mDNSv6AddressIsLoopback(X) ((((X)->l[0] | (X)->l[1] | (X)->l[2]) == 0) && ((X)->b[12] == 0 && (X)->b[13] == 0 && (X)->b[14] == 0 && (X)->b[15] == 1)) + +#define mDNSAddressIsLoopback(X) ( \ + ((X)->type == mDNSAddrType_IPv4) ? mDNSv4AddressIsLoopback(&(X)->ip.v4) : \ + ((X)->type == mDNSAddrType_IPv6) ? mDNSv6AddressIsLoopback(&(X)->ip.v6) : mDNSfalse) // *************************************************************************** #if 0 +#pragma mark - #pragma mark - Authentication Support #endif -#define HMAC_LEN 64 -#define HMAC_IPAD 0x36 -#define HMAC_OPAD 0x5c -#define MD5_LEN 16 - -// padded keys for inned/outer hash rounds -typedef struct - { - mDNSu8 ipad[HMAC_LEN]; - mDNSu8 opad[HMAC_LEN]; - } HMAC_Key; - -// Internal data structure to maintain authentication information for an update domain -typedef struct uDNS_AuthInfo - { - domainname zone; - domainname keyname; - HMAC_Key key; - struct uDNS_AuthInfo *next; - } uDNS_AuthInfo; - // Unicast DNS and Dynamic Update specific Client Calls // -// mDNS_SetSecretForZone tells the core to authenticate (via TSIG with an HMAC_MD5 hash of the shared secret) +// mDNS_SetSecretForDomain tells the core to authenticate (via TSIG with an HMAC_MD5 hash of the shared secret) // when dynamically updating a given zone (and its subdomains). The key used in authentication must be in // domain name format. The shared secret must be a null-terminated base64 encoded string. A minimum size of // 16 bytes (128 bits) is recommended for an MD5 hash as per RFC 2485. // Calling this routine multiple times for a zone replaces previously entered values. Call with a NULL key -// to dissable authentication for the zone. +// to disable authentication for the zone. A non-NULL autoTunnelPrefix means this is an AutoTunnel domain, +// and the value is prepended to the IPSec identifier (used for key lookup) -extern mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const domainname *key, const char *sharedSecret); +extern mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info, + const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port, mDNSBool autoTunnel); + +extern void RecreateNATMappings(mDNS *const m, const mDNSu32 waitTicks); // Hostname/Unicast Interface Configuration // All hostnames advertised point to one IPv4 address and/or one IPv6 address, set via SetPrimaryInterfaceInfo. Invoking this routine // updates all existing hostnames to point to the new address. - + // A hostname is added via AddDynDNSHostName, which points to the primary interface's v4 and/or v6 addresss // The status callback is invoked to convey success or failure codes - the callback should not modify the AuthRecord or free memory. @@ -2559,37 +2990,55 @@ extern mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const doma // Host domains added prior to specification of the primary interface address and computer name will be deferred until // these values are initialized. -// When routable V4 interfaces are added or removed, mDNS_UpdateLLQs should be called to re-estabish LLQs in case the -// destination address for events (i.e. the route) has changed. For performance reasons, the caller is responsible for -// batching changes, e.g. calling the routine only once if multiple interfaces are simultanously removed or added. - -// DNS servers used to resolve unicast queries are specified by mDNS_AddDNSServer, and may later be removed via mDNS_DeleteDNSServers. +// DNS servers used to resolve unicast queries are specified by mDNS_AddDNSServer. // For "split" DNS configurations, in which queries for different domains are sent to different servers (e.g. VPN and external), // a domain may be associated with a DNS server. For standard configurations, specify the root label (".") or NULL. - + extern void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext); extern void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn); extern void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router); -extern void mDNS_UpdateLLQs(mDNS *m); -extern void mDNS_AddDNSServer(mDNS *const m, const mDNSAddr *dnsAddr, const domainname *domain); -extern void mDNS_DeleteDNSServers(mDNS *const m); +extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, mDNSs32 serviceID, const mDNSAddr *addr, + const mDNSIPPort port, mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSu16 resGroupID, mDNSBool reqA, + mDNSBool reqAAAA, mDNSBool reqDO); +extern void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSOpaque16 responseFlags); +extern void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID); -// Routines called by the core, exported by DNSDigest.c +extern McastResolver *mDNS_AddMcastResolver(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, mDNSu32 timeout); + +// We use ((void *)0) here instead of mDNSNULL to avoid compile warnings on gcc 4.2 +#define mDNS_AddSearchDomain_CString(X, I) \ + do { domainname d__; if (((X) != (void*)0) && MakeDomainNameFromDNSNameString(&d__, (X)) && d__.c[0]) mDNS_AddSearchDomain(&d__, I);} while(0) -// Convert a base64 encoded key into a binary byte stream -extern mDNSs32 DNSDigest_Base64ToBin(const char *src, mDNSu8 *target, mDNSu32 targsize); +// Routines called by the core, exported by DNSDigest.c -// Convert an arbitrary binary key (of any length) into an HMAC key (stored in AuthInfo struct) -extern void DNSDigest_ConstructHMACKey(uDNS_AuthInfo *info, const mDNSu8 *key, mDNSu32 len); +// Convert an arbitrary base64 encoded key key into an HMAC key (stored in AuthInfo struct) +extern mDNSs32 DNSDigest_ConstructHMACKeyfromBase64(DomainAuthInfo *info, const char *b64key); -// sign a DNS message. The message must be compete, with all values in network byte order. end points to the end +// sign a DNS message. The message must be complete, with all values in network byte order. end points to the end // of the message, and is modified by this routine. numAdditionals is a pointer to the number of additional // records in HOST byte order, which is incremented upon successful completion of this routine. The function returns // the new end pointer on success, and NULL on failure. -extern mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16 *numAdditionals, uDNS_AuthInfo *info); +extern void DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAuthInfo *info, mDNSu16 tcode); + +#define SwapDNSHeaderBytes(M) do { \ + (M)->h.numQuestions = (mDNSu16)((mDNSu8 *)&(M)->h.numQuestions )[0] << 8 | ((mDNSu8 *)&(M)->h.numQuestions )[1]; \ + (M)->h.numAnswers = (mDNSu16)((mDNSu8 *)&(M)->h.numAnswers )[0] << 8 | ((mDNSu8 *)&(M)->h.numAnswers )[1]; \ + (M)->h.numAuthorities = (mDNSu16)((mDNSu8 *)&(M)->h.numAuthorities)[0] << 8 | ((mDNSu8 *)&(M)->h.numAuthorities)[1]; \ + (M)->h.numAdditionals = (mDNSu16)((mDNSu8 *)&(M)->h.numAdditionals)[0] << 8 | ((mDNSu8 *)&(M)->h.numAdditionals)[1]; \ +} while (0) + +#define DNSDigest_SignMessageHostByteOrder(M,E,INFO) \ + do { SwapDNSHeaderBytes(M); DNSDigest_SignMessage((M), (E), (INFO), 0); SwapDNSHeaderBytes(M); } while (0) + +// verify a DNS message. The message must be complete, with all values in network byte order. end points to the +// end of the record. tsig is a pointer to the resource record that contains the TSIG OPT record. info is +// the matching key to use for verifying the message. This function expects that the additionals member +// of the DNS message header has already had one subtracted from it. +extern mDNSBool DNSDigest_VerifyMessage(DNSMessage *msg, mDNSu8 *end, LargeCacheRecord *tsig, DomainAuthInfo *info, mDNSu16 *rcode, mDNSu16 *tcode); // *************************************************************************** #if 0 +#pragma mark - #pragma mark - PlatformSupport interface #endif @@ -2608,7 +3057,7 @@ extern mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16 *num // Note: mDNSPlatformMemAllocate/mDNSPlatformMemFree are only required for handling oversized resource records and unicast DNS. // If your target platform has a well-defined specialized application, and you know that all the records it uses // are InlineCacheRDSize or less, then you can just make a simple mDNSPlatformMemAllocate() stub that always returns -// NULL. InlineCacheRDSize is a compile-time constant, which is set by default to 64. If you need to handle records +// NULL. InlineCacheRDSize is a compile-time constant, which is set by default to 68. If you need to handle records // a little larger than this and you don't want to have to implement run-time allocation and freeing, then you // can raise the value of this constant to a suitable value (at the expense of increased memory usage). // @@ -2625,29 +3074,65 @@ extern mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16 *num 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, const mDNSAddr *dst, mDNSIPPort dstport); + 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 (const void *src, void *dst); -extern mDNSu32 mDNSPlatformStrLen (const void *src); -extern void mDNSPlatformMemCopy (const void *src, void *dst, mDNSu32 len); -extern mDNSBool mDNSPlatformMemSame (const void *src, const void *dst, mDNSu32 len); -extern void mDNSPlatformMemZero ( void *dst, mDNSu32 len); +extern void mDNSPlatformStrCopy ( void *dst, const void *src); +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); +extern int mDNSPlatformMemCmp (const void *dst, const void *src, mDNSu32 len); +extern void mDNSPlatformMemZero ( void *dst, mDNSu32 len); +extern void mDNSPlatformQsort (void *base, int nel, int width, int (*compar)(const void *, const void *)); +#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING +#define mDNSPlatformMemAllocate(X) mallocL(# X, X) +#else extern void * mDNSPlatformMemAllocate (mDNSu32 len); +#endif extern void mDNSPlatformMemFree (void *mem); + +// If the platform doesn't have a strong PRNG, we define a naive multiply-and-add based on a seed +// from the platform layer. Long-term, we should embed an arc4 implementation, but the strength +// will still depend on the randomness of the seed. +#if !defined(_PLATFORM_HAS_STRONG_PRNG_) && (_BUILDING_XCODE_PROJECT_ || defined(_WIN32)) +#define _PLATFORM_HAS_STRONG_PRNG_ 1 +#endif +#if _PLATFORM_HAS_STRONG_PRNG_ +extern mDNSu32 mDNSPlatformRandomNumber(void); +#else extern mDNSu32 mDNSPlatformRandomSeed (void); +#endif // _PLATFORM_HAS_STRONG_PRNG_ + extern mStatus mDNSPlatformTimeInit (void); extern mDNSs32 mDNSPlatformRawTime (void); extern mDNSs32 mDNSPlatformUTC (void); -#define mDNS_TimeNow_NoLock(m) (mDNSPlatformRawTime() + m->timenow_adjust) +#define mDNS_TimeNow_NoLock(m) (mDNSPlatformRawTime() + (m)->timenow_adjust) + +#if MDNS_DEBUGMSGS +extern void mDNSPlatformWriteDebugMsg(const char *msg); +#endif +extern void mDNSPlatformWriteLogMsg(const char *ident, const char *msg, mDNSLogLevel_t loglevel); + +#if APPLE_OSX_mDNSResponder +// Utility function for ASL logging +mDNSexport void mDNSASLLog(uuid_t *uuid, const char *subdomain, const char *result, const char *signature, const char *fmt, ...); + +// Log unicast and multicast traffic statistics once a day. Also used for DNSSEC statistics. +#define kDefaultNextStatsticsLogTime (24 * 60 * 60) + +extern void mDNSLogStatistics(mDNS *const m); + +#endif // APPLE_OSX_mDNSResponder // Platform support modules should provide the following functions to map between opaque interface IDs // and interface indexes in order to support the DNS-SD API. If your target platform does not support // multiple interfaces and/or does not support the DNS-SD API, these functions can be empty. -extern mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS *const m, mDNSu32 index); -extern mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mDNSInterfaceID id); +extern mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex); +extern mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange); // Every platform support module must provide the following functions if it is to support unicast DNS // and Dynamic Update. @@ -2661,46 +3146,71 @@ extern mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mD // asynchronously fails, the TCPConnectionCallback should be invoked as usual, with the error being // returned in subsequent calls to PlatformReadTCP or PlatformWriteTCP. (This allows for platforms // with limited asynchronous error detection capabilities.) PlatformReadTCP and PlatformWriteTCP must -// return the number of bytes read/written, 0 if the call would block, and -1 if an error. +// return the number of bytes read/written, 0 if the call would block, and -1 if an error. PlatformReadTCP +// should set the closed argument if the socket has been closed. // PlatformTCPCloseConnection must close the connection to the peer and remove the descriptor from the // event loop. CloseConnectin may be called at any time, including in a ConnectionCallback. -typedef void (*TCPConnectionCallback)(int sd, void *context, mDNSBool ConnectionEstablished); -extern mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID, - TCPConnectionCallback callback, void *context, int *descriptor); -extern void mDNSPlatformTCPCloseConnection(int sd); -extern int mDNSPlatformReadTCP(int sd, void *buf, int buflen); -extern int mDNSPlatformWriteTCP(int sd, const char *msg, int len); +typedef enum +{ + kTCPSocketFlags_Zero = 0, + kTCPSocketFlags_UseTLS = (1 << 0) +} TCPSocketFlags; + +typedef void (*TCPConnectionCallback)(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err); +extern TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass); // creates a TCP socket +extern TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd); +extern int mDNSPlatformTCPGetFD(TCPSocket *sock); +extern mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, + mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context); +extern void mDNSPlatformTCPCloseConnection(TCPSocket *sock); +extern long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed); +extern long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len); +extern UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport); +extern mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock); +extern void mDNSPlatformUDPClose(UDPSocket *sock); +extern void mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd); +extern void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID); +extern void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID); +extern void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID); +extern void mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst); +extern void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win); +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); + +// mDNSPlatformTLSSetupCerts/mDNSPlatformTLSTearDownCerts used by dnsextd +extern mStatus mDNSPlatformTLSSetupCerts(void); +extern void mDNSPlatformTLSTearDownCerts(void); // Platforms that support unicast browsing and dynamic update registration for clients who do not specify a domain // in browse/registration calls must implement these routines to get the "default" browse/registration list. -// The Get() functions must return a linked list of DNameListElem structs, allocated via mDNSPlatformMemAllocate. -// Platforms may implement the Get() calls via the mDNS_CopyDNameList() helper routine. -// Callers should free lists obtained via the Get() calls with th mDNS_FreeDNameList routine, provided by the core. -typedef struct DNameListElem - { - domainname name; - struct DNameListElem *next; - } DNameListElem; +extern mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains, + DNameListElem **BrowseDomains, mDNSBool ackConfig); +extern mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *router); +extern void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status); -extern DNameListElem *mDNSPlatformGetSearchDomainList(void); -extern DNameListElem *mDNSPlatformGetRegDomainList(void); +extern void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason); +extern void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration); -// Helper functions provided by the core -extern DNameListElem *mDNS_CopyDNameList(const DNameListElem *orig); -extern void mDNS_FreeDNameList(DNameListElem *list); +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 mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf); + +extern void mDNSPlatformFormatTime(unsigned long t, mDNSu8 *buf, int bufsize); #ifdef _LEGACY_NAT_TRAVERSAL_ // Support for legacy NAT traversal protocols, implemented by the platform layer and callable by the core. - -#define DYN_PORT_MIN 49152 // ephemeral port range -#define DYN_PORT_MAX 65535 -#define LEGACY_NATMAP_MAX_TRIES 4 // if our desired mapping is taken, how many times we try mapping to a random port - -extern mStatus LNT_GetPublicIP(mDNSOpaque32 *ip); -extern mStatus LNT_MapPort(mDNSIPPort priv, mDNSIPPort pub, mDNSBool tcp); -extern mStatus LNT_UnmapPort(mDNSIPPort PubPort, mDNSBool tcp); +extern void LNT_SendDiscoveryMsg(mDNS *m); +extern void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID InterfaceID, const mDNSu8 *const data, const mDNSu16 len); +extern mStatus LNT_GetExternalAddress(mDNS *m); +extern mStatus LNT_MapPort(mDNS *m, NATTraversalInfo *const n); +extern mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *const n); +extern void LNT_ClearState(mDNS *const m); #endif // _LEGACY_NAT_TRAVERSAL_ // The core mDNS code provides these functions, for the platform support code to call at appropriate times @@ -2739,18 +3249,266 @@ extern mStatus LNT_UnmapPort(mDNSIPPort PubPort, mDNSBool tcp); // not lightweight second-by-second CPU power management modes.) extern void mDNS_SetFQDN(mDNS *const m); -extern mStatus mDNS_RegisterInterface (mDNS *const m, NetworkInterfaceInfo *set, mDNSs32 delay); -extern void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set); +extern void mDNS_ActivateNetWake_internal (mDNS *const m, NetworkInterfaceInfo *set); +extern void mDNS_DeactivateNetWake_internal(mDNS *const m, NetworkInterfaceInfo *set); +extern mStatus mDNS_RegisterInterface (mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping); +extern void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping); extern void mDNSCoreInitComplete(mDNS *const m, mStatus result); extern void mDNSCoreReceive(mDNS *const m, void *const msg, const mDNSu8 *const end, - const mDNSAddr *const srcaddr, const mDNSIPPort srcport, - const mDNSAddr *const dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID); + const mDNSAddr *const srcaddr, const mDNSIPPort srcport, + const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID); +extern void mDNSCoreRestartQueries(mDNS *const m); +extern void mDNSCoreRestartQuestion(mDNS *const m, DNSQuestion *q); +extern void mDNSCoreRestartRegistration(mDNS *const m, AuthRecord *rr, int announceCount); +typedef void (*FlushCache)(mDNS *const m); +typedef void (*CallbackBeforeStartQuery)(mDNS *const m, void *context); +extern void mDNSCoreRestartAddressQueries(mDNS *const m, mDNSBool SearchDomainsChanged, FlushCache flushCacheRecords, + CallbackBeforeStartQuery beforeQueryStart, void *context); +extern mDNSBool mDNSCoreHaveAdvertisedMulticastServices(mDNS *const m); extern void mDNSCoreMachineSleep(mDNS *const m, mDNSBool wake); +extern mDNSBool mDNSCoreReadyForSleep(mDNS *m, mDNSs32 now); +extern mDNSs32 mDNSCoreIntervalToNextWake(mDNS *const m, mDNSs32 now); + +extern void mDNSCoreReceiveRawPacket (mDNS *const m, const mDNSu8 *const p, const mDNSu8 *const end, const mDNSInterfaceID InterfaceID); extern mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip); +extern CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg, mDNSs32 delay, mDNSBool Add, const mDNSAddr *sourceAddress); +extern CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name); +extern void ReleaseCacheRecord(mDNS *const m, CacheRecord *r); +extern void ScheduleNextCacheCheckTime(mDNS *const m, const mDNSu32 slot, const mDNSs32 event); +extern void SetNextCacheCheckTimeForRecord(mDNS *const m, CacheRecord *const rr); +extern void GrantCacheExtensions(mDNS *const m, DNSQuestion *q, mDNSu32 lease); +extern void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr, + const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds, + mDNSInterfaceID InterfaceID, DNSServer *dnsserver); +extern void CompleteDeregistration(mDNS *const m, AuthRecord *rr); +extern void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheRecord *const rr, const QC_result AddRecord); +extern void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, ResourceRecord *rr); +extern char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID); +extern void DNSServerChangeForQuestion(mDNS *const m, DNSQuestion *q, DNSServer *newServer); +extern void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr); +extern void CheckSuppressUnusableQuestions(mDNS *const m); +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); + +// Used only in logging to restrict the number of /etc/hosts entries printed +extern void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result); +// exported for using the hash for /etc/hosts AuthRecords +extern AuthGroup *AuthGroupForName(AuthHash *r, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name); +extern AuthGroup *AuthGroupForRecord(AuthHash *r, const mDNSu32 slot, const ResourceRecord *const rr); +extern AuthGroup *InsertAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr); +extern AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr); +extern mDNSBool mDNS_CheckForCacheRecord(mDNS *const m, DNSQuestion *q, mDNSu16 qtype); + +// For now this AutoTunnel stuff is specific to Mac OS X. +// In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer +#if APPLE_OSX_mDNSResponder +extern void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord); +extern void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q); +extern void StartServerTunnel(mDNS *const m, DomainAuthInfo *const info); +extern void UpdateAutoTunnelDomainStatuses(const mDNS *const m); +extern void RemoveAutoTunnel6Record(mDNS *const m); +extern mDNSBool RecordReadyForSleep(mDNS *const m, AuthRecord *rr); +// For now this LocalSleepProxy stuff is specific to Mac OS X. +// In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer +extern mStatus ActivateLocalProxy(mDNS *const m, NetworkInterfaceInfo *const intf); +extern void mDNSPlatformUpdateDNSStatus(mDNS *const m, DNSQuestion *q); +extern void mDNSPlatformTriggerDNSRetry(mDNS *const m, DNSQuestion *v4q, DNSQuestion *v6q); +extern void mDNSPlatformLogToFile(int log_level, const char *buffer); +extern mDNSBool SupportsInNICProxy(NetworkInterfaceInfo *const intf); +#endif + +typedef void ProxyCallback (mDNS *const m, void *socket, void *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, + const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context); +extern void mDNSPlatformInitDNSProxySkts(mDNS *const m, ProxyCallback *UDPCallback, ProxyCallback *TCPCallback); +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 mDNSBool mDNSPlatformAllowPID(mDNS *const m, DNSQuestion *q); +extern mDNSs32 mDNSPlatformGetServiceID(mDNS *const m, DNSQuestion *q); +extern void mDNSPlatformSetDelegatePID(UDPSocket *src, const mDNSAddr *dst, DNSQuestion *q); +extern mDNSs32 mDNSPlatformGetPID(void); + +// *************************************************************************** +#if 0 +#pragma mark - +#pragma mark - Sleep Proxy +#endif + +// Sleep Proxy Server Property Encoding +// +// Sleep Proxy Servers are advertised using a structured service name, consisting of four +// metrics followed by a human-readable name. The metrics assist clients in deciding which +// Sleep Proxy Server(s) to use when multiple are available on the network. Each metric +// is a two-digit decimal number in the range 10-99. Lower metrics are generally better. +// +// AA-BB-CC-DD.FF Name +// +// Metrics: +// +// AA = Intent +// BB = Portability +// CC = Marginal Power +// DD = Total Power +// FF = Features Supported (Currently TCP Keepalive only) +// +// +// ** Intent Metric ** +// +// 20 = Dedicated Sleep Proxy Server -- a device, permanently powered on, +// installed for the express purpose of providing Sleep Proxy Service. +// +// 30 = Primary Network Infrastructure Hardware -- a router, DHCP server, NAT gateway, +// or similar permanently installed device which is permanently powered on. +// This is hardware designed for the express purpose of being network +// infrastructure, and for most home users is typically a single point +// of failure for the local network -- e.g. most home users only have +// a single NAT gateway / DHCP server. Even though in principle the +// hardware might technically be capable of running different software, +// a typical user is unlikely to do that. e.g. AirPort base station. +// +// 40 = Primary Network Infrastructure Software -- a general-purpose computer +// (e.g. Mac, Windows, Linux, etc.) which is currently running DHCP server +// or NAT gateway software, but the user could choose to turn that off +// fairly easily. e.g. iMac running Internet Sharing +// +// 50 = Secondary Network Infrastructure Hardware -- like primary infrastructure +// hardware, except not a single point of failure for the entire local network. +// For example, an AirPort base station in bridge mode. This may have clients +// associated with it, and if it goes away those clients will be inconvenienced, +// but unlike the NAT gateway / DHCP server, the entire local network is not +// dependent on it. +// +// 60 = Secondary Network Infrastructure Software -- like 50, but in a general- +// purpose CPU. +// +// 70 = Incidentally Available Hardware -- a device which has no power switch +// and is generally left powered on all the time. Even though it is not a +// part of what we conventionally consider network infrastructure (router, +// DHCP, NAT, DNS, etc.), and the rest of the network can operate fine +// without it, since it's available and unlikely to be turned off, it is a +// reasonable candidate for providing Sleep Proxy Service e.g. Apple TV, +// or an AirPort base station in client mode, associated with an existing +// wireless network (e.g. AirPort Express connected to a music system, or +// being used to share a USB printer). +// +// 80 = Incidentally Available Software -- a general-purpose computer which +// happens at this time to be set to "never sleep", and as such could be +// useful as a Sleep Proxy Server, but has not been intentionally provided +// for this purpose. Of all the Intent Metric categories this is the +// one most likely to be shut down or put to sleep without warning. +// However, if nothing else is availalable, it may be better than nothing. +// e.g. Office computer in the workplace which has been set to "never sleep" +// +// +// ** Portability Metric ** +// +// Inversely related to mass of device, on the basis that, all other things +// being equal, heavier devices are less likely to be moved than lighter devices. +// E.g. A MacBook running Internet Sharing is probably more likely to be +// put to sleep and taken away than a Mac Pro running Internet Sharing. +// The Portability Metric is a logarithmic decibel scale, computed by taking the +// (approximate) mass of the device in milligrammes, taking the base 10 logarithm +// of that, multiplying by 10, and subtracting the result from 100: +// +// Portability Metric = 100 - (log10(mg) * 10) +// +// The Portability Metric is not necessarily computed literally from the actual +// mass of the device; the intent is just that lower numbers indicate more +// permanent devices, and higher numbers indicate devices more likely to be +// removed from the network, e.g., in order of increasing portability: +// +// Mac Pro < iMac < Laptop < iPhone +// +// Example values: +// +// 10 = 1 metric tonne +// 40 = 1kg +// 70 = 1g +// 90 = 10mg +// +// +// ** Marginal Power and Total Power Metrics ** +// +// The Marginal Power Metric is the power difference between sleeping and staying awake +// to be a Sleep Proxy Server. +// +// The Total Power Metric is the total power consumption when being Sleep Proxy Server. +// +// The Power Metrics use a logarithmic decibel scale, computed as ten times the +// base 10 logarithm of the (approximate) power in microwatts: +// +// Power Metric = log10(uW) * 10 +// +// Higher values indicate higher power consumption. Example values: +// +// 10 = 10 uW +// 20 = 100 uW +// 30 = 1 mW +// 60 = 1 W +// 90 = 1 kW + +typedef enum +{ + mDNSSleepProxyMetric_Dedicated = 20, + mDNSSleepProxyMetric_PrimaryHardware = 30, + mDNSSleepProxyMetric_PrimarySoftware = 40, + mDNSSleepProxyMetric_SecondaryHardware = 50, + mDNSSleepProxyMetric_SecondarySoftware = 60, + mDNSSleepProxyMetric_IncidentalHardware = 70, + mDNSSleepProxyMetric_IncidentalSoftware = 80 +} mDNSSleepProxyMetric; + +typedef enum +{ + mDNS_NoWake = 0, // System does not support Wake on LAN + mDNS_WakeOnAC = 1, // System supports Wake on LAN when connected to AC power only + mDNS_WakeOnBattery = 2 // System supports Wake on LAN on battery +} mDNSWakeForNetworkAccess; + +extern void mDNSCoreBeSleepProxyServer_internal(mDNS *const m, mDNSu8 sps, mDNSu8 port, mDNSu8 marginalpower, mDNSu8 totpower, mDNSu8 features); +#define mDNSCoreBeSleepProxyServer(M,S,P,MP,TP,F) \ + do { mDNS_Lock(m); mDNSCoreBeSleepProxyServer_internal((M),(S),(P),(MP),(TP),(F)); mDNS_Unlock(m); } while(0) + +extern void FindSPSInCache(mDNS *const m, const DNSQuestion *const q, const CacheRecord *sps[3]); +#define PrototypeSPSName(X) ((X)[0] >= 11 && (X)[3] == '-' && (X)[ 4] == '9' && (X)[ 5] == '9' && \ + (X)[6] == '-' && (X)[ 7] == '9' && (X)[ 8] == '9' && \ + (X)[9] == '-' && (X)[10] == '9' && (X)[11] == '9' ) +#define ValidSPSName(X) ((X)[0] >= 5 && mDNSIsDigit((X)[1]) && mDNSIsDigit((X)[2]) && mDNSIsDigit((X)[4]) && mDNSIsDigit((X)[5])) +#define SPSMetric(X) (!ValidSPSName(X) || PrototypeSPSName(X) ? 1000000 : \ + ((X)[1]-'0') * 100000 + ((X)[2]-'0') * 10000 + ((X)[4]-'0') * 1000 + ((X)[5]-'0') * 100 + ((X)[7]-'0') * 10 + ((X)[8]-'0')) +#define LocalSPSMetric(X) ( (X)->SPSType * 10000 + (X)->SPSPortability * 100 + (X)->SPSMarginalPower) +#define SPSFeatures(X) ((X)[0] >= 13 && (X)[12] =='.' ? ((X)[13]-'0') : 0 ) + +#define MD5_DIGEST_LENGTH 16 /* digest length in bytes */ +#define MD5_BLOCK_BYTES 64 /* block size in bytes */ +#define MD5_BLOCK_LONG (MD5_BLOCK_BYTES / sizeof(mDNSu32)) + +typedef struct MD5state_st +{ + mDNSu32 A,B,C,D; + mDNSu32 Nl,Nh; + mDNSu32 data[MD5_BLOCK_LONG]; + int num; +} MD5_CTX; + +extern int MD5_Init(MD5_CTX *c); +extern int MD5_Update(MD5_CTX *c, const void *data, unsigned long len); +extern int MD5_Final(unsigned char *md, MD5_CTX *c); + // *************************************************************************** #if 0 +#pragma mark - #pragma mark - Compile-Time assertion checks #endif @@ -2760,29 +3518,72 @@ extern mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip); // what's wrong until you run the software. This way, if the assertion condition // is false, the array size is negative, and the complier complains immediately. -struct mDNS_CompileTimeAssertionChecks - { - // Check that the compiler generated our on-the-wire packet format structure definitions - // properly packed, without adding padding bytes to align fields on 32-bit or 64-bit boundaries. - char assert0[(sizeof(rdataSRV) == 262 ) ? 1 : -1]; - char assert1[(sizeof(DNSMessageHeader) == 12 ) ? 1 : -1]; - char assert2[(sizeof(DNSMessage) == 12+AbsoluteMaxDNSMessageData) ? 1 : -1]; - char assert3[(sizeof(mDNSs8) == 1 ) ? 1 : -1]; - char assert4[(sizeof(mDNSu8) == 1 ) ? 1 : -1]; - char assert5[(sizeof(mDNSs16) == 2 ) ? 1 : -1]; - char assert6[(sizeof(mDNSu16) == 2 ) ? 1 : -1]; - char assert7[(sizeof(mDNSs32) == 4 ) ? 1 : -1]; - char assert8[(sizeof(mDNSu32) == 4 ) ? 1 : -1]; - char assert9[(sizeof(mDNSOpaque16) == 2 ) ? 1 : -1]; - char assertA[(sizeof(mDNSOpaque32) == 4 ) ? 1 : -1]; - char assertB[(sizeof(mDNSOpaque128) == 16 ) ? 1 : -1]; - char assertC[(sizeof(CacheRecord ) >= sizeof(CacheGroup) ) ? 1 : -1]; - }; +struct CompileTimeAssertionChecks_mDNS +{ + // Check that the compiler generated our on-the-wire packet format structure definitions + // properly packed, without adding padding bytes to align fields on 32-bit or 64-bit boundaries. + char assert0[(sizeof(rdataSRV) == 262 ) ? 1 : -1]; + char assert1[(sizeof(DNSMessageHeader) == 12 ) ? 1 : -1]; + char assert2[(sizeof(DNSMessage) == 12+AbsoluteMaxDNSMessageData) ? 1 : -1]; + char assert3[(sizeof(mDNSs8) == 1 ) ? 1 : -1]; + char assert4[(sizeof(mDNSu8) == 1 ) ? 1 : -1]; + char assert5[(sizeof(mDNSs16) == 2 ) ? 1 : -1]; + char assert6[(sizeof(mDNSu16) == 2 ) ? 1 : -1]; + char assert7[(sizeof(mDNSs32) == 4 ) ? 1 : -1]; + char assert8[(sizeof(mDNSu32) == 4 ) ? 1 : -1]; + char assert9[(sizeof(mDNSOpaque16) == 2 ) ? 1 : -1]; + char assertA[(sizeof(mDNSOpaque32) == 4 ) ? 1 : -1]; + char assertB[(sizeof(mDNSOpaque128) == 16 ) ? 1 : -1]; + char assertC[(sizeof(CacheRecord ) == sizeof(CacheGroup) ) ? 1 : -1]; + char assertD[(sizeof(int) >= 4 ) ? 1 : -1]; + char assertE[(StandardAuthRDSize >= 256 ) ? 1 : -1]; + char assertF[(sizeof(EthernetHeader) == 14 ) ? 1 : -1]; + char assertG[(sizeof(ARP_EthIP ) == 28 ) ? 1 : -1]; + char assertH[(sizeof(IPv4Header ) == 20 ) ? 1 : -1]; + char assertI[(sizeof(IPv6Header ) == 40 ) ? 1 : -1]; + char assertJ[(sizeof(IPv6NDP ) == 24 ) ? 1 : -1]; + char assertK[(sizeof(UDPHeader ) == 8 ) ? 1 : -1]; + char assertL[(sizeof(IKEHeader ) == 28 ) ? 1 : -1]; + char assertM[(sizeof(TCPHeader ) == 20 ) ? 1 : -1]; + + // 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_RDataBody [(sizeof(RDataBody) == 264) ? 1 : -1]; + char sizecheck_ResourceRecord [(sizeof(ResourceRecord) <= 72) ? 1 : -1]; + 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) <= 832) ? 1 : -1]; + +// Checks commented out when sizeof(DNSQuestion) change cascaded into having to change yet another +// set of hardcoded size values because these structures contain one or more DNSQuestion +// instances. +// char sizecheck_ZoneData [(sizeof(ZoneData) <= 1648) ? 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) <= 6988) ? 1 : -1]; + char sizecheck_ServiceRecordSet [(sizeof(ServiceRecordSet) <= 5540) ? 1 : -1]; + char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 7888) ? 1 : -1]; +// char sizecheck_ServiceInfoQuery [(sizeof(ServiceInfoQuery) <= 3302) ? 1 : -1]; +#if APPLE_OSX_mDNSResponder +// char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1160) ? 1 : -1]; +#endif +}; + +// Routine to initialize device-info TXT record contents +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); +#endif // *************************************************************************** #ifdef __cplusplus - } +} #endif #endif