]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSCore/DNSCommon.c
mDNSResponder-108.5.tar.gz
[apple/mdnsresponder.git] / mDNSCore / DNSCommon.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
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
12 * file.
13 *
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.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23
24 Change History (most recent first):
25
26 $Log: DNSCommon.c,v $
27 Revision 1.96.2.1 2006/10/31 02:50:16 cheshire
28 <rdar://problem/4683163> mDNSResponder insufficiently defensive against malformed browsing PTR responses
29
30 Revision 1.96 2006/03/10 21:51:42 cheshire
31 <rdar://problem/4111464> After record update, old record sometimes remains in cache
32 Split out SameRDataBody() into a separate routine so it can be called from other code
33
34 Revision 1.95 2006/03/08 22:43:11 cheshire
35 Use "localdomain" symbol instead of literal string
36
37 Revision 1.94 2006/03/02 21:59:55 cheshire
38 <rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
39 Improve sanity checks & debugging support in GetLargeResourceRecord()
40
41 Revision 1.93 2006/03/02 20:30:47 cheshire
42 Improved GetRRDisplayString to also show priority, weight, and port for SRV records
43
44 Revision 1.92 2005/09/16 21:06:49 cheshire
45 Use mDNS_TimeNow_NoLock macro, instead of writing "mDNSPlatformRawTime() + m->timenow_adjust" all over the place
46
47 Revision 1.91 2005/07/10 22:10:37 cheshire
48 The getOptRdata routine implicitly assumes the destination ResourceRecord is large enough to
49 hold MaximumRDSize bytes, but its parameter was a generic ResourceRecord, which need not be that
50 large. Changing the parameter to a LargeCacheRecord makes it clearer what the routine requires.
51
52 Revision 1.90 2005/03/21 00:33:51 shersche
53 <rdar://problem/4021486> Fix build warnings on Win32 platform
54
55 Revision 1.89 2005/03/17 18:59:38 ksekar
56 <rdar://problem/4012279> Properly parse multiple LLQ Options per packet on Windows
57
58 Revision 1.88 2005/03/16 00:42:32 ksekar
59 <rdar://problem/4012279> Long-lived queries not working on Windows
60
61 Revision 1.87 2005/02/25 04:21:00 cheshire
62 <rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing
63
64 Revision 1.86 2005/02/18 00:43:12 cheshire
65 <rdar://problem/4010245> mDNSResponder should auto-truncate service names that are too long
66
67 Revision 1.85 2005/02/10 22:35:17 cheshire
68 <rdar://problem/3727944> Update name
69
70 Revision 1.84 2005/02/03 00:44:38 cheshire
71 <rdar://problem/3986663> DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL
72
73 Revision 1.83 2005/01/27 22:57:55 cheshire
74 Fix compile errors on gcc4
75
76 Revision 1.82 2005/01/19 03:27:03 cheshire
77 <rdar://problem/3961051> CPU Spin in mDNSResponder
78 GetNextScheduledEvent() needs to check LocalRecordReady()
79
80 Revision 1.81 2004/12/18 03:13:45 cheshire
81 <rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records
82
83 Revision 1.80 2004/12/16 21:46:43 cheshire
84 Add DNSTypeName case for kDNSType_SOA
85
86 Revision 1.79 2004/12/16 21:38:37 cheshire
87 Add DNSTypeName case for kDNSType_NS
88
89 Revision 1.78 2004/12/16 21:27:37 ksekar
90 Fixed build failures when compiled with verbose debugging messages
91
92 Revision 1.77 2004/12/16 20:12:59 cheshire
93 <rdar://problem/3324626> Cache memory management improvements
94
95 Revision 1.76 2004/12/16 08:05:29 shersche
96 Remove extranenous semicolons that cause compilation errors on Windows
97
98 Revision 1.75 2004/12/15 02:11:22 ksekar
99 <rdar://problem/3917317> Don't check for Dynamic DNS hostname uniqueness
100
101 Revision 1.74 2004/12/09 22:49:15 ksekar
102 <rdar://problem/3913653> Wide-Area Goodbyes broken
103
104 Revision 1.73 2004/12/07 22:49:06 cheshire
105 <rdar://problem/3908850> BIND doesn't allow zero-length TXT records
106
107 Revision 1.72 2004/12/06 21:15:20 ksekar
108 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
109
110 Revision 1.71 2004/12/04 02:12:45 cheshire
111 <rdar://problem/3517236> mDNSResponder puts LargeCacheRecord on the stack
112
113 Revision 1.70 2004/12/03 19:52:44 ksekar
114 Use PutResourceRecordTTLJumbo for putDeletionRecord()
115
116 Revision 1.69 2004/12/03 07:20:50 ksekar
117 <rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
118
119 Revision 1.68 2004/11/24 00:10:43 cheshire
120 <rdar://problem/3869241> For unicast operations, verify that service types are legal
121
122 Revision 1.67 2004/10/26 03:52:02 cheshire
123 Update checkin comments
124
125 Revision 1.66 2004/10/23 01:16:00 cheshire
126 <rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
127
128 Revision 1.65 2004/10/20 02:15:09 cheshire
129 Add case in GetRRDisplayString() to display NS rdata
130
131 Revision 1.64 2004/10/13 00:24:02 cheshire
132 Disable "array is too small to include a terminating null character" warning on Windows
133
134 Revision 1.63 2004/10/10 06:57:14 cheshire
135 Change definition of "localdomain" to make code compile a little smaller
136
137 Revision 1.62 2004/10/06 01:44:19 cheshire
138 <rdar://problem/3813936> Resolving too quickly sometimes returns stale TXT record
139
140 Revision 1.61 2004/09/30 00:24:56 ksekar
141 <rdar://problem/3695802> Dynamically update default registration domains on config change
142
143 Revision 1.60 2004/09/27 23:25:30 cheshire
144 Fix compiler warning: soa.serial is signed, not unsigned
145
146 Revision 1.59 2004/09/27 22:53:45 ksekar
147 Fixed getLargeResourceRecord for SOA rdata.
148
149 Revision 1.58 2004/09/25 02:41:39 cheshire
150 <rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events
151
152 Revision 1.57 2004/09/25 02:24:27 cheshire
153 Removed unused rr->UseCount
154
155 Revision 1.56 2004/09/24 20:57:39 cheshire
156 <rdar://problem/3680902> Eliminate inappropriate casts that cause misaligned-address errors
157
158 Revision 1.55 2004/09/17 01:08:48 cheshire
159 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
160 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
161 declared in that file are ONLY appropriate to single-address-space embedded applications.
162 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
163
164 Revision 1.54 2004/09/17 00:49:51 cheshire
165 Get rid of now-unused GetResourceRecord -- the correct (safe) routine to use
166 is GetLargeResourceRecord
167
168 Revision 1.53 2004/09/17 00:31:51 cheshire
169 For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
170
171 Revision 1.52 2004/09/17 00:19:10 cheshire
172 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
173
174 Revision 1.51 2004/09/16 02:29:39 cheshire
175 Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
176 uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
177
178 Revision 1.50 2004/09/16 01:58:14 cheshire
179 Fix compiler warnings
180
181 Revision 1.49 2004/09/14 23:42:35 cheshire
182 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
183
184 Revision 1.48 2004/09/14 23:27:46 cheshire
185 Fix compile errors
186
187 Revision 1.47 2004/08/25 02:50:04 cheshire
188 <rdar://problem/3561220> Browses are no longer piggybacking on other browses
189 Make mDNSSameAddress() recognise that two mDNSAddrType_None addresses are necessarily equal
190
191 Revision 1.46 2004/08/18 17:35:40 ksekar
192 <rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
193
194 Revision 1.45 2004/08/15 18:26:00 cheshire
195 Don't use strcpy() on "struct domainname" objects; use AssignDomainName() instead
196 (A "struct domainname" is a collection of packed pascal strings, not a C string.)
197
198 Revision 1.44 2004/08/13 23:46:58 cheshire
199 "asyncronous" -> "asynchronous"
200
201 Revision 1.43 2004/08/12 02:55:46 ksekar
202 Fix param order error moving putPrereqNameNotInUse from uDNS.c using
203 ustrcpy macro to DNSCommon.c using mDNSPlatformStrCopy().
204
205 Revision 1.42 2004/08/10 23:19:14 ksekar
206 <rdar://problem/3722542>: DNS Extension daemon for Wide Area Service Discovery
207 Moved routines/constants to allow extern access for garbage collection daemon
208
209 Revision 1.41 2004/08/10 01:10:01 cheshire
210 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
211 Minor revision from Roger Pantos
212
213 Revision 1.40 2004/08/04 22:10:46 cheshire
214 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
215 Change to use "._sub." instead of ".s." to mark subtypes.
216
217 Revision 1.39 2004/07/13 21:24:24 rpantos
218 Fix for <rdar://problem/3701120>.
219
220 Revision 1.38 2004/06/18 21:08:58 cheshire
221 <rdar://problem/3540040> Applications are registering invalid records
222 Attempts to create domain names like "www..apple.com." now logged to aid debugging
223
224 Revision 1.37 2004/06/18 20:25:42 cheshire
225 <rdar://problem/3488547> Add a syslog message if someone tries to use "local.arpa".
226
227 Revision 1.36 2004/06/18 19:09:59 cheshire
228 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
229
230 Revision 1.35 2004/06/05 00:14:44 cheshire
231 Fix signed/unsigned and other compiler warnings
232
233 Revision 1.34 2004/06/04 00:25:25 cheshire
234 Fix misaligned write exception that occurs on some platforms
235
236 Revision 1.33 2004/06/04 00:16:18 cheshire
237 Remove non-portable use of 'inline'
238
239 Revision 1.32 2004/06/03 03:09:58 ksekar
240 <rdar://problem/3668626>: Garbage Collection for Dynamic Updates
241
242 Revision 1.31 2004/05/28 23:42:36 ksekar
243 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
244
245 Revision 1.30 2004/05/26 09:08:04 bradley
246 Added cast to correct structure pointer when allocating domain name list element to fix C++ builds.
247
248 Revision 1.29 2004/05/18 23:51:25 cheshire
249 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
250
251 Revision 1.28 2004/05/13 04:54:20 ksekar
252 Unified list copy/free code. Added symetric list for
253
254 Revision 1.27 2004/04/22 20:29:07 cheshire
255 Log error message if no count field passed to PutResourceRecordTTL()
256
257 Revision 1.26 2004/04/22 04:07:01 cheshire
258 Fix from Bob Bradley: Don't try to do inline functions on compilers that don't support it
259
260 Revision 1.25 2004/04/22 03:05:28 cheshire
261 kDNSClass_ANY should be kDNSQClass_ANY
262
263 Revision 1.24 2004/04/22 02:51:20 cheshire
264 Use common code for HINFO/TXT and TSIG cases in putRData
265
266 Revision 1.23 2004/04/15 00:51:28 bradley
267 Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers.
268 Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers.
269
270 Revision 1.22 2004/04/14 23:09:28 ksekar
271 Support for TSIG signed dynamic updates.
272
273 Revision 1.21 2004/04/09 16:47:28 cheshire
274 <rdar://problem/3617655>: mDNSResponder escape handling inconsistent with BIND
275
276 Revision 1.20 2004/04/09 16:37:15 cheshire
277 Suggestion from Bob Bradley:
278 Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers
279
280 Revision 1.19 2004/04/02 19:34:38 cheshire
281 Fix broken comment
282
283 Revision 1.18 2004/03/30 06:45:00 cheshire
284 Compiler warning fixes from Don Woodward at Roku Labs
285
286 Revision 1.17 2004/03/19 22:25:20 cheshire
287 <rdar://problem/3579561>: Need to limit service types to fourteen characters
288 Won't actually do this for now, but keep the code around just in case
289
290 Revision 1.16 2004/03/08 02:45:35 cheshire
291 Minor change to make a couple of the log messages a bit shorter
292
293 Revision 1.15 2004/03/08 02:44:09 cheshire
294 <rdar://problem/3579561>: Need to limit service types to fourteen characters
295
296 Revision 1.14 2004/02/21 02:06:24 cheshire
297 Can't use anonymous unions -- they're non-standard and don't work on all compilers
298
299 Revision 1.13 2004/02/06 23:04:18 ksekar
300 Basic Dynamic Update support via mDNS_Register (dissabled via
301 UNICAST_REGISTRATION #define)
302
303 Revision 1.12 2004/02/03 22:37:10 cheshire
304 Delete unused (commented-out) code
305
306 Revision 1.11 2004/02/03 22:35:34 cheshire
307 <rdar://problem/3548256>: Should not allow empty string for resolve domain
308
309 Revision 1.10 2004/02/03 19:47:36 ksekar
310 Added an asynchronous state machine mechanism to uDNS.c, including
311 calls to find the parent zone for a domain name. Changes include code
312 in repository previously dissabled via "#if 0 incomplete". Codepath
313 is currently unused, and will be called to create update records, etc.
314
315 Revision 1.9 2004/01/27 20:15:22 cheshire
316 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
317
318 Revision 1.8 2004/01/24 23:24:36 cheshire
319 Expanded out the list of local domains to reduce risk of mistakes in future
320
321 Revision 1.7 2004/01/24 08:32:30 bradley
322 Mask values with 0xFF before casting to avoid runtime truncation errors on Windows debug builds.
323 Separated octal-escaped sequences preceding decimal digits to avoid errors with some compilers wanting
324 to signal potentially hidden errors about the subsequent digit not being part of the octal sequence.
325
326 Revision 1.6 2004/01/24 04:59:15 cheshire
327 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
328
329 Revision 1.5 2004/01/23 23:23:14 ksekar
330 Added TCP support for truncated unicast messages.
331
332 Revision 1.4 2004/01/22 02:15:33 cheshire
333 <rdar://problem/3536597>: Link-local reverse-mapping domains need to be resolved using link-local multicast
334
335 Revision 1.3 2004/01/21 21:16:29 cheshire
336 Minor tidy-up: Deleted a bunch of blank lines, trailing spaces, tabs, etc.
337
338 Revision 1.2 2003/12/13 05:47:48 bradley
339 Made local ptr const to fix error when assigning from const structure. Disable benign conditional
340 expression is constant warning when building with Microsoft compilers.
341
342 Revision 1.1 2003/12/13 03:05:27 ksekar
343 <rdar://problem/3192548>: DynDNS: Unicast query of service records
344
345 */
346
347 // Set mDNS_InstantiateInlines to tell mDNSEmbeddedAPI.h to instantiate inline functions, if necessary
348 #define mDNS_InstantiateInlines 1
349 #include "DNSCommon.h"
350
351 // Disable certain benign warnings with Microsoft compilers
352 #if (defined(_MSC_VER))
353 // Disable "conditional expression is constant" warning for debug macros.
354 // Otherwise, this generates warnings for the perfectly natural construct "while(1)"
355 // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know
356 #pragma warning(disable:4127)
357 // Disable "array is too small to include a terminating null character" warning
358 // -- domain labels have an initial length byte, not a terminating null character
359 #pragma warning(disable:4295)
360 #endif
361
362 // ***************************************************************************
363 #if COMPILER_LIKES_PRAGMA_MARK
364 #pragma mark -
365 #pragma mark - DNameList copy/deallocation routines
366 #endif
367
368 mDNSexport DNameListElem *mDNS_CopyDNameList(const DNameListElem *orig)
369 {
370 DNameListElem *copy = mDNSNULL, *newelem;
371 const DNameListElem *ptr;
372
373 for (ptr = orig; ptr; ptr = ptr->next)
374 {
375 newelem = (DNameListElem*)mDNSPlatformMemAllocate(sizeof(DNameListElem));
376 if (!newelem) { LogMsg("ERROR: malloc"); return mDNSNULL; }
377 AssignDomainName(&newelem->name, &ptr->name);
378 newelem->next = copy;
379 copy = newelem;
380 }
381 return copy;
382 }
383
384 mDNSexport void mDNS_FreeDNameList(DNameListElem *list)
385 {
386 DNameListElem *fptr;
387
388 while (list)
389 {
390 fptr = list;
391 list = list->next;
392 mDNSPlatformMemFree(fptr);
393 }
394 }
395
396 // ***************************************************************************
397 #if COMPILER_LIKES_PRAGMA_MARK
398 #pragma mark -
399 #pragma mark - General Utility Functions
400 #endif
401
402 // return true for RFC1918 private addresses
403 mDNSexport mDNSBool IsPrivateV4Addr(mDNSAddr *addr)
404 {
405 mDNSu8 *b;
406
407 if (addr->type != mDNSAddrType_IPv4) return mDNSfalse;
408 b = addr->ip.v4.b;
409
410 return ((b[0] == 10) || // 10/8 prefix
411 (b[0] == 172 && b[1] > 15 && b[1] < 32) || // 172.16/12
412 (b[0] == 192 && b[1] == 168)); // 192.168/16
413 }
414
415 mDNSexport const NetworkInterfaceInfo *GetFirstActiveInterface(const NetworkInterfaceInfo *intf)
416 {
417 while (intf && !intf->InterfaceActive) intf = intf->next;
418 return(intf);
419 }
420
421 mDNSexport mDNSInterfaceID GetNextActiveInterfaceID(const NetworkInterfaceInfo *intf)
422 {
423 const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next);
424 if (next) return(next->InterfaceID); else return(mDNSNULL);
425 }
426
427 mDNSexport mDNSu32 NumCacheRecordsForInterfaceID(const mDNS *const m, mDNSInterfaceID id)
428 {
429 mDNSu32 slot, used = 0;
430 CacheGroup *cg;
431 CacheRecord *rr;
432 FORALL_CACHERECORDS(slot, cg, rr)
433 if (rr->resrec.InterfaceID == id) used++;
434 return(used);
435 }
436
437 mDNSexport char *DNSTypeName(mDNSu16 rrtype)
438 {
439 switch (rrtype)
440 {
441 case kDNSType_A: return("Addr");
442 case kDNSType_NS: return("NS");
443 case kDNSType_CNAME:return("CNAME");
444 case kDNSType_SOA: return("SOA");
445 case kDNSType_NULL: return("NULL");
446 case kDNSType_PTR: return("PTR");
447 case kDNSType_HINFO:return("HINFO");
448 case kDNSType_TXT: return("TXT");
449 case kDNSType_AAAA: return("AAAA");
450 case kDNSType_SRV: return("SRV");
451 case kDNSQType_ANY: return("ANY");
452 default: {
453 static char buffer[16];
454 mDNS_snprintf(buffer, sizeof(buffer), "(%d)", rrtype);
455 return(buffer);
456 }
457 }
458 }
459
460 // Note slight bug: this code uses the rdlength from the ResourceRecord object, to display
461 // the rdata from the RDataBody object. Sometimes this could be the wrong length -- but as
462 // long as this routine is only used for debugging messages, it probably isn't a big problem.
463 mDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *rr, RDataBody *rd, char *buffer)
464 {
465 char *ptr = buffer;
466 mDNSu32 length = mDNS_snprintf(buffer, 79, "%4d %##s %s ", rr->rdlength, rr->name->c, DNSTypeName(rr->rrtype));
467 switch (rr->rrtype)
468 {
469 case kDNSType_A: mDNS_snprintf(buffer+length, 79-length, "%.4a", &rd->ipv4); break;
470
471 case kDNSType_NS: // Same as PTR
472 case kDNSType_CNAME:// Same as PTR
473 case kDNSType_PTR: mDNS_snprintf(buffer+length, 79-length, "%##s", rd->name.c); break;
474
475 case kDNSType_HINFO:// Display this the same as TXT (just show first string)
476 case kDNSType_TXT: mDNS_snprintf(buffer+length, 79-length, "%#s", rd->txt.c); break;
477
478 case kDNSType_AAAA: mDNS_snprintf(buffer+length, 79-length, "%.16a", &rd->ipv6); break;
479 case kDNSType_SRV: mDNS_snprintf(buffer+length, 79-length, "%u %u %u %##s",
480 rd->srv.priority, rd->srv.weight, mDNSVal16(rd->srv.port), rd->srv.target.c); break;
481 default: mDNS_snprintf(buffer+length, 79-length, "RDLen %d: %s", rr->rdlength, rd->data); break;
482 }
483 for (ptr = buffer; *ptr; ptr++) if (*ptr < ' ') *ptr='.';
484 return(buffer);
485 }
486
487 mDNSexport mDNSu32 mDNSRandom(mDNSu32 max)
488 {
489 static mDNSu32 seed = 0;
490 mDNSu32 mask = 1;
491
492 if (!seed)
493 {
494 int i;
495 seed = mDNSPlatformRandomSeed(); // Pick an initial seed
496 for (i=0; i<100; i++) seed = seed * 21 + 1; // And mix it up a bit
497 }
498 while (mask < max) mask = (mask << 1) | 1;
499 do seed = seed * 21 + 1; while ((seed & mask) > max);
500 return (seed & mask);
501 }
502
503 mDNSexport mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2)
504 {
505 if (ip1->type == ip2->type)
506 {
507 switch (ip1->type)
508 {
509 case mDNSAddrType_None : return(mDNStrue); // Empty addresses have no data and are therefore always equal
510 case mDNSAddrType_IPv4 : return(mDNSBool)(mDNSSameIPv4Address(ip1->ip.v4, ip2->ip.v4));
511 case mDNSAddrType_IPv6 : return(mDNSBool)(mDNSSameIPv6Address(ip1->ip.v6, ip2->ip.v6));
512 }
513 }
514 return(mDNSfalse);
515 }
516
517 mDNSexport mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip)
518 {
519 switch(ip->type)
520 {
521 case mDNSAddrType_IPv4: return(mDNSBool)(ip->ip.v4.NotAnInteger == AllDNSLinkGroupv4.NotAnInteger);
522 case mDNSAddrType_IPv6: return(mDNSBool)(ip->ip.v6.l[0] == AllDNSLinkGroupv6.l[0] &&
523 ip->ip.v6.l[1] == AllDNSLinkGroupv6.l[1] &&
524 ip->ip.v6.l[2] == AllDNSLinkGroupv6.l[2] &&
525 ip->ip.v6.l[3] == AllDNSLinkGroupv6.l[3] );
526 default: return(mDNSfalse);
527 }
528 }
529
530 // ***************************************************************************
531 #if COMPILER_LIKES_PRAGMA_MARK
532 #pragma mark -
533 #pragma mark - Domain Name Utility Functions
534 #endif
535
536 mDNSexport mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
537 {
538 int i;
539 const int len = *a++;
540
541 if (len > MAX_DOMAIN_LABEL)
542 { debugf("Malformed label (too long)"); return(mDNSfalse); }
543
544 if (len != *b++) return(mDNSfalse);
545 for (i=0; i<len; i++)
546 {
547 mDNSu8 ac = *a++;
548 mDNSu8 bc = *b++;
549 if (mDNSIsUpperCase(ac)) ac += 'a' - 'A';
550 if (mDNSIsUpperCase(bc)) bc += 'a' - 'A';
551 if (ac != bc) return(mDNSfalse);
552 }
553 return(mDNStrue);
554 }
555
556 mDNSexport mDNSBool SameDomainName(const domainname *const d1, const domainname *const d2)
557 {
558 const mDNSu8 * a = d1->c;
559 const mDNSu8 * b = d2->c;
560 const mDNSu8 *const max = d1->c + MAX_DOMAIN_NAME; // Maximum that's valid
561
562 while (*a || *b)
563 {
564 if (a + 1 + *a >= max)
565 { debugf("Malformed domain name (more than 255 characters)"); return(mDNSfalse); }
566 if (!SameDomainLabel(a, b)) return(mDNSfalse);
567 a += 1 + *a;
568 b += 1 + *b;
569 }
570
571 return(mDNStrue);
572 }
573
574 mDNSexport mDNSBool IsLocalDomain(const domainname *d)
575 {
576 // Domains that are defined to be resolved via link-local multicast are:
577 // local., 254.169.in-addr.arpa., and 0.8.E.F.ip6.arpa.
578 static const domainname *n0 = (domainname*)"\x5" "local";
579 static const domainname *n1 = (domainname*)"\x3" "254" "\x3" "169" "\x7" "in-addr" "\x4" "arpa";
580 static const domainname *n2 = (domainname*)"\x1" "0" "\x1" "8" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa";
581
582 const domainname *d1, *d2, *d3, *d4, *d5, *d6; // Top-level domain, second-level domain, etc.
583 d1 = d2 = d3 = d4 = d5 = d6 = mDNSNULL;
584 while (d->c[0])
585 {
586 d6 = d5; d5 = d4; d4 = d3; d3 = d2; d2 = d1; d1 = d;
587 d = (domainname*)(d->c + 1 + d->c[0]);
588 }
589
590 if (d1 && SameDomainName(d1, n0)) return(mDNStrue);
591 if (d4 && SameDomainName(d4, n1)) return(mDNStrue);
592 if (d6 && SameDomainName(d6, n2)) return(mDNStrue);
593 return(mDNSfalse);
594 }
595
596 // Returns length of a domain name INCLUDING the byte for the final null label
597 // i.e. for the root label "." it returns one
598 // For the FQDN "com." it returns 5 (length byte, three data bytes, final zero)
599 // Legal results are 1 (just root label) to 255 (MAX_DOMAIN_NAME)
600 // If the given domainname is invalid, result is 256
601 mDNSexport mDNSu16 DomainNameLength(const domainname *const name)
602 {
603 const mDNSu8 *src = name->c;
604 while (*src)
605 {
606 if (*src > MAX_DOMAIN_LABEL) return(MAX_DOMAIN_NAME+1);
607 src += 1 + *src;
608 if (src - name->c >= MAX_DOMAIN_NAME) return(MAX_DOMAIN_NAME+1);
609 }
610 return((mDNSu16)(src - name->c + 1));
611 }
612
613 // CompressedDomainNameLength returns the length of a domain name INCLUDING the byte
614 // for the final null label i.e. for the root label "." it returns one.
615 // E.g. for the FQDN "foo.com." it returns 9
616 // (length, three data bytes, length, three more data bytes, final zero).
617 // In the case where a parent domain name is provided, and the given name is a child
618 // of that parent, CompressedDomainNameLength returns the length of the prefix portion
619 // of the child name, plus TWO bytes for the compression pointer.
620 // E.g. for the name "foo.com." with parent "com.", it returns 6
621 // (length, three data bytes, two-byte compression pointer).
622 mDNSexport mDNSu16 CompressedDomainNameLength(const domainname *const name, const domainname *parent)
623 {
624 const mDNSu8 *src = name->c;
625 if (parent && parent->c[0] == 0) parent = mDNSNULL;
626 while (*src)
627 {
628 if (*src > MAX_DOMAIN_LABEL) return(MAX_DOMAIN_NAME+1);
629 if (parent && SameDomainName((domainname *)src, parent)) return((mDNSu16)(src - name->c + 2));
630 src += 1 + *src;
631 if (src - name->c >= MAX_DOMAIN_NAME) return(MAX_DOMAIN_NAME+1);
632 }
633 return((mDNSu16)(src - name->c + 1));
634 }
635
636 // AppendLiteralLabelString appends a single label to an existing (possibly empty) domainname.
637 // The C string contains the label as-is, with no escaping, etc.
638 // Any dots in the name are literal dots, not label separators
639 // If successful, AppendLiteralLabelString returns a pointer to the next unused byte
640 // in the domainname bufer (i.e., the next byte after the terminating zero).
641 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
642 // AppendLiteralLabelString returns mDNSNULL.
643 mDNSexport mDNSu8 *AppendLiteralLabelString(domainname *const name, const char *cstr)
644 {
645 mDNSu8 * ptr = name->c + DomainNameLength(name) - 1; // Find end of current name
646 const mDNSu8 *const lim1 = name->c + MAX_DOMAIN_NAME - 1; // Limit of how much we can add (not counting final zero)
647 const mDNSu8 *const lim2 = ptr + 1 + MAX_DOMAIN_LABEL;
648 const mDNSu8 *const lim = (lim1 < lim2) ? lim1 : lim2;
649 mDNSu8 *lengthbyte = ptr++; // Record where the length is going to go
650
651 while (*cstr && ptr < lim) *ptr++ = (mDNSu8)*cstr++; // Copy the data
652 *lengthbyte = (mDNSu8)(ptr - lengthbyte - 1); // Fill in the length byte
653 *ptr++ = 0; // Put the null root label on the end
654 if (*cstr) return(mDNSNULL); // Failure: We didn't successfully consume all input
655 else return(ptr); // Success: return new value of ptr
656 }
657
658 // AppendDNSNameString appends zero or more labels to an existing (possibly empty) domainname.
659 // The C string is in conventional DNS syntax:
660 // Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots.
661 // If successful, AppendDNSNameString returns a pointer to the next unused byte
662 // in the domainname bufer (i.e., the next byte after the terminating zero).
663 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
664 // AppendDNSNameString returns mDNSNULL.
665 mDNSexport mDNSu8 *AppendDNSNameString(domainname *const name, const char *cstring)
666 {
667 const char *cstr = cstring;
668 mDNSu8 * ptr = name->c + DomainNameLength(name) - 1; // Find end of current name
669 const mDNSu8 *const lim = name->c + MAX_DOMAIN_NAME - 1; // Limit of how much we can add (not counting final zero)
670 while (*cstr && ptr < lim) // While more characters, and space to put them...
671 {
672 mDNSu8 *lengthbyte = ptr++; // Record where the length is going to go
673 if (*cstr == '.') { LogMsg("AppendDNSNameString: Illegal empty label in name \"%s\"", cstring); return(mDNSNULL); }
674 while (*cstr && *cstr != '.' && ptr < lim) // While we have characters in the label...
675 {
676 mDNSu8 c = (mDNSu8)*cstr++; // Read the character
677 if (c == '\\') // If escape character, check next character
678 {
679 c = (mDNSu8)*cstr++; // Assume we'll just take the next character
680 if (mdnsIsDigit(cstr[-1]) && mdnsIsDigit(cstr[0]) && mdnsIsDigit(cstr[1]))
681 { // If three decimal digits,
682 int v0 = cstr[-1] - '0'; // then interpret as three-digit decimal
683 int v1 = cstr[ 0] - '0';
684 int v2 = cstr[ 1] - '0';
685 int val = v0 * 100 + v1 * 10 + v2;
686 if (val <= 255) { c = (mDNSu8)val; cstr += 2; } // If valid three-digit decimal value, use it
687 }
688 }
689 *ptr++ = c; // Write the character
690 }
691 if (*cstr) cstr++; // Skip over the trailing dot (if present)
692 if (ptr - lengthbyte - 1 > MAX_DOMAIN_LABEL) // If illegal label, abort
693 return(mDNSNULL);
694 *lengthbyte = (mDNSu8)(ptr - lengthbyte - 1); // Fill in the length byte
695 }
696
697 *ptr++ = 0; // Put the null root label on the end
698 if (*cstr) return(mDNSNULL); // Failure: We didn't successfully consume all input
699 else return(ptr); // Success: return new value of ptr
700 }
701
702 // AppendDomainLabel appends a single label to a name.
703 // If successful, AppendDomainLabel returns a pointer to the next unused byte
704 // in the domainname bufer (i.e., the next byte after the terminating zero).
705 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
706 // AppendDomainLabel returns mDNSNULL.
707 mDNSexport mDNSu8 *AppendDomainLabel(domainname *const name, const domainlabel *const label)
708 {
709 int i;
710 mDNSu8 *ptr = name->c + DomainNameLength(name) - 1;
711
712 // Check label is legal
713 if (label->c[0] > MAX_DOMAIN_LABEL) return(mDNSNULL);
714
715 // Check that ptr + length byte + data bytes + final zero does not exceed our limit
716 if (ptr + 1 + label->c[0] + 1 > name->c + MAX_DOMAIN_NAME) return(mDNSNULL);
717
718 for (i=0; i<=label->c[0]; i++) *ptr++ = label->c[i]; // Copy the label data
719 *ptr++ = 0; // Put the null root label on the end
720 return(ptr);
721 }
722
723 mDNSexport mDNSu8 *AppendDomainName(domainname *const name, const domainname *const append)
724 {
725 mDNSu8 * ptr = name->c + DomainNameLength(name) - 1; // Find end of current name
726 const mDNSu8 *const lim = name->c + MAX_DOMAIN_NAME - 1; // Limit of how much we can add (not counting final zero)
727 const mDNSu8 * src = append->c;
728 while(src[0])
729 {
730 int i;
731 if (ptr + 1 + src[0] > lim) return(mDNSNULL);
732 for (i=0; i<=src[0]; i++) *ptr++ = src[i];
733 *ptr = 0; // Put the null root label on the end
734 src += i;
735 }
736 return(ptr);
737 }
738
739 // MakeDomainLabelFromLiteralString makes a single domain label from a single literal C string (with no escaping).
740 // If successful, MakeDomainLabelFromLiteralString returns mDNStrue.
741 // If unable to convert the whole string to a legal domain label (i.e. because length is more than 63 bytes) then
742 // MakeDomainLabelFromLiteralString makes a legal domain label from the first 63 bytes of the string and returns mDNSfalse.
743 // In some cases silently truncated oversized names to 63 bytes is acceptable, so the return result may be ignored.
744 // In other cases silent truncation may not be acceptable, so in those cases the calling function needs to check the return result.
745 mDNSexport mDNSBool MakeDomainLabelFromLiteralString(domainlabel *const label, const char *cstr)
746 {
747 mDNSu8 * ptr = label->c + 1; // Where we're putting it
748 const mDNSu8 *const limit = label->c + 1 + MAX_DOMAIN_LABEL; // The maximum we can put
749 while (*cstr && ptr < limit) *ptr++ = (mDNSu8)*cstr++; // Copy the label
750 label->c[0] = (mDNSu8)(ptr - label->c - 1); // Set the length byte
751 return(*cstr == 0); // Return mDNStrue if we successfully consumed all input
752 }
753
754 // MakeDomainNameFromDNSNameString makes a native DNS-format domainname from a C string.
755 // The C string is in conventional DNS syntax:
756 // Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots.
757 // If successful, MakeDomainNameFromDNSNameString returns a pointer to the next unused byte
758 // in the domainname bufer (i.e., the next byte after the terminating zero).
759 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
760 // MakeDomainNameFromDNSNameString returns mDNSNULL.
761 mDNSexport mDNSu8 *MakeDomainNameFromDNSNameString(domainname *const name, const char *cstr)
762 {
763 name->c[0] = 0; // Make an empty domain name
764 return(AppendDNSNameString(name, cstr)); // And then add this string to it
765 }
766
767 mDNSexport char *ConvertDomainLabelToCString_withescape(const domainlabel *const label, char *ptr, char esc)
768 {
769 const mDNSu8 * src = label->c; // Domain label we're reading
770 const mDNSu8 len = *src++; // Read length of this (non-null) label
771 const mDNSu8 *const end = src + len; // Work out where the label ends
772 if (len > MAX_DOMAIN_LABEL) return(mDNSNULL); // If illegal label, abort
773 while (src < end) // While we have characters in the label
774 {
775 mDNSu8 c = *src++;
776 if (esc)
777 {
778 if (c == '.' || c == esc) // If character is a dot or the escape character
779 *ptr++ = esc; // Output escape character
780 else if (c <= ' ') // If non-printing ascii,
781 { // Output decimal escape sequence
782 *ptr++ = esc;
783 *ptr++ = (char) ('0' + (c / 100) );
784 *ptr++ = (char) ('0' + (c / 10) % 10);
785 c = (mDNSu8)('0' + (c ) % 10);
786 }
787 }
788 *ptr++ = (char)c; // Copy the character
789 }
790 *ptr = 0; // Null-terminate the string
791 return(ptr); // and return
792 }
793
794 // Note: To guarantee that there will be no possible overrun, cstr must be at least MAX_ESCAPED_DOMAIN_NAME (1005 bytes)
795 mDNSexport char *ConvertDomainNameToCString_withescape(const domainname *const name, char *ptr, char esc)
796 {
797 const mDNSu8 *src = name->c; // Domain name we're reading
798 const mDNSu8 *const max = name->c + MAX_DOMAIN_NAME; // Maximum that's valid
799
800 if (*src == 0) *ptr++ = '.'; // Special case: For root, just write a dot
801
802 while (*src) // While more characters in the domain name
803 {
804 if (src + 1 + *src >= max) return(mDNSNULL);
805 ptr = ConvertDomainLabelToCString_withescape((const domainlabel *)src, ptr, esc);
806 if (!ptr) return(mDNSNULL);
807 src += 1 + *src;
808 *ptr++ = '.'; // Write the dot after the label
809 }
810
811 *ptr++ = 0; // Null-terminate the string
812 return(ptr); // and return
813 }
814
815 // RFC 1034 rules:
816 // Host names must start with a letter, end with a letter or digit,
817 // and have as interior characters only letters, digits, and hyphen.
818 // This was subsequently modified in RFC 1123 to allow the first character to be either a letter or a digit
819
820 mDNSexport void ConvertUTF8PstringToRFC1034HostLabel(const mDNSu8 UTF8Name[], domainlabel *const hostlabel)
821 {
822 const mDNSu8 * src = &UTF8Name[1];
823 const mDNSu8 *const end = &UTF8Name[1] + UTF8Name[0];
824 mDNSu8 * ptr = &hostlabel->c[1];
825 const mDNSu8 *const lim = &hostlabel->c[1] + MAX_DOMAIN_LABEL;
826 while (src < end)
827 {
828 // Delete apostrophes from source name
829 if (src[0] == '\'') { src++; continue; } // Standard straight single quote
830 if (src + 2 < end && src[0] == 0xE2 && src[1] == 0x80 && src[2] == 0x99)
831 { src += 3; continue; } // Unicode curly apostrophe
832 if (ptr < lim)
833 {
834 if (mdnsValidHostChar(*src, (ptr > &hostlabel->c[1]), (src < end-1))) *ptr++ = *src;
835 else if (ptr > &hostlabel->c[1] && ptr[-1] != '-') *ptr++ = '-';
836 }
837 src++;
838 }
839 while (ptr > &hostlabel->c[1] && ptr[-1] == '-') ptr--; // Truncate trailing '-' marks
840 hostlabel->c[0] = (mDNSu8)(ptr - &hostlabel->c[1]);
841 }
842
843 mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn,
844 const domainlabel *name, const domainname *type, const domainname *const domain)
845 {
846 int i, len;
847 mDNSu8 *dst = fqdn->c;
848 const mDNSu8 *src;
849 const char *errormsg;
850
851 // In the case where there is no name (and ONLY in that case),
852 // a single-label subtype is allowed as the first label of a three-part "type"
853 if (!name && type)
854 {
855 const mDNSu8 *s0 = type->c;
856 if (s0[0] && s0[0] < 0x40) // If legal first label (at least one character, and no more than 63)
857 {
858 const mDNSu8 * s1 = s0 + 1 + s0[0];
859 if (s1[0] && s1[0] < 0x40) // and legal second label (at least one character, and no more than 63)
860 {
861 const mDNSu8 *s2 = s1 + 1 + s1[0];
862 if (s2[0] && s2[0] < 0x40 && s2[1+s2[0]] == 0) // and we have three and only three labels
863 {
864 static const mDNSu8 SubTypeLabel[5] = "\x04_sub";
865 src = s0; // Copy the first label
866 len = *src;
867 for (i=0; i <= len; i++) *dst++ = *src++;
868 for (i=0; i < (int)sizeof(SubTypeLabel); i++) *dst++ = SubTypeLabel[i];
869 type = (domainname *)s1;
870
871 // Special support for queries done by some third-party network monitoring software
872 // For these queries, we retract the "._sub" we just added between the subtype and the main type
873 if (SameDomainName((domainname*)s0, (domainname*)"\x09_services\x07_dns-sd\x04_udp") ||
874 SameDomainName((domainname*)s0, (domainname*)"\x09_services\x05_mdns\x04_udp"))
875 dst -= sizeof(SubTypeLabel);
876 }
877 }
878 }
879 }
880
881 if (name && name->c[0])
882 {
883 src = name->c; // Put the service name into the domain name
884 len = *src;
885 if (len >= 0x40) { errormsg="Service instance name too long"; goto fail; }
886 for (i=0; i<=len; i++) *dst++ = *src++;
887 }
888 else
889 name = (domainlabel*)""; // Set this up to be non-null, to avoid errors if we have to call LogMsg() below
890
891 src = type->c; // Put the service type into the domain name
892 len = *src;
893 if (len < 2 || len >= 0x40 || (len > 15 && !SameDomainName(domain, &localdomain)))
894 {
895 errormsg="Application protocol name must be underscore plus 1-14 characters. See <http://www.dns-sd.org/ServiceTypes.html>";
896 goto fail;
897 }
898 if (src[1] != '_') { errormsg="Application protocol name must begin with underscore"; goto fail; }
899 for (i=2; i<=len; i++)
900 if (!mdnsIsLetter(src[i]) && !mdnsIsDigit(src[i]) && src[i] != '-' && src[i] != '_')
901 { errormsg="Application protocol name must contain only letters, digits, and hyphens"; goto fail; }
902 for (i=0; i<=len; i++) *dst++ = *src++;
903
904 len = *src;
905 if (!(len == 4 && src[1] == '_' &&
906 (((src[2] | 0x20) == 'u' && (src[3] | 0x20) == 'd') || ((src[2] | 0x20) == 't' && (src[3] | 0x20) == 'c')) &&
907 (src[4] | 0x20) == 'p'))
908 { errormsg="Transport protocol name must be _udp or _tcp"; goto fail; }
909 for (i=0; i<=len; i++) *dst++ = *src++;
910
911 if (*src) { errormsg="Service type must have only two labels"; goto fail; }
912
913 *dst = 0;
914 if (!domain->c[0]) { errormsg="Service domain must be non-empty"; goto fail; }
915 if (SameDomainName(domain, (domainname*)"\x05" "local" "\x04" "arpa"))
916 { errormsg="Illegal domain \"local.arpa.\" Use \"local.\" (or empty string)"; goto fail; }
917 dst = AppendDomainName(fqdn, domain);
918 if (!dst) { errormsg="Service domain too long"; goto fail; }
919 return(dst);
920
921 fail:
922 LogMsg("ConstructServiceName: %s: %#s.%##s%##s", errormsg, name->c, type->c, domain->c);
923 return(mDNSNULL);
924 }
925
926 // A service name has the form: instance.application-protocol.transport-protocol.domain
927 // DeconstructServiceName is currently fairly forgiving: It doesn't try to enforce character
928 // set or length limits for the protocol names, and the final domain is allowed to be empty.
929 // However, if the given FQDN doesn't contain at least three labels,
930 // DeconstructServiceName will reject it and return mDNSfalse.
931 mDNSexport mDNSBool DeconstructServiceName(const domainname *const fqdn,
932 domainlabel *const name, domainname *const type, domainname *const domain)
933 {
934 int i, len;
935 const mDNSu8 *src = fqdn->c;
936 const mDNSu8 *max = fqdn->c + MAX_DOMAIN_NAME;
937 mDNSu8 *dst;
938
939 dst = name->c; // Extract the service name
940 len = *src;
941 if (!len) { debugf("DeconstructServiceName: FQDN empty!"); return(mDNSfalse); }
942 if (len >= 0x40) { debugf("DeconstructServiceName: Instance name too long"); return(mDNSfalse); }
943 for (i=0; i<=len; i++) *dst++ = *src++;
944
945 dst = type->c; // Extract the service type
946 len = *src;
947 if (!len) { debugf("DeconstructServiceName: FQDN contains only one label!"); return(mDNSfalse); }
948 if (len >= 0x40) { debugf("DeconstructServiceName: Application protocol name too long"); return(mDNSfalse); }
949 for (i=0; i<=len; i++) *dst++ = *src++;
950
951 len = *src;
952 if (!len) { debugf("DeconstructServiceName: FQDN contains only two labels!"); return(mDNSfalse); }
953 if (len >= 0x40) { debugf("DeconstructServiceName: Transport protocol name too long"); return(mDNSfalse); }
954 for (i=0; i<=len; i++) *dst++ = *src++;
955 *dst++ = 0; // Put terminator on the end of service type
956
957 dst = domain->c; // Extract the service domain
958 while (*src)
959 {
960 len = *src;
961 if (len >= 0x40)
962 { debugf("DeconstructServiceName: Label in service domain too long"); return(mDNSfalse); }
963 if (src + 1 + len + 1 >= max)
964 { debugf("DeconstructServiceName: Total service domain too long"); return(mDNSfalse); }
965 for (i=0; i<=len; i++) *dst++ = *src++;
966 }
967 *dst++ = 0; // Put the null root label on the end
968
969 return(mDNStrue);
970 }
971
972 // Notes on UTF-8:
973 // 0xxxxxxx represents a 7-bit ASCII value from 0x00 to 0x7F
974 // 10xxxxxx is a continuation byte of a multi-byte character
975 // 110xxxxx is the first byte of a 2-byte character (11 effective bits; values 0x 80 - 0x 800-1)
976 // 1110xxxx is the first byte of a 3-byte character (16 effective bits; values 0x 800 - 0x 10000-1)
977 // 11110xxx is the first byte of a 4-byte character (21 effective bits; values 0x 10000 - 0x 200000-1)
978 // 111110xx is the first byte of a 5-byte character (26 effective bits; values 0x 200000 - 0x 4000000-1)
979 // 1111110x is the first byte of a 6-byte character (31 effective bits; values 0x4000000 - 0x80000000-1)
980 //
981 // UTF-16 surrogate pairs are used in UTF-16 to encode values larger than 0xFFFF.
982 // Although UTF-16 surrogate pairs are not supposed to appear in legal UTF-8, we want to be defensive
983 // about that too. (See <http://www.unicode.org/faq/utf_bom.html#34>, "What are surrogates?")
984 // The first of pair is a UTF-16 value in the range 0xD800-0xDBFF (11101101 1010xxxx 10xxxxxx in UTF-8),
985 // and the second is a UTF-16 value in the range 0xDC00-0xDFFF (11101101 1011xxxx 10xxxxxx in UTF-8).
986
987 mDNSexport mDNSu32 TruncateUTF8ToLength(mDNSu8 *string, mDNSu32 length, mDNSu32 max)
988 {
989 if (length > max)
990 {
991 mDNSu8 c1 = string[max]; // First byte after cut point
992 mDNSu8 c2 = (max+1 < length) ? string[max+1] : 0xB0; // Second byte after cut point
993 length = max; // Trim length down
994 while (length > 0)
995 {
996 // Check if the byte right after the chop point is a UTF-8 continuation byte,
997 // or if the character right after the chop point is the second of a UTF-16 surrogate pair.
998 // If so, then we continue to chop more bytes until we get to a legal chop point.
999 mDNSBool continuation = ((c1 & 0xC0) == 0x80);
1000 mDNSBool secondsurrogate = (c1 == 0xED && (c2 & 0xF0) == 0xB0);
1001 if (!continuation && !secondsurrogate) break;
1002 c2 = c1;
1003 c1 = string[--length];
1004 }
1005 // Having truncated characters off the end of our string, also cut off any residual white space
1006 while (length > 0 && string[length-1] <= ' ') length--;
1007 }
1008 return(length);
1009 }
1010
1011 // Returns true if a rich text label ends in " (nnn)", or if an RFC 1034
1012 // name ends in "-nnn", where n is some decimal number.
1013 mDNSexport mDNSBool LabelContainsSuffix(const domainlabel *const name, const mDNSBool RichText)
1014 {
1015 mDNSu16 l = name->c[0];
1016
1017 if (RichText)
1018 {
1019 if (l < 4) return mDNSfalse; // Need at least " (2)"
1020 if (name->c[l--] != ')') return mDNSfalse; // Last char must be ')'
1021 if (!mdnsIsDigit(name->c[l])) return mDNSfalse; // Preceeded by a digit
1022 l--;
1023 while (l > 2 && mdnsIsDigit(name->c[l])) l--; // Strip off digits
1024 return (name->c[l] == '(' && name->c[l - 1] == ' ');
1025 }
1026 else
1027 {
1028 if (l < 2) return mDNSfalse; // Need at least "-2"
1029 if (!mdnsIsDigit(name->c[l])) return mDNSfalse; // Last char must be a digit
1030 l--;
1031 while (l > 2 && mdnsIsDigit(name->c[l])) l--; // Strip off digits
1032 return (name->c[l] == '-');
1033 }
1034 }
1035
1036 // removes an auto-generated suffix (appended on a name collision) from a label. caller is
1037 // responsible for ensuring that the label does indeed contain a suffix. returns the number
1038 // from the suffix that was removed.
1039 mDNSexport mDNSu32 RemoveLabelSuffix(domainlabel *name, mDNSBool RichText)
1040 {
1041 mDNSu32 val = 0, multiplier = 1;
1042
1043 // Chop closing parentheses from RichText suffix
1044 if (RichText && name->c[0] >= 1 && name->c[name->c[0]] == ')') name->c[0]--;
1045
1046 // Get any existing numerical suffix off the name
1047 while (mdnsIsDigit(name->c[name->c[0]]))
1048 { val += (name->c[name->c[0]] - '0') * multiplier; multiplier *= 10; name->c[0]--; }
1049
1050 // Chop opening parentheses or dash from suffix
1051 if (RichText)
1052 {
1053 if (name->c[0] >= 2 && name->c[name->c[0]] == '(' && name->c[name->c[0]-1] == ' ') name->c[0] -= 2;
1054 }
1055 else
1056 {
1057 if (name->c[0] >= 1 && name->c[name->c[0]] == '-') name->c[0] -= 1;
1058 }
1059
1060 return(val);
1061 }
1062
1063 // appends a numerical suffix to a label, with the number following a whitespace and enclosed
1064 // in parentheses (rich text) or following two consecutive hyphens (RFC 1034 domain label).
1065 mDNSexport void AppendLabelSuffix(domainlabel *name, mDNSu32 val, mDNSBool RichText)
1066 {
1067 mDNSu32 divisor = 1, chars = 2; // Shortest possible RFC1034 name suffix is 2 characters ("-2")
1068 if (RichText) chars = 4; // Shortest possible RichText suffix is 4 characters (" (2)")
1069
1070 // Truncate trailing spaces from RichText names
1071 if (RichText) while (name->c[name->c[0]] == ' ') name->c[0]--;
1072
1073 while (val >= divisor * 10) { divisor *= 10; chars++; }
1074
1075 name->c[0] = (mDNSu8) TruncateUTF8ToLength(name->c+1, name->c[0], MAX_DOMAIN_LABEL - chars);
1076
1077 if (RichText) { name->c[++name->c[0]] = ' '; name->c[++name->c[0]] = '('; }
1078 else { name->c[++name->c[0]] = '-'; }
1079
1080 while (divisor)
1081 {
1082 name->c[++name->c[0]] = (mDNSu8)('0' + val / divisor);
1083 val %= divisor;
1084 divisor /= 10;
1085 }
1086
1087 if (RichText) name->c[++name->c[0]] = ')';
1088 }
1089
1090 mDNSexport void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText)
1091 {
1092 mDNSu32 val = 0;
1093
1094 if (LabelContainsSuffix(name, RichText))
1095 val = RemoveLabelSuffix(name, RichText);
1096
1097 // If no existing suffix, start by renaming "Foo" as "Foo (2)" or "Foo-2" as appropriate.
1098 // If existing suffix in the range 2-9, increment it.
1099 // If we've had ten conflicts already, there are probably too many hosts trying to use the same name,
1100 // so add a random increment to improve the chances of finding an available name next time.
1101 if (val == 0) val = 2;
1102 else if (val < 10) val++;
1103 else val += 1 + mDNSRandom(99);
1104
1105 AppendLabelSuffix(name, val, RichText);
1106 }
1107
1108 // ***************************************************************************
1109 #if COMPILER_LIKES_PRAGMA_MARK
1110 #pragma mark -
1111 #pragma mark - Resource Record Utility Functions
1112 #endif
1113
1114 mDNSexport mDNSu32 RDataHashValue(mDNSu16 const rdlength, const RDataBody *const rdb)
1115 {
1116 mDNSu32 sum = 0;
1117 int i;
1118 for (i=0; i+1 < rdlength; i+=2)
1119 {
1120 sum += (((mDNSu32)(rdb->data[i])) << 8) | rdb->data[i+1];
1121 sum = (sum<<3) | (sum>>29);
1122 }
1123 if (i < rdlength)
1124 {
1125 sum += ((mDNSu32)(rdb->data[i])) << 8;
1126 }
1127 return(sum);
1128 }
1129
1130 // r1 has to be a full ResourceRecord including rrtype and rdlength
1131 // r2 is just a bare RDataBody, which MUST be the same rrtype and rdlength as r1
1132 mDNSexport mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2)
1133 {
1134 switch(r1->rrtype)
1135 {
1136 case kDNSType_CNAME:// Same as PTR
1137 case kDNSType_PTR: return(SameDomainName(&r1->rdata->u.name, &r2->name));
1138
1139 case kDNSType_SRV: return(mDNSBool)( r1->rdata->u.srv.priority == r2->srv.priority &&
1140 r1->rdata->u.srv.weight == r2->srv.weight &&
1141 r1->rdata->u.srv.port.NotAnInteger == r2->srv.port.NotAnInteger &&
1142 SameDomainName(&r1->rdata->u.srv.target, &r2->srv.target) );
1143
1144 default: return(mDNSPlatformMemSame(r1->rdata->u.data, r2->data, r1->rdlength));
1145 }
1146 }
1147
1148 mDNSexport mDNSBool SameRData(const ResourceRecord *const r1, const ResourceRecord *const r2)
1149 {
1150 if (r1->rrtype != r2->rrtype) return(mDNSfalse);
1151 if (r1->rdlength != r2->rdlength) return(mDNSfalse);
1152 if (r1->rdatahash != r2->rdatahash) return(mDNSfalse);
1153 return(SameRDataBody(r1, &r2->rdata->u));
1154 }
1155
1156 mDNSexport mDNSBool SameResourceRecord(ResourceRecord *r1, ResourceRecord *r2)
1157 {
1158 return (r1->namehash == r2->namehash &&
1159 r1->rrtype == r2->rrtype &&
1160 SameDomainName(r1->name, r2->name) &&
1161 SameRData(r1, r2));
1162 }
1163
1164 mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
1165 {
1166 if (rr->InterfaceID &&
1167 q ->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly &&
1168 rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
1169
1170 // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
1171 if (rr->rrtype != kDNSType_CNAME && rr->rrtype != q->qtype && q->qtype != kDNSQType_ANY ) return(mDNSfalse);
1172 if ( rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
1173 return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
1174 }
1175
1176 mDNSexport mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate)
1177 {
1178 const RDataBody *rd = &rr->rdata->u;
1179 const domainname *const name = estimate ? rr->name : mDNSNULL;
1180 switch (rr->rrtype)
1181 {
1182 case kDNSType_A: return(sizeof(rd->ipv4));
1183 case kDNSType_CNAME:// Same as PTR
1184 case kDNSType_NS: // Same as PTR
1185 case kDNSType_PTR: return(CompressedDomainNameLength(&rd->name, name));
1186 case kDNSType_HINFO:return(mDNSu16)(2 + (int)rd->data[0] + (int)rd->data[1 + (int)rd->data[0]]);
1187 case kDNSType_NULL: // Same as TXT -- not self-describing, so have to just trust rdlength
1188 case kDNSType_TXT: return(rr->rdlength); // TXT is not self-describing, so have to just trust rdlength
1189 case kDNSType_AAAA: return(sizeof(rd->ipv6));
1190 case kDNSType_SRV: return(mDNSu16)(6 + CompressedDomainNameLength(&rd->srv.target, name));
1191 case kDNSType_SOA: return (mDNSu16)(CompressedDomainNameLength(&rd->soa.mname, name) +
1192 CompressedDomainNameLength(&rd->soa.rname, name) +
1193 5 * sizeof(mDNSOpaque32));
1194 case kDNSType_OPT: return(rr->rdlength);
1195 default: debugf("Warning! Don't know how to get length of resource type %d", rr->rrtype);
1196 return(rr->rdlength);
1197 }
1198 }
1199
1200 mDNSexport mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd)
1201 {
1202 mDNSu16 len;
1203
1204 switch(rrtype)
1205 {
1206 case kDNSType_A: return(rdlength == sizeof(mDNSv4Addr));
1207
1208 case kDNSType_NS: // Same as PTR
1209 case kDNSType_MD: // Same as PTR
1210 case kDNSType_MF: // Same as PTR
1211 case kDNSType_CNAME:// Same as PTR
1212 //case kDNSType_SOA not checked
1213 case kDNSType_MB: // Same as PTR
1214 case kDNSType_MG: // Same as PTR
1215 case kDNSType_MR: // Same as PTR
1216 //case kDNSType_NULL not checked (no specified format, so always valid)
1217 //case kDNSType_WKS not checked
1218 case kDNSType_PTR: if (!rdlength) return(mDNSfalse);
1219 len = DomainNameLength(&rd->u.name);
1220 return(len <= MAX_DOMAIN_NAME && rdlength == len);
1221
1222 case kDNSType_HINFO:// Same as TXT (roughly)
1223 case kDNSType_MINFO:// Same as TXT (roughly)
1224 case kDNSType_TXT: if (!rdlength) return(mDNSfalse); // TXT record has to be at least one byte (RFC 1035)
1225 {
1226 const mDNSu8 *ptr = rd->u.txt.c;
1227 const mDNSu8 *end = rd->u.txt.c + rdlength;
1228 while (ptr < end) ptr += 1 + ptr[0];
1229 return (ptr == end);
1230 }
1231
1232 case kDNSType_AAAA: return(rdlength == sizeof(mDNSv6Addr));
1233
1234 case kDNSType_MX: if (!rdlength) return(mDNSfalse);
1235 len = DomainNameLength(&rd->u.mx.exchange);
1236 return(len <= MAX_DOMAIN_NAME && rdlength == 2+len);
1237
1238 case kDNSType_SRV: if (!rdlength) return(mDNSfalse);
1239 len = DomainNameLength(&rd->u.srv.target);
1240 return(len <= MAX_DOMAIN_NAME && rdlength == 6+len);
1241
1242 default: return(mDNStrue); // Allow all other types without checking
1243 }
1244 }
1245
1246 // ***************************************************************************
1247 #if COMPILER_LIKES_PRAGMA_MARK
1248 #pragma mark -
1249 #pragma mark -
1250 #pragma mark - DNS Message Creation Functions
1251 #endif
1252
1253 mDNSexport void InitializeDNSMessage(DNSMessageHeader *h, mDNSOpaque16 id, mDNSOpaque16 flags)
1254 {
1255 h->id = id;
1256 h->flags = flags;
1257 h->numQuestions = 0;
1258 h->numAnswers = 0;
1259 h->numAuthorities = 0;
1260 h->numAdditionals = 0;
1261 }
1262
1263 mDNSexport const mDNSu8 *FindCompressionPointer(const mDNSu8 *const base, const mDNSu8 *const end, const mDNSu8 *const domname)
1264 {
1265 const mDNSu8 *result = end - *domname - 1;
1266
1267 if (*domname == 0) return(mDNSNULL); // There's no point trying to match just the root label
1268
1269 // This loop examines each possible starting position in packet, starting end of the packet and working backwards
1270 while (result >= base)
1271 {
1272 // If the length byte and first character of the label match, then check further to see
1273 // if this location in the packet will yield a useful name compression pointer.
1274 if (result[0] == domname[0] && result[1] == domname[1])
1275 {
1276 const mDNSu8 *name = domname;
1277 const mDNSu8 *targ = result;
1278 while (targ + *name < end)
1279 {
1280 // First see if this label matches
1281 int i;
1282 const mDNSu8 *pointertarget;
1283 for (i=0; i <= *name; i++) if (targ[i] != name[i]) break;
1284 if (i <= *name) break; // If label did not match, bail out
1285 targ += 1 + *name; // Else, did match, so advance target pointer
1286 name += 1 + *name; // and proceed to check next label
1287 if (*name == 0 && *targ == 0) return(result); // If no more labels, we found a match!
1288 if (*name == 0) break; // If no more labels to match, we failed, so bail out
1289
1290 // The label matched, so now follow the pointer (if appropriate) and then see if the next label matches
1291 if (targ[0] < 0x40) continue; // If length value, continue to check next label
1292 if (targ[0] < 0xC0) break; // If 40-BF, not valid
1293 if (targ+1 >= end) break; // Second byte not present!
1294 pointertarget = base + (((mDNSu16)(targ[0] & 0x3F)) << 8) + targ[1];
1295 if (targ < pointertarget) break; // Pointertarget must point *backwards* in the packet
1296 if (pointertarget[0] >= 0x40) break; // Pointertarget must point to a valid length byte
1297 targ = pointertarget;
1298 }
1299 }
1300 result--; // We failed to match at this search position, so back up the tentative result pointer and try again
1301 }
1302 return(mDNSNULL);
1303 }
1304
1305 // Put a string of dot-separated labels as length-prefixed labels
1306 // domainname is a fully-qualified name (i.e. assumed to be ending in a dot, even if it doesn't)
1307 // msg points to the message we're building (pass mDNSNULL if we don't want to use compression pointers)
1308 // end points to the end of the message so far
1309 // ptr points to where we want to put the name
1310 // limit points to one byte past the end of the buffer that we must not overrun
1311 // domainname is the name to put
1312 mDNSexport mDNSu8 *putDomainNameAsLabels(const DNSMessage *const msg,
1313 mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name)
1314 {
1315 const mDNSu8 *const base = (const mDNSu8 *)msg;
1316 const mDNSu8 * np = name->c;
1317 const mDNSu8 *const max = name->c + MAX_DOMAIN_NAME; // Maximum that's valid
1318 const mDNSu8 * pointer = mDNSNULL;
1319 const mDNSu8 *const searchlimit = ptr;
1320
1321 while (*np && ptr < limit-1) // While we've got characters in the name, and space to write them in the message...
1322 {
1323 if (*np > MAX_DOMAIN_LABEL)
1324 { LogMsg("Malformed domain name %##s (label more than 63 bytes)", name->c); return(mDNSNULL); }
1325
1326 // This check correctly allows for the final trailing root label:
1327 // e.g.
1328 // Suppose our domain name is exactly 255 bytes long, including the final trailing root label.
1329 // Suppose np is now at name->c[248], and we're about to write our last non-null label ("local").
1330 // We know that max will be at name->c[255]
1331 // That means that np + 1 + 5 == max - 1, so we (just) pass the "if" test below, write our
1332 // six bytes, then exit the loop, write the final terminating root label, and the domain
1333 // name we've written is exactly 255 bytes long, exactly at the correct legal limit.
1334 // If the name is one byte longer, then we fail the "if" test below, and correctly bail out.
1335 if (np + 1 + *np >= max)
1336 { LogMsg("Malformed domain name %##s (more than 255 bytes)", name->c); return(mDNSNULL); }
1337
1338 if (base) pointer = FindCompressionPointer(base, searchlimit, np);
1339 if (pointer) // Use a compression pointer if we can
1340 {
1341 mDNSu16 offset = (mDNSu16)(pointer - base);
1342 *ptr++ = (mDNSu8)(0xC0 | (offset >> 8));
1343 *ptr++ = (mDNSu8)( offset & 0xFF);
1344 return(ptr);
1345 }
1346 else // Else copy one label and try again
1347 {
1348 int i;
1349 mDNSu8 len = *np++;
1350 if (ptr + 1 + len >= limit) return(mDNSNULL);
1351 *ptr++ = len;
1352 for (i=0; i<len; i++) *ptr++ = *np++;
1353 }
1354 }
1355
1356 if (ptr < limit) // If we didn't run out of space
1357 {
1358 *ptr++ = 0; // Put the final root label
1359 return(ptr); // and return
1360 }
1361
1362 return(mDNSNULL);
1363 }
1364
1365 mDNSlocal mDNSu8 *putVal16(mDNSu8 *ptr, mDNSu16 val)
1366 {
1367 ptr[0] = (mDNSu8)((val >> 8 ) & 0xFF);
1368 ptr[1] = (mDNSu8)((val ) & 0xFF);
1369 return ptr + sizeof(mDNSOpaque16);
1370 }
1371
1372 mDNSlocal mDNSu8 *putVal32(mDNSu8 *ptr, mDNSu32 val)
1373 {
1374 ptr[0] = (mDNSu8)((val >> 24) & 0xFF);
1375 ptr[1] = (mDNSu8)((val >> 16) & 0xFF);
1376 ptr[2] = (mDNSu8)((val >> 8) & 0xFF);
1377 ptr[3] = (mDNSu8)((val ) & 0xFF);
1378 return ptr + sizeof(mDNSu32);
1379 }
1380
1381 mDNSlocal mDNSu8 *putOptRData(mDNSu8 *ptr, const mDNSu8 *limit, ResourceRecord *rr)
1382 {
1383 int nput = 0;
1384 rdataOpt *opt;
1385
1386 while (nput < rr->rdlength)
1387 {
1388 // check if space for opt/optlen
1389 if (ptr + (2 * sizeof(mDNSu16)) > limit) goto space_err;
1390 opt = (rdataOpt *)(rr->rdata->u.data + nput);
1391 ptr = putVal16(ptr, opt->opt);
1392 ptr = putVal16(ptr, opt->optlen);
1393 nput += 2 * sizeof(mDNSu16);
1394 if (opt->opt == kDNSOpt_LLQ)
1395 {
1396 if (ptr + LLQ_OPTLEN > limit) goto space_err;
1397 ptr = putVal16(ptr, opt->OptData.llq.vers);
1398 ptr = putVal16(ptr, opt->OptData.llq.llqOp);
1399 ptr = putVal16(ptr, opt->OptData.llq.err);
1400 mDNSPlatformMemCopy(opt->OptData.llq.id, ptr, 8); // 8-byte id
1401 ptr += 8;
1402 ptr = putVal32(ptr, opt->OptData.llq.lease);
1403 nput += LLQ_OPTLEN;
1404 }
1405 else if (opt->opt == kDNSOpt_Lease)
1406 {
1407 if (ptr + sizeof(mDNSs32) > limit) goto space_err;
1408 ptr = putVal32(ptr, opt->OptData.lease);
1409 nput += sizeof(mDNSs32);
1410 }
1411 else { LogMsg("putOptRData - unknown option %d", opt->opt); return mDNSNULL; }
1412 }
1413
1414 return ptr;
1415
1416 space_err:
1417 LogMsg("ERROR: putOptRData - out of space");
1418 return mDNSNULL;
1419 }
1420
1421 mDNSlocal mDNSu16 getVal16(const mDNSu8 **ptr)
1422 {
1423 mDNSu16 val = (mDNSu16)(((mDNSu16)(*ptr)[0]) << 8 | (*ptr)[1]);
1424 *ptr += sizeof(mDNSOpaque16);
1425 return val;
1426 }
1427
1428 mDNSlocal const mDNSu8 *getOptRdata(const mDNSu8 *ptr, const mDNSu8 *const limit, LargeCacheRecord *const cr, mDNSu16 pktRDLen)
1429 {
1430 int nread = 0;
1431 ResourceRecord *const rr = &cr->r.resrec;
1432 rdataOpt *opt = (rdataOpt *)rr->rdata->u.data;
1433
1434 while (nread < pktRDLen && (mDNSu8 *)opt < rr->rdata->u.data + MaximumRDSize - sizeof(rdataOpt))
1435 {
1436 // space for opt + optlen
1437 if (nread + (2 * sizeof(mDNSu16)) > rr->rdata->MaxRDLength) goto space_err;
1438 opt->opt = getVal16(&ptr);
1439 opt->optlen = getVal16(&ptr);
1440 nread += 2 * sizeof(mDNSu16);
1441 if (opt->opt == kDNSOpt_LLQ)
1442 {
1443 if ((unsigned)(limit - ptr) < LLQ_OPTLEN) goto space_err;
1444 opt->OptData.llq.vers = getVal16(&ptr);
1445 opt->OptData.llq.llqOp = getVal16(&ptr);
1446 opt->OptData.llq.err = getVal16(&ptr);
1447 mDNSPlatformMemCopy(ptr, opt->OptData.llq.id, 8);
1448 ptr += 8;
1449 opt->OptData.llq.lease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
1450 if (opt->OptData.llq.lease > 0x70000000UL / mDNSPlatformOneSecond)
1451 opt->OptData.llq.lease = 0x70000000UL / mDNSPlatformOneSecond;
1452 ptr += sizeof(mDNSOpaque32);
1453 nread += LLQ_OPTLEN;
1454 }
1455 else if (opt->opt == kDNSOpt_Lease)
1456 {
1457 if ((unsigned)(limit - ptr) < sizeof(mDNSs32)) goto space_err;
1458
1459 opt->OptData.lease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
1460 if (opt->OptData.lease > 0x70000000UL / mDNSPlatformOneSecond)
1461 opt->OptData.lease = 0x70000000UL / mDNSPlatformOneSecond;
1462 ptr += sizeof(mDNSs32);
1463 nread += sizeof(mDNSs32);
1464 }
1465 else { LogMsg("ERROR: getOptRdata - unknown opt %d", opt->opt); return mDNSNULL; }
1466 opt++; // increment pointer into rdatabody
1467 }
1468
1469 rr->rdlength = pktRDLen;
1470 return ptr;
1471
1472 space_err:
1473 LogMsg("ERROR: getLLQRdata - out of space");
1474 return mDNSNULL;
1475 }
1476
1477 mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, ResourceRecord *rr)
1478 {
1479 switch (rr->rrtype)
1480 {
1481 case kDNSType_A: if (rr->rdlength != 4)
1482 {
1483 debugf("putRData: Illegal length %d for kDNSType_A", rr->rdlength);
1484 return(mDNSNULL);
1485 }
1486 if (ptr + 4 > limit) return(mDNSNULL);
1487 *ptr++ = rr->rdata->u.ipv4.b[0];
1488 *ptr++ = rr->rdata->u.ipv4.b[1];
1489 *ptr++ = rr->rdata->u.ipv4.b[2];
1490 *ptr++ = rr->rdata->u.ipv4.b[3];
1491 return(ptr);
1492
1493 case kDNSType_CNAME:// Same as PTR
1494 case kDNSType_PTR: return(putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.name));
1495
1496 case kDNSType_AAAA: if (rr->rdlength != sizeof(rr->rdata->u.ipv6))
1497 {
1498 debugf("putRData: Illegal length %d for kDNSType_AAAA", rr->rdlength);
1499 return(mDNSNULL);
1500 }
1501 if (ptr + sizeof(rr->rdata->u.ipv6) > limit) return(mDNSNULL);
1502 mDNSPlatformMemCopy(&rr->rdata->u.ipv6, ptr, sizeof(rr->rdata->u.ipv6));
1503 return(ptr + sizeof(rr->rdata->u.ipv6));
1504
1505 case kDNSType_SRV: if (ptr + 6 > limit) return(mDNSNULL);
1506 *ptr++ = (mDNSu8)(rr->rdata->u.srv.priority >> 8);
1507 *ptr++ = (mDNSu8)(rr->rdata->u.srv.priority & 0xFF);
1508 *ptr++ = (mDNSu8)(rr->rdata->u.srv.weight >> 8);
1509 *ptr++ = (mDNSu8)(rr->rdata->u.srv.weight & 0xFF);
1510 *ptr++ = rr->rdata->u.srv.port.b[0];
1511 *ptr++ = rr->rdata->u.srv.port.b[1];
1512 return(putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.srv.target));
1513 case kDNSType_OPT: return putOptRData(ptr, limit, rr);
1514
1515 default: debugf("putRData: Warning! Writing unknown resource type %d as raw data", rr->rrtype);
1516 // Fall through to common code below
1517 case kDNSType_HINFO:
1518 case kDNSType_TXT:
1519 case kDNSType_TSIG: if (ptr + rr->rdlength > limit) return(mDNSNULL);
1520 mDNSPlatformMemCopy(rr->rdata->u.data, ptr, rr->rdlength);
1521 return(ptr + rr->rdlength);
1522 }
1523 }
1524
1525 mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 ttl, const mDNSu8 *limit)
1526 {
1527 mDNSu8 *endofrdata;
1528 mDNSu16 actualLength;
1529
1530 if (rr->RecordType == kDNSRecordTypeUnregistered)
1531 {
1532 LogMsg("PutResourceRecord ERROR! Attempt to put kDNSRecordTypeUnregistered %##s (%s)", rr->name->c, DNSTypeName(rr->rrtype));
1533 return(ptr);
1534 }
1535
1536 ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name);
1537 if (!ptr || ptr + 10 >= limit) return(mDNSNULL); // If we're out-of-space, return mDNSNULL
1538 ptr[0] = (mDNSu8)(rr->rrtype >> 8);
1539 ptr[1] = (mDNSu8)(rr->rrtype & 0xFF);
1540 ptr[2] = (mDNSu8)(rr->rrclass >> 8);
1541 ptr[3] = (mDNSu8)(rr->rrclass & 0xFF);
1542 ptr[4] = (mDNSu8)((ttl >> 24) & 0xFF);
1543 ptr[5] = (mDNSu8)((ttl >> 16) & 0xFF);
1544 ptr[6] = (mDNSu8)((ttl >> 8) & 0xFF);
1545 ptr[7] = (mDNSu8)( ttl & 0xFF);
1546 endofrdata = putRData(msg, ptr+10, limit, rr);
1547 if (!endofrdata) { verbosedebugf("Ran out of space in PutResourceRecord for %##s (%s)", rr->name->c, DNSTypeName(rr->rrtype)); return(mDNSNULL); }
1548
1549 // Go back and fill in the actual number of data bytes we wrote
1550 // (actualLength can be less than rdlength when domain name compression is used)
1551 actualLength = (mDNSu16)(endofrdata - ptr - 10);
1552 ptr[8] = (mDNSu8)(actualLength >> 8);
1553 ptr[9] = (mDNSu8)(actualLength & 0xFF);
1554
1555 if (count) (*count)++;
1556 else LogMsg("PutResourceRecordTTL: ERROR: No target count to update for %##s (%s)", rr->name->c, DNSTypeName(rr->rrtype));
1557 return(endofrdata);
1558 }
1559
1560 mDNSexport mDNSu8 *PutResourceRecordCappedTTL(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32
1561 maxttl)
1562 {
1563 if (maxttl > rr->rroriginalttl) maxttl = rr->rroriginalttl;
1564 return(PutResourceRecordTTL(msg, ptr, count, rr, maxttl));
1565 }
1566
1567 mDNSexport mDNSu8 *putEmptyResourceRecord(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit,
1568 mDNSu16 *count, const AuthRecord *rr)
1569 {
1570 ptr = putDomainNameAsLabels(msg, ptr, limit, rr->resrec.name);
1571 if (!ptr || ptr + 10 > limit) return(mDNSNULL); // If we're out-of-space, return mDNSNULL
1572 ptr[0] = (mDNSu8)(rr->resrec.rrtype >> 8); // Put type
1573 ptr[1] = (mDNSu8)(rr->resrec.rrtype & 0xFF);
1574 ptr[2] = (mDNSu8)(rr->resrec.rrclass >> 8); // Put class
1575 ptr[3] = (mDNSu8)(rr->resrec.rrclass & 0xFF);
1576 ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // TTL is zero
1577 ptr[8] = ptr[9] = 0; // RDATA length is zero
1578 (*count)++;
1579 return(ptr + 10);
1580 }
1581
1582 mDNSexport mDNSu8 *putQuestion(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name, mDNSu16 rrtype, mDNSu16 rrclass)
1583 {
1584 ptr = putDomainNameAsLabels(msg, ptr, limit, name);
1585 if (!ptr || ptr+4 >= limit) return(mDNSNULL); // If we're out-of-space, return mDNSNULL
1586 ptr[0] = (mDNSu8)(rrtype >> 8);
1587 ptr[1] = (mDNSu8)(rrtype & 0xFF);
1588 ptr[2] = (mDNSu8)(rrclass >> 8);
1589 ptr[3] = (mDNSu8)(rrclass & 0xFF);
1590 msg->h.numQuestions++;
1591 return(ptr+4);
1592 }
1593
1594 // for dynamic updates
1595 mDNSexport mDNSu8 *putZone(DNSMessage *const msg, mDNSu8 *ptr, mDNSu8 *limit, const domainname *zone, mDNSOpaque16 zoneClass)
1596 {
1597 ptr = putDomainNameAsLabels(msg, ptr, limit, zone);
1598 if (!ptr || ptr + 4 > limit) return mDNSNULL; // If we're out-of-space, return NULL
1599 *ptr++ = (mDNSu8)(kDNSType_SOA >> 8);
1600 *ptr++ = (mDNSu8)(kDNSType_SOA & 0xFF);
1601 *ptr++ = zoneClass.b[0];
1602 *ptr++ = zoneClass.b[1];
1603 msg->h.mDNS_numZones++;
1604 return ptr;
1605 }
1606
1607 // for dynamic updates
1608 mDNSexport mDNSu8 *putPrereqNameNotInUse(domainname *name, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *end)
1609 {
1610 AuthRecord prereq;
1611
1612 mDNSPlatformMemZero(&prereq, sizeof(AuthRecord));
1613 mDNS_SetupResourceRecord(&prereq, mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, mDNSNULL, mDNSNULL);
1614 AssignDomainName(prereq.resrec.name, name);
1615 prereq.resrec.rrtype = kDNSQType_ANY;
1616 prereq.resrec.rrclass = kDNSClass_NONE;
1617 ptr = putEmptyResourceRecord(msg, ptr, end, &msg->h.mDNS_numPrereqs, &prereq);
1618 return ptr;
1619 }
1620
1621 // for dynamic updates
1622 mDNSexport mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr)
1623 {
1624 mDNSu16 origclass;
1625 // deletion: specify record w/ TTL 0, class NONE
1626
1627 origclass = rr->rrclass;
1628 rr->rrclass = kDNSClass_NONE;
1629 ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.mDNS_numUpdates, rr, 0);
1630 rr->rrclass = origclass;
1631 return ptr;
1632 }
1633
1634 mDNSexport mDNSu8 *putDeleteRRSet(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype)
1635 {
1636 const mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;
1637 mDNSu16 class = kDNSQClass_ANY;
1638
1639 ptr = putDomainNameAsLabels(msg, ptr, limit, name);
1640 if (!ptr || ptr + 10 >= limit) return mDNSNULL; // If we're out-of-space, return mDNSNULL
1641 ptr[0] = (mDNSu8)(rrtype >> 8);
1642 ptr[1] = (mDNSu8)(rrtype & 0xFF);
1643 ptr[2] = (mDNSu8)(class >> 8);
1644 ptr[3] = (mDNSu8)(class & 0xFF);
1645 ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // zero ttl
1646 ptr[8] = ptr[9] = 0; // zero rdlength/rdata
1647
1648 msg->h.mDNS_numUpdates++;
1649 return ptr + 10;
1650 }
1651
1652 // for dynamic updates
1653 mDNSexport mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domainname *name)
1654 {
1655 const mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;
1656 mDNSu16 class = kDNSQClass_ANY;
1657 mDNSu16 rrtype = kDNSQType_ANY;
1658
1659 ptr = putDomainNameAsLabels(msg, ptr, limit, name);
1660 if (!ptr || ptr + 10 >= limit) return mDNSNULL; // If we're out-of-space, return mDNSNULL
1661 ptr[0] = (mDNSu8)(rrtype >> 8);
1662 ptr[1] = (mDNSu8)(rrtype & 0xFF);
1663 ptr[2] = (mDNSu8)(class >> 8);
1664 ptr[3] = (mDNSu8)(class & 0xFF);
1665 ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // zero ttl
1666 ptr[8] = ptr[9] = 0; // zero rdlength/rdata
1667
1668 msg->h.mDNS_numUpdates++;
1669 return ptr + 10;
1670 }
1671
1672 // for dynamic updates
1673 mDNSexport mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease)
1674 {
1675 AuthRecord rr;
1676 ResourceRecord *opt = &rr.resrec;
1677 rdataOpt *optRD;
1678
1679 mDNSPlatformMemZero(&rr, sizeof(AuthRecord));
1680 mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, 0, mDNSNULL, mDNSNULL);
1681
1682 opt->RecordType = kDNSRecordTypeKnownUnique; // to avoid warnings in other layers
1683 opt->rrtype = kDNSType_OPT;
1684 opt->rdlength = LEASE_OPT_RDLEN;
1685 opt->rdestimate = LEASE_OPT_RDLEN;
1686
1687 optRD = &rr.resrec.rdata->u.opt;
1688 optRD->opt = kDNSOpt_Lease;
1689 optRD->optlen = sizeof(mDNSs32);
1690 optRD->OptData.lease = lease;
1691 end = PutResourceRecordTTLJumbo(msg, end, &msg->h.numAdditionals, opt, 0);
1692 if (!end) { LogMsg("ERROR: putUpdateLease - PutResourceRecordTTL"); return mDNSNULL; }
1693
1694 return end;
1695 }
1696
1697 // ***************************************************************************
1698 #if COMPILER_LIKES_PRAGMA_MARK
1699 #pragma mark -
1700 #pragma mark - DNS Message Parsing Functions
1701 #endif
1702
1703 mDNSexport mDNSu32 DomainNameHashValue(const domainname *const name)
1704 {
1705 mDNSu32 sum = 0;
1706 const mDNSu8 *c;
1707
1708 for (c = name->c; c[0] != 0 && c[1] != 0; c += 2)
1709 {
1710 sum += ((mDNSIsUpperCase(c[0]) ? c[0] + 'a' - 'A' : c[0]) << 8) |
1711 (mDNSIsUpperCase(c[1]) ? c[1] + 'a' - 'A' : c[1]);
1712 sum = (sum<<3) | (sum>>29);
1713 }
1714 if (c[0]) sum += ((mDNSIsUpperCase(c[0]) ? c[0] + 'a' - 'A' : c[0]) << 8);
1715 return(sum);
1716 }
1717
1718 mDNSexport void SetNewRData(ResourceRecord *const rr, RData *NewRData, mDNSu16 rdlength)
1719 {
1720 domainname *target;
1721 if (NewRData)
1722 {
1723 rr->rdata = NewRData;
1724 rr->rdlength = rdlength;
1725 }
1726 // Must not try to get target pointer until after updating rr->rdata
1727 target = GetRRDomainNameTarget(rr);
1728 rr->rdlength = GetRDLength(rr, mDNSfalse);
1729 rr->rdestimate = GetRDLength(rr, mDNStrue);
1730 rr->rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(rr->rdlength, &rr->rdata->u);
1731 }
1732
1733 mDNSexport const mDNSu8 *skipDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end)
1734 {
1735 mDNSu16 total = 0;
1736
1737 if (ptr < (mDNSu8*)msg || ptr >= end)
1738 { debugf("skipDomainName: Illegal ptr not within packet boundaries"); return(mDNSNULL); }
1739
1740 while (1) // Read sequence of labels
1741 {
1742 const mDNSu8 len = *ptr++; // Read length of this label
1743 if (len == 0) return(ptr); // If length is zero, that means this name is complete
1744 switch (len & 0xC0)
1745 {
1746 case 0x00: if (ptr + len >= end) // Remember: expect at least one more byte for the root label
1747 { debugf("skipDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); }
1748 if (total + 1 + len >= MAX_DOMAIN_NAME) // Remember: expect at least one more byte for the root label
1749 { debugf("skipDomainName: Malformed domain name (more than 255 characters)"); return(mDNSNULL); }
1750 ptr += len;
1751 total += 1 + len;
1752 break;
1753
1754 case 0x40: debugf("skipDomainName: Extended EDNS0 label types 0x%X not supported", len); return(mDNSNULL);
1755 case 0x80: debugf("skipDomainName: Illegal label length 0x%X", len); return(mDNSNULL);
1756 case 0xC0: return(ptr+1);
1757 }
1758 }
1759 }
1760
1761 // Routine to fetch an FQDN from the DNS message, following compression pointers if necessary.
1762 mDNSexport const mDNSu8 *getDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end,
1763 domainname *const name)
1764 {
1765 const mDNSu8 *nextbyte = mDNSNULL; // Record where we got to before we started following pointers
1766 mDNSu8 *np = name->c; // Name pointer
1767 const mDNSu8 *const limit = np + MAX_DOMAIN_NAME; // Limit so we don't overrun buffer
1768
1769 if (ptr < (mDNSu8*)msg || ptr >= end)
1770 { debugf("getDomainName: Illegal ptr not within packet boundaries"); return(mDNSNULL); }
1771
1772 *np = 0; // Tentatively place the root label here (may be overwritten if we have more labels)
1773
1774 while (1) // Read sequence of labels
1775 {
1776 const mDNSu8 len = *ptr++; // Read length of this label
1777 if (len == 0) break; // If length is zero, that means this name is complete
1778 switch (len & 0xC0)
1779 {
1780 int i;
1781 mDNSu16 offset;
1782
1783 case 0x00: if (ptr + len >= end) // Remember: expect at least one more byte for the root label
1784 { debugf("getDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); }
1785 if (np + 1 + len >= limit) // Remember: expect at least one more byte for the root label
1786 { debugf("getDomainName: Malformed domain name (more than 255 characters)"); return(mDNSNULL); }
1787 *np++ = len;
1788 for (i=0; i<len; i++) *np++ = *ptr++;
1789 *np = 0; // Tentatively place the root label here (may be overwritten if we have more labels)
1790 break;
1791
1792 case 0x40: debugf("getDomainName: Extended EDNS0 label types 0x%X not supported in name %##s", len, name->c);
1793 return(mDNSNULL);
1794
1795 case 0x80: debugf("getDomainName: Illegal label length 0x%X in domain name %##s", len, name->c); return(mDNSNULL);
1796
1797 case 0xC0: offset = (mDNSu16)((((mDNSu16)(len & 0x3F)) << 8) | *ptr++);
1798 if (!nextbyte) nextbyte = ptr; // Record where we got to before we started following pointers
1799 ptr = (mDNSu8 *)msg + offset;
1800 if (ptr < (mDNSu8*)msg || ptr >= end)
1801 { debugf("getDomainName: Illegal compression pointer not within packet boundaries"); return(mDNSNULL); }
1802 if (*ptr & 0xC0)
1803 { debugf("getDomainName: Compression pointer must point to real label"); return(mDNSNULL); }
1804 break;
1805 }
1806 }
1807
1808 if (nextbyte) return(nextbyte);
1809 else return(ptr);
1810 }
1811
1812 mDNSexport const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end)
1813 {
1814 mDNSu16 pktrdlength;
1815
1816 ptr = skipDomainName(msg, ptr, end);
1817 if (!ptr) { debugf("skipResourceRecord: Malformed RR name"); return(mDNSNULL); }
1818
1819 if (ptr + 10 > end) { debugf("skipResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
1820 pktrdlength = (mDNSu16)((mDNSu16)ptr[8] << 8 | ptr[9]);
1821 ptr += 10;
1822 if (ptr + pktrdlength > end) { debugf("skipResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); }
1823
1824 return(ptr + pktrdlength);
1825 }
1826
1827 mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage * const msg, const mDNSu8 *ptr,
1828 const mDNSu8 *end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *largecr)
1829 {
1830 CacheRecord *rr = &largecr->r;
1831 mDNSu16 pktrdlength;
1832
1833 if (largecr == &m->rec && largecr->r.resrec.RecordType)
1834 LogMsg("GetLargeResourceRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &largecr->r));
1835
1836 rr->next = mDNSNULL;
1837 rr->resrec.name = &largecr->namestorage;
1838
1839 rr->NextInKAList = mDNSNULL;
1840 rr->TimeRcvd = m ? m->timenow : 0;
1841 rr->DelayDelivery = 0;
1842 rr->NextRequiredQuery = m ? m->timenow : 0; // Will be updated to the real value when we call SetNextCacheCheckTime()
1843 rr->LastUsed = m ? m->timenow : 0;
1844 rr->CRActiveQuestion = mDNSNULL;
1845 rr->UnansweredQueries = 0;
1846 rr->LastUnansweredTime= 0;
1847 rr->MPUnansweredQ = 0;
1848 rr->MPLastUnansweredQT= 0;
1849 rr->MPUnansweredKA = 0;
1850 rr->MPExpectingKA = mDNSfalse;
1851 rr->NextInCFList = mDNSNULL;
1852
1853 rr->resrec.InterfaceID = InterfaceID;
1854 ptr = getDomainName(msg, ptr, end, rr->resrec.name);
1855 if (!ptr) { debugf("GetResourceRecord: Malformed RR name"); return(mDNSNULL); }
1856
1857 if (ptr + 10 > end) { debugf("GetResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
1858
1859 rr->resrec.rrtype = (mDNSu16) ((mDNSu16)ptr[0] << 8 | ptr[1]);
1860 rr->resrec.rrclass = (mDNSu16)(((mDNSu16)ptr[2] << 8 | ptr[3]) & kDNSClass_Mask);
1861 rr->resrec.rroriginalttl = (mDNSu32) ((mDNSu32)ptr[4] << 24 | (mDNSu32)ptr[5] << 16 | (mDNSu32)ptr[6] << 8 | ptr[7]);
1862 if (rr->resrec.rroriginalttl > 0x70000000UL / mDNSPlatformOneSecond && (mDNSs32)rr->resrec.rroriginalttl != -1)
1863 rr->resrec.rroriginalttl = 0x70000000UL / mDNSPlatformOneSecond;
1864 // Note: We don't have to adjust m->NextCacheCheck here -- this is just getting a record into memory for
1865 // us to look at. If we decide to copy it into the cache, then we'll update m->NextCacheCheck accordingly.
1866 pktrdlength = (mDNSu16)((mDNSu16)ptr[8] << 8 | ptr[9]);
1867 if (ptr[2] & (kDNSClass_UniqueRRSet >> 8))
1868 RecordType |= kDNSRecordTypePacketUniqueMask;
1869 ptr += 10;
1870 if (ptr + pktrdlength > end) { debugf("GetResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); }
1871 end = ptr + pktrdlength; // Adjust end to indicate the end of the rdata for this resource record
1872
1873 rr->resrec.rdata = (RData*)&rr->rdatastorage;
1874 rr->resrec.rdata->MaxRDLength = MaximumRDSize;
1875
1876 if (!RecordType) LogMsg("GetLargeResourceRecord: No RecordType for %##s", rr->resrec.name->c);
1877
1878 switch (rr->resrec.rrtype)
1879 {
1880 case kDNSType_A: rr->resrec.rdata->u.ipv4.b[0] = ptr[0];
1881 rr->resrec.rdata->u.ipv4.b[1] = ptr[1];
1882 rr->resrec.rdata->u.ipv4.b[2] = ptr[2];
1883 rr->resrec.rdata->u.ipv4.b[3] = ptr[3];
1884 break;
1885
1886 case kDNSType_CNAME:// Same as PTR
1887 case kDNSType_NS:
1888 case kDNSType_PTR: if (!getDomainName(msg, ptr, end, &rr->resrec.rdata->u.name))
1889 { debugf("GetResourceRecord: Malformed CNAME/PTR RDATA name"); return(mDNSNULL); }
1890 //debugf("%##s PTR %##s rdlen %d", rr->resrec.name.c, rr->resrec.rdata->u.name.c, pktrdlength);
1891 break;
1892
1893 case kDNSType_NULL: //Same as TXT
1894 case kDNSType_HINFO://Same as TXT
1895 case kDNSType_TXT: if (pktrdlength > rr->resrec.rdata->MaxRDLength)
1896 {
1897 debugf("GetResourceRecord: %s rdata size (%d) exceeds storage (%d)",
1898 DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength);
1899 return(mDNSNULL);
1900 }
1901 rr->resrec.rdlength = pktrdlength;
1902 mDNSPlatformMemCopy(ptr, rr->resrec.rdata->u.data, pktrdlength);
1903 break;
1904
1905 case kDNSType_AAAA: mDNSPlatformMemCopy(ptr, &rr->resrec.rdata->u.ipv6, sizeof(rr->resrec.rdata->u.ipv6));
1906 break;
1907
1908 case kDNSType_SRV: rr->resrec.rdata->u.srv.priority = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
1909 rr->resrec.rdata->u.srv.weight = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
1910 rr->resrec.rdata->u.srv.port.b[0] = ptr[4];
1911 rr->resrec.rdata->u.srv.port.b[1] = ptr[5];
1912 if (!getDomainName(msg, ptr+6, end, &rr->resrec.rdata->u.srv.target))
1913 { debugf("GetResourceRecord: Malformed SRV RDATA name"); return(mDNSNULL); }
1914 //debugf("%##s SRV %##s rdlen %d", rr->resrec.name.c, rr->resrec.rdata->u.srv.target.c, pktrdlength);
1915 break;
1916
1917 case kDNSType_SOA: ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.mname);
1918 if (!ptr) { debugf("GetResourceRecord: Malformed SOA RDATA mname"); return mDNSNULL; }
1919 ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.rname);
1920 if (!ptr) { debugf("GetResourceRecord: Malformed SOA RDATA rname"); return mDNSNULL; }
1921 if (ptr + 0x14 != end) { debugf("GetResourceRecord: Malformed SOA RDATA"); return mDNSNULL; }
1922 rr->resrec.rdata->u.soa.serial = (mDNSs32) ((mDNSs32)ptr[0x00] << 24 | (mDNSs32)ptr[0x01] << 16 | (mDNSs32)ptr[0x02] << 8 | ptr[0x03]);
1923 rr->resrec.rdata->u.soa.refresh = (mDNSu32) ((mDNSu32)ptr[0x04] << 24 | (mDNSu32)ptr[0x05] << 16 | (mDNSu32)ptr[0x06] << 8 | ptr[0x07]);
1924 rr->resrec.rdata->u.soa.retry = (mDNSu32) ((mDNSu32)ptr[0x08] << 24 | (mDNSu32)ptr[0x09] << 16 | (mDNSu32)ptr[0x0A] << 8 | ptr[0x0B]);
1925 rr->resrec.rdata->u.soa.expire = (mDNSu32) ((mDNSu32)ptr[0x0C] << 24 | (mDNSu32)ptr[0x0D] << 16 | (mDNSu32)ptr[0x0E] << 8 | ptr[0x0F]);
1926 rr->resrec.rdata->u.soa.min = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]);
1927 break;
1928
1929 case kDNSType_OPT: getOptRdata(ptr, end, largecr, pktrdlength); break;
1930
1931 default: if (pktrdlength > rr->resrec.rdata->MaxRDLength)
1932 {
1933 debugf("GetResourceRecord: rdata %d (%s) size (%d) exceeds storage (%d)",
1934 rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength);
1935 return(mDNSNULL);
1936 }
1937 debugf("GetResourceRecord: Warning! Reading resource type %d (%s) as opaque data",
1938 rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype));
1939 // Note: Just because we don't understand the record type, that doesn't
1940 // mean we fail. The DNS protocol specifies rdlength, so we can
1941 // safely skip over unknown records and ignore them.
1942 // We also grab a binary copy of the rdata anyway, since the caller
1943 // might know how to interpret it even if we don't.
1944 rr->resrec.rdlength = pktrdlength;
1945 mDNSPlatformMemCopy(ptr, rr->resrec.rdata->u.data, pktrdlength);
1946 break;
1947 }
1948
1949 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
1950 SetNewRData(&rr->resrec, mDNSNULL, 0);
1951
1952 // Success! Now fill in RecordType to show this record contains valid data
1953 rr->resrec.RecordType = RecordType;
1954 return(ptr + pktrdlength);
1955 }
1956
1957 mDNSexport const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end)
1958 {
1959 ptr = skipDomainName(msg, ptr, end);
1960 if (!ptr) { debugf("skipQuestion: Malformed domain name in DNS question section"); return(mDNSNULL); }
1961 if (ptr+4 > end) { debugf("skipQuestion: Malformed DNS question section -- no query type and class!"); return(mDNSNULL); }
1962 return(ptr+4);
1963 }
1964
1965 mDNSexport const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end, const mDNSInterfaceID InterfaceID,
1966 DNSQuestion *question)
1967 {
1968 question->InterfaceID = InterfaceID;
1969 ptr = getDomainName(msg, ptr, end, &question->qname);
1970 if (!ptr) { debugf("Malformed domain name in DNS question section"); return(mDNSNULL); }
1971 if (ptr+4 > end) { debugf("Malformed DNS question section -- no query type and class!"); return(mDNSNULL); }
1972
1973 question->qnamehash = DomainNameHashValue(&question->qname);
1974 question->qtype = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); // Get type
1975 question->qclass = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]); // and class
1976 return(ptr+4);
1977 }
1978
1979 mDNSexport const mDNSu8 *LocateAnswers(const DNSMessage *const msg, const mDNSu8 *const end)
1980 {
1981 int i;
1982 const mDNSu8 *ptr = msg->data;
1983 for (i = 0; i < msg->h.numQuestions && ptr; i++) ptr = skipQuestion(msg, ptr, end);
1984 return(ptr);
1985 }
1986
1987 mDNSexport const mDNSu8 *LocateAuthorities(const DNSMessage *const msg, const mDNSu8 *const end)
1988 {
1989 int i;
1990 const mDNSu8 *ptr = LocateAnswers(msg, end);
1991 for (i = 0; i < msg->h.numAnswers && ptr; i++) ptr = skipResourceRecord(msg, ptr, end);
1992 return(ptr);
1993 }
1994
1995 mDNSexport const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mDNSu8 *const end)
1996 {
1997 int i;
1998 const mDNSu8 *ptr = LocateAuthorities(msg, end);
1999 for (i = 0; i < msg->h.numAuthorities; i++) ptr = skipResourceRecord(msg, ptr, end);
2000 return (ptr);
2001 }
2002
2003 // ***************************************************************************
2004 #if COMPILER_LIKES_PRAGMA_MARK
2005 #pragma mark -
2006 #pragma mark -
2007 #pragma mark - Packet Sending Functions
2008 #endif
2009
2010 mDNSexport mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
2011 mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, int sd, uDNS_AuthInfo *authInfo)
2012 {
2013 mStatus status;
2014 int nsent;
2015 mDNSs32 msglen;
2016 mDNSu8 lenbuf[2];
2017 mDNSu16 numQuestions = msg->h.numQuestions;
2018 mDNSu16 numAnswers = msg->h.numAnswers;
2019 mDNSu16 numAuthorities = msg->h.numAuthorities;
2020 mDNSu16 numAdditionals = msg->h.numAdditionals;
2021 mDNSu8 *ptr = (mDNSu8 *)&msg->h.numQuestions;
2022
2023 // Put all the integer values in IETF byte-order (MSB first, LSB second)
2024 *ptr++ = (mDNSu8)(numQuestions >> 8);
2025 *ptr++ = (mDNSu8)(numQuestions & 0xFF);
2026 *ptr++ = (mDNSu8)(numAnswers >> 8);
2027 *ptr++ = (mDNSu8)(numAnswers & 0xFF);
2028 *ptr++ = (mDNSu8)(numAuthorities >> 8);
2029 *ptr++ = (mDNSu8)(numAuthorities & 0xFF);
2030 *ptr++ = (mDNSu8)(numAdditionals >> 8);
2031 *ptr++ = (mDNSu8)(numAdditionals & 0xFF);
2032
2033 if (authInfo)
2034 {
2035 end = DNSDigest_SignMessage(msg, &end, &numAdditionals, authInfo);
2036 if (!end) return mStatus_UnknownErr;
2037 }
2038
2039 // Send the packet on the wire
2040
2041 if (sd >= 0)
2042 {
2043 msglen = (mDNSu16)(end - (mDNSu8 *)msg);
2044 lenbuf[0] = (mDNSu8)(msglen >> 8); // host->network byte conversion
2045 lenbuf[1] = (mDNSu8)(msglen & 0xFF);
2046 nsent = mDNSPlatformWriteTCP(sd, (char*)lenbuf, 2);
2047 //!!!KRS make sure kernel is sending these as 1 packet!
2048 if (nsent != 2) goto tcp_error;
2049 nsent = mDNSPlatformWriteTCP(sd, (char *)msg, msglen);
2050 if (nsent != msglen) goto tcp_error;
2051 status = mStatus_NoError;
2052 }
2053 else
2054 {
2055 status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, dst, dstport);
2056 }
2057
2058 // Put all the integer values back the way they were before we return
2059 msg->h.numQuestions = numQuestions;
2060 msg->h.numAnswers = numAnswers;
2061 msg->h.numAuthorities = numAuthorities;
2062 msg->h.numAdditionals = (mDNSu16)(authInfo ? numAdditionals - 1 : numAdditionals);
2063
2064 return(status);
2065
2066 tcp_error:
2067 LogMsg("mDNSSendDNSMessage: error sending message over tcp");
2068 return mStatus_UnknownErr;
2069 }
2070
2071 // ***************************************************************************
2072 #if COMPILER_LIKES_PRAGMA_MARK
2073 #pragma mark -
2074 #pragma mark - RR List Management & Task Management
2075 #endif
2076
2077 mDNSexport void mDNS_Lock(mDNS *const m)
2078 {
2079 // MUST grab the platform lock FIRST!
2080 mDNSPlatformLock(m);
2081
2082 // Normally, mDNS_reentrancy is zero and so is mDNS_busy
2083 // However, when we call a client callback mDNS_busy is one, and we increment mDNS_reentrancy too
2084 // If that client callback does mDNS API calls, mDNS_reentrancy and mDNS_busy will both be one
2085 // If mDNS_busy != mDNS_reentrancy that's a bad sign
2086 if (m->mDNS_busy != m->mDNS_reentrancy)
2087 LogMsg("mDNS_Lock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
2088
2089 // If this is an initial entry into the mDNSCore code, set m->timenow
2090 // else, if this is a re-entrant entry into the mDNSCore code, m->timenow should already be set
2091 if (m->mDNS_busy == 0)
2092 {
2093 if (m->timenow)
2094 LogMsg("mDNS_Lock: m->timenow already set (%ld/%ld)", m->timenow, mDNS_TimeNow_NoLock(m));
2095 m->timenow = mDNS_TimeNow_NoLock(m);
2096 if (m->timenow == 0) m->timenow = 1;
2097 }
2098 else if (m->timenow == 0)
2099 {
2100 LogMsg("mDNS_Lock: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy);
2101 m->timenow = mDNS_TimeNow_NoLock(m);
2102 if (m->timenow == 0) m->timenow = 1;
2103 }
2104
2105 if (m->timenow_last - m->timenow > 0)
2106 {
2107 m->timenow_adjust += m->timenow_last - m->timenow;
2108 LogMsg("mDNSPlatformRawTime went backwards by %ld ticks; setting correction factor to %ld", m->timenow_last - m->timenow, m->timenow_adjust);
2109 m->timenow = m->timenow_last;
2110 }
2111 m->timenow_last = m->timenow;
2112
2113 // Increment mDNS_busy so we'll recognise re-entrant calls
2114 m->mDNS_busy++;
2115 }
2116
2117 mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
2118 {
2119 mDNSs32 e = m->timenow + 0x78000000;
2120 if (m->mDNSPlatformStatus != mStatus_NoError || m->SleepState) return(e);
2121 if (m->NewQuestions)
2122 {
2123 if (m->NewQuestions->DelayAnswering) e = m->NewQuestions->DelayAnswering;
2124 else return(m->timenow);
2125 }
2126 if (m->NewLocalOnlyQuestions) return(m->timenow);
2127 if (m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords)) return(m->timenow);
2128 if (m->SuppressSending) return(m->SuppressSending);
2129 #ifndef UNICAST_DISABLED
2130 if (e - m->uDNS_info.nextevent > 0) e = m->uDNS_info.nextevent;
2131 #endif
2132 if (e - m->NextCacheCheck > 0) e = m->NextCacheCheck;
2133 if (e - m->NextScheduledQuery > 0) e = m->NextScheduledQuery;
2134 if (e - m->NextScheduledProbe > 0) e = m->NextScheduledProbe;
2135 if (e - m->NextScheduledResponse > 0) e = m->NextScheduledResponse;
2136 return(e);
2137 }
2138
2139 mDNSexport void mDNS_Unlock(mDNS *const m)
2140 {
2141 // Decrement mDNS_busy
2142 m->mDNS_busy--;
2143
2144 // Check for locking failures
2145 if (m->mDNS_busy != m->mDNS_reentrancy)
2146 LogMsg("mDNS_Unlock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
2147
2148 // If this is a final exit from the mDNSCore code, set m->NextScheduledEvent and clear m->timenow
2149 if (m->mDNS_busy == 0)
2150 {
2151 m->NextScheduledEvent = GetNextScheduledEvent(m);
2152 if (m->timenow == 0) LogMsg("mDNS_Unlock: ERROR! m->timenow aready zero");
2153 m->timenow = 0;
2154 }
2155
2156 // MUST release the platform lock LAST!
2157 mDNSPlatformUnlock(m);
2158 }