14b22b933Srs200217 /* -*- Mode: C; tab-width: 4 -*-
24b22b933Srs200217 *
34b22b933Srs200217 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
44b22b933Srs200217 *
54b22b933Srs200217 * Licensed under the Apache License, Version 2.0 (the "License");
64b22b933Srs200217 * you may not use this file except in compliance with the License.
74b22b933Srs200217 * You may obtain a copy of the License at
84b22b933Srs200217 *
94b22b933Srs200217 * http://www.apache.org/licenses/LICENSE-2.0
104b22b933Srs200217 *
114b22b933Srs200217 * Unless required by applicable law or agreed to in writing, software
124b22b933Srs200217 * distributed under the License is distributed on an "AS IS" BASIS,
134b22b933Srs200217 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
144b22b933Srs200217 * See the License for the specific language governing permissions and
154b22b933Srs200217 * limitations under the License.
164b22b933Srs200217
174b22b933Srs200217 Change History (most recent first):
184b22b933Srs200217
194b22b933Srs200217 $Log: DNSCommon.c,v $
204b22b933Srs200217 Revision 1.100.2.1 2006/08/29 06:24:22 cheshire
214b22b933Srs200217 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
224b22b933Srs200217
234b22b933Srs200217 Revision 1.100 2006/06/08 22:58:46 cheshire
244b22b933Srs200217 <rdar://problem/4335605> IPv6 link-local address prefix is FE80::/10, not FE80::/16
254b22b933Srs200217
264b22b933Srs200217 Revision 1.99 2006/05/18 01:32:33 cheshire
274b22b933Srs200217 <rdar://problem/4472706> iChat: Lost connection with Bonjour
284b22b933Srs200217 (mDNSResponder insufficiently defensive against malformed browsing PTR responses)
294b22b933Srs200217
304b22b933Srs200217 Revision 1.98 2006/03/19 17:00:58 cheshire
314b22b933Srs200217 Define symbol MaxMsg instead of using hard-coded constant value '80'
324b22b933Srs200217
334b22b933Srs200217 Revision 1.97 2006/03/18 21:47:56 cheshire
344b22b933Srs200217 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
354b22b933Srs200217
364b22b933Srs200217 Revision 1.96 2006/03/10 21:51:42 cheshire
374b22b933Srs200217 <rdar://problem/4111464> After record update, old record sometimes remains in cache
384b22b933Srs200217 Split out SameRDataBody() into a separate routine so it can be called from other code
394b22b933Srs200217
404b22b933Srs200217 Revision 1.95 2006/03/08 22:43:11 cheshire
414b22b933Srs200217 Use "localdomain" symbol instead of literal string
424b22b933Srs200217
434b22b933Srs200217 Revision 1.94 2006/03/02 21:59:55 cheshire
444b22b933Srs200217 <rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
454b22b933Srs200217 Improve sanity checks & debugging support in GetLargeResourceRecord()
464b22b933Srs200217
474b22b933Srs200217 Revision 1.93 2006/03/02 20:30:47 cheshire
484b22b933Srs200217 Improved GetRRDisplayString to also show priority, weight, and port for SRV records
494b22b933Srs200217
504b22b933Srs200217 Revision 1.92 2005/09/16 21:06:49 cheshire
514b22b933Srs200217 Use mDNS_TimeNow_NoLock macro, instead of writing "mDNSPlatformRawTime() + m->timenow_adjust" all over the place
524b22b933Srs200217
534b22b933Srs200217 Revision 1.91 2005/07/10 22:10:37 cheshire
544b22b933Srs200217 The getOptRdata routine implicitly assumes the destination ResourceRecord is large enough to
554b22b933Srs200217 hold MaximumRDSize bytes, but its parameter was a generic ResourceRecord, which need not be that
564b22b933Srs200217 large. Changing the parameter to a LargeCacheRecord makes it clearer what the routine requires.
574b22b933Srs200217
584b22b933Srs200217 Revision 1.90 2005/03/21 00:33:51 shersche
594b22b933Srs200217 <rdar://problem/4021486> Fix build warnings on Win32 platform
604b22b933Srs200217
614b22b933Srs200217 Revision 1.89 2005/03/17 18:59:38 ksekar
624b22b933Srs200217 <rdar://problem/4012279> Properly parse multiple LLQ Options per packet on Windows
634b22b933Srs200217
644b22b933Srs200217 Revision 1.88 2005/03/16 00:42:32 ksekar
654b22b933Srs200217 <rdar://problem/4012279> Long-lived queries not working on Windows
664b22b933Srs200217
674b22b933Srs200217 Revision 1.87 2005/02/25 04:21:00 cheshire
684b22b933Srs200217 <rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing
694b22b933Srs200217
704b22b933Srs200217 Revision 1.86 2005/02/18 00:43:12 cheshire
714b22b933Srs200217 <rdar://problem/4010245> mDNSResponder should auto-truncate service names that are too long
724b22b933Srs200217
734b22b933Srs200217 Revision 1.85 2005/02/10 22:35:17 cheshire
744b22b933Srs200217 <rdar://problem/3727944> Update name
754b22b933Srs200217
764b22b933Srs200217 Revision 1.84 2005/02/03 00:44:38 cheshire
774b22b933Srs200217 <rdar://problem/3986663> DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL
784b22b933Srs200217
794b22b933Srs200217 Revision 1.83 2005/01/27 22:57:55 cheshire
804b22b933Srs200217 Fix compile errors on gcc4
814b22b933Srs200217
824b22b933Srs200217 Revision 1.82 2005/01/19 03:27:03 cheshire
834b22b933Srs200217 <rdar://problem/3961051> CPU Spin in mDNSResponder
844b22b933Srs200217 GetNextScheduledEvent() needs to check LocalRecordReady()
854b22b933Srs200217
864b22b933Srs200217 Revision 1.81 2004/12/18 03:13:45 cheshire
874b22b933Srs200217 <rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records
884b22b933Srs200217
894b22b933Srs200217 Revision 1.80 2004/12/16 21:46:43 cheshire
904b22b933Srs200217 Add DNSTypeName case for kDNSType_SOA
914b22b933Srs200217
924b22b933Srs200217 Revision 1.79 2004/12/16 21:38:37 cheshire
934b22b933Srs200217 Add DNSTypeName case for kDNSType_NS
944b22b933Srs200217
954b22b933Srs200217 Revision 1.78 2004/12/16 21:27:37 ksekar
964b22b933Srs200217 Fixed build failures when compiled with verbose debugging messages
974b22b933Srs200217
984b22b933Srs200217 Revision 1.77 2004/12/16 20:12:59 cheshire
994b22b933Srs200217 <rdar://problem/3324626> Cache memory management improvements
1004b22b933Srs200217
1014b22b933Srs200217 Revision 1.76 2004/12/16 08:05:29 shersche
1024b22b933Srs200217 Remove extranenous semicolons that cause compilation errors on Windows
1034b22b933Srs200217
1044b22b933Srs200217 Revision 1.75 2004/12/15 02:11:22 ksekar
1054b22b933Srs200217 <rdar://problem/3917317> Don't check for Dynamic DNS hostname uniqueness
1064b22b933Srs200217
1074b22b933Srs200217 Revision 1.74 2004/12/09 22:49:15 ksekar
1084b22b933Srs200217 <rdar://problem/3913653> Wide-Area Goodbyes broken
1094b22b933Srs200217
1104b22b933Srs200217 Revision 1.73 2004/12/07 22:49:06 cheshire
1114b22b933Srs200217 <rdar://problem/3908850> BIND doesn't allow zero-length TXT records
1124b22b933Srs200217
1134b22b933Srs200217 Revision 1.72 2004/12/06 21:15:20 ksekar
1144b22b933Srs200217 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
1154b22b933Srs200217
1164b22b933Srs200217 Revision 1.71 2004/12/04 02:12:45 cheshire
1174b22b933Srs200217 <rdar://problem/3517236> mDNSResponder puts LargeCacheRecord on the stack
1184b22b933Srs200217
1194b22b933Srs200217 Revision 1.70 2004/12/03 19:52:44 ksekar
1204b22b933Srs200217 Use PutResourceRecordTTLJumbo for putDeletionRecord()
1214b22b933Srs200217
1224b22b933Srs200217 Revision 1.69 2004/12/03 07:20:50 ksekar
1234b22b933Srs200217 <rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
1244b22b933Srs200217
1254b22b933Srs200217 Revision 1.68 2004/11/24 00:10:43 cheshire
1264b22b933Srs200217 <rdar://problem/3869241> For unicast operations, verify that service types are legal
1274b22b933Srs200217
1284b22b933Srs200217 Revision 1.67 2004/10/26 03:52:02 cheshire
1294b22b933Srs200217 Update checkin comments
1304b22b933Srs200217
1314b22b933Srs200217 Revision 1.66 2004/10/23 01:16:00 cheshire
1324b22b933Srs200217 <rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
1334b22b933Srs200217
1344b22b933Srs200217 Revision 1.65 2004/10/20 02:15:09 cheshire
1354b22b933Srs200217 Add case in GetRRDisplayString() to display NS rdata
1364b22b933Srs200217
1374b22b933Srs200217 Revision 1.64 2004/10/13 00:24:02 cheshire
1384b22b933Srs200217 Disable "array is too small to include a terminating null character" warning on Windows
1394b22b933Srs200217
1404b22b933Srs200217 Revision 1.63 2004/10/10 06:57:14 cheshire
1414b22b933Srs200217 Change definition of "localdomain" to make code compile a little smaller
1424b22b933Srs200217
1434b22b933Srs200217 Revision 1.62 2004/10/06 01:44:19 cheshire
1444b22b933Srs200217 <rdar://problem/3813936> Resolving too quickly sometimes returns stale TXT record
1454b22b933Srs200217
1464b22b933Srs200217 Revision 1.61 2004/09/30 00:24:56 ksekar
1474b22b933Srs200217 <rdar://problem/3695802> Dynamically update default registration domains on config change
1484b22b933Srs200217
1494b22b933Srs200217 Revision 1.60 2004/09/27 23:25:30 cheshire
1504b22b933Srs200217 Fix compiler warning: soa.serial is signed, not unsigned
1514b22b933Srs200217
1524b22b933Srs200217 Revision 1.59 2004/09/27 22:53:45 ksekar
1534b22b933Srs200217 Fixed getLargeResourceRecord for SOA rdata.
1544b22b933Srs200217
1554b22b933Srs200217 Revision 1.58 2004/09/25 02:41:39 cheshire
1564b22b933Srs200217 <rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events
1574b22b933Srs200217
1584b22b933Srs200217 Revision 1.57 2004/09/25 02:24:27 cheshire
1594b22b933Srs200217 Removed unused rr->UseCount
1604b22b933Srs200217
1614b22b933Srs200217 Revision 1.56 2004/09/24 20:57:39 cheshire
1624b22b933Srs200217 <rdar://problem/3680902> Eliminate inappropriate casts that cause misaligned-address errors
1634b22b933Srs200217
1644b22b933Srs200217 Revision 1.55 2004/09/17 01:08:48 cheshire
1654b22b933Srs200217 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
1664b22b933Srs200217 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
1674b22b933Srs200217 declared in that file are ONLY appropriate to single-address-space embedded applications.
1684b22b933Srs200217 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
1694b22b933Srs200217
1704b22b933Srs200217 Revision 1.54 2004/09/17 00:49:51 cheshire
1714b22b933Srs200217 Get rid of now-unused GetResourceRecord -- the correct (safe) routine to use
1724b22b933Srs200217 is GetLargeResourceRecord
1734b22b933Srs200217
1744b22b933Srs200217 Revision 1.53 2004/09/17 00:31:51 cheshire
1754b22b933Srs200217 For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
1764b22b933Srs200217
1774b22b933Srs200217 Revision 1.52 2004/09/17 00:19:10 cheshire
1784b22b933Srs200217 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
1794b22b933Srs200217
1804b22b933Srs200217 Revision 1.51 2004/09/16 02:29:39 cheshire
1814b22b933Srs200217 Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
1824b22b933Srs200217 uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
1834b22b933Srs200217
1844b22b933Srs200217 Revision 1.50 2004/09/16 01:58:14 cheshire
1854b22b933Srs200217 Fix compiler warnings
1864b22b933Srs200217
1874b22b933Srs200217 Revision 1.49 2004/09/14 23:42:35 cheshire
1884b22b933Srs200217 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
1894b22b933Srs200217
1904b22b933Srs200217 Revision 1.48 2004/09/14 23:27:46 cheshire
1914b22b933Srs200217 Fix compile errors
1924b22b933Srs200217
1934b22b933Srs200217 Revision 1.47 2004/08/25 02:50:04 cheshire
1944b22b933Srs200217 <rdar://problem/3561220> Browses are no longer piggybacking on other browses
1954b22b933Srs200217 Make mDNSSameAddress() recognise that two mDNSAddrType_None addresses are necessarily equal
1964b22b933Srs200217
1974b22b933Srs200217 Revision 1.46 2004/08/18 17:35:40 ksekar
1984b22b933Srs200217 <rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
1994b22b933Srs200217
2004b22b933Srs200217 Revision 1.45 2004/08/15 18:26:00 cheshire
2014b22b933Srs200217 Don't use strcpy() on "struct domainname" objects; use AssignDomainName() instead
2024b22b933Srs200217 (A "struct domainname" is a collection of packed pascal strings, not a C string.)
2034b22b933Srs200217
2044b22b933Srs200217 Revision 1.44 2004/08/13 23:46:58 cheshire
2054b22b933Srs200217 "asyncronous" -> "asynchronous"
2064b22b933Srs200217
2074b22b933Srs200217 Revision 1.43 2004/08/12 02:55:46 ksekar
2084b22b933Srs200217 Fix param order error moving putPrereqNameNotInUse from uDNS.c using
2094b22b933Srs200217 ustrcpy macro to DNSCommon.c using mDNSPlatformStrCopy().
2104b22b933Srs200217
2114b22b933Srs200217 Revision 1.42 2004/08/10 23:19:14 ksekar
2124b22b933Srs200217 <rdar://problem/3722542>: DNS Extension daemon for Wide Area Service Discovery
2134b22b933Srs200217 Moved routines/constants to allow extern access for garbage collection daemon
2144b22b933Srs200217
2154b22b933Srs200217 Revision 1.41 2004/08/10 01:10:01 cheshire
2164b22b933Srs200217 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
2174b22b933Srs200217 Minor revision from Roger Pantos
2184b22b933Srs200217
2194b22b933Srs200217 Revision 1.40 2004/08/04 22:10:46 cheshire
2204b22b933Srs200217 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
2214b22b933Srs200217 Change to use "._sub." instead of ".s." to mark subtypes.
2224b22b933Srs200217
2234b22b933Srs200217 Revision 1.39 2004/07/13 21:24:24 rpantos
2244b22b933Srs200217 Fix for <rdar://problem/3701120>.
2254b22b933Srs200217
2264b22b933Srs200217 Revision 1.38 2004/06/18 21:08:58 cheshire
2274b22b933Srs200217 <rdar://problem/3540040> Applications are registering invalid records
2284b22b933Srs200217 Attempts to create domain names like "www..apple.com." now logged to aid debugging
2294b22b933Srs200217
2304b22b933Srs200217 Revision 1.37 2004/06/18 20:25:42 cheshire
2314b22b933Srs200217 <rdar://problem/3488547> Add a syslog message if someone tries to use "local.arpa".
2324b22b933Srs200217
2334b22b933Srs200217 Revision 1.36 2004/06/18 19:09:59 cheshire
2344b22b933Srs200217 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
2354b22b933Srs200217
2364b22b933Srs200217 Revision 1.35 2004/06/05 00:14:44 cheshire
2374b22b933Srs200217 Fix signed/unsigned and other compiler warnings
2384b22b933Srs200217
2394b22b933Srs200217 Revision 1.34 2004/06/04 00:25:25 cheshire
2404b22b933Srs200217 Fix misaligned write exception that occurs on some platforms
2414b22b933Srs200217
2424b22b933Srs200217 Revision 1.33 2004/06/04 00:16:18 cheshire
2434b22b933Srs200217 Remove non-portable use of 'inline'
2444b22b933Srs200217
2454b22b933Srs200217 Revision 1.32 2004/06/03 03:09:58 ksekar
2464b22b933Srs200217 <rdar://problem/3668626>: Garbage Collection for Dynamic Updates
2474b22b933Srs200217
2484b22b933Srs200217 Revision 1.31 2004/05/28 23:42:36 ksekar
2494b22b933Srs200217 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
2504b22b933Srs200217
2514b22b933Srs200217 Revision 1.30 2004/05/26 09:08:04 bradley
2524b22b933Srs200217 Added cast to correct structure pointer when allocating domain name list element to fix C++ builds.
2534b22b933Srs200217
2544b22b933Srs200217 Revision 1.29 2004/05/18 23:51:25 cheshire
2554b22b933Srs200217 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
2564b22b933Srs200217
2574b22b933Srs200217 Revision 1.28 2004/05/13 04:54:20 ksekar
2584b22b933Srs200217 Unified list copy/free code. Added symetric list for
2594b22b933Srs200217
2604b22b933Srs200217 Revision 1.27 2004/04/22 20:29:07 cheshire
2614b22b933Srs200217 Log error message if no count field passed to PutResourceRecordTTL()
2624b22b933Srs200217
2634b22b933Srs200217 Revision 1.26 2004/04/22 04:07:01 cheshire
2644b22b933Srs200217 Fix from Bob Bradley: Don't try to do inline functions on compilers that don't support it
2654b22b933Srs200217
2664b22b933Srs200217 Revision 1.25 2004/04/22 03:05:28 cheshire
2674b22b933Srs200217 kDNSClass_ANY should be kDNSQClass_ANY
2684b22b933Srs200217
2694b22b933Srs200217 Revision 1.24 2004/04/22 02:51:20 cheshire
2704b22b933Srs200217 Use common code for HINFO/TXT and TSIG cases in putRData
2714b22b933Srs200217
2724b22b933Srs200217 Revision 1.23 2004/04/15 00:51:28 bradley
2734b22b933Srs200217 Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers.
2744b22b933Srs200217 Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers.
2754b22b933Srs200217
2764b22b933Srs200217 Revision 1.22 2004/04/14 23:09:28 ksekar
2774b22b933Srs200217 Support for TSIG signed dynamic updates.
2784b22b933Srs200217
2794b22b933Srs200217 Revision 1.21 2004/04/09 16:47:28 cheshire
2804b22b933Srs200217 <rdar://problem/3617655>: mDNSResponder escape handling inconsistent with BIND
2814b22b933Srs200217
2824b22b933Srs200217 Revision 1.20 2004/04/09 16:37:15 cheshire
2834b22b933Srs200217 Suggestion from Bob Bradley:
2844b22b933Srs200217 Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers
2854b22b933Srs200217
2864b22b933Srs200217 Revision 1.19 2004/04/02 19:34:38 cheshire
2874b22b933Srs200217 Fix broken comment
2884b22b933Srs200217
2894b22b933Srs200217 Revision 1.18 2004/03/30 06:45:00 cheshire
2904b22b933Srs200217 Compiler warning fixes from Don Woodward at Roku Labs
2914b22b933Srs200217
2924b22b933Srs200217 Revision 1.17 2004/03/19 22:25:20 cheshire
2934b22b933Srs200217 <rdar://problem/3579561>: Need to limit service types to fourteen characters
2944b22b933Srs200217 Won't actually do this for now, but keep the code around just in case
2954b22b933Srs200217
2964b22b933Srs200217 Revision 1.16 2004/03/08 02:45:35 cheshire
2974b22b933Srs200217 Minor change to make a couple of the log messages a bit shorter
2984b22b933Srs200217
2994b22b933Srs200217 Revision 1.15 2004/03/08 02:44:09 cheshire
3004b22b933Srs200217 <rdar://problem/3579561>: Need to limit service types to fourteen characters
3014b22b933Srs200217
3024b22b933Srs200217 Revision 1.14 2004/02/21 02:06:24 cheshire
3034b22b933Srs200217 Can't use anonymous unions -- they're non-standard and don't work on all compilers
3044b22b933Srs200217
3054b22b933Srs200217 Revision 1.13 2004/02/06 23:04:18 ksekar
3064b22b933Srs200217 Basic Dynamic Update support via mDNS_Register (dissabled via
3074b22b933Srs200217 UNICAST_REGISTRATION #define)
3084b22b933Srs200217
3094b22b933Srs200217 Revision 1.12 2004/02/03 22:37:10 cheshire
3104b22b933Srs200217 Delete unused (commented-out) code
3114b22b933Srs200217
3124b22b933Srs200217 Revision 1.11 2004/02/03 22:35:34 cheshire
3134b22b933Srs200217 <rdar://problem/3548256>: Should not allow empty string for resolve domain
3144b22b933Srs200217
3154b22b933Srs200217 Revision 1.10 2004/02/03 19:47:36 ksekar
3164b22b933Srs200217 Added an asynchronous state machine mechanism to uDNS.c, including
3174b22b933Srs200217 calls to find the parent zone for a domain name. Changes include code
3184b22b933Srs200217 in repository previously dissabled via "#if 0 incomplete". Codepath
3194b22b933Srs200217 is currently unused, and will be called to create update records, etc.
3204b22b933Srs200217
3214b22b933Srs200217 Revision 1.9 2004/01/27 20:15:22 cheshire
3224b22b933Srs200217 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
3234b22b933Srs200217
3244b22b933Srs200217 Revision 1.8 2004/01/24 23:24:36 cheshire
3254b22b933Srs200217 Expanded out the list of local domains to reduce risk of mistakes in future
3264b22b933Srs200217
3274b22b933Srs200217 Revision 1.7 2004/01/24 08:32:30 bradley
3284b22b933Srs200217 Mask values with 0xFF before casting to avoid runtime truncation errors on Windows debug builds.
3294b22b933Srs200217 Separated octal-escaped sequences preceding decimal digits to avoid errors with some compilers wanting
3304b22b933Srs200217 to signal potentially hidden errors about the subsequent digit not being part of the octal sequence.
3314b22b933Srs200217
3324b22b933Srs200217 Revision 1.6 2004/01/24 04:59:15 cheshire
3334b22b933Srs200217 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
3344b22b933Srs200217
3354b22b933Srs200217 Revision 1.5 2004/01/23 23:23:14 ksekar
3364b22b933Srs200217 Added TCP support for truncated unicast messages.
3374b22b933Srs200217
3384b22b933Srs200217 Revision 1.4 2004/01/22 02:15:33 cheshire
3394b22b933Srs200217 <rdar://problem/3536597>: Link-local reverse-mapping domains need to be resolved using link-local multicast
3404b22b933Srs200217
3414b22b933Srs200217 Revision 1.3 2004/01/21 21:16:29 cheshire
3424b22b933Srs200217 Minor tidy-up: Deleted a bunch of blank lines, trailing spaces, tabs, etc.
3434b22b933Srs200217
3444b22b933Srs200217 Revision 1.2 2003/12/13 05:47:48 bradley
3454b22b933Srs200217 Made local ptr const to fix error when assigning from const structure. Disable benign conditional
3464b22b933Srs200217 expression is constant warning when building with Microsoft compilers.
3474b22b933Srs200217
3484b22b933Srs200217 Revision 1.1 2003/12/13 03:05:27 ksekar
3494b22b933Srs200217 <rdar://problem/3192548>: DynDNS: Unicast query of service records
3504b22b933Srs200217
3514b22b933Srs200217 */
3524b22b933Srs200217
3534b22b933Srs200217 #pragma ident "%Z%%M% %I% %E% SMI"
3544b22b933Srs200217
3554b22b933Srs200217 // Set mDNS_InstantiateInlines to tell mDNSEmbeddedAPI.h to instantiate inline functions, if necessary
3564b22b933Srs200217 #define mDNS_InstantiateInlines 1
3574b22b933Srs200217 #include "DNSCommon.h"
3584b22b933Srs200217
3594b22b933Srs200217 // Disable certain benign warnings with Microsoft compilers
3604b22b933Srs200217 #if (defined(_MSC_VER))
3614b22b933Srs200217 // Disable "conditional expression is constant" warning for debug macros.
3624b22b933Srs200217 // Otherwise, this generates warnings for the perfectly natural construct "while(1)"
3634b22b933Srs200217 // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know
3644b22b933Srs200217 #pragma warning(disable:4127)
3654b22b933Srs200217 // Disable "array is too small to include a terminating null character" warning
3664b22b933Srs200217 // -- domain labels have an initial length byte, not a terminating null character
3674b22b933Srs200217 #pragma warning(disable:4295)
3684b22b933Srs200217 #endif
3694b22b933Srs200217
3704b22b933Srs200217 // ***************************************************************************
3714b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
3724b22b933Srs200217 #pragma mark -
3734b22b933Srs200217 #pragma mark - DNameList copy/deallocation routines
3744b22b933Srs200217 #endif
3754b22b933Srs200217
mDNS_CopyDNameList(const DNameListElem * orig)3764b22b933Srs200217 mDNSexport DNameListElem *mDNS_CopyDNameList(const DNameListElem *orig)
3774b22b933Srs200217 {
3784b22b933Srs200217 DNameListElem *copy = mDNSNULL, *newelem;
3794b22b933Srs200217 const DNameListElem *ptr;
3804b22b933Srs200217
3814b22b933Srs200217 for (ptr = orig; ptr; ptr = ptr->next)
3824b22b933Srs200217 {
3834b22b933Srs200217 newelem = (DNameListElem*)mDNSPlatformMemAllocate(sizeof(DNameListElem));
3844b22b933Srs200217 if (!newelem) { LogMsg("ERROR: malloc"); return mDNSNULL; }
3854b22b933Srs200217 AssignDomainName(&newelem->name, &ptr->name);
3864b22b933Srs200217 newelem->next = copy;
3874b22b933Srs200217 copy = newelem;
3884b22b933Srs200217 }
3894b22b933Srs200217 return copy;
3904b22b933Srs200217 }
3914b22b933Srs200217
mDNS_FreeDNameList(DNameListElem * list)3924b22b933Srs200217 mDNSexport void mDNS_FreeDNameList(DNameListElem *list)
3934b22b933Srs200217 {
3944b22b933Srs200217 DNameListElem *fptr;
3954b22b933Srs200217
3964b22b933Srs200217 while (list)
3974b22b933Srs200217 {
3984b22b933Srs200217 fptr = list;
3994b22b933Srs200217 list = list->next;
4004b22b933Srs200217 mDNSPlatformMemFree(fptr);
4014b22b933Srs200217 }
4024b22b933Srs200217 }
4034b22b933Srs200217
4044b22b933Srs200217 // ***************************************************************************
4054b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
4064b22b933Srs200217 #pragma mark -
4074b22b933Srs200217 #pragma mark - General Utility Functions
4084b22b933Srs200217 #endif
4094b22b933Srs200217
4104b22b933Srs200217 // return true for RFC1918 private addresses
IsPrivateV4Addr(mDNSAddr * addr)4114b22b933Srs200217 mDNSexport mDNSBool IsPrivateV4Addr(mDNSAddr *addr)
4124b22b933Srs200217 {
4134b22b933Srs200217 mDNSu8 *b;
4144b22b933Srs200217
4154b22b933Srs200217 if (addr->type != mDNSAddrType_IPv4) return mDNSfalse;
4164b22b933Srs200217 b = addr->ip.v4.b;
4174b22b933Srs200217
4184b22b933Srs200217 return ((b[0] == 10) || // 10/8 prefix
4194b22b933Srs200217 (b[0] == 172 && b[1] > 15 && b[1] < 32) || // 172.16/12
4204b22b933Srs200217 (b[0] == 192 && b[1] == 168)); // 192.168/16
4214b22b933Srs200217 }
4224b22b933Srs200217
GetFirstActiveInterface(const NetworkInterfaceInfo * intf)4234b22b933Srs200217 mDNSexport const NetworkInterfaceInfo *GetFirstActiveInterface(const NetworkInterfaceInfo *intf)
4244b22b933Srs200217 {
4254b22b933Srs200217 while (intf && !intf->InterfaceActive) intf = intf->next;
4264b22b933Srs200217 return(intf);
4274b22b933Srs200217 }
4284b22b933Srs200217
GetNextActiveInterfaceID(const NetworkInterfaceInfo * intf)4294b22b933Srs200217 mDNSexport mDNSInterfaceID GetNextActiveInterfaceID(const NetworkInterfaceInfo *intf)
4304b22b933Srs200217 {
4314b22b933Srs200217 const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next);
4324b22b933Srs200217 if (next) return(next->InterfaceID); else return(mDNSNULL);
4334b22b933Srs200217 }
4344b22b933Srs200217
NumCacheRecordsForInterfaceID(const mDNS * const m,mDNSInterfaceID id)4354b22b933Srs200217 mDNSexport mDNSu32 NumCacheRecordsForInterfaceID(const mDNS *const m, mDNSInterfaceID id)
4364b22b933Srs200217 {
4374b22b933Srs200217 mDNSu32 slot, used = 0;
4384b22b933Srs200217 CacheGroup *cg;
4394b22b933Srs200217 CacheRecord *rr;
4404b22b933Srs200217 FORALL_CACHERECORDS(slot, cg, rr)
4414b22b933Srs200217 if (rr->resrec.InterfaceID == id) used++;
4424b22b933Srs200217 return(used);
4434b22b933Srs200217 }
4444b22b933Srs200217
DNSTypeName(mDNSu16 rrtype)4454b22b933Srs200217 mDNSexport char *DNSTypeName(mDNSu16 rrtype)
4464b22b933Srs200217 {
4474b22b933Srs200217 switch (rrtype)
4484b22b933Srs200217 {
4494b22b933Srs200217 case kDNSType_A: return("Addr");
4504b22b933Srs200217 case kDNSType_NS: return("NS");
4514b22b933Srs200217 case kDNSType_CNAME:return("CNAME");
4524b22b933Srs200217 case kDNSType_SOA: return("SOA");
4534b22b933Srs200217 case kDNSType_NULL: return("NULL");
4544b22b933Srs200217 case kDNSType_PTR: return("PTR");
4554b22b933Srs200217 case kDNSType_HINFO:return("HINFO");
4564b22b933Srs200217 case kDNSType_TXT: return("TXT");
4574b22b933Srs200217 case kDNSType_AAAA: return("AAAA");
4584b22b933Srs200217 case kDNSType_SRV: return("SRV");
4594b22b933Srs200217 case kDNSQType_ANY: return("ANY");
4604b22b933Srs200217 default: {
4614b22b933Srs200217 static char buffer[16];
4624b22b933Srs200217 mDNS_snprintf(buffer, sizeof(buffer), "(%d)", rrtype);
4634b22b933Srs200217 return(buffer);
4644b22b933Srs200217 }
4654b22b933Srs200217 }
4664b22b933Srs200217 }
4674b22b933Srs200217
4684b22b933Srs200217 // Note slight bug: this code uses the rdlength from the ResourceRecord object, to display
4694b22b933Srs200217 // the rdata from the RDataBody object. Sometimes this could be the wrong length -- but as
4704b22b933Srs200217 // long as this routine is only used for debugging messages, it probably isn't a big problem.
GetRRDisplayString_rdb(const ResourceRecord * rr,RDataBody * rd,char * buffer)4714b22b933Srs200217 mDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *rr, RDataBody *rd, char *buffer)
4724b22b933Srs200217 {
4734b22b933Srs200217 #define Max (MaxMsg-1)
4744b22b933Srs200217 char *ptr = buffer;
4754b22b933Srs200217 mDNSu32 length = mDNS_snprintf(buffer, Max, "%4d %##s %s ", rr->rdlength, rr->name->c, DNSTypeName(rr->rrtype));
4764b22b933Srs200217 switch (rr->rrtype)
4774b22b933Srs200217 {
4784b22b933Srs200217 case kDNSType_A: mDNS_snprintf(buffer+length, Max-length, "%.4a", &rd->ipv4); break;
4794b22b933Srs200217
4804b22b933Srs200217 case kDNSType_NS: // Same as PTR
4814b22b933Srs200217 case kDNSType_CNAME:// Same as PTR
4824b22b933Srs200217 case kDNSType_PTR: mDNS_snprintf(buffer+length, Max-length, "%##s", rd->name.c); break;
4834b22b933Srs200217
4844b22b933Srs200217 case kDNSType_HINFO:// Display this the same as TXT (just show first string)
4854b22b933Srs200217 case kDNSType_TXT: mDNS_snprintf(buffer+length, Max-length, "%#s", rd->txt.c); break;
4864b22b933Srs200217
4874b22b933Srs200217 case kDNSType_AAAA: mDNS_snprintf(buffer+length, Max-length, "%.16a", &rd->ipv6); break;
4884b22b933Srs200217 case kDNSType_SRV: mDNS_snprintf(buffer+length, Max-length, "%u %u %u %##s",
4894b22b933Srs200217 rd->srv.priority, rd->srv.weight, mDNSVal16(rd->srv.port), rd->srv.target.c); break;
4904b22b933Srs200217 default: mDNS_snprintf(buffer+length, Max-length, "RDLen %d: %s", rr->rdlength, rd->data); break;
4914b22b933Srs200217 }
4924b22b933Srs200217 for (ptr = buffer; *ptr; ptr++) if (*ptr < ' ') *ptr='.';
4934b22b933Srs200217 return(buffer);
4944b22b933Srs200217 }
4954b22b933Srs200217
mDNSRandom(mDNSu32 max)4964b22b933Srs200217 mDNSexport mDNSu32 mDNSRandom(mDNSu32 max)
4974b22b933Srs200217 {
4984b22b933Srs200217 static mDNSu32 seed = 0;
4994b22b933Srs200217 mDNSu32 mask = 1;
5004b22b933Srs200217
5014b22b933Srs200217 if (!seed)
5024b22b933Srs200217 {
5034b22b933Srs200217 int i;
5044b22b933Srs200217 seed = mDNSPlatformRandomSeed(); // Pick an initial seed
5054b22b933Srs200217 for (i=0; i<100; i++) seed = seed * 21 + 1; // And mix it up a bit
5064b22b933Srs200217 }
5074b22b933Srs200217 while (mask < max) mask = (mask << 1) | 1;
5084b22b933Srs200217 do seed = seed * 21 + 1; while ((seed & mask) > max);
5094b22b933Srs200217 return (seed & mask);
5104b22b933Srs200217 }
5114b22b933Srs200217
mDNSRandomFromFixedSeed(mDNSu32 seed,mDNSu32 max)5124b22b933Srs200217 mDNSexport mDNSu32 mDNSRandomFromFixedSeed(mDNSu32 seed, mDNSu32 max)
5134b22b933Srs200217 {
5144b22b933Srs200217 mDNSu32 mask = 1;
5154b22b933Srs200217 while (mask < max) mask = (mask << 1) | 1;
5164b22b933Srs200217 do seed = seed * 21 + 1; while ((seed & mask) > max);
5174b22b933Srs200217 return (seed & mask);
5184b22b933Srs200217 }
5194b22b933Srs200217
mDNSSameAddress(const mDNSAddr * ip1,const mDNSAddr * ip2)5204b22b933Srs200217 mDNSexport mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2)
5214b22b933Srs200217 {
5224b22b933Srs200217 if (ip1->type == ip2->type)
5234b22b933Srs200217 {
5244b22b933Srs200217 switch (ip1->type)
5254b22b933Srs200217 {
5264b22b933Srs200217 case mDNSAddrType_None : return(mDNStrue); // Empty addresses have no data and are therefore always equal
5274b22b933Srs200217 case mDNSAddrType_IPv4 : return(mDNSBool)(mDNSSameIPv4Address(ip1->ip.v4, ip2->ip.v4));
5284b22b933Srs200217 case mDNSAddrType_IPv6 : return(mDNSBool)(mDNSSameIPv6Address(ip1->ip.v6, ip2->ip.v6));
5294b22b933Srs200217 }
5304b22b933Srs200217 }
5314b22b933Srs200217 return(mDNSfalse);
5324b22b933Srs200217 }
5334b22b933Srs200217
mDNSAddrIsDNSMulticast(const mDNSAddr * ip)5344b22b933Srs200217 mDNSexport mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip)
5354b22b933Srs200217 {
5364b22b933Srs200217 switch(ip->type)
5374b22b933Srs200217 {
5384b22b933Srs200217 case mDNSAddrType_IPv4: return(mDNSBool)(ip->ip.v4.NotAnInteger == AllDNSLinkGroupv4.NotAnInteger);
5394b22b933Srs200217 case mDNSAddrType_IPv6: return(mDNSBool)(ip->ip.v6.l[0] == AllDNSLinkGroupv6.l[0] &&
5404b22b933Srs200217 ip->ip.v6.l[1] == AllDNSLinkGroupv6.l[1] &&
5414b22b933Srs200217 ip->ip.v6.l[2] == AllDNSLinkGroupv6.l[2] &&
5424b22b933Srs200217 ip->ip.v6.l[3] == AllDNSLinkGroupv6.l[3] );
5434b22b933Srs200217 default: return(mDNSfalse);
5444b22b933Srs200217 }
5454b22b933Srs200217 }
5464b22b933Srs200217
5474b22b933Srs200217 // ***************************************************************************
5484b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
5494b22b933Srs200217 #pragma mark -
5504b22b933Srs200217 #pragma mark - Domain Name Utility Functions
5514b22b933Srs200217 #endif
5524b22b933Srs200217
SameDomainLabel(const mDNSu8 * a,const mDNSu8 * b)5534b22b933Srs200217 mDNSexport mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
5544b22b933Srs200217 {
5554b22b933Srs200217 int i;
5564b22b933Srs200217 const int len = *a++;
5574b22b933Srs200217
5584b22b933Srs200217 if (len > MAX_DOMAIN_LABEL)
5594b22b933Srs200217 { debugf("Malformed label (too long)"); return(mDNSfalse); }
5604b22b933Srs200217
5614b22b933Srs200217 if (len != *b++) return(mDNSfalse);
5624b22b933Srs200217 for (i=0; i<len; i++)
5634b22b933Srs200217 {
5644b22b933Srs200217 mDNSu8 ac = *a++;
5654b22b933Srs200217 mDNSu8 bc = *b++;
5664b22b933Srs200217 if (mDNSIsUpperCase(ac)) ac += 'a' - 'A';
5674b22b933Srs200217 if (mDNSIsUpperCase(bc)) bc += 'a' - 'A';
5684b22b933Srs200217 if (ac != bc) return(mDNSfalse);
5694b22b933Srs200217 }
5704b22b933Srs200217 return(mDNStrue);
5714b22b933Srs200217 }
5724b22b933Srs200217
SameDomainName(const domainname * const d1,const domainname * const d2)5734b22b933Srs200217 mDNSexport mDNSBool SameDomainName(const domainname *const d1, const domainname *const d2)
5744b22b933Srs200217 {
5754b22b933Srs200217 const mDNSu8 * a = d1->c;
5764b22b933Srs200217 const mDNSu8 * b = d2->c;
5774b22b933Srs200217 const mDNSu8 *const max = d1->c + MAX_DOMAIN_NAME; // Maximum that's valid
5784b22b933Srs200217
5794b22b933Srs200217 while (*a || *b)
5804b22b933Srs200217 {
5814b22b933Srs200217 if (a + 1 + *a >= max)
5824b22b933Srs200217 { debugf("Malformed domain name (more than 255 characters)"); return(mDNSfalse); }
5834b22b933Srs200217 if (!SameDomainLabel(a, b)) return(mDNSfalse);
5844b22b933Srs200217 a += 1 + *a;
5854b22b933Srs200217 b += 1 + *b;
5864b22b933Srs200217 }
5874b22b933Srs200217
5884b22b933Srs200217 return(mDNStrue);
5894b22b933Srs200217 }
5904b22b933Srs200217
IsLocalDomain(const domainname * d)5914b22b933Srs200217 mDNSexport mDNSBool IsLocalDomain(const domainname *d)
5924b22b933Srs200217 {
5934b22b933Srs200217 // Domains that are defined to be resolved via link-local multicast are:
5944b22b933Srs200217 // local., 254.169.in-addr.arpa., and {8,9,A,B}.E.F.ip6.arpa.
5954b22b933Srs200217 static const domainname *nL = (domainname*)"\x5" "local";
5964b22b933Srs200217 static const domainname *nR = (domainname*)"\x3" "254" "\x3" "169" "\x7" "in-addr" "\x4" "arpa";
5974b22b933Srs200217 static const domainname *n8 = (domainname*)"\x1" "8" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa";
5984b22b933Srs200217 static const domainname *n9 = (domainname*)"\x1" "9" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa";
5994b22b933Srs200217 static const domainname *nA = (domainname*)"\x1" "a" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa";
6004b22b933Srs200217 static const domainname *nB = (domainname*)"\x1" "b" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa";
6014b22b933Srs200217
6024b22b933Srs200217 const domainname *d1, *d2, *d3, *d4, *d5, *d6; // Top-level domain, second-level domain, etc.
6034b22b933Srs200217 d1 = d2 = d3 = d4 = d5 = d6 = mDNSNULL;
6044b22b933Srs200217 while (d->c[0])
6054b22b933Srs200217 {
6064b22b933Srs200217 d6 = d5; d5 = d4; d4 = d3; d3 = d2; d2 = d1; d1 = d;
6074b22b933Srs200217 d = (domainname*)(d->c + 1 + d->c[0]);
6084b22b933Srs200217 }
6094b22b933Srs200217
6104b22b933Srs200217 if (d1 && SameDomainName(d1, nL)) return(mDNStrue);
6114b22b933Srs200217 if (d4 && SameDomainName(d4, nR)) return(mDNStrue);
6124b22b933Srs200217 if (d6 && SameDomainName(d6, n8)) return(mDNStrue);
6134b22b933Srs200217 if (d6 && SameDomainName(d6, n9)) return(mDNStrue);
6144b22b933Srs200217 if (d6 && SameDomainName(d6, nA)) return(mDNStrue);
6154b22b933Srs200217 if (d6 && SameDomainName(d6, nB)) return(mDNStrue);
6164b22b933Srs200217 return(mDNSfalse);
6174b22b933Srs200217 }
6184b22b933Srs200217
6194b22b933Srs200217 // Returns length of a domain name INCLUDING the byte for the final null label
6204b22b933Srs200217 // i.e. for the root label "." it returns one
6214b22b933Srs200217 // For the FQDN "com." it returns 5 (length byte, three data bytes, final zero)
6224b22b933Srs200217 // Legal results are 1 (just root label) to 255 (MAX_DOMAIN_NAME)
6234b22b933Srs200217 // If the given domainname is invalid, result is 256
DomainNameLength(const domainname * const name)6244b22b933Srs200217 mDNSexport mDNSu16 DomainNameLength(const domainname *const name)
6254b22b933Srs200217 {
6264b22b933Srs200217 const mDNSu8 *src = name->c;
6274b22b933Srs200217 while (*src)
6284b22b933Srs200217 {
6294b22b933Srs200217 if (*src > MAX_DOMAIN_LABEL) return(MAX_DOMAIN_NAME+1);
6304b22b933Srs200217 src += 1 + *src;
6314b22b933Srs200217 if (src - name->c >= MAX_DOMAIN_NAME) return(MAX_DOMAIN_NAME+1);
6324b22b933Srs200217 }
6334b22b933Srs200217 return((mDNSu16)(src - name->c + 1));
6344b22b933Srs200217 }
6354b22b933Srs200217
6364b22b933Srs200217 // CompressedDomainNameLength returns the length of a domain name INCLUDING the byte
6374b22b933Srs200217 // for the final null label i.e. for the root label "." it returns one.
6384b22b933Srs200217 // E.g. for the FQDN "foo.com." it returns 9
6394b22b933Srs200217 // (length, three data bytes, length, three more data bytes, final zero).
6404b22b933Srs200217 // In the case where a parent domain name is provided, and the given name is a child
6414b22b933Srs200217 // of that parent, CompressedDomainNameLength returns the length of the prefix portion
6424b22b933Srs200217 // of the child name, plus TWO bytes for the compression pointer.
6434b22b933Srs200217 // E.g. for the name "foo.com." with parent "com.", it returns 6
6444b22b933Srs200217 // (length, three data bytes, two-byte compression pointer).
CompressedDomainNameLength(const domainname * const name,const domainname * parent)6454b22b933Srs200217 mDNSexport mDNSu16 CompressedDomainNameLength(const domainname *const name, const domainname *parent)
6464b22b933Srs200217 {
6474b22b933Srs200217 const mDNSu8 *src = name->c;
6484b22b933Srs200217 if (parent && parent->c[0] == 0) parent = mDNSNULL;
6494b22b933Srs200217 while (*src)
6504b22b933Srs200217 {
6514b22b933Srs200217 if (*src > MAX_DOMAIN_LABEL) return(MAX_DOMAIN_NAME+1);
6524b22b933Srs200217 if (parent && SameDomainName((domainname *)src, parent)) return((mDNSu16)(src - name->c + 2));
6534b22b933Srs200217 src += 1 + *src;
6544b22b933Srs200217 if (src - name->c >= MAX_DOMAIN_NAME) return(MAX_DOMAIN_NAME+1);
6554b22b933Srs200217 }
6564b22b933Srs200217 return((mDNSu16)(src - name->c + 1));
6574b22b933Srs200217 }
6584b22b933Srs200217
6594b22b933Srs200217 // AppendLiteralLabelString appends a single label to an existing (possibly empty) domainname.
6604b22b933Srs200217 // The C string contains the label as-is, with no escaping, etc.
6614b22b933Srs200217 // Any dots in the name are literal dots, not label separators
6624b22b933Srs200217 // If successful, AppendLiteralLabelString returns a pointer to the next unused byte
6634b22b933Srs200217 // in the domainname bufer (i.e., the next byte after the terminating zero).
6644b22b933Srs200217 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
6654b22b933Srs200217 // AppendLiteralLabelString returns mDNSNULL.
AppendLiteralLabelString(domainname * const name,const char * cstr)6664b22b933Srs200217 mDNSexport mDNSu8 *AppendLiteralLabelString(domainname *const name, const char *cstr)
6674b22b933Srs200217 {
6684b22b933Srs200217 mDNSu8 * ptr = name->c + DomainNameLength(name) - 1; // Find end of current name
6694b22b933Srs200217 const mDNSu8 *const lim1 = name->c + MAX_DOMAIN_NAME - 1; // Limit of how much we can add (not counting final zero)
6704b22b933Srs200217 const mDNSu8 *const lim2 = ptr + 1 + MAX_DOMAIN_LABEL;
6714b22b933Srs200217 const mDNSu8 *const lim = (lim1 < lim2) ? lim1 : lim2;
6724b22b933Srs200217 mDNSu8 *lengthbyte = ptr++; // Record where the length is going to go
6734b22b933Srs200217
6744b22b933Srs200217 while (*cstr && ptr < lim) *ptr++ = (mDNSu8)*cstr++; // Copy the data
6754b22b933Srs200217 *lengthbyte = (mDNSu8)(ptr - lengthbyte - 1); // Fill in the length byte
6764b22b933Srs200217 *ptr++ = 0; // Put the null root label on the end
6774b22b933Srs200217 if (*cstr) return(mDNSNULL); // Failure: We didn't successfully consume all input
6784b22b933Srs200217 else return(ptr); // Success: return new value of ptr
6794b22b933Srs200217 }
6804b22b933Srs200217
6814b22b933Srs200217 // AppendDNSNameString appends zero or more labels to an existing (possibly empty) domainname.
6824b22b933Srs200217 // The C string is in conventional DNS syntax:
6834b22b933Srs200217 // Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots.
6844b22b933Srs200217 // If successful, AppendDNSNameString returns a pointer to the next unused byte
6854b22b933Srs200217 // in the domainname bufer (i.e., the next byte after the terminating zero).
6864b22b933Srs200217 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
6874b22b933Srs200217 // AppendDNSNameString returns mDNSNULL.
AppendDNSNameString(domainname * const name,const char * cstring)6884b22b933Srs200217 mDNSexport mDNSu8 *AppendDNSNameString(domainname *const name, const char *cstring)
6894b22b933Srs200217 {
6904b22b933Srs200217 const char *cstr = cstring;
6914b22b933Srs200217 mDNSu8 * ptr = name->c + DomainNameLength(name) - 1; // Find end of current name
6924b22b933Srs200217 const mDNSu8 *const lim = name->c + MAX_DOMAIN_NAME - 1; // Limit of how much we can add (not counting final zero)
6934b22b933Srs200217 while (*cstr && ptr < lim) // While more characters, and space to put them...
6944b22b933Srs200217 {
6954b22b933Srs200217 mDNSu8 *lengthbyte = ptr++; // Record where the length is going to go
6964b22b933Srs200217 if (*cstr == '.') { LogMsg("AppendDNSNameString: Illegal empty label in name \"%s\"", cstring); return(mDNSNULL); }
6974b22b933Srs200217 while (*cstr && *cstr != '.' && ptr < lim) // While we have characters in the label...
6984b22b933Srs200217 {
6994b22b933Srs200217 mDNSu8 c = (mDNSu8)*cstr++; // Read the character
7004b22b933Srs200217 if (c == '\\') // If escape character, check next character
7014b22b933Srs200217 {
7024b22b933Srs200217 c = (mDNSu8)*cstr++; // Assume we'll just take the next character
7034b22b933Srs200217 if (mdnsIsDigit(cstr[-1]) && mdnsIsDigit(cstr[0]) && mdnsIsDigit(cstr[1]))
7044b22b933Srs200217 { // If three decimal digits,
7054b22b933Srs200217 int v0 = cstr[-1] - '0'; // then interpret as three-digit decimal
7064b22b933Srs200217 int v1 = cstr[ 0] - '0';
7074b22b933Srs200217 int v2 = cstr[ 1] - '0';
7084b22b933Srs200217 int val = v0 * 100 + v1 * 10 + v2;
7094b22b933Srs200217 if (val <= 255) { c = (mDNSu8)val; cstr += 2; } // If valid three-digit decimal value, use it
7104b22b933Srs200217 }
7114b22b933Srs200217 }
7124b22b933Srs200217 *ptr++ = c; // Write the character
7134b22b933Srs200217 }
7144b22b933Srs200217 if (*cstr) cstr++; // Skip over the trailing dot (if present)
7154b22b933Srs200217 if (ptr - lengthbyte - 1 > MAX_DOMAIN_LABEL) // If illegal label, abort
7164b22b933Srs200217 return(mDNSNULL);
7174b22b933Srs200217 *lengthbyte = (mDNSu8)(ptr - lengthbyte - 1); // Fill in the length byte
7184b22b933Srs200217 }
7194b22b933Srs200217
7204b22b933Srs200217 *ptr++ = 0; // Put the null root label on the end
7214b22b933Srs200217 if (*cstr) return(mDNSNULL); // Failure: We didn't successfully consume all input
7224b22b933Srs200217 else return(ptr); // Success: return new value of ptr
7234b22b933Srs200217 }
7244b22b933Srs200217
7254b22b933Srs200217 // AppendDomainLabel appends a single label to a name.
7264b22b933Srs200217 // If successful, AppendDomainLabel returns a pointer to the next unused byte
7274b22b933Srs200217 // in the domainname bufer (i.e., the next byte after the terminating zero).
7284b22b933Srs200217 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
7294b22b933Srs200217 // AppendDomainLabel returns mDNSNULL.
AppendDomainLabel(domainname * const name,const domainlabel * const label)7304b22b933Srs200217 mDNSexport mDNSu8 *AppendDomainLabel(domainname *const name, const domainlabel *const label)
7314b22b933Srs200217 {
7324b22b933Srs200217 int i;
7334b22b933Srs200217 mDNSu8 *ptr = name->c + DomainNameLength(name) - 1;
7344b22b933Srs200217
7354b22b933Srs200217 // Check label is legal
7364b22b933Srs200217 if (label->c[0] > MAX_DOMAIN_LABEL) return(mDNSNULL);
7374b22b933Srs200217
7384b22b933Srs200217 // Check that ptr + length byte + data bytes + final zero does not exceed our limit
7394b22b933Srs200217 if (ptr + 1 + label->c[0] + 1 > name->c + MAX_DOMAIN_NAME) return(mDNSNULL);
7404b22b933Srs200217
7414b22b933Srs200217 for (i=0; i<=label->c[0]; i++) *ptr++ = label->c[i]; // Copy the label data
7424b22b933Srs200217 *ptr++ = 0; // Put the null root label on the end
7434b22b933Srs200217 return(ptr);
7444b22b933Srs200217 }
7454b22b933Srs200217
AppendDomainName(domainname * const name,const domainname * const append)7464b22b933Srs200217 mDNSexport mDNSu8 *AppendDomainName(domainname *const name, const domainname *const append)
7474b22b933Srs200217 {
7484b22b933Srs200217 mDNSu8 * ptr = name->c + DomainNameLength(name) - 1; // Find end of current name
7494b22b933Srs200217 const mDNSu8 *const lim = name->c + MAX_DOMAIN_NAME - 1; // Limit of how much we can add (not counting final zero)
7504b22b933Srs200217 const mDNSu8 * src = append->c;
7514b22b933Srs200217 while(src[0])
7524b22b933Srs200217 {
7534b22b933Srs200217 int i;
7544b22b933Srs200217 if (ptr + 1 + src[0] > lim) return(mDNSNULL);
7554b22b933Srs200217 for (i=0; i<=src[0]; i++) *ptr++ = src[i];
7564b22b933Srs200217 *ptr = 0; // Put the null root label on the end
7574b22b933Srs200217 src += i;
7584b22b933Srs200217 }
7594b22b933Srs200217 return(ptr);
7604b22b933Srs200217 }
7614b22b933Srs200217
7624b22b933Srs200217 // MakeDomainLabelFromLiteralString makes a single domain label from a single literal C string (with no escaping).
7634b22b933Srs200217 // If successful, MakeDomainLabelFromLiteralString returns mDNStrue.
7644b22b933Srs200217 // If unable to convert the whole string to a legal domain label (i.e. because length is more than 63 bytes) then
7654b22b933Srs200217 // MakeDomainLabelFromLiteralString makes a legal domain label from the first 63 bytes of the string and returns mDNSfalse.
7664b22b933Srs200217 // In some cases silently truncated oversized names to 63 bytes is acceptable, so the return result may be ignored.
7674b22b933Srs200217 // In other cases silent truncation may not be acceptable, so in those cases the calling function needs to check the return result.
MakeDomainLabelFromLiteralString(domainlabel * const label,const char * cstr)7684b22b933Srs200217 mDNSexport mDNSBool MakeDomainLabelFromLiteralString(domainlabel *const label, const char *cstr)
7694b22b933Srs200217 {
7704b22b933Srs200217 mDNSu8 * ptr = label->c + 1; // Where we're putting it
7714b22b933Srs200217 const mDNSu8 *const limit = label->c + 1 + MAX_DOMAIN_LABEL; // The maximum we can put
7724b22b933Srs200217 while (*cstr && ptr < limit) *ptr++ = (mDNSu8)*cstr++; // Copy the label
7734b22b933Srs200217 label->c[0] = (mDNSu8)(ptr - label->c - 1); // Set the length byte
7744b22b933Srs200217 return(*cstr == 0); // Return mDNStrue if we successfully consumed all input
7754b22b933Srs200217 }
7764b22b933Srs200217
7774b22b933Srs200217 // MakeDomainNameFromDNSNameString makes a native DNS-format domainname from a C string.
7784b22b933Srs200217 // The C string is in conventional DNS syntax:
7794b22b933Srs200217 // Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots.
7804b22b933Srs200217 // If successful, MakeDomainNameFromDNSNameString returns a pointer to the next unused byte
7814b22b933Srs200217 // in the domainname bufer (i.e., the next byte after the terminating zero).
7824b22b933Srs200217 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
7834b22b933Srs200217 // MakeDomainNameFromDNSNameString returns mDNSNULL.
MakeDomainNameFromDNSNameString(domainname * const name,const char * cstr)7844b22b933Srs200217 mDNSexport mDNSu8 *MakeDomainNameFromDNSNameString(domainname *const name, const char *cstr)
7854b22b933Srs200217 {
7864b22b933Srs200217 name->c[0] = 0; // Make an empty domain name
7874b22b933Srs200217 return(AppendDNSNameString(name, cstr)); // And then add this string to it
7884b22b933Srs200217 }
7894b22b933Srs200217
ConvertDomainLabelToCString_withescape(const domainlabel * const label,char * ptr,char esc)7904b22b933Srs200217 mDNSexport char *ConvertDomainLabelToCString_withescape(const domainlabel *const label, char *ptr, char esc)
7914b22b933Srs200217 {
7924b22b933Srs200217 const mDNSu8 * src = label->c; // Domain label we're reading
7934b22b933Srs200217 const mDNSu8 len = *src++; // Read length of this (non-null) label
7944b22b933Srs200217 const mDNSu8 *const end = src + len; // Work out where the label ends
7954b22b933Srs200217 if (len > MAX_DOMAIN_LABEL) return(mDNSNULL); // If illegal label, abort
7964b22b933Srs200217 while (src < end) // While we have characters in the label
7974b22b933Srs200217 {
7984b22b933Srs200217 mDNSu8 c = *src++;
7994b22b933Srs200217 if (esc)
8004b22b933Srs200217 {
8014b22b933Srs200217 if (c == '.' || c == esc) // If character is a dot or the escape character
8024b22b933Srs200217 *ptr++ = esc; // Output escape character
8034b22b933Srs200217 else if (c <= ' ') // If non-printing ascii,
8044b22b933Srs200217 { // Output decimal escape sequence
8054b22b933Srs200217 *ptr++ = esc;
8064b22b933Srs200217 *ptr++ = (char) ('0' + (c / 100) );
8074b22b933Srs200217 *ptr++ = (char) ('0' + (c / 10) % 10);
8084b22b933Srs200217 c = (mDNSu8)('0' + (c ) % 10);
8094b22b933Srs200217 }
8104b22b933Srs200217 }
8114b22b933Srs200217 *ptr++ = (char)c; // Copy the character
8124b22b933Srs200217 }
8134b22b933Srs200217 *ptr = 0; // Null-terminate the string
8144b22b933Srs200217 return(ptr); // and return
8154b22b933Srs200217 }
8164b22b933Srs200217
8174b22b933Srs200217 // Note: To guarantee that there will be no possible overrun, cstr must be at least MAX_ESCAPED_DOMAIN_NAME (1005 bytes)
ConvertDomainNameToCString_withescape(const domainname * const name,char * ptr,char esc)8184b22b933Srs200217 mDNSexport char *ConvertDomainNameToCString_withescape(const domainname *const name, char *ptr, char esc)
8194b22b933Srs200217 {
8204b22b933Srs200217 const mDNSu8 *src = name->c; // Domain name we're reading
8214b22b933Srs200217 const mDNSu8 *const max = name->c + MAX_DOMAIN_NAME; // Maximum that's valid
8224b22b933Srs200217
8234b22b933Srs200217 if (*src == 0) *ptr++ = '.'; // Special case: For root, just write a dot
8244b22b933Srs200217
8254b22b933Srs200217 while (*src) // While more characters in the domain name
8264b22b933Srs200217 {
8274b22b933Srs200217 if (src + 1 + *src >= max) return(mDNSNULL);
8284b22b933Srs200217 ptr = ConvertDomainLabelToCString_withescape((const domainlabel *)src, ptr, esc);
8294b22b933Srs200217 if (!ptr) return(mDNSNULL);
8304b22b933Srs200217 src += 1 + *src;
8314b22b933Srs200217 *ptr++ = '.'; // Write the dot after the label
8324b22b933Srs200217 }
8334b22b933Srs200217
8344b22b933Srs200217 *ptr++ = 0; // Null-terminate the string
8354b22b933Srs200217 return(ptr); // and return
8364b22b933Srs200217 }
8374b22b933Srs200217
8384b22b933Srs200217 // RFC 1034 rules:
8394b22b933Srs200217 // Host names must start with a letter, end with a letter or digit,
8404b22b933Srs200217 // and have as interior characters only letters, digits, and hyphen.
8414b22b933Srs200217 // This was subsequently modified in RFC 1123 to allow the first character to be either a letter or a digit
8424b22b933Srs200217
ConvertUTF8PstringToRFC1034HostLabel(const mDNSu8 UTF8Name[],domainlabel * const hostlabel)8434b22b933Srs200217 mDNSexport void ConvertUTF8PstringToRFC1034HostLabel(const mDNSu8 UTF8Name[], domainlabel *const hostlabel)
8444b22b933Srs200217 {
8454b22b933Srs200217 const mDNSu8 * src = &UTF8Name[1];
8464b22b933Srs200217 const mDNSu8 *const end = &UTF8Name[1] + UTF8Name[0];
8474b22b933Srs200217 mDNSu8 * ptr = &hostlabel->c[1];
8484b22b933Srs200217 const mDNSu8 *const lim = &hostlabel->c[1] + MAX_DOMAIN_LABEL;
8494b22b933Srs200217 while (src < end)
8504b22b933Srs200217 {
8514b22b933Srs200217 // Delete apostrophes from source name
8524b22b933Srs200217 if (src[0] == '\'') { src++; continue; } // Standard straight single quote
8534b22b933Srs200217 if (src + 2 < end && src[0] == 0xE2 && src[1] == 0x80 && src[2] == 0x99)
8544b22b933Srs200217 { src += 3; continue; } // Unicode curly apostrophe
8554b22b933Srs200217 if (ptr < lim)
8564b22b933Srs200217 {
8574b22b933Srs200217 if (mdnsValidHostChar(*src, (ptr > &hostlabel->c[1]), (src < end-1))) *ptr++ = *src;
8584b22b933Srs200217 else if (ptr > &hostlabel->c[1] && ptr[-1] != '-') *ptr++ = '-';
8594b22b933Srs200217 }
8604b22b933Srs200217 src++;
8614b22b933Srs200217 }
8624b22b933Srs200217 while (ptr > &hostlabel->c[1] && ptr[-1] == '-') ptr--; // Truncate trailing '-' marks
8634b22b933Srs200217 hostlabel->c[0] = (mDNSu8)(ptr - &hostlabel->c[1]);
8644b22b933Srs200217 }
8654b22b933Srs200217
ConstructServiceName(domainname * const fqdn,const domainlabel * name,const domainname * type,const domainname * const domain)8664b22b933Srs200217 mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn,
8674b22b933Srs200217 const domainlabel *name, const domainname *type, const domainname *const domain)
8684b22b933Srs200217 {
8694b22b933Srs200217 int i, len;
8704b22b933Srs200217 mDNSu8 *dst = fqdn->c;
8714b22b933Srs200217 const mDNSu8 *src;
8724b22b933Srs200217 const char *errormsg;
8734b22b933Srs200217
8744b22b933Srs200217 // In the case where there is no name (and ONLY in that case),
8754b22b933Srs200217 // a single-label subtype is allowed as the first label of a three-part "type"
8764b22b933Srs200217 if (!name && type)
8774b22b933Srs200217 {
8784b22b933Srs200217 const mDNSu8 *s0 = type->c;
8794b22b933Srs200217 if (s0[0] && s0[0] < 0x40) // If legal first label (at least one character, and no more than 63)
8804b22b933Srs200217 {
8814b22b933Srs200217 const mDNSu8 * s1 = s0 + 1 + s0[0];
8824b22b933Srs200217 if (s1[0] && s1[0] < 0x40) // and legal second label (at least one character, and no more than 63)
8834b22b933Srs200217 {
8844b22b933Srs200217 const mDNSu8 *s2 = s1 + 1 + s1[0];
8854b22b933Srs200217 if (s2[0] && s2[0] < 0x40 && s2[1+s2[0]] == 0) // and we have three and only three labels
8864b22b933Srs200217 {
8874b22b933Srs200217 static const mDNSu8 SubTypeLabel[5] = "\x04_sub";
8884b22b933Srs200217 src = s0; // Copy the first label
8894b22b933Srs200217 len = *src;
8904b22b933Srs200217 for (i=0; i <= len; i++) *dst++ = *src++;
8914b22b933Srs200217 for (i=0; i < (int)sizeof(SubTypeLabel); i++) *dst++ = SubTypeLabel[i];
8924b22b933Srs200217 type = (domainname *)s1;
8934b22b933Srs200217
8944b22b933Srs200217 // Special support for queries done by some third-party network monitoring software
8954b22b933Srs200217 // For these queries, we retract the "._sub" we just added between the subtype and the main type
8964b22b933Srs200217 if (SameDomainName((domainname*)s0, (domainname*)"\x09_services\x07_dns-sd\x04_udp") ||
8974b22b933Srs200217 SameDomainName((domainname*)s0, (domainname*)"\x09_services\x05_mdns\x04_udp"))
8984b22b933Srs200217 dst -= sizeof(SubTypeLabel);
8994b22b933Srs200217 }
9004b22b933Srs200217 }
9014b22b933Srs200217 }
9024b22b933Srs200217 }
9034b22b933Srs200217
9044b22b933Srs200217 if (name && name->c[0])
9054b22b933Srs200217 {
9064b22b933Srs200217 src = name->c; // Put the service name into the domain name
9074b22b933Srs200217 len = *src;
9084b22b933Srs200217 if (len >= 0x40) { errormsg="Service instance name too long"; goto fail; }
9094b22b933Srs200217 for (i=0; i<=len; i++) *dst++ = *src++;
9104b22b933Srs200217 }
9114b22b933Srs200217 else
9124b22b933Srs200217 name = (domainlabel*)""; // Set this up to be non-null, to avoid errors if we have to call LogMsg() below
9134b22b933Srs200217
9144b22b933Srs200217 src = type->c; // Put the service type into the domain name
9154b22b933Srs200217 len = *src;
9164b22b933Srs200217 if (len < 2 || len >= 0x40 || (len > 15 && !SameDomainName(domain, &localdomain)))
9174b22b933Srs200217 {
9184b22b933Srs200217 errormsg="Application protocol name must be underscore plus 1-14 characters. See <http://www.dns-sd.org/ServiceTypes.html>";
9194b22b933Srs200217 goto fail;
9204b22b933Srs200217 }
9214b22b933Srs200217 if (src[1] != '_') { errormsg="Application protocol name must begin with underscore"; goto fail; }
9224b22b933Srs200217 for (i=2; i<=len; i++)
9234b22b933Srs200217 if (!mdnsIsLetter(src[i]) && !mdnsIsDigit(src[i]) && src[i] != '-' && src[i] != '_')
9244b22b933Srs200217 { errormsg="Application protocol name must contain only letters, digits, and hyphens"; goto fail; }
9254b22b933Srs200217 for (i=0; i<=len; i++) *dst++ = *src++;
9264b22b933Srs200217
9274b22b933Srs200217 len = *src;
9284b22b933Srs200217 if (!(len == 4 && src[1] == '_' &&
9294b22b933Srs200217 (((src[2] | 0x20) == 'u' && (src[3] | 0x20) == 'd') || ((src[2] | 0x20) == 't' && (src[3] | 0x20) == 'c')) &&
9304b22b933Srs200217 (src[4] | 0x20) == 'p'))
9314b22b933Srs200217 { errormsg="Transport protocol name must be _udp or _tcp"; goto fail; }
9324b22b933Srs200217 for (i=0; i<=len; i++) *dst++ = *src++;
9334b22b933Srs200217
9344b22b933Srs200217 if (*src) { errormsg="Service type must have only two labels"; goto fail; }
9354b22b933Srs200217
9364b22b933Srs200217 *dst = 0;
9374b22b933Srs200217 if (!domain->c[0]) { errormsg="Service domain must be non-empty"; goto fail; }
9384b22b933Srs200217 if (SameDomainName(domain, (domainname*)"\x05" "local" "\x04" "arpa"))
9394b22b933Srs200217 { errormsg="Illegal domain \"local.arpa.\" Use \"local.\" (or empty string)"; goto fail; }
9404b22b933Srs200217 dst = AppendDomainName(fqdn, domain);
9414b22b933Srs200217 if (!dst) { errormsg="Service domain too long"; goto fail; }
9424b22b933Srs200217 return(dst);
9434b22b933Srs200217
9444b22b933Srs200217 fail:
9454b22b933Srs200217 LogMsg("ConstructServiceName: %s: %#s.%##s%##s", errormsg, name->c, type->c, domain->c);
9464b22b933Srs200217 return(mDNSNULL);
9474b22b933Srs200217 }
9484b22b933Srs200217
9494b22b933Srs200217 // A service name has the form: instance.application-protocol.transport-protocol.domain
9504b22b933Srs200217 // DeconstructServiceName is currently fairly forgiving: It doesn't try to enforce character
9514b22b933Srs200217 // set or length limits for the protocol names, and the final domain is allowed to be empty.
9524b22b933Srs200217 // However, if the given FQDN doesn't contain at least three labels,
9534b22b933Srs200217 // DeconstructServiceName will reject it and return mDNSfalse.
DeconstructServiceName(const domainname * const fqdn,domainlabel * const name,domainname * const type,domainname * const domain)9544b22b933Srs200217 mDNSexport mDNSBool DeconstructServiceName(const domainname *const fqdn,
9554b22b933Srs200217 domainlabel *const name, domainname *const type, domainname *const domain)
9564b22b933Srs200217 {
9574b22b933Srs200217 int i, len;
9584b22b933Srs200217 const mDNSu8 *src = fqdn->c;
9594b22b933Srs200217 const mDNSu8 *max = fqdn->c + MAX_DOMAIN_NAME;
9604b22b933Srs200217 mDNSu8 *dst;
9614b22b933Srs200217
9624b22b933Srs200217 dst = name->c; // Extract the service name
9634b22b933Srs200217 len = *src;
9644b22b933Srs200217 if (!len) { debugf("DeconstructServiceName: FQDN empty!"); return(mDNSfalse); }
9654b22b933Srs200217 if (len >= 0x40) { debugf("DeconstructServiceName: Instance name too long"); return(mDNSfalse); }
9664b22b933Srs200217 for (i=0; i<=len; i++) *dst++ = *src++;
9674b22b933Srs200217
9684b22b933Srs200217 dst = type->c; // Extract the service type
9694b22b933Srs200217 len = *src;
9704b22b933Srs200217 if (!len) { debugf("DeconstructServiceName: FQDN contains only one label!"); return(mDNSfalse); }
9714b22b933Srs200217 if (len >= 0x40) { debugf("DeconstructServiceName: Application protocol name too long"); return(mDNSfalse); }
9724b22b933Srs200217 for (i=0; i<=len; i++) *dst++ = *src++;
9734b22b933Srs200217
9744b22b933Srs200217 len = *src;
9754b22b933Srs200217 if (!len) { debugf("DeconstructServiceName: FQDN contains only two labels!"); return(mDNSfalse); }
9764b22b933Srs200217 if (len >= 0x40) { debugf("DeconstructServiceName: Transport protocol name too long"); return(mDNSfalse); }
9774b22b933Srs200217 for (i=0; i<=len; i++) *dst++ = *src++;
9784b22b933Srs200217 *dst++ = 0; // Put terminator on the end of service type
9794b22b933Srs200217
9804b22b933Srs200217 dst = domain->c; // Extract the service domain
9814b22b933Srs200217 while (*src)
9824b22b933Srs200217 {
9834b22b933Srs200217 len = *src;
9844b22b933Srs200217 if (len >= 0x40)
9854b22b933Srs200217 { debugf("DeconstructServiceName: Label in service domain too long"); return(mDNSfalse); }
9864b22b933Srs200217 if (src + 1 + len + 1 >= max)
9874b22b933Srs200217 { debugf("DeconstructServiceName: Total service domain too long"); return(mDNSfalse); }
9884b22b933Srs200217 for (i=0; i<=len; i++) *dst++ = *src++;
9894b22b933Srs200217 }
9904b22b933Srs200217 *dst++ = 0; // Put the null root label on the end
9914b22b933Srs200217
9924b22b933Srs200217 return(mDNStrue);
9934b22b933Srs200217 }
9944b22b933Srs200217
9954b22b933Srs200217 // Notes on UTF-8:
9964b22b933Srs200217 // 0xxxxxxx represents a 7-bit ASCII value from 0x00 to 0x7F
9974b22b933Srs200217 // 10xxxxxx is a continuation byte of a multi-byte character
9984b22b933Srs200217 // 110xxxxx is the first byte of a 2-byte character (11 effective bits; values 0x 80 - 0x 800-1)
9994b22b933Srs200217 // 1110xxxx is the first byte of a 3-byte character (16 effective bits; values 0x 800 - 0x 10000-1)
10004b22b933Srs200217 // 11110xxx is the first byte of a 4-byte character (21 effective bits; values 0x 10000 - 0x 200000-1)
10014b22b933Srs200217 // 111110xx is the first byte of a 5-byte character (26 effective bits; values 0x 200000 - 0x 4000000-1)
10024b22b933Srs200217 // 1111110x is the first byte of a 6-byte character (31 effective bits; values 0x4000000 - 0x80000000-1)
10034b22b933Srs200217 //
10044b22b933Srs200217 // UTF-16 surrogate pairs are used in UTF-16 to encode values larger than 0xFFFF.
10054b22b933Srs200217 // Although UTF-16 surrogate pairs are not supposed to appear in legal UTF-8, we want to be defensive
10064b22b933Srs200217 // about that too. (See <http://www.unicode.org/faq/utf_bom.html#34>, "What are surrogates?")
10074b22b933Srs200217 // The first of pair is a UTF-16 value in the range 0xD800-0xDBFF (11101101 1010xxxx 10xxxxxx in UTF-8),
10084b22b933Srs200217 // and the second is a UTF-16 value in the range 0xDC00-0xDFFF (11101101 1011xxxx 10xxxxxx in UTF-8).
10094b22b933Srs200217
TruncateUTF8ToLength(mDNSu8 * string,mDNSu32 length,mDNSu32 max)10104b22b933Srs200217 mDNSexport mDNSu32 TruncateUTF8ToLength(mDNSu8 *string, mDNSu32 length, mDNSu32 max)
10114b22b933Srs200217 {
10124b22b933Srs200217 if (length > max)
10134b22b933Srs200217 {
10144b22b933Srs200217 mDNSu8 c1 = string[max]; // First byte after cut point
10154b22b933Srs200217 mDNSu8 c2 = (max+1 < length) ? string[max+1] : 0xB0; // Second byte after cut point
10164b22b933Srs200217 length = max; // Trim length down
10174b22b933Srs200217 while (length > 0)
10184b22b933Srs200217 {
10194b22b933Srs200217 // Check if the byte right after the chop point is a UTF-8 continuation byte,
10204b22b933Srs200217 // or if the character right after the chop point is the second of a UTF-16 surrogate pair.
10214b22b933Srs200217 // If so, then we continue to chop more bytes until we get to a legal chop point.
10224b22b933Srs200217 mDNSBool continuation = ((c1 & 0xC0) == 0x80);
10234b22b933Srs200217 mDNSBool secondsurrogate = (c1 == 0xED && (c2 & 0xF0) == 0xB0);
10244b22b933Srs200217 if (!continuation && !secondsurrogate) break;
10254b22b933Srs200217 c2 = c1;
10264b22b933Srs200217 c1 = string[--length];
10274b22b933Srs200217 }
10284b22b933Srs200217 // Having truncated characters off the end of our string, also cut off any residual white space
10294b22b933Srs200217 while (length > 0 && string[length-1] <= ' ') length--;
10304b22b933Srs200217 }
10314b22b933Srs200217 return(length);
10324b22b933Srs200217 }
10334b22b933Srs200217
10344b22b933Srs200217 // Returns true if a rich text label ends in " (nnn)", or if an RFC 1034
10354b22b933Srs200217 // name ends in "-nnn", where n is some decimal number.
LabelContainsSuffix(const domainlabel * const name,const mDNSBool RichText)10364b22b933Srs200217 mDNSexport mDNSBool LabelContainsSuffix(const domainlabel *const name, const mDNSBool RichText)
10374b22b933Srs200217 {
10384b22b933Srs200217 mDNSu16 l = name->c[0];
10394b22b933Srs200217
10404b22b933Srs200217 if (RichText)
10414b22b933Srs200217 {
10424b22b933Srs200217 if (l < 4) return mDNSfalse; // Need at least " (2)"
10434b22b933Srs200217 if (name->c[l--] != ')') return mDNSfalse; // Last char must be ')'
10444b22b933Srs200217 if (!mdnsIsDigit(name->c[l])) return mDNSfalse; // Preceeded by a digit
10454b22b933Srs200217 l--;
10464b22b933Srs200217 while (l > 2 && mdnsIsDigit(name->c[l])) l--; // Strip off digits
10474b22b933Srs200217 return (name->c[l] == '(' && name->c[l - 1] == ' ');
10484b22b933Srs200217 }
10494b22b933Srs200217 else
10504b22b933Srs200217 {
10514b22b933Srs200217 if (l < 2) return mDNSfalse; // Need at least "-2"
10524b22b933Srs200217 if (!mdnsIsDigit(name->c[l])) return mDNSfalse; // Last char must be a digit
10534b22b933Srs200217 l--;
10544b22b933Srs200217 while (l > 2 && mdnsIsDigit(name->c[l])) l--; // Strip off digits
10554b22b933Srs200217 return (name->c[l] == '-');
10564b22b933Srs200217 }
10574b22b933Srs200217 }
10584b22b933Srs200217
10594b22b933Srs200217 // removes an auto-generated suffix (appended on a name collision) from a label. caller is
10604b22b933Srs200217 // responsible for ensuring that the label does indeed contain a suffix. returns the number
10614b22b933Srs200217 // from the suffix that was removed.
RemoveLabelSuffix(domainlabel * name,mDNSBool RichText)10624b22b933Srs200217 mDNSexport mDNSu32 RemoveLabelSuffix(domainlabel *name, mDNSBool RichText)
10634b22b933Srs200217 {
10644b22b933Srs200217 mDNSu32 val = 0, multiplier = 1;
10654b22b933Srs200217
10664b22b933Srs200217 // Chop closing parentheses from RichText suffix
10674b22b933Srs200217 if (RichText && name->c[0] >= 1 && name->c[name->c[0]] == ')') name->c[0]--;
10684b22b933Srs200217
10694b22b933Srs200217 // Get any existing numerical suffix off the name
10704b22b933Srs200217 while (mdnsIsDigit(name->c[name->c[0]]))
10714b22b933Srs200217 { val += (name->c[name->c[0]] - '0') * multiplier; multiplier *= 10; name->c[0]--; }
10724b22b933Srs200217
10734b22b933Srs200217 // Chop opening parentheses or dash from suffix
10744b22b933Srs200217 if (RichText)
10754b22b933Srs200217 {
10764b22b933Srs200217 if (name->c[0] >= 2 && name->c[name->c[0]] == '(' && name->c[name->c[0]-1] == ' ') name->c[0] -= 2;
10774b22b933Srs200217 }
10784b22b933Srs200217 else
10794b22b933Srs200217 {
10804b22b933Srs200217 if (name->c[0] >= 1 && name->c[name->c[0]] == '-') name->c[0] -= 1;
10814b22b933Srs200217 }
10824b22b933Srs200217
10834b22b933Srs200217 return(val);
10844b22b933Srs200217 }
10854b22b933Srs200217
10864b22b933Srs200217 // appends a numerical suffix to a label, with the number following a whitespace and enclosed
10874b22b933Srs200217 // in parentheses (rich text) or following two consecutive hyphens (RFC 1034 domain label).
AppendLabelSuffix(domainlabel * name,mDNSu32 val,mDNSBool RichText)10884b22b933Srs200217 mDNSexport void AppendLabelSuffix(domainlabel *name, mDNSu32 val, mDNSBool RichText)
10894b22b933Srs200217 {
10904b22b933Srs200217 mDNSu32 divisor = 1, chars = 2; // Shortest possible RFC1034 name suffix is 2 characters ("-2")
10914b22b933Srs200217 if (RichText) chars = 4; // Shortest possible RichText suffix is 4 characters (" (2)")
10924b22b933Srs200217
10934b22b933Srs200217 // Truncate trailing spaces from RichText names
10944b22b933Srs200217 if (RichText) while (name->c[name->c[0]] == ' ') name->c[0]--;
10954b22b933Srs200217
10964b22b933Srs200217 while (val >= divisor * 10) { divisor *= 10; chars++; }
10974b22b933Srs200217
10984b22b933Srs200217 name->c[0] = (mDNSu8) TruncateUTF8ToLength(name->c+1, name->c[0], MAX_DOMAIN_LABEL - chars);
10994b22b933Srs200217
11004b22b933Srs200217 if (RichText) { name->c[++name->c[0]] = ' '; name->c[++name->c[0]] = '('; }
11014b22b933Srs200217 else { name->c[++name->c[0]] = '-'; }
11024b22b933Srs200217
11034b22b933Srs200217 while (divisor)
11044b22b933Srs200217 {
11054b22b933Srs200217 name->c[++name->c[0]] = (mDNSu8)('0' + val / divisor);
11064b22b933Srs200217 val %= divisor;
11074b22b933Srs200217 divisor /= 10;
11084b22b933Srs200217 }
11094b22b933Srs200217
11104b22b933Srs200217 if (RichText) name->c[++name->c[0]] = ')';
11114b22b933Srs200217 }
11124b22b933Srs200217
IncrementLabelSuffix(domainlabel * name,mDNSBool RichText)11134b22b933Srs200217 mDNSexport void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText)
11144b22b933Srs200217 {
11154b22b933Srs200217 mDNSu32 val = 0;
11164b22b933Srs200217
11174b22b933Srs200217 if (LabelContainsSuffix(name, RichText))
11184b22b933Srs200217 val = RemoveLabelSuffix(name, RichText);
11194b22b933Srs200217
11204b22b933Srs200217 // If no existing suffix, start by renaming "Foo" as "Foo (2)" or "Foo-2" as appropriate.
11214b22b933Srs200217 // If existing suffix in the range 2-9, increment it.
11224b22b933Srs200217 // If we've had ten conflicts already, there are probably too many hosts trying to use the same name,
11234b22b933Srs200217 // so add a random increment to improve the chances of finding an available name next time.
11244b22b933Srs200217 if (val == 0) val = 2;
11254b22b933Srs200217 else if (val < 10) val++;
11264b22b933Srs200217 else val += 1 + mDNSRandom(99);
11274b22b933Srs200217
11284b22b933Srs200217 AppendLabelSuffix(name, val, RichText);
11294b22b933Srs200217 }
11304b22b933Srs200217
11314b22b933Srs200217 // ***************************************************************************
11324b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
11334b22b933Srs200217 #pragma mark -
11344b22b933Srs200217 #pragma mark - Resource Record Utility Functions
11354b22b933Srs200217 #endif
11364b22b933Srs200217
RDataHashValue(mDNSu16 const rdlength,const RDataBody * const rdb)11374b22b933Srs200217 mDNSexport mDNSu32 RDataHashValue(mDNSu16 const rdlength, const RDataBody *const rdb)
11384b22b933Srs200217 {
11394b22b933Srs200217 mDNSu32 sum = 0;
11404b22b933Srs200217 int i;
11414b22b933Srs200217 for (i=0; i+1 < rdlength; i+=2)
11424b22b933Srs200217 {
11434b22b933Srs200217 sum += (((mDNSu32)(rdb->data[i])) << 8) | rdb->data[i+1];
11444b22b933Srs200217 sum = (sum<<3) | (sum>>29);
11454b22b933Srs200217 }
11464b22b933Srs200217 if (i < rdlength)
11474b22b933Srs200217 {
11484b22b933Srs200217 sum += ((mDNSu32)(rdb->data[i])) << 8;
11494b22b933Srs200217 }
11504b22b933Srs200217 return(sum);
11514b22b933Srs200217 }
11524b22b933Srs200217
11534b22b933Srs200217 // r1 has to be a full ResourceRecord including rrtype and rdlength
11544b22b933Srs200217 // r2 is just a bare RDataBody, which MUST be the same rrtype and rdlength as r1
SameRDataBody(const ResourceRecord * const r1,const RDataBody * const r2)11554b22b933Srs200217 mDNSexport mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2)
11564b22b933Srs200217 {
11574b22b933Srs200217 switch(r1->rrtype)
11584b22b933Srs200217 {
11594b22b933Srs200217 case kDNSType_CNAME:// Same as PTR
11604b22b933Srs200217 case kDNSType_PTR: return(SameDomainName(&r1->rdata->u.name, &r2->name));
11614b22b933Srs200217
11624b22b933Srs200217 case kDNSType_SRV: return(mDNSBool)( r1->rdata->u.srv.priority == r2->srv.priority &&
11634b22b933Srs200217 r1->rdata->u.srv.weight == r2->srv.weight &&
11644b22b933Srs200217 r1->rdata->u.srv.port.NotAnInteger == r2->srv.port.NotAnInteger &&
11654b22b933Srs200217 SameDomainName(&r1->rdata->u.srv.target, &r2->srv.target) );
11664b22b933Srs200217
11674b22b933Srs200217 default: return(mDNSPlatformMemSame(r1->rdata->u.data, r2->data, r1->rdlength));
11684b22b933Srs200217 }
11694b22b933Srs200217 }
11704b22b933Srs200217
SameRData(const ResourceRecord * const r1,const ResourceRecord * const r2)11714b22b933Srs200217 mDNSexport mDNSBool SameRData(const ResourceRecord *const r1, const ResourceRecord *const r2)
11724b22b933Srs200217 {
11734b22b933Srs200217 if (r1->rrtype != r2->rrtype) return(mDNSfalse);
11744b22b933Srs200217 if (r1->rdlength != r2->rdlength) return(mDNSfalse);
11754b22b933Srs200217 if (r1->rdatahash != r2->rdatahash) return(mDNSfalse);
11764b22b933Srs200217 return(SameRDataBody(r1, &r2->rdata->u));
11774b22b933Srs200217 }
11784b22b933Srs200217
SameResourceRecord(ResourceRecord * r1,ResourceRecord * r2)11794b22b933Srs200217 mDNSexport mDNSBool SameResourceRecord(ResourceRecord *r1, ResourceRecord *r2)
11804b22b933Srs200217 {
11814b22b933Srs200217 return (r1->namehash == r2->namehash &&
11824b22b933Srs200217 r1->rrtype == r2->rrtype &&
11834b22b933Srs200217 SameDomainName(r1->name, r2->name) &&
11844b22b933Srs200217 SameRData(r1, r2));
11854b22b933Srs200217 }
11864b22b933Srs200217
ResourceRecordAnswersQuestion(const ResourceRecord * const rr,const DNSQuestion * const q)11874b22b933Srs200217 mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
11884b22b933Srs200217 {
11894b22b933Srs200217 if (rr->InterfaceID &&
11904b22b933Srs200217 q ->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly &&
11914b22b933Srs200217 rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
11924b22b933Srs200217
11934b22b933Srs200217 // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
11944b22b933Srs200217 if (rr->rrtype != kDNSType_CNAME && rr->rrtype != q->qtype && q->qtype != kDNSQType_ANY ) return(mDNSfalse);
11954b22b933Srs200217 if ( rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
11964b22b933Srs200217 return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
11974b22b933Srs200217 }
11984b22b933Srs200217
GetRDLength(const ResourceRecord * const rr,mDNSBool estimate)11994b22b933Srs200217 mDNSexport mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate)
12004b22b933Srs200217 {
12014b22b933Srs200217 const RDataBody *rd = &rr->rdata->u;
12024b22b933Srs200217 const domainname *const name = estimate ? rr->name : mDNSNULL;
12034b22b933Srs200217 switch (rr->rrtype)
12044b22b933Srs200217 {
12054b22b933Srs200217 case kDNSType_A: return(sizeof(rd->ipv4));
12064b22b933Srs200217 case kDNSType_CNAME:// Same as PTR
12074b22b933Srs200217 case kDNSType_NS: // Same as PTR
12084b22b933Srs200217 case kDNSType_PTR: return(CompressedDomainNameLength(&rd->name, name));
12094b22b933Srs200217 case kDNSType_HINFO:return(mDNSu16)(2 + (int)rd->data[0] + (int)rd->data[1 + (int)rd->data[0]]);
12104b22b933Srs200217 case kDNSType_NULL: // Same as TXT -- not self-describing, so have to just trust rdlength
12114b22b933Srs200217 case kDNSType_TXT: return(rr->rdlength); // TXT is not self-describing, so have to just trust rdlength
12124b22b933Srs200217 case kDNSType_AAAA: return(sizeof(rd->ipv6));
12134b22b933Srs200217 case kDNSType_SRV: return(mDNSu16)(6 + CompressedDomainNameLength(&rd->srv.target, name));
12144b22b933Srs200217 case kDNSType_SOA: return (mDNSu16)(CompressedDomainNameLength(&rd->soa.mname, name) +
12154b22b933Srs200217 CompressedDomainNameLength(&rd->soa.rname, name) +
12164b22b933Srs200217 5 * sizeof(mDNSOpaque32));
12174b22b933Srs200217 case kDNSType_OPT: return(rr->rdlength);
12184b22b933Srs200217 default: debugf("Warning! Don't know how to get length of resource type %d", rr->rrtype);
12194b22b933Srs200217 return(rr->rdlength);
12204b22b933Srs200217 }
12214b22b933Srs200217 }
12224b22b933Srs200217
ValidateRData(const mDNSu16 rrtype,const mDNSu16 rdlength,const RData * const rd)12234b22b933Srs200217 mDNSexport mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd)
12244b22b933Srs200217 {
12254b22b933Srs200217 mDNSu16 len;
12264b22b933Srs200217
12274b22b933Srs200217 switch(rrtype)
12284b22b933Srs200217 {
12294b22b933Srs200217 case kDNSType_A: return(rdlength == sizeof(mDNSv4Addr));
12304b22b933Srs200217
12314b22b933Srs200217 case kDNSType_NS: // Same as PTR
12324b22b933Srs200217 case kDNSType_MD: // Same as PTR
12334b22b933Srs200217 case kDNSType_MF: // Same as PTR
12344b22b933Srs200217 case kDNSType_CNAME:// Same as PTR
12354b22b933Srs200217 //case kDNSType_SOA not checked
12364b22b933Srs200217 case kDNSType_MB: // Same as PTR
12374b22b933Srs200217 case kDNSType_MG: // Same as PTR
12384b22b933Srs200217 case kDNSType_MR: // Same as PTR
12394b22b933Srs200217 //case kDNSType_NULL not checked (no specified format, so always valid)
12404b22b933Srs200217 //case kDNSType_WKS not checked
12414b22b933Srs200217 case kDNSType_PTR: if (!rdlength) return(mDNSfalse);
12424b22b933Srs200217 len = DomainNameLength(&rd->u.name);
12434b22b933Srs200217 return(len <= MAX_DOMAIN_NAME && rdlength == len);
12444b22b933Srs200217
12454b22b933Srs200217 case kDNSType_HINFO:// Same as TXT (roughly)
12464b22b933Srs200217 case kDNSType_MINFO:// Same as TXT (roughly)
12474b22b933Srs200217 case kDNSType_TXT: if (!rdlength) return(mDNSfalse); // TXT record has to be at least one byte (RFC 1035)
12484b22b933Srs200217 {
12494b22b933Srs200217 const mDNSu8 *ptr = rd->u.txt.c;
12504b22b933Srs200217 const mDNSu8 *end = rd->u.txt.c + rdlength;
12514b22b933Srs200217 while (ptr < end) ptr += 1 + ptr[0];
12524b22b933Srs200217 return (ptr == end);
12534b22b933Srs200217 }
12544b22b933Srs200217
12554b22b933Srs200217 case kDNSType_AAAA: return(rdlength == sizeof(mDNSv6Addr));
12564b22b933Srs200217
12574b22b933Srs200217 case kDNSType_MX: if (!rdlength) return(mDNSfalse);
12584b22b933Srs200217 len = DomainNameLength(&rd->u.mx.exchange);
12594b22b933Srs200217 return(len <= MAX_DOMAIN_NAME && rdlength == 2+len);
12604b22b933Srs200217
12614b22b933Srs200217 case kDNSType_SRV: if (!rdlength) return(mDNSfalse);
12624b22b933Srs200217 len = DomainNameLength(&rd->u.srv.target);
12634b22b933Srs200217 return(len <= MAX_DOMAIN_NAME && rdlength == 6+len);
12644b22b933Srs200217
12654b22b933Srs200217 default: return(mDNStrue); // Allow all other types without checking
12664b22b933Srs200217 }
12674b22b933Srs200217 }
12684b22b933Srs200217
12694b22b933Srs200217 // ***************************************************************************
12704b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
12714b22b933Srs200217 #pragma mark -
12724b22b933Srs200217 #pragma mark -
12734b22b933Srs200217 #pragma mark - DNS Message Creation Functions
12744b22b933Srs200217 #endif
12754b22b933Srs200217
InitializeDNSMessage(DNSMessageHeader * h,mDNSOpaque16 id,mDNSOpaque16 flags)12764b22b933Srs200217 mDNSexport void InitializeDNSMessage(DNSMessageHeader *h, mDNSOpaque16 id, mDNSOpaque16 flags)
12774b22b933Srs200217 {
12784b22b933Srs200217 h->id = id;
12794b22b933Srs200217 h->flags = flags;
12804b22b933Srs200217 h->numQuestions = 0;
12814b22b933Srs200217 h->numAnswers = 0;
12824b22b933Srs200217 h->numAuthorities = 0;
12834b22b933Srs200217 h->numAdditionals = 0;
12844b22b933Srs200217 }
12854b22b933Srs200217
FindCompressionPointer(const mDNSu8 * const base,const mDNSu8 * const end,const mDNSu8 * const domname)12864b22b933Srs200217 mDNSexport const mDNSu8 *FindCompressionPointer(const mDNSu8 *const base, const mDNSu8 *const end, const mDNSu8 *const domname)
12874b22b933Srs200217 {
12884b22b933Srs200217 const mDNSu8 *result = end - *domname - 1;
12894b22b933Srs200217
12904b22b933Srs200217 if (*domname == 0) return(mDNSNULL); // There's no point trying to match just the root label
12914b22b933Srs200217
12924b22b933Srs200217 // This loop examines each possible starting position in packet, starting end of the packet and working backwards
12934b22b933Srs200217 while (result >= base)
12944b22b933Srs200217 {
12954b22b933Srs200217 // If the length byte and first character of the label match, then check further to see
12964b22b933Srs200217 // if this location in the packet will yield a useful name compression pointer.
12974b22b933Srs200217 if (result[0] == domname[0] && result[1] == domname[1])
12984b22b933Srs200217 {
12994b22b933Srs200217 const mDNSu8 *name = domname;
13004b22b933Srs200217 const mDNSu8 *targ = result;
13014b22b933Srs200217 while (targ + *name < end)
13024b22b933Srs200217 {
13034b22b933Srs200217 // First see if this label matches
13044b22b933Srs200217 int i;
13054b22b933Srs200217 const mDNSu8 *pointertarget;
13064b22b933Srs200217 for (i=0; i <= *name; i++) if (targ[i] != name[i]) break;
13074b22b933Srs200217 if (i <= *name) break; // If label did not match, bail out
13084b22b933Srs200217 targ += 1 + *name; // Else, did match, so advance target pointer
13094b22b933Srs200217 name += 1 + *name; // and proceed to check next label
13104b22b933Srs200217 if (*name == 0 && *targ == 0) return(result); // If no more labels, we found a match!
13114b22b933Srs200217 if (*name == 0) break; // If no more labels to match, we failed, so bail out
13124b22b933Srs200217
13134b22b933Srs200217 // The label matched, so now follow the pointer (if appropriate) and then see if the next label matches
13144b22b933Srs200217 if (targ[0] < 0x40) continue; // If length value, continue to check next label
13154b22b933Srs200217 if (targ[0] < 0xC0) break; // If 40-BF, not valid
13164b22b933Srs200217 if (targ+1 >= end) break; // Second byte not present!
13174b22b933Srs200217 pointertarget = base + (((mDNSu16)(targ[0] & 0x3F)) << 8) + targ[1];
13184b22b933Srs200217 if (targ < pointertarget) break; // Pointertarget must point *backwards* in the packet
13194b22b933Srs200217 if (pointertarget[0] >= 0x40) break; // Pointertarget must point to a valid length byte
13204b22b933Srs200217 targ = pointertarget;
13214b22b933Srs200217 }
13224b22b933Srs200217 }
13234b22b933Srs200217 result--; // We failed to match at this search position, so back up the tentative result pointer and try again
13244b22b933Srs200217 }
13254b22b933Srs200217 return(mDNSNULL);
13264b22b933Srs200217 }
13274b22b933Srs200217
13284b22b933Srs200217 // Put a string of dot-separated labels as length-prefixed labels
13294b22b933Srs200217 // domainname is a fully-qualified name (i.e. assumed to be ending in a dot, even if it doesn't)
13304b22b933Srs200217 // msg points to the message we're building (pass mDNSNULL if we don't want to use compression pointers)
13314b22b933Srs200217 // end points to the end of the message so far
13324b22b933Srs200217 // ptr points to where we want to put the name
13334b22b933Srs200217 // limit points to one byte past the end of the buffer that we must not overrun
13344b22b933Srs200217 // domainname is the name to put
putDomainNameAsLabels(const DNSMessage * const msg,mDNSu8 * ptr,const mDNSu8 * const limit,const domainname * const name)13354b22b933Srs200217 mDNSexport mDNSu8 *putDomainNameAsLabels(const DNSMessage *const msg,
13364b22b933Srs200217 mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name)
13374b22b933Srs200217 {
13384b22b933Srs200217 const mDNSu8 *const base = (const mDNSu8 *)msg;
13394b22b933Srs200217 const mDNSu8 * np = name->c;
13404b22b933Srs200217 const mDNSu8 *const max = name->c + MAX_DOMAIN_NAME; // Maximum that's valid
13414b22b933Srs200217 const mDNSu8 * pointer = mDNSNULL;
13424b22b933Srs200217 const mDNSu8 *const searchlimit = ptr;
13434b22b933Srs200217
13444b22b933Srs200217 while (*np && ptr < limit-1) // While we've got characters in the name, and space to write them in the message...
13454b22b933Srs200217 {
13464b22b933Srs200217 if (*np > MAX_DOMAIN_LABEL)
13474b22b933Srs200217 { LogMsg("Malformed domain name %##s (label more than 63 bytes)", name->c); return(mDNSNULL); }
13484b22b933Srs200217
13494b22b933Srs200217 // This check correctly allows for the final trailing root label:
13504b22b933Srs200217 // e.g.
13514b22b933Srs200217 // Suppose our domain name is exactly 255 bytes long, including the final trailing root label.
13524b22b933Srs200217 // Suppose np is now at name->c[248], and we're about to write our last non-null label ("local").
13534b22b933Srs200217 // We know that max will be at name->c[255]
13544b22b933Srs200217 // That means that np + 1 + 5 == max - 1, so we (just) pass the "if" test below, write our
13554b22b933Srs200217 // six bytes, then exit the loop, write the final terminating root label, and the domain
13564b22b933Srs200217 // name we've written is exactly 255 bytes long, exactly at the correct legal limit.
13574b22b933Srs200217 // If the name is one byte longer, then we fail the "if" test below, and correctly bail out.
13584b22b933Srs200217 if (np + 1 + *np >= max)
13594b22b933Srs200217 { LogMsg("Malformed domain name %##s (more than 255 bytes)", name->c); return(mDNSNULL); }
13604b22b933Srs200217
13614b22b933Srs200217 if (base) pointer = FindCompressionPointer(base, searchlimit, np);
13624b22b933Srs200217 if (pointer) // Use a compression pointer if we can
13634b22b933Srs200217 {
13644b22b933Srs200217 mDNSu16 offset = (mDNSu16)(pointer - base);
13654b22b933Srs200217 *ptr++ = (mDNSu8)(0xC0 | (offset >> 8));
13664b22b933Srs200217 *ptr++ = (mDNSu8)( offset & 0xFF);
13674b22b933Srs200217 return(ptr);
13684b22b933Srs200217 }
13694b22b933Srs200217 else // Else copy one label and try again
13704b22b933Srs200217 {
13714b22b933Srs200217 int i;
13724b22b933Srs200217 mDNSu8 len = *np++;
13734b22b933Srs200217 if (ptr + 1 + len >= limit) return(mDNSNULL);
13744b22b933Srs200217 *ptr++ = len;
13754b22b933Srs200217 for (i=0; i<len; i++) *ptr++ = *np++;
13764b22b933Srs200217 }
13774b22b933Srs200217 }
13784b22b933Srs200217
13794b22b933Srs200217 if (ptr < limit) // If we didn't run out of space
13804b22b933Srs200217 {
13814b22b933Srs200217 *ptr++ = 0; // Put the final root label
13824b22b933Srs200217 return(ptr); // and return
13834b22b933Srs200217 }
13844b22b933Srs200217
13854b22b933Srs200217 return(mDNSNULL);
13864b22b933Srs200217 }
13874b22b933Srs200217
putVal16(mDNSu8 * ptr,mDNSu16 val)13884b22b933Srs200217 mDNSlocal mDNSu8 *putVal16(mDNSu8 *ptr, mDNSu16 val)
13894b22b933Srs200217 {
13904b22b933Srs200217 ptr[0] = (mDNSu8)((val >> 8 ) & 0xFF);
13914b22b933Srs200217 ptr[1] = (mDNSu8)((val ) & 0xFF);
13924b22b933Srs200217 return ptr + sizeof(mDNSOpaque16);
13934b22b933Srs200217 }
13944b22b933Srs200217
putVal32(mDNSu8 * ptr,mDNSu32 val)13954b22b933Srs200217 mDNSlocal mDNSu8 *putVal32(mDNSu8 *ptr, mDNSu32 val)
13964b22b933Srs200217 {
13974b22b933Srs200217 ptr[0] = (mDNSu8)((val >> 24) & 0xFF);
13984b22b933Srs200217 ptr[1] = (mDNSu8)((val >> 16) & 0xFF);
13994b22b933Srs200217 ptr[2] = (mDNSu8)((val >> 8) & 0xFF);
14004b22b933Srs200217 ptr[3] = (mDNSu8)((val ) & 0xFF);
14014b22b933Srs200217 return ptr + sizeof(mDNSu32);
14024b22b933Srs200217 }
14034b22b933Srs200217
putOptRData(mDNSu8 * ptr,const mDNSu8 * limit,ResourceRecord * rr)14044b22b933Srs200217 mDNSlocal mDNSu8 *putOptRData(mDNSu8 *ptr, const mDNSu8 *limit, ResourceRecord *rr)
14054b22b933Srs200217 {
14064b22b933Srs200217 int nput = 0;
14074b22b933Srs200217 rdataOpt *opt;
14084b22b933Srs200217
14094b22b933Srs200217 while (nput < rr->rdlength)
14104b22b933Srs200217 {
14114b22b933Srs200217 // check if space for opt/optlen
14124b22b933Srs200217 if (ptr + (2 * sizeof(mDNSu16)) > limit) goto space_err;
14134b22b933Srs200217 opt = (rdataOpt *)(rr->rdata->u.data + nput);
14144b22b933Srs200217 ptr = putVal16(ptr, opt->opt);
14154b22b933Srs200217 ptr = putVal16(ptr, opt->optlen);
14164b22b933Srs200217 nput += 2 * sizeof(mDNSu16);
14174b22b933Srs200217 if (opt->opt == kDNSOpt_LLQ)
14184b22b933Srs200217 {
14194b22b933Srs200217 if (ptr + LLQ_OPTLEN > limit) goto space_err;
14204b22b933Srs200217 ptr = putVal16(ptr, opt->OptData.llq.vers);
14214b22b933Srs200217 ptr = putVal16(ptr, opt->OptData.llq.llqOp);
14224b22b933Srs200217 ptr = putVal16(ptr, opt->OptData.llq.err);
14234b22b933Srs200217 mDNSPlatformMemCopy(opt->OptData.llq.id, ptr, 8); // 8-byte id
14244b22b933Srs200217 ptr += 8;
14254b22b933Srs200217 ptr = putVal32(ptr, opt->OptData.llq.lease);
14264b22b933Srs200217 nput += LLQ_OPTLEN;
14274b22b933Srs200217 }
14284b22b933Srs200217 else if (opt->opt == kDNSOpt_Lease)
14294b22b933Srs200217 {
14304b22b933Srs200217 if (ptr + sizeof(mDNSs32) > limit) goto space_err;
14314b22b933Srs200217 ptr = putVal32(ptr, opt->OptData.lease);
14324b22b933Srs200217 nput += sizeof(mDNSs32);
14334b22b933Srs200217 }
14344b22b933Srs200217 else { LogMsg("putOptRData - unknown option %d", opt->opt); return mDNSNULL; }
14354b22b933Srs200217 }
14364b22b933Srs200217
14374b22b933Srs200217 return ptr;
14384b22b933Srs200217
14394b22b933Srs200217 space_err:
14404b22b933Srs200217 LogMsg("ERROR: putOptRData - out of space");
14414b22b933Srs200217 return mDNSNULL;
14424b22b933Srs200217 }
14434b22b933Srs200217
getVal16(const mDNSu8 ** ptr)14444b22b933Srs200217 mDNSlocal mDNSu16 getVal16(const mDNSu8 **ptr)
14454b22b933Srs200217 {
14464b22b933Srs200217 mDNSu16 val = (mDNSu16)(((mDNSu16)(*ptr)[0]) << 8 | (*ptr)[1]);
14474b22b933Srs200217 *ptr += sizeof(mDNSOpaque16);
14484b22b933Srs200217 return val;
14494b22b933Srs200217 }
14504b22b933Srs200217
getOptRdata(const mDNSu8 * ptr,const mDNSu8 * const limit,LargeCacheRecord * const cr,mDNSu16 pktRDLen)14514b22b933Srs200217 mDNSlocal const mDNSu8 *getOptRdata(const mDNSu8 *ptr, const mDNSu8 *const limit, LargeCacheRecord *const cr, mDNSu16 pktRDLen)
14524b22b933Srs200217 {
14534b22b933Srs200217 int nread = 0;
14544b22b933Srs200217 ResourceRecord *const rr = &cr->r.resrec;
14554b22b933Srs200217 rdataOpt *opt = (rdataOpt *)rr->rdata->u.data;
14564b22b933Srs200217
14574b22b933Srs200217 while (nread < pktRDLen && (mDNSu8 *)opt < rr->rdata->u.data + MaximumRDSize - sizeof(rdataOpt))
14584b22b933Srs200217 {
14594b22b933Srs200217 // space for opt + optlen
14604b22b933Srs200217 if (nread + (2 * sizeof(mDNSu16)) > rr->rdata->MaxRDLength) goto space_err;
14614b22b933Srs200217 opt->opt = getVal16(&ptr);
14624b22b933Srs200217 opt->optlen = getVal16(&ptr);
14634b22b933Srs200217 nread += 2 * sizeof(mDNSu16);
14644b22b933Srs200217 if (opt->opt == kDNSOpt_LLQ)
14654b22b933Srs200217 {
14664b22b933Srs200217 if ((unsigned)(limit - ptr) < LLQ_OPTLEN) goto space_err;
14674b22b933Srs200217 opt->OptData.llq.vers = getVal16(&ptr);
14684b22b933Srs200217 opt->OptData.llq.llqOp = getVal16(&ptr);
14694b22b933Srs200217 opt->OptData.llq.err = getVal16(&ptr);
14704b22b933Srs200217 mDNSPlatformMemCopy(ptr, opt->OptData.llq.id, 8);
14714b22b933Srs200217 ptr += 8;
14724b22b933Srs200217 opt->OptData.llq.lease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
14734b22b933Srs200217 if (opt->OptData.llq.lease > 0x70000000UL / mDNSPlatformOneSecond)
14744b22b933Srs200217 opt->OptData.llq.lease = 0x70000000UL / mDNSPlatformOneSecond;
14754b22b933Srs200217 ptr += sizeof(mDNSOpaque32);
14764b22b933Srs200217 nread += LLQ_OPTLEN;
14774b22b933Srs200217 }
14784b22b933Srs200217 else if (opt->opt == kDNSOpt_Lease)
14794b22b933Srs200217 {
14804b22b933Srs200217 if ((unsigned)(limit - ptr) < sizeof(mDNSs32)) goto space_err;
14814b22b933Srs200217
14824b22b933Srs200217 opt->OptData.lease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
14834b22b933Srs200217 if (opt->OptData.lease > 0x70000000UL / mDNSPlatformOneSecond)
14844b22b933Srs200217 opt->OptData.lease = 0x70000000UL / mDNSPlatformOneSecond;
14854b22b933Srs200217 ptr += sizeof(mDNSs32);
14864b22b933Srs200217 nread += sizeof(mDNSs32);
14874b22b933Srs200217 }
14884b22b933Srs200217 else { LogMsg("ERROR: getOptRdata - unknown opt %d", opt->opt); return mDNSNULL; }
14894b22b933Srs200217 opt++; // increment pointer into rdatabody
14904b22b933Srs200217 }
14914b22b933Srs200217
14924b22b933Srs200217 rr->rdlength = pktRDLen;
14934b22b933Srs200217 return ptr;
14944b22b933Srs200217
14954b22b933Srs200217 space_err:
14964b22b933Srs200217 LogMsg("ERROR: getLLQRdata - out of space");
14974b22b933Srs200217 return mDNSNULL;
14984b22b933Srs200217 }
14994b22b933Srs200217
putRData(const DNSMessage * const msg,mDNSu8 * ptr,const mDNSu8 * const limit,ResourceRecord * rr)15004b22b933Srs200217 mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, ResourceRecord *rr)
15014b22b933Srs200217 {
15024b22b933Srs200217 switch (rr->rrtype)
15034b22b933Srs200217 {
15044b22b933Srs200217 case kDNSType_A: if (rr->rdlength != 4)
15054b22b933Srs200217 {
15064b22b933Srs200217 debugf("putRData: Illegal length %d for kDNSType_A", rr->rdlength);
15074b22b933Srs200217 return(mDNSNULL);
15084b22b933Srs200217 }
15094b22b933Srs200217 if (ptr + 4 > limit) return(mDNSNULL);
15104b22b933Srs200217 *ptr++ = rr->rdata->u.ipv4.b[0];
15114b22b933Srs200217 *ptr++ = rr->rdata->u.ipv4.b[1];
15124b22b933Srs200217 *ptr++ = rr->rdata->u.ipv4.b[2];
15134b22b933Srs200217 *ptr++ = rr->rdata->u.ipv4.b[3];
15144b22b933Srs200217 return(ptr);
15154b22b933Srs200217
15164b22b933Srs200217 case kDNSType_CNAME:// Same as PTR
15174b22b933Srs200217 case kDNSType_PTR: return(putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.name));
15184b22b933Srs200217
15194b22b933Srs200217 case kDNSType_AAAA: if (rr->rdlength != sizeof(rr->rdata->u.ipv6))
15204b22b933Srs200217 {
15214b22b933Srs200217 debugf("putRData: Illegal length %d for kDNSType_AAAA", rr->rdlength);
15224b22b933Srs200217 return(mDNSNULL);
15234b22b933Srs200217 }
15244b22b933Srs200217 if (ptr + sizeof(rr->rdata->u.ipv6) > limit) return(mDNSNULL);
15254b22b933Srs200217 mDNSPlatformMemCopy(&rr->rdata->u.ipv6, ptr, sizeof(rr->rdata->u.ipv6));
15264b22b933Srs200217 return(ptr + sizeof(rr->rdata->u.ipv6));
15274b22b933Srs200217
15284b22b933Srs200217 case kDNSType_SRV: if (ptr + 6 > limit) return(mDNSNULL);
15294b22b933Srs200217 *ptr++ = (mDNSu8)(rr->rdata->u.srv.priority >> 8);
15304b22b933Srs200217 *ptr++ = (mDNSu8)(rr->rdata->u.srv.priority & 0xFF);
15314b22b933Srs200217 *ptr++ = (mDNSu8)(rr->rdata->u.srv.weight >> 8);
15324b22b933Srs200217 *ptr++ = (mDNSu8)(rr->rdata->u.srv.weight & 0xFF);
15334b22b933Srs200217 *ptr++ = rr->rdata->u.srv.port.b[0];
15344b22b933Srs200217 *ptr++ = rr->rdata->u.srv.port.b[1];
15354b22b933Srs200217 return(putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.srv.target));
15364b22b933Srs200217 case kDNSType_OPT: return putOptRData(ptr, limit, rr);
15374b22b933Srs200217
15384b22b933Srs200217 default: debugf("putRData: Warning! Writing unknown resource type %d as raw data", rr->rrtype);
15394b22b933Srs200217 // Fall through to common code below
15404b22b933Srs200217 case kDNSType_HINFO:
15414b22b933Srs200217 case kDNSType_TXT:
15424b22b933Srs200217 case kDNSType_TSIG: if (ptr + rr->rdlength > limit) return(mDNSNULL);
15434b22b933Srs200217 mDNSPlatformMemCopy(rr->rdata->u.data, ptr, rr->rdlength);
15444b22b933Srs200217 return(ptr + rr->rdlength);
15454b22b933Srs200217 }
15464b22b933Srs200217 }
15474b22b933Srs200217
PutResourceRecordTTLWithLimit(DNSMessage * const msg,mDNSu8 * ptr,mDNSu16 * count,ResourceRecord * rr,mDNSu32 ttl,const mDNSu8 * limit)15484b22b933Srs200217 mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 ttl, const mDNSu8 *limit)
15494b22b933Srs200217 {
15504b22b933Srs200217 mDNSu8 *endofrdata;
15514b22b933Srs200217 mDNSu16 actualLength;
15524b22b933Srs200217
15534b22b933Srs200217 if (rr->RecordType == kDNSRecordTypeUnregistered)
15544b22b933Srs200217 {
15554b22b933Srs200217 LogMsg("PutResourceRecord ERROR! Attempt to put kDNSRecordTypeUnregistered %##s (%s)", rr->name->c, DNSTypeName(rr->rrtype));
15564b22b933Srs200217 return(ptr);
15574b22b933Srs200217 }
15584b22b933Srs200217
15594b22b933Srs200217 ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name);
15604b22b933Srs200217 if (!ptr || ptr + 10 >= limit) return(mDNSNULL); // If we're out-of-space, return mDNSNULL
15614b22b933Srs200217 ptr[0] = (mDNSu8)(rr->rrtype >> 8);
15624b22b933Srs200217 ptr[1] = (mDNSu8)(rr->rrtype & 0xFF);
15634b22b933Srs200217 ptr[2] = (mDNSu8)(rr->rrclass >> 8);
15644b22b933Srs200217 ptr[3] = (mDNSu8)(rr->rrclass & 0xFF);
15654b22b933Srs200217 ptr[4] = (mDNSu8)((ttl >> 24) & 0xFF);
15664b22b933Srs200217 ptr[5] = (mDNSu8)((ttl >> 16) & 0xFF);
15674b22b933Srs200217 ptr[6] = (mDNSu8)((ttl >> 8) & 0xFF);
15684b22b933Srs200217 ptr[7] = (mDNSu8)( ttl & 0xFF);
15694b22b933Srs200217 endofrdata = putRData(msg, ptr+10, limit, rr);
15704b22b933Srs200217 if (!endofrdata) { verbosedebugf("Ran out of space in PutResourceRecord for %##s (%s)", rr->name->c, DNSTypeName(rr->rrtype)); return(mDNSNULL); }
15714b22b933Srs200217
15724b22b933Srs200217 // Go back and fill in the actual number of data bytes we wrote
15734b22b933Srs200217 // (actualLength can be less than rdlength when domain name compression is used)
15744b22b933Srs200217 actualLength = (mDNSu16)(endofrdata - ptr - 10);
15754b22b933Srs200217 ptr[8] = (mDNSu8)(actualLength >> 8);
15764b22b933Srs200217 ptr[9] = (mDNSu8)(actualLength & 0xFF);
15774b22b933Srs200217
15784b22b933Srs200217 if (count) (*count)++;
15794b22b933Srs200217 else LogMsg("PutResourceRecordTTL: ERROR: No target count to update for %##s (%s)", rr->name->c, DNSTypeName(rr->rrtype));
15804b22b933Srs200217 return(endofrdata);
15814b22b933Srs200217 }
15824b22b933Srs200217
PutResourceRecordCappedTTL(DNSMessage * const msg,mDNSu8 * ptr,mDNSu16 * count,ResourceRecord * rr,mDNSu32 maxttl)15834b22b933Srs200217 mDNSexport mDNSu8 *PutResourceRecordCappedTTL(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32
15844b22b933Srs200217 maxttl)
15854b22b933Srs200217 {
15864b22b933Srs200217 if (maxttl > rr->rroriginalttl) maxttl = rr->rroriginalttl;
15874b22b933Srs200217 return(PutResourceRecordTTL(msg, ptr, count, rr, maxttl));
15884b22b933Srs200217 }
15894b22b933Srs200217
putEmptyResourceRecord(DNSMessage * const msg,mDNSu8 * ptr,const mDNSu8 * const limit,mDNSu16 * count,const AuthRecord * rr)15904b22b933Srs200217 mDNSexport mDNSu8 *putEmptyResourceRecord(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit,
15914b22b933Srs200217 mDNSu16 *count, const AuthRecord *rr)
15924b22b933Srs200217 {
15934b22b933Srs200217 ptr = putDomainNameAsLabels(msg, ptr, limit, rr->resrec.name);
15944b22b933Srs200217 if (!ptr || ptr + 10 > limit) return(mDNSNULL); // If we're out-of-space, return mDNSNULL
15954b22b933Srs200217 ptr[0] = (mDNSu8)(rr->resrec.rrtype >> 8); // Put type
15964b22b933Srs200217 ptr[1] = (mDNSu8)(rr->resrec.rrtype & 0xFF);
15974b22b933Srs200217 ptr[2] = (mDNSu8)(rr->resrec.rrclass >> 8); // Put class
15984b22b933Srs200217 ptr[3] = (mDNSu8)(rr->resrec.rrclass & 0xFF);
15994b22b933Srs200217 ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // TTL is zero
16004b22b933Srs200217 ptr[8] = ptr[9] = 0; // RDATA length is zero
16014b22b933Srs200217 (*count)++;
16024b22b933Srs200217 return(ptr + 10);
16034b22b933Srs200217 }
16044b22b933Srs200217
putQuestion(DNSMessage * const msg,mDNSu8 * ptr,const mDNSu8 * const limit,const domainname * const name,mDNSu16 rrtype,mDNSu16 rrclass)16054b22b933Srs200217 mDNSexport mDNSu8 *putQuestion(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name, mDNSu16 rrtype, mDNSu16 rrclass)
16064b22b933Srs200217 {
16074b22b933Srs200217 ptr = putDomainNameAsLabels(msg, ptr, limit, name);
16084b22b933Srs200217 if (!ptr || ptr+4 >= limit) return(mDNSNULL); // If we're out-of-space, return mDNSNULL
16094b22b933Srs200217 ptr[0] = (mDNSu8)(rrtype >> 8);
16104b22b933Srs200217 ptr[1] = (mDNSu8)(rrtype & 0xFF);
16114b22b933Srs200217 ptr[2] = (mDNSu8)(rrclass >> 8);
16124b22b933Srs200217 ptr[3] = (mDNSu8)(rrclass & 0xFF);
16134b22b933Srs200217 msg->h.numQuestions++;
16144b22b933Srs200217 return(ptr+4);
16154b22b933Srs200217 }
16164b22b933Srs200217
16174b22b933Srs200217 // for dynamic updates
putZone(DNSMessage * const msg,mDNSu8 * ptr,mDNSu8 * limit,const domainname * zone,mDNSOpaque16 zoneClass)16184b22b933Srs200217 mDNSexport mDNSu8 *putZone(DNSMessage *const msg, mDNSu8 *ptr, mDNSu8 *limit, const domainname *zone, mDNSOpaque16 zoneClass)
16194b22b933Srs200217 {
16204b22b933Srs200217 ptr = putDomainNameAsLabels(msg, ptr, limit, zone);
16214b22b933Srs200217 if (!ptr || ptr + 4 > limit) return mDNSNULL; // If we're out-of-space, return NULL
16224b22b933Srs200217 *ptr++ = (mDNSu8)(kDNSType_SOA >> 8);
16234b22b933Srs200217 *ptr++ = (mDNSu8)(kDNSType_SOA & 0xFF);
16244b22b933Srs200217 *ptr++ = zoneClass.b[0];
16254b22b933Srs200217 *ptr++ = zoneClass.b[1];
16264b22b933Srs200217 msg->h.mDNS_numZones++;
16274b22b933Srs200217 return ptr;
16284b22b933Srs200217 }
16294b22b933Srs200217
16304b22b933Srs200217 // for dynamic updates
putPrereqNameNotInUse(domainname * name,DNSMessage * msg,mDNSu8 * ptr,mDNSu8 * end)16314b22b933Srs200217 mDNSexport mDNSu8 *putPrereqNameNotInUse(domainname *name, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *end)
16324b22b933Srs200217 {
16334b22b933Srs200217 AuthRecord prereq;
16344b22b933Srs200217
16354b22b933Srs200217 mDNSPlatformMemZero(&prereq, sizeof(AuthRecord));
16364b22b933Srs200217 mDNS_SetupResourceRecord(&prereq, mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, mDNSNULL, mDNSNULL);
16374b22b933Srs200217 AssignDomainName(prereq.resrec.name, name);
16384b22b933Srs200217 prereq.resrec.rrtype = kDNSQType_ANY;
16394b22b933Srs200217 prereq.resrec.rrclass = kDNSClass_NONE;
16404b22b933Srs200217 ptr = putEmptyResourceRecord(msg, ptr, end, &msg->h.mDNS_numPrereqs, &prereq);
16414b22b933Srs200217 return ptr;
16424b22b933Srs200217 }
16434b22b933Srs200217
16444b22b933Srs200217 // for dynamic updates
putDeletionRecord(DNSMessage * msg,mDNSu8 * ptr,ResourceRecord * rr)16454b22b933Srs200217 mDNSexport mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr)
16464b22b933Srs200217 {
16474b22b933Srs200217 mDNSu16 origclass;
16484b22b933Srs200217 // deletion: specify record w/ TTL 0, class NONE
16494b22b933Srs200217
16504b22b933Srs200217 origclass = rr->rrclass;
16514b22b933Srs200217 rr->rrclass = kDNSClass_NONE;
16524b22b933Srs200217 ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.mDNS_numUpdates, rr, 0);
16534b22b933Srs200217 rr->rrclass = origclass;
16544b22b933Srs200217 return ptr;
16554b22b933Srs200217 }
16564b22b933Srs200217
putDeleteRRSet(DNSMessage * msg,mDNSu8 * ptr,const domainname * name,mDNSu16 rrtype)16574b22b933Srs200217 mDNSexport mDNSu8 *putDeleteRRSet(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype)
16584b22b933Srs200217 {
16594b22b933Srs200217 const mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;
16604b22b933Srs200217 mDNSu16 class = kDNSQClass_ANY;
16614b22b933Srs200217
16624b22b933Srs200217 ptr = putDomainNameAsLabels(msg, ptr, limit, name);
16634b22b933Srs200217 if (!ptr || ptr + 10 >= limit) return mDNSNULL; // If we're out-of-space, return mDNSNULL
16644b22b933Srs200217 ptr[0] = (mDNSu8)(rrtype >> 8);
16654b22b933Srs200217 ptr[1] = (mDNSu8)(rrtype & 0xFF);
16664b22b933Srs200217 ptr[2] = (mDNSu8)(class >> 8);
16674b22b933Srs200217 ptr[3] = (mDNSu8)(class & 0xFF);
16684b22b933Srs200217 ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // zero ttl
16694b22b933Srs200217 ptr[8] = ptr[9] = 0; // zero rdlength/rdata
16704b22b933Srs200217
16714b22b933Srs200217 msg->h.mDNS_numUpdates++;
16724b22b933Srs200217 return ptr + 10;
16734b22b933Srs200217 }
16744b22b933Srs200217
16754b22b933Srs200217 // for dynamic updates
putDeleteAllRRSets(DNSMessage * msg,mDNSu8 * ptr,const domainname * name)16764b22b933Srs200217 mDNSexport mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domainname *name)
16774b22b933Srs200217 {
16784b22b933Srs200217 const mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;
16794b22b933Srs200217 mDNSu16 class = kDNSQClass_ANY;
16804b22b933Srs200217 mDNSu16 rrtype = kDNSQType_ANY;
16814b22b933Srs200217
16824b22b933Srs200217 ptr = putDomainNameAsLabels(msg, ptr, limit, name);
16834b22b933Srs200217 if (!ptr || ptr + 10 >= limit) return mDNSNULL; // If we're out-of-space, return mDNSNULL
16844b22b933Srs200217 ptr[0] = (mDNSu8)(rrtype >> 8);
16854b22b933Srs200217 ptr[1] = (mDNSu8)(rrtype & 0xFF);
16864b22b933Srs200217 ptr[2] = (mDNSu8)(class >> 8);
16874b22b933Srs200217 ptr[3] = (mDNSu8)(class & 0xFF);
16884b22b933Srs200217 ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // zero ttl
16894b22b933Srs200217 ptr[8] = ptr[9] = 0; // zero rdlength/rdata
16904b22b933Srs200217
16914b22b933Srs200217 msg->h.mDNS_numUpdates++;
16924b22b933Srs200217 return ptr + 10;
16934b22b933Srs200217 }
16944b22b933Srs200217
16954b22b933Srs200217 // for dynamic updates
putUpdateLease(DNSMessage * msg,mDNSu8 * end,mDNSu32 lease)16964b22b933Srs200217 mDNSexport mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease)
16974b22b933Srs200217 {
16984b22b933Srs200217 AuthRecord rr;
16994b22b933Srs200217 ResourceRecord *opt = &rr.resrec;
17004b22b933Srs200217 rdataOpt *optRD;
17014b22b933Srs200217
17024b22b933Srs200217 mDNSPlatformMemZero(&rr, sizeof(AuthRecord));
17034b22b933Srs200217 mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, 0, mDNSNULL, mDNSNULL);
17044b22b933Srs200217
17054b22b933Srs200217 opt->RecordType = kDNSRecordTypeKnownUnique; // to avoid warnings in other layers
17064b22b933Srs200217 opt->rrtype = kDNSType_OPT;
17074b22b933Srs200217 opt->rdlength = LEASE_OPT_RDLEN;
17084b22b933Srs200217 opt->rdestimate = LEASE_OPT_RDLEN;
17094b22b933Srs200217
17104b22b933Srs200217 optRD = &rr.resrec.rdata->u.opt;
17114b22b933Srs200217 optRD->opt = kDNSOpt_Lease;
17124b22b933Srs200217 optRD->optlen = sizeof(mDNSs32);
17134b22b933Srs200217 optRD->OptData.lease = lease;
17144b22b933Srs200217 end = PutResourceRecordTTLJumbo(msg, end, &msg->h.numAdditionals, opt, 0);
17154b22b933Srs200217 if (!end) { LogMsg("ERROR: putUpdateLease - PutResourceRecordTTL"); return mDNSNULL; }
17164b22b933Srs200217
17174b22b933Srs200217 return end;
17184b22b933Srs200217 }
17194b22b933Srs200217
17204b22b933Srs200217 // ***************************************************************************
17214b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
17224b22b933Srs200217 #pragma mark -
17234b22b933Srs200217 #pragma mark - DNS Message Parsing Functions
17244b22b933Srs200217 #endif
17254b22b933Srs200217
DomainNameHashValue(const domainname * const name)17264b22b933Srs200217 mDNSexport mDNSu32 DomainNameHashValue(const domainname *const name)
17274b22b933Srs200217 {
17284b22b933Srs200217 mDNSu32 sum = 0;
17294b22b933Srs200217 const mDNSu8 *c;
17304b22b933Srs200217
17314b22b933Srs200217 for (c = name->c; c[0] != 0 && c[1] != 0; c += 2)
17324b22b933Srs200217 {
17334b22b933Srs200217 sum += ((mDNSIsUpperCase(c[0]) ? c[0] + 'a' - 'A' : c[0]) << 8) |
17344b22b933Srs200217 (mDNSIsUpperCase(c[1]) ? c[1] + 'a' - 'A' : c[1]);
17354b22b933Srs200217 sum = (sum<<3) | (sum>>29);
17364b22b933Srs200217 }
17374b22b933Srs200217 if (c[0]) sum += ((mDNSIsUpperCase(c[0]) ? c[0] + 'a' - 'A' : c[0]) << 8);
17384b22b933Srs200217 return(sum);
17394b22b933Srs200217 }
17404b22b933Srs200217
SetNewRData(ResourceRecord * const rr,RData * NewRData,mDNSu16 rdlength)17414b22b933Srs200217 mDNSexport void SetNewRData(ResourceRecord *const rr, RData *NewRData, mDNSu16 rdlength)
17424b22b933Srs200217 {
17434b22b933Srs200217 domainname *target;
17444b22b933Srs200217 if (NewRData)
17454b22b933Srs200217 {
17464b22b933Srs200217 rr->rdata = NewRData;
17474b22b933Srs200217 rr->rdlength = rdlength;
17484b22b933Srs200217 }
17494b22b933Srs200217 // Must not try to get target pointer until after updating rr->rdata
17504b22b933Srs200217 target = GetRRDomainNameTarget(rr);
17514b22b933Srs200217 rr->rdlength = GetRDLength(rr, mDNSfalse);
17524b22b933Srs200217 rr->rdestimate = GetRDLength(rr, mDNStrue);
17534b22b933Srs200217 rr->rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(rr->rdlength, &rr->rdata->u);
17544b22b933Srs200217 }
17554b22b933Srs200217
skipDomainName(const DNSMessage * const msg,const mDNSu8 * ptr,const mDNSu8 * const end)17564b22b933Srs200217 mDNSexport const mDNSu8 *skipDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end)
17574b22b933Srs200217 {
17584b22b933Srs200217 mDNSu16 total = 0;
17594b22b933Srs200217
17604b22b933Srs200217 if (ptr < (mDNSu8*)msg || ptr >= end)
17614b22b933Srs200217 { debugf("skipDomainName: Illegal ptr not within packet boundaries"); return(mDNSNULL); }
17624b22b933Srs200217
17634b22b933Srs200217 while (1) // Read sequence of labels
17644b22b933Srs200217 {
17654b22b933Srs200217 const mDNSu8 len = *ptr++; // Read length of this label
17664b22b933Srs200217 if (len == 0) return(ptr); // If length is zero, that means this name is complete
17674b22b933Srs200217 switch (len & 0xC0)
17684b22b933Srs200217 {
17694b22b933Srs200217 case 0x00: if (ptr + len >= end) // Remember: expect at least one more byte for the root label
17704b22b933Srs200217 { debugf("skipDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); }
17714b22b933Srs200217 if (total + 1 + len >= MAX_DOMAIN_NAME) // Remember: expect at least one more byte for the root label
17724b22b933Srs200217 { debugf("skipDomainName: Malformed domain name (more than 255 characters)"); return(mDNSNULL); }
17734b22b933Srs200217 ptr += len;
17744b22b933Srs200217 total += 1 + len;
17754b22b933Srs200217 break;
17764b22b933Srs200217
17774b22b933Srs200217 case 0x40: debugf("skipDomainName: Extended EDNS0 label types 0x%X not supported", len); return(mDNSNULL);
17784b22b933Srs200217 case 0x80: debugf("skipDomainName: Illegal label length 0x%X", len); return(mDNSNULL);
17794b22b933Srs200217 case 0xC0: return(ptr+1);
17804b22b933Srs200217 }
17814b22b933Srs200217 }
17824b22b933Srs200217 }
17834b22b933Srs200217
17844b22b933Srs200217 // Routine to fetch an FQDN from the DNS message, following compression pointers if necessary.
getDomainName(const DNSMessage * const msg,const mDNSu8 * ptr,const mDNSu8 * const end,domainname * const name)17854b22b933Srs200217 mDNSexport const mDNSu8 *getDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end,
17864b22b933Srs200217 domainname *const name)
17874b22b933Srs200217 {
17884b22b933Srs200217 const mDNSu8 *nextbyte = mDNSNULL; // Record where we got to before we started following pointers
17894b22b933Srs200217 mDNSu8 *np = name->c; // Name pointer
17904b22b933Srs200217 const mDNSu8 *const limit = np + MAX_DOMAIN_NAME; // Limit so we don't overrun buffer
17914b22b933Srs200217
17924b22b933Srs200217 if (ptr < (mDNSu8*)msg || ptr >= end)
17934b22b933Srs200217 { debugf("getDomainName: Illegal ptr not within packet boundaries"); return(mDNSNULL); }
17944b22b933Srs200217
17954b22b933Srs200217 *np = 0; // Tentatively place the root label here (may be overwritten if we have more labels)
17964b22b933Srs200217
17974b22b933Srs200217 while (1) // Read sequence of labels
17984b22b933Srs200217 {
17994b22b933Srs200217 const mDNSu8 len = *ptr++; // Read length of this label
18004b22b933Srs200217 if (len == 0) break; // If length is zero, that means this name is complete
18014b22b933Srs200217 switch (len & 0xC0)
18024b22b933Srs200217 {
18034b22b933Srs200217 int i;
18044b22b933Srs200217 mDNSu16 offset;
18054b22b933Srs200217
18064b22b933Srs200217 case 0x00: if (ptr + len >= end) // Remember: expect at least one more byte for the root label
18074b22b933Srs200217 { debugf("getDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); }
18084b22b933Srs200217 if (np + 1 + len >= limit) // Remember: expect at least one more byte for the root label
18094b22b933Srs200217 { debugf("getDomainName: Malformed domain name (more than 255 characters)"); return(mDNSNULL); }
18104b22b933Srs200217 *np++ = len;
18114b22b933Srs200217 for (i=0; i<len; i++) *np++ = *ptr++;
18124b22b933Srs200217 *np = 0; // Tentatively place the root label here (may be overwritten if we have more labels)
18134b22b933Srs200217 break;
18144b22b933Srs200217
18154b22b933Srs200217 case 0x40: debugf("getDomainName: Extended EDNS0 label types 0x%X not supported in name %##s", len, name->c);
18164b22b933Srs200217 return(mDNSNULL);
18174b22b933Srs200217
18184b22b933Srs200217 case 0x80: debugf("getDomainName: Illegal label length 0x%X in domain name %##s", len, name->c); return(mDNSNULL);
18194b22b933Srs200217
18204b22b933Srs200217 case 0xC0: offset = (mDNSu16)((((mDNSu16)(len & 0x3F)) << 8) | *ptr++);
18214b22b933Srs200217 if (!nextbyte) nextbyte = ptr; // Record where we got to before we started following pointers
18224b22b933Srs200217 ptr = (mDNSu8 *)msg + offset;
18234b22b933Srs200217 if (ptr < (mDNSu8*)msg || ptr >= end)
18244b22b933Srs200217 { debugf("getDomainName: Illegal compression pointer not within packet boundaries"); return(mDNSNULL); }
18254b22b933Srs200217 if (*ptr & 0xC0)
18264b22b933Srs200217 { debugf("getDomainName: Compression pointer must point to real label"); return(mDNSNULL); }
18274b22b933Srs200217 break;
18284b22b933Srs200217 }
18294b22b933Srs200217 }
18304b22b933Srs200217
18314b22b933Srs200217 if (nextbyte) return(nextbyte);
18324b22b933Srs200217 else return(ptr);
18334b22b933Srs200217 }
18344b22b933Srs200217
skipResourceRecord(const DNSMessage * msg,const mDNSu8 * ptr,const mDNSu8 * end)18354b22b933Srs200217 mDNSexport const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end)
18364b22b933Srs200217 {
18374b22b933Srs200217 mDNSu16 pktrdlength;
18384b22b933Srs200217
18394b22b933Srs200217 ptr = skipDomainName(msg, ptr, end);
18404b22b933Srs200217 if (!ptr) { debugf("skipResourceRecord: Malformed RR name"); return(mDNSNULL); }
18414b22b933Srs200217
18424b22b933Srs200217 if (ptr + 10 > end) { debugf("skipResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
18434b22b933Srs200217 pktrdlength = (mDNSu16)((mDNSu16)ptr[8] << 8 | ptr[9]);
18444b22b933Srs200217 ptr += 10;
18454b22b933Srs200217 if (ptr + pktrdlength > end) { debugf("skipResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); }
18464b22b933Srs200217
18474b22b933Srs200217 return(ptr + pktrdlength);
18484b22b933Srs200217 }
18494b22b933Srs200217
GetLargeResourceRecord(mDNS * const m,const DNSMessage * const msg,const mDNSu8 * ptr,const mDNSu8 * end,const mDNSInterfaceID InterfaceID,mDNSu8 RecordType,LargeCacheRecord * largecr)18504b22b933Srs200217 mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage * const msg, const mDNSu8 *ptr,
18514b22b933Srs200217 const mDNSu8 *end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *largecr)
18524b22b933Srs200217 {
18534b22b933Srs200217 CacheRecord *rr = &largecr->r;
18544b22b933Srs200217 mDNSu16 pktrdlength;
18554b22b933Srs200217
18564b22b933Srs200217 if (largecr == &m->rec && largecr->r.resrec.RecordType)
18574b22b933Srs200217 LogMsg("GetLargeResourceRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &largecr->r));
18584b22b933Srs200217
18594b22b933Srs200217 rr->next = mDNSNULL;
18604b22b933Srs200217 rr->resrec.name = &largecr->namestorage;
18614b22b933Srs200217
18624b22b933Srs200217 rr->NextInKAList = mDNSNULL;
18634b22b933Srs200217 rr->TimeRcvd = m ? m->timenow : 0;
18644b22b933Srs200217 rr->DelayDelivery = 0;
18654b22b933Srs200217 rr->NextRequiredQuery = m ? m->timenow : 0; // Will be updated to the real value when we call SetNextCacheCheckTime()
18664b22b933Srs200217 rr->LastUsed = m ? m->timenow : 0;
18674b22b933Srs200217 rr->CRActiveQuestion = mDNSNULL;
18684b22b933Srs200217 rr->UnansweredQueries = 0;
18694b22b933Srs200217 rr->LastUnansweredTime= 0;
18704b22b933Srs200217 rr->MPUnansweredQ = 0;
18714b22b933Srs200217 rr->MPLastUnansweredQT= 0;
18724b22b933Srs200217 rr->MPUnansweredKA = 0;
18734b22b933Srs200217 rr->MPExpectingKA = mDNSfalse;
18744b22b933Srs200217 rr->NextInCFList = mDNSNULL;
18754b22b933Srs200217
18764b22b933Srs200217 rr->resrec.InterfaceID = InterfaceID;
18774b22b933Srs200217 ptr = getDomainName(msg, ptr, end, rr->resrec.name);
18784b22b933Srs200217 if (!ptr) { debugf("GetResourceRecord: Malformed RR name"); return(mDNSNULL); }
18794b22b933Srs200217
18804b22b933Srs200217 if (ptr + 10 > end) { debugf("GetResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
18814b22b933Srs200217
18824b22b933Srs200217 rr->resrec.rrtype = (mDNSu16) ((mDNSu16)ptr[0] << 8 | ptr[1]);
18834b22b933Srs200217 rr->resrec.rrclass = (mDNSu16)(((mDNSu16)ptr[2] << 8 | ptr[3]) & kDNSClass_Mask);
18844b22b933Srs200217 rr->resrec.rroriginalttl = (mDNSu32) ((mDNSu32)ptr[4] << 24 | (mDNSu32)ptr[5] << 16 | (mDNSu32)ptr[6] << 8 | ptr[7]);
18854b22b933Srs200217 if (rr->resrec.rroriginalttl > 0x70000000UL / mDNSPlatformOneSecond && (mDNSs32)rr->resrec.rroriginalttl != -1)
18864b22b933Srs200217 rr->resrec.rroriginalttl = 0x70000000UL / mDNSPlatformOneSecond;
18874b22b933Srs200217 // Note: We don't have to adjust m->NextCacheCheck here -- this is just getting a record into memory for
18884b22b933Srs200217 // us to look at. If we decide to copy it into the cache, then we'll update m->NextCacheCheck accordingly.
18894b22b933Srs200217 pktrdlength = (mDNSu16)((mDNSu16)ptr[8] << 8 | ptr[9]);
18904b22b933Srs200217 if (ptr[2] & (kDNSClass_UniqueRRSet >> 8))
18914b22b933Srs200217 RecordType |= kDNSRecordTypePacketUniqueMask;
18924b22b933Srs200217 ptr += 10;
18934b22b933Srs200217 if (ptr + pktrdlength > end) { debugf("GetResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); }
18944b22b933Srs200217 end = ptr + pktrdlength; // Adjust end to indicate the end of the rdata for this resource record
18954b22b933Srs200217
18964b22b933Srs200217 rr->resrec.rdata = (RData*)&rr->rdatastorage;
18974b22b933Srs200217 rr->resrec.rdata->MaxRDLength = MaximumRDSize;
18984b22b933Srs200217
18994b22b933Srs200217 if (!RecordType) LogMsg("GetLargeResourceRecord: No RecordType for %##s", rr->resrec.name->c);
19004b22b933Srs200217
19014b22b933Srs200217 switch (rr->resrec.rrtype)
19024b22b933Srs200217 {
19034b22b933Srs200217 case kDNSType_A: rr->resrec.rdata->u.ipv4.b[0] = ptr[0];
19044b22b933Srs200217 rr->resrec.rdata->u.ipv4.b[1] = ptr[1];
19054b22b933Srs200217 rr->resrec.rdata->u.ipv4.b[2] = ptr[2];
19064b22b933Srs200217 rr->resrec.rdata->u.ipv4.b[3] = ptr[3];
19074b22b933Srs200217 break;
19084b22b933Srs200217
19094b22b933Srs200217 case kDNSType_CNAME:// Same as PTR
19104b22b933Srs200217 case kDNSType_NS:
19114b22b933Srs200217 case kDNSType_PTR: if (!getDomainName(msg, ptr, end, &rr->resrec.rdata->u.name))
19124b22b933Srs200217 { debugf("GetResourceRecord: Malformed CNAME/PTR RDATA name"); return(mDNSNULL); }
19134b22b933Srs200217 //debugf("%##s PTR %##s rdlen %d", rr->resrec.name.c, rr->resrec.rdata->u.name.c, pktrdlength);
19144b22b933Srs200217 break;
19154b22b933Srs200217
19164b22b933Srs200217 case kDNSType_NULL: //Same as TXT
19174b22b933Srs200217 case kDNSType_HINFO://Same as TXT
19184b22b933Srs200217 case kDNSType_TXT: if (pktrdlength > rr->resrec.rdata->MaxRDLength)
19194b22b933Srs200217 {
19204b22b933Srs200217 debugf("GetResourceRecord: %s rdata size (%d) exceeds storage (%d)",
19214b22b933Srs200217 DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength);
19224b22b933Srs200217 return(mDNSNULL);
19234b22b933Srs200217 }
19244b22b933Srs200217 rr->resrec.rdlength = pktrdlength;
19254b22b933Srs200217 mDNSPlatformMemCopy(ptr, rr->resrec.rdata->u.data, pktrdlength);
19264b22b933Srs200217 break;
19274b22b933Srs200217
19284b22b933Srs200217 case kDNSType_AAAA: mDNSPlatformMemCopy(ptr, &rr->resrec.rdata->u.ipv6, sizeof(rr->resrec.rdata->u.ipv6));
19294b22b933Srs200217 break;
19304b22b933Srs200217
19314b22b933Srs200217 case kDNSType_SRV: rr->resrec.rdata->u.srv.priority = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
19324b22b933Srs200217 rr->resrec.rdata->u.srv.weight = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
19334b22b933Srs200217 rr->resrec.rdata->u.srv.port.b[0] = ptr[4];
19344b22b933Srs200217 rr->resrec.rdata->u.srv.port.b[1] = ptr[5];
19354b22b933Srs200217 if (!getDomainName(msg, ptr+6, end, &rr->resrec.rdata->u.srv.target))
19364b22b933Srs200217 { debugf("GetResourceRecord: Malformed SRV RDATA name"); return(mDNSNULL); }
19374b22b933Srs200217 //debugf("%##s SRV %##s rdlen %d", rr->resrec.name.c, rr->resrec.rdata->u.srv.target.c, pktrdlength);
19384b22b933Srs200217 break;
19394b22b933Srs200217
19404b22b933Srs200217 case kDNSType_SOA: ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.mname);
19414b22b933Srs200217 if (!ptr) { debugf("GetResourceRecord: Malformed SOA RDATA mname"); return mDNSNULL; }
19424b22b933Srs200217 ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.rname);
19434b22b933Srs200217 if (!ptr) { debugf("GetResourceRecord: Malformed SOA RDATA rname"); return mDNSNULL; }
19444b22b933Srs200217 if (ptr + 0x14 != end) { debugf("GetResourceRecord: Malformed SOA RDATA"); return mDNSNULL; }
19454b22b933Srs200217 rr->resrec.rdata->u.soa.serial = (mDNSs32) ((mDNSs32)ptr[0x00] << 24 | (mDNSs32)ptr[0x01] << 16 | (mDNSs32)ptr[0x02] << 8 | ptr[0x03]);
19464b22b933Srs200217 rr->resrec.rdata->u.soa.refresh = (mDNSu32) ((mDNSu32)ptr[0x04] << 24 | (mDNSu32)ptr[0x05] << 16 | (mDNSu32)ptr[0x06] << 8 | ptr[0x07]);
19474b22b933Srs200217 rr->resrec.rdata->u.soa.retry = (mDNSu32) ((mDNSu32)ptr[0x08] << 24 | (mDNSu32)ptr[0x09] << 16 | (mDNSu32)ptr[0x0A] << 8 | ptr[0x0B]);
19484b22b933Srs200217 rr->resrec.rdata->u.soa.expire = (mDNSu32) ((mDNSu32)ptr[0x0C] << 24 | (mDNSu32)ptr[0x0D] << 16 | (mDNSu32)ptr[0x0E] << 8 | ptr[0x0F]);
19494b22b933Srs200217 rr->resrec.rdata->u.soa.min = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]);
19504b22b933Srs200217 break;
19514b22b933Srs200217
19524b22b933Srs200217 case kDNSType_OPT: getOptRdata(ptr, end, largecr, pktrdlength); break;
19534b22b933Srs200217
19544b22b933Srs200217 default: if (pktrdlength > rr->resrec.rdata->MaxRDLength)
19554b22b933Srs200217 {
19564b22b933Srs200217 debugf("GetResourceRecord: rdata %d (%s) size (%d) exceeds storage (%d)",
19574b22b933Srs200217 rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength);
19584b22b933Srs200217 return(mDNSNULL);
19594b22b933Srs200217 }
19604b22b933Srs200217 debugf("GetResourceRecord: Warning! Reading resource type %d (%s) as opaque data",
19614b22b933Srs200217 rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype));
19624b22b933Srs200217 // Note: Just because we don't understand the record type, that doesn't
19634b22b933Srs200217 // mean we fail. The DNS protocol specifies rdlength, so we can
19644b22b933Srs200217 // safely skip over unknown records and ignore them.
19654b22b933Srs200217 // We also grab a binary copy of the rdata anyway, since the caller
19664b22b933Srs200217 // might know how to interpret it even if we don't.
19674b22b933Srs200217 rr->resrec.rdlength = pktrdlength;
19684b22b933Srs200217 mDNSPlatformMemCopy(ptr, rr->resrec.rdata->u.data, pktrdlength);
19694b22b933Srs200217 break;
19704b22b933Srs200217 }
19714b22b933Srs200217
19724b22b933Srs200217 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
19734b22b933Srs200217 SetNewRData(&rr->resrec, mDNSNULL, 0);
19744b22b933Srs200217
19754b22b933Srs200217 // Success! Now fill in RecordType to show this record contains valid data
19764b22b933Srs200217 rr->resrec.RecordType = RecordType;
19774b22b933Srs200217 return(ptr + pktrdlength);
19784b22b933Srs200217 }
19794b22b933Srs200217
skipQuestion(const DNSMessage * msg,const mDNSu8 * ptr,const mDNSu8 * end)19804b22b933Srs200217 mDNSexport const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end)
19814b22b933Srs200217 {
19824b22b933Srs200217 ptr = skipDomainName(msg, ptr, end);
19834b22b933Srs200217 if (!ptr) { debugf("skipQuestion: Malformed domain name in DNS question section"); return(mDNSNULL); }
19844b22b933Srs200217 if (ptr+4 > end) { debugf("skipQuestion: Malformed DNS question section -- no query type and class!"); return(mDNSNULL); }
19854b22b933Srs200217 return(ptr+4);
19864b22b933Srs200217 }
19874b22b933Srs200217
getQuestion(const DNSMessage * msg,const mDNSu8 * ptr,const mDNSu8 * end,const mDNSInterfaceID InterfaceID,DNSQuestion * question)19884b22b933Srs200217 mDNSexport const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end, const mDNSInterfaceID InterfaceID,
19894b22b933Srs200217 DNSQuestion *question)
19904b22b933Srs200217 {
19914b22b933Srs200217 question->InterfaceID = InterfaceID;
19924b22b933Srs200217 ptr = getDomainName(msg, ptr, end, &question->qname);
19934b22b933Srs200217 if (!ptr) { debugf("Malformed domain name in DNS question section"); return(mDNSNULL); }
19944b22b933Srs200217 if (ptr+4 > end) { debugf("Malformed DNS question section -- no query type and class!"); return(mDNSNULL); }
19954b22b933Srs200217
19964b22b933Srs200217 question->qnamehash = DomainNameHashValue(&question->qname);
19974b22b933Srs200217 question->qtype = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); // Get type
19984b22b933Srs200217 question->qclass = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]); // and class
19994b22b933Srs200217 return(ptr+4);
20004b22b933Srs200217 }
20014b22b933Srs200217
LocateAnswers(const DNSMessage * const msg,const mDNSu8 * const end)20024b22b933Srs200217 mDNSexport const mDNSu8 *LocateAnswers(const DNSMessage *const msg, const mDNSu8 *const end)
20034b22b933Srs200217 {
20044b22b933Srs200217 int i;
20054b22b933Srs200217 const mDNSu8 *ptr = msg->data;
20064b22b933Srs200217 for (i = 0; i < msg->h.numQuestions && ptr; i++) ptr = skipQuestion(msg, ptr, end);
20074b22b933Srs200217 return(ptr);
20084b22b933Srs200217 }
20094b22b933Srs200217
LocateAuthorities(const DNSMessage * const msg,const mDNSu8 * const end)20104b22b933Srs200217 mDNSexport const mDNSu8 *LocateAuthorities(const DNSMessage *const msg, const mDNSu8 *const end)
20114b22b933Srs200217 {
20124b22b933Srs200217 int i;
20134b22b933Srs200217 const mDNSu8 *ptr = LocateAnswers(msg, end);
20144b22b933Srs200217 for (i = 0; i < msg->h.numAnswers && ptr; i++) ptr = skipResourceRecord(msg, ptr, end);
20154b22b933Srs200217 return(ptr);
20164b22b933Srs200217 }
20174b22b933Srs200217
LocateAdditionals(const DNSMessage * const msg,const mDNSu8 * const end)20184b22b933Srs200217 mDNSexport const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mDNSu8 *const end)
20194b22b933Srs200217 {
20204b22b933Srs200217 int i;
20214b22b933Srs200217 const mDNSu8 *ptr = LocateAuthorities(msg, end);
20224b22b933Srs200217 for (i = 0; i < msg->h.numAuthorities; i++) ptr = skipResourceRecord(msg, ptr, end);
20234b22b933Srs200217 return (ptr);
20244b22b933Srs200217 }
20254b22b933Srs200217
20264b22b933Srs200217 // ***************************************************************************
20274b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
20284b22b933Srs200217 #pragma mark -
20294b22b933Srs200217 #pragma mark -
20304b22b933Srs200217 #pragma mark - Packet Sending Functions
20314b22b933Srs200217 #endif
20324b22b933Srs200217
mDNSSendDNSMessage(const mDNS * const m,DNSMessage * const msg,mDNSu8 * end,mDNSInterfaceID InterfaceID,const mDNSAddr * dst,mDNSIPPort dstport,int sd,uDNS_AuthInfo * authInfo)20334b22b933Srs200217 mDNSexport mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
20344b22b933Srs200217 mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, int sd, uDNS_AuthInfo *authInfo)
20354b22b933Srs200217 {
20364b22b933Srs200217 mStatus status;
20374b22b933Srs200217 int nsent;
20384b22b933Srs200217 mDNSs32 msglen;
20394b22b933Srs200217 mDNSu8 lenbuf[2];
20404b22b933Srs200217 mDNSu16 numQuestions = msg->h.numQuestions;
20414b22b933Srs200217 mDNSu16 numAnswers = msg->h.numAnswers;
20424b22b933Srs200217 mDNSu16 numAuthorities = msg->h.numAuthorities;
20434b22b933Srs200217 mDNSu16 numAdditionals = msg->h.numAdditionals;
20444b22b933Srs200217 mDNSu8 *ptr = (mDNSu8 *)&msg->h.numQuestions;
20454b22b933Srs200217
20464b22b933Srs200217 // Put all the integer values in IETF byte-order (MSB first, LSB second)
20474b22b933Srs200217 *ptr++ = (mDNSu8)(numQuestions >> 8);
20484b22b933Srs200217 *ptr++ = (mDNSu8)(numQuestions & 0xFF);
20494b22b933Srs200217 *ptr++ = (mDNSu8)(numAnswers >> 8);
20504b22b933Srs200217 *ptr++ = (mDNSu8)(numAnswers & 0xFF);
20514b22b933Srs200217 *ptr++ = (mDNSu8)(numAuthorities >> 8);
20524b22b933Srs200217 *ptr++ = (mDNSu8)(numAuthorities & 0xFF);
20534b22b933Srs200217 *ptr++ = (mDNSu8)(numAdditionals >> 8);
20544b22b933Srs200217 *ptr++ = (mDNSu8)(numAdditionals & 0xFF);
20554b22b933Srs200217
20564b22b933Srs200217 if (authInfo)
20574b22b933Srs200217 {
20584b22b933Srs200217 end = DNSDigest_SignMessage(msg, &end, &numAdditionals, authInfo);
20594b22b933Srs200217 if (!end) return mStatus_UnknownErr;
20604b22b933Srs200217 }
20614b22b933Srs200217
20624b22b933Srs200217 // Send the packet on the wire
20634b22b933Srs200217
20644b22b933Srs200217 if (sd >= 0)
20654b22b933Srs200217 {
20664b22b933Srs200217 msglen = (mDNSu16)(end - (mDNSu8 *)msg);
20674b22b933Srs200217 lenbuf[0] = (mDNSu8)(msglen >> 8); // host->network byte conversion
20684b22b933Srs200217 lenbuf[1] = (mDNSu8)(msglen & 0xFF);
20694b22b933Srs200217 nsent = mDNSPlatformWriteTCP(sd, (char*)lenbuf, 2);
20704b22b933Srs200217 //!!!KRS make sure kernel is sending these as 1 packet!
20714b22b933Srs200217 if (nsent != 2) goto tcp_error;
20724b22b933Srs200217 nsent = mDNSPlatformWriteTCP(sd, (char *)msg, msglen);
20734b22b933Srs200217 if (nsent != msglen) goto tcp_error;
20744b22b933Srs200217 status = mStatus_NoError;
20754b22b933Srs200217 }
20764b22b933Srs200217 else
20774b22b933Srs200217 {
20784b22b933Srs200217 status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, dst, dstport);
20794b22b933Srs200217 }
20804b22b933Srs200217
20814b22b933Srs200217 // Put all the integer values back the way they were before we return
20824b22b933Srs200217 msg->h.numQuestions = numQuestions;
20834b22b933Srs200217 msg->h.numAnswers = numAnswers;
20844b22b933Srs200217 msg->h.numAuthorities = numAuthorities;
20854b22b933Srs200217 msg->h.numAdditionals = (mDNSu16)(authInfo ? numAdditionals - 1 : numAdditionals);
20864b22b933Srs200217
20874b22b933Srs200217 return(status);
20884b22b933Srs200217
20894b22b933Srs200217 tcp_error:
20904b22b933Srs200217 LogMsg("mDNSSendDNSMessage: error sending message over tcp");
20914b22b933Srs200217 return mStatus_UnknownErr;
20924b22b933Srs200217 }
20934b22b933Srs200217
20944b22b933Srs200217 // ***************************************************************************
20954b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
20964b22b933Srs200217 #pragma mark -
20974b22b933Srs200217 #pragma mark - RR List Management & Task Management
20984b22b933Srs200217 #endif
20994b22b933Srs200217
mDNS_Lock(mDNS * const m)21004b22b933Srs200217 mDNSexport void mDNS_Lock(mDNS *const m)
21014b22b933Srs200217 {
21024b22b933Srs200217 // MUST grab the platform lock FIRST!
21034b22b933Srs200217 mDNSPlatformLock(m);
21044b22b933Srs200217
21054b22b933Srs200217 // Normally, mDNS_reentrancy is zero and so is mDNS_busy
21064b22b933Srs200217 // However, when we call a client callback mDNS_busy is one, and we increment mDNS_reentrancy too
21074b22b933Srs200217 // If that client callback does mDNS API calls, mDNS_reentrancy and mDNS_busy will both be one
21084b22b933Srs200217 // If mDNS_busy != mDNS_reentrancy that's a bad sign
21094b22b933Srs200217 if (m->mDNS_busy != m->mDNS_reentrancy)
21104b22b933Srs200217 LogMsg("mDNS_Lock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
21114b22b933Srs200217
21124b22b933Srs200217 // If this is an initial entry into the mDNSCore code, set m->timenow
21134b22b933Srs200217 // else, if this is a re-entrant entry into the mDNSCore code, m->timenow should already be set
21144b22b933Srs200217 if (m->mDNS_busy == 0)
21154b22b933Srs200217 {
21164b22b933Srs200217 if (m->timenow)
21174b22b933Srs200217 LogMsg("mDNS_Lock: m->timenow already set (%ld/%ld)", m->timenow, mDNS_TimeNow_NoLock(m));
21184b22b933Srs200217 m->timenow = mDNS_TimeNow_NoLock(m);
21194b22b933Srs200217 if (m->timenow == 0) m->timenow = 1;
21204b22b933Srs200217 }
21214b22b933Srs200217 else if (m->timenow == 0)
21224b22b933Srs200217 {
21234b22b933Srs200217 LogMsg("mDNS_Lock: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy);
21244b22b933Srs200217 m->timenow = mDNS_TimeNow_NoLock(m);
21254b22b933Srs200217 if (m->timenow == 0) m->timenow = 1;
21264b22b933Srs200217 }
21274b22b933Srs200217
21284b22b933Srs200217 if (m->timenow_last - m->timenow > 0)
21294b22b933Srs200217 {
21304b22b933Srs200217 m->timenow_adjust += m->timenow_last - m->timenow;
2131*180be2b7SRishi Srivatsavai LogMsgNoIdent("mDNSPlatformRawTime went backwards by %ld ticks; setting correction factor to %ld", m->timenow_last - m->timenow, m->timenow_adjust);
21324b22b933Srs200217 m->timenow = m->timenow_last;
21334b22b933Srs200217 }
21344b22b933Srs200217 m->timenow_last = m->timenow;
21354b22b933Srs200217
21364b22b933Srs200217 // Increment mDNS_busy so we'll recognise re-entrant calls
21374b22b933Srs200217 m->mDNS_busy++;
21384b22b933Srs200217 }
21394b22b933Srs200217
GetNextScheduledEvent(const mDNS * const m)21404b22b933Srs200217 mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
21414b22b933Srs200217 {
21424b22b933Srs200217 mDNSs32 e = m->timenow + 0x78000000;
21434b22b933Srs200217 if (m->mDNSPlatformStatus != mStatus_NoError || m->SleepState) return(e);
21444b22b933Srs200217 if (m->NewQuestions)
21454b22b933Srs200217 {
21464b22b933Srs200217 if (m->NewQuestions->DelayAnswering) e = m->NewQuestions->DelayAnswering;
21474b22b933Srs200217 else return(m->timenow);
21484b22b933Srs200217 }
21494b22b933Srs200217 if (m->NewLocalOnlyQuestions) return(m->timenow);
21504b22b933Srs200217 if (m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords)) return(m->timenow);
21514b22b933Srs200217 if (m->SuppressSending) return(m->SuppressSending);
21524b22b933Srs200217 #ifndef UNICAST_DISABLED
21534b22b933Srs200217 if (e - m->uDNS_info.nextevent > 0) e = m->uDNS_info.nextevent;
21544b22b933Srs200217 #endif
21554b22b933Srs200217 if (e - m->NextCacheCheck > 0) e = m->NextCacheCheck;
21564b22b933Srs200217 if (e - m->NextScheduledQuery > 0) e = m->NextScheduledQuery;
21574b22b933Srs200217 if (e - m->NextScheduledProbe > 0) e = m->NextScheduledProbe;
21584b22b933Srs200217 if (e - m->NextScheduledResponse > 0) e = m->NextScheduledResponse;
21594b22b933Srs200217 return(e);
21604b22b933Srs200217 }
21614b22b933Srs200217
mDNS_Unlock(mDNS * const m)21624b22b933Srs200217 mDNSexport void mDNS_Unlock(mDNS *const m)
21634b22b933Srs200217 {
21644b22b933Srs200217 // Decrement mDNS_busy
21654b22b933Srs200217 m->mDNS_busy--;
21664b22b933Srs200217
21674b22b933Srs200217 // Check for locking failures
21684b22b933Srs200217 if (m->mDNS_busy != m->mDNS_reentrancy)
21694b22b933Srs200217 LogMsg("mDNS_Unlock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
21704b22b933Srs200217
21714b22b933Srs200217 // If this is a final exit from the mDNSCore code, set m->NextScheduledEvent and clear m->timenow
21724b22b933Srs200217 if (m->mDNS_busy == 0)
21734b22b933Srs200217 {
21744b22b933Srs200217 m->NextScheduledEvent = GetNextScheduledEvent(m);
21754b22b933Srs200217 if (m->timenow == 0) LogMsg("mDNS_Unlock: ERROR! m->timenow aready zero");
21764b22b933Srs200217 m->timenow = 0;
21774b22b933Srs200217 }
21784b22b933Srs200217
21794b22b933Srs200217 // MUST release the platform lock LAST!
21804b22b933Srs200217 mDNSPlatformUnlock(m);
21814b22b933Srs200217 }
2182