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