1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
24 Change History (most recent first):
27 Revision 1.92 2005/09/16 21:06:49 cheshire
28 Use mDNS_TimeNow_NoLock macro, instead of writing "mDNSPlatformRawTime() + m->timenow_adjust" all over the place
30 Revision 1.91 2005/07/10 22:10:37 cheshire
31 The getOptRdata routine implicitly assumes the destination ResourceRecord is large enough to
32 hold MaximumRDSize bytes, but its parameter was a generic ResourceRecord, which need not be that
33 large. Changing the parameter to a LargeCacheRecord makes it clearer what the routine requires.
35 Revision 1.90 2005/03/21 00:33:51 shersche
36 <rdar://problem/4021486> Fix build warnings on Win32 platform
38 Revision 1.89 2005/03/17 18:59:38 ksekar
39 <rdar://problem/4012279> Properly parse multiple LLQ Options per packet on Windows
41 Revision 1.88 2005/03/16 00:42:32 ksekar
42 <rdar://problem/4012279> Long-lived queries not working on Windows
44 Revision 1.87 2005/02/25 04:21:00 cheshire
45 <rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing
47 Revision 1.86 2005/02/18 00:43:12 cheshire
48 <rdar://problem/4010245> mDNSResponder should auto-truncate service names that are too long
50 Revision 1.85 2005/02/10 22:35:17 cheshire
51 <rdar://problem/3727944> Update name
53 Revision 1.84 2005/02/03 00:44:38 cheshire
54 <rdar://problem/3986663> DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL
56 Revision 1.83 2005/01/27 22:57:55 cheshire
57 Fix compile errors on gcc4
59 Revision 1.82 2005/01/19 03:27:03 cheshire
60 <rdar://problem/3961051> CPU Spin in mDNSResponder
61 GetNextScheduledEvent() needs to check LocalRecordReady()
63 Revision 1.81 2004/12/18 03:13:45 cheshire
64 <rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records
66 Revision 1.80 2004/12/16 21:46:43 cheshire
67 Add DNSTypeName case for kDNSType_SOA
69 Revision 1.79 2004/12/16 21:38:37 cheshire
70 Add DNSTypeName case for kDNSType_NS
72 Revision 1.78 2004/12/16 21:27:37 ksekar
73 Fixed build failures when compiled with verbose debugging messages
75 Revision 1.77 2004/12/16 20:12:59 cheshire
76 <rdar://problem/3324626> Cache memory management improvements
78 Revision 1.76 2004/12/16 08:05:29 shersche
79 Remove extranenous semicolons that cause compilation errors on Windows
81 Revision 1.75 2004/12/15 02:11:22 ksekar
82 <rdar://problem/3917317> Don't check for Dynamic DNS hostname uniqueness
84 Revision 1.74 2004/12/09 22:49:15 ksekar
85 <rdar://problem/3913653> Wide-Area Goodbyes broken
87 Revision 1.73 2004/12/07 22:49:06 cheshire
88 <rdar://problem/3908850> BIND doesn't allow zero-length TXT records
90 Revision 1.72 2004/12/06 21:15:20 ksekar
91 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
93 Revision 1.71 2004/12/04 02:12:45 cheshire
94 <rdar://problem/3517236> mDNSResponder puts LargeCacheRecord on the stack
96 Revision 1.70 2004/12/03 19:52:44 ksekar
97 Use PutResourceRecordTTLJumbo for putDeletionRecord()
99 Revision 1.69 2004/12/03 07:20:50 ksekar
100 <rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
102 Revision 1.68 2004/11/24 00:10:43 cheshire
103 <rdar://problem/3869241> For unicast operations, verify that service types are legal
105 Revision 1.67 2004/10/26 03:52:02 cheshire
106 Update checkin comments
108 Revision 1.66 2004/10/23 01:16:00 cheshire
109 <rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
111 Revision 1.65 2004/10/20 02:15:09 cheshire
112 Add case in GetRRDisplayString() to display NS rdata
114 Revision 1.64 2004/10/13 00:24:02 cheshire
115 Disable "array is too small to include a terminating null character" warning on Windows
117 Revision 1.63 2004/10/10 06:57:14 cheshire
118 Change definition of "localdomain" to make code compile a little smaller
120 Revision 1.62 2004/10/06 01:44:19 cheshire
121 <rdar://problem/3813936> Resolving too quickly sometimes returns stale TXT record
123 Revision 1.61 2004/09/30 00:24:56 ksekar
124 <rdar://problem/3695802> Dynamically update default registration domains on config change
126 Revision 1.60 2004/09/27 23:25:30 cheshire
127 Fix compiler warning: soa.serial is signed, not unsigned
129 Revision 1.59 2004/09/27 22:53:45 ksekar
130 Fixed getLargeResourceRecord for SOA rdata.
132 Revision 1.58 2004/09/25 02:41:39 cheshire
133 <rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events
135 Revision 1.57 2004/09/25 02:24:27 cheshire
136 Removed unused rr->UseCount
138 Revision 1.56 2004/09/24 20:57:39 cheshire
139 <rdar://problem/3680902> Eliminate inappropriate casts that cause misaligned-address errors
141 Revision 1.55 2004/09/17 01:08:48 cheshire
142 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
143 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
144 declared in that file are ONLY appropriate to single-address-space embedded applications.
145 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
147 Revision 1.54 2004/09/17 00:49:51 cheshire
148 Get rid of now-unused GetResourceRecord -- the correct (safe) routine to use
149 is GetLargeResourceRecord
151 Revision 1.53 2004/09/17 00:31:51 cheshire
152 For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
154 Revision 1.52 2004/09/17 00:19:10 cheshire
155 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
157 Revision 1.51 2004/09/16 02:29:39 cheshire
158 Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
159 uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
161 Revision 1.50 2004/09/16 01:58:14 cheshire
162 Fix compiler warnings
164 Revision 1.49 2004/09/14 23:42:35 cheshire
165 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
167 Revision 1.48 2004/09/14 23:27:46 cheshire
170 Revision 1.47 2004/08/25 02:50:04 cheshire
171 <rdar://problem/3561220> Browses are no longer piggybacking on other browses
172 Make mDNSSameAddress() recognise that two mDNSAddrType_None addresses are necessarily equal
174 Revision 1.46 2004/08/18 17:35:40 ksekar
175 <rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
177 Revision 1.45 2004/08/15 18:26:00 cheshire
178 Don't use strcpy() on "struct domainname" objects; use AssignDomainName() instead
179 (A "struct domainname" is a collection of packed pascal strings, not a C string.)
181 Revision 1.44 2004/08/13 23:46:58 cheshire
182 "asyncronous" -> "asynchronous"
184 Revision 1.43 2004/08/12 02:55:46 ksekar
185 Fix param order error moving putPrereqNameNotInUse from uDNS.c using
186 ustrcpy macro to DNSCommon.c using mDNSPlatformStrCopy().
188 Revision 1.42 2004/08/10 23:19:14 ksekar
189 <rdar://problem/3722542>: DNS Extension daemon for Wide Area Service Discovery
190 Moved routines/constants to allow extern access for garbage collection daemon
192 Revision 1.41 2004/08/10 01:10:01 cheshire
193 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
194 Minor revision from Roger Pantos
196 Revision 1.40 2004/08/04 22:10:46 cheshire
197 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
198 Change to use "._sub." instead of ".s." to mark subtypes.
200 Revision 1.39 2004/07/13 21:24:24 rpantos
201 Fix for <rdar://problem/3701120>.
203 Revision 1.38 2004/06/18 21:08:58 cheshire
204 <rdar://problem/3540040> Applications are registering invalid records
205 Attempts to create domain names like "www..apple.com." now logged to aid debugging
207 Revision 1.37 2004/06/18 20:25:42 cheshire
208 <rdar://problem/3488547> Add a syslog message if someone tries to use "local.arpa".
210 Revision 1.36 2004/06/18 19:09:59 cheshire
211 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
213 Revision 1.35 2004/06/05 00:14:44 cheshire
214 Fix signed/unsigned and other compiler warnings
216 Revision 1.34 2004/06/04 00:25:25 cheshire
217 Fix misaligned write exception that occurs on some platforms
219 Revision 1.33 2004/06/04 00:16:18 cheshire
220 Remove non-portable use of 'inline'
222 Revision 1.32 2004/06/03 03:09:58 ksekar
223 <rdar://problem/3668626>: Garbage Collection for Dynamic Updates
225 Revision 1.31 2004/05/28 23:42:36 ksekar
226 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
228 Revision 1.30 2004/05/26 09:08:04 bradley
229 Added cast to correct structure pointer when allocating domain name list element to fix C++ builds.
231 Revision 1.29 2004/05/18 23:51:25 cheshire
232 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
234 Revision 1.28 2004/05/13 04:54:20 ksekar
235 Unified list copy/free code. Added symetric list for
237 Revision 1.27 2004/04/22 20:29:07 cheshire
238 Log error message if no count field passed to PutResourceRecordTTL()
240 Revision 1.26 2004/04/22 04:07:01 cheshire
241 Fix from Bob Bradley: Don't try to do inline functions on compilers that don't support it
243 Revision 1.25 2004/04/22 03:05:28 cheshire
244 kDNSClass_ANY should be kDNSQClass_ANY
246 Revision 1.24 2004/04/22 02:51:20 cheshire
247 Use common code for HINFO/TXT and TSIG cases in putRData
249 Revision 1.23 2004/04/15 00:51:28 bradley
250 Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers.
251 Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers.
253 Revision 1.22 2004/04/14 23:09:28 ksekar
254 Support for TSIG signed dynamic updates.
256 Revision 1.21 2004/04/09 16:47:28 cheshire
257 <rdar://problem/3617655>: mDNSResponder escape handling inconsistent with BIND
259 Revision 1.20 2004/04/09 16:37:15 cheshire
260 Suggestion from Bob Bradley:
261 Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers
263 Revision 1.19 2004/04/02 19:34:38 cheshire
266 Revision 1.18 2004/03/30 06:45:00 cheshire
267 Compiler warning fixes from Don Woodward at Roku Labs
269 Revision 1.17 2004/03/19 22:25:20 cheshire
270 <rdar://problem/3579561>: Need to limit service types to fourteen characters
271 Won't actually do this for now, but keep the code around just in case
273 Revision 1.16 2004/03/08 02:45:35 cheshire
274 Minor change to make a couple of the log messages a bit shorter
276 Revision 1.15 2004/03/08 02:44:09 cheshire
277 <rdar://problem/3579561>: Need to limit service types to fourteen characters
279 Revision 1.14 2004/02/21 02:06:24 cheshire
280 Can't use anonymous unions -- they're non-standard and don't work on all compilers
282 Revision 1.13 2004/02/06 23:04:18 ksekar
283 Basic Dynamic Update support via mDNS_Register (dissabled via
284 UNICAST_REGISTRATION #define)
286 Revision 1.12 2004/02/03 22:37:10 cheshire
287 Delete unused (commented-out) code
289 Revision 1.11 2004/02/03 22:35:34 cheshire
290 <rdar://problem/3548256>: Should not allow empty string for resolve domain
292 Revision 1.10 2004/02/03 19:47:36 ksekar
293 Added an asynchronous state machine mechanism to uDNS.c, including
294 calls to find the parent zone for a domain name. Changes include code
295 in repository previously dissabled via "#if 0 incomplete". Codepath
296 is currently unused, and will be called to create update records, etc.
298 Revision 1.9 2004/01/27 20:15:22 cheshire
299 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
301 Revision 1.8 2004/01/24 23:24:36 cheshire
302 Expanded out the list of local domains to reduce risk of mistakes in future
304 Revision 1.7 2004/01/24 08:32:30 bradley
305 Mask values with 0xFF before casting to avoid runtime truncation errors on Windows debug builds.
306 Separated octal-escaped sequences preceding decimal digits to avoid errors with some compilers wanting
307 to signal potentially hidden errors about the subsequent digit not being part of the octal sequence.
309 Revision 1.6 2004/01/24 04:59:15 cheshire
310 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
312 Revision 1.5 2004/01/23 23:23:14 ksekar
313 Added TCP support for truncated unicast messages.
315 Revision 1.4 2004/01/22 02:15:33 cheshire
316 <rdar://problem/3536597>: Link-local reverse-mapping domains need to be resolved using link-local multicast
318 Revision 1.3 2004/01/21 21:16:29 cheshire
319 Minor tidy-up: Deleted a bunch of blank lines, trailing spaces, tabs, etc.
321 Revision 1.2 2003/12/13 05:47:48 bradley
322 Made local ptr const to fix error when assigning from const structure. Disable benign conditional
323 expression is constant warning when building with Microsoft compilers.
325 Revision 1.1 2003/12/13 03:05:27 ksekar
326 <rdar://problem/3192548>: DynDNS: Unicast query of service records
330 // Set mDNS_InstantiateInlines to tell mDNSEmbeddedAPI.h to instantiate inline functions, if necessary
331 #define mDNS_InstantiateInlines 1
332 #include "DNSCommon.h"
334 // Disable certain benign warnings with Microsoft compilers
335 #if (defined(_MSC_VER))
336 // Disable "conditional expression is constant" warning for debug macros.
337 // Otherwise, this generates warnings for the perfectly natural construct "while(1)"
338 // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know
339 #pragma warning(disable:4127)
340 // Disable "array is too small to include a terminating null character" warning
341 // -- domain labels have an initial length byte, not a terminating null character
342 #pragma warning(disable:4295)
345 // ***************************************************************************
346 #if COMPILER_LIKES_PRAGMA_MARK
348 #pragma mark - DNameList copy/deallocation routines
351 mDNSexport DNameListElem
*mDNS_CopyDNameList(const DNameListElem
*orig
)
353 DNameListElem
*copy
= mDNSNULL
, *newelem
;
354 const DNameListElem
*ptr
;
356 for (ptr
= orig
; ptr
; ptr
= ptr
->next
)
358 newelem
= (DNameListElem
*)mDNSPlatformMemAllocate(sizeof(DNameListElem
));
359 if (!newelem
) { LogMsg("ERROR: malloc"); return mDNSNULL
; }
360 AssignDomainName(&newelem
->name
, &ptr
->name
);
361 newelem
->next
= copy
;
367 mDNSexport
void mDNS_FreeDNameList(DNameListElem
*list
)
375 mDNSPlatformMemFree(fptr
);
379 // ***************************************************************************
380 #if COMPILER_LIKES_PRAGMA_MARK
382 #pragma mark - General Utility Functions
385 // return true for RFC1918 private addresses
386 mDNSexport mDNSBool
IsPrivateV4Addr(mDNSAddr
*addr
)
390 if (addr
->type
!= mDNSAddrType_IPv4
) return mDNSfalse
;
393 return ((b
[0] == 10) || // 10/8 prefix
394 (b
[0] == 172 && b
[1] > 15 && b
[1] < 32) || // 172.16/12
395 (b
[0] == 192 && b
[1] == 168)); // 192.168/16
398 mDNSexport
const NetworkInterfaceInfo
*GetFirstActiveInterface(const NetworkInterfaceInfo
*intf
)
400 while (intf
&& !intf
->InterfaceActive
) intf
= intf
->next
;
404 mDNSexport mDNSInterfaceID
GetNextActiveInterfaceID(const NetworkInterfaceInfo
*intf
)
406 const NetworkInterfaceInfo
*next
= GetFirstActiveInterface(intf
->next
);
407 if (next
) return(next
->InterfaceID
); else return(mDNSNULL
);
410 mDNSexport mDNSu32
NumCacheRecordsForInterfaceID(const mDNS
*const m
, mDNSInterfaceID id
)
412 mDNSu32 slot
, used
= 0;
415 FORALL_CACHERECORDS(slot
, cg
, rr
)
416 if (rr
->resrec
.InterfaceID
== id
) used
++;
420 mDNSexport
char *DNSTypeName(mDNSu16 rrtype
)
424 case kDNSType_A
: return("Addr");
425 case kDNSType_NS
: return("NS");
426 case kDNSType_CNAME
:return("CNAME");
427 case kDNSType_SOA
: return("SOA");
428 case kDNSType_NULL
: return("NULL");
429 case kDNSType_PTR
: return("PTR");
430 case kDNSType_HINFO
:return("HINFO");
431 case kDNSType_TXT
: return("TXT");
432 case kDNSType_AAAA
: return("AAAA");
433 case kDNSType_SRV
: return("SRV");
434 case kDNSQType_ANY
: return("ANY");
436 static char buffer
[16];
437 mDNS_snprintf(buffer
, sizeof(buffer
), "(%d)", rrtype
);
443 // Note slight bug: this code uses the rdlength from the ResourceRecord object, to display
444 // the rdata from the RDataBody object. Sometimes this could be the wrong length -- but as
445 // long as this routine is only used for debugging messages, it probably isn't a big problem.
446 mDNSexport
char *GetRRDisplayString_rdb(const ResourceRecord
*rr
, RDataBody
*rd
, char *buffer
)
449 mDNSu32 length
= mDNS_snprintf(buffer
, 79, "%4d %##s %s ", rr
->rdlength
, rr
->name
->c
, DNSTypeName(rr
->rrtype
));
452 case kDNSType_A
: mDNS_snprintf(buffer
+length
, 79-length
, "%.4a", &rd
->ipv4
); break;
454 case kDNSType_NS
: // Same as PTR
455 case kDNSType_CNAME
:// Same as PTR
456 case kDNSType_PTR
: mDNS_snprintf(buffer
+length
, 79-length
, "%##s", rd
->name
.c
); break;
458 case kDNSType_HINFO
:// Display this the same as TXT (just show first string)
459 case kDNSType_TXT
: mDNS_snprintf(buffer
+length
, 79-length
, "%#s", rd
->txt
.c
); break;
461 case kDNSType_AAAA
: mDNS_snprintf(buffer
+length
, 79-length
, "%.16a", &rd
->ipv6
); break;
462 case kDNSType_SRV
: mDNS_snprintf(buffer
+length
, 79-length
, "%##s", rd
->srv
.target
.c
); break;
463 default: mDNS_snprintf(buffer
+length
, 79-length
, "RDLen %d: %s", rr
->rdlength
, rd
->data
); break;
465 for (ptr
= buffer
; *ptr
; ptr
++) if (*ptr
< ' ') *ptr
='.';
469 mDNSexport mDNSu32
mDNSRandom(mDNSu32 max
)
471 static mDNSu32 seed
= 0;
477 seed
= mDNSPlatformRandomSeed(); // Pick an initial seed
478 for (i
=0; i
<100; i
++) seed
= seed
* 21 + 1; // And mix it up a bit
480 while (mask
< max
) mask
= (mask
<< 1) | 1;
481 do seed
= seed
* 21 + 1; while ((seed
& mask
) > max
);
482 return (seed
& mask
);
485 mDNSexport mDNSBool
mDNSSameAddress(const mDNSAddr
*ip1
, const mDNSAddr
*ip2
)
487 if (ip1
->type
== ip2
->type
)
491 case mDNSAddrType_None
: return(mDNStrue
); // Empty addresses have no data and are therefore always equal
492 case mDNSAddrType_IPv4
: return(mDNSBool
)(mDNSSameIPv4Address(ip1
->ip
.v4
, ip2
->ip
.v4
));
493 case mDNSAddrType_IPv6
: return(mDNSBool
)(mDNSSameIPv6Address(ip1
->ip
.v6
, ip2
->ip
.v6
));
499 mDNSexport mDNSBool
mDNSAddrIsDNSMulticast(const mDNSAddr
*ip
)
503 case mDNSAddrType_IPv4
: return(mDNSBool
)(ip
->ip
.v4
.NotAnInteger
== AllDNSLinkGroupv4
.NotAnInteger
);
504 case mDNSAddrType_IPv6
: return(mDNSBool
)(ip
->ip
.v6
.l
[0] == AllDNSLinkGroupv6
.l
[0] &&
505 ip
->ip
.v6
.l
[1] == AllDNSLinkGroupv6
.l
[1] &&
506 ip
->ip
.v6
.l
[2] == AllDNSLinkGroupv6
.l
[2] &&
507 ip
->ip
.v6
.l
[3] == AllDNSLinkGroupv6
.l
[3] );
508 default: return(mDNSfalse
);
512 // ***************************************************************************
513 #if COMPILER_LIKES_PRAGMA_MARK
515 #pragma mark - Domain Name Utility Functions
518 mDNSexport mDNSBool
SameDomainLabel(const mDNSu8
*a
, const mDNSu8
*b
)
521 const int len
= *a
++;
523 if (len
> MAX_DOMAIN_LABEL
)
524 { debugf("Malformed label (too long)"); return(mDNSfalse
); }
526 if (len
!= *b
++) return(mDNSfalse
);
527 for (i
=0; i
<len
; i
++)
531 if (mDNSIsUpperCase(ac
)) ac
+= 'a' - 'A';
532 if (mDNSIsUpperCase(bc
)) bc
+= 'a' - 'A';
533 if (ac
!= bc
) return(mDNSfalse
);
538 mDNSexport mDNSBool
SameDomainName(const domainname
*const d1
, const domainname
*const d2
)
540 const mDNSu8
* a
= d1
->c
;
541 const mDNSu8
* b
= d2
->c
;
542 const mDNSu8
*const max
= d1
->c
+ MAX_DOMAIN_NAME
; // Maximum that's valid
546 if (a
+ 1 + *a
>= max
)
547 { debugf("Malformed domain name (more than 255 characters)"); return(mDNSfalse
); }
548 if (!SameDomainLabel(a
, b
)) return(mDNSfalse
);
556 mDNSexport mDNSBool
IsLocalDomain(const domainname
*d
)
558 // Domains that are defined to be resolved via link-local multicast are:
559 // local., 254.169.in-addr.arpa., and 0.8.E.F.ip6.arpa.
560 static const domainname
*n0
= (domainname
*)"\x5" "local";
561 static const domainname
*n1
= (domainname
*)"\x3" "254" "\x3" "169" "\x7" "in-addr" "\x4" "arpa";
562 static const domainname
*n2
= (domainname
*)"\x1" "0" "\x1" "8" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa";
564 const domainname
*d1
, *d2
, *d3
, *d4
, *d5
, *d6
; // Top-level domain, second-level domain, etc.
565 d1
= d2
= d3
= d4
= d5
= d6
= mDNSNULL
;
568 d6
= d5
; d5
= d4
; d4
= d3
; d3
= d2
; d2
= d1
; d1
= d
;
569 d
= (domainname
*)(d
->c
+ 1 + d
->c
[0]);
572 if (d1
&& SameDomainName(d1
, n0
)) return(mDNStrue
);
573 if (d4
&& SameDomainName(d4
, n1
)) return(mDNStrue
);
574 if (d6
&& SameDomainName(d6
, n2
)) return(mDNStrue
);
578 // Returns length of a domain name INCLUDING the byte for the final null label
579 // i.e. for the root label "." it returns one
580 // For the FQDN "com." it returns 5 (length byte, three data bytes, final zero)
581 // Legal results are 1 (just root label) to 255 (MAX_DOMAIN_NAME)
582 // If the given domainname is invalid, result is 256
583 mDNSexport mDNSu16
DomainNameLength(const domainname
*const name
)
585 const mDNSu8
*src
= name
->c
;
588 if (*src
> MAX_DOMAIN_LABEL
) return(MAX_DOMAIN_NAME
+1);
590 if (src
- name
->c
>= MAX_DOMAIN_NAME
) return(MAX_DOMAIN_NAME
+1);
592 return((mDNSu16
)(src
- name
->c
+ 1));
595 // CompressedDomainNameLength returns the length of a domain name INCLUDING the byte
596 // for the final null label i.e. for the root label "." it returns one.
597 // E.g. for the FQDN "foo.com." it returns 9
598 // (length, three data bytes, length, three more data bytes, final zero).
599 // In the case where a parent domain name is provided, and the given name is a child
600 // of that parent, CompressedDomainNameLength returns the length of the prefix portion
601 // of the child name, plus TWO bytes for the compression pointer.
602 // E.g. for the name "foo.com." with parent "com.", it returns 6
603 // (length, three data bytes, two-byte compression pointer).
604 mDNSexport mDNSu16
CompressedDomainNameLength(const domainname
*const name
, const domainname
*parent
)
606 const mDNSu8
*src
= name
->c
;
607 if (parent
&& parent
->c
[0] == 0) parent
= mDNSNULL
;
610 if (*src
> MAX_DOMAIN_LABEL
) return(MAX_DOMAIN_NAME
+1);
611 if (parent
&& SameDomainName((domainname
*)src
, parent
)) return((mDNSu16
)(src
- name
->c
+ 2));
613 if (src
- name
->c
>= MAX_DOMAIN_NAME
) return(MAX_DOMAIN_NAME
+1);
615 return((mDNSu16
)(src
- name
->c
+ 1));
618 // AppendLiteralLabelString appends a single label to an existing (possibly empty) domainname.
619 // The C string contains the label as-is, with no escaping, etc.
620 // Any dots in the name are literal dots, not label separators
621 // If successful, AppendLiteralLabelString returns a pointer to the next unused byte
622 // in the domainname bufer (i.e., the next byte after the terminating zero).
623 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
624 // AppendLiteralLabelString returns mDNSNULL.
625 mDNSexport mDNSu8
*AppendLiteralLabelString(domainname
*const name
, const char *cstr
)
627 mDNSu8
* ptr
= name
->c
+ DomainNameLength(name
) - 1; // Find end of current name
628 const mDNSu8
*const lim1
= name
->c
+ MAX_DOMAIN_NAME
- 1; // Limit of how much we can add (not counting final zero)
629 const mDNSu8
*const lim2
= ptr
+ 1 + MAX_DOMAIN_LABEL
;
630 const mDNSu8
*const lim
= (lim1
< lim2
) ? lim1
: lim2
;
631 mDNSu8
*lengthbyte
= ptr
++; // Record where the length is going to go
633 while (*cstr
&& ptr
< lim
) *ptr
++ = (mDNSu8
)*cstr
++; // Copy the data
634 *lengthbyte
= (mDNSu8
)(ptr
- lengthbyte
- 1); // Fill in the length byte
635 *ptr
++ = 0; // Put the null root label on the end
636 if (*cstr
) return(mDNSNULL
); // Failure: We didn't successfully consume all input
637 else return(ptr
); // Success: return new value of ptr
640 // AppendDNSNameString appends zero or more labels to an existing (possibly empty) domainname.
641 // The C string is in conventional DNS syntax:
642 // Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots.
643 // If successful, AppendDNSNameString returns a pointer to the next unused byte
644 // in the domainname bufer (i.e., the next byte after the terminating zero).
645 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
646 // AppendDNSNameString returns mDNSNULL.
647 mDNSexport mDNSu8
*AppendDNSNameString(domainname
*const name
, const char *cstring
)
649 const char *cstr
= cstring
;
650 mDNSu8
* ptr
= name
->c
+ DomainNameLength(name
) - 1; // Find end of current name
651 const mDNSu8
*const lim
= name
->c
+ MAX_DOMAIN_NAME
- 1; // Limit of how much we can add (not counting final zero)
652 while (*cstr
&& ptr
< lim
) // While more characters, and space to put them...
654 mDNSu8
*lengthbyte
= ptr
++; // Record where the length is going to go
655 if (*cstr
== '.') { LogMsg("AppendDNSNameString: Illegal empty label in name \"%s\"", cstring
); return(mDNSNULL
); }
656 while (*cstr
&& *cstr
!= '.' && ptr
< lim
) // While we have characters in the label...
658 mDNSu8 c
= (mDNSu8
)*cstr
++; // Read the character
659 if (c
== '\\') // If escape character, check next character
661 c
= (mDNSu8
)*cstr
++; // Assume we'll just take the next character
662 if (mdnsIsDigit(cstr
[-1]) && mdnsIsDigit(cstr
[0]) && mdnsIsDigit(cstr
[1]))
663 { // If three decimal digits,
664 int v0
= cstr
[-1] - '0'; // then interpret as three-digit decimal
665 int v1
= cstr
[ 0] - '0';
666 int v2
= cstr
[ 1] - '0';
667 int val
= v0
* 100 + v1
* 10 + v2
;
668 if (val
<= 255) { c
= (mDNSu8
)val
; cstr
+= 2; } // If valid three-digit decimal value, use it
671 *ptr
++ = c
; // Write the character
673 if (*cstr
) cstr
++; // Skip over the trailing dot (if present)
674 if (ptr
- lengthbyte
- 1 > MAX_DOMAIN_LABEL
) // If illegal label, abort
676 *lengthbyte
= (mDNSu8
)(ptr
- lengthbyte
- 1); // Fill in the length byte
679 *ptr
++ = 0; // Put the null root label on the end
680 if (*cstr
) return(mDNSNULL
); // Failure: We didn't successfully consume all input
681 else return(ptr
); // Success: return new value of ptr
684 // AppendDomainLabel appends a single label to a name.
685 // If successful, AppendDomainLabel returns a pointer to the next unused byte
686 // in the domainname bufer (i.e., the next byte after the terminating zero).
687 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
688 // AppendDomainLabel returns mDNSNULL.
689 mDNSexport mDNSu8
*AppendDomainLabel(domainname
*const name
, const domainlabel
*const label
)
692 mDNSu8
*ptr
= name
->c
+ DomainNameLength(name
) - 1;
694 // Check label is legal
695 if (label
->c
[0] > MAX_DOMAIN_LABEL
) return(mDNSNULL
);
697 // Check that ptr + length byte + data bytes + final zero does not exceed our limit
698 if (ptr
+ 1 + label
->c
[0] + 1 > name
->c
+ MAX_DOMAIN_NAME
) return(mDNSNULL
);
700 for (i
=0; i
<=label
->c
[0]; i
++) *ptr
++ = label
->c
[i
]; // Copy the label data
701 *ptr
++ = 0; // Put the null root label on the end
705 mDNSexport mDNSu8
*AppendDomainName(domainname
*const name
, const domainname
*const append
)
707 mDNSu8
* ptr
= name
->c
+ DomainNameLength(name
) - 1; // Find end of current name
708 const mDNSu8
*const lim
= name
->c
+ MAX_DOMAIN_NAME
- 1; // Limit of how much we can add (not counting final zero)
709 const mDNSu8
* src
= append
->c
;
713 if (ptr
+ 1 + src
[0] > lim
) return(mDNSNULL
);
714 for (i
=0; i
<=src
[0]; i
++) *ptr
++ = src
[i
];
715 *ptr
= 0; // Put the null root label on the end
721 // MakeDomainLabelFromLiteralString makes a single domain label from a single literal C string (with no escaping).
722 // If successful, MakeDomainLabelFromLiteralString returns mDNStrue.
723 // If unable to convert the whole string to a legal domain label (i.e. because length is more than 63 bytes) then
724 // MakeDomainLabelFromLiteralString makes a legal domain label from the first 63 bytes of the string and returns mDNSfalse.
725 // In some cases silently truncated oversized names to 63 bytes is acceptable, so the return result may be ignored.
726 // In other cases silent truncation may not be acceptable, so in those cases the calling function needs to check the return result.
727 mDNSexport mDNSBool
MakeDomainLabelFromLiteralString(domainlabel
*const label
, const char *cstr
)
729 mDNSu8
* ptr
= label
->c
+ 1; // Where we're putting it
730 const mDNSu8
*const limit
= label
->c
+ 1 + MAX_DOMAIN_LABEL
; // The maximum we can put
731 while (*cstr
&& ptr
< limit
) *ptr
++ = (mDNSu8
)*cstr
++; // Copy the label
732 label
->c
[0] = (mDNSu8
)(ptr
- label
->c
- 1); // Set the length byte
733 return(*cstr
== 0); // Return mDNStrue if we successfully consumed all input
736 // MakeDomainNameFromDNSNameString makes a native DNS-format domainname from a C string.
737 // The C string is in conventional DNS syntax:
738 // Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots.
739 // If successful, MakeDomainNameFromDNSNameString returns a pointer to the next unused byte
740 // in the domainname bufer (i.e., the next byte after the terminating zero).
741 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
742 // MakeDomainNameFromDNSNameString returns mDNSNULL.
743 mDNSexport mDNSu8
*MakeDomainNameFromDNSNameString(domainname
*const name
, const char *cstr
)
745 name
->c
[0] = 0; // Make an empty domain name
746 return(AppendDNSNameString(name
, cstr
)); // And then add this string to it
749 mDNSexport
char *ConvertDomainLabelToCString_withescape(const domainlabel
*const label
, char *ptr
, char esc
)
751 const mDNSu8
* src
= label
->c
; // Domain label we're reading
752 const mDNSu8 len
= *src
++; // Read length of this (non-null) label
753 const mDNSu8
*const end
= src
+ len
; // Work out where the label ends
754 if (len
> MAX_DOMAIN_LABEL
) return(mDNSNULL
); // If illegal label, abort
755 while (src
< end
) // While we have characters in the label
760 if (c
== '.' || c
== esc
) // If character is a dot or the escape character
761 *ptr
++ = esc
; // Output escape character
762 else if (c
<= ' ') // If non-printing ascii,
763 { // Output decimal escape sequence
765 *ptr
++ = (char) ('0' + (c
/ 100) );
766 *ptr
++ = (char) ('0' + (c
/ 10) % 10);
767 c
= (mDNSu8
)('0' + (c
) % 10);
770 *ptr
++ = (char)c
; // Copy the character
772 *ptr
= 0; // Null-terminate the string
773 return(ptr
); // and return
776 // Note: To guarantee that there will be no possible overrun, cstr must be at least MAX_ESCAPED_DOMAIN_NAME (1005 bytes)
777 mDNSexport
char *ConvertDomainNameToCString_withescape(const domainname
*const name
, char *ptr
, char esc
)
779 const mDNSu8
*src
= name
->c
; // Domain name we're reading
780 const mDNSu8
*const max
= name
->c
+ MAX_DOMAIN_NAME
; // Maximum that's valid
782 if (*src
== 0) *ptr
++ = '.'; // Special case: For root, just write a dot
784 while (*src
) // While more characters in the domain name
786 if (src
+ 1 + *src
>= max
) return(mDNSNULL
);
787 ptr
= ConvertDomainLabelToCString_withescape((const domainlabel
*)src
, ptr
, esc
);
788 if (!ptr
) return(mDNSNULL
);
790 *ptr
++ = '.'; // Write the dot after the label
793 *ptr
++ = 0; // Null-terminate the string
794 return(ptr
); // and return
798 // Host names must start with a letter, end with a letter or digit,
799 // and have as interior characters only letters, digits, and hyphen.
800 // This was subsequently modified in RFC 1123 to allow the first character to be either a letter or a digit
802 mDNSexport
void ConvertUTF8PstringToRFC1034HostLabel(const mDNSu8 UTF8Name
[], domainlabel
*const hostlabel
)
804 const mDNSu8
* src
= &UTF8Name
[1];
805 const mDNSu8
*const end
= &UTF8Name
[1] + UTF8Name
[0];
806 mDNSu8
* ptr
= &hostlabel
->c
[1];
807 const mDNSu8
*const lim
= &hostlabel
->c
[1] + MAX_DOMAIN_LABEL
;
810 // Delete apostrophes from source name
811 if (src
[0] == '\'') { src
++; continue; } // Standard straight single quote
812 if (src
+ 2 < end
&& src
[0] == 0xE2 && src
[1] == 0x80 && src
[2] == 0x99)
813 { src
+= 3; continue; } // Unicode curly apostrophe
816 if (mdnsValidHostChar(*src
, (ptr
> &hostlabel
->c
[1]), (src
< end
-1))) *ptr
++ = *src
;
817 else if (ptr
> &hostlabel
->c
[1] && ptr
[-1] != '-') *ptr
++ = '-';
821 while (ptr
> &hostlabel
->c
[1] && ptr
[-1] == '-') ptr
--; // Truncate trailing '-' marks
822 hostlabel
->c
[0] = (mDNSu8
)(ptr
- &hostlabel
->c
[1]);
825 mDNSexport mDNSu8
*ConstructServiceName(domainname
*const fqdn
,
826 const domainlabel
*name
, const domainname
*type
, const domainname
*const domain
)
829 mDNSu8
*dst
= fqdn
->c
;
831 const char *errormsg
;
833 // In the case where there is no name (and ONLY in that case),
834 // a single-label subtype is allowed as the first label of a three-part "type"
837 const mDNSu8
*s0
= type
->c
;
838 if (s0
[0] && s0
[0] < 0x40) // If legal first label (at least one character, and no more than 63)
840 const mDNSu8
* s1
= s0
+ 1 + s0
[0];
841 if (s1
[0] && s1
[0] < 0x40) // and legal second label (at least one character, and no more than 63)
843 const mDNSu8
*s2
= s1
+ 1 + s1
[0];
844 if (s2
[0] && s2
[0] < 0x40 && s2
[1+s2
[0]] == 0) // and we have three and only three labels
846 static const mDNSu8 SubTypeLabel
[5] = "\x04_sub";
847 src
= s0
; // Copy the first label
849 for (i
=0; i
<= len
; i
++) *dst
++ = *src
++;
850 for (i
=0; i
< (int)sizeof(SubTypeLabel
); i
++) *dst
++ = SubTypeLabel
[i
];
851 type
= (domainname
*)s1
;
853 // Special support for queries done by some third-party network monitoring software
854 // For these queries, we retract the "._sub" we just added between the subtype and the main type
855 if (SameDomainName((domainname
*)s0
, (domainname
*)"\x09_services\x07_dns-sd\x04_udp") ||
856 SameDomainName((domainname
*)s0
, (domainname
*)"\x09_services\x05_mdns\x04_udp"))
857 dst
-= sizeof(SubTypeLabel
);
863 if (name
&& name
->c
[0])
865 src
= name
->c
; // Put the service name into the domain name
867 if (len
>= 0x40) { errormsg
="Service instance name too long"; goto fail
; }
868 for (i
=0; i
<=len
; i
++) *dst
++ = *src
++;
871 name
= (domainlabel
*)""; // Set this up to be non-null, to avoid errors if we have to call LogMsg() below
873 src
= type
->c
; // Put the service type into the domain name
875 if (len
< 2 || len
>= 0x40 || (len
> 15 && !SameDomainName(domain
, (domainname
*)"\x05" "local")))
877 errormsg
="Application protocol name must be underscore plus 1-14 characters. See <http://www.dns-sd.org/ServiceTypes.html>";
880 if (src
[1] != '_') { errormsg
="Application protocol name must begin with underscore"; goto fail
; }
881 for (i
=2; i
<=len
; i
++)
882 if (!mdnsIsLetter(src
[i
]) && !mdnsIsDigit(src
[i
]) && src
[i
] != '-' && src
[i
] != '_')
883 { errormsg
="Application protocol name must contain only letters, digits, and hyphens"; goto fail
; }
884 for (i
=0; i
<=len
; i
++) *dst
++ = *src
++;
887 if (!(len
== 4 && src
[1] == '_' &&
888 (((src
[2] | 0x20) == 'u' && (src
[3] | 0x20) == 'd') || ((src
[2] | 0x20) == 't' && (src
[3] | 0x20) == 'c')) &&
889 (src
[4] | 0x20) == 'p'))
890 { errormsg
="Transport protocol name must be _udp or _tcp"; goto fail
; }
891 for (i
=0; i
<=len
; i
++) *dst
++ = *src
++;
893 if (*src
) { errormsg
="Service type must have only two labels"; goto fail
; }
896 if (!domain
->c
[0]) { errormsg
="Service domain must be non-empty"; goto fail
; }
897 if (SameDomainName(domain
, (domainname
*)"\x05" "local" "\x04" "arpa"))
898 { errormsg
="Illegal domain \"local.arpa.\" Use \"local.\" (or empty string)"; goto fail
; }
899 dst
= AppendDomainName(fqdn
, domain
);
900 if (!dst
) { errormsg
="Service domain too long"; goto fail
; }
904 LogMsg("ConstructServiceName: %s: %#s.%##s%##s", errormsg
, name
->c
, type
->c
, domain
->c
);
908 mDNSexport mDNSBool
DeconstructServiceName(const domainname
*const fqdn
,
909 domainlabel
*const name
, domainname
*const type
, domainname
*const domain
)
912 const mDNSu8
*src
= fqdn
->c
;
913 const mDNSu8
*max
= fqdn
->c
+ MAX_DOMAIN_NAME
;
916 dst
= name
->c
; // Extract the service name from the domain name
918 if (len
>= 0x40) { debugf("DeconstructServiceName: service name too long"); return(mDNSfalse
); }
919 for (i
=0; i
<=len
; i
++) *dst
++ = *src
++;
921 dst
= type
->c
; // Extract the service type from the domain name
923 if (len
>= 0x40) { debugf("DeconstructServiceName: service type too long"); return(mDNSfalse
); }
924 for (i
=0; i
<=len
; i
++) *dst
++ = *src
++;
927 if (len
>= 0x40) { debugf("DeconstructServiceName: service type too long"); return(mDNSfalse
); }
928 for (i
=0; i
<=len
; i
++) *dst
++ = *src
++;
929 *dst
++ = 0; // Put the null root label on the end of the service type
931 dst
= domain
->c
; // Extract the service domain from the domain name
936 { debugf("DeconstructServiceName: service domain label too long"); return(mDNSfalse
); }
937 if (src
+ 1 + len
+ 1 >= max
)
938 { debugf("DeconstructServiceName: service domain too long"); return(mDNSfalse
); }
939 for (i
=0; i
<=len
; i
++) *dst
++ = *src
++;
941 *dst
++ = 0; // Put the null root label on the end
947 // 0xxxxxxx represents a 7-bit ASCII value from 0x00 to 0x7F
948 // 10xxxxxx is a continuation byte of a multi-byte character
949 // 110xxxxx is the first byte of a 2-byte character (11 effective bits; values 0x 80 - 0x 800-1)
950 // 1110xxxx is the first byte of a 3-byte character (16 effective bits; values 0x 800 - 0x 10000-1)
951 // 11110xxx is the first byte of a 4-byte character (21 effective bits; values 0x 10000 - 0x 200000-1)
952 // 111110xx is the first byte of a 5-byte character (26 effective bits; values 0x 200000 - 0x 4000000-1)
953 // 1111110x is the first byte of a 6-byte character (31 effective bits; values 0x4000000 - 0x80000000-1)
955 // UTF-16 surrogate pairs are used in UTF-16 to encode values larger than 0xFFFF.
956 // Although UTF-16 surrogate pairs are not supposed to appear in legal UTF-8, we want to be defensive
957 // about that too. (See <http://www.unicode.org/faq/utf_bom.html#34>, "What are surrogates?")
958 // The first of pair is a UTF-16 value in the range 0xD800-0xDBFF (11101101 1010xxxx 10xxxxxx in UTF-8),
959 // and the second is a UTF-16 value in the range 0xDC00-0xDFFF (11101101 1011xxxx 10xxxxxx in UTF-8).
961 mDNSexport mDNSu32
TruncateUTF8ToLength(mDNSu8
*string
, mDNSu32 length
, mDNSu32 max
)
965 mDNSu8 c1
= string
[max
]; // First byte after cut point
966 mDNSu8 c2
= (max
+1 < length
) ? string
[max
+1] : 0xB0; // Second byte after cut point
967 length
= max
; // Trim length down
970 // Check if the byte right after the chop point is a UTF-8 continuation byte,
971 // or if the character right after the chop point is the second of a UTF-16 surrogate pair.
972 // If so, then we continue to chop more bytes until we get to a legal chop point.
973 mDNSBool continuation
= ((c1
& 0xC0) == 0x80);
974 mDNSBool secondsurrogate
= (c1
== 0xED && (c2
& 0xF0) == 0xB0);
975 if (!continuation
&& !secondsurrogate
) break;
977 c1
= string
[--length
];
979 // Having truncated characters off the end of our string, also cut off any residual white space
980 while (length
> 0 && string
[length
-1] <= ' ') length
--;
985 // Returns true if a rich text label ends in " (nnn)", or if an RFC 1034
986 // name ends in "-nnn", where n is some decimal number.
987 mDNSexport mDNSBool
LabelContainsSuffix(const domainlabel
*const name
, const mDNSBool RichText
)
989 mDNSu16 l
= name
->c
[0];
993 if (l
< 4) return mDNSfalse
; // Need at least " (2)"
994 if (name
->c
[l
--] != ')') return mDNSfalse
; // Last char must be ')'
995 if (!mdnsIsDigit(name
->c
[l
])) return mDNSfalse
; // Preceeded by a digit
997 while (l
> 2 && mdnsIsDigit(name
->c
[l
])) l
--; // Strip off digits
998 return (name
->c
[l
] == '(' && name
->c
[l
- 1] == ' ');
1002 if (l
< 2) return mDNSfalse
; // Need at least "-2"
1003 if (!mdnsIsDigit(name
->c
[l
])) return mDNSfalse
; // Last char must be a digit
1005 while (l
> 2 && mdnsIsDigit(name
->c
[l
])) l
--; // Strip off digits
1006 return (name
->c
[l
] == '-');
1010 // removes an auto-generated suffix (appended on a name collision) from a label. caller is
1011 // responsible for ensuring that the label does indeed contain a suffix. returns the number
1012 // from the suffix that was removed.
1013 mDNSexport mDNSu32
RemoveLabelSuffix(domainlabel
*name
, mDNSBool RichText
)
1015 mDNSu32 val
= 0, multiplier
= 1;
1017 // Chop closing parentheses from RichText suffix
1018 if (RichText
&& name
->c
[0] >= 1 && name
->c
[name
->c
[0]] == ')') name
->c
[0]--;
1020 // Get any existing numerical suffix off the name
1021 while (mdnsIsDigit(name
->c
[name
->c
[0]]))
1022 { val
+= (name
->c
[name
->c
[0]] - '0') * multiplier
; multiplier
*= 10; name
->c
[0]--; }
1024 // Chop opening parentheses or dash from suffix
1027 if (name
->c
[0] >= 2 && name
->c
[name
->c
[0]] == '(' && name
->c
[name
->c
[0]-1] == ' ') name
->c
[0] -= 2;
1031 if (name
->c
[0] >= 1 && name
->c
[name
->c
[0]] == '-') name
->c
[0] -= 1;
1037 // appends a numerical suffix to a label, with the number following a whitespace and enclosed
1038 // in parentheses (rich text) or following two consecutive hyphens (RFC 1034 domain label).
1039 mDNSexport
void AppendLabelSuffix(domainlabel
*name
, mDNSu32 val
, mDNSBool RichText
)
1041 mDNSu32 divisor
= 1, chars
= 2; // Shortest possible RFC1034 name suffix is 2 characters ("-2")
1042 if (RichText
) chars
= 4; // Shortest possible RichText suffix is 4 characters (" (2)")
1044 // Truncate trailing spaces from RichText names
1045 if (RichText
) while (name
->c
[name
->c
[0]] == ' ') name
->c
[0]--;
1047 while (val
>= divisor
* 10) { divisor
*= 10; chars
++; }
1049 name
->c
[0] = (mDNSu8
) TruncateUTF8ToLength(name
->c
+1, name
->c
[0], MAX_DOMAIN_LABEL
- chars
);
1051 if (RichText
) { name
->c
[++name
->c
[0]] = ' '; name
->c
[++name
->c
[0]] = '('; }
1052 else { name
->c
[++name
->c
[0]] = '-'; }
1056 name
->c
[++name
->c
[0]] = (mDNSu8
)('0' + val
/ divisor
);
1061 if (RichText
) name
->c
[++name
->c
[0]] = ')';
1064 mDNSexport
void IncrementLabelSuffix(domainlabel
*name
, mDNSBool RichText
)
1068 if (LabelContainsSuffix(name
, RichText
))
1069 val
= RemoveLabelSuffix(name
, RichText
);
1071 // If no existing suffix, start by renaming "Foo" as "Foo (2)" or "Foo-2" as appropriate.
1072 // If existing suffix in the range 2-9, increment it.
1073 // If we've had ten conflicts already, there are probably too many hosts trying to use the same name,
1074 // so add a random increment to improve the chances of finding an available name next time.
1075 if (val
== 0) val
= 2;
1076 else if (val
< 10) val
++;
1077 else val
+= 1 + mDNSRandom(99);
1079 AppendLabelSuffix(name
, val
, RichText
);
1082 // ***************************************************************************
1083 #if COMPILER_LIKES_PRAGMA_MARK
1085 #pragma mark - Resource Record Utility Functions
1088 mDNSexport mDNSu32
RDataHashValue(mDNSu16
const rdlength
, const RDataBody
*const rdb
)
1092 for (i
=0; i
+1 < rdlength
; i
+=2)
1094 sum
+= (((mDNSu32
)(rdb
->data
[i
])) << 8) | rdb
->data
[i
+1];
1095 sum
= (sum
<<3) | (sum
>>29);
1099 sum
+= ((mDNSu32
)(rdb
->data
[i
])) << 8;
1104 mDNSexport mDNSBool
SameRData(const ResourceRecord
*const r1
, const ResourceRecord
*const r2
)
1106 if (r1
->rrtype
!= r2
->rrtype
) return(mDNSfalse
);
1107 if (r1
->rdlength
!= r2
->rdlength
) return(mDNSfalse
);
1108 if (r1
->rdatahash
!= r2
->rdatahash
) return(mDNSfalse
);
1111 case kDNSType_CNAME
:// Same as PTR
1112 case kDNSType_PTR
: return(SameDomainName(&r1
->rdata
->u
.name
, &r2
->rdata
->u
.name
));
1114 case kDNSType_SRV
: return(mDNSBool
)( r1
->rdata
->u
.srv
.priority
== r2
->rdata
->u
.srv
.priority
&&
1115 r1
->rdata
->u
.srv
.weight
== r2
->rdata
->u
.srv
.weight
&&
1116 r1
->rdata
->u
.srv
.port
.NotAnInteger
== r2
->rdata
->u
.srv
.port
.NotAnInteger
&&
1117 SameDomainName(&r1
->rdata
->u
.srv
.target
, &r2
->rdata
->u
.srv
.target
) );
1119 default: return(mDNSPlatformMemSame(r1
->rdata
->u
.data
, r2
->rdata
->u
.data
, r1
->rdlength
));
1123 mDNSexport mDNSBool
SameResourceRecord(ResourceRecord
*r1
, ResourceRecord
*r2
)
1125 return (r1
->namehash
== r2
->namehash
&&
1126 r1
->rrtype
== r2
->rrtype
&&
1127 SameDomainName(r1
->name
, r2
->name
) &&
1131 mDNSexport mDNSBool
ResourceRecordAnswersQuestion(const ResourceRecord
*const rr
, const DNSQuestion
*const q
)
1133 if (rr
->InterfaceID
&&
1134 q
->InterfaceID
&& q
->InterfaceID
!= mDNSInterface_LocalOnly
&&
1135 rr
->InterfaceID
!= q
->InterfaceID
) return(mDNSfalse
);
1137 // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
1138 if (rr
->rrtype
!= kDNSType_CNAME
&& rr
->rrtype
!= q
->qtype
&& q
->qtype
!= kDNSQType_ANY
) return(mDNSfalse
);
1139 if ( rr
->rrclass
!= q
->qclass
&& q
->qclass
!= kDNSQClass_ANY
) return(mDNSfalse
);
1140 return(rr
->namehash
== q
->qnamehash
&& SameDomainName(rr
->name
, &q
->qname
));
1143 mDNSexport mDNSu16
GetRDLength(const ResourceRecord
*const rr
, mDNSBool estimate
)
1145 const RDataBody
*rd
= &rr
->rdata
->u
;
1146 const domainname
*const name
= estimate
? rr
->name
: mDNSNULL
;
1149 case kDNSType_A
: return(sizeof(rd
->ipv4
));
1150 case kDNSType_CNAME
:// Same as PTR
1151 case kDNSType_NS
: // Same as PTR
1152 case kDNSType_PTR
: return(CompressedDomainNameLength(&rd
->name
, name
));
1153 case kDNSType_HINFO
:return(mDNSu16
)(2 + (int)rd
->data
[0] + (int)rd
->data
[1 + (int)rd
->data
[0]]);
1154 case kDNSType_NULL
: // Same as TXT -- not self-describing, so have to just trust rdlength
1155 case kDNSType_TXT
: return(rr
->rdlength
); // TXT is not self-describing, so have to just trust rdlength
1156 case kDNSType_AAAA
: return(sizeof(rd
->ipv6
));
1157 case kDNSType_SRV
: return(mDNSu16
)(6 + CompressedDomainNameLength(&rd
->srv
.target
, name
));
1158 case kDNSType_SOA
: return (mDNSu16
)(CompressedDomainNameLength(&rd
->soa
.mname
, name
) +
1159 CompressedDomainNameLength(&rd
->soa
.rname
, name
) +
1160 5 * sizeof(mDNSOpaque32
));
1161 case kDNSType_OPT
: return(rr
->rdlength
);
1162 default: debugf("Warning! Don't know how to get length of resource type %d", rr
->rrtype
);
1163 return(rr
->rdlength
);
1167 mDNSexport mDNSBool
ValidateRData(const mDNSu16 rrtype
, const mDNSu16 rdlength
, const RData
*const rd
)
1173 case kDNSType_A
: return(rdlength
== sizeof(mDNSv4Addr
));
1175 case kDNSType_NS
: // Same as PTR
1176 case kDNSType_MD
: // Same as PTR
1177 case kDNSType_MF
: // Same as PTR
1178 case kDNSType_CNAME
:// Same as PTR
1179 //case kDNSType_SOA not checked
1180 case kDNSType_MB
: // Same as PTR
1181 case kDNSType_MG
: // Same as PTR
1182 case kDNSType_MR
: // Same as PTR
1183 //case kDNSType_NULL not checked (no specified format, so always valid)
1184 //case kDNSType_WKS not checked
1185 case kDNSType_PTR
: if (!rdlength
) return(mDNSfalse
);
1186 len
= DomainNameLength(&rd
->u
.name
);
1187 return(len
<= MAX_DOMAIN_NAME
&& rdlength
== len
);
1189 case kDNSType_HINFO
:// Same as TXT (roughly)
1190 case kDNSType_MINFO
:// Same as TXT (roughly)
1191 case kDNSType_TXT
: if (!rdlength
) return(mDNSfalse
); // TXT record has to be at least one byte (RFC 1035)
1193 const mDNSu8
*ptr
= rd
->u
.txt
.c
;
1194 const mDNSu8
*end
= rd
->u
.txt
.c
+ rdlength
;
1195 while (ptr
< end
) ptr
+= 1 + ptr
[0];
1196 return (ptr
== end
);
1199 case kDNSType_AAAA
: return(rdlength
== sizeof(mDNSv6Addr
));
1201 case kDNSType_MX
: if (!rdlength
) return(mDNSfalse
);
1202 len
= DomainNameLength(&rd
->u
.mx
.exchange
);
1203 return(len
<= MAX_DOMAIN_NAME
&& rdlength
== 2+len
);
1205 case kDNSType_SRV
: if (!rdlength
) return(mDNSfalse
);
1206 len
= DomainNameLength(&rd
->u
.srv
.target
);
1207 return(len
<= MAX_DOMAIN_NAME
&& rdlength
== 6+len
);
1209 default: return(mDNStrue
); // Allow all other types without checking
1213 // ***************************************************************************
1214 #if COMPILER_LIKES_PRAGMA_MARK
1217 #pragma mark - DNS Message Creation Functions
1220 mDNSexport
void InitializeDNSMessage(DNSMessageHeader
*h
, mDNSOpaque16 id
, mDNSOpaque16 flags
)
1224 h
->numQuestions
= 0;
1226 h
->numAuthorities
= 0;
1227 h
->numAdditionals
= 0;
1230 mDNSexport
const mDNSu8
*FindCompressionPointer(const mDNSu8
*const base
, const mDNSu8
*const end
, const mDNSu8
*const domname
)
1232 const mDNSu8
*result
= end
- *domname
- 1;
1234 if (*domname
== 0) return(mDNSNULL
); // There's no point trying to match just the root label
1236 // This loop examines each possible starting position in packet, starting end of the packet and working backwards
1237 while (result
>= base
)
1239 // If the length byte and first character of the label match, then check further to see
1240 // if this location in the packet will yield a useful name compression pointer.
1241 if (result
[0] == domname
[0] && result
[1] == domname
[1])
1243 const mDNSu8
*name
= domname
;
1244 const mDNSu8
*targ
= result
;
1245 while (targ
+ *name
< end
)
1247 // First see if this label matches
1249 const mDNSu8
*pointertarget
;
1250 for (i
=0; i
<= *name
; i
++) if (targ
[i
] != name
[i
]) break;
1251 if (i
<= *name
) break; // If label did not match, bail out
1252 targ
+= 1 + *name
; // Else, did match, so advance target pointer
1253 name
+= 1 + *name
; // and proceed to check next label
1254 if (*name
== 0 && *targ
== 0) return(result
); // If no more labels, we found a match!
1255 if (*name
== 0) break; // If no more labels to match, we failed, so bail out
1257 // The label matched, so now follow the pointer (if appropriate) and then see if the next label matches
1258 if (targ
[0] < 0x40) continue; // If length value, continue to check next label
1259 if (targ
[0] < 0xC0) break; // If 40-BF, not valid
1260 if (targ
+1 >= end
) break; // Second byte not present!
1261 pointertarget
= base
+ (((mDNSu16
)(targ
[0] & 0x3F)) << 8) + targ
[1];
1262 if (targ
< pointertarget
) break; // Pointertarget must point *backwards* in the packet
1263 if (pointertarget
[0] >= 0x40) break; // Pointertarget must point to a valid length byte
1264 targ
= pointertarget
;
1267 result
--; // We failed to match at this search position, so back up the tentative result pointer and try again
1272 // Put a string of dot-separated labels as length-prefixed labels
1273 // domainname is a fully-qualified name (i.e. assumed to be ending in a dot, even if it doesn't)
1274 // msg points to the message we're building (pass mDNSNULL if we don't want to use compression pointers)
1275 // end points to the end of the message so far
1276 // ptr points to where we want to put the name
1277 // limit points to one byte past the end of the buffer that we must not overrun
1278 // domainname is the name to put
1279 mDNSexport mDNSu8
*putDomainNameAsLabels(const DNSMessage
*const msg
,
1280 mDNSu8
*ptr
, const mDNSu8
*const limit
, const domainname
*const name
)
1282 const mDNSu8
*const base
= (const mDNSu8
*)msg
;
1283 const mDNSu8
* np
= name
->c
;
1284 const mDNSu8
*const max
= name
->c
+ MAX_DOMAIN_NAME
; // Maximum that's valid
1285 const mDNSu8
* pointer
= mDNSNULL
;
1286 const mDNSu8
*const searchlimit
= ptr
;
1288 while (*np
&& ptr
< limit
-1) // While we've got characters in the name, and space to write them in the message...
1290 if (*np
> MAX_DOMAIN_LABEL
)
1291 { LogMsg("Malformed domain name %##s (label more than 63 bytes)", name
->c
); return(mDNSNULL
); }
1293 // This check correctly allows for the final trailing root label:
1295 // Suppose our domain name is exactly 255 bytes long, including the final trailing root label.
1296 // Suppose np is now at name->c[248], and we're about to write our last non-null label ("local").
1297 // We know that max will be at name->c[255]
1298 // That means that np + 1 + 5 == max - 1, so we (just) pass the "if" test below, write our
1299 // six bytes, then exit the loop, write the final terminating root label, and the domain
1300 // name we've written is exactly 255 bytes long, exactly at the correct legal limit.
1301 // If the name is one byte longer, then we fail the "if" test below, and correctly bail out.
1302 if (np
+ 1 + *np
>= max
)
1303 { LogMsg("Malformed domain name %##s (more than 255 bytes)", name
->c
); return(mDNSNULL
); }
1305 if (base
) pointer
= FindCompressionPointer(base
, searchlimit
, np
);
1306 if (pointer
) // Use a compression pointer if we can
1308 mDNSu16 offset
= (mDNSu16
)(pointer
- base
);
1309 *ptr
++ = (mDNSu8
)(0xC0 | (offset
>> 8));
1310 *ptr
++ = (mDNSu8
)( offset
& 0xFF);
1313 else // Else copy one label and try again
1317 if (ptr
+ 1 + len
>= limit
) return(mDNSNULL
);
1319 for (i
=0; i
<len
; i
++) *ptr
++ = *np
++;
1323 if (ptr
< limit
) // If we didn't run out of space
1325 *ptr
++ = 0; // Put the final root label
1326 return(ptr
); // and return
1332 mDNSlocal mDNSu8
*putVal16(mDNSu8
*ptr
, mDNSu16 val
)
1334 ptr
[0] = (mDNSu8
)((val
>> 8 ) & 0xFF);
1335 ptr
[1] = (mDNSu8
)((val
) & 0xFF);
1336 return ptr
+ sizeof(mDNSOpaque16
);
1339 mDNSlocal mDNSu8
*putVal32(mDNSu8
*ptr
, mDNSu32 val
)
1341 ptr
[0] = (mDNSu8
)((val
>> 24) & 0xFF);
1342 ptr
[1] = (mDNSu8
)((val
>> 16) & 0xFF);
1343 ptr
[2] = (mDNSu8
)((val
>> 8) & 0xFF);
1344 ptr
[3] = (mDNSu8
)((val
) & 0xFF);
1345 return ptr
+ sizeof(mDNSu32
);
1348 mDNSlocal mDNSu8
*putOptRData(mDNSu8
*ptr
, const mDNSu8
*limit
, ResourceRecord
*rr
)
1353 while (nput
< rr
->rdlength
)
1355 // check if space for opt/optlen
1356 if (ptr
+ (2 * sizeof(mDNSu16
)) > limit
) goto space_err
;
1357 opt
= (rdataOpt
*)(rr
->rdata
->u
.data
+ nput
);
1358 ptr
= putVal16(ptr
, opt
->opt
);
1359 ptr
= putVal16(ptr
, opt
->optlen
);
1360 nput
+= 2 * sizeof(mDNSu16
);
1361 if (opt
->opt
== kDNSOpt_LLQ
)
1363 if (ptr
+ LLQ_OPTLEN
> limit
) goto space_err
;
1364 ptr
= putVal16(ptr
, opt
->OptData
.llq
.vers
);
1365 ptr
= putVal16(ptr
, opt
->OptData
.llq
.llqOp
);
1366 ptr
= putVal16(ptr
, opt
->OptData
.llq
.err
);
1367 mDNSPlatformMemCopy(opt
->OptData
.llq
.id
, ptr
, 8); // 8-byte id
1369 ptr
= putVal32(ptr
, opt
->OptData
.llq
.lease
);
1372 else if (opt
->opt
== kDNSOpt_Lease
)
1374 if (ptr
+ sizeof(mDNSs32
) > limit
) goto space_err
;
1375 ptr
= putVal32(ptr
, opt
->OptData
.lease
);
1376 nput
+= sizeof(mDNSs32
);
1378 else { LogMsg("putOptRData - unknown option %d", opt
->opt
); return mDNSNULL
; }
1384 LogMsg("ERROR: putOptRData - out of space");
1388 mDNSlocal mDNSu16
getVal16(const mDNSu8
**ptr
)
1390 mDNSu16 val
= (mDNSu16
)(((mDNSu16
)(*ptr
)[0]) << 8 | (*ptr
)[1]);
1391 *ptr
+= sizeof(mDNSOpaque16
);
1395 mDNSlocal
const mDNSu8
*getOptRdata(const mDNSu8
*ptr
, const mDNSu8
*const limit
, LargeCacheRecord
*const cr
, mDNSu16 pktRDLen
)
1398 ResourceRecord
*const rr
= &cr
->r
.resrec
;
1399 rdataOpt
*opt
= (rdataOpt
*)rr
->rdata
->u
.data
;
1401 while (nread
< pktRDLen
&& (mDNSu8
*)opt
< rr
->rdata
->u
.data
+ MaximumRDSize
- sizeof(rdataOpt
))
1403 // space for opt + optlen
1404 if (nread
+ (2 * sizeof(mDNSu16
)) > rr
->rdata
->MaxRDLength
) goto space_err
;
1405 opt
->opt
= getVal16(&ptr
);
1406 opt
->optlen
= getVal16(&ptr
);
1407 nread
+= 2 * sizeof(mDNSu16
);
1408 if (opt
->opt
== kDNSOpt_LLQ
)
1410 if ((unsigned)(limit
- ptr
) < LLQ_OPTLEN
) goto space_err
;
1411 opt
->OptData
.llq
.vers
= getVal16(&ptr
);
1412 opt
->OptData
.llq
.llqOp
= getVal16(&ptr
);
1413 opt
->OptData
.llq
.err
= getVal16(&ptr
);
1414 mDNSPlatformMemCopy(ptr
, opt
->OptData
.llq
.id
, 8);
1416 opt
->OptData
.llq
.lease
= (mDNSu32
) ((mDNSu32
)ptr
[0] << 24 | (mDNSu32
)ptr
[1] << 16 | (mDNSu32
)ptr
[2] << 8 | ptr
[3]);
1417 if (opt
->OptData
.llq
.lease
> 0x70000000UL
/ mDNSPlatformOneSecond
)
1418 opt
->OptData
.llq
.lease
= 0x70000000UL
/ mDNSPlatformOneSecond
;
1419 ptr
+= sizeof(mDNSOpaque32
);
1420 nread
+= LLQ_OPTLEN
;
1422 else if (opt
->opt
== kDNSOpt_Lease
)
1424 if ((unsigned)(limit
- ptr
) < sizeof(mDNSs32
)) goto space_err
;
1426 opt
->OptData
.lease
= (mDNSu32
) ((mDNSu32
)ptr
[0] << 24 | (mDNSu32
)ptr
[1] << 16 | (mDNSu32
)ptr
[2] << 8 | ptr
[3]);
1427 if (opt
->OptData
.lease
> 0x70000000UL
/ mDNSPlatformOneSecond
)
1428 opt
->OptData
.lease
= 0x70000000UL
/ mDNSPlatformOneSecond
;
1429 ptr
+= sizeof(mDNSs32
);
1430 nread
+= sizeof(mDNSs32
);
1432 else { LogMsg("ERROR: getOptRdata - unknown opt %d", opt
->opt
); return mDNSNULL
; }
1433 opt
++; // increment pointer into rdatabody
1436 rr
->rdlength
= pktRDLen
;
1440 LogMsg("ERROR: getLLQRdata - out of space");
1444 mDNSexport mDNSu8
*putRData(const DNSMessage
*const msg
, mDNSu8
*ptr
, const mDNSu8
*const limit
, ResourceRecord
*rr
)
1448 case kDNSType_A
: if (rr
->rdlength
!= 4)
1450 debugf("putRData: Illegal length %d for kDNSType_A", rr
->rdlength
);
1453 if (ptr
+ 4 > limit
) return(mDNSNULL
);
1454 *ptr
++ = rr
->rdata
->u
.ipv4
.b
[0];
1455 *ptr
++ = rr
->rdata
->u
.ipv4
.b
[1];
1456 *ptr
++ = rr
->rdata
->u
.ipv4
.b
[2];
1457 *ptr
++ = rr
->rdata
->u
.ipv4
.b
[3];
1460 case kDNSType_CNAME
:// Same as PTR
1461 case kDNSType_PTR
: return(putDomainNameAsLabels(msg
, ptr
, limit
, &rr
->rdata
->u
.name
));
1463 case kDNSType_AAAA
: if (rr
->rdlength
!= sizeof(rr
->rdata
->u
.ipv6
))
1465 debugf("putRData: Illegal length %d for kDNSType_AAAA", rr
->rdlength
);
1468 if (ptr
+ sizeof(rr
->rdata
->u
.ipv6
) > limit
) return(mDNSNULL
);
1469 mDNSPlatformMemCopy(&rr
->rdata
->u
.ipv6
, ptr
, sizeof(rr
->rdata
->u
.ipv6
));
1470 return(ptr
+ sizeof(rr
->rdata
->u
.ipv6
));
1472 case kDNSType_SRV
: if (ptr
+ 6 > limit
) return(mDNSNULL
);
1473 *ptr
++ = (mDNSu8
)(rr
->rdata
->u
.srv
.priority
>> 8);
1474 *ptr
++ = (mDNSu8
)(rr
->rdata
->u
.srv
.priority
& 0xFF);
1475 *ptr
++ = (mDNSu8
)(rr
->rdata
->u
.srv
.weight
>> 8);
1476 *ptr
++ = (mDNSu8
)(rr
->rdata
->u
.srv
.weight
& 0xFF);
1477 *ptr
++ = rr
->rdata
->u
.srv
.port
.b
[0];
1478 *ptr
++ = rr
->rdata
->u
.srv
.port
.b
[1];
1479 return(putDomainNameAsLabels(msg
, ptr
, limit
, &rr
->rdata
->u
.srv
.target
));
1480 case kDNSType_OPT
: return putOptRData(ptr
, limit
, rr
);
1482 default: debugf("putRData: Warning! Writing unknown resource type %d as raw data", rr
->rrtype
);
1483 // Fall through to common code below
1484 case kDNSType_HINFO
:
1486 case kDNSType_TSIG
: if (ptr
+ rr
->rdlength
> limit
) return(mDNSNULL
);
1487 mDNSPlatformMemCopy(rr
->rdata
->u
.data
, ptr
, rr
->rdlength
);
1488 return(ptr
+ rr
->rdlength
);
1492 mDNSexport mDNSu8
*PutResourceRecordTTLWithLimit(DNSMessage
*const msg
, mDNSu8
*ptr
, mDNSu16
*count
, ResourceRecord
*rr
, mDNSu32 ttl
, const mDNSu8
*limit
)
1495 mDNSu16 actualLength
;
1497 if (rr
->RecordType
== kDNSRecordTypeUnregistered
)
1499 LogMsg("PutResourceRecord ERROR! Attempt to put kDNSRecordTypeUnregistered %##s (%s)", rr
->name
->c
, DNSTypeName(rr
->rrtype
));
1503 ptr
= putDomainNameAsLabels(msg
, ptr
, limit
, rr
->name
);
1504 if (!ptr
|| ptr
+ 10 >= limit
) return(mDNSNULL
); // If we're out-of-space, return mDNSNULL
1505 ptr
[0] = (mDNSu8
)(rr
->rrtype
>> 8);
1506 ptr
[1] = (mDNSu8
)(rr
->rrtype
& 0xFF);
1507 ptr
[2] = (mDNSu8
)(rr
->rrclass
>> 8);
1508 ptr
[3] = (mDNSu8
)(rr
->rrclass
& 0xFF);
1509 ptr
[4] = (mDNSu8
)((ttl
>> 24) & 0xFF);
1510 ptr
[5] = (mDNSu8
)((ttl
>> 16) & 0xFF);
1511 ptr
[6] = (mDNSu8
)((ttl
>> 8) & 0xFF);
1512 ptr
[7] = (mDNSu8
)( ttl
& 0xFF);
1513 endofrdata
= putRData(msg
, ptr
+10, limit
, rr
);
1514 if (!endofrdata
) { verbosedebugf("Ran out of space in PutResourceRecord for %##s (%s)", rr
->name
->c
, DNSTypeName(rr
->rrtype
)); return(mDNSNULL
); }
1516 // Go back and fill in the actual number of data bytes we wrote
1517 // (actualLength can be less than rdlength when domain name compression is used)
1518 actualLength
= (mDNSu16
)(endofrdata
- ptr
- 10);
1519 ptr
[8] = (mDNSu8
)(actualLength
>> 8);
1520 ptr
[9] = (mDNSu8
)(actualLength
& 0xFF);
1522 if (count
) (*count
)++;
1523 else LogMsg("PutResourceRecordTTL: ERROR: No target count to update for %##s (%s)", rr
->name
->c
, DNSTypeName(rr
->rrtype
));
1527 mDNSexport mDNSu8
*PutResourceRecordCappedTTL(DNSMessage
*const msg
, mDNSu8
*ptr
, mDNSu16
*count
, ResourceRecord
*rr
, mDNSu32
1530 if (maxttl
> rr
->rroriginalttl
) maxttl
= rr
->rroriginalttl
;
1531 return(PutResourceRecordTTL(msg
, ptr
, count
, rr
, maxttl
));
1534 mDNSexport mDNSu8
*putEmptyResourceRecord(DNSMessage
*const msg
, mDNSu8
*ptr
, const mDNSu8
*const limit
,
1535 mDNSu16
*count
, const AuthRecord
*rr
)
1537 ptr
= putDomainNameAsLabels(msg
, ptr
, limit
, rr
->resrec
.name
);
1538 if (!ptr
|| ptr
+ 10 > limit
) return(mDNSNULL
); // If we're out-of-space, return mDNSNULL
1539 ptr
[0] = (mDNSu8
)(rr
->resrec
.rrtype
>> 8); // Put type
1540 ptr
[1] = (mDNSu8
)(rr
->resrec
.rrtype
& 0xFF);
1541 ptr
[2] = (mDNSu8
)(rr
->resrec
.rrclass
>> 8); // Put class
1542 ptr
[3] = (mDNSu8
)(rr
->resrec
.rrclass
& 0xFF);
1543 ptr
[4] = ptr
[5] = ptr
[6] = ptr
[7] = 0; // TTL is zero
1544 ptr
[8] = ptr
[9] = 0; // RDATA length is zero
1549 mDNSexport mDNSu8
*putQuestion(DNSMessage
*const msg
, mDNSu8
*ptr
, const mDNSu8
*const limit
, const domainname
*const name
, mDNSu16 rrtype
, mDNSu16 rrclass
)
1551 ptr
= putDomainNameAsLabels(msg
, ptr
, limit
, name
);
1552 if (!ptr
|| ptr
+4 >= limit
) return(mDNSNULL
); // If we're out-of-space, return mDNSNULL
1553 ptr
[0] = (mDNSu8
)(rrtype
>> 8);
1554 ptr
[1] = (mDNSu8
)(rrtype
& 0xFF);
1555 ptr
[2] = (mDNSu8
)(rrclass
>> 8);
1556 ptr
[3] = (mDNSu8
)(rrclass
& 0xFF);
1557 msg
->h
.numQuestions
++;
1561 // for dynamic updates
1562 mDNSexport mDNSu8
*putZone(DNSMessage
*const msg
, mDNSu8
*ptr
, mDNSu8
*limit
, const domainname
*zone
, mDNSOpaque16 zoneClass
)
1564 ptr
= putDomainNameAsLabels(msg
, ptr
, limit
, zone
);
1565 if (!ptr
|| ptr
+ 4 > limit
) return mDNSNULL
; // If we're out-of-space, return NULL
1566 *ptr
++ = (mDNSu8
)(kDNSType_SOA
>> 8);
1567 *ptr
++ = (mDNSu8
)(kDNSType_SOA
& 0xFF);
1568 *ptr
++ = zoneClass
.b
[0];
1569 *ptr
++ = zoneClass
.b
[1];
1570 msg
->h
.mDNS_numZones
++;
1574 // for dynamic updates
1575 mDNSexport mDNSu8
*putPrereqNameNotInUse(domainname
*name
, DNSMessage
*msg
, mDNSu8
*ptr
, mDNSu8
*end
)
1579 mDNSPlatformMemZero(&prereq
, sizeof(AuthRecord
));
1580 mDNS_SetupResourceRecord(&prereq
, mDNSNULL
, mDNSInterface_Any
, kDNSQType_ANY
, kStandardTTL
, 0, mDNSNULL
, mDNSNULL
);
1581 AssignDomainName(prereq
.resrec
.name
, name
);
1582 prereq
.resrec
.rrtype
= kDNSQType_ANY
;
1583 prereq
.resrec
.rrclass
= kDNSClass_NONE
;
1584 ptr
= putEmptyResourceRecord(msg
, ptr
, end
, &msg
->h
.mDNS_numPrereqs
, &prereq
);
1588 // for dynamic updates
1589 mDNSexport mDNSu8
*putDeletionRecord(DNSMessage
*msg
, mDNSu8
*ptr
, ResourceRecord
*rr
)
1592 // deletion: specify record w/ TTL 0, class NONE
1594 origclass
= rr
->rrclass
;
1595 rr
->rrclass
= kDNSClass_NONE
;
1596 ptr
= PutResourceRecordTTLJumbo(msg
, ptr
, &msg
->h
.mDNS_numUpdates
, rr
, 0);
1597 rr
->rrclass
= origclass
;
1601 mDNSexport mDNSu8
*putDeleteRRSet(DNSMessage
*msg
, mDNSu8
*ptr
, const domainname
*name
, mDNSu16 rrtype
)
1603 const mDNSu8
*limit
= msg
->data
+ AbsoluteMaxDNSMessageData
;
1604 mDNSu16
class = kDNSQClass_ANY
;
1606 ptr
= putDomainNameAsLabels(msg
, ptr
, limit
, name
);
1607 if (!ptr
|| ptr
+ 10 >= limit
) return mDNSNULL
; // If we're out-of-space, return mDNSNULL
1608 ptr
[0] = (mDNSu8
)(rrtype
>> 8);
1609 ptr
[1] = (mDNSu8
)(rrtype
& 0xFF);
1610 ptr
[2] = (mDNSu8
)(class >> 8);
1611 ptr
[3] = (mDNSu8
)(class & 0xFF);
1612 ptr
[4] = ptr
[5] = ptr
[6] = ptr
[7] = 0; // zero ttl
1613 ptr
[8] = ptr
[9] = 0; // zero rdlength/rdata
1615 msg
->h
.mDNS_numUpdates
++;
1619 // for dynamic updates
1620 mDNSexport mDNSu8
*putDeleteAllRRSets(DNSMessage
*msg
, mDNSu8
*ptr
, const domainname
*name
)
1622 const mDNSu8
*limit
= msg
->data
+ AbsoluteMaxDNSMessageData
;
1623 mDNSu16
class = kDNSQClass_ANY
;
1624 mDNSu16 rrtype
= kDNSQType_ANY
;
1626 ptr
= putDomainNameAsLabels(msg
, ptr
, limit
, name
);
1627 if (!ptr
|| ptr
+ 10 >= limit
) return mDNSNULL
; // If we're out-of-space, return mDNSNULL
1628 ptr
[0] = (mDNSu8
)(rrtype
>> 8);
1629 ptr
[1] = (mDNSu8
)(rrtype
& 0xFF);
1630 ptr
[2] = (mDNSu8
)(class >> 8);
1631 ptr
[3] = (mDNSu8
)(class & 0xFF);
1632 ptr
[4] = ptr
[5] = ptr
[6] = ptr
[7] = 0; // zero ttl
1633 ptr
[8] = ptr
[9] = 0; // zero rdlength/rdata
1635 msg
->h
.mDNS_numUpdates
++;
1639 // for dynamic updates
1640 mDNSexport mDNSu8
*putUpdateLease(DNSMessage
*msg
, mDNSu8
*end
, mDNSu32 lease
)
1643 ResourceRecord
*opt
= &rr
.resrec
;
1646 mDNSPlatformMemZero(&rr
, sizeof(AuthRecord
));
1647 mDNS_SetupResourceRecord(&rr
, mDNSNULL
, mDNSInterface_Any
, kDNSType_OPT
, kStandardTTL
, 0, mDNSNULL
, mDNSNULL
);
1649 opt
->RecordType
= kDNSRecordTypeKnownUnique
; // to avoid warnings in other layers
1650 opt
->rrtype
= kDNSType_OPT
;
1651 opt
->rdlength
= LEASE_OPT_RDLEN
;
1652 opt
->rdestimate
= LEASE_OPT_RDLEN
;
1654 optRD
= &rr
.resrec
.rdata
->u
.opt
;
1655 optRD
->opt
= kDNSOpt_Lease
;
1656 optRD
->optlen
= sizeof(mDNSs32
);
1657 optRD
->OptData
.lease
= lease
;
1658 end
= PutResourceRecordTTLJumbo(msg
, end
, &msg
->h
.numAdditionals
, opt
, 0);
1659 if (!end
) { LogMsg("ERROR: putUpdateLease - PutResourceRecordTTL"); return mDNSNULL
; }
1664 // ***************************************************************************
1665 #if COMPILER_LIKES_PRAGMA_MARK
1667 #pragma mark - DNS Message Parsing Functions
1670 mDNSexport mDNSu32
DomainNameHashValue(const domainname
*const name
)
1675 for (c
= name
->c
; c
[0] != 0 && c
[1] != 0; c
+= 2)
1677 sum
+= ((mDNSIsUpperCase(c
[0]) ? c
[0] + 'a' - 'A' : c
[0]) << 8) |
1678 (mDNSIsUpperCase(c
[1]) ? c
[1] + 'a' - 'A' : c
[1]);
1679 sum
= (sum
<<3) | (sum
>>29);
1681 if (c
[0]) sum
+= ((mDNSIsUpperCase(c
[0]) ? c
[0] + 'a' - 'A' : c
[0]) << 8);
1685 mDNSexport
void SetNewRData(ResourceRecord
*const rr
, RData
*NewRData
, mDNSu16 rdlength
)
1690 rr
->rdata
= NewRData
;
1691 rr
->rdlength
= rdlength
;
1693 // Must not try to get target pointer until after updating rr->rdata
1694 target
= GetRRDomainNameTarget(rr
);
1695 rr
->rdlength
= GetRDLength(rr
, mDNSfalse
);
1696 rr
->rdestimate
= GetRDLength(rr
, mDNStrue
);
1697 rr
->rdatahash
= target
? DomainNameHashValue(target
) : RDataHashValue(rr
->rdlength
, &rr
->rdata
->u
);
1700 mDNSexport
const mDNSu8
*skipDomainName(const DNSMessage
*const msg
, const mDNSu8
*ptr
, const mDNSu8
*const end
)
1704 if (ptr
< (mDNSu8
*)msg
|| ptr
>= end
)
1705 { debugf("skipDomainName: Illegal ptr not within packet boundaries"); return(mDNSNULL
); }
1707 while (1) // Read sequence of labels
1709 const mDNSu8 len
= *ptr
++; // Read length of this label
1710 if (len
== 0) return(ptr
); // If length is zero, that means this name is complete
1713 case 0x00: if (ptr
+ len
>= end
) // Remember: expect at least one more byte for the root label
1714 { debugf("skipDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL
); }
1715 if (total
+ 1 + len
>= MAX_DOMAIN_NAME
) // Remember: expect at least one more byte for the root label
1716 { debugf("skipDomainName: Malformed domain name (more than 255 characters)"); return(mDNSNULL
); }
1721 case 0x40: debugf("skipDomainName: Extended EDNS0 label types 0x%X not supported", len
); return(mDNSNULL
);
1722 case 0x80: debugf("skipDomainName: Illegal label length 0x%X", len
); return(mDNSNULL
);
1723 case 0xC0: return(ptr
+1);
1728 // Routine to fetch an FQDN from the DNS message, following compression pointers if necessary.
1729 mDNSexport
const mDNSu8
*getDomainName(const DNSMessage
*const msg
, const mDNSu8
*ptr
, const mDNSu8
*const end
,
1730 domainname
*const name
)
1732 const mDNSu8
*nextbyte
= mDNSNULL
; // Record where we got to before we started following pointers
1733 mDNSu8
*np
= name
->c
; // Name pointer
1734 const mDNSu8
*const limit
= np
+ MAX_DOMAIN_NAME
; // Limit so we don't overrun buffer
1736 if (ptr
< (mDNSu8
*)msg
|| ptr
>= end
)
1737 { debugf("getDomainName: Illegal ptr not within packet boundaries"); return(mDNSNULL
); }
1739 *np
= 0; // Tentatively place the root label here (may be overwritten if we have more labels)
1741 while (1) // Read sequence of labels
1743 const mDNSu8 len
= *ptr
++; // Read length of this label
1744 if (len
== 0) break; // If length is zero, that means this name is complete
1750 case 0x00: if (ptr
+ len
>= end
) // Remember: expect at least one more byte for the root label
1751 { debugf("getDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL
); }
1752 if (np
+ 1 + len
>= limit
) // Remember: expect at least one more byte for the root label
1753 { debugf("getDomainName: Malformed domain name (more than 255 characters)"); return(mDNSNULL
); }
1755 for (i
=0; i
<len
; i
++) *np
++ = *ptr
++;
1756 *np
= 0; // Tentatively place the root label here (may be overwritten if we have more labels)
1759 case 0x40: debugf("getDomainName: Extended EDNS0 label types 0x%X not supported in name %##s", len
, name
->c
);
1762 case 0x80: debugf("getDomainName: Illegal label length 0x%X in domain name %##s", len
, name
->c
); return(mDNSNULL
);
1764 case 0xC0: offset
= (mDNSu16
)((((mDNSu16
)(len
& 0x3F)) << 8) | *ptr
++);
1765 if (!nextbyte
) nextbyte
= ptr
; // Record where we got to before we started following pointers
1766 ptr
= (mDNSu8
*)msg
+ offset
;
1767 if (ptr
< (mDNSu8
*)msg
|| ptr
>= end
)
1768 { debugf("getDomainName: Illegal compression pointer not within packet boundaries"); return(mDNSNULL
); }
1770 { debugf("getDomainName: Compression pointer must point to real label"); return(mDNSNULL
); }
1775 if (nextbyte
) return(nextbyte
);
1779 mDNSexport
const mDNSu8
*skipResourceRecord(const DNSMessage
*msg
, const mDNSu8
*ptr
, const mDNSu8
*end
)
1781 mDNSu16 pktrdlength
;
1783 ptr
= skipDomainName(msg
, ptr
, end
);
1784 if (!ptr
) { debugf("skipResourceRecord: Malformed RR name"); return(mDNSNULL
); }
1786 if (ptr
+ 10 > end
) { debugf("skipResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL
); }
1787 pktrdlength
= (mDNSu16
)((mDNSu16
)ptr
[8] << 8 | ptr
[9]);
1789 if (ptr
+ pktrdlength
> end
) { debugf("skipResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL
); }
1791 return(ptr
+ pktrdlength
);
1794 mDNSexport
const mDNSu8
*GetLargeResourceRecord(mDNS
*const m
, const DNSMessage
* const msg
, const mDNSu8
*ptr
,
1795 const mDNSu8
*end
, const mDNSInterfaceID InterfaceID
, mDNSu8 RecordType
, LargeCacheRecord
*largecr
)
1797 CacheRecord
*rr
= &largecr
->r
;
1798 mDNSu16 pktrdlength
;
1800 if (largecr
== &m
->rec
&& rr
->resrec
.RecordType
)
1801 LogMsg("GetLargeResourceRecord: m->rec appears to be already in use");
1803 rr
->next
= mDNSNULL
;
1804 rr
->resrec
.RecordType
= RecordType
;
1805 rr
->resrec
.name
= &largecr
->namestorage
;
1807 rr
->NextInKAList
= mDNSNULL
;
1808 rr
->TimeRcvd
= m
? m
->timenow
: 0;
1809 rr
->DelayDelivery
= 0;
1810 rr
->NextRequiredQuery
= m
? m
->timenow
: 0; // Will be updated to the real value when we call SetNextCacheCheckTime()
1811 rr
->LastUsed
= m
? m
->timenow
: 0;
1812 rr
->CRActiveQuestion
= mDNSNULL
;
1813 rr
->UnansweredQueries
= 0;
1814 rr
->LastUnansweredTime
= 0;
1815 rr
->MPUnansweredQ
= 0;
1816 rr
->MPLastUnansweredQT
= 0;
1817 rr
->MPUnansweredKA
= 0;
1818 rr
->MPExpectingKA
= mDNSfalse
;
1819 rr
->NextInCFList
= mDNSNULL
;
1821 rr
->resrec
.InterfaceID
= InterfaceID
;
1822 ptr
= getDomainName(msg
, ptr
, end
, rr
->resrec
.name
);
1823 if (!ptr
) { debugf("GetResourceRecord: Malformed RR name"); return(mDNSNULL
); }
1825 if (ptr
+ 10 > end
) { debugf("GetResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL
); }
1827 rr
->resrec
.rrtype
= (mDNSu16
) ((mDNSu16
)ptr
[0] << 8 | ptr
[1]);
1828 rr
->resrec
.rrclass
= (mDNSu16
)(((mDNSu16
)ptr
[2] << 8 | ptr
[3]) & kDNSClass_Mask
);
1829 rr
->resrec
.rroriginalttl
= (mDNSu32
) ((mDNSu32
)ptr
[4] << 24 | (mDNSu32
)ptr
[5] << 16 | (mDNSu32
)ptr
[6] << 8 | ptr
[7]);
1830 if (rr
->resrec
.rroriginalttl
> 0x70000000UL
/ mDNSPlatformOneSecond
&& (mDNSs32
)rr
->resrec
.rroriginalttl
!= -1)
1831 rr
->resrec
.rroriginalttl
= 0x70000000UL
/ mDNSPlatformOneSecond
;
1832 // Note: We don't have to adjust m->NextCacheCheck here -- this is just getting a record into memory for
1833 // us to look at. If we decide to copy it into the cache, then we'll update m->NextCacheCheck accordingly.
1834 pktrdlength
= (mDNSu16
)((mDNSu16
)ptr
[8] << 8 | ptr
[9]);
1835 if (ptr
[2] & (kDNSClass_UniqueRRSet
>> 8))
1836 rr
->resrec
.RecordType
|= kDNSRecordTypePacketUniqueMask
;
1838 if (ptr
+ pktrdlength
> end
) { debugf("GetResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL
); }
1839 end
= ptr
+ pktrdlength
; // Adjust end to indicate the end of the rdata for this resource record
1841 rr
->resrec
.rdata
= (RData
*)&rr
->rdatastorage
;
1842 rr
->resrec
.rdata
->MaxRDLength
= MaximumRDSize
;
1844 if (!RecordType
) LogMsg("GetLargeResourceRecord: No RecordType for %##s", rr
->resrec
.name
->c
);
1846 switch (rr
->resrec
.rrtype
)
1848 case kDNSType_A
: rr
->resrec
.rdata
->u
.ipv4
.b
[0] = ptr
[0];
1849 rr
->resrec
.rdata
->u
.ipv4
.b
[1] = ptr
[1];
1850 rr
->resrec
.rdata
->u
.ipv4
.b
[2] = ptr
[2];
1851 rr
->resrec
.rdata
->u
.ipv4
.b
[3] = ptr
[3];
1854 case kDNSType_CNAME
:// Same as PTR
1856 case kDNSType_PTR
: if (!getDomainName(msg
, ptr
, end
, &rr
->resrec
.rdata
->u
.name
))
1857 { debugf("GetResourceRecord: Malformed CNAME/PTR RDATA name"); return(mDNSNULL
); }
1858 //debugf("%##s PTR %##s rdlen %d", rr->resrec.name.c, rr->resrec.rdata->u.name.c, pktrdlength);
1861 case kDNSType_NULL
: //Same as TXT
1862 case kDNSType_HINFO
://Same as TXT
1863 case kDNSType_TXT
: if (pktrdlength
> rr
->resrec
.rdata
->MaxRDLength
)
1865 debugf("GetResourceRecord: %s rdata size (%d) exceeds storage (%d)",
1866 DNSTypeName(rr
->resrec
.rrtype
), pktrdlength
, rr
->resrec
.rdata
->MaxRDLength
);
1869 rr
->resrec
.rdlength
= pktrdlength
;
1870 mDNSPlatformMemCopy(ptr
, rr
->resrec
.rdata
->u
.data
, pktrdlength
);
1873 case kDNSType_AAAA
: mDNSPlatformMemCopy(ptr
, &rr
->resrec
.rdata
->u
.ipv6
, sizeof(rr
->resrec
.rdata
->u
.ipv6
));
1876 case kDNSType_SRV
: rr
->resrec
.rdata
->u
.srv
.priority
= (mDNSu16
)((mDNSu16
)ptr
[0] << 8 | ptr
[1]);
1877 rr
->resrec
.rdata
->u
.srv
.weight
= (mDNSu16
)((mDNSu16
)ptr
[2] << 8 | ptr
[3]);
1878 rr
->resrec
.rdata
->u
.srv
.port
.b
[0] = ptr
[4];
1879 rr
->resrec
.rdata
->u
.srv
.port
.b
[1] = ptr
[5];
1880 if (!getDomainName(msg
, ptr
+6, end
, &rr
->resrec
.rdata
->u
.srv
.target
))
1881 { debugf("GetResourceRecord: Malformed SRV RDATA name"); return(mDNSNULL
); }
1882 //debugf("%##s SRV %##s rdlen %d", rr->resrec.name.c, rr->resrec.rdata->u.srv.target.c, pktrdlength);
1885 case kDNSType_SOA
: ptr
= getDomainName(msg
, ptr
, end
, &rr
->resrec
.rdata
->u
.soa
.mname
);
1886 if (!ptr
) { debugf("GetResourceRecord: Malformed SOA RDATA mname"); return mDNSNULL
; }
1887 ptr
= getDomainName(msg
, ptr
, end
, &rr
->resrec
.rdata
->u
.soa
.rname
);
1888 if (!ptr
) { debugf("GetResourceRecord: Malformed SOA RDATA rname"); return mDNSNULL
; }
1889 if (ptr
+ 0x14 != end
) { debugf("GetResourceRecord: Malformed SOA RDATA"); return mDNSNULL
; }
1890 rr
->resrec
.rdata
->u
.soa
.serial
= (mDNSs32
) ((mDNSs32
)ptr
[0x00] << 24 | (mDNSs32
)ptr
[0x01] << 16 | (mDNSs32
)ptr
[0x02] << 8 | ptr
[0x03]);
1891 rr
->resrec
.rdata
->u
.soa
.refresh
= (mDNSu32
) ((mDNSu32
)ptr
[0x04] << 24 | (mDNSu32
)ptr
[0x05] << 16 | (mDNSu32
)ptr
[0x06] << 8 | ptr
[0x07]);
1892 rr
->resrec
.rdata
->u
.soa
.retry
= (mDNSu32
) ((mDNSu32
)ptr
[0x08] << 24 | (mDNSu32
)ptr
[0x09] << 16 | (mDNSu32
)ptr
[0x0A] << 8 | ptr
[0x0B]);
1893 rr
->resrec
.rdata
->u
.soa
.expire
= (mDNSu32
) ((mDNSu32
)ptr
[0x0C] << 24 | (mDNSu32
)ptr
[0x0D] << 16 | (mDNSu32
)ptr
[0x0E] << 8 | ptr
[0x0F]);
1894 rr
->resrec
.rdata
->u
.soa
.min
= (mDNSu32
) ((mDNSu32
)ptr
[0x10] << 24 | (mDNSu32
)ptr
[0x11] << 16 | (mDNSu32
)ptr
[0x12] << 8 | ptr
[0x13]);
1897 case kDNSType_OPT
: getOptRdata(ptr
, end
, largecr
, pktrdlength
); break;
1899 default: if (pktrdlength
> rr
->resrec
.rdata
->MaxRDLength
)
1901 debugf("GetResourceRecord: rdata %d (%s) size (%d) exceeds storage (%d)",
1902 rr
->resrec
.rrtype
, DNSTypeName(rr
->resrec
.rrtype
), pktrdlength
, rr
->resrec
.rdata
->MaxRDLength
);
1905 debugf("GetResourceRecord: Warning! Reading resource type %d (%s) as opaque data",
1906 rr
->resrec
.rrtype
, DNSTypeName(rr
->resrec
.rrtype
));
1907 // Note: Just because we don't understand the record type, that doesn't
1908 // mean we fail. The DNS protocol specifies rdlength, so we can
1909 // safely skip over unknown records and ignore them.
1910 // We also grab a binary copy of the rdata anyway, since the caller
1911 // might know how to interpret it even if we don't.
1912 rr
->resrec
.rdlength
= pktrdlength
;
1913 mDNSPlatformMemCopy(ptr
, rr
->resrec
.rdata
->u
.data
, pktrdlength
);
1917 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
1918 SetNewRData(&rr
->resrec
, mDNSNULL
, 0);
1920 return(ptr
+ pktrdlength
);
1923 mDNSexport
const mDNSu8
*skipQuestion(const DNSMessage
*msg
, const mDNSu8
*ptr
, const mDNSu8
*end
)
1925 ptr
= skipDomainName(msg
, ptr
, end
);
1926 if (!ptr
) { debugf("skipQuestion: Malformed domain name in DNS question section"); return(mDNSNULL
); }
1927 if (ptr
+4 > end
) { debugf("skipQuestion: Malformed DNS question section -- no query type and class!"); return(mDNSNULL
); }
1931 mDNSexport
const mDNSu8
*getQuestion(const DNSMessage
*msg
, const mDNSu8
*ptr
, const mDNSu8
*end
, const mDNSInterfaceID InterfaceID
,
1932 DNSQuestion
*question
)
1934 question
->InterfaceID
= InterfaceID
;
1935 ptr
= getDomainName(msg
, ptr
, end
, &question
->qname
);
1936 if (!ptr
) { debugf("Malformed domain name in DNS question section"); return(mDNSNULL
); }
1937 if (ptr
+4 > end
) { debugf("Malformed DNS question section -- no query type and class!"); return(mDNSNULL
); }
1939 question
->qnamehash
= DomainNameHashValue(&question
->qname
);
1940 question
->qtype
= (mDNSu16
)((mDNSu16
)ptr
[0] << 8 | ptr
[1]); // Get type
1941 question
->qclass
= (mDNSu16
)((mDNSu16
)ptr
[2] << 8 | ptr
[3]); // and class
1945 mDNSexport
const mDNSu8
*LocateAnswers(const DNSMessage
*const msg
, const mDNSu8
*const end
)
1948 const mDNSu8
*ptr
= msg
->data
;
1949 for (i
= 0; i
< msg
->h
.numQuestions
&& ptr
; i
++) ptr
= skipQuestion(msg
, ptr
, end
);
1953 mDNSexport
const mDNSu8
*LocateAuthorities(const DNSMessage
*const msg
, const mDNSu8
*const end
)
1956 const mDNSu8
*ptr
= LocateAnswers(msg
, end
);
1957 for (i
= 0; i
< msg
->h
.numAnswers
&& ptr
; i
++) ptr
= skipResourceRecord(msg
, ptr
, end
);
1961 mDNSexport
const mDNSu8
*LocateAdditionals(const DNSMessage
*const msg
, const mDNSu8
*const end
)
1964 const mDNSu8
*ptr
= LocateAuthorities(msg
, end
);
1965 for (i
= 0; i
< msg
->h
.numAuthorities
; i
++) ptr
= skipResourceRecord(msg
, ptr
, end
);
1969 // ***************************************************************************
1970 #if COMPILER_LIKES_PRAGMA_MARK
1973 #pragma mark - Packet Sending Functions
1976 mDNSexport mStatus
mDNSSendDNSMessage(const mDNS
*const m
, DNSMessage
*const msg
, mDNSu8
*end
,
1977 mDNSInterfaceID InterfaceID
, const mDNSAddr
*dst
, mDNSIPPort dstport
, int sd
, uDNS_AuthInfo
*authInfo
)
1983 mDNSu16 numQuestions
= msg
->h
.numQuestions
;
1984 mDNSu16 numAnswers
= msg
->h
.numAnswers
;
1985 mDNSu16 numAuthorities
= msg
->h
.numAuthorities
;
1986 mDNSu16 numAdditionals
= msg
->h
.numAdditionals
;
1987 mDNSu8
*ptr
= (mDNSu8
*)&msg
->h
.numQuestions
;
1989 // Put all the integer values in IETF byte-order (MSB first, LSB second)
1990 *ptr
++ = (mDNSu8
)(numQuestions
>> 8);
1991 *ptr
++ = (mDNSu8
)(numQuestions
& 0xFF);
1992 *ptr
++ = (mDNSu8
)(numAnswers
>> 8);
1993 *ptr
++ = (mDNSu8
)(numAnswers
& 0xFF);
1994 *ptr
++ = (mDNSu8
)(numAuthorities
>> 8);
1995 *ptr
++ = (mDNSu8
)(numAuthorities
& 0xFF);
1996 *ptr
++ = (mDNSu8
)(numAdditionals
>> 8);
1997 *ptr
++ = (mDNSu8
)(numAdditionals
& 0xFF);
2001 end
= DNSDigest_SignMessage(msg
, &end
, &numAdditionals
, authInfo
);
2002 if (!end
) return mStatus_UnknownErr
;
2005 // Send the packet on the wire
2009 msglen
= (mDNSu16
)(end
- (mDNSu8
*)msg
);
2010 lenbuf
[0] = (mDNSu8
)(msglen
>> 8); // host->network byte conversion
2011 lenbuf
[1] = (mDNSu8
)(msglen
& 0xFF);
2012 nsent
= mDNSPlatformWriteTCP(sd
, (char*)lenbuf
, 2);
2013 //!!!KRS make sure kernel is sending these as 1 packet!
2014 if (nsent
!= 2) goto tcp_error
;
2015 nsent
= mDNSPlatformWriteTCP(sd
, (char *)msg
, msglen
);
2016 if (nsent
!= msglen
) goto tcp_error
;
2017 status
= mStatus_NoError
;
2021 status
= mDNSPlatformSendUDP(m
, msg
, end
, InterfaceID
, dst
, dstport
);
2024 // Put all the integer values back the way they were before we return
2025 msg
->h
.numQuestions
= numQuestions
;
2026 msg
->h
.numAnswers
= numAnswers
;
2027 msg
->h
.numAuthorities
= numAuthorities
;
2028 msg
->h
.numAdditionals
= (mDNSu16
)(authInfo
? numAdditionals
- 1 : numAdditionals
);
2033 LogMsg("mDNSSendDNSMessage: error sending message over tcp");
2034 return mStatus_UnknownErr
;
2037 // ***************************************************************************
2038 #if COMPILER_LIKES_PRAGMA_MARK
2040 #pragma mark - RR List Management & Task Management
2043 mDNSexport
void mDNS_Lock(mDNS
*const m
)
2045 // MUST grab the platform lock FIRST!
2046 mDNSPlatformLock(m
);
2048 // Normally, mDNS_reentrancy is zero and so is mDNS_busy
2049 // However, when we call a client callback mDNS_busy is one, and we increment mDNS_reentrancy too
2050 // If that client callback does mDNS API calls, mDNS_reentrancy and mDNS_busy will both be one
2051 // If mDNS_busy != mDNS_reentrancy that's a bad sign
2052 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
)
2053 LogMsg("mDNS_Lock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
2055 // If this is an initial entry into the mDNSCore code, set m->timenow
2056 // else, if this is a re-entrant entry into the mDNSCore code, m->timenow should already be set
2057 if (m
->mDNS_busy
== 0)
2060 LogMsg("mDNS_Lock: m->timenow already set (%ld/%ld)", m
->timenow
, mDNS_TimeNow_NoLock(m
));
2061 m
->timenow
= mDNS_TimeNow_NoLock(m
);
2062 if (m
->timenow
== 0) m
->timenow
= 1;
2064 else if (m
->timenow
== 0)
2066 LogMsg("mDNS_Lock: m->mDNS_busy is %ld but m->timenow not set", m
->mDNS_busy
);
2067 m
->timenow
= mDNS_TimeNow_NoLock(m
);
2068 if (m
->timenow
== 0) m
->timenow
= 1;
2071 if (m
->timenow_last
- m
->timenow
> 0)
2073 m
->timenow_adjust
+= m
->timenow_last
- m
->timenow
;
2074 LogMsg("mDNSPlatformRawTime went backwards by %ld ticks; setting correction factor to %ld", m
->timenow_last
- m
->timenow
, m
->timenow_adjust
);
2075 m
->timenow
= m
->timenow_last
;
2077 m
->timenow_last
= m
->timenow
;
2079 // Increment mDNS_busy so we'll recognise re-entrant calls
2083 mDNSlocal mDNSs32
GetNextScheduledEvent(const mDNS
*const m
)
2085 mDNSs32 e
= m
->timenow
+ 0x78000000;
2086 if (m
->mDNSPlatformStatus
!= mStatus_NoError
|| m
->SleepState
) return(e
);
2087 if (m
->NewQuestions
)
2089 if (m
->NewQuestions
->DelayAnswering
) e
= m
->NewQuestions
->DelayAnswering
;
2090 else return(m
->timenow
);
2092 if (m
->NewLocalOnlyQuestions
) return(m
->timenow
);
2093 if (m
->NewLocalRecords
&& LocalRecordReady(m
->NewLocalRecords
)) return(m
->timenow
);
2094 if (m
->SuppressSending
) return(m
->SuppressSending
);
2095 #ifndef UNICAST_DISABLED
2096 if (e
- m
->uDNS_info
.nextevent
> 0) e
= m
->uDNS_info
.nextevent
;
2098 if (e
- m
->NextCacheCheck
> 0) e
= m
->NextCacheCheck
;
2099 if (e
- m
->NextScheduledQuery
> 0) e
= m
->NextScheduledQuery
;
2100 if (e
- m
->NextScheduledProbe
> 0) e
= m
->NextScheduledProbe
;
2101 if (e
- m
->NextScheduledResponse
> 0) e
= m
->NextScheduledResponse
;
2105 mDNSexport
void mDNS_Unlock(mDNS
*const m
)
2107 // Decrement mDNS_busy
2110 // Check for locking failures
2111 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
)
2112 LogMsg("mDNS_Unlock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
2114 // If this is a final exit from the mDNSCore code, set m->NextScheduledEvent and clear m->timenow
2115 if (m
->mDNS_busy
== 0)
2117 m
->NextScheduledEvent
= GetNextScheduledEvent(m
);
2118 if (m
->timenow
== 0) LogMsg("mDNS_Unlock: ERROR! m->timenow aready zero");
2122 // MUST release the platform lock LAST!
2123 mDNSPlatformUnlock(m
);