2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
26 Revision 1.83 2005/01/27 22:57:55 cheshire
27 Fix compile errors on gcc4
29 Revision 1.82 2005/01/19 03:27:03 cheshire
30 <rdar://problem/3961051> CPU Spin in mDNSResponder
31 GetNextScheduledEvent() needs to check LocalRecordReady()
33 Revision 1.81 2004/12/18 03:13:45 cheshire
34 <rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records
36 Revision 1.80 2004/12/16 21:46:43 cheshire
37 Add DNSTypeName case for kDNSType_SOA
39 Revision 1.79 2004/12/16 21:38:37 cheshire
40 Add DNSTypeName case for kDNSType_NS
42 Revision 1.78 2004/12/16 21:27:37 ksekar
43 Fixed build failures when compiled with verbose debugging messages
45 Revision 1.77 2004/12/16 20:12:59 cheshire
46 <rdar://problem/3324626> Cache memory management improvements
48 Revision 1.76 2004/12/16 08:05:29 shersche
49 Remove extranenous semicolons that cause compilation errors on Windows
51 Revision 1.75 2004/12/15 02:11:22 ksekar
52 <rdar://problem/3917317> Don't check for Dynamic DNS hostname uniqueness
54 Revision 1.74 2004/12/09 22:49:15 ksekar
55 <rdar://problem/3913653> Wide-Area Goodbyes broken
57 Revision 1.73 2004/12/07 22:49:06 cheshire
58 <rdar://problem/3908850> BIND doesn't like zero-length rdata
60 Revision 1.72 2004/12/06 21:15:20 ksekar
61 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
63 Revision 1.71 2004/12/04 02:12:45 cheshire
64 <rdar://problem/3517236> mDNSResponder puts LargeCacheRecord on the stack
66 Revision 1.70 2004/12/03 19:52:44 ksekar
67 Use PutResourceRecordTTLJumbo for putDeletionRecord()
69 Revision 1.69 2004/12/03 07:20:50 ksekar
70 <rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
72 Revision 1.68 2004/11/24 00:10:43 cheshire
73 <rdar://problem/3869241> For unicast operations, verify that service types are legal
75 Revision 1.67 2004/10/26 03:52:02 cheshire
76 Update checkin comments
78 Revision 1.66 2004/10/23 01:16:00 cheshire
79 <rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
81 Revision 1.65 2004/10/20 02:15:09 cheshire
82 Add case in GetRRDisplayString() to display NS rdata
84 Revision 1.64 2004/10/13 00:24:02 cheshire
85 Disable "array is too small to include a terminating null character" warning on Windows
87 Revision 1.63 2004/10/10 06:57:14 cheshire
88 Change definition of "localdomain" to make code compile a little smaller
90 Revision 1.62 2004/10/06 01:44:19 cheshire
91 <rdar://problem/3813936> Resolving too quickly sometimes returns stale TXT record
93 Revision 1.61 2004/09/30 00:24:56 ksekar
94 <rdar://problem/3695802> Dynamically update default registration domains on config change
96 Revision 1.60 2004/09/27 23:25:30 cheshire
97 Fix compiler warning: soa.serial is signed, not unsigned
99 Revision 1.59 2004/09/27 22:53:45 ksekar
100 Fixed getLargeResourceRecord for SOA rdata.
102 Revision 1.58 2004/09/25 02:41:39 cheshire
103 <rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events
105 Revision 1.57 2004/09/25 02:24:27 cheshire
106 Removed unused rr->UseCount
108 Revision 1.56 2004/09/24 20:57:39 cheshire
109 <rdar://problem/3680902> Eliminate inappropriate casts that cause misaligned-address errors
111 Revision 1.55 2004/09/17 01:08:48 cheshire
112 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
113 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
114 declared in that file are ONLY appropriate to single-address-space embedded applications.
115 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
117 Revision 1.54 2004/09/17 00:49:51 cheshire
118 Get rid of now-unused GetResourceRecord -- the correct (safe) routine to use
119 is GetLargeResourceRecord
121 Revision 1.53 2004/09/17 00:31:51 cheshire
122 For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
124 Revision 1.52 2004/09/17 00:19:10 cheshire
125 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
127 Revision 1.51 2004/09/16 02:29:39 cheshire
128 Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
129 uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
131 Revision 1.50 2004/09/16 01:58:14 cheshire
132 Fix compiler warnings
134 Revision 1.49 2004/09/14 23:42:35 cheshire
135 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
137 Revision 1.48 2004/09/14 23:27:46 cheshire
140 Revision 1.47 2004/08/25 02:50:04 cheshire
141 <rdar://problem/3561220> Browses are no longer piggybacking on other browses
142 Make mDNSSameAddress() recognise that two mDNSAddrType_None addresses are necessarily equal
144 Revision 1.46 2004/08/18 17:35:40 ksekar
145 <rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
147 Revision 1.45 2004/08/15 18:26:00 cheshire
148 Don't use strcpy() on "struct domainname" objects; use AssignDomainName() instead
149 (A "struct domainname" is a collection of packed pascal strings, not a C string.)
151 Revision 1.44 2004/08/13 23:46:58 cheshire
152 "asyncronous" -> "asynchronous"
154 Revision 1.43 2004/08/12 02:55:46 ksekar
155 Fix param order error moving putPrereqNameNotInUse from uDNS.c using
156 ustrcpy macro to DNSCommon.c using mDNSPlatformStrCopy().
158 Revision 1.42 2004/08/10 23:19:14 ksekar
159 <rdar://problem/3722542>: DNS Extension daemon for Wide Area Rendezvous
160 Moved routines/constants to allow extern access for garbage collection daemon
162 Revision 1.41 2004/08/10 01:10:01 cheshire
163 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
164 Minor revision from Roger Pantos
166 Revision 1.40 2004/08/04 22:10:46 cheshire
167 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
168 Change to use "._sub." instead of ".s." to mark subtypes.
170 Revision 1.39 2004/07/13 21:24:24 rpantos
171 Fix for <rdar://problem/3701120>.
173 Revision 1.38 2004/06/18 21:08:58 cheshire
174 <rdar://problem/3540040> Applications are registering invalid records
175 Attempts to create domain names like "www..apple.com." now logged to aid debugging
177 Revision 1.37 2004/06/18 20:25:42 cheshire
178 <rdar://problem/3488547> Add a syslog message if someone tries to use "local.arpa".
180 Revision 1.36 2004/06/18 19:09:59 cheshire
181 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
183 Revision 1.35 2004/06/05 00:14:44 cheshire
184 Fix signed/unsigned and other compiler warnings
186 Revision 1.34 2004/06/04 00:25:25 cheshire
187 Fix misaligned write exception that occurs on some platforms
189 Revision 1.33 2004/06/04 00:16:18 cheshire
190 Remove non-portable use of 'inline'
192 Revision 1.32 2004/06/03 03:09:58 ksekar
193 <rdar://problem/3668626>: Garbage Collection for Dynamic Updates
195 Revision 1.31 2004/05/28 23:42:36 ksekar
196 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
198 Revision 1.30 2004/05/26 09:08:04 bradley
199 Added cast to correct structure pointer when allocating domain name list element to fix C++ builds.
201 Revision 1.29 2004/05/18 23:51:25 cheshire
202 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
204 Revision 1.28 2004/05/13 04:54:20 ksekar
205 Unified list copy/free code. Added symetric list for
207 Revision 1.27 2004/04/22 20:29:07 cheshire
208 Log error message if no count field passed to PutResourceRecordTTL()
210 Revision 1.26 2004/04/22 04:07:01 cheshire
211 Fix from Bob Bradley: Don't try to do inline functions on compilers that don't support it
213 Revision 1.25 2004/04/22 03:05:28 cheshire
214 kDNSClass_ANY should be kDNSQClass_ANY
216 Revision 1.24 2004/04/22 02:51:20 cheshire
217 Use common code for HINFO/TXT and TSIG cases in putRData
219 Revision 1.23 2004/04/15 00:51:28 bradley
220 Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers.
221 Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers.
223 Revision 1.22 2004/04/14 23:09:28 ksekar
224 Support for TSIG signed dynamic updates.
226 Revision 1.21 2004/04/09 16:47:28 cheshire
227 <rdar://problem/3617655>: mDNSResponder escape handling inconsistent with BIND
229 Revision 1.20 2004/04/09 16:37:15 cheshire
230 Suggestion from Bob Bradley:
231 Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers
233 Revision 1.19 2004/04/02 19:34:38 cheshire
236 Revision 1.18 2004/03/30 06:45:00 cheshire
237 Compiler warning fixes from Don Woodward at Roku Labs
239 Revision 1.17 2004/03/19 22:25:20 cheshire
240 <rdar://problem/3579561>: Need to limit service types to fourteen characters
241 Won't actually do this for now, but keep the code around just in case
243 Revision 1.16 2004/03/08 02:45:35 cheshire
244 Minor change to make a couple of the log messages a bit shorter
246 Revision 1.15 2004/03/08 02:44:09 cheshire
247 <rdar://problem/3579561>: Need to limit service types to fourteen characters
249 Revision 1.14 2004/02/21 02:06:24 cheshire
250 Can't use anonymous unions -- they're non-standard and don't work on all compilers
252 Revision 1.13 2004/02/06 23:04:18 ksekar
253 Basic Dynamic Update support via mDNS_Register (dissabled via
254 UNICAST_REGISTRATION #define)
256 Revision 1.12 2004/02/03 22:37:10 cheshire
257 Delete unused (commented-out) code
259 Revision 1.11 2004/02/03 22:35:34 cheshire
260 <rdar://problem/3548256>: Should not allow empty string for resolve domain
262 Revision 1.10 2004/02/03 19:47:36 ksekar
263 Added an asynchronous state machine mechanism to uDNS.c, including
264 calls to find the parent zone for a domain name. Changes include code
265 in repository previously dissabled via "#if 0 incomplete". Codepath
266 is currently unused, and will be called to create update records, etc.
268 Revision 1.9 2004/01/27 20:15:22 cheshire
269 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
271 Revision 1.8 2004/01/24 23:24:36 cheshire
272 Expanded out the list of local domains to reduce risk of mistakes in future
274 Revision 1.7 2004/01/24 08:32:30 bradley
275 Mask values with 0xFF before casting to avoid runtime truncation errors on Windows debug builds.
276 Separated octal-escaped sequences preceding decimal digits to avoid errors with some compilers wanting
277 to signal potentially hidden errors about the subsequent digit not being part of the octal sequence.
279 Revision 1.6 2004/01/24 04:59:15 cheshire
280 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
282 Revision 1.5 2004/01/23 23:23:14 ksekar
283 Added TCP support for truncated unicast messages.
285 Revision 1.4 2004/01/22 02:15:33 cheshire
286 <rdar://problem/3536597>: Link-local reverse-mapping domains need to be resolved using link-local multicast
288 Revision 1.3 2004/01/21 21:16:29 cheshire
289 Minor tidy-up: Deleted a bunch of blank lines, trailing spaces, tabs, etc.
291 Revision 1.2 2003/12/13 05:47:48 bradley
292 Made local ptr const to fix error when assigning from const structure. Disable benign conditional
293 expression is constant warning when building with Microsoft compilers.
295 Revision 1.1 2003/12/13 03:05:27 ksekar
296 <rdar://problem/3192548>: DynDNS: Unicast query of service records
300 // Set mDNS_InstantiateInlines to tell mDNSEmbeddedAPI.h to instantiate inline functions, if necessary
301 #define mDNS_InstantiateInlines 1
302 #include "DNSCommon.h"
304 // Disable certain benign warnings with Microsoft compilers
305 #if (defined(_MSC_VER))
306 // Disable "conditional expression is constant" warning for debug macros.
307 // Otherwise, this generates warnings for the perfectly natural construct "while(1)"
308 // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know
309 #pragma warning(disable:4127)
310 // Disable "array is too small to include a terminating null character" warning
311 // -- domain labels have an initial length byte, not a terminating null character
312 #pragma warning(disable:4295)
315 // ***************************************************************************
316 #if COMPILER_LIKES_PRAGMA_MARK
318 #pragma mark - DNameList copy/deallocation routines
321 mDNSexport DNameListElem
*mDNS_CopyDNameList(const DNameListElem
*orig
)
323 DNameListElem
*copy
= mDNSNULL
, *newelem
;
324 const DNameListElem
*ptr
;
326 for (ptr
= orig
; ptr
; ptr
= ptr
->next
)
328 newelem
= (DNameListElem
*)mDNSPlatformMemAllocate(sizeof(DNameListElem
));
329 if (!newelem
) { LogMsg("ERROR: malloc"); return mDNSNULL
; }
330 AssignDomainName(&newelem
->name
, &ptr
->name
);
331 newelem
->next
= copy
;
337 mDNSexport
void mDNS_FreeDNameList(DNameListElem
*list
)
345 mDNSPlatformMemFree(fptr
);
349 // ***************************************************************************
350 #if COMPILER_LIKES_PRAGMA_MARK
352 #pragma mark - General Utility Functions
355 // return true for RFC1918 private addresses
356 mDNSexport mDNSBool
IsPrivateV4Addr(mDNSAddr
*addr
)
360 if (addr
->type
!= mDNSAddrType_IPv4
) return mDNSfalse
;
363 return ((b
[0] == 10) || // 10/8 prefix
364 (b
[0] == 172 && b
[1] > 15 && b
[1] < 32) || // 172.16/12
365 (b
[0] == 192 && b
[1] == 168)); // 192.168/16
368 mDNSexport
const NetworkInterfaceInfo
*GetFirstActiveInterface(const NetworkInterfaceInfo
*intf
)
370 while (intf
&& !intf
->InterfaceActive
) intf
= intf
->next
;
374 mDNSexport mDNSInterfaceID
GetNextActiveInterfaceID(const NetworkInterfaceInfo
*intf
)
376 const NetworkInterfaceInfo
*next
= GetFirstActiveInterface(intf
->next
);
377 if (next
) return(next
->InterfaceID
); else return(mDNSNULL
);
380 mDNSexport mDNSu32
NumCacheRecordsForInterfaceID(const mDNS
*const m
, mDNSInterfaceID id
)
382 mDNSu32 slot
, used
= 0;
385 FORALL_CACHERECORDS(slot
, cg
, rr
)
386 if (rr
->resrec
.InterfaceID
== id
) used
++;
390 mDNSexport
char *DNSTypeName(mDNSu16 rrtype
)
394 case kDNSType_A
: return("Addr");
395 case kDNSType_NS
: return("NS");
396 case kDNSType_CNAME
:return("CNAME");
397 case kDNSType_SOA
: return("SOA");
398 case kDNSType_NULL
: return("NULL");
399 case kDNSType_PTR
: return("PTR");
400 case kDNSType_HINFO
:return("HINFO");
401 case kDNSType_TXT
: return("TXT");
402 case kDNSType_AAAA
: return("AAAA");
403 case kDNSType_SRV
: return("SRV");
404 case kDNSQType_ANY
: return("ANY");
406 static char buffer
[16];
407 mDNS_snprintf(buffer
, sizeof(buffer
), "(%d)", rrtype
);
413 mDNSexport
char *GetRRDisplayString_rdb(const ResourceRecord
*rr
, RDataBody
*rd
, char *buffer
)
416 mDNSu32 length
= mDNS_snprintf(buffer
, 79, "%4d %##s %s ", rr
->rdlength
, rr
->name
->c
, DNSTypeName(rr
->rrtype
));
419 case kDNSType_A
: mDNS_snprintf(buffer
+length
, 79-length
, "%.4a", &rd
->ipv4
); break;
421 case kDNSType_NS
: // Same as PTR
422 case kDNSType_CNAME
:// Same as PTR
423 case kDNSType_PTR
: mDNS_snprintf(buffer
+length
, 79-length
, "%##s", rd
->name
.c
); break;
425 case kDNSType_HINFO
:// Display this the same as TXT (just show first string)
426 case kDNSType_TXT
: mDNS_snprintf(buffer
+length
, 79-length
, "%#s", rd
->txt
.c
); break;
428 case kDNSType_AAAA
: mDNS_snprintf(buffer
+length
, 79-length
, "%.16a", &rd
->ipv6
); break;
429 case kDNSType_SRV
: mDNS_snprintf(buffer
+length
, 79-length
, "%##s", rd
->srv
.target
.c
); break;
430 default: mDNS_snprintf(buffer
+length
, 79-length
, "RDLen %d: %s", rr
->rdlength
, rd
->data
); break;
432 for (ptr
= buffer
; *ptr
; ptr
++) if (*ptr
< ' ') *ptr
='.';
436 mDNSexport mDNSu32
mDNSRandom(mDNSu32 max
)
438 static mDNSu32 seed
= 0;
444 seed
= mDNSPlatformRandomSeed(); // Pick an initial seed
445 for (i
=0; i
<100; i
++) seed
= seed
* 21 + 1; // And mix it up a bit
447 while (mask
< max
) mask
= (mask
<< 1) | 1;
448 do seed
= seed
* 21 + 1; while ((seed
& mask
) > max
);
449 return (seed
& mask
);
452 mDNSexport mDNSBool
mDNSSameAddress(const mDNSAddr
*ip1
, const mDNSAddr
*ip2
)
454 if (ip1
->type
== ip2
->type
)
458 case mDNSAddrType_None
: return(mDNStrue
); // Empty addresses have no data and are therefore always equal
459 case mDNSAddrType_IPv4
: return(mDNSBool
)(mDNSSameIPv4Address(ip1
->ip
.v4
, ip2
->ip
.v4
));
460 case mDNSAddrType_IPv6
: return(mDNSBool
)(mDNSSameIPv6Address(ip1
->ip
.v6
, ip2
->ip
.v6
));
466 mDNSexport mDNSBool
mDNSAddrIsDNSMulticast(const mDNSAddr
*ip
)
470 case mDNSAddrType_IPv4
: return(mDNSBool
)(ip
->ip
.v4
.NotAnInteger
== AllDNSLinkGroupv4
.NotAnInteger
);
471 case mDNSAddrType_IPv6
: return(mDNSBool
)(ip
->ip
.v6
.l
[0] == AllDNSLinkGroupv6
.l
[0] &&
472 ip
->ip
.v6
.l
[1] == AllDNSLinkGroupv6
.l
[1] &&
473 ip
->ip
.v6
.l
[2] == AllDNSLinkGroupv6
.l
[2] &&
474 ip
->ip
.v6
.l
[3] == AllDNSLinkGroupv6
.l
[3] );
475 default: return(mDNSfalse
);
479 // ***************************************************************************
480 #if COMPILER_LIKES_PRAGMA_MARK
482 #pragma mark - Domain Name Utility Functions
485 mDNSexport mDNSBool
SameDomainLabel(const mDNSu8
*a
, const mDNSu8
*b
)
488 const int len
= *a
++;
490 if (len
> MAX_DOMAIN_LABEL
)
491 { debugf("Malformed label (too long)"); return(mDNSfalse
); }
493 if (len
!= *b
++) return(mDNSfalse
);
494 for (i
=0; i
<len
; i
++)
498 if (mDNSIsUpperCase(ac
)) ac
+= 'a' - 'A';
499 if (mDNSIsUpperCase(bc
)) bc
+= 'a' - 'A';
500 if (ac
!= bc
) return(mDNSfalse
);
505 mDNSexport mDNSBool
SameDomainName(const domainname
*const d1
, const domainname
*const d2
)
507 const mDNSu8
* a
= d1
->c
;
508 const mDNSu8
* b
= d2
->c
;
509 const mDNSu8
*const max
= d1
->c
+ MAX_DOMAIN_NAME
; // Maximum that's valid
513 if (a
+ 1 + *a
>= max
)
514 { debugf("Malformed domain name (more than 255 characters)"); return(mDNSfalse
); }
515 if (!SameDomainLabel(a
, b
)) return(mDNSfalse
);
523 mDNSexport mDNSBool
IsLocalDomain(const domainname
*d
)
525 // Domains that are defined to be resolved via link-local multicast are:
526 // local., 254.169.in-addr.arpa., and 0.8.E.F.ip6.arpa.
527 static const domainname
*n0
= (domainname
*)"\x5" "local";
528 static const domainname
*n1
= (domainname
*)"\x3" "254" "\x3" "169" "\x7" "in-addr" "\x4" "arpa";
529 static const domainname
*n2
= (domainname
*)"\x1" "0" "\x1" "8" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa";
531 const domainname
*d1
, *d2
, *d3
, *d4
, *d5
, *d6
; // Top-level domain, second-level domain, etc.
532 d1
= d2
= d3
= d4
= d5
= d6
= mDNSNULL
;
535 d6
= d5
; d5
= d4
; d4
= d3
; d3
= d2
; d2
= d1
; d1
= d
;
536 d
= (domainname
*)(d
->c
+ 1 + d
->c
[0]);
539 if (d1
&& SameDomainName(d1
, n0
)) return(mDNStrue
);
540 if (d4
&& SameDomainName(d4
, n1
)) return(mDNStrue
);
541 if (d6
&& SameDomainName(d6
, n2
)) return(mDNStrue
);
545 // Returns length of a domain name INCLUDING the byte for the final null label
546 // i.e. for the root label "." it returns one
547 // For the FQDN "com." it returns 5 (length byte, three data bytes, final zero)
548 // Legal results are 1 (just root label) to 255 (MAX_DOMAIN_NAME)
549 // If the given domainname is invalid, result is 256
550 mDNSexport mDNSu16
DomainNameLength(const domainname
*const name
)
552 const mDNSu8
*src
= name
->c
;
555 if (*src
> MAX_DOMAIN_LABEL
) return(MAX_DOMAIN_NAME
+1);
557 if (src
- name
->c
>= MAX_DOMAIN_NAME
) return(MAX_DOMAIN_NAME
+1);
559 return((mDNSu16
)(src
- name
->c
+ 1));
562 // CompressedDomainNameLength returns the length of a domain name INCLUDING the byte
563 // for the final null label i.e. for the root label "." it returns one.
564 // E.g. for the FQDN "foo.com." it returns 9
565 // (length, three data bytes, length, three more data bytes, final zero).
566 // In the case where a parent domain name is provided, and the given name is a child
567 // of that parent, CompressedDomainNameLength returns the length of the prefix portion
568 // of the child name, plus TWO bytes for the compression pointer.
569 // E.g. for the name "foo.com." with parent "com.", it returns 6
570 // (length, three data bytes, two-byte compression pointer).
571 mDNSexport mDNSu16
CompressedDomainNameLength(const domainname
*const name
, const domainname
*parent
)
573 const mDNSu8
*src
= name
->c
;
574 if (parent
&& parent
->c
[0] == 0) parent
= mDNSNULL
;
577 if (*src
> MAX_DOMAIN_LABEL
) return(MAX_DOMAIN_NAME
+1);
578 if (parent
&& SameDomainName((domainname
*)src
, parent
)) return((mDNSu16
)(src
- name
->c
+ 2));
580 if (src
- name
->c
>= MAX_DOMAIN_NAME
) return(MAX_DOMAIN_NAME
+1);
582 return((mDNSu16
)(src
- name
->c
+ 1));
585 // AppendLiteralLabelString appends a single label to an existing (possibly empty) domainname.
586 // The C string contains the label as-is, with no escaping, etc.
587 // Any dots in the name are literal dots, not label separators
588 // If successful, AppendLiteralLabelString returns a pointer to the next unused byte
589 // in the domainname bufer (i.e., the next byte after the terminating zero).
590 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
591 // AppendLiteralLabelString returns mDNSNULL.
592 mDNSexport mDNSu8
*AppendLiteralLabelString(domainname
*const name
, const char *cstr
)
594 mDNSu8
* ptr
= name
->c
+ DomainNameLength(name
) - 1; // Find end of current name
595 const mDNSu8
*const lim1
= name
->c
+ MAX_DOMAIN_NAME
- 1; // Limit of how much we can add (not counting final zero)
596 const mDNSu8
*const lim2
= ptr
+ 1 + MAX_DOMAIN_LABEL
;
597 const mDNSu8
*const lim
= (lim1
< lim2
) ? lim1
: lim2
;
598 mDNSu8
*lengthbyte
= ptr
++; // Record where the length is going to go
600 while (*cstr
&& ptr
< lim
) *ptr
++ = (mDNSu8
)*cstr
++; // Copy the data
601 *lengthbyte
= (mDNSu8
)(ptr
- lengthbyte
- 1); // Fill in the length byte
602 *ptr
++ = 0; // Put the null root label on the end
603 if (*cstr
) return(mDNSNULL
); // Failure: We didn't successfully consume all input
604 else return(ptr
); // Success: return new value of ptr
607 // AppendDNSNameString appends zero or more labels to an existing (possibly empty) domainname.
608 // The C string is in conventional DNS syntax:
609 // Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots.
610 // If successful, AppendDNSNameString returns a pointer to the next unused byte
611 // in the domainname bufer (i.e., the next byte after the terminating zero).
612 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
613 // AppendDNSNameString returns mDNSNULL.
614 mDNSexport mDNSu8
*AppendDNSNameString(domainname
*const name
, const char *cstring
)
616 const char *cstr
= cstring
;
617 mDNSu8
* ptr
= name
->c
+ DomainNameLength(name
) - 1; // Find end of current name
618 const mDNSu8
*const lim
= name
->c
+ MAX_DOMAIN_NAME
- 1; // Limit of how much we can add (not counting final zero)
619 while (*cstr
&& ptr
< lim
) // While more characters, and space to put them...
621 mDNSu8
*lengthbyte
= ptr
++; // Record where the length is going to go
622 if (*cstr
== '.') { LogMsg("AppendDNSNameString: Illegal empty label in name \"%s\"", cstring
); return(mDNSNULL
); }
623 while (*cstr
&& *cstr
!= '.' && ptr
< lim
) // While we have characters in the label...
625 mDNSu8 c
= (mDNSu8
)*cstr
++; // Read the character
626 if (c
== '\\') // If escape character, check next character
628 c
= (mDNSu8
)*cstr
++; // Assume we'll just take the next character
629 if (mdnsIsDigit(cstr
[-1]) && mdnsIsDigit(cstr
[0]) && mdnsIsDigit(cstr
[1]))
630 { // If three decimal digits,
631 int v0
= cstr
[-1] - '0'; // then interpret as three-digit decimal
632 int v1
= cstr
[ 0] - '0';
633 int v2
= cstr
[ 1] - '0';
634 int val
= v0
* 100 + v1
* 10 + v2
;
635 if (val
<= 255) { c
= (mDNSu8
)val
; cstr
+= 2; } // If valid three-digit decimal value, use it
638 *ptr
++ = c
; // Write the character
640 if (*cstr
) cstr
++; // Skip over the trailing dot (if present)
641 if (ptr
- lengthbyte
- 1 > MAX_DOMAIN_LABEL
) // If illegal label, abort
643 *lengthbyte
= (mDNSu8
)(ptr
- lengthbyte
- 1); // Fill in the length byte
646 *ptr
++ = 0; // Put the null root label on the end
647 if (*cstr
) return(mDNSNULL
); // Failure: We didn't successfully consume all input
648 else return(ptr
); // Success: return new value of ptr
651 // AppendDomainLabel appends a single label to a name.
652 // If successful, AppendDomainLabel returns a pointer to the next unused byte
653 // in the domainname bufer (i.e., the next byte after the terminating zero).
654 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
655 // AppendDomainLabel returns mDNSNULL.
656 mDNSexport mDNSu8
*AppendDomainLabel(domainname
*const name
, const domainlabel
*const label
)
659 mDNSu8
*ptr
= name
->c
+ DomainNameLength(name
) - 1;
661 // Check label is legal
662 if (label
->c
[0] > MAX_DOMAIN_LABEL
) return(mDNSNULL
);
664 // Check that ptr + length byte + data bytes + final zero does not exceed our limit
665 if (ptr
+ 1 + label
->c
[0] + 1 > name
->c
+ MAX_DOMAIN_NAME
) return(mDNSNULL
);
667 for (i
=0; i
<=label
->c
[0]; i
++) *ptr
++ = label
->c
[i
]; // Copy the label data
668 *ptr
++ = 0; // Put the null root label on the end
672 mDNSexport mDNSu8
*AppendDomainName(domainname
*const name
, const domainname
*const append
)
674 mDNSu8
* ptr
= name
->c
+ DomainNameLength(name
) - 1; // Find end of current name
675 const mDNSu8
*const lim
= name
->c
+ MAX_DOMAIN_NAME
- 1; // Limit of how much we can add (not counting final zero)
676 const mDNSu8
* src
= append
->c
;
680 if (ptr
+ 1 + src
[0] > lim
) return(mDNSNULL
);
681 for (i
=0; i
<=src
[0]; i
++) *ptr
++ = src
[i
];
682 *ptr
= 0; // Put the null root label on the end
688 // MakeDomainLabelFromLiteralString makes a single domain label from a single literal C string (with no escaping).
689 // If successful, MakeDomainLabelFromLiteralString returns mDNStrue.
690 // If unable to convert the whole string to a legal domain label (i.e. because length is more than 63 bytes) then
691 // MakeDomainLabelFromLiteralString makes a legal domain label from the first 63 bytes of the string and returns mDNSfalse.
692 // In some cases silently truncated oversized names to 63 bytes is acceptable, so the return result may be ignored.
693 // In other cases silent truncation may not be acceptable, so in those cases the calling function needs to check the return result.
694 mDNSexport mDNSBool
MakeDomainLabelFromLiteralString(domainlabel
*const label
, const char *cstr
)
696 mDNSu8
* ptr
= label
->c
+ 1; // Where we're putting it
697 const mDNSu8
*const limit
= label
->c
+ 1 + MAX_DOMAIN_LABEL
; // The maximum we can put
698 while (*cstr
&& ptr
< limit
) *ptr
++ = (mDNSu8
)*cstr
++; // Copy the label
699 label
->c
[0] = (mDNSu8
)(ptr
- label
->c
- 1); // Set the length byte
700 return(*cstr
== 0); // Return mDNStrue if we successfully consumed all input
703 // MakeDomainNameFromDNSNameString makes a native DNS-format domainname from a C string.
704 // The C string is in conventional DNS syntax:
705 // Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots.
706 // If successful, MakeDomainNameFromDNSNameString returns a pointer to the next unused byte
707 // in the domainname bufer (i.e., the next byte after the terminating zero).
708 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
709 // MakeDomainNameFromDNSNameString returns mDNSNULL.
710 mDNSexport mDNSu8
*MakeDomainNameFromDNSNameString(domainname
*const name
, const char *cstr
)
712 name
->c
[0] = 0; // Make an empty domain name
713 return(AppendDNSNameString(name
, cstr
)); // And then add this string to it
716 mDNSexport
char *ConvertDomainLabelToCString_withescape(const domainlabel
*const label
, char *ptr
, char esc
)
718 const mDNSu8
* src
= label
->c
; // Domain label we're reading
719 const mDNSu8 len
= *src
++; // Read length of this (non-null) label
720 const mDNSu8
*const end
= src
+ len
; // Work out where the label ends
721 if (len
> MAX_DOMAIN_LABEL
) return(mDNSNULL
); // If illegal label, abort
722 while (src
< end
) // While we have characters in the label
727 if (c
== '.' || c
== esc
) // If character is a dot or the escape character
728 *ptr
++ = esc
; // Output escape character
729 else if (c
<= ' ') // If non-printing ascii,
730 { // Output decimal escape sequence
732 *ptr
++ = (char) ('0' + (c
/ 100) );
733 *ptr
++ = (char) ('0' + (c
/ 10) % 10);
734 c
= (mDNSu8
)('0' + (c
) % 10);
737 *ptr
++ = (char)c
; // Copy the character
739 *ptr
= 0; // Null-terminate the string
740 return(ptr
); // and return
743 // Note: To guarantee that there will be no possible overrun, cstr must be at least MAX_ESCAPED_DOMAIN_NAME (1005 bytes)
744 mDNSexport
char *ConvertDomainNameToCString_withescape(const domainname
*const name
, char *ptr
, char esc
)
746 const mDNSu8
*src
= name
->c
; // Domain name we're reading
747 const mDNSu8
*const max
= name
->c
+ MAX_DOMAIN_NAME
; // Maximum that's valid
749 if (*src
== 0) *ptr
++ = '.'; // Special case: For root, just write a dot
751 while (*src
) // While more characters in the domain name
753 if (src
+ 1 + *src
>= max
) return(mDNSNULL
);
754 ptr
= ConvertDomainLabelToCString_withescape((const domainlabel
*)src
, ptr
, esc
);
755 if (!ptr
) return(mDNSNULL
);
757 *ptr
++ = '.'; // Write the dot after the label
760 *ptr
++ = 0; // Null-terminate the string
761 return(ptr
); // and return
765 // Host names must start with a letter, end with a letter or digit,
766 // and have as interior characters only letters, digits, and hyphen.
767 // This was subsequently modified in RFC 1123 to allow the first character to be either a letter or a digit
769 mDNSexport
void ConvertUTF8PstringToRFC1034HostLabel(const mDNSu8 UTF8Name
[], domainlabel
*const hostlabel
)
771 const mDNSu8
* src
= &UTF8Name
[1];
772 const mDNSu8
*const end
= &UTF8Name
[1] + UTF8Name
[0];
773 mDNSu8
* ptr
= &hostlabel
->c
[1];
774 const mDNSu8
*const lim
= &hostlabel
->c
[1] + MAX_DOMAIN_LABEL
;
777 // Delete apostrophes from source name
778 if (src
[0] == '\'') { src
++; continue; } // Standard straight single quote
779 if (src
+ 2 < end
&& src
[0] == 0xE2 && src
[1] == 0x80 && src
[2] == 0x99)
780 { src
+= 3; continue; } // Unicode curly apostrophe
783 if (mdnsValidHostChar(*src
, (ptr
> &hostlabel
->c
[1]), (src
< end
-1))) *ptr
++ = *src
;
784 else if (ptr
> &hostlabel
->c
[1] && ptr
[-1] != '-') *ptr
++ = '-';
788 while (ptr
> &hostlabel
->c
[1] && ptr
[-1] == '-') ptr
--; // Truncate trailing '-' marks
789 hostlabel
->c
[0] = (mDNSu8
)(ptr
- &hostlabel
->c
[1]);
792 mDNSexport mDNSu8
*ConstructServiceName(domainname
*const fqdn
,
793 const domainlabel
*name
, const domainname
*type
, const domainname
*const domain
)
796 mDNSu8
*dst
= fqdn
->c
;
798 const char *errormsg
;
800 // In the case where there is no name (and ONLY in that case),
801 // a single-label subtype is allowed as the first label of a three-part "type"
804 const mDNSu8
*s0
= type
->c
;
805 if (s0
[0] && s0
[0] < 0x40) // If legal first label (at least one character, and no more than 63)
807 const mDNSu8
* s1
= s0
+ 1 + s0
[0];
808 if (s1
[0] && s1
[0] < 0x40) // and legal second label (at least one character, and no more than 63)
810 const mDNSu8
*s2
= s1
+ 1 + s1
[0];
811 if (s2
[0] && s2
[0] < 0x40 && s2
[1+s2
[0]] == 0) // and we have three and only three labels
813 static const mDNSu8 SubTypeLabel
[5] = "\x04_sub";
814 src
= s0
; // Copy the first label
816 for (i
=0; i
<= len
; i
++) *dst
++ = *src
++;
817 for (i
=0; i
< (int)sizeof(SubTypeLabel
); i
++) *dst
++ = SubTypeLabel
[i
];
818 type
= (domainname
*)s1
;
820 // Special support for queries done by older versions of "Rendezvous Browser"
821 // For these queries, we retract the "._sub" we just added between the subtype and the main type
822 if (SameDomainName((domainname
*)s0
, (domainname
*)"\x09_services\x07_dns-sd\x04_udp") ||
823 SameDomainName((domainname
*)s0
, (domainname
*)"\x09_services\x05_mdns\x04_udp"))
824 dst
-= sizeof(SubTypeLabel
);
830 if (name
&& name
->c
[0])
832 src
= name
->c
; // Put the service name into the domain name
834 if (len
>= 0x40) { errormsg
="Service instance name too long"; goto fail
; }
835 for (i
=0; i
<=len
; i
++) *dst
++ = *src
++;
838 name
= (domainlabel
*)""; // Set this up to be non-null, to avoid errors if we have to call LogMsg() below
840 src
= type
->c
; // Put the service type into the domain name
842 if (len
< 2 || len
>= 0x40 || (len
> 15 && !SameDomainName(domain
, (domainname
*)"\x05" "local")))
844 errormsg
="Application protocol name must be underscore plus 1-14 characters. See <http://www.dns-sd.org/ServiceTypes.html>";
847 if (src
[1] != '_') { errormsg
="Application protocol name must begin with underscore"; goto fail
; }
848 for (i
=2; i
<=len
; i
++)
849 if (!mdnsIsLetter(src
[i
]) && !mdnsIsDigit(src
[i
]) && src
[i
] != '-' && src
[i
] != '_')
850 { errormsg
="Application protocol name must contain only letters, digits, and hyphens"; goto fail
; }
851 for (i
=0; i
<=len
; i
++) *dst
++ = *src
++;
854 if (!(len
== 4 && src
[1] == '_' &&
855 (((src
[2] | 0x20) == 'u' && (src
[3] | 0x20) == 'd') || ((src
[2] | 0x20) == 't' && (src
[3] | 0x20) == 'c')) &&
856 (src
[4] | 0x20) == 'p'))
857 { errormsg
="Transport protocol name must be _udp or _tcp"; goto fail
; }
858 for (i
=0; i
<=len
; i
++) *dst
++ = *src
++;
860 if (*src
) { errormsg
="Service type must have only two labels"; goto fail
; }
863 if (!domain
->c
[0]) { errormsg
="Service domain must be non-empty"; goto fail
; }
864 if (SameDomainName(domain
, (domainname
*)"\x05" "local" "\x04" "arpa"))
865 { errormsg
="Illegal domain \"local.arpa.\" Use \"local.\" (or empty string)"; goto fail
; }
866 dst
= AppendDomainName(fqdn
, domain
);
867 if (!dst
) { errormsg
="Service domain too long"; goto fail
; }
871 LogMsg("ConstructServiceName: %s: %#s.%##s%##s", errormsg
, name
->c
, type
->c
, domain
->c
);
875 mDNSexport mDNSBool
DeconstructServiceName(const domainname
*const fqdn
,
876 domainlabel
*const name
, domainname
*const type
, domainname
*const domain
)
879 const mDNSu8
*src
= fqdn
->c
;
880 const mDNSu8
*max
= fqdn
->c
+ MAX_DOMAIN_NAME
;
883 dst
= name
->c
; // Extract the service name from the domain name
885 if (len
>= 0x40) { debugf("DeconstructServiceName: service name too long"); return(mDNSfalse
); }
886 for (i
=0; i
<=len
; i
++) *dst
++ = *src
++;
888 dst
= type
->c
; // Extract the service type from the domain name
890 if (len
>= 0x40) { debugf("DeconstructServiceName: service type too long"); return(mDNSfalse
); }
891 for (i
=0; i
<=len
; i
++) *dst
++ = *src
++;
894 if (len
>= 0x40) { debugf("DeconstructServiceName: service type too long"); return(mDNSfalse
); }
895 for (i
=0; i
<=len
; i
++) *dst
++ = *src
++;
896 *dst
++ = 0; // Put the null root label on the end of the service type
898 dst
= domain
->c
; // Extract the service domain from the domain name
903 { debugf("DeconstructServiceName: service domain label too long"); return(mDNSfalse
); }
904 if (src
+ 1 + len
+ 1 >= max
)
905 { debugf("DeconstructServiceName: service domain too long"); return(mDNSfalse
); }
906 for (i
=0; i
<=len
; i
++) *dst
++ = *src
++;
908 *dst
++ = 0; // Put the null root label on the end
913 // Returns true if a rich text label ends in " (nnn)", or if an RFC 1034
914 // name ends in "-nnn", where n is some decimal number.
915 mDNSexport mDNSBool
LabelContainsSuffix(const domainlabel
*const name
, const mDNSBool RichText
)
917 mDNSu16 l
= name
->c
[0];
921 if (l
< 4) return mDNSfalse
; // Need at least " (2)"
922 if (name
->c
[l
--] != ')') return mDNSfalse
; // Last char must be ')'
923 if (!mdnsIsDigit(name
->c
[l
])) return mDNSfalse
; // Preceeded by a digit
925 while (l
> 2 && mdnsIsDigit(name
->c
[l
])) l
--; // Strip off digits
926 return (name
->c
[l
] == '(' && name
->c
[l
- 1] == ' ');
930 if (l
< 2) return mDNSfalse
; // Need at least "-2"
931 if (!mdnsIsDigit(name
->c
[l
])) return mDNSfalse
; // Last char must be a digit
933 while (l
> 2 && mdnsIsDigit(name
->c
[l
])) l
--; // Strip off digits
934 return (name
->c
[l
] == '-');
938 // removes an auto-generated suffix (appended on a name collision) from a label. caller is
939 // responsible for ensuring that the label does indeed contain a suffix. returns the number
940 // from the suffix that was removed.
941 mDNSexport mDNSu32
RemoveLabelSuffix(domainlabel
*name
, mDNSBool RichText
)
943 mDNSu32 val
= 0, multiplier
= 1;
945 // Chop closing parentheses from RichText suffix
946 if (RichText
&& name
->c
[0] >= 1 && name
->c
[name
->c
[0]] == ')') name
->c
[0]--;
948 // Get any existing numerical suffix off the name
949 while (mdnsIsDigit(name
->c
[name
->c
[0]]))
950 { val
+= (name
->c
[name
->c
[0]] - '0') * multiplier
; multiplier
*= 10; name
->c
[0]--; }
952 // Chop opening parentheses or dash from suffix
955 if (name
->c
[0] >= 2 && name
->c
[name
->c
[0]] == '(' && name
->c
[name
->c
[0]-1] == ' ') name
->c
[0] -= 2;
959 if (name
->c
[0] >= 1 && name
->c
[name
->c
[0]] == '-') name
->c
[0] -= 1;
965 // appends a numerical suffix to a label, with the number following a whitespace and enclosed
966 // in parentheses (rich text) or following two consecutive hyphens (RFC 1034 domain label).
967 mDNSexport
void AppendLabelSuffix(domainlabel
*name
, mDNSu32 val
, mDNSBool RichText
)
969 mDNSu32 divisor
= 1, chars
= 2; // Shortest possible RFC1034 name suffix is 2 characters ("-2")
970 if (RichText
) chars
= 4; // Shortest possible RichText suffix is 4 characters (" (2)")
972 // Truncate trailing spaces from RichText names
973 if (RichText
) while (name
->c
[name
->c
[0]] == ' ') name
->c
[0]--;
975 while (val
>= divisor
* 10) { divisor
*= 10; chars
++; }
977 if (name
->c
[0] > (mDNSu8
)(MAX_DOMAIN_LABEL
- chars
))
979 name
->c
[0] = (mDNSu8
)(MAX_DOMAIN_LABEL
- chars
);
980 // If the following character is a UTF-8 continuation character,
981 // we just chopped a multi-byte UTF-8 character in the middle, so strip back to a safe truncation point
982 while (name
->c
[0] > 0 && (name
->c
[name
->c
[0]+1] & 0xC0) == 0x80) name
->c
[0]--;
985 if (RichText
) { name
->c
[++name
->c
[0]] = ' '; name
->c
[++name
->c
[0]] = '('; }
986 else { name
->c
[++name
->c
[0]] = '-'; }
990 name
->c
[++name
->c
[0]] = (mDNSu8
)('0' + val
/ divisor
);
995 if (RichText
) name
->c
[++name
->c
[0]] = ')';
998 mDNSexport
void IncrementLabelSuffix(domainlabel
*name
, mDNSBool RichText
)
1002 if (LabelContainsSuffix(name
, RichText
))
1003 val
= RemoveLabelSuffix(name
, RichText
);
1005 // If no existing suffix, start by renaming "Foo" as "Foo (2)" or "Foo-2" as appropriate.
1006 // If existing suffix in the range 2-9, increment it.
1007 // If we've had ten conflicts already, there are probably too many hosts trying to use the same name,
1008 // so add a random increment to improve the chances of finding an available name next time.
1009 if (val
== 0) val
= 2;
1010 else if (val
< 10) val
++;
1011 else val
+= 1 + mDNSRandom(99);
1013 AppendLabelSuffix(name
, val
, RichText
);
1016 // ***************************************************************************
1017 #if COMPILER_LIKES_PRAGMA_MARK
1019 #pragma mark - Resource Record Utility Functions
1022 mDNSexport mDNSu32
RDataHashValue(mDNSu16
const rdlength
, const RDataBody
*const rdb
)
1026 for (i
=0; i
+1 < rdlength
; i
+=2)
1028 sum
+= (((mDNSu32
)(rdb
->data
[i
])) << 8) | rdb
->data
[i
+1];
1029 sum
= (sum
<<3) | (sum
>>29);
1033 sum
+= ((mDNSu32
)(rdb
->data
[i
])) << 8;
1038 mDNSexport mDNSBool
SameRData(const ResourceRecord
*const r1
, const ResourceRecord
*const r2
)
1040 if (r1
->rrtype
!= r2
->rrtype
) return(mDNSfalse
);
1041 if (r1
->rdlength
!= r2
->rdlength
) return(mDNSfalse
);
1042 if (r1
->rdatahash
!= r2
->rdatahash
) return(mDNSfalse
);
1043 if (r1
->rdnamehash
!= r2
->rdnamehash
) return(mDNSfalse
);
1046 case kDNSType_CNAME
:// Same as PTR
1047 case kDNSType_PTR
: return(SameDomainName(&r1
->rdata
->u
.name
, &r2
->rdata
->u
.name
));
1049 case kDNSType_SRV
: return(mDNSBool
)( r1
->rdata
->u
.srv
.priority
== r2
->rdata
->u
.srv
.priority
&&
1050 r1
->rdata
->u
.srv
.weight
== r2
->rdata
->u
.srv
.weight
&&
1051 r1
->rdata
->u
.srv
.port
.NotAnInteger
== r2
->rdata
->u
.srv
.port
.NotAnInteger
&&
1052 SameDomainName(&r1
->rdata
->u
.srv
.target
, &r2
->rdata
->u
.srv
.target
) );
1054 default: return(mDNSPlatformMemSame(r1
->rdata
->u
.data
, r2
->rdata
->u
.data
, r1
->rdlength
));
1058 mDNSexport mDNSBool
SameResourceRecord(ResourceRecord
*r1
, ResourceRecord
*r2
)
1060 return (r1
->namehash
== r2
->namehash
&&
1061 r1
->rrtype
== r2
->rrtype
&&
1062 SameDomainName(r1
->name
, r2
->name
) &&
1066 mDNSexport mDNSBool
ResourceRecordAnswersQuestion(const ResourceRecord
*const rr
, const DNSQuestion
*const q
)
1068 if (rr
->InterfaceID
&&
1069 q
->InterfaceID
&& q
->InterfaceID
!= mDNSInterface_LocalOnly
&&
1070 rr
->InterfaceID
!= q
->InterfaceID
) return(mDNSfalse
);
1072 // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
1073 if (rr
->rrtype
!= kDNSType_CNAME
&& rr
->rrtype
!= q
->qtype
&& q
->qtype
!= kDNSQType_ANY
) return(mDNSfalse
);
1074 if ( rr
->rrclass
!= q
->qclass
&& q
->qclass
!= kDNSQClass_ANY
) return(mDNSfalse
);
1075 return(rr
->namehash
== q
->qnamehash
&& SameDomainName(rr
->name
, &q
->qname
));
1078 mDNSexport mDNSu16
GetRDLength(const ResourceRecord
*const rr
, mDNSBool estimate
)
1080 const RDataBody
*rd
= &rr
->rdata
->u
;
1081 const domainname
*const name
= estimate
? rr
->name
: mDNSNULL
;
1084 case kDNSType_A
: return(sizeof(rd
->ipv4
));
1085 case kDNSType_CNAME
:// Same as PTR
1086 case kDNSType_NS
: // Same as PTR
1087 case kDNSType_PTR
: return(CompressedDomainNameLength(&rd
->name
, name
));
1088 case kDNSType_HINFO
:return(mDNSu16
)(2 + (int)rd
->data
[0] + (int)rd
->data
[1 + (int)rd
->data
[0]]);
1089 case kDNSType_NULL
: // Same as TXT -- not self-describing, so have to just trust rdlength
1090 case kDNSType_TXT
: return(rr
->rdlength
); // TXT is not self-describing, so have to just trust rdlength
1091 case kDNSType_AAAA
: return(sizeof(rd
->ipv6
));
1092 case kDNSType_SRV
: return(mDNSu16
)(6 + CompressedDomainNameLength(&rd
->srv
.target
, name
));
1093 case kDNSType_SOA
: return (mDNSu16
)(CompressedDomainNameLength(&rd
->soa
.mname
, name
) +
1094 CompressedDomainNameLength(&rd
->soa
.rname
, name
) +
1095 5 * sizeof(mDNSOpaque32
));
1096 case kDNSType_OPT
: return(rr
->rdlength
);
1097 default: debugf("Warning! Don't know how to get length of resource type %d", rr
->rrtype
);
1098 return(rr
->rdlength
);
1102 mDNSexport mDNSBool
ValidateRData(const mDNSu16 rrtype
, const mDNSu16 rdlength
, const RData
*const rd
)
1105 // Some (or perhaps all) versions of BIND named (name daemon) don't allow updates
1106 // with zero-length rdata, so for consistency we don't allow them for mDNS either.
1107 // Otherwise we risk having applications that work with mDNS but not with uDNS.
1108 if (!rdlength
) return(mDNSfalse
);
1112 case kDNSType_A
: return(rdlength
== sizeof(mDNSv4Addr
));
1114 case kDNSType_NS
: // Same as PTR
1115 case kDNSType_MD
: // Same as PTR
1116 case kDNSType_MF
: // Same as PTR
1117 case kDNSType_CNAME
:// Same as PTR
1118 //case kDNSType_SOA not checked
1119 case kDNSType_MB
: // Same as PTR
1120 case kDNSType_MG
: // Same as PTR
1121 case kDNSType_MR
: // Same as PTR
1122 //case kDNSType_NULL not checked (no specified format, so always valid)
1123 //case kDNSType_WKS not checked
1124 case kDNSType_PTR
: len
= DomainNameLength(&rd
->u
.name
);
1125 return(len
<= MAX_DOMAIN_NAME
&& rdlength
== len
);
1127 case kDNSType_HINFO
:// Same as TXT (roughly)
1128 case kDNSType_MINFO
:// Same as TXT (roughly)
1129 case kDNSType_TXT
: {
1130 const mDNSu8
*ptr
= rd
->u
.txt
.c
;
1131 const mDNSu8
*end
= rd
->u
.txt
.c
+ rdlength
;
1132 while (ptr
< end
) ptr
+= 1 + ptr
[0];
1133 return (ptr
== end
);
1136 case kDNSType_AAAA
: return(rdlength
== sizeof(mDNSv6Addr
));
1138 case kDNSType_MX
: len
= DomainNameLength(&rd
->u
.mx
.exchange
);
1139 return(len
<= MAX_DOMAIN_NAME
&& rdlength
== 2+len
);
1141 case kDNSType_SRV
: len
= DomainNameLength(&rd
->u
.srv
.target
);
1142 return(len
<= MAX_DOMAIN_NAME
&& rdlength
== 6+len
);
1144 default: return(mDNStrue
); // Allow all other types without checking
1148 // ***************************************************************************
1149 #if COMPILER_LIKES_PRAGMA_MARK
1152 #pragma mark - DNS Message Creation Functions
1155 mDNSexport
void InitializeDNSMessage(DNSMessageHeader
*h
, mDNSOpaque16 id
, mDNSOpaque16 flags
)
1159 h
->numQuestions
= 0;
1161 h
->numAuthorities
= 0;
1162 h
->numAdditionals
= 0;
1165 mDNSexport
const mDNSu8
*FindCompressionPointer(const mDNSu8
*const base
, const mDNSu8
*const end
, const mDNSu8
*const domname
)
1167 const mDNSu8
*result
= end
- *domname
- 1;
1169 if (*domname
== 0) return(mDNSNULL
); // There's no point trying to match just the root label
1171 // This loop examines each possible starting position in packet, starting end of the packet and working backwards
1172 while (result
>= base
)
1174 // If the length byte and first character of the label match, then check further to see
1175 // if this location in the packet will yield a useful name compression pointer.
1176 if (result
[0] == domname
[0] && result
[1] == domname
[1])
1178 const mDNSu8
*name
= domname
;
1179 const mDNSu8
*targ
= result
;
1180 while (targ
+ *name
< end
)
1182 // First see if this label matches
1184 const mDNSu8
*pointertarget
;
1185 for (i
=0; i
<= *name
; i
++) if (targ
[i
] != name
[i
]) break;
1186 if (i
<= *name
) break; // If label did not match, bail out
1187 targ
+= 1 + *name
; // Else, did match, so advance target pointer
1188 name
+= 1 + *name
; // and proceed to check next label
1189 if (*name
== 0 && *targ
== 0) return(result
); // If no more labels, we found a match!
1190 if (*name
== 0) break; // If no more labels to match, we failed, so bail out
1192 // The label matched, so now follow the pointer (if appropriate) and then see if the next label matches
1193 if (targ
[0] < 0x40) continue; // If length value, continue to check next label
1194 if (targ
[0] < 0xC0) break; // If 40-BF, not valid
1195 if (targ
+1 >= end
) break; // Second byte not present!
1196 pointertarget
= base
+ (((mDNSu16
)(targ
[0] & 0x3F)) << 8) + targ
[1];
1197 if (targ
< pointertarget
) break; // Pointertarget must point *backwards* in the packet
1198 if (pointertarget
[0] >= 0x40) break; // Pointertarget must point to a valid length byte
1199 targ
= pointertarget
;
1202 result
--; // We failed to match at this search position, so back up the tentative result pointer and try again
1207 // Put a string of dot-separated labels as length-prefixed labels
1208 // domainname is a fully-qualified name (i.e. assumed to be ending in a dot, even if it doesn't)
1209 // msg points to the message we're building (pass mDNSNULL if we don't want to use compression pointers)
1210 // end points to the end of the message so far
1211 // ptr points to where we want to put the name
1212 // limit points to one byte past the end of the buffer that we must not overrun
1213 // domainname is the name to put
1214 mDNSexport mDNSu8
*putDomainNameAsLabels(const DNSMessage
*const msg
,
1215 mDNSu8
*ptr
, const mDNSu8
*const limit
, const domainname
*const name
)
1217 const mDNSu8
*const base
= (const mDNSu8
*)msg
;
1218 const mDNSu8
* np
= name
->c
;
1219 const mDNSu8
*const max
= name
->c
+ MAX_DOMAIN_NAME
; // Maximum that's valid
1220 const mDNSu8
* pointer
= mDNSNULL
;
1221 const mDNSu8
*const searchlimit
= ptr
;
1223 while (*np
&& ptr
< limit
-1) // While we've got characters in the name, and space to write them in the message...
1225 if (*np
> MAX_DOMAIN_LABEL
)
1226 { LogMsg("Malformed domain name %##s (label more than 63 bytes)", name
->c
); return(mDNSNULL
); }
1228 // This check correctly allows for the final trailing root label:
1230 // Suppose our domain name is exactly 255 bytes long, including the final trailing root label.
1231 // Suppose np is now at name->c[248], and we're about to write our last non-null label ("local").
1232 // We know that max will be at name->c[255]
1233 // That means that np + 1 + 5 == max - 1, so we (just) pass the "if" test below, write our
1234 // six bytes, then exit the loop, write the final terminating root label, and the domain
1235 // name we've written is exactly 255 bytes long, exactly at the correct legal limit.
1236 // If the name is one byte longer, then we fail the "if" test below, and correctly bail out.
1237 if (np
+ 1 + *np
>= max
)
1238 { LogMsg("Malformed domain name %##s (more than 255 bytes)", name
->c
); return(mDNSNULL
); }
1240 if (base
) pointer
= FindCompressionPointer(base
, searchlimit
, np
);
1241 if (pointer
) // Use a compression pointer if we can
1243 mDNSu16 offset
= (mDNSu16
)(pointer
- base
);
1244 *ptr
++ = (mDNSu8
)(0xC0 | (offset
>> 8));
1245 *ptr
++ = (mDNSu8
)( offset
& 0xFF);
1248 else // Else copy one label and try again
1252 if (ptr
+ 1 + len
>= limit
) return(mDNSNULL
);
1254 for (i
=0; i
<len
; i
++) *ptr
++ = *np
++;
1258 if (ptr
< limit
) // If we didn't run out of space
1260 *ptr
++ = 0; // Put the final root label
1261 return(ptr
); // and return
1267 mDNSlocal mDNSu8
*putVal16(mDNSu8
*ptr
, mDNSu16 val
)
1269 ptr
[0] = (mDNSu8
)((val
>> 8 ) & 0xFF);
1270 ptr
[1] = (mDNSu8
)((val
) & 0xFF);
1271 return ptr
+ sizeof(mDNSOpaque16
);
1274 mDNSlocal mDNSu8
*putVal32(mDNSu8
*ptr
, mDNSu32 val
)
1276 ptr
[0] = (mDNSu8
)((val
>> 24) & 0xFF);
1277 ptr
[1] = (mDNSu8
)((val
>> 16) & 0xFF);
1278 ptr
[2] = (mDNSu8
)((val
>> 8) & 0xFF);
1279 ptr
[3] = (mDNSu8
)((val
) & 0xFF);
1280 return ptr
+ sizeof(mDNSu32
);
1283 mDNSlocal mDNSu8
*putOptRData(mDNSu8
*ptr
, const mDNSu8
*limit
, ResourceRecord
*rr
)
1288 while (nput
< rr
->rdlength
)
1290 // check if space for opt/optlen
1291 if (ptr
+ (2 * sizeof(mDNSu16
)) > limit
) goto space_err
;
1292 opt
= (rdataOpt
*)(rr
->rdata
->u
.data
+ nput
);
1293 ptr
= putVal16(ptr
, opt
->opt
);
1294 ptr
= putVal16(ptr
, opt
->optlen
);
1295 nput
+= 2 * sizeof(mDNSu16
);
1296 if (opt
->opt
== kDNSOpt_LLQ
)
1298 if (ptr
+ sizeof(LLQOptData
) > limit
) goto space_err
;
1299 ptr
= putVal16(ptr
, opt
->OptData
.llq
.vers
);
1300 ptr
= putVal16(ptr
, opt
->OptData
.llq
.llqOp
);
1301 ptr
= putVal16(ptr
, opt
->OptData
.llq
.err
);
1302 mDNSPlatformMemCopy(opt
->OptData
.llq
.id
, ptr
, 8); // 8-byte id
1304 ptr
= putVal32(ptr
, opt
->OptData
.llq
.lease
);
1305 nput
+= sizeof(LLQOptData
);
1307 else if (opt
->opt
== kDNSOpt_Lease
)
1309 if (ptr
+ sizeof(mDNSs32
) > limit
) goto space_err
;
1310 ptr
= putVal32(ptr
, opt
->OptData
.lease
);
1311 nput
+= sizeof(mDNSs32
);
1313 else { LogMsg("putOptRData - unknown option %d", opt
->opt
); return mDNSNULL
; }
1319 LogMsg("ERROR: putOptRData - out of space");
1323 mDNSlocal mDNSu16
getVal16(const mDNSu8
**ptr
)
1325 mDNSu16 val
= (mDNSu16
)(((mDNSu16
)(*ptr
)[0]) << 8 | (*ptr
)[1]);
1326 *ptr
+= sizeof(mDNSOpaque16
);
1330 mDNSlocal
const mDNSu8
*getOptRdata(const mDNSu8
*ptr
, const mDNSu8
*limit
, ResourceRecord
*rr
, mDNSu16 pktRDLen
)
1335 while (nread
< pktRDLen
)
1337 opt
= (rdataOpt
*)(rr
->rdata
->u
.data
+ nread
);
1338 // space for opt + optlen
1339 if (nread
+ (2 * sizeof(mDNSu16
)) > rr
->rdata
->MaxRDLength
) goto space_err
;
1340 opt
->opt
= getVal16(&ptr
);
1341 opt
->optlen
= getVal16(&ptr
);
1342 nread
+= 2 * sizeof(mDNSu16
);
1343 if (opt
->opt
== kDNSOpt_LLQ
)
1345 if ((unsigned)(limit
- ptr
) < sizeof(LLQOptData
)) goto space_err
;
1346 opt
->OptData
.llq
.vers
= getVal16(&ptr
);
1347 opt
->OptData
.llq
.llqOp
= getVal16(&ptr
);
1348 opt
->OptData
.llq
.err
= getVal16(&ptr
);
1349 mDNSPlatformMemCopy(ptr
, opt
->OptData
.llq
.id
, 8);
1351 opt
->OptData
.llq
.lease
= (mDNSu32
) ((mDNSu32
)ptr
[0] << 24 | (mDNSu32
)ptr
[1] << 16 | (mDNSu32
)ptr
[2] << 8 | ptr
[3]);
1352 if (opt
->OptData
.llq
.lease
> 0x70000000UL
/ mDNSPlatformOneSecond
)
1353 opt
->OptData
.llq
.lease
= 0x70000000UL
/ mDNSPlatformOneSecond
;
1354 ptr
+= sizeof(mDNSOpaque32
);
1355 nread
+= sizeof(LLQOptData
);
1357 else if (opt
->opt
== kDNSOpt_Lease
)
1359 if ((unsigned)(limit
- ptr
) < sizeof(mDNSs32
)) goto space_err
;
1361 opt
->OptData
.lease
= (mDNSu32
) ((mDNSu32
)ptr
[0] << 24 | (mDNSu32
)ptr
[1] << 16 | (mDNSu32
)ptr
[2] << 8 | ptr
[3]);
1362 if (opt
->OptData
.lease
> 0x70000000UL
/ mDNSPlatformOneSecond
)
1363 opt
->OptData
.lease
= 0x70000000UL
/ mDNSPlatformOneSecond
;
1364 ptr
+= sizeof(mDNSs32
);
1365 nread
+= sizeof(mDNSs32
);
1367 else { LogMsg("ERROR: getOptRdata - unknown opt %d", opt
->opt
); return mDNSNULL
; }
1370 rr
->rdlength
= pktRDLen
;
1374 LogMsg("ERROR: getLLQRdata - out of space");
1378 mDNSexport mDNSu8
*putRData(const DNSMessage
*const msg
, mDNSu8
*ptr
, const mDNSu8
*const limit
, ResourceRecord
*rr
)
1382 case kDNSType_A
: if (rr
->rdlength
!= 4)
1384 debugf("putRData: Illegal length %d for kDNSType_A", rr
->rdlength
);
1387 if (ptr
+ 4 > limit
) return(mDNSNULL
);
1388 *ptr
++ = rr
->rdata
->u
.ipv4
.b
[0];
1389 *ptr
++ = rr
->rdata
->u
.ipv4
.b
[1];
1390 *ptr
++ = rr
->rdata
->u
.ipv4
.b
[2];
1391 *ptr
++ = rr
->rdata
->u
.ipv4
.b
[3];
1394 case kDNSType_CNAME
:// Same as PTR
1395 case kDNSType_PTR
: return(putDomainNameAsLabels(msg
, ptr
, limit
, &rr
->rdata
->u
.name
));
1397 case kDNSType_AAAA
: if (rr
->rdlength
!= sizeof(rr
->rdata
->u
.ipv6
))
1399 debugf("putRData: Illegal length %d for kDNSType_AAAA", rr
->rdlength
);
1402 if (ptr
+ sizeof(rr
->rdata
->u
.ipv6
) > limit
) return(mDNSNULL
);
1403 mDNSPlatformMemCopy(&rr
->rdata
->u
.ipv6
, ptr
, sizeof(rr
->rdata
->u
.ipv6
));
1404 return(ptr
+ sizeof(rr
->rdata
->u
.ipv6
));
1406 case kDNSType_SRV
: if (ptr
+ 6 > limit
) return(mDNSNULL
);
1407 *ptr
++ = (mDNSu8
)(rr
->rdata
->u
.srv
.priority
>> 8);
1408 *ptr
++ = (mDNSu8
)(rr
->rdata
->u
.srv
.priority
& 0xFF);
1409 *ptr
++ = (mDNSu8
)(rr
->rdata
->u
.srv
.weight
>> 8);
1410 *ptr
++ = (mDNSu8
)(rr
->rdata
->u
.srv
.weight
& 0xFF);
1411 *ptr
++ = rr
->rdata
->u
.srv
.port
.b
[0];
1412 *ptr
++ = rr
->rdata
->u
.srv
.port
.b
[1];
1413 return(putDomainNameAsLabels(msg
, ptr
, limit
, &rr
->rdata
->u
.srv
.target
));
1414 case kDNSType_OPT
: return putOptRData(ptr
, limit
, rr
);
1416 default: debugf("putRData: Warning! Writing unknown resource type %d as raw data", rr
->rrtype
);
1417 // Fall through to common code below
1418 case kDNSType_HINFO
:
1420 case kDNSType_TSIG
: if (ptr
+ rr
->rdlength
> limit
) return(mDNSNULL
);
1421 mDNSPlatformMemCopy(rr
->rdata
->u
.data
, ptr
, rr
->rdlength
);
1422 return(ptr
+ rr
->rdlength
);
1426 mDNSexport mDNSu8
*PutResourceRecordTTLWithLimit(DNSMessage
*const msg
, mDNSu8
*ptr
, mDNSu16
*count
, ResourceRecord
*rr
, mDNSu32 ttl
, const mDNSu8
*limit
)
1429 mDNSu16 actualLength
;
1431 if (rr
->RecordType
== kDNSRecordTypeUnregistered
)
1433 LogMsg("PutResourceRecord ERROR! Attempt to put kDNSRecordTypeUnregistered %##s (%s)", rr
->name
->c
, DNSTypeName(rr
->rrtype
));
1437 ptr
= putDomainNameAsLabels(msg
, ptr
, limit
, rr
->name
);
1438 if (!ptr
|| ptr
+ 10 >= limit
) return(mDNSNULL
); // If we're out-of-space, return mDNSNULL
1439 ptr
[0] = (mDNSu8
)(rr
->rrtype
>> 8);
1440 ptr
[1] = (mDNSu8
)(rr
->rrtype
& 0xFF);
1441 ptr
[2] = (mDNSu8
)(rr
->rrclass
>> 8);
1442 ptr
[3] = (mDNSu8
)(rr
->rrclass
& 0xFF);
1443 ptr
[4] = (mDNSu8
)((ttl
>> 24) & 0xFF);
1444 ptr
[5] = (mDNSu8
)((ttl
>> 16) & 0xFF);
1445 ptr
[6] = (mDNSu8
)((ttl
>> 8) & 0xFF);
1446 ptr
[7] = (mDNSu8
)( ttl
& 0xFF);
1447 endofrdata
= putRData(msg
, ptr
+10, limit
, rr
);
1448 if (!endofrdata
) { verbosedebugf("Ran out of space in PutResourceRecord for %##s (%s)", rr
->name
->c
, DNSTypeName(rr
->rrtype
)); return(mDNSNULL
); }
1450 // Go back and fill in the actual number of data bytes we wrote
1451 // (actualLength can be less than rdlength when domain name compression is used)
1452 actualLength
= (mDNSu16
)(endofrdata
- ptr
- 10);
1453 ptr
[8] = (mDNSu8
)(actualLength
>> 8);
1454 ptr
[9] = (mDNSu8
)(actualLength
& 0xFF);
1456 if (count
) (*count
)++;
1457 else LogMsg("PutResourceRecordTTL: ERROR: No target count to update for %##s (%s)", rr
->name
->c
, DNSTypeName(rr
->rrtype
));
1461 mDNSexport mDNSu8
*PutResourceRecordCappedTTL(DNSMessage
*const msg
, mDNSu8
*ptr
, mDNSu16
*count
, ResourceRecord
*rr
, mDNSu32
1464 if (maxttl
> rr
->rroriginalttl
) maxttl
= rr
->rroriginalttl
;
1465 return(PutResourceRecordTTL(msg
, ptr
, count
, rr
, maxttl
));
1468 mDNSexport mDNSu8
*putEmptyResourceRecord(DNSMessage
*const msg
, mDNSu8
*ptr
, const mDNSu8
*const limit
,
1469 mDNSu16
*count
, const AuthRecord
*rr
)
1471 ptr
= putDomainNameAsLabels(msg
, ptr
, limit
, rr
->resrec
.name
);
1472 if (!ptr
|| ptr
+ 10 > limit
) return(mDNSNULL
); // If we're out-of-space, return mDNSNULL
1473 ptr
[0] = (mDNSu8
)(rr
->resrec
.rrtype
>> 8); // Put type
1474 ptr
[1] = (mDNSu8
)(rr
->resrec
.rrtype
& 0xFF);
1475 ptr
[2] = (mDNSu8
)(rr
->resrec
.rrclass
>> 8); // Put class
1476 ptr
[3] = (mDNSu8
)(rr
->resrec
.rrclass
& 0xFF);
1477 ptr
[4] = ptr
[5] = ptr
[6] = ptr
[7] = 0; // TTL is zero
1478 ptr
[8] = ptr
[9] = 0; // RDATA length is zero
1483 mDNSexport mDNSu8
*putQuestion(DNSMessage
*const msg
, mDNSu8
*ptr
, const mDNSu8
*const limit
, const domainname
*const name
, mDNSu16 rrtype
, mDNSu16 rrclass
)
1485 ptr
= putDomainNameAsLabels(msg
, ptr
, limit
, name
);
1486 if (!ptr
|| ptr
+4 >= limit
) return(mDNSNULL
); // If we're out-of-space, return mDNSNULL
1487 ptr
[0] = (mDNSu8
)(rrtype
>> 8);
1488 ptr
[1] = (mDNSu8
)(rrtype
& 0xFF);
1489 ptr
[2] = (mDNSu8
)(rrclass
>> 8);
1490 ptr
[3] = (mDNSu8
)(rrclass
& 0xFF);
1491 msg
->h
.numQuestions
++;
1495 // for dynamic updates
1496 mDNSexport mDNSu8
*putZone(DNSMessage
*const msg
, mDNSu8
*ptr
, mDNSu8
*limit
, const domainname
*zone
, mDNSOpaque16 zoneClass
)
1498 ptr
= putDomainNameAsLabels(msg
, ptr
, limit
, zone
);
1499 if (!ptr
|| ptr
+ 4 > limit
) return mDNSNULL
; // If we're out-of-space, return NULL
1500 *ptr
++ = (mDNSu8
)(kDNSType_SOA
>> 8);
1501 *ptr
++ = (mDNSu8
)(kDNSType_SOA
& 0xFF);
1502 *ptr
++ = zoneClass
.b
[0];
1503 *ptr
++ = zoneClass
.b
[1];
1504 msg
->h
.mDNS_numZones
++;
1508 // for dynamic updates
1509 mDNSexport mDNSu8
*putPrereqNameNotInUse(domainname
*name
, DNSMessage
*msg
, mDNSu8
*ptr
, mDNSu8
*end
)
1513 mDNSPlatformMemZero(&prereq
, sizeof(AuthRecord
));
1514 mDNS_SetupResourceRecord(&prereq
, mDNSNULL
, mDNSInterface_Any
, kDNSQType_ANY
, kStandardTTL
, 0, mDNSNULL
, mDNSNULL
);
1515 AssignDomainName(prereq
.resrec
.name
, name
);
1516 prereq
.resrec
.rrtype
= kDNSQType_ANY
;
1517 prereq
.resrec
.rrclass
= kDNSClass_NONE
;
1518 ptr
= putEmptyResourceRecord(msg
, ptr
, end
, &msg
->h
.mDNS_numPrereqs
, &prereq
);
1522 // for dynamic updates
1523 mDNSexport mDNSu8
*putDeletionRecord(DNSMessage
*msg
, mDNSu8
*ptr
, ResourceRecord
*rr
)
1526 // deletion: specify record w/ TTL 0, class NONE
1528 origclass
= rr
->rrclass
;
1529 rr
->rrclass
= kDNSClass_NONE
;
1530 ptr
= PutResourceRecordTTLJumbo(msg
, ptr
, &msg
->h
.mDNS_numUpdates
, rr
, 0);
1531 rr
->rrclass
= origclass
;
1535 mDNSexport mDNSu8
*putDeleteRRSet(DNSMessage
*msg
, mDNSu8
*ptr
, const domainname
*name
, mDNSu16 rrtype
)
1537 const mDNSu8
*limit
= msg
->data
+ AbsoluteMaxDNSMessageData
;
1538 mDNSu16
class = kDNSQClass_ANY
;
1540 ptr
= putDomainNameAsLabels(msg
, ptr
, limit
, name
);
1541 if (!ptr
|| ptr
+ 10 >= limit
) return mDNSNULL
; // If we're out-of-space, return mDNSNULL
1542 ptr
[0] = (mDNSu8
)(rrtype
>> 8);
1543 ptr
[1] = (mDNSu8
)(rrtype
& 0xFF);
1544 ptr
[2] = (mDNSu8
)(class >> 8);
1545 ptr
[3] = (mDNSu8
)(class & 0xFF);
1546 ptr
[4] = ptr
[5] = ptr
[6] = ptr
[7] = 0; // zero ttl
1547 ptr
[8] = ptr
[9] = 0; // zero rdlength/rdata
1549 msg
->h
.mDNS_numUpdates
++;
1553 // for dynamic updates
1554 mDNSexport mDNSu8
*putDeleteAllRRSets(DNSMessage
*msg
, mDNSu8
*ptr
, const domainname
*name
)
1556 const mDNSu8
*limit
= msg
->data
+ AbsoluteMaxDNSMessageData
;
1557 mDNSu16
class = kDNSQClass_ANY
;
1558 mDNSu16 rrtype
= kDNSQType_ANY
;
1560 ptr
= putDomainNameAsLabels(msg
, ptr
, limit
, name
);
1561 if (!ptr
|| ptr
+ 10 >= limit
) return mDNSNULL
; // If we're out-of-space, return mDNSNULL
1562 ptr
[0] = (mDNSu8
)(rrtype
>> 8);
1563 ptr
[1] = (mDNSu8
)(rrtype
& 0xFF);
1564 ptr
[2] = (mDNSu8
)(class >> 8);
1565 ptr
[3] = (mDNSu8
)(class & 0xFF);
1566 ptr
[4] = ptr
[5] = ptr
[6] = ptr
[7] = 0; // zero ttl
1567 ptr
[8] = ptr
[9] = 0; // zero rdlength/rdata
1569 msg
->h
.mDNS_numUpdates
++;
1573 // for dynamic updates
1574 mDNSexport mDNSu8
*putUpdateLease(DNSMessage
*msg
, mDNSu8
*end
, mDNSu32 lease
)
1577 ResourceRecord
*opt
= &rr
.resrec
;
1580 mDNSPlatformMemZero(&rr
, sizeof(AuthRecord
));
1581 mDNS_SetupResourceRecord(&rr
, mDNSNULL
, mDNSInterface_Any
, kDNSType_OPT
, kStandardTTL
, 0, mDNSNULL
, mDNSNULL
);
1583 opt
->RecordType
= kDNSRecordTypeKnownUnique
; // to avoid warnings in other layers
1584 opt
->rrtype
= kDNSType_OPT
;
1585 opt
->rdlength
= LEASE_OPT_SIZE
;
1586 opt
->rdestimate
= LEASE_OPT_SIZE
;
1588 optRD
= &rr
.resrec
.rdata
->u
.opt
;
1589 optRD
->opt
= kDNSOpt_Lease
;
1590 optRD
->optlen
= sizeof(mDNSs32
);
1591 optRD
->OptData
.lease
= lease
;
1592 end
= PutResourceRecordTTLJumbo(msg
, end
, &msg
->h
.numAdditionals
, opt
, 0);
1593 if (!end
) { LogMsg("ERROR: putUpdateLease - PutResourceRecordTTL"); return mDNSNULL
; }
1598 // ***************************************************************************
1599 #if COMPILER_LIKES_PRAGMA_MARK
1601 #pragma mark - DNS Message Parsing Functions
1604 mDNSexport mDNSu32
DomainNameHashValue(const domainname
*const name
)
1609 for (c
= name
->c
; c
[0] != 0 && c
[1] != 0; c
+= 2)
1611 sum
+= ((mDNSIsUpperCase(c
[0]) ? c
[0] + 'a' - 'A' : c
[0]) << 8) |
1612 (mDNSIsUpperCase(c
[1]) ? c
[1] + 'a' - 'A' : c
[1]);
1613 sum
= (sum
<<3) | (sum
>>29);
1615 if (c
[0]) sum
+= ((mDNSIsUpperCase(c
[0]) ? c
[0] + 'a' - 'A' : c
[0]) << 8);
1619 mDNSexport
void SetNewRData(ResourceRecord
*const rr
, RData
*NewRData
, mDNSu16 rdlength
)
1624 rr
->rdata
= NewRData
;
1625 rr
->rdlength
= rdlength
;
1627 // Must not try to get target pointer until after updating rr->rdata
1628 target
= GetRRDomainNameTarget(rr
);
1629 rr
->rdlength
= GetRDLength(rr
, mDNSfalse
);
1630 rr
->rdestimate
= GetRDLength(rr
, mDNStrue
);
1631 rr
->rdatahash
= RDataHashValue(rr
->rdlength
, &rr
->rdata
->u
);
1632 rr
->rdnamehash
= target
? DomainNameHashValue(target
) : 0;
1635 mDNSexport
const mDNSu8
*skipDomainName(const DNSMessage
*const msg
, const mDNSu8
*ptr
, const mDNSu8
*const end
)
1639 if (ptr
< (mDNSu8
*)msg
|| ptr
>= end
)
1640 { debugf("skipDomainName: Illegal ptr not within packet boundaries"); return(mDNSNULL
); }
1642 while (1) // Read sequence of labels
1644 const mDNSu8 len
= *ptr
++; // Read length of this label
1645 if (len
== 0) return(ptr
); // If length is zero, that means this name is complete
1648 case 0x00: if (ptr
+ len
>= end
) // Remember: expect at least one more byte for the root label
1649 { debugf("skipDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL
); }
1650 if (total
+ 1 + len
>= MAX_DOMAIN_NAME
) // Remember: expect at least one more byte for the root label
1651 { debugf("skipDomainName: Malformed domain name (more than 255 characters)"); return(mDNSNULL
); }
1656 case 0x40: debugf("skipDomainName: Extended EDNS0 label types 0x%X not supported", len
); return(mDNSNULL
);
1657 case 0x80: debugf("skipDomainName: Illegal label length 0x%X", len
); return(mDNSNULL
);
1658 case 0xC0: return(ptr
+1);
1663 // Routine to fetch an FQDN from the DNS message, following compression pointers if necessary.
1664 mDNSexport
const mDNSu8
*getDomainName(const DNSMessage
*const msg
, const mDNSu8
*ptr
, const mDNSu8
*const end
,
1665 domainname
*const name
)
1667 const mDNSu8
*nextbyte
= mDNSNULL
; // Record where we got to before we started following pointers
1668 mDNSu8
*np
= name
->c
; // Name pointer
1669 const mDNSu8
*const limit
= np
+ MAX_DOMAIN_NAME
; // Limit so we don't overrun buffer
1671 if (ptr
< (mDNSu8
*)msg
|| ptr
>= end
)
1672 { debugf("getDomainName: Illegal ptr not within packet boundaries"); return(mDNSNULL
); }
1674 *np
= 0; // Tentatively place the root label here (may be overwritten if we have more labels)
1676 while (1) // Read sequence of labels
1678 const mDNSu8 len
= *ptr
++; // Read length of this label
1679 if (len
== 0) break; // If length is zero, that means this name is complete
1685 case 0x00: if (ptr
+ len
>= end
) // Remember: expect at least one more byte for the root label
1686 { debugf("getDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL
); }
1687 if (np
+ 1 + len
>= limit
) // Remember: expect at least one more byte for the root label
1688 { debugf("getDomainName: Malformed domain name (more than 255 characters)"); return(mDNSNULL
); }
1690 for (i
=0; i
<len
; i
++) *np
++ = *ptr
++;
1691 *np
= 0; // Tentatively place the root label here (may be overwritten if we have more labels)
1694 case 0x40: debugf("getDomainName: Extended EDNS0 label types 0x%X not supported in name %##s", len
, name
->c
);
1697 case 0x80: debugf("getDomainName: Illegal label length 0x%X in domain name %##s", len
, name
->c
); return(mDNSNULL
);
1699 case 0xC0: offset
= (mDNSu16
)((((mDNSu16
)(len
& 0x3F)) << 8) | *ptr
++);
1700 if (!nextbyte
) nextbyte
= ptr
; // Record where we got to before we started following pointers
1701 ptr
= (mDNSu8
*)msg
+ offset
;
1702 if (ptr
< (mDNSu8
*)msg
|| ptr
>= end
)
1703 { debugf("getDomainName: Illegal compression pointer not within packet boundaries"); return(mDNSNULL
); }
1705 { debugf("getDomainName: Compression pointer must point to real label"); return(mDNSNULL
); }
1710 if (nextbyte
) return(nextbyte
);
1714 mDNSexport
const mDNSu8
*skipResourceRecord(const DNSMessage
*msg
, const mDNSu8
*ptr
, const mDNSu8
*end
)
1716 mDNSu16 pktrdlength
;
1718 ptr
= skipDomainName(msg
, ptr
, end
);
1719 if (!ptr
) { debugf("skipResourceRecord: Malformed RR name"); return(mDNSNULL
); }
1721 if (ptr
+ 10 > end
) { debugf("skipResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL
); }
1722 pktrdlength
= (mDNSu16
)((mDNSu16
)ptr
[8] << 8 | ptr
[9]);
1724 if (ptr
+ pktrdlength
> end
) { debugf("skipResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL
); }
1726 return(ptr
+ pktrdlength
);
1729 mDNSexport
const mDNSu8
*GetLargeResourceRecord(mDNS
*const m
, const DNSMessage
* const msg
, const mDNSu8
*ptr
,
1730 const mDNSu8
*end
, const mDNSInterfaceID InterfaceID
, mDNSu8 RecordType
, LargeCacheRecord
*largecr
)
1732 CacheRecord
*rr
= &largecr
->r
;
1733 mDNSu16 pktrdlength
;
1735 if (largecr
== &m
->rec
&& rr
->resrec
.RecordType
)
1736 LogMsg("GetLargeResourceRecord: m->rec appears to be already in use");
1738 rr
->next
= mDNSNULL
;
1739 rr
->resrec
.RecordType
= RecordType
;
1740 rr
->resrec
.name
= &largecr
->namestorage
;
1742 rr
->NextInKAList
= mDNSNULL
;
1743 rr
->TimeRcvd
= m
? m
->timenow
: 0;
1744 rr
->DelayDelivery
= 0;
1745 rr
->NextRequiredQuery
= m
? m
->timenow
: 0; // Will be updated to the real value when we call SetNextCacheCheckTime()
1746 rr
->LastUsed
= m
? m
->timenow
: 0;
1747 rr
->CRActiveQuestion
= mDNSNULL
;
1748 rr
->UnansweredQueries
= 0;
1749 rr
->LastUnansweredTime
= 0;
1750 rr
->MPUnansweredQ
= 0;
1751 rr
->MPLastUnansweredQT
= 0;
1752 rr
->MPUnansweredKA
= 0;
1753 rr
->MPExpectingKA
= mDNSfalse
;
1754 rr
->NextInCFList
= mDNSNULL
;
1756 rr
->resrec
.InterfaceID
= InterfaceID
;
1757 ptr
= getDomainName(msg
, ptr
, end
, rr
->resrec
.name
);
1758 if (!ptr
) { debugf("GetResourceRecord: Malformed RR name"); return(mDNSNULL
); }
1760 if (ptr
+ 10 > end
) { debugf("GetResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL
); }
1762 rr
->resrec
.rrtype
= (mDNSu16
) ((mDNSu16
)ptr
[0] << 8 | ptr
[1]);
1763 rr
->resrec
.rrclass
= (mDNSu16
)(((mDNSu16
)ptr
[2] << 8 | ptr
[3]) & kDNSClass_Mask
);
1764 rr
->resrec
.rroriginalttl
= (mDNSu32
) ((mDNSu32
)ptr
[4] << 24 | (mDNSu32
)ptr
[5] << 16 | (mDNSu32
)ptr
[6] << 8 | ptr
[7]);
1765 if (rr
->resrec
.rroriginalttl
> 0x70000000UL
/ mDNSPlatformOneSecond
&& (mDNSs32
)rr
->resrec
.rroriginalttl
!= -1)
1766 rr
->resrec
.rroriginalttl
= 0x70000000UL
/ mDNSPlatformOneSecond
;
1767 // Note: We don't have to adjust m->NextCacheCheck here -- this is just getting a record into memory for
1768 // us to look at. If we decide to copy it into the cache, then we'll update m->NextCacheCheck accordingly.
1769 pktrdlength
= (mDNSu16
)((mDNSu16
)ptr
[8] << 8 | ptr
[9]);
1770 if (ptr
[2] & (kDNSClass_UniqueRRSet
>> 8))
1771 rr
->resrec
.RecordType
|= kDNSRecordTypePacketUniqueMask
;
1773 if (ptr
+ pktrdlength
> end
) { debugf("GetResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL
); }
1774 end
= ptr
+ pktrdlength
; // Adjust end to indicate the end of the rdata for this resource record
1776 rr
->resrec
.rdata
= (RData
*)&rr
->rdatastorage
;
1777 rr
->resrec
.rdata
->MaxRDLength
= MaximumRDSize
;
1779 if (!RecordType
) LogMsg("GetLargeResourceRecord: No RecordType for %##s", rr
->resrec
.name
->c
);
1781 switch (rr
->resrec
.rrtype
)
1783 case kDNSType_A
: rr
->resrec
.rdata
->u
.ipv4
.b
[0] = ptr
[0];
1784 rr
->resrec
.rdata
->u
.ipv4
.b
[1] = ptr
[1];
1785 rr
->resrec
.rdata
->u
.ipv4
.b
[2] = ptr
[2];
1786 rr
->resrec
.rdata
->u
.ipv4
.b
[3] = ptr
[3];
1789 case kDNSType_CNAME
:// Same as PTR
1791 case kDNSType_PTR
: if (!getDomainName(msg
, ptr
, end
, &rr
->resrec
.rdata
->u
.name
))
1792 { debugf("GetResourceRecord: Malformed CNAME/PTR RDATA name"); return(mDNSNULL
); }
1793 //debugf("%##s PTR %##s rdlen %d", rr->resrec.name.c, rr->resrec.rdata->u.name.c, pktrdlength);
1796 case kDNSType_NULL
: //Same as TXT
1797 case kDNSType_HINFO
://Same as TXT
1798 case kDNSType_TXT
: if (pktrdlength
> rr
->resrec
.rdata
->MaxRDLength
)
1800 debugf("GetResourceRecord: %s rdata size (%d) exceeds storage (%d)",
1801 DNSTypeName(rr
->resrec
.rrtype
), pktrdlength
, rr
->resrec
.rdata
->MaxRDLength
);
1804 rr
->resrec
.rdlength
= pktrdlength
;
1805 mDNSPlatformMemCopy(ptr
, rr
->resrec
.rdata
->u
.data
, pktrdlength
);
1808 case kDNSType_AAAA
: mDNSPlatformMemCopy(ptr
, &rr
->resrec
.rdata
->u
.ipv6
, sizeof(rr
->resrec
.rdata
->u
.ipv6
));
1811 case kDNSType_SRV
: rr
->resrec
.rdata
->u
.srv
.priority
= (mDNSu16
)((mDNSu16
)ptr
[0] << 8 | ptr
[1]);
1812 rr
->resrec
.rdata
->u
.srv
.weight
= (mDNSu16
)((mDNSu16
)ptr
[2] << 8 | ptr
[3]);
1813 rr
->resrec
.rdata
->u
.srv
.port
.b
[0] = ptr
[4];
1814 rr
->resrec
.rdata
->u
.srv
.port
.b
[1] = ptr
[5];
1815 if (!getDomainName(msg
, ptr
+6, end
, &rr
->resrec
.rdata
->u
.srv
.target
))
1816 { debugf("GetResourceRecord: Malformed SRV RDATA name"); return(mDNSNULL
); }
1817 //debugf("%##s SRV %##s rdlen %d", rr->resrec.name.c, rr->resrec.rdata->u.srv.target.c, pktrdlength);
1820 case kDNSType_SOA
: ptr
= getDomainName(msg
, ptr
, end
, &rr
->resrec
.rdata
->u
.soa
.mname
);
1821 if (!ptr
) { debugf("GetResourceRecord: Malformed SOA RDATA mname"); return mDNSNULL
; }
1822 ptr
= getDomainName(msg
, ptr
, end
, &rr
->resrec
.rdata
->u
.soa
.rname
);
1823 if (!ptr
) { debugf("GetResourceRecord: Malformed SOA RDATA rname"); return mDNSNULL
; }
1824 if (ptr
+ 0x14 != end
) { debugf("GetResourceRecord: Malformed SOA RDATA"); return mDNSNULL
; }
1825 rr
->resrec
.rdata
->u
.soa
.serial
= (mDNSs32
) ((mDNSs32
)ptr
[0x00] << 24 | (mDNSs32
)ptr
[0x01] << 16 | (mDNSs32
)ptr
[0x02] << 8 | ptr
[0x03]);
1826 rr
->resrec
.rdata
->u
.soa
.refresh
= (mDNSu32
) ((mDNSu32
)ptr
[0x04] << 24 | (mDNSu32
)ptr
[0x05] << 16 | (mDNSu32
)ptr
[0x06] << 8 | ptr
[0x07]);
1827 rr
->resrec
.rdata
->u
.soa
.retry
= (mDNSu32
) ((mDNSu32
)ptr
[0x08] << 24 | (mDNSu32
)ptr
[0x09] << 16 | (mDNSu32
)ptr
[0x0A] << 8 | ptr
[0x0B]);
1828 rr
->resrec
.rdata
->u
.soa
.expire
= (mDNSu32
) ((mDNSu32
)ptr
[0x0C] << 24 | (mDNSu32
)ptr
[0x0D] << 16 | (mDNSu32
)ptr
[0x0E] << 8 | ptr
[0x0F]);
1829 rr
->resrec
.rdata
->u
.soa
.min
= (mDNSu32
) ((mDNSu32
)ptr
[0x10] << 24 | (mDNSu32
)ptr
[0x11] << 16 | (mDNSu32
)ptr
[0x12] << 8 | ptr
[0x13]);
1832 case kDNSType_OPT
: getOptRdata(ptr
, end
, &rr
->resrec
, pktrdlength
); break;
1834 default: if (pktrdlength
> rr
->resrec
.rdata
->MaxRDLength
)
1836 debugf("GetResourceRecord: rdata %d (%s) size (%d) exceeds storage (%d)",
1837 rr
->resrec
.rrtype
, DNSTypeName(rr
->resrec
.rrtype
), pktrdlength
, rr
->resrec
.rdata
->MaxRDLength
);
1840 debugf("GetResourceRecord: Warning! Reading resource type %d (%s) as opaque data",
1841 rr
->resrec
.rrtype
, DNSTypeName(rr
->resrec
.rrtype
));
1842 // Note: Just because we don't understand the record type, that doesn't
1843 // mean we fail. The DNS protocol specifies rdlength, so we can
1844 // safely skip over unknown records and ignore them.
1845 // We also grab a binary copy of the rdata anyway, since the caller
1846 // might know how to interpret it even if we don't.
1847 rr
->resrec
.rdlength
= pktrdlength
;
1848 mDNSPlatformMemCopy(ptr
, rr
->resrec
.rdata
->u
.data
, pktrdlength
);
1852 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
1853 SetNewRData(&rr
->resrec
, mDNSNULL
, 0);
1855 return(ptr
+ pktrdlength
);
1858 mDNSexport
const mDNSu8
*skipQuestion(const DNSMessage
*msg
, const mDNSu8
*ptr
, const mDNSu8
*end
)
1860 ptr
= skipDomainName(msg
, ptr
, end
);
1861 if (!ptr
) { debugf("skipQuestion: Malformed domain name in DNS question section"); return(mDNSNULL
); }
1862 if (ptr
+4 > end
) { debugf("skipQuestion: Malformed DNS question section -- no query type and class!"); return(mDNSNULL
); }
1866 mDNSexport
const mDNSu8
*getQuestion(const DNSMessage
*msg
, const mDNSu8
*ptr
, const mDNSu8
*end
, const mDNSInterfaceID InterfaceID
,
1867 DNSQuestion
*question
)
1869 question
->InterfaceID
= InterfaceID
;
1870 ptr
= getDomainName(msg
, ptr
, end
, &question
->qname
);
1871 if (!ptr
) { debugf("Malformed domain name in DNS question section"); return(mDNSNULL
); }
1872 if (ptr
+4 > end
) { debugf("Malformed DNS question section -- no query type and class!"); return(mDNSNULL
); }
1874 question
->qnamehash
= DomainNameHashValue(&question
->qname
);
1875 question
->qtype
= (mDNSu16
)((mDNSu16
)ptr
[0] << 8 | ptr
[1]); // Get type
1876 question
->qclass
= (mDNSu16
)((mDNSu16
)ptr
[2] << 8 | ptr
[3]); // and class
1880 mDNSexport
const mDNSu8
*LocateAnswers(const DNSMessage
*const msg
, const mDNSu8
*const end
)
1883 const mDNSu8
*ptr
= msg
->data
;
1884 for (i
= 0; i
< msg
->h
.numQuestions
&& ptr
; i
++) ptr
= skipQuestion(msg
, ptr
, end
);
1888 mDNSexport
const mDNSu8
*LocateAuthorities(const DNSMessage
*const msg
, const mDNSu8
*const end
)
1891 const mDNSu8
*ptr
= LocateAnswers(msg
, end
);
1892 for (i
= 0; i
< msg
->h
.numAnswers
&& ptr
; i
++) ptr
= skipResourceRecord(msg
, ptr
, end
);
1896 mDNSexport
const mDNSu8
*LocateAdditionals(const DNSMessage
*const msg
, const mDNSu8
*const end
)
1899 const mDNSu8
*ptr
= LocateAuthorities(msg
, end
);
1900 for (i
= 0; i
< msg
->h
.numAuthorities
; i
++) ptr
= skipResourceRecord(msg
, ptr
, end
);
1904 // ***************************************************************************
1905 #if COMPILER_LIKES_PRAGMA_MARK
1908 #pragma mark - Packet Sending Functions
1911 mDNSexport mStatus
mDNSSendDNSMessage(const mDNS
*const m
, DNSMessage
*const msg
, mDNSu8
*end
,
1912 mDNSInterfaceID InterfaceID
, const mDNSAddr
*dst
, mDNSIPPort dstport
, int sd
, uDNS_AuthInfo
*authInfo
)
1918 mDNSu16 numQuestions
= msg
->h
.numQuestions
;
1919 mDNSu16 numAnswers
= msg
->h
.numAnswers
;
1920 mDNSu16 numAuthorities
= msg
->h
.numAuthorities
;
1921 mDNSu16 numAdditionals
= msg
->h
.numAdditionals
;
1922 mDNSu8
*ptr
= (mDNSu8
*)&msg
->h
.numQuestions
;
1924 // Put all the integer values in IETF byte-order (MSB first, LSB second)
1925 *ptr
++ = (mDNSu8
)(numQuestions
>> 8);
1926 *ptr
++ = (mDNSu8
)(numQuestions
& 0xFF);
1927 *ptr
++ = (mDNSu8
)(numAnswers
>> 8);
1928 *ptr
++ = (mDNSu8
)(numAnswers
& 0xFF);
1929 *ptr
++ = (mDNSu8
)(numAuthorities
>> 8);
1930 *ptr
++ = (mDNSu8
)(numAuthorities
& 0xFF);
1931 *ptr
++ = (mDNSu8
)(numAdditionals
>> 8);
1932 *ptr
++ = (mDNSu8
)(numAdditionals
& 0xFF);
1936 end
= DNSDigest_SignMessage(msg
, &end
, &numAdditionals
, authInfo
);
1937 if (!end
) return mStatus_UnknownErr
;
1940 // Send the packet on the wire
1944 msglen
= (mDNSu16
)(end
- (mDNSu8
*)msg
);
1945 lenbuf
[0] = (mDNSu8
)(msglen
>> 8); // host->network byte conversion
1946 lenbuf
[1] = (mDNSu8
)(msglen
& 0xFF);
1947 nsent
= mDNSPlatformWriteTCP(sd
, (char*)lenbuf
, 2);
1948 //!!!KRS make sure kernel is sending these as 1 packet!
1949 if (nsent
!= 2) goto tcp_error
;
1950 nsent
= mDNSPlatformWriteTCP(sd
, (char *)msg
, msglen
);
1951 if (nsent
!= msglen
) goto tcp_error
;
1952 status
= mStatus_NoError
;
1956 status
= mDNSPlatformSendUDP(m
, msg
, end
, InterfaceID
, dst
, dstport
);
1959 // Put all the integer values back the way they were before we return
1960 msg
->h
.numQuestions
= numQuestions
;
1961 msg
->h
.numAnswers
= numAnswers
;
1962 msg
->h
.numAuthorities
= numAuthorities
;
1963 msg
->h
.numAdditionals
= (mDNSu16
)(authInfo
? numAdditionals
- 1 : numAdditionals
);
1968 LogMsg("mDNSSendDNSMessage: error sending message over tcp");
1969 return mStatus_UnknownErr
;
1972 // ***************************************************************************
1973 #if COMPILER_LIKES_PRAGMA_MARK
1975 #pragma mark - RR List Management & Task Management
1978 mDNSexport
void mDNS_Lock(mDNS
*const m
)
1980 // MUST grab the platform lock FIRST!
1981 mDNSPlatformLock(m
);
1983 // Normally, mDNS_reentrancy is zero and so is mDNS_busy
1984 // However, when we call a client callback mDNS_busy is one, and we increment mDNS_reentrancy too
1985 // If that client callback does mDNS API calls, mDNS_reentrancy and mDNS_busy will both be one
1986 // If mDNS_busy != mDNS_reentrancy that's a bad sign
1987 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
)
1988 LogMsg("mDNS_Lock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
1990 // If this is an initial entry into the mDNSCore code, set m->timenow
1991 // else, if this is a re-entrant entry into the mDNSCore code, m->timenow should already be set
1992 if (m
->mDNS_busy
== 0)
1995 LogMsg("mDNS_Lock: m->timenow already set (%ld/%ld)", m
->timenow
, mDNSPlatformRawTime() + m
->timenow_adjust
);
1996 m
->timenow
= mDNSPlatformRawTime() + m
->timenow_adjust
;
1997 if (m
->timenow
== 0) m
->timenow
= 1;
1999 else if (m
->timenow
== 0)
2001 LogMsg("mDNS_Lock: m->mDNS_busy is %ld but m->timenow not set", m
->mDNS_busy
);
2002 m
->timenow
= mDNSPlatformRawTime() + m
->timenow_adjust
;
2003 if (m
->timenow
== 0) m
->timenow
= 1;
2006 if (m
->timenow_last
- m
->timenow
> 0)
2008 m
->timenow_adjust
+= m
->timenow_last
- m
->timenow
;
2009 LogMsg("mDNSPlatformRawTime went backwards by %ld ticks; setting correction factor to %ld", m
->timenow_last
- m
->timenow
, m
->timenow_adjust
);
2010 m
->timenow
= m
->timenow_last
;
2012 m
->timenow_last
= m
->timenow
;
2014 // Increment mDNS_busy so we'll recognise re-entrant calls
2018 mDNSlocal mDNSs32
GetNextScheduledEvent(const mDNS
*const m
)
2020 mDNSs32 e
= m
->timenow
+ 0x78000000;
2021 if (m
->mDNSPlatformStatus
!= mStatus_NoError
|| m
->SleepState
) return(e
);
2022 if (m
->NewQuestions
)
2024 if (m
->NewQuestions
->DelayAnswering
) e
= m
->NewQuestions
->DelayAnswering
;
2025 else return(m
->timenow
);
2027 if (m
->NewLocalOnlyQuestions
) return(m
->timenow
);
2028 if (m
->NewLocalRecords
&& LocalRecordReady(m
->NewLocalRecords
)) return(m
->timenow
);
2029 if (m
->SuppressSending
) return(m
->SuppressSending
);
2030 #ifndef UNICAST_DISABLED
2031 if (e
- m
->uDNS_info
.nextevent
> 0) e
= m
->uDNS_info
.nextevent
;
2033 if (e
- m
->NextCacheCheck
> 0) e
= m
->NextCacheCheck
;
2034 if (e
- m
->NextScheduledQuery
> 0) e
= m
->NextScheduledQuery
;
2035 if (e
- m
->NextScheduledProbe
> 0) e
= m
->NextScheduledProbe
;
2036 if (e
- m
->NextScheduledResponse
> 0) e
= m
->NextScheduledResponse
;
2040 mDNSexport
void mDNS_Unlock(mDNS
*const m
)
2042 // Decrement mDNS_busy
2045 // Check for locking failures
2046 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
)
2047 LogMsg("mDNS_Unlock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
2049 // If this is a final exit from the mDNSCore code, set m->NextScheduledEvent and clear m->timenow
2050 if (m
->mDNS_busy
== 0)
2052 m
->NextScheduledEvent
= GetNextScheduledEvent(m
);
2053 if (m
->timenow
== 0) LogMsg("mDNS_Unlock: ERROR! m->timenow aready zero");
2057 // MUST release the platform lock LAST!
2058 mDNSPlatformUnlock(m
);