2 * Copyright (c) 2002-2004 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.151 2004/12/13 21:45:08 ksekar
27 uDNS_DeregisterService should return NoError if called twice (to follow mDNS behavior expected by daemon layer)
29 Revision 1.150 2004/12/13 20:42:41 ksekar
32 Revision 1.149 2004/12/13 18:10:03 ksekar
35 Revision 1.148 2004/12/13 01:18:04 ksekar
36 Fixed unused variable warning for non-debug builds
38 Revision 1.147 2004/12/12 23:51:42 ksekar
39 <rdar://problem/3845683> Wide-area registrations should fallback to using DHCP hostname as target
41 Revision 1.146 2004/12/12 23:30:40 ksekar
42 <rdar://problem/3916987> Extra RRs not properly unlinked when parent service registration fails
44 Revision 1.145 2004/12/12 22:56:29 ksekar
45 <rdar://problem/3668508> Need to properly handle duplicate long-lived queries
47 Revision 1.144 2004/12/11 20:55:29 ksekar
48 <rdar://problem/3916479> Clean up registration state machines
50 Revision 1.143 2004/12/10 01:21:27 cheshire
51 <rdar://problem/3914089> Get rid of "LLQ Responses over TCP not currently supported" message
53 Revision 1.142 2004/12/08 02:03:31 ksekar
54 <rdar://problem/3865124> Looping on NAT Traversal error - check for
57 Revision 1.141 2004/12/07 01:39:28 cheshire
58 Don't fail if the same server is responsible for more than one domain
59 (e.g. the same DNS server may be responsible for both apple.com. and 17.in-addr.arpa.)
61 Revision 1.140 2004/12/06 21:15:22 ksekar
62 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
64 Revision 1.139 2004/12/06 19:08:03 cheshire
65 Add clarifying comment -- CountLabels() excludes the final root label.
67 Revision 1.138 2004/12/06 01:45:54 ksekar
68 Correct wording in LogMsg
70 Revision 1.137 2004/12/03 20:40:35 ksekar
71 <rdar://problem/3865124> Looping on NAT Traversal error
73 Revision 1.136 2004/12/03 07:20:50 ksekar
74 <rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
76 Revision 1.135 2004/12/03 05:18:33 ksekar
77 <rdar://problem/3810596> mDNSResponder needs to return more specific TSIG errors
79 Revision 1.134 2004/12/02 20:03:49 ksekar
80 <rdar://problem/3889647> Rendezvous still publishes wide-area domains even after switching to a local subnet
82 Revision 1.133 2004/12/02 18:37:52 ksekar
83 <rdar://problem/3758233> Registering with port number zero should not create a port mapping
85 Revision 1.132 2004/12/01 20:57:19 ksekar
86 <rdar://problem/3873921> Wide Area Rendezvous must be split-DNS aware
88 Revision 1.131 2004/12/01 19:59:27 cheshire
89 <rdar://problem/3882643> Crash in mDNSPlatformTCPConnect
90 If a TCP response has the TC bit set, don't respond by just trying another TCP connection
92 Revision 1.130 2004/12/01 02:43:23 cheshire
93 Don't call StatusCallback if function pointer is null
95 Revision 1.129 2004/11/30 23:51:06 cheshire
96 Remove double semicolons
98 Revision 1.128 2004/11/25 01:48:30 ksekar
99 <rdar://problem/3878991> Logging into VPN does not trigger registration of address record
101 Revision 1.127 2004/11/25 01:41:36 ksekar
102 Changed unnecessary LogMsgs to debugfs
104 Revision 1.126 2004/11/23 23:54:17 ksekar
105 <rdar://problem/3890318> Wide-Area DNSServiceRegisterRecord() failures
106 can crash mDNSResponder
108 Revision 1.125 2004/11/23 04:16:48 cheshire
109 Removed receiveMsg() routine.
111 Revision 1.124 2004/11/23 04:06:51 cheshire
112 Get rid of floating point constant -- in a small embedded device, bringing in all
113 the floating point libraries just to halve an integer value is a bit too heavyweight.
115 Revision 1.123 2004/11/22 17:16:20 ksekar
116 <rdar://problem/3854298> Unicast services don't disappear when you disable all networking
118 Revision 1.122 2004/11/19 18:00:34 ksekar
119 <rdar://problem/3682646> Security: use random ID for one-shot unicast queries
121 Revision 1.121 2004/11/19 04:24:08 ksekar
122 <rdar://problem/3682609> Security: Enforce a "window" on one-shot wide-area queries
124 Revision 1.120 2004/11/19 02:32:43 ksekar
125 <rdar://problem/3682608> Wide-Area Rendezvous Security: Add LLQ-ID to events
127 Revision 1.119 2004/11/18 23:21:24 ksekar
128 <rdar://problem/3764544> LLQ Security: Need to verify src port/address for LLQ handshake
130 Revision 1.118 2004/11/18 22:58:37 ksekar
133 Revision 1.117 2004/11/18 18:04:21 ksekar
134 Restore checkins lost due to repository disk failure: Update comments & <rdar://problem/3880688>
136 Revision 1.xxx 2004/11/17 06:17:57 cheshire
137 Update comments to show correct SRV names: _dns-update._udp.<zone>. and _dns-llq._udp.<zone>.
139 Revision 1.xxx 2004/11/17 00:45:28 ksekar
140 <rdar://problem/3880688> Result of putUpdateLease not error-checked
142 Revision 1.116 2004/11/16 01:41:47 ksekar
145 Revision 1.115 2004/11/15 20:09:24 ksekar
146 <rdar://problem/3719050> Wide Area support for Add/Remove record
148 Revision 1.114 2004/11/13 02:32:47 ksekar
149 <rdar://problem/3868216> LLQ mobility fragile on non-primary interface
150 - fixed incorrect state comparison in CheckQueries
152 Revision 1.113 2004/11/13 02:29:52 ksekar
153 <rdar://problem/3878386> LLQ refreshes not reliable
155 Revision 1.112 2004/11/11 20:45:14 ksekar
156 <rdar://problem/3876052> self-conflict test not compatible with some BIND servers
158 Revision 1.111 2004/11/11 20:14:55 ksekar
159 <rdar://problem/3719574> Wide-Area registrations not deregistered on sleep
161 Revision 1.110 2004/11/10 23:53:53 ksekar
162 Remove no longer relevant comment
164 Revision 1.109 2004/11/10 20:40:53 ksekar
165 <rdar://problem/3868216> LLQ mobility fragile on non-primary interface
167 Revision 1.108 2004/11/01 20:36:16 ksekar
168 <rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
170 Revision 1.107 2004/10/26 06:11:41 cheshire
171 Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
173 Revision 1.106 2004/10/26 03:52:03 cheshire
174 Update checkin comments
176 Revision 1.105 2004/10/26 01:15:06 cheshire
177 Use "#if 0" instead of commenting out code
179 Revision 1.104 2004/10/25 21:41:38 ksekar
180 <rdar://problem/3852958> wide-area name conflicts can cause crash
182 Revision 1.103 2004/10/25 19:30:52 ksekar
183 <rdar://problem/3827956> Simplify dynamic host name structures
185 Revision 1.102 2004/10/23 01:16:00 cheshire
186 <rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
188 Revision 1.101 2004/10/22 20:52:07 ksekar
189 <rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
191 Revision 1.100 2004/10/20 02:16:41 cheshire
192 Improve "could not confirm existence of NS record" error message
193 Don't call newRR->RecordCallback if it is NULL
195 Revision 1.99 2004/10/19 21:33:18 cheshire
196 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
197 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
198 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
200 Revision 1.98 2004/10/16 00:16:59 cheshire
201 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
203 Revision 1.97 2004/10/15 23:00:18 ksekar
204 <rdar://problem/3799242> Need to update LLQs on location changes
206 Revision 1.96 2004/10/12 23:30:44 ksekar
207 <rdar://problem/3609944> mDNSResponder needs to follow CNAME referrals
209 Revision 1.95 2004/10/12 03:15:09 ksekar
210 <rdar://problem/3835612> mDNS_StartQuery shouldn't return transient no-server error
212 Revision 1.94 2004/10/12 02:49:20 ksekar
213 <rdar://problem/3831228> Clean up LLQ sleep/wake, error handling
215 Revision 1.93 2004/10/08 04:17:25 ksekar
216 <rdar://problem/3831819> Don't use DNS extensions if the server does not advertise required SRV record
218 Revision 1.92 2004/10/08 03:54:35 ksekar
219 <rdar://problem/3831802> Refine unicast polling intervals
221 Revision 1.91 2004/09/30 17:45:34 ksekar
222 <rdar://problem/3821119> lots of log messages: mDNS_SetPrimaryIP: IP address unchanged
224 Revision 1.90 2004/09/25 00:22:13 ksekar
225 <rdar://problem/3815534> Crash in uDNS_RegisterService
227 Revision 1.89 2004/09/24 19:14:53 cheshire
228 Remove unused "extern mDNS mDNSStorage"
230 Revision 1.88 2004/09/23 20:48:15 ksekar
231 Clarify retransmission debugf messages.
233 Revision 1.87 2004/09/22 00:41:59 cheshire
234 Move tcp connection status codes into the legal range allocated for mDNS use
236 Revision 1.86 2004/09/21 23:40:11 ksekar
237 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
239 Revision 1.85 2004/09/21 22:38:27 ksekar
240 <rdar://problem/3810286> PrimaryIP type uninitialized
242 Revision 1.84 2004/09/18 00:30:39 cheshire
243 <rdar://problem/3806643> Infinite loop in CheckServiceRegistrations
245 Revision 1.83 2004/09/17 00:31:51 cheshire
246 For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
248 Revision 1.82 2004/09/16 21:36:36 cheshire
249 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
250 Changes to add necessary locking calls around unicast DNS operations
252 Revision 1.81 2004/09/16 02:29:39 cheshire
253 Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
254 uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
256 Revision 1.80 2004/09/16 01:58:21 cheshire
257 Fix compiler warnings
259 Revision 1.79 2004/09/16 00:24:48 cheshire
260 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
262 Revision 1.78 2004/09/15 01:16:57 ksekar
263 <rdar://problem/3797598> mDNSResponder printing too many messages
265 Revision 1.77 2004/09/14 23:27:47 cheshire
268 Revision 1.76 2004/09/14 22:22:00 ksekar
269 <rdar://problem/3800920> Legacy browses broken against some BIND versions
271 Revision 1.75 2004/09/03 19:23:05 ksekar
272 <rdar://problem/3788460>: Need retransmission mechanism for wide-area service registrations
274 Revision 1.74 2004/09/02 17:49:04 ksekar
275 <rdar://problem/3785135>: 8A246: mDNSResponder crash while logging on restart
276 Fixed incorrect conversions, changed %s to %##s for all domain names.
278 Revision 1.73 2004/09/02 01:39:40 cheshire
279 For better readability, follow consistent convention that QR bit comes first, followed by OP bits
281 Revision 1.72 2004/09/01 03:59:29 ksekar
282 <rdar://problem/3783453>: Conditionally compile out uDNS code on Windows
284 Revision 1.71 2004/08/27 17:51:53 ksekar
285 Replaced unnecessary LogMsg with debugf.
287 Revision 1.70 2004/08/25 00:37:27 ksekar
288 <rdar://problem/3774635>: Cleanup DynDNS hostname registration code
290 Revision 1.69 2004/08/18 17:35:41 ksekar
291 <rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
293 Revision 1.68 2004/08/14 03:22:41 cheshire
294 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
295 Add GetUserSpecifiedDDNSName() routine
296 Convert ServiceRegDomain to domainname instead of C string
297 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
299 Revision 1.67 2004/08/13 23:46:58 cheshire
300 "asyncronous" -> "asynchronous"
302 Revision 1.66 2004/08/13 23:37:02 cheshire
303 Now that we do both uDNS and mDNS, global replace "uDNS_info.hostname" with
304 "uDNS_info.UnicastHostname" for clarity
306 Revision 1.65 2004/08/13 23:12:32 cheshire
307 Don't use strcpy() and strlen() on "struct domainname" objects;
308 use AssignDomainName() and DomainNameLength() instead
309 (A "struct domainname" is a collection of packed pascal strings, not a C string.)
311 Revision 1.64 2004/08/13 23:01:05 cheshire
312 Use platform-independent mDNSNULL instead of NULL
314 Revision 1.63 2004/08/12 00:32:36 ksekar
315 <rdar://problem/3759567>: LLQ Refreshes never terminate if unanswered
317 Revision 1.62 2004/08/10 23:19:14 ksekar
318 <rdar://problem/3722542>: DNS Extension daemon for Wide Area Rendezvous
319 Moved routines/constants to allow extern access for garbage collection daemon
321 Revision 1.61 2004/07/30 17:40:06 ksekar
322 <rdar://problem/3739115>: TXT Record updates not available for wide-area services
324 Revision 1.60 2004/07/29 19:40:05 ksekar
325 NATPMP Support - minor fixes and cleanup
327 Revision 1.59 2004/07/29 19:27:15 ksekar
328 NATPMP Support - minor fixes and cleanup
330 Revision 1.58 2004/07/27 07:35:38 shersche
331 fix syntax error, variables declared in the middle of a block
333 Revision 1.57 2004/07/26 22:49:30 ksekar
334 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
336 Revision 1.56 2004/07/26 19:14:44 ksekar
337 <rdar://problem/3737814>: 8A210: mDNSResponder crashed in startLLQHandshakeCallback
339 Revision 1.55 2004/07/15 19:01:33 ksekar
340 <rdar://problem/3681029>: Check for incorrect time comparisons
342 Revision 1.54 2004/06/22 02:10:53 ksekar
343 <rdar://problem/3705433>: Lighthouse failure causes packet flood to DNS
345 Revision 1.53 2004/06/17 20:49:09 ksekar
346 <rdar://problem/3690436>: mDNSResponder crash while location cycling
348 Revision 1.52 2004/06/17 01:13:11 ksekar
349 <rdar://problem/3696616>: polling interval too short
351 Revision 1.51 2004/06/10 04:36:44 cheshire
354 Revision 1.50 2004/06/10 00:55:13 ksekar
355 <rdar://problem/3686213>: crash on network reconnect
357 Revision 1.49 2004/06/10 00:10:50 ksekar
358 <rdar://problem/3686174>: Infinite Loop in uDNS_Execute()
360 Revision 1.48 2004/06/09 20:03:37 ksekar
361 <rdar://problem/3686163>: Incorrect copying of resource record in deregistration
363 Revision 1.47 2004/06/09 03:48:28 ksekar
364 <rdar://problem/3685226>: nameserver address fails with prod. Lighthouse server
366 Revision 1.46 2004/06/09 01:44:30 ksekar
367 <rdar://problem/3681378> reworked Cache Record copy code
369 Revision 1.45 2004/06/08 18:54:47 ksekar
370 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
372 Revision 1.44 2004/06/05 00:33:51 cheshire
373 <rdar://problem/3681029>: Check for incorrect time comparisons
375 Revision 1.43 2004/06/05 00:14:44 cheshire
376 Fix signed/unsigned and other compiler warnings
378 Revision 1.42 2004/06/04 22:36:16 ksekar
379 Properly set u->nextevent in uDNS_Execute
381 Revision 1.41 2004/06/04 08:58:29 ksekar
382 <rdar://problem/3668624>: Keychain integration for secure dynamic update
384 Revision 1.40 2004/06/03 03:09:58 ksekar
385 <rdar://problem/3668626>: Garbage Collection for Dynamic Updates
387 Revision 1.39 2004/06/01 23:46:50 ksekar
388 <rdar://problem/3675149>: DynDNS: dynamically look up LLQ/Update ports
390 Revision 1.38 2004/05/31 22:19:44 ksekar
391 <rdar://problem/3258021>: Feature: DNS server->client notification on
392 record changes (#7805) - revert to polling mode on setup errors
394 Revision 1.37 2004/05/28 23:42:37 ksekar
395 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
397 Revision 1.36 2004/05/18 23:51:25 cheshire
398 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
400 Revision 1.35 2004/05/07 23:01:04 ksekar
401 Cleaned up list traversal in deriveGoodbyes - removed unnecessary
402 conditional assignment.
404 Revision 1.34 2004/05/05 18:26:12 ksekar
405 Periodically re-transmit questions if the send() fails. Include
406 internal questions in retransmission.
408 Revision 1.33 2004/05/05 17:40:06 ksekar
409 Removed prerequisite from deregistration update - it does not work for
410 shared records, and is unnecessary until we have more sophisticated
411 name conflict management.
413 Revision 1.32 2004/05/05 17:32:18 ksekar
414 Prevent registration of loopback interface caused by removal of
415 Multicast flag in interface structure.
417 Revision 1.31 2004/05/05 17:05:02 ksekar
418 Use LargeCacheRecord structs when pulling records off packets
420 Revision 1.30 2004/04/16 21:33:27 ksekar
421 Fixed bug in processing GetZoneData responses that do not use BIND formatting.
423 Revision 1.29 2004/04/15 20:03:13 ksekar
424 Clarified log message when pulling bad resource records off packet.
426 Revision 1.28 2004/04/15 00:51:28 bradley
427 Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers.
428 Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers.
430 Revision 1.27 2004/04/14 23:09:28 ksekar
431 Support for TSIG signed dynamic updates.
433 Revision 1.26 2004/04/14 19:36:05 ksekar
434 Fixed memory corruption error in deriveGoodbyes.
436 Revision 1.25 2004/04/14 04:07:11 ksekar
437 Fixed crash in IsActiveUnicastQuery(). Removed redundant checks in routine.
439 Revision 1.24 2004/04/08 09:41:40 bradley
440 Added const to AuthRecord in deadvertiseIfCallback to match callback typedef.
442 Revision 1.23 2004/03/24 00:29:45 ksekar
443 Make it safe to call StopQuery in a unicast question callback
445 Revision 1.22 2004/03/19 10:11:09 bradley
446 Added AuthRecord * cast from umalloc for C++ builds.
448 Revision 1.21 2004/03/15 02:03:45 bradley
449 Added const to params where needed to match prototypes. Changed SetNewRData calls to use 0 instead
450 of -1 for unused size to fix warning. Disable assignment within conditional warnings with Visual C++.
452 Revision 1.20 2004/03/13 02:07:26 ksekar
453 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
455 Revision 1.19 2004/03/13 01:57:33 ksekar
456 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
458 Revision 1.18 2004/02/21 08:34:15 bradley
459 Added casts from void * to specific type for C++ builds. Changed void * l-value cast
460 r-value cast to fix problems with VC++ builds. Removed empty switch to fix VC++ error.
462 Revision 1.17 2004/02/21 02:06:24 cheshire
463 Can't use anonymous unions -- they're non-standard and don't work on all compilers
465 Revision 1.16 2004/02/12 01:51:45 cheshire
466 Don't try to send uDNS queries unless we have at least one uDNS server available
468 Revision 1.15 2004/02/10 03:02:46 cheshire
471 Revision 1.14 2004/02/06 23:04:19 ksekar
472 Basic Dynamic Update support via mDNS_Register (dissabled via
473 UNICAST_REGISTRATION #define)
475 Revision 1.13 2004/02/03 22:15:01 ksekar
476 Fixed nameToAddr error check: don't abort state machine on nxdomain error.
478 Revision 1.12 2004/02/03 19:47:36 ksekar
479 Added an asynchronous state machine mechanism to uDNS.c, including
480 calls to find the parent zone for a domain name. Changes include code
481 in repository previously dissabled via "#if 0 incomplete". Codepath
482 is currently unused, and will be called to create update records, etc.
484 Revision 1.11 2004/01/30 02:12:30 ksekar
485 Changed uDNS_ReceiveMsg() to correctly return void.
487 Revision 1.10 2004/01/29 02:59:17 ksekar
488 Unicast DNS: Changed from a resource record oriented question/response
489 matching to packet based matching. New callback architecture allows
490 collections of records in a response to be processed differently
491 depending on the nature of the request, and allows the same structure
492 to be used for internal and client-driven queries with different processing needs.
494 Revision 1.9 2004/01/28 20:20:45 ksekar
495 Unified ActiveQueries and ActiveInternalQueries lists, using a flag to
496 demux them. Check-in includes work-in-progress code, #ifdef'd out.
498 Revision 1.8 2004/01/28 02:30:07 ksekar
499 Added default Search Domains to unicast browsing, controlled via
500 Networking sharing prefs pane. Stopped sending unicast messages on
501 every interface. Fixed unicast resolving via mach-port API.
503 Revision 1.7 2004/01/27 20:15:22 cheshire
504 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
506 Revision 1.6 2004/01/24 23:47:17 cheshire
507 Use mDNSOpaque16fromIntVal() instead of shifting and masking
509 Revision 1.5 2004/01/24 04:59:15 cheshire
510 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
512 Revision 1.4 2004/01/24 04:19:26 cheshire
513 Restore overwritten checkin 1.2
515 Revision 1.3 2004/01/23 23:23:15 ksekar
516 Added TCP support for truncated unicast messages.
518 Revision 1.2 2004/01/22 03:48:41 cheshire
519 Make sure uDNS client doesn't accidentally use query ID zero
521 Revision 1.1 2003/12/13 03:05:27 ksekar
522 <rdar://problem/3192548>: DynDNS: Unicast query of service records
528 #if(defined(_MSC_VER))
529 // Disable "assignment within conditional expression".
530 // Other compilers understand the convention that if you place the assignment expression within an extra pair
531 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
532 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
533 // to the compiler that the assignment is intentional, we have to just turn this warning off completely.
534 #pragma warning(disable:4706)
537 #define umalloc(x) mDNSPlatformMemAllocate(x) // short hands for common routines
538 #define ufree(x) mDNSPlatformMemFree(x)
539 #define ubzero(x,y) mDNSPlatformMemZero(x,y)
540 #define umemcpy(x, y, l) mDNSPlatformMemCopy(y, x, l) // uses memcpy(2) arg ordering
542 // Asynchronous operation types
547 // other async. operation names go here
553 mDNSAddr primaryAddr
;
556 mDNSIPPort updatePort
;
559 // other async. result struct defs go here
563 AsyncOpResultType type
;
565 // other async result structs go here
568 typedef void AsyncOpCallback(mStatus err
, mDNS
*const m
, void *info
, const AsyncOpResult
*result
);
571 // Private Function Prototypes
572 // Note: In general, functions are ordered such that they do not require forward declarations.
573 // However, prototypes are used where cyclic call graphs exist (e.g. foo calls bar, and bar calls
574 // foo), or when they aid in the grouping or readability of code (e.g. state machine code that is easier
575 // read top-to-bottom.)
577 mDNSlocal
void hndlTruncatedAnswer(DNSQuestion
*question
, const mDNSAddr
*src
, mDNS
*m
);
578 mDNSlocal mStatus
startGetZoneData(domainname
*name
, mDNS
*m
, mDNSBool findUpdatePort
, mDNSBool findLLQPort
, AsyncOpCallback callback
, void *callbackInfo
);
579 mDNSlocal mDNSBool
recvLLQResponse(mDNS
*m
, DNSMessage
*msg
, const mDNSu8
*end
, const mDNSAddr
*srcaddr
, mDNSIPPort srcport
, const mDNSInterfaceID InterfaceID
);
580 mDNSlocal
void sendRecordRegistration(mDNS
*const m
, AuthRecord
*rr
);
581 mDNSlocal
void SendServiceRegistration(mDNS
*m
, ServiceRecordSet
*srs
);
582 mDNSlocal
void SendServiceDeregistration(mDNS
*m
, ServiceRecordSet
*srs
);
583 mDNSlocal
void serviceRegistrationCallback(mStatus err
, mDNS
*const m
, void *srsPtr
, const AsyncOpResult
*result
);
584 mDNSlocal
void SendRecordUpdate(mDNS
*m
, AuthRecord
*rr
, uDNS_RegInfo
*info
);
585 mDNSlocal mStatus
RegisterService(mDNS
*m
, ServiceRecordSet
*srs
);
586 mDNSlocal
void SuspendLLQs(mDNS
*m
, mDNSBool DeregisterActive
);
587 mDNSlocal
void RestartQueries(mDNS
*m
);
588 mDNSlocal
void startLLQHandshake(mDNS
*m
, LLQ_Info
*info
, mDNSBool defer
);
589 mDNSlocal
void llqResponseHndlr(mDNS
* const m
, DNSMessage
*msg
, const mDNSu8
*end
, DNSQuestion
*question
, void *context
);
591 // ***************************************************************************
592 #if COMPILER_LIKES_PRAGMA_MARK
593 #pragma mark - Temporary workaround
596 // 17 Places in this file directly call mDNSPlatformTimeNow(), which is unsafe
597 // The platform function is now called mDNSPlatformRawTime(), and
598 // mDNSPlatformTimeNow() is defined here as a temporary workaround.
599 // This is a gross hack, and after this change has been tested for a while,
600 // all these calls should be replaced by simple references to m->timenow
602 mDNSlocal mDNSs32
mDNSPlatformTimeNow(mDNS
*m
)
604 if (m
->mDNS_busy
&& m
->timenow
) return(m
->timenow
);
605 LogMsg("ERROR: uDNS.c code executing without holding main mDNS lock");
607 // To get a quick and easy stack trace to find out *how* this routine
608 // is being called without holding main mDNS lock, uncomment the line below:
611 return(mDNS_TimeNow(m
));
614 // ***************************************************************************
615 #if COMPILER_LIKES_PRAGMA_MARK
616 #pragma mark - General Utility Functions
619 // CountLabels() returns number of labels in name, excluding final root label
620 // (e.g. for "apple.com." CountLabels returns 2.)
621 mDNSlocal
int CountLabels(const domainname
*d
)
626 for (ptr
= d
->c
; *ptr
; ptr
= ptr
+ ptr
[0] + 1) count
++;
630 mDNSlocal mDNSOpaque16
newMessageID(uDNS_GlobalInfo
*u
)
632 static mDNSBool randomized
= mDNSfalse
;
634 if (!randomized
) { u
->NextMessageID
= mDNSRandom(~0); randomized
= mDNStrue
; }
635 return mDNSOpaque16fromIntVal(u
->NextMessageID
++);
638 // unlink an AuthRecord from a linked list
639 mDNSlocal mStatus
unlinkAR(AuthRecord
**list
, AuthRecord
*const rr
)
641 AuthRecord
*rptr
, *prev
= mDNSNULL
;
643 for (rptr
= *list
; rptr
; rptr
= rptr
->next
)
647 if (prev
) prev
->next
= rptr
->next
;
648 else *list
= rptr
->next
;
649 rptr
->next
= mDNSNULL
;
650 return mStatus_NoError
;
654 LogMsg("ERROR: unlinkAR - no such active record");
655 return mStatus_UnknownErr
;
658 mDNSlocal
void unlinkSRS(uDNS_GlobalInfo
*u
, ServiceRecordSet
*srs
)
660 ServiceRecordSet
**p
;
661 for (p
= &u
->ServiceRegistrations
; *p
; p
= &(*p
)->next
)
662 if (*p
== srs
) { *p
= srs
->next
; srs
->next
= mDNSNULL
; return; }
663 LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list");
666 mDNSlocal
void LinkActiveQuestion(uDNS_GlobalInfo
*u
, DNSQuestion
*q
)
668 if (uDNS_IsActiveQuery(q
, u
))
669 { LogMsg("LinkActiveQuestion - %##s (%d) already in list!", q
->qname
.c
, q
->qtype
); return; }
671 q
->next
= u
->ActiveQueries
;
672 u
->ActiveQueries
= q
;
675 mDNSlocal
void SwapRData(mDNS
*m
, AuthRecord
*rr
, mDNSBool DeallocOld
)
677 RData
*oldrd
= rr
->resrec
.rdata
;
678 mDNSu16 oldrdlen
= rr
->resrec
.rdlength
;
680 if (!rr
->uDNS_info
.UpdateRData
) { LogMsg("SwapRData invoked with NULL UpdateRData field"); return; }
681 SetNewRData(&rr
->resrec
, rr
->uDNS_info
.UpdateRData
, rr
->uDNS_info
.UpdateRDLen
);
684 rr
->uDNS_info
.UpdateRData
= mDNSNULL
; // Clear the NewRData pointer ...
685 if (rr
->uDNS_info
.UpdateRDCallback
) rr
->uDNS_info
.UpdateRDCallback(m
, rr
, oldrd
); // ... and let the client know
689 rr
->uDNS_info
.UpdateRData
= oldrd
;
690 rr
->uDNS_info
.UpdateRDLen
= oldrdlen
;
694 // set retry timestamp for record with exponential backoff
695 // (for service record sets, use RR_SRV as representative for time checks
696 mDNSlocal
void SetRecordRetry(mDNS
*const m
, AuthRecord
*rr
)
698 rr
->LastAPTime
= mDNSPlatformTimeNow(m
);
699 if (rr
->ThisAPInterval
< INIT_UCAST_POLL_INTERVAL
) { rr
->ThisAPInterval
= INIT_UCAST_POLL_INTERVAL
; return; }
700 if (rr
->ThisAPInterval
*2 <= MAX_UCAST_POLL_INTERVAL
) { rr
->ThisAPInterval
*= 2; return; }
701 if (rr
->ThisAPInterval
!= MAX_UCAST_POLL_INTERVAL
) { rr
->ThisAPInterval
= MAX_UCAST_POLL_INTERVAL
; }
705 // ***************************************************************************
706 #if COMPILER_LIKES_PRAGMA_MARK
707 #pragma mark - Name Server List Management
710 mDNSexport
void mDNS_AddDNSServer(mDNS
*const m
, const mDNSAddr
*addr
, const domainname
*d
)
712 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
713 DNSServer
*s
, **p
= &u
->Servers
;
716 if (!d
) d
= (domainname
*)"";
718 while (*p
) // Check if we already have this {server,domain} pair registered
720 if (mDNSSameAddress(&(*p
)->addr
, addr
) && SameDomainName(&(*p
)->domain
, d
))
721 LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr
, d
->c
);
725 // allocate, add to list
726 s
= umalloc(sizeof(*s
));
727 if (!s
) { LogMsg("Error: mDNS_AddDNSServer - malloc"); goto end
; }
729 AssignDomainName(s
->domain
, *d
);
737 mDNSexport
void mDNS_DeleteDNSServers(mDNS
*const m
)
742 s
= m
->uDNS_info
.Servers
;
743 m
->uDNS_info
.Servers
= mDNSNULL
;
754 // ***************************************************************************
755 #if COMPILER_LIKES_PRAGMA_MARK
756 #pragma mark - authorization management
759 mDNSlocal uDNS_AuthInfo
*GetAuthInfoForZone(const uDNS_GlobalInfo
*u
, const domainname
*zone
)
764 for (ptr
= u
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
765 if (SameDomainName(&ptr
->zone
, zone
)) return(ptr
);
766 zone
= (const domainname
*)(zone
->c
+ 1 + zone
->c
[0]);
771 mDNSlocal
void DeleteAuthInfoForZone(uDNS_GlobalInfo
*u
, const domainname
*zone
)
773 uDNS_AuthInfo
*ptr
, *prev
= mDNSNULL
;
775 for (ptr
= u
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
777 if (SameDomainName(&ptr
->zone
, zone
))
779 if (prev
) prev
->next
= ptr
->next
;
780 else u
->AuthInfoList
= ptr
->next
;
788 mDNSexport mStatus
mDNS_SetSecretForZone(mDNS
*m
, const domainname
*zone
, const domainname
*key
, const mDNSu8
*sharedSecret
, mDNSu32 ssLen
, mDNSBool base64
)
793 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
794 mStatus status
= mStatus_NoError
;
798 if (GetAuthInfoForZone(u
, zone
)) DeleteAuthInfoForZone(u
, zone
);
801 info
= (uDNS_AuthInfo
*)umalloc(sizeof(uDNS_AuthInfo
) + ssLen
);
802 if (!info
) { LogMsg("ERROR: umalloc"); status
= mStatus_NoMemoryErr
; goto exit
; }
803 ubzero(info
, sizeof(uDNS_AuthInfo
));
804 AssignDomainName(info
->zone
, *zone
);
805 AssignDomainName(info
->keyname
, *key
);
809 keylen
= DNSDigest_Base64ToBin((const char*)sharedSecret
, keybuf
, 1024);
812 LogMsg("ERROR: mDNS_UpdateDomainRequiresAuthentication - could not convert shared secret from base64");
814 status
= mStatus_UnknownErr
;
817 DNSDigest_ConstructHMACKey(info
, keybuf
, (mDNSu32
)keylen
);
819 else DNSDigest_ConstructHMACKey(info
, sharedSecret
, ssLen
);
822 info
->next
= m
->uDNS_info
.AuthInfoList
;
823 m
->uDNS_info
.AuthInfoList
= info
;
829 // ***************************************************************************
830 #if COMPILER_LIKES_PRAGMA_MARK
831 #pragma mark - NAT Traversal
834 mDNSlocal mDNSBool
MapServicePort(mDNS
*m
)
836 uDNS_HostnameInfo
*i
;
838 //!!!KRS this could be cached
839 for (i
= m
->uDNS_info
.Hostnames
; i
; i
= i
->next
)
840 if (i
->ar
->uDNS_info
.NATinfo
&& i
->ar
->uDNS_info
.NATinfo
->state
!= NATState_Error
) return mDNStrue
;
845 mDNSlocal mDNSBool
DomainContainsLabelString(const domainname
*d
, const char *str
)
847 const domainlabel
*l
;
850 if (!MakeDomainLabelFromLiteralString(&buf
, str
)) return mDNSfalse
;
852 for (l
= (const domainlabel
*)d
; l
->c
[0]; l
= (const domainlabel
*)(l
->c
+ l
->c
[0]+1))
853 if (SameDomainLabel(l
->c
, buf
.c
)) return mDNStrue
;
857 // allocate struct, link into global list, initialize
858 mDNSlocal NATTraversalInfo
*AllocNATInfo(mDNS
*const m
, NATOp_t op
, NATResponseHndlr callback
)
860 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
861 NATTraversalInfo
*info
= umalloc(sizeof(NATTraversalInfo
));
862 if (!info
) { LogMsg("ERROR: malloc"); return mDNSNULL
; }
863 ubzero(info
, sizeof(NATTraversalInfo
));
864 info
->next
= u
->NATTraversals
;
865 u
->NATTraversals
= info
;
866 info
->retry
= mDNSPlatformTimeNow(m
) + NATMAP_INIT_RETRY
;
868 info
->state
= NATState_Init
;
869 info
->ReceiveResponse
= callback
;
870 info
->PublicPort
.NotAnInteger
= 0;
874 // unlink from list, deallocate
875 mDNSlocal mDNSBool
FreeNATInfo(mDNS
*m
, NATTraversalInfo
*n
)
877 NATTraversalInfo
*ptr
, *prev
= mDNSNULL
;
879 if (n
== m
->uDNS_info
.LLQNatInfo
) m
->uDNS_info
.LLQNatInfo
= mDNSNULL
;
880 ptr
= m
->uDNS_info
.NATTraversals
;
885 if (prev
) prev
->next
= ptr
->next
;
886 else m
->uDNS_info
.NATTraversals
= ptr
->next
;
893 LogMsg("FreeNATInfo: NATTraversalInfo not found in list");
897 mDNSlocal
void SendNATMsg(NATTraversalInfo
*info
, mDNS
*m
)
902 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
904 if (info
->state
!= NATState_Request
&& info
->state
!= NATState_Refresh
)
905 { LogMsg("SendNATMsg: Bad state %d", info
->state
); return; }
907 if (u
->Router
.ip
.v4
.NotAnInteger
)
909 // send msg if we have a router
910 dst
.type
= u
->Router
.type
;
911 dst
.ip
.v4
= u
->Router
.ip
.v4
;
912 dstport
= mDNSOpaque16fromIntVal(NATMAP_PORT
);
913 err
= mDNSPlatformSendUDP(m
, info
->request
, info
->request
+info
->requestlen
, 0, &dst
, dstport
);
914 if (!err
) (info
->ntries
++); // don't increment attempt counter if the send failed
918 if (info
->RetryInterval
< NATMAP_INIT_RETRY
) info
->RetryInterval
= NATMAP_INIT_RETRY
;
919 else if (info
->RetryInterval
* 2 > NATMAP_MAX_RETRY
) info
->RetryInterval
= NATMAP_MAX_RETRY
;
920 else info
->RetryInterval
*= 2;
921 info
->retry
= mDNSPlatformTimeNow(m
) + info
->RetryInterval
;
924 mDNSlocal
void ReceiveNATAddrResponse(NATTraversalInfo
*n
, mDNS
*m
, mDNSu8
*pkt
, mDNSu16 len
)
926 NATErr_t NatErr
= NATErr_None
;
927 mStatus err
= mStatus_NoError
;
928 AuthRecord
*rr
= mDNSNULL
;
931 if (n
->state
!= NATState_Request
)
933 LogMsg("ReceiveNATAddrResponse: bad state %d", n
->state
);
934 err
= mStatus_UnknownErr
;
938 rr
= n
->reg
.RecordRegistration
;
941 LogMsg("ReceiveNATAddrResponse: registration cancelled");
942 err
= mStatus_UnknownErr
;
946 addr
.type
= mDNSAddrType_IPv4
;
947 addr
.ip
.v4
= rr
->resrec
.rdata
->u
.ipv4
;
951 #ifdef _LEGACY_NAT_TRAVERSAL_
952 err
= LNT_GetPublicIP(&addr
.ip
.v4
);
954 else n
->state
= NATState_Legacy
;
956 debugf("ReceiveNATAddrResponse: timeout");
957 err
= mStatus_NATTraversal
;
959 #endif // _LEGACY_NAT_TRAVERSAL_
963 if (len
< ADDR_REPLY_PKTLEN
)
965 LogMsg("ReceiveNATAddrResponse: response too short (%d bytes)", len
);
966 err
= mStatus_NATTraversal
;
969 if (pkt
[0] != NATMAP_VERS
)
971 LogMsg("ReceiveNATAddrResponse: received version %d (expect version %d)", pkt
[0], NATMAP_VERS
);
972 err
= mStatus_NATTraversal
;
975 if (pkt
[1] != (NATOp_AddrRequest
| NATMAP_RESPONSE_MASK
))
977 LogMsg("ReceiveNATAddrResponse: bad response code %d", pkt
[1]);
978 err
= mStatus_NATTraversal
;
981 NatErr
= (NATErr_t
)((NATErr_t
)pkt
[2] << 8 | (NATErr_t
)pkt
[3]);
982 if (NatErr
) { LogMsg("ReceiveAddrResponse: received error %d", err
); err
= mStatus_NATTraversal
; goto end
; }
984 addr
.ip
.v4
.b
[0] = pkt
[4];
985 addr
.ip
.v4
.b
[1] = pkt
[5];
986 addr
.ip
.v4
.b
[2] = pkt
[6];
987 addr
.ip
.v4
.b
[3] = pkt
[7];
988 n
->state
= NATState_Established
;
991 if (IsPrivateV4Addr(&addr
))
993 LogMsg("ReceiveNATAddrResponse: Double NAT");
994 err
= mStatus_DblNAT
;
1004 rr
->uDNS_info
.NATinfo
= mDNSNULL
;
1005 rr
->uDNS_info
.state
= regState_Unregistered
; // note that rr is not yet in global list
1006 rr
->RecordCallback(m
, rr
, mStatus_NATTraversal
);
1007 // note - unsafe to touch rr after callback
1011 else LogMsg("Received public IP address %d.%d.%d.%d from NAT.", addr
.ip
.v4
.b
[0], addr
.ip
.v4
.b
[1], addr
.ip
.v4
.b
[2], addr
.ip
.v4
.b
[3]);
1012 rr
->resrec
.rdata
->u
.ipv4
= addr
.ip
.v4
; // replace rdata w/ public address
1013 uDNS_RegisterRecord(m
, rr
);
1017 mDNSlocal
void StartGetPublicAddr(mDNS
*m
, uDNS_HostnameInfo
*hInfo
)
1020 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1022 NATTraversalInfo
*info
= AllocNATInfo(m
, NATOp_AddrRequest
, ReceiveNATAddrResponse
);
1023 if (!info
) { uDNS_RegisterRecord(m
, hInfo
->ar
); return; }
1024 hInfo
->ar
->uDNS_info
.NATinfo
= info
;
1025 info
->reg
.RecordRegistration
= hInfo
->ar
;
1026 info
->state
= NATState_Request
;
1029 msg
= info
->request
;
1030 msg
[0] = NATMAP_VERS
;
1031 msg
[1] = NATOp_AddrRequest
;
1032 info
->requestlen
= ADDR_REQUEST_PKTLEN
;
1034 if (!u
->Router
.ip
.v4
.NotAnInteger
)
1036 debugf("No router. Will retry NAT traversal in %ld ticks", NATMAP_INIT_RETRY
);
1040 SendNATMsg(info
, m
);
1044 mDNSlocal
void RefreshNATMapping(NATTraversalInfo
*n
, mDNS
*m
)
1046 n
->state
= NATState_Refresh
;
1047 n
->RetryInterval
= NATMAP_INIT_RETRY
;
1052 mDNSlocal
void LLQNatMapComplete(mDNS
*m
)
1054 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1056 NATTraversalInfo
*n
= u
->LLQNatInfo
;
1058 if (!n
) { LogMsg("Error: LLQNatMapComplete called with NULL LLQNatInfo"); return; }
1059 if (n
->state
!= NATState_Established
&& n
->state
!= NATState_Legacy
&& n
->state
!= NATState_Error
)
1060 { LogMsg("LLQNatMapComplete - bad nat state %d", n
->state
); return; }
1062 u
->CurrentQuery
= u
->ActiveQueries
;
1063 while (u
->CurrentQuery
)
1065 DNSQuestion
*q
= u
->CurrentQuery
;
1066 u
->CurrentQuery
= u
->CurrentQuery
->next
;
1067 llqInfo
= q
->uDNS_info
.llq
;
1068 if (q
->LongLived
&& llqInfo
->state
== LLQ_NatMapWait
)
1070 if (n
->state
== NATState_Error
)
1072 llqInfo
->NATMap
= mDNSfalse
;
1073 llqInfo
->question
->uDNS_info
.responseCallback
= llqResponseHndlr
;
1074 llqInfo
->state
= LLQ_Poll
;
1075 llqInfo
->question
->LastQTime
= mDNSPlatformTimeNow(m
) - (2 * INIT_UCAST_POLL_INTERVAL
); // trigger immediate poll
1076 llqInfo
->question
->ThisQInterval
= INIT_UCAST_POLL_INTERVAL
;
1078 else { llqInfo
->state
= LLQ_GetZoneInfo
; startLLQHandshake(m
, llqInfo
, mDNSfalse
); }
1083 mDNSlocal
void ReceivePortMapReply(NATTraversalInfo
*n
, mDNS
*m
, mDNSu8
*pkt
, mDNSu16 len
)
1086 ServiceRecordSet
*srs
;
1087 mDNSIPPort priv
, pktpriv
, pub
;
1091 if (n
->state
!= NATState_Request
&& n
->state
!= NATState_Refresh
)
1092 { LogMsg("ReceivePortMapReply: bad state %d", n
->state
); return; }
1094 deletion
= !(n
->request
[8] | n
->request
[9] | n
->request
[10] | n
->request
[11]); // zero lease
1095 if (deletion
) { n
->state
= NATState_Deleted
; return; }
1096 // note that we explicitly ignore timeouts here
1097 // we keep the context struct around so that the SendServiceDeregistration code can reference
1098 // it to determine the public port to delete in the SRV record.
1100 srs
= n
->reg
.ServiceRegistration
;
1101 if (!srs
&& n
!= m
->uDNS_info
.LLQNatInfo
)
1103 debugf("ReceivePortMapReply: registration cancelled");
1108 priv
= srs
? srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
: m
->UnicastPort4
;
1110 if (!pkt
) // timeout
1112 #ifdef _LEGACY_NAT_TRAVERSAL_
1115 mDNSBool tcp
= (srs
&& DomainContainsLabelString(&srs
->RR_PTR
.resrec
.name
, "_tcp"));
1117 pub
= priv
; // initially request priv == pub
1120 err
= LNT_MapPort(priv
, pub
, tcp
);
1123 n
->PublicPort
= pub
;
1124 n
->state
= NATState_Legacy
;
1127 else if (err
!= mStatus_AlreadyRegistered
|| ++ntries
> LEGACY_NATMAP_MAX_TRIES
)
1129 n
->state
= NATState_Error
;
1134 // the mapping we want is taken - try a random port
1135 mDNSu16 RandPort
= mDNSRandom(DYN_PORT_MAX
- DYN_PORT_MIN
) + DYN_PORT_MIN
;
1136 pub
= mDNSOpaque16fromIntVal(RandPort
);
1141 #endif // _LEGACY_NAT_TRAVERSAL_
1144 if (len
< PORTMAP_PKTLEN
) { LogMsg("ReceivePortMapReply: response too short (%d bytes)", len
); goto end
; }
1145 if (pkt
[0] != NATMAP_VERS
) { LogMsg("ReceivePortMapReply: received version %d (expect version %d)", pkt
[0], NATMAP_VERS
); goto end
; }
1146 if (pkt
[1] != (n
->op
| NATMAP_RESPONSE_MASK
)) { LogMsg("ReceivePortMapReply: bad response code %d", pkt
[1]); goto end
; }
1147 err
= (NATErr_t
)((NATErr_t
)pkt
[2] << 8 | (NATErr_t
)pkt
[3]);
1148 if (err
) { LogMsg("ReceivePortMapReply: received error %d", err
); goto end
; }
1150 pktpriv
.b
[0] = pkt
[4];
1151 pktpriv
.b
[1] = pkt
[5];
1155 lease
= (mDNSu32
) ((mDNSu32
)pkt
[8] << 24 | (mDNSu32
)pkt
[9] << 16 | (mDNSu32
)pkt
[10] << 8 | pkt
[11]);
1156 if (lease
> 0x70000000UL
/ mDNSPlatformOneSecond
)
1157 lease
= 0x70000000UL
/ mDNSPlatformOneSecond
;
1159 if (priv
.NotAnInteger
!= pktpriv
.NotAnInteger
)
1160 { LogMsg("ReceivePortMapReply: reply private port does not match requested private port"); goto end
; }
1162 if (n
->state
== NATState_Refresh
&& pub
.NotAnInteger
!= n
->PublicPort
.NotAnInteger
)
1163 LogMsg("ReceivePortMapReply: NAT refresh changed public port from %d to %d", mDNSVal16(n
->PublicPort
), mDNSVal16(pub
));
1164 // !!!KRS we need to update the SRV here!
1165 n
->PublicPort
= pub
;
1167 n
->retry
= mDNSPlatformTimeNow(m
) + ((mDNSs32
)lease
* mDNSPlatformOneSecond
/2); // retry half way to expiration
1169 if (n
->state
== NATState_Refresh
) { n
->state
= NATState_Established
; return; }
1170 n
->state
= NATState_Established
;
1173 if (n
->state
!= NATState_Established
&& n
->state
!= NATState_Legacy
)
1175 LogMsg("NAT Port Mapping: timeout");
1176 n
->state
= NATState_Error
;
1177 if (!srs
) { LLQNatMapComplete(m
); return; }
1179 srs
->uDNS_info
.NATinfo
= mDNSNULL
;
1180 unlinkSRS(&m
->uDNS_info
, srs
);
1181 srs
->uDNS_info
.state
= regState_Unregistered
;
1182 srs
->ServiceCallback(m
, srs
, mStatus_NATTraversal
);
1183 return; // note - unsafe to touch srs here
1186 LogMsg("Mapped private port %d to public port %d", mDNSVal16(priv
), mDNSVal16(n
->PublicPort
));
1187 if (!srs
) { LLQNatMapComplete(m
); return; }
1188 srs
->uDNS_info
.state
= regState_FetchingZoneData
;
1189 startGetZoneData(&srs
->RR_SRV
.resrec
.name
, m
, mDNStrue
, mDNSfalse
, serviceRegistrationCallback
, srs
);
1192 mDNSlocal
void FormatPortMaprequest(NATTraversalInfo
*info
, mDNSIPPort port
)
1194 mDNSu8
*msg
= info
->request
;
1195 mDNSOpaque32 lease
= mDNSOpaque32fromIntVal(NATMAP_DEFAULT_LEASE
);
1197 msg
[0] = NATMAP_VERS
;
1199 msg
[2] = 0; // reserved
1200 msg
[3] = 0; // reserved
1201 msg
[4] = port
.b
[0]; // private port
1203 msg
[6] = port
.b
[0]; // requested pub. port
1206 msg
[8] = lease
.b
[0];
1207 msg
[9] = lease
.b
[1];
1208 msg
[10] = lease
.b
[2];
1209 msg
[11] = lease
.b
[3];
1212 mDNSlocal
void SendInitialPMapReq(mDNS
*m
, NATTraversalInfo
*info
)
1214 if (!m
->uDNS_info
.Router
.ip
.v4
.NotAnInteger
)
1216 debugf("No router. Will retry NAT traversal in %ld seconds", NATMAP_INIT_RETRY
);
1217 info
->retry
= mDNSPlatformTimeNow(m
) + NATMAP_INIT_RETRY
;
1218 info
->RetryInterval
= NATMAP_INIT_RETRY
;
1221 SendNATMsg(info
, m
);
1225 mDNSlocal
void StartNATPortMap(mDNS
*m
, ServiceRecordSet
*srs
)
1228 NATTraversalInfo
*info
;
1230 if (DomainContainsLabelString(&srs
->RR_PTR
.resrec
.name
, "_tcp")) op
= NATOp_MapTCP
;
1231 else if (DomainContainsLabelString(&srs
->RR_PTR
.resrec
.name
, "_udp")) op
= NATOp_MapUDP
;
1232 else { LogMsg("StartNATPortMap: could not determine transport protocol of service %##s", srs
->RR_SRV
.resrec
.name
.c
); goto error
; }
1234 info
= AllocNATInfo(m
, op
, ReceivePortMapReply
);
1235 srs
->uDNS_info
.NATinfo
= info
;
1236 info
->reg
.ServiceRegistration
= srs
;
1237 info
->state
= NATState_Request
;
1238 info
->requestlen
= PORTMAP_PKTLEN
;
1240 FormatPortMaprequest(info
, srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
);
1241 SendInitialPMapReq(m
, info
);
1245 startGetZoneData(&srs
->RR_SRV
.resrec
.name
, m
, mDNStrue
, mDNSfalse
, serviceRegistrationCallback
, srs
);
1248 mDNSlocal
void DeleteNATPortMapping(mDNS
*m
, NATTraversalInfo
*nat
, ServiceRecordSet
*srs
)
1250 if (nat
->state
== NATState_Established
) // let other edge-case states expire for simplicity
1253 nat
->request
[8] = 0;
1254 nat
->request
[9] = 0;
1255 nat
->request
[10] = 0 ;
1256 nat
->request
[11] = 0;
1257 nat
->state
= NATState_Request
;
1260 #ifdef _LEGACY_NAT_TRAVERSAL_
1261 else if (nat
->state
== NATState_Legacy
)
1263 mStatus err
= mStatus_NoError
;
1264 mDNSBool tcp
= srs
? DomainContainsLabelString(&srs
->RR_PTR
.resrec
.name
, "_tcp") : mDNSfalse
;
1265 err
= LNT_UnmapPort(nat
->PublicPort
, tcp
);
1266 if (err
) LogMsg("Legacy NAT Traversal - unmap request failed with error %ld", err
);
1269 (void)srs
; // unused
1270 #endif // _LEGACY_NAT_TRAVERSAL_
1273 mDNSlocal
void StartLLQNatMap(mDNS
*m
)
1275 NATTraversalInfo
*info
= AllocNATInfo(m
, NATOp_MapUDP
, ReceivePortMapReply
);
1276 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1278 u
->LLQNatInfo
= info
;
1280 info
->reg
.RecordRegistration
= mDNSNULL
;
1281 info
->reg
.ServiceRegistration
= mDNSNULL
;
1282 info
->state
= NATState_Request
;
1283 info
->requestlen
= PORTMAP_PKTLEN
;
1284 FormatPortMaprequest(info
, m
->UnicastPort4
);
1285 SendInitialPMapReq(m
, info
);
1289 // if LLQ NAT context unreferenced, delete the mapping
1290 mDNSlocal
void CheckForUnreferencedLLQMapping(mDNS
*m
)
1292 NATTraversalInfo
*nat
= m
->uDNS_info
.LLQNatInfo
;
1297 for (q
= m
->uDNS_info
.ActiveQueries
; q
; q
= q
->next
)
1298 if (q
->LongLived
&& q
->uDNS_info
.llq
->NATMap
) return;
1300 //to avoid race condition if we need to recreate before this finishes, we do one-shot deregistration
1301 if (nat
->state
== NATState_Established
|| nat
->state
== NATState_Legacy
)
1302 DeleteNATPortMapping(m
, nat
, mDNSNULL
); // for simplicity we allow other states to expire
1303 FreeNATInfo(m
, nat
); // note: this clears the global LLQNatInfo pointer
1306 // ***************************************************************************
1307 #if COMPILER_LIKES_PRAGMA_MARK
1308 #pragma mark - host name and interface management
1311 // if we ever want to refine support for multiple hostnames, we can add logic matching service names to a particular hostname
1312 // for now, we grab the first registered DynDNS name, if any, or a static name we learned via a reverse-map query
1313 mDNSlocal mDNSBool
GetServiceTarget(uDNS_GlobalInfo
*u
, AuthRecord
*srv
, domainname
*dst
)
1315 uDNS_HostnameInfo
*hi
= u
->Hostnames
;
1316 (void)srv
; // unused
1321 if (hi
->ar
->uDNS_info
.state
== regState_Registered
|| hi
->ar
->uDNS_info
.state
== regState_Refresh
)
1322 { AssignDomainName(*dst
, hi
->ar
->resrec
.name
); return mDNStrue
; }
1326 if (u
->StaticHostname
.c
[0]) { AssignDomainName(*dst
, u
->StaticHostname
); return mDNStrue
; }
1330 mDNSlocal
void UpdateSRV(mDNS
*m
, ServiceRecordSet
*srs
)
1332 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1333 ExtraResourceRecord
*e
;
1334 domainname newtarget
;
1335 domainname
*curtarget
= &srs
->RR_SRV
.resrec
.rdata
->u
.srv
.target
;
1336 mDNSBool havetarget
= GetServiceTarget(u
, &srs
->RR_SRV
, &newtarget
);
1338 if ((!havetarget
&& srs
->uDNS_info
.state
== regState_NoTarget
) || (havetarget
&& SameDomainName(curtarget
, &newtarget
))) return; // target unchanged
1340 switch(srs
->uDNS_info
.state
)
1342 case regState_FetchingZoneData
:
1343 case regState_Cancelled
:
1344 case regState_DeregPending
:
1345 case regState_DeregDeferred
:
1346 case regState_Unregistered
:
1347 case regState_NATMap
:
1348 case regState_ExtraQueued
:
1349 // In these states, the SRV has either not yet been registered (it will get up-to-date information when it is)
1350 // or is in the process of, or has already been, deregistered
1353 case regState_Pending
:
1354 case regState_Refresh
:
1355 case regState_UpdatePending
:
1356 // let the in-flight operation complete before updating
1357 srs
->uDNS_info
.SRVUpdateDeferred
= mDNStrue
;
1360 case regState_NoTarget
:
1361 // Service has not been registered due to lack of a target hostname
1362 if (havetarget
) SendServiceRegistration(m
, srs
);
1365 case regState_Registered
:
1366 // target lost or changed. deregister service. upon completion, we'll look for a new target
1367 // extra will be re-registed if the service is re-registered
1368 for (e
= srs
->Extras
; e
; e
= e
->next
) e
->r
.uDNS_info
.state
= regState_ExtraQueued
;
1370 srs
->uDNS_info
.LostTarget
= mDNStrue
;
1371 SendServiceDeregistration(m
, srs
);
1376 mDNSlocal
void UpdateSRVRecords(mDNS
*m
)
1378 ServiceRecordSet
*srs
;
1380 for (srs
= m
->uDNS_info
.ServiceRegistrations
; srs
; srs
= srs
->next
) UpdateSRV(m
, srs
);
1383 mDNSlocal
void HostnameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
1385 uDNS_HostnameInfo
*hi
= (uDNS_HostnameInfo
*)rr
->RecordContext
;
1386 mDNSu8
*ip
= rr
->resrec
.rdata
->u
.ipv4
.b
;
1388 if (result
== mStatus_MemFree
)
1390 debugf("MemFree: %##s IP %d.%d.%d.%d", rr
->resrec
.name
.c
, ip
[0], ip
[1], ip
[2], ip
[3]);
1396 if (result
== mStatus_NameConflict
&& rr
->resrec
.RecordType
== kDNSRecordTypeUnique
)
1398 // if we get a name conflict, make sure our name/addr isn't already registered by re-registering
1399 debugf("Name in use - retrying as type KnownUnique");
1400 rr
->resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
1401 uDNS_RegisterRecord(m
, rr
);
1405 if (rr
->resrec
.RecordType
== kDNSRecordTypeKnownUnique
)
1407 // we've already tried to re-register. reset RecordType before returning RR to client
1408 if (result
== mStatus_NoSuchRecord
) // name is advertised for some other address
1409 result
= mStatus_NameConflict
;
1414 // don't unlink or free - we can retry when we get a new address/router
1415 LogMsg("HostnameCallback: Error %ld for registration of %##s IP %d.%d.%d.%d", result
, rr
->resrec
.name
.c
, ip
[0], ip
[1], ip
[2], ip
[3]);
1416 if (!hi
) { ufree(rr
); return; }
1417 if (hi
->ar
->uDNS_info
.state
!= regState_Unregistered
) LogMsg("Error: HostnameCallback invoked with error code for record not in regState_Unregistered!");
1418 (const void *)rr
->RecordContext
= hi
->StatusContext
;
1419 if (hi
->StatusCallback
)
1420 hi
->StatusCallback(m
, rr
, result
); // client may NOT make API calls here
1421 rr
->RecordContext
= (void *)hi
;
1425 // register any pending services that require a target
1426 UpdateSRVRecords(m
);
1428 // Deliver success to client
1429 if (!hi
) { LogMsg("HostnameCallback invoked with orphaned address record"); return; }
1430 LogMsg("Registered hostname %##s IP %d.%d.%d.%d", rr
->resrec
.name
.c
, ip
[0], ip
[1], ip
[2], ip
[3]);
1431 (const void *)rr
->RecordContext
= hi
->StatusContext
;
1432 if (hi
->StatusCallback
)
1433 hi
->StatusCallback(m
, rr
, result
); // client may NOT make API calls here
1434 rr
->RecordContext
= (void *)hi
;
1437 // register record or begin NAT traversal
1438 mDNSlocal
void AdvertiseHostname(mDNS
*m
, uDNS_HostnameInfo
*h
)
1440 if (IsPrivateV4Addr(&m
->uDNS_info
.PrimaryIP
))
1441 StartGetPublicAddr(m
, h
);
1444 mDNSu8
*ip
= m
->uDNS_info
.PrimaryIP
.ip
.v4
.b
;
1445 LogMsg("Advertising %##s IP %d.%d.%d.%d", h
->ar
->resrec
.name
.c
, ip
[0], ip
[1], ip
[2], ip
[3]);
1446 uDNS_RegisterRecord(m
, h
->ar
);
1450 mDNSlocal
void FoundStaticHostname(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1452 const domainname
*pktname
= &answer
->rdata
->u
.name
;
1453 domainname
*storedname
= &m
->uDNS_info
.StaticHostname
;
1456 debugf("FoundStaticHostname: %##s -> %##s (%s)", question
->qname
.c
, answer
->rdata
->u
.name
.c
, AddRecord
? "added" : "removed");
1457 if (AddRecord
&& !SameDomainName(pktname
, storedname
))
1459 AssignDomainName(*storedname
, *pktname
);
1460 UpdateSRVRecords(m
);
1462 else if (!AddRecord
&& SameDomainName(pktname
, storedname
))
1464 storedname
->c
[0] = 0;
1465 UpdateSRVRecords(m
);
1469 mDNSlocal
void GetStaticHostname(mDNS
*m
)
1471 char buf
[MAX_ESCAPED_DOMAIN_NAME
];
1472 DNSQuestion
*q
= &m
->uDNS_info
.ReverseMap
;
1473 mDNSu8
*ip
= m
->uDNS_info
.PrimaryIP
.ip
.v4
.b
;
1476 ubzero(q
, sizeof(*q
));
1478 if (m
->uDNS_info
.ReverseMapActive
)
1480 uDNS_StopQuery(m
, q
);
1481 m
->uDNS_info
.ReverseMapActive
= mDNSfalse
;
1484 if (!m
->uDNS_info
.PrimaryIP
.ip
.v4
.NotAnInteger
) return;
1485 mDNS_snprintf(buf
, MAX_ESCAPED_DOMAIN_NAME
, "%d.%d.%d.%d.in-addr.arpa.", ip
[3], ip
[2], ip
[1], ip
[0]);
1486 if (!MakeDomainNameFromDNSNameString(&q
->qname
, buf
)) { LogMsg("Error: GetStaticHostname - bad name %s", buf
); return; }
1488 q
->InterfaceID
= mDNSInterface_Any
;
1489 q
->Target
= zeroAddr
;
1490 q
->qtype
= kDNSType_PTR
;
1491 q
->qclass
= kDNSClass_IN
;
1492 q
->LongLived
= mDNSfalse
;
1493 q
->ExpectUnique
= mDNSfalse
;
1494 q
->ForceMCast
= mDNSfalse
;
1495 q
->QuestionCallback
= FoundStaticHostname
;
1496 q
->QuestionContext
= mDNSNULL
;
1498 err
= uDNS_StartQuery(m
, q
);
1499 if (err
) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err
);
1500 else m
->uDNS_info
.ReverseMapActive
= mDNStrue
;
1503 // Deregister hostnames and register new names for each host domain with the current global
1504 // values for the hostlabel and primary IP address
1505 mDNSlocal
void UpdateHostnameRegistrations(mDNS
*m
)
1507 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1509 uDNS_HostnameInfo
*i
;
1511 for (i
= u
->Hostnames
; i
; i
= i
->next
)
1513 // only allocate new record if existing record is actually registered (i.e. it wasn't pending the hostname or IP being set)
1514 if (i
->ar
->uDNS_info
.state
== regState_Unregistered
) new = i
->ar
;
1517 new = umalloc(sizeof(AuthRecord
));
1518 if (!new) { LogMsg("ERROR: UpdateHostnameRegistration - malloc"); return; }
1519 mDNS_SetupResourceRecord(new, mDNSNULL
, 0, kDNSType_A
, 1, kDNSRecordTypeUnique
, HostnameCallback
, i
);
1523 AssignDomainName(new->resrec
.name
, i
->ar
->resrec
.name
);
1524 new->resrec
.rdata
->u
.ipv4
= u
->PrimaryIP
.ip
.v4
;
1526 if (i
->ar
->uDNS_info
.state
!= regState_Unregistered
)
1528 // delete old record
1529 i
->ar
->RecordContext
= mDNSNULL
; // clear backpointer to HostnameInfo
1530 uDNS_DeregisterRecord(m
, i
->ar
);
1535 AdvertiseHostname(m
, i
);
1539 mDNSexport
void mDNS_AddDynDNSHostName(mDNS
*m
, const domainname
*fqdn
, mDNSRecordCallback
*StatusCallback
, const void *StatusContext
)
1541 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1542 uDNS_HostnameInfo
*ptr
, *new;
1546 // check if domain already registered
1547 for (ptr
= u
->Hostnames
; ptr
; ptr
= ptr
->next
)
1549 if (SameDomainName(fqdn
, &ptr
->ar
->resrec
.name
))
1550 { LogMsg("Host Domain %##s already in list", fqdn
->c
); goto exit
; }
1553 // allocate and format new address record
1554 new = umalloc(sizeof(*new));
1555 if (new) new->ar
= umalloc(sizeof(AuthRecord
));
1556 if (!new || !new->ar
) { LogMsg("ERROR: mDNS_AddDynDNSHostname - malloc"); goto exit
; }
1557 new->StatusCallback
= StatusCallback
;
1558 new->StatusContext
= StatusContext
;
1559 mDNS_SetupResourceRecord(new->ar
, mDNSNULL
, 0, kDNSType_A
, 1, kDNSRecordTypeUnique
, HostnameCallback
, new);
1560 AppendDomainName(&new->ar
->resrec
.name
, fqdn
);
1561 new->next
= u
->Hostnames
;
1563 if (u
->PrimaryIP
.ip
.v4
.NotAnInteger
)
1565 // only set RData if we have a valid IP
1566 if (u
->MappedPrimaryIP
.ip
.v4
.NotAnInteger
) new->ar
->resrec
.rdata
->u
.ipv4
= u
->MappedPrimaryIP
.ip
.v4
; //!!!KRS implement code that caches this
1567 else new->ar
->resrec
.rdata
->u
.ipv4
= u
->PrimaryIP
.ip
.v4
;
1568 AdvertiseHostname(m
, new);
1570 else new->ar
->uDNS_info
.state
= regState_Unregistered
;
1575 mDNSexport
void mDNS_RemoveDynDNSHostName(mDNS
*m
, const domainname
*fqdn
)
1577 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1578 uDNS_HostnameInfo
**ptr
= &u
->Hostnames
;
1582 while (*ptr
&& !SameDomainName(fqdn
, &(*ptr
)->ar
->resrec
.name
)) ptr
= &(*ptr
)->next
;
1583 if (!*ptr
) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn
->c
);
1586 uDNS_HostnameInfo
*hi
= *ptr
;
1587 *ptr
= (*ptr
)->next
; // unlink
1588 hi
->ar
->RecordContext
= mDNSNULL
; // about to free wrapper struct
1589 if (hi
->ar
->uDNS_info
.state
!= regState_Unregistered
) uDNS_DeregisterRecord(m
, hi
->ar
);
1590 else { ufree(hi
->ar
); hi
->ar
= mDNSNULL
; }
1593 UpdateSRVRecords(m
);
1597 mDNSexport
void mDNS_SetPrimaryInterfaceInfo(mDNS
*m
, const mDNSAddr
*addr
, const mDNSAddr
*router
)
1599 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1600 mDNSBool AddrChanged
, RouterChanged
;
1602 if (addr
&& addr
->type
!=mDNSAddrType_IPv4
) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-V4 address. Discarding."); return; }
1603 if (router
&& router
->type
!=mDNSAddrType_IPv4
) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-V4 address. Discarding."); return; }
1606 AddrChanged
= addr
? (addr
->ip
.v4
.NotAnInteger
!= u
->PrimaryIP
.ip
.v4
.NotAnInteger
) : u
->PrimaryIP
.ip
.v4
.NotAnInteger
;
1607 RouterChanged
= router
? (router
->ip
.v4
.NotAnInteger
!= u
->Router
.ip
.v4
.NotAnInteger
) : u
->Router
.ip
.v4
.NotAnInteger
;
1610 if (addr
&& (AddrChanged
|| RouterChanged
))
1611 LogMsg("mDNS_SetPrimaryInterfaceInfo: address changed from %d.%d.%d.%d to %d.%d.%d.%d:%d",
1612 u
->PrimaryIP
.ip
.v4
.b
[0], u
->PrimaryIP
.ip
.v4
.b
[1], u
->PrimaryIP
.ip
.v4
.b
[2], u
->PrimaryIP
.ip
.v4
.b
[3],
1613 addr
->ip
.v4
.b
[0], addr
->ip
.v4
.b
[1], addr
->ip
.v4
.b
[2], addr
->ip
.v4
.b
[3], mDNSVal16(m
->UnicastPort4
));
1614 #endif // MDNS_DEBUGMSGS
1616 if (addr
) u
->PrimaryIP
= *addr
;
1617 if (router
) u
->Router
= *router
;
1618 else u
->Router
.ip
.v4
.NotAnInteger
= 0; // setting router to zero indicates that nat mappings must be reestablished when router is reset
1624 UpdateHostnameRegistrations(m
);
1625 UpdateSRVRecords(m
);
1627 GetStaticHostname(m
); // look up reverse map record to find any static hostnames for our IP address
1633 // ***************************************************************************
1634 #if COMPILER_LIKES_PRAGMA_MARK
1635 #pragma mark - Incoming Message Processing
1638 mDNSlocal mDNSBool
kaListContainsAnswer(DNSQuestion
*question
, CacheRecord
*rr
)
1642 for (ptr
= question
->uDNS_info
.knownAnswers
; ptr
; ptr
= ptr
->next
)
1643 if (SameResourceRecord(&ptr
->resrec
, &rr
->resrec
)) return mDNStrue
;
1649 mDNSlocal
void removeKnownAnswer(DNSQuestion
*question
, CacheRecord
*rr
)
1651 CacheRecord
*ptr
, *prev
= mDNSNULL
;
1653 for (ptr
= question
->uDNS_info
.knownAnswers
; ptr
; ptr
= ptr
->next
)
1655 if (SameResourceRecord(&ptr
->resrec
, &rr
->resrec
))
1657 if (prev
) prev
->next
= ptr
->next
;
1658 else question
->uDNS_info
.knownAnswers
= ptr
->next
;
1664 LogMsg("removeKnownAnswer() called for record not in KA list");
1668 mDNSlocal
void addKnownAnswer(DNSQuestion
*question
, const CacheRecord
*rr
)
1670 CacheRecord
*newCR
= mDNSNULL
;
1673 size
= sizeof(CacheRecord
) + rr
->resrec
.rdlength
- InlineCacheRDSize
;
1674 newCR
= (CacheRecord
*)umalloc(size
);
1675 if (!newCR
) { LogMsg("ERROR: addKnownAnswer - malloc"); return; }
1676 umemcpy(newCR
, rr
, size
);
1677 newCR
->resrec
.rdata
= (RData
*)&newCR
->rdatastorage
;
1678 newCR
->resrec
.rdata
->MaxRDLength
= rr
->resrec
.rdlength
;
1679 newCR
->next
= question
->uDNS_info
.knownAnswers
;
1680 question
->uDNS_info
.knownAnswers
= newCR
;
1683 mDNSlocal
void deriveGoodbyes(mDNS
* const m
, DNSMessage
*msg
, const mDNSu8
*end
, DNSQuestion
*question
)
1687 CacheRecord
*fptr
, *ka
, *cr
, *answers
= mDNSNULL
, *prev
= mDNSNULL
;
1688 LargeCacheRecord
*lcr
;
1690 if (question
!= m
->uDNS_info
.CurrentQuery
) { LogMsg("ERROR: deriveGoodbyes called without CurrentQuery set!"); return; }
1692 ptr
= LocateAnswers(msg
, end
);
1693 if (!ptr
) goto pkt_error
;
1695 if (!msg
->h
.numAnswers
)
1697 // delete the whole KA list
1698 ka
= question
->uDNS_info
.knownAnswers
;
1701 debugf("deriving goodbye for %##s", ka
->resrec
.name
.c
);
1703 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
1704 question
->QuestionCallback(m
, question
, &ka
->resrec
, mDNSfalse
);
1705 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
1706 if (question
!= m
->uDNS_info
.CurrentQuery
)
1708 debugf("deriveGoodbyes - question removed via callback. returning.");
1715 question
->uDNS_info
.knownAnswers
= mDNSNULL
;
1719 // make a list of all the new answers
1720 for (i
= 0; i
< msg
->h
.numAnswers
; i
++)
1722 lcr
= (LargeCacheRecord
*)umalloc(sizeof(LargeCacheRecord
));
1723 if (!lcr
) goto malloc_error
;
1724 ubzero(lcr
, sizeof(LargeCacheRecord
));
1725 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, lcr
);
1726 if (!ptr
) goto pkt_error
;
1728 if (ResourceRecordAnswersQuestion(&cr
->resrec
, question
))
1736 // make sure every known answer is in the answer list
1737 ka
= question
->uDNS_info
.knownAnswers
;
1740 for (cr
= answers
; cr
; cr
= cr
->next
)
1741 { if (SameResourceRecord(&ka
->resrec
, &cr
->resrec
)) break; }
1744 // record is in KA list but not answer list - remove from KA list
1745 if (prev
) prev
->next
= ka
->next
;
1746 else question
->uDNS_info
.knownAnswers
= ka
->next
;
1747 debugf("deriving goodbye for %##s", ka
->resrec
.name
.c
);
1748 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
1749 question
->QuestionCallback(m
, question
, &ka
->resrec
, mDNSfalse
);
1750 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
1751 if (question
!= m
->uDNS_info
.CurrentQuery
)
1753 debugf("deriveGoodbyes - question removed via callback. returning.");
1767 // free temp answers list
1769 while (cr
) { fptr
= cr
; cr
= cr
->next
; ufree(fptr
); }
1774 LogMsg("ERROR: deriveGoodbyes - received malformed response to query for %##s (%d)",
1775 question
->qname
.c
, question
->qtype
);
1779 LogMsg("ERROR: Malloc");
1782 mDNSlocal
void pktResponseHndlr(mDNS
* const m
, DNSMessage
*msg
, const mDNSu8
*end
, DNSQuestion
*question
, mDNSBool llq
)
1786 LargeCacheRecord lcr
;
1787 CacheRecord
*cr
= &lcr
.r
;
1788 mDNSBool goodbye
, inKAList
, followedCName
= mDNSfalse
;
1789 LLQ_Info
*llqInfo
= question
->uDNS_info
.llq
;
1790 domainname origname
;
1792 if (question
!= m
->uDNS_info
.CurrentQuery
)
1793 { LogMsg("ERROR: pktResponseHdnlr called without CurrentQuery ptr set!"); return; }
1795 question
->uDNS_info
.Answered
= mDNStrue
;
1797 ptr
= LocateAnswers(msg
, end
);
1798 if (!ptr
) goto pkt_error
;
1800 for (i
= 0; i
< msg
->h
.numAnswers
; i
++)
1802 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
1803 if (!ptr
) goto pkt_error
;
1804 if (ResourceRecordAnswersQuestion(&cr
->resrec
, question
))
1806 if (cr
->resrec
.rrtype
== kDNSType_CNAME
)
1808 if (followedCName
) LogMsg("Error: multiple CNAME referals for question %##s", question
->qname
.c
);
1811 debugf("Following cname %##s -> %##s", question
->qname
.c
, cr
->resrec
.rdata
->u
.name
.c
);
1812 AssignDomainName(origname
, question
->qname
);
1813 AssignDomainName(question
->qname
, cr
->resrec
.rdata
->u
.name
);
1814 question
->qnamehash
= DomainNameHashValue(&question
->qname
);
1815 followedCName
= mDNStrue
;
1816 i
= -1; // restart packet answer matching
1817 ptr
= LocateAnswers(msg
, end
);
1822 goodbye
= llq
? ((mDNSs32
)cr
->resrec
.rroriginalttl
== -1) : mDNSfalse
;
1823 inKAList
= kaListContainsAnswer(question
, cr
);
1825 if ((goodbye
&& !inKAList
) || (!goodbye
&& inKAList
)) continue; // list up to date
1826 if (!inKAList
) addKnownAnswer(question
, cr
);
1827 if (goodbye
) removeKnownAnswer(question
, cr
);
1828 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
1829 question
->QuestionCallback(m
, question
, &cr
->resrec
, !goodbye
);
1830 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
1831 if (question
!= m
->uDNS_info
.CurrentQuery
)
1833 debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning");
1837 else if (!followedCName
|| !SameDomainName(&cr
->resrec
.name
, &origname
))
1838 LogMsg("Question %##s type %d - unexpected answer %##s type %d", question
->qname
.c
, question
->qtype
, cr
->resrec
.name
.c
, cr
->resrec
.rrtype
);
1841 if (!llq
|| llqInfo
->state
== LLQ_Poll
|| llqInfo
->deriveRemovesOnResume
)
1843 deriveGoodbyes(m
, msg
, end
,question
);
1844 if (llq
&& llqInfo
->deriveRemovesOnResume
) llqInfo
->deriveRemovesOnResume
= mDNSfalse
;
1847 // our interval may be set lower to recover from failures - now that we have an answer, fully back off retry
1848 if (question
->ThisQInterval
< MAX_UCAST_POLL_INTERVAL
) question
->ThisQInterval
= MAX_UCAST_POLL_INTERVAL
;
1852 LogMsg("ERROR: pktResponseHndlr - received malformed response to query for %##s (%d)",
1853 question
->qname
.c
, question
->qtype
);
1857 mDNSlocal
void simpleResponseHndlr(mDNS
* const m
, DNSMessage
*msg
, const mDNSu8
*end
, DNSQuestion
*question
, void *context
)
1859 (void)context
; // unused
1860 pktResponseHndlr(m
, msg
, end
, question
, mDNSfalse
);
1863 mDNSlocal
void llqResponseHndlr(mDNS
* const m
, DNSMessage
*msg
, const mDNSu8
*end
, DNSQuestion
*question
, void *context
)
1865 (void)context
; // unused
1866 pktResponseHndlr(m
, msg
, end
, question
, mDNStrue
);
1869 mDNSlocal mStatus
ParseTSIGError(mDNS
*m
, const DNSMessage
*msg
, const mDNSu8
*end
, const domainname
*displayname
)
1871 LargeCacheRecord lcr
;
1873 mStatus err
= mStatus_NoError
;
1876 ptr
= LocateAdditionals(msg
, end
);
1877 if (!ptr
) goto finish
;
1879 for (i
= 0; i
< msg
->h
.numAdditionals
; i
++)
1881 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &lcr
);;
1882 if (!ptr
) goto finish
;
1883 if (lcr
.r
.resrec
.rrtype
== kDNSType_TSIG
)
1886 mDNSu8
*rd
= lcr
.r
.resrec
.rdata
->u
.data
;
1887 mDNSu8
*rdend
= rd
+ MaximumRDSize
;
1888 int alglen
= DomainNameLength(&lcr
.r
.resrec
.rdata
->u
.name
);
1890 if (rd
+ alglen
> rdend
) goto finish
;
1891 rd
+= alglen
; // algorithm name
1892 if (rd
+ 6 > rdend
) goto finish
;
1893 rd
+= 6; // 48-bit timestamp
1894 if (rd
+ sizeof(mDNSOpaque16
) > rdend
) goto finish
;
1895 rd
+= sizeof(mDNSOpaque16
); // fudge
1896 if (rd
+ sizeof(mDNSOpaque16
) > rdend
) goto finish
;
1897 macsize
= mDNSVal16(*(mDNSOpaque16
*)rd
);
1898 rd
+= sizeof(mDNSOpaque16
); // MAC size
1899 if (rd
+ macsize
> rdend
) goto finish
;
1901 if (rd
+ sizeof(mDNSOpaque16
) > rdend
) goto finish
;
1902 rd
+= sizeof(mDNSOpaque16
); // orig id
1903 if (rd
+ sizeof(mDNSOpaque16
) > rdend
) goto finish
;
1904 err
= mDNSVal16(*(mDNSOpaque16
*)rd
); // error code
1906 if (err
== TSIG_ErrBadSig
) { LogMsg("%##s: bad signature", displayname
->c
); err
= mStatus_BadSig
; }
1907 else if (err
== TSIG_ErrBadKey
) { LogMsg("%##s: bad key", displayname
->c
); err
= mStatus_BadKey
; }
1908 else if (err
== TSIG_ErrBadTime
) { LogMsg("%##s: bad time", displayname
->c
); err
= mStatus_BadTime
; }
1909 else if (err
) { LogMsg("%##s: unknown tsig error %d", err
); err
= mStatus_UnknownErr
; }
1918 mDNSlocal mStatus
checkUpdateResult(domainname
*displayname
, mDNSu8 rcode
, mDNS
*m
, const DNSMessage
*msg
, const mDNSu8
*end
)
1920 (void)msg
; // currently unused, needed for TSIG errors
1921 if (!rcode
) return mStatus_NoError
;
1922 else if (rcode
== kDNSFlag1_RC_YXDomain
)
1924 LogMsg("name in use: %##s", displayname
->c
);
1925 return mStatus_NameConflict
;
1927 else if (rcode
== kDNSFlag1_RC_Refused
)
1929 LogMsg("Update %##s refused", displayname
->c
);
1930 return mStatus_Refused
;
1932 else if (rcode
== kDNSFlag1_RC_NXRRSet
)
1934 LogMsg("Reregister refused (NXRRSET): %##s", displayname
->c
);
1935 return mStatus_NoSuchRecord
;
1937 else if (rcode
== kDNSFlag1_RC_NotAuth
)
1939 // TSIG errors should come with FmtErr as per RFC 2845, but BIND 9 sends them with NotAuth so we look here too
1940 mStatus tsigerr
= ParseTSIGError(m
, msg
, end
, displayname
);
1943 LogMsg("Permission denied (NOAUTH): %##s", displayname
->c
);
1944 return mStatus_UnknownErr
;
1946 else return tsigerr
;
1948 else if (rcode
== kDNSFlag1_RC_FmtErr
)
1950 mStatus tsigerr
= ParseTSIGError(m
, msg
, end
, displayname
);
1953 LogMsg("Format Error: %##s", displayname
->c
);
1954 return mStatus_UnknownErr
;
1956 else return tsigerr
;
1960 LogMsg("Update %##s failed with rcode %d", displayname
->c
, rcode
);
1961 return mStatus_UnknownErr
;
1965 mDNSlocal
void hndlServiceUpdateReply(mDNS
* const m
, ServiceRecordSet
*srs
, mStatus err
)
1967 mDNSBool InvokeCallback
= mDNSfalse
;
1968 AuthRecord
*UpdateR
= mDNSNULL
;
1969 uDNS_RegInfo
*info
= &srs
->uDNS_info
;
1970 NATTraversalInfo
*nat
= srs
->uDNS_info
.NATinfo
;
1971 ExtraResourceRecord
**e
= &srs
->Extras
;
1973 switch (info
->state
)
1975 case regState_Pending
:
1976 if (err
== mStatus_NameConflict
&& !info
->TestForSelfConflict
)
1978 info
->TestForSelfConflict
= mDNStrue
;
1979 debugf("checking for self-conflict of service %##s", srs
->RR_SRV
.resrec
.name
.c
);
1980 SendServiceRegistration(m
, srs
);
1983 else if (info
->TestForSelfConflict
)
1985 info
->TestForSelfConflict
= mDNSfalse
;
1986 if (err
== mStatus_NoSuchRecord
) err
= mStatus_NameConflict
; // NoSuchRecord implies that our prereq was not met, so we actually have a name conflict
1987 if (err
) info
->state
= regState_Unregistered
;
1988 else info
->state
= regState_Registered
;
1989 InvokeCallback
= mDNStrue
;
1992 else if (err
== mStatus_UnknownErr
&& info
->lease
)
1994 LogMsg("Re-trying update of service %##s without lease option", srs
->RR_SRV
.resrec
.name
.c
);
1995 info
->lease
= mDNSfalse
;
1997 SendServiceRegistration(m
, srs
);
2002 if (err
) { LogMsg("Error %ld for registration of service %##s", err
, srs
->RR_SRV
.resrec
.name
.c
); info
->state
= regState_Unregistered
; } //!!!KRS make sure all structs will still get cleaned up when client calls DeregisterService with this state
2003 else info
->state
= regState_Registered
;
2004 InvokeCallback
= mDNStrue
;
2007 case regState_Refresh
:
2010 LogMsg("Error %ld for refresh of service %##s", err
, srs
->RR_SRV
.resrec
.name
.c
);
2011 InvokeCallback
= mDNStrue
;
2012 info
->state
= regState_Unregistered
;
2014 else info
->state
= regState_Registered
;
2016 case regState_DeregPending
:
2017 if (err
) LogMsg("Error %ld for deregistration of service %##s", err
, srs
->RR_SRV
.resrec
.name
.c
);
2018 if (info
->LostTarget
)
2020 info
->state
= regState_NoTarget
;
2023 err
= mStatus_MemFree
;
2024 InvokeCallback
= mDNStrue
;
2027 if (nat
->state
== NATState_Deleted
) { FreeNATInfo(m
, nat
); info
->NATinfo
= mDNSNULL
; } // deletion copmleted
2028 else nat
->reg
.ServiceRegistration
= mDNSNULL
; // allow mapping deletion to continue
2030 info
->state
= regState_Unregistered
;
2032 case regState_DeregDeferred
:
2033 if (err
) { debugf("Error %ld received prior to deferred derigstration of %##s", err
, srs
->RR_SRV
.resrec
.name
.c
); }
2034 debugf("Performing deferred deregistration of %##s", srs
->RR_SRV
.resrec
.name
.c
);
2035 info
->state
= regState_Registered
; // benign to set even if we've got an error
2036 SendServiceDeregistration(m
, srs
);
2038 case regState_UpdatePending
:
2039 // find the record being updated
2040 UpdateR
= &srs
->RR_TXT
;
2043 LogMsg("hndlServiceUpdateReply: error updating resource record");
2044 UpdateR
->uDNS_info
.state
= regState_Unregistered
;
2045 InvokeCallback
= mDNStrue
; // signal error via service callback
2049 UpdateR
->uDNS_info
.state
= regState_Registered
;
2050 SwapRData(m
, UpdateR
, mDNStrue
);
2052 info
->state
= regState_Registered
;
2054 case regState_FetchingZoneData
:
2055 case regState_Registered
:
2056 case regState_Cancelled
:
2057 case regState_Unregistered
:
2058 case regState_NATMap
:
2059 case regState_NoTarget
:
2060 case regState_ExtraQueued
:
2061 LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %ld. Unlinking.",
2062 srs
->RR_SRV
.resrec
.name
.c
, info
->state
, err
);
2063 err
= mStatus_UnknownErr
;
2066 if ((info
->LostTarget
|| info
->SRVUpdateDeferred
) && (info
->state
== regState_NoTarget
|| info
->state
== regState_Registered
))
2074 uDNS_RegInfo
*einfo
= &(*e
)->r
.uDNS_info
;
2075 if (einfo
->state
== regState_ExtraQueued
)
2077 if (info
->state
== regState_Registered
&& !err
)
2079 // extra resource record queued for this service - copy zone info and register
2080 AssignDomainName(einfo
->zone
, info
->zone
);
2081 einfo
->ns
= info
->ns
;
2082 einfo
->port
= info
->port
;
2083 einfo
->lease
= info
->lease
;
2084 sendRecordRegistration(m
, &(*e
)->r
);
2087 else if (err
&& einfo
->state
!= regState_Unregistered
)
2089 // unlink extra from list
2090 einfo
->state
= regState_Unregistered
;
2093 else e
= &(*e
)->next
;
2095 else e
= &(*e
)->next
;
2098 srs
->RR_SRV
.ThisAPInterval
= INIT_UCAST_POLL_INTERVAL
- 1; // reset retry delay for future refreshes, dereg, etc.
2099 if (srs
->RR_TXT
.uDNS_info
.UpdateQueued
) SendRecordUpdate(m
, &srs
->RR_TXT
, &srs
->uDNS_info
);
2101 if (info
->state
== regState_Unregistered
) unlinkSRS(&m
->uDNS_info
, srs
);
2103 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
2104 if (InvokeCallback
) srs
->ServiceCallback(m
, srs
, err
);
2105 else if (info
->ClientCallbackDeferred
)
2107 info
->ClientCallbackDeferred
= mDNSfalse
;
2108 srs
->ServiceCallback(m
, srs
, info
->DeferredStatus
);
2110 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
2111 // NOTE: do not touch structures after calling ServiceCallback
2114 mDNSlocal
void hndlRecordUpdateReply(mDNS
*m
, AuthRecord
*rr
, mStatus err
)
2116 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
2118 if (rr
->uDNS_info
.state
== regState_UpdatePending
)
2122 LogMsg("Update record failed for %##s (err %d)", rr
->resrec
.name
.c
, err
);
2123 rr
->uDNS_info
.state
= regState_Unregistered
;
2127 debugf("Update record %##s - success", rr
->resrec
.name
.c
);
2128 rr
->uDNS_info
.state
= regState_Registered
;
2129 SwapRData(m
, rr
, mDNStrue
);
2131 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
2132 if (rr
->RecordCallback
) rr
->RecordCallback(m
, rr
, err
);
2133 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
2137 if (rr
->uDNS_info
.state
== regState_DeregPending
)
2139 debugf("Received reply for deregister record %##s type %d", rr
->resrec
.name
.c
, rr
->resrec
.rrtype
);
2140 if (err
) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %ld",
2141 rr
->resrec
.name
.c
, rr
->resrec
.rrtype
, err
);
2142 err
= mStatus_MemFree
;
2143 if (unlinkAR(&m
->uDNS_info
.RecordRegistrations
, rr
))
2144 LogMsg("ERROR: Could not unlink resource record following deregistration");
2145 rr
->uDNS_info
.state
= regState_Unregistered
;
2146 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
2147 if (rr
->RecordCallback
) rr
->RecordCallback(m
, rr
, err
);
2148 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
2152 if (rr
->uDNS_info
.state
== regState_DeregDeferred
)
2156 LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %ld",
2157 rr
->resrec
.name
.c
, rr
->resrec
.rrtype
, err
);
2158 unlinkAR(&m
->uDNS_info
.RecordRegistrations
, rr
);
2159 rr
->uDNS_info
.state
= regState_Unregistered
;
2162 LogMsg("Calling deferred deregistration of record %##s type %d",
2163 rr
->resrec
.name
.c
, rr
->resrec
.rrtype
);
2164 rr
->uDNS_info
.state
= regState_Registered
;
2165 uDNS_DeregisterRecord(m
, rr
);
2169 if (rr
->uDNS_info
.state
== regState_Pending
|| rr
->uDNS_info
.state
== regState_Refresh
)
2173 if (rr
->uDNS_info
.lease
&& err
== mStatus_UnknownErr
)
2175 LogMsg("Re-trying update of record %##s without lease option", rr
->resrec
.name
.c
);
2176 rr
->uDNS_info
.lease
= mDNSfalse
;
2177 rr
->uDNS_info
.expire
= -1;
2178 sendRecordRegistration(m
, rr
);
2182 LogMsg("Registration of record %##s type %d failed with error %ld",
2183 rr
->resrec
.name
.c
, rr
->resrec
.rrtype
, err
);
2184 unlinkAR(&u
->RecordRegistrations
, rr
);
2185 rr
->uDNS_info
.state
= regState_Unregistered
;
2186 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
2187 if (rr
->RecordCallback
) rr
->RecordCallback(m
, rr
, err
);
2188 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
2193 if (rr
->uDNS_info
.UpdateQueued
)
2195 debugf("%##s: sending queued update", rr
->resrec
.name
.c
);
2196 rr
->uDNS_info
.state
= regState_Registered
;
2197 SendRecordUpdate(m
,rr
, &rr
->uDNS_info
);
2200 if (rr
->uDNS_info
.state
== regState_Refresh
)
2201 rr
->uDNS_info
.state
= regState_Registered
;
2204 rr
->uDNS_info
.state
= regState_Registered
;
2205 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
2206 if (rr
->RecordCallback
) rr
->RecordCallback(m
, rr
, err
);
2207 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
2213 LogMsg("Received unexpected response for record %##s type %d, in state %d, with response error %ld",
2214 rr
->resrec
.name
.c
, rr
->resrec
.rrtype
, rr
->uDNS_info
.state
, err
);
2218 mDNSlocal
void SetUpdateExpiration(mDNS
*m
, DNSMessage
*msg
, const mDNSu8
*end
, uDNS_RegInfo
*info
)
2220 LargeCacheRecord lcr
;
2226 ptr
= LocateAdditionals(msg
, end
);
2228 if (info
->lease
&& (ptr
= LocateAdditionals(msg
, end
)))
2230 for (i
= 0; i
< msg
->h
.numAdditionals
; i
++)
2232 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &lcr
);
2234 if (lcr
.r
.resrec
.rrtype
== kDNSType_OPT
)
2236 if (lcr
.r
.resrec
.rdlength
< LEASE_OPT_SIZE
) continue;
2237 if (lcr
.r
.resrec
.rdata
->u
.opt
.opt
!= kDNSOpt_Lease
) continue;
2238 lease
= lcr
.r
.resrec
.rdata
->u
.opt
.OptData
.lease
;
2246 expire
= (mDNSPlatformTimeNow(m
) + (((mDNSs32
)lease
* mDNSPlatformOneSecond
)) * 3/4);
2247 if (info
->state
== regState_UpdatePending
)
2248 // if updating individual record, the service record set may expire sooner
2249 { if (expire
- info
->expire
< 0) info
->expire
= expire
; }
2250 else info
->expire
= expire
;
2252 else info
->expire
= -1;
2255 mDNSexport
void uDNS_ReceiveNATMap(mDNS
*m
, mDNSu8
*pkt
, mDNSu16 len
)
2257 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
2258 NATTraversalInfo
*ptr
, *cur
;
2261 // check length, version, opcode
2262 if (len
< ADDR_REPLY_PKTLEN
&& len
< PORTMAP_PKTLEN
) { LogMsg("NAT Traversal message too short (%d bytes)", len
); return; }
2263 if (pkt
[0] != NATMAP_VERS
) { LogMsg("Received NAT Traversal response with version %d (expect version %d)", pkt
[0], NATMAP_VERS
); return; }
2265 if (!(op
& NATMAP_RESPONSE_MASK
)) { LogMsg("Received NAT Traversal message that is not a response (opcode %d)", op
); return; }
2267 ptr
= u
->NATTraversals
;
2272 if ((cur
->state
== NATState_Request
|| cur
->state
== NATState_Refresh
) &&
2273 (cur
->op
| NATMAP_RESPONSE_MASK
) == op
)
2274 cur
->ReceiveResponse(cur
, m
, pkt
, len
); // callback may delete "cur"
2275 // specific request/reply matching logic handled by callback - we don't know if this was a match, so we don't break here
2279 mDNSexport
void uDNS_ReceiveMsg(mDNS
*const m
, DNSMessage
*const msg
, const mDNSu8
*const end
,
2280 const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
, const mDNSAddr
*const dstaddr
,
2281 const mDNSIPPort dstport
, const mDNSInterfaceID InterfaceID
)
2285 ServiceRecordSet
*sptr
;
2286 mStatus err
= mStatus_NoError
;
2287 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
2289 mDNSu8 StdR
= kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
;
2290 mDNSu8 UpdateR
= kDNSFlag0_QR_Response
| kDNSFlag0_OP_Update
;
2291 mDNSu8 QR_OP
= (mDNSu8
)(msg
->h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
);
2292 mDNSu8 rcode
= (mDNSu8
)(msg
->h
.flags
.b
[1] & kDNSFlag1_RC
);
2294 mDNSs32 timenow
= mDNSPlatformTimeNow(m
);
2303 // !!!KRS we should to a table lookup here to see if it answers an LLQ or a 1-shot
2304 // LLQ Responses over TCP not currently supported
2305 if (srcaddr
&& recvLLQResponse(m
, msg
, end
, srcaddr
, srcport
, InterfaceID
)) return;
2307 for (qptr
= u
->ActiveQueries
; qptr
; qptr
= qptr
->next
)
2309 //!!!KRS we should have a hashtable, hashed on message id
2310 if (qptr
->uDNS_info
.id
.NotAnInteger
== msg
->h
.id
.NotAnInteger
)
2312 if (timenow
- (qptr
->LastQTime
+ RESPONSE_WINDOW
) > 0)
2313 { LogMsg("uDNS_ReceiveMsg - response received after maximum allowed window. Discarding"); return; }
2314 if (msg
->h
.flags
.b
[0] & kDNSFlag0_TC
)
2315 { hndlTruncatedAnswer(qptr
, srcaddr
, m
); return; }
2318 u
->CurrentQuery
= qptr
;
2319 qptr
->uDNS_info
.responseCallback(m
, msg
, end
, qptr
, qptr
->uDNS_info
.context
);
2320 u
->CurrentQuery
= mDNSNULL
;
2321 // Note: responseCallback can invalidate qptr
2327 if (QR_OP
== UpdateR
)
2329 for (sptr
= u
->ServiceRegistrations
; sptr
; sptr
= sptr
->next
)
2331 if (sptr
->uDNS_info
.id
.NotAnInteger
== msg
->h
.id
.NotAnInteger
)
2333 err
= checkUpdateResult(&sptr
->RR_SRV
.resrec
.name
, rcode
, m
, msg
, end
);
2334 if (!err
) SetUpdateExpiration(m
, msg
, end
, &sptr
->uDNS_info
);
2335 hndlServiceUpdateReply(m
, sptr
, err
);
2339 for (rptr
= u
->RecordRegistrations
; rptr
; rptr
= rptr
->next
)
2341 if (rptr
->uDNS_info
.id
.NotAnInteger
== msg
->h
.id
.NotAnInteger
)
2343 err
= checkUpdateResult(&rptr
->resrec
.name
, rcode
, m
, msg
, end
);
2344 if (!err
) SetUpdateExpiration(m
, msg
, end
, &rptr
->uDNS_info
);
2345 hndlRecordUpdateReply(m
, rptr
, err
);
2350 debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg
->h
.id
));
2353 // lookup a DNS Server, matching by name in split-dns configurations. Result stored in addr parameter if successful
2354 mDNSlocal mDNSBool
GetServerForName(uDNS_GlobalInfo
*u
, const domainname
*name
, mDNSAddr
*addr
)
2356 DNSServer
*curmatch
= mDNSNULL
, *p
= u
->Servers
;
2357 int i
, ncount
, scount
, curmatchlen
= -1;
2360 ncount
= name
? CountLabels(name
) : 0;
2363 scount
= CountLabels(&p
->domain
);
2364 if (scount
<= ncount
&& scount
> curmatchlen
)
2366 // only inspect if server's domain is longer than current best match and shorter than the name itself
2367 const domainname
*tail
= name
;
2368 for (i
= 0; i
< ncount
- scount
; i
++)
2369 tail
= (domainname
*)(tail
->c
+ 1 + tail
->c
[0]); // find "tail" (scount labels) of name
2370 if (SameDomainName(tail
, &p
->domain
)) { curmatch
= p
; curmatchlen
= scount
; }
2377 *addr
= curmatch
->addr
;
2380 else return mDNSfalse
;
2383 // ***************************************************************************
2384 #if COMPILER_LIKES_PRAGMA_MARK
2385 #pragma mark - Query Routines
2388 #define sameID(x,y) mDNSPlatformMemSame(x,y,8)
2390 mDNSlocal
void initializeQuery(DNSMessage
*msg
, DNSQuestion
*question
)
2392 mDNSOpaque16 flags
= QueryFlags
;
2394 ubzero(msg
, sizeof(msg
));
2395 flags
.b
[0] |= kDNSFlag0_RD
; // recursion desired
2396 InitializeDNSMessage(&msg
->h
, question
->uDNS_info
.id
, flags
);
2399 mDNSlocal mStatus
constructQueryMsg(DNSMessage
*msg
, mDNSu8
**endPtr
, DNSQuestion
*const question
)
2401 initializeQuery(msg
, question
);
2403 *endPtr
= putQuestion(msg
, msg
->data
, msg
->data
+ AbsoluteMaxDNSMessageData
, &question
->qname
, question
->qtype
, question
->qclass
);
2406 LogMsg("ERROR: Unicast query out of space in packet");
2407 return mStatus_UnknownErr
;
2409 return mStatus_NoError
;
2412 mDNSlocal mDNSu8
*putLLQ(DNSMessage
*const msg
, mDNSu8
*ptr
, DNSQuestion
*question
, LLQOptData
*data
, mDNSBool includeQuestion
)
2415 ResourceRecord
*opt
= &rr
.resrec
;
2418 //!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section
2419 if (includeQuestion
)
2421 ptr
= putQuestion(msg
, ptr
, msg
->data
+ AbsoluteMaxDNSMessageData
, &question
->qname
, question
->qtype
, question
->qclass
);
2422 if (!ptr
) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL
; }
2424 // locate OptRR if it exists, set pointer to end
2425 // !!!KRS implement me
2428 // format opt rr (fields not specified are zero-valued)
2429 ubzero(&rr
, sizeof(AuthRecord
));
2430 opt
->rdata
= &rr
.rdatastorage
;
2432 opt
->RecordType
= kDNSRecordTypeKnownUnique
; // to avoid warnings in other layers
2433 opt
->rrtype
= kDNSType_OPT
;
2434 opt
->rdlength
= LLQ_OPT_SIZE
;
2435 opt
->rdestimate
= LLQ_OPT_SIZE
;
2437 optRD
= &rr
.resrec
.rdata
->u
.opt
;
2438 optRD
->opt
= kDNSOpt_LLQ
;
2439 optRD
->optlen
= sizeof(LLQOptData
);
2440 umemcpy(&optRD
->OptData
.llq
, data
, sizeof(LLQOptData
));
2441 ptr
= PutResourceRecordTTLJumbo(msg
, ptr
, &msg
->h
.numAdditionals
, opt
, 0);
2442 if (!ptr
) { LogMsg("ERROR: putLLQ - PutResourceRecordTTLJumbo"); return mDNSNULL
; }
2448 mDNSlocal mDNSBool
getLLQAtIndex(mDNS
*m
, DNSMessage
*msg
, const mDNSu8
*end
, LLQOptData
*llq
, int index
)
2450 LargeCacheRecord lcr
;
2454 ptr
= LocateAdditionals(msg
, end
);
2455 if (!ptr
) return mDNSfalse
;
2457 // find the last additional
2458 for (i
= 0; i
< msg
->h
.numAdditionals
; i
++)
2459 // { ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; }
2460 //!!!KRS workaround for LH server bug, which puts OPT as first additional
2461 { ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &lcr
); if (!ptr
) return mDNSfalse
; if (lcr
.r
.resrec
.rrtype
== kDNSType_OPT
) break; }
2462 if (lcr
.r
.resrec
.rrtype
!= kDNSType_OPT
) return mDNSfalse
;
2463 if (lcr
.r
.resrec
.rdlength
< (index
+ 1) * LLQ_OPT_SIZE
) return mDNSfalse
; // rdata too small
2464 umemcpy(llq
, (mDNSu8
*)&lcr
.r
.resrec
.rdata
->u
.opt
.OptData
.llq
+ (index
* sizeof(LLQOptData
)), sizeof(LLQOptData
)); // !!! Should convert to host byte order?
2468 mDNSlocal
void recvRefreshReply(mDNS
*m
, DNSMessage
*msg
, const mDNSu8
*end
, DNSQuestion
*q
)
2473 qInfo
= q
->uDNS_info
.llq
;
2474 if (!getLLQAtIndex(m
, msg
, end
, &pktData
, 0)) { LogMsg("ERROR recvRefreshReply - getLLQAtIndex"); return; }
2475 if (pktData
.llqOp
!= kLLQOp_Refresh
) return;
2476 if (!sameID(pktData
.id
, qInfo
->id
)) { LogMsg("recvRefreshReply - ID mismatch. Discarding"); return; }
2477 if (pktData
.err
!= LLQErr_NoError
) { LogMsg("recvRefreshReply: received error %d from server", pktData
.err
); return; }
2479 qInfo
->expire
= mDNSPlatformTimeNow(m
) + ((mDNSs32
)pktData
.lease
* mDNSPlatformOneSecond
);
2480 qInfo
->retry
= qInfo
->expire
- ((mDNSs32
)pktData
.lease
* mDNSPlatformOneSecond
/2);
2482 qInfo
->origLease
= pktData
.lease
;
2483 qInfo
->state
= LLQ_Established
;
2486 mDNSlocal
void sendLLQRefresh(mDNS
*m
, DNSQuestion
*q
, mDNSu32 lease
)
2491 LLQ_Info
*info
= q
->uDNS_info
.llq
;
2495 timenow
= mDNSPlatformTimeNow(m
);
2496 if ((info
->state
== LLQ_Refresh
&& info
->ntries
>= kLLQ_MAX_TRIES
) ||
2497 info
->expire
- timenow
< 0)
2499 LogMsg("Unable to refresh LLQ %##s - will retry in %d minutes", q
->qname
.c
, kLLQ_DEF_RETRY
/60);
2500 info
->state
= LLQ_Retry
;
2501 info
->retry
= mDNSPlatformTimeNow(m
) + kLLQ_DEF_RETRY
* mDNSPlatformOneSecond
;
2502 info
->deriveRemovesOnResume
= mDNStrue
;
2504 //!!!KRS handle this - periodically try to re-establish
2507 llq
.vers
= kLLQ_Vers
;
2508 llq
.llqOp
= kLLQOp_Refresh
;
2509 llq
.err
= LLQErr_NoError
;
2510 umemcpy(llq
.id
, info
->id
, 8);
2513 initializeQuery(&msg
, q
);
2514 end
= putLLQ(&msg
, msg
.data
, q
, &llq
, mDNStrue
);
2515 if (!end
) { LogMsg("ERROR: sendLLQRefresh - putLLQ"); return; }
2517 err
= mDNSSendDNSMessage(m
, &msg
, end
, mDNSInterface_Any
, &info
->servAddr
, info
->servPort
, -1, mDNSNULL
);
2518 if (err
) LogMsg("ERROR: sendLLQRefresh - mDNSSendDNSMessage returned %ld", err
);
2520 if (info
->state
== LLQ_Established
) info
->ntries
= 1;
2521 else info
->ntries
++;
2522 info
->state
= LLQ_Refresh
;
2523 q
->LastQTime
= timenow
;
2524 info
->retry
= (info
->expire
- q
->LastQTime
) / 2;
2527 mDNSlocal mDNSBool
recvLLQEvent(mDNS
*m
, DNSQuestion
*q
, DNSMessage
*msg
, const mDNSu8
*end
, const mDNSAddr
*srcaddr
, mDNSIPPort srcport
, mDNSInterfaceID InterfaceID
)
2530 mDNSu8
*ackEnd
= ack
.data
;
2534 (void)InterfaceID
; // unused
2536 // find Opt RR, verify correct ID
2537 if (!getLLQAtIndex(m
, msg
, end
, &opt
, 0)) { debugf("Pkt does not contain LLQ Opt"); return mDNSfalse
; }
2538 if (opt
.llqOp
!= kLLQOp_Event
) { LogMsg("recvLLQEvent - Bad LLQ Opcode %d", opt
.llqOp
); return mDNSfalse
; }
2539 if (!q
->uDNS_info
.llq
) { LogMsg("Error: recvLLQEvent - question onject does not contain LLQ metadata"); return mDNSfalse
; }
2540 if (!sameID(opt
.id
, q
->uDNS_info
.llq
->id
)) { LogMsg("recvLLQEvent - incorrect ID. Discarding"); return mDNSfalse
; }
2542 // invoke response handler
2543 m
->uDNS_info
.CurrentQuery
= q
;
2544 q
->uDNS_info
.responseCallback(m
, msg
, end
, q
, q
->uDNS_info
.context
);
2545 if (m
->uDNS_info
.CurrentQuery
!= q
) return mDNStrue
;
2547 // format and send ack
2548 InitializeDNSMessage(&ack
.h
, msg
->h
.id
, ResponseFlags
);
2549 ackEnd
= putQuestion(&ack
, ack
.data
, ack
.data
+ AbsoluteMaxDNSMessageData
, &q
->qname
, q
->qtype
, q
->qclass
);
2550 if (!ackEnd
) { LogMsg("ERROR: recvLLQEvent - putQuestion"); return mDNSfalse
; }
2551 err
= mDNSSendDNSMessage(m
, &ack
, ackEnd
, mDNSInterface_Any
, srcaddr
, srcport
, -1, mDNSNULL
);
2552 if (err
) LogMsg("ERROR: recvLLQEvent - mDNSSendDNSMessage returned %ld", err
);
2558 mDNSlocal
void hndlChallengeResponseAck(mDNS
*m
, DNSMessage
*pktMsg
, const mDNSu8
*end
, LLQOptData
*llq
, DNSQuestion
*q
)
2560 LLQ_Info
*info
= q
->uDNS_info
.llq
;
2562 if (llq
->err
) { LogMsg("hndlChallengeResponseAck - received error %d from server", llq
->err
); goto error
; }
2563 if (!sameID(info
->id
, llq
->id
)) { LogMsg("hndlChallengeResponseAck - ID changed. discarding"); return; } // this can happen rarely (on packet loss + reordering)
2564 info
->expire
= mDNSPlatformTimeNow(m
) + ((mDNSs32
)llq
->lease
* mDNSPlatformOneSecond
);
2565 info
->retry
= info
->expire
- ((mDNSs32
)llq
->lease
* mDNSPlatformOneSecond
/ 2);
2567 info
->origLease
= llq
->lease
;
2568 info
->state
= LLQ_Established
;
2570 q
->uDNS_info
.responseCallback
= llqResponseHndlr
;
2571 llqResponseHndlr(m
, pktMsg
, end
, q
, mDNSNULL
);
2575 info
->state
= LLQ_Error
;
2578 mDNSlocal
void sendChallengeResponse(mDNS
*m
, DNSQuestion
*q
, LLQOptData
*llq
)
2580 LLQ_Info
*info
= q
->uDNS_info
.llq
;
2581 DNSMessage response
;
2582 mDNSu8
*responsePtr
= response
.data
;
2585 mDNSs32 timenow
= mDNSPlatformTimeNow(m
);
2587 if (info
->ntries
++ == kLLQ_MAX_TRIES
)
2589 LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s. Will re-try in %d minutes",
2590 kLLQ_MAX_TRIES
, q
->qname
.c
, kLLQ_DEF_RETRY
/ 60);
2591 info
->state
= LLQ_Retry
;
2592 info
->retry
= timenow
+ (kLLQ_DEF_RETRY
* mDNSPlatformOneSecond
);
2593 // !!!KRS give a callback error in these cases?
2601 llq
->vers
= kLLQ_Vers
;
2602 llq
->llqOp
= kLLQOp_Setup
;
2603 llq
->err
= LLQErr_NoError
;
2604 umemcpy(llq
->id
, info
->id
, 8);
2605 llq
->lease
= info
->origLease
;
2608 q
->LastQTime
= timenow
;
2609 info
->retry
= timenow
+ (kLLQ_INIT_RESEND
* info
->ntries
* mDNSPlatformOneSecond
);
2611 if (constructQueryMsg(&response
, &responsePtr
, q
)) goto error
;
2612 responsePtr
= putLLQ(&response
, responsePtr
, q
, llq
, mDNSfalse
);
2613 if (!responsePtr
) { LogMsg("ERROR: sendChallengeResponse - putLLQ"); goto error
; }
2615 err
= mDNSSendDNSMessage(m
, &response
, responsePtr
, mDNSInterface_Any
, &info
->servAddr
, info
->servPort
, -1, mDNSNULL
);
2616 if (err
) LogMsg("ERROR: sendChallengeResponse - mDNSSendDNSMessage returned %ld", err
);
2617 // on error, we procede as normal and retry after the appropriate interval
2622 info
->state
= LLQ_Error
;
2627 mDNSlocal
void hndlRequestChallenge(mDNS
*m
, DNSMessage
*pktMsg
, const mDNSu8
*end
, LLQOptData
*llq
, DNSQuestion
*q
)
2629 LLQ_Info
*info
= q
->uDNS_info
.llq
;
2630 mDNSs32 timenow
= mDNSPlatformTimeNow(m
);
2633 case LLQErr_NoError
: break;
2634 case LLQErr_ServFull
:
2635 LogMsg("hndlRequestChallenge - received ServFull from server for LLQ %##s. Retry in %lu sec", q
->qname
.c
, llq
->lease
);
2636 info
->retry
= timenow
+ ((mDNSs32
)llq
->lease
* mDNSPlatformOneSecond
);
2637 info
->state
= LLQ_Retry
;
2638 simpleResponseHndlr(m
, pktMsg
, end
, q
, mDNSNULL
); // get available answers
2639 info
->deriveRemovesOnResume
= mDNStrue
;
2641 info
->state
= LLQ_Static
;
2642 LogMsg("LLQ %##s: static", q
->qname
.c
);
2643 simpleResponseHndlr(m
, pktMsg
, end
, q
, mDNSNULL
);
2645 case LLQErr_FormErr
:
2646 LogMsg("ERROR: hndlRequestChallenge - received FormErr from server for LLQ %##s", q
->qname
.c
);
2648 case LLQErr_BadVers
:
2649 LogMsg("ERROR: hndlRequestChallenge - received BadVers from server");
2651 case LLQErr_UnknownErr
:
2652 LogMsg("ERROR: hndlRequestChallenge - received UnknownErr from server for LLQ %##s", q
->qname
.c
);
2655 LogMsg("ERROR: hndlRequestChallenge - received invalid error %d for LLQ %##s", llq
->err
, q
->qname
.c
);
2659 if (info
->origLease
!= llq
->lease
)
2660 LogMsg("hndlRequestChallenge: requested lease %lu, granted lease %lu", info
->origLease
, llq
->lease
);
2662 // cache expiration in case we go to sleep before finishing setup
2663 info
->origLease
= llq
->lease
;
2664 info
->expire
= timenow
+ ((mDNSs32
)llq
->lease
* mDNSPlatformOneSecond
);
2667 info
->state
= LLQ_SecondaryRequest
;
2668 umemcpy(info
->id
, llq
->id
, 8);
2669 info
->ntries
= 0; // first attempt to send response
2671 sendChallengeResponse(m
, q
, llq
);
2676 info
->state
= LLQ_Error
;
2680 // response handler for initial and secondary setup responses
2681 mDNSlocal
void recvSetupResponse(mDNS
*m
, DNSMessage
*pktMsg
, const mDNSu8
*end
, DNSQuestion
*q
, void *clientContext
)
2683 DNSQuestion pktQuestion
;
2685 const mDNSu8
*ptr
= pktMsg
->data
;
2686 LLQ_Info
*info
= q
->uDNS_info
.llq
;
2687 mDNSu8 rcode
= (mDNSu8
)(pktMsg
->h
.flags
.b
[1] & kDNSFlag1_RC
);
2689 (void)clientContext
; // unused
2691 if (rcode
&& rcode
!= kDNSFlag1_RC_NXDomain
) goto poll
;
2693 ptr
= getQuestion(pktMsg
, ptr
, end
, 0, &pktQuestion
);
2694 if (!ptr
) { LogMsg("ERROR: recvSetupResponse - getQuestion"); goto poll
; }
2695 if (!SameDomainName(&q
->qname
, &pktQuestion
.qname
))
2696 { LogMsg("ERROR: recvSetupResponse - mismatched question in response for llq setup %##s", q
->qname
.c
); goto poll
; }
2698 if (!getLLQAtIndex(m
, pktMsg
, end
, &llq
, 0)) { debugf("recvSetupResponse - GetLLQAtIndex"); goto poll
; }
2699 if (llq
.llqOp
!= kLLQOp_Setup
) { LogMsg("ERROR: recvSetupResponse - bad op %d", llq
.llqOp
); goto poll
; }
2700 if (llq
.vers
!= kLLQ_Vers
) { LogMsg("ERROR: recvSetupResponse - bad vers %d", llq
.vers
); goto poll
; }
2702 if (info
->state
== LLQ_InitialRequest
) { hndlRequestChallenge(m
, pktMsg
, end
, &llq
, q
); return; }
2703 if (info
->state
== LLQ_SecondaryRequest
) { hndlChallengeResponseAck(m
, pktMsg
, end
, &llq
, q
); return; }
2704 LogMsg("recvSetupResponse - bad state %d", info
->state
);
2707 info
->state
= LLQ_Poll
;
2708 q
->uDNS_info
.responseCallback
= llqResponseHndlr
;
2709 info
->question
->LastQTime
= mDNSPlatformTimeNow(m
) - (2 * INIT_UCAST_POLL_INTERVAL
); // trigger immediate poll
2710 info
->question
->ThisQInterval
= INIT_UCAST_POLL_INTERVAL
;
2713 mDNSlocal
void startLLQHandshake(mDNS
*m
, LLQ_Info
*info
, mDNSBool defer
)
2718 DNSQuestion
*q
= info
->question
;
2719 mStatus err
= mStatus_NoError
;
2720 mDNSs32 timenow
= mDNSPlatformTimeNow(m
);
2721 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
2723 if (IsPrivateV4Addr(&u
->PrimaryIP
))
2727 info
->state
= LLQ_NatMapWait
;
2731 if (u
->LLQNatInfo
->state
== NATState_Error
) goto poll
;
2732 if (u
->LLQNatInfo
->state
!= NATState_Established
&& u
->LLQNatInfo
->state
!= NATState_Legacy
)
2733 { info
->state
= LLQ_NatMapWait
; info
->NATMap
= mDNStrue
; return; }
2734 info
->NATMap
= mDNStrue
; // this llq references the global llq nat mapping
2737 if (info
->ntries
++ >= kLLQ_MAX_TRIES
)
2739 debugf("startLLQHandshake: %d failed attempts for LLQ %##s. Polling.", kLLQ_MAX_TRIES
, q
->qname
.c
, kLLQ_DEF_RETRY
/ 60);
2744 llqData
.vers
= kLLQ_Vers
;
2745 llqData
.llqOp
= kLLQOp_Setup
;
2746 llqData
.err
= LLQErr_NoError
;
2747 ubzero(llqData
.id
, 8);
2748 llqData
.lease
= kLLQ_DefLease
;
2750 initializeQuery(&msg
, q
);
2751 end
= putLLQ(&msg
, msg
.data
, q
, &llqData
, mDNStrue
);
2754 LogMsg("ERROR: startLLQHandshake - putLLQ");
2755 info
->state
= LLQ_Error
;
2759 if (!defer
) // if we are to defer, we simply set the retry timers so the request goes out in the future
2761 err
= mDNSSendDNSMessage(m
, &msg
, end
, mDNSInterface_Any
, &info
->servAddr
, info
->servPort
, -1, mDNSNULL
);
2762 if (err
) LogMsg("ERROR: startLLQHandshake - mDNSSendDNSMessage returned %ld", err
);
2763 // on error, we procede as normal and retry after the appropriate interval
2766 // update question/info state
2767 info
->state
= LLQ_InitialRequest
;
2768 info
->origLease
= kLLQ_DefLease
;
2769 info
->retry
= timenow
+ (kLLQ_INIT_RESEND
* mDNSPlatformOneSecond
);
2770 q
->LastQTime
= timenow
;
2771 q
->uDNS_info
.responseCallback
= recvSetupResponse
;
2772 q
->uDNS_info
.internal
= mDNStrue
;
2776 info
->question
->uDNS_info
.responseCallback
= llqResponseHndlr
;
2777 info
->state
= LLQ_Poll
;
2778 info
->question
->LastQTime
= mDNSPlatformTimeNow(m
) - (2 * INIT_UCAST_POLL_INTERVAL
); // trigger immediate poll
2779 info
->question
->ThisQInterval
= INIT_UCAST_POLL_INTERVAL
;
2782 // wrapper for startLLQHandshake, invoked by async op callback
2783 mDNSlocal
void startLLQHandshakeCallback(mStatus err
, mDNS
*const m
, void *llqInfo
, const AsyncOpResult
*result
)
2785 LLQ_Info
*info
= (LLQ_Info
*)llqInfo
;
2786 const zoneData_t
*zoneInfo
= mDNSNULL
;
2788 // check state first to make sure it is OK to touch question object
2789 if (info
->state
== LLQ_Cancelled
)
2791 // StopQuery was called while we were getting the zone info
2792 debugf("startLLQHandshake - LLQ Cancelled.");
2793 info
->question
= mDNSNULL
; // question may be deallocated
2798 if (!info
->question
)
2799 { LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL question"); goto error
; }
2801 if (info
->state
!= LLQ_GetZoneInfo
)
2802 { LogMsg("ERROR: startLLQHandshake - bad state %d", info
->state
); goto error
; }
2805 { LogMsg("ERROR: startLLQHandshakeCallback invoked with error code %ld", err
); goto poll
; }
2808 { LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL result and no error code"); goto error
; }
2810 zoneInfo
= &result
->zoneData
;
2812 if (!zoneInfo
->llqPort
.NotAnInteger
)
2813 { debugf("LLQ port lookup failed - reverting to polling"); goto poll
; }
2815 // cache necessary zone data
2816 info
->servAddr
.type
= zoneInfo
->primaryAddr
.type
;
2817 info
->servAddr
.ip
.v4
.NotAnInteger
= zoneInfo
->primaryAddr
.ip
.v4
.NotAnInteger
;
2818 info
->servPort
.NotAnInteger
= zoneInfo
->llqPort
.NotAnInteger
;
2821 if (info
->state
== LLQ_SuspendDeferred
) info
->state
= LLQ_Suspended
;
2822 else startLLQHandshake(m
, info
, mDNSfalse
);
2826 info
->question
->uDNS_info
.responseCallback
= llqResponseHndlr
;
2827 info
->state
= LLQ_Poll
;
2828 info
->question
->LastQTime
= mDNSPlatformTimeNow(m
) - (2 * INIT_UCAST_POLL_INTERVAL
); // trigger immediate poll
2829 info
->question
->ThisQInterval
= INIT_UCAST_POLL_INTERVAL
;
2833 info
->state
= LLQ_Error
;
2836 mDNSlocal mStatus
startLLQ(mDNS
*m
, DNSQuestion
*question
)
2839 mStatus err
= mStatus_NoError
;
2841 // allocate / init info struct
2842 info
= umalloc(sizeof(LLQ_Info
));
2843 if (!info
) { LogMsg("ERROR: startLLQ - malloc"); return mStatus_NoMemoryErr
; }
2844 ubzero(info
, sizeof(LLQ_Info
));
2845 info
->state
= LLQ_GetZoneInfo
;
2847 // link info/question
2848 info
->question
= question
;
2849 question
->uDNS_info
.llq
= info
;
2851 question
->uDNS_info
.responseCallback
= llqResponseHndlr
;
2853 err
= startGetZoneData(&question
->qname
, m
, mDNSfalse
, mDNStrue
, startLLQHandshakeCallback
, info
);
2856 LogMsg("ERROR: startLLQ - startGetZoneData returned %ld", err
);
2857 info
->question
= mDNSNULL
;
2859 question
->uDNS_info
.llq
= mDNSNULL
;
2863 LinkActiveQuestion(&m
->uDNS_info
, question
);
2867 mDNSlocal mDNSBool
recvLLQResponse(mDNS
*m
, DNSMessage
*msg
, const mDNSu8
*end
, const mDNSAddr
*srcaddr
, mDNSIPPort srcport
, const mDNSInterfaceID InterfaceID
)
2869 DNSQuestion pktQ
, *q
;
2870 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
2871 const mDNSu8
*ptr
= msg
->data
;
2874 if (!msg
->h
.numQuestions
) return mDNSfalse
;
2876 ptr
= getQuestion(msg
, ptr
, end
, 0, &pktQ
);
2877 if (!ptr
) return mDNSfalse
;
2878 pktQ
.uDNS_info
.id
= msg
->h
.id
;
2880 q
= u
->ActiveQueries
;
2883 llqInfo
= q
->uDNS_info
.llq
;
2886 q
->qnamehash
== pktQ
.qnamehash
&&
2887 q
->qtype
== pktQ
.qtype
&&
2888 SameDomainName(&q
->qname
, &pktQ
.qname
))
2890 u
->CurrentQuery
= q
;
2891 if (llqInfo
->state
== LLQ_Established
|| (llqInfo
->state
== LLQ_Refresh
&& msg
->h
.numAnswers
))
2892 { if (recvLLQEvent(m
, q
, msg
, end
, srcaddr
, srcport
, InterfaceID
)) return mDNStrue
; }
2893 else if (msg
->h
.id
.NotAnInteger
== q
->uDNS_info
.id
.NotAnInteger
)
2895 if (llqInfo
->state
== LLQ_Refresh
&& msg
->h
.numAdditionals
&& !msg
->h
.numAnswers
)
2896 { recvRefreshReply(m
, msg
, end
, q
); return mDNStrue
; }
2897 if (llqInfo
->state
< LLQ_Static
)
2899 if ((llqInfo
->state
!= LLQ_InitialRequest
&& llqInfo
->state
!= LLQ_SecondaryRequest
) || mDNSSameAddress(srcaddr
, &llqInfo
->servAddr
))
2900 { q
->uDNS_info
.responseCallback(m
, msg
, end
, q
, q
->uDNS_info
.context
); return mDNStrue
; }
2909 mDNSexport mDNSBool
uDNS_IsActiveQuery(DNSQuestion
*const question
, uDNS_GlobalInfo
*u
)
2913 for (q
= u
->ActiveQueries
; q
; q
= q
->next
)
2917 if (!question
->uDNS_info
.id
.NotAnInteger
|| question
->InterfaceID
== mDNSInterface_LocalOnly
|| IsLocalDomain(&question
->qname
))
2918 LogMsg("Warning: Question %##s in Active Unicast Query list with id %d, interfaceID %p",
2919 question
->qname
.c
, question
->uDNS_info
.id
.NotAnInteger
, question
->InterfaceID
);
2926 // stopLLQ happens IN ADDITION to stopQuery
2927 mDNSlocal
void stopLLQ(mDNS
*m
, DNSQuestion
*question
)
2929 LLQ_Info
*info
= question
->uDNS_info
.llq
;
2932 if (!question
->LongLived
) { LogMsg("ERROR: stopLLQ - LongLived flag not set"); return; }
2933 if (!info
) { LogMsg("ERROR: stopLLQ - llq info is NULL"); return; }
2935 switch (info
->state
)
2938 LogMsg("ERROR: stopLLQ - state LLQ_UnInit");
2939 //!!!KRS should we unlink info<->question here?
2941 case LLQ_GetZoneInfo
:
2942 case LLQ_SuspendDeferred
:
2943 info
->question
= mDNSNULL
; // remove ref to question, as it may be freed when we get called back from async op
2944 info
->state
= LLQ_Cancelled
;
2946 case LLQ_Established
:
2948 // refresh w/ lease 0
2949 sendLLQRefresh(m
, question
, 0);
2952 debugf("stopLLQ - silently discarding LLQ in state %d", info
->state
);
2957 if (info
->NATMap
) info
->NATMap
= mDNSfalse
;
2958 CheckForUnreferencedLLQMapping(m
);
2959 info
->question
= mDNSNULL
;
2961 question
->uDNS_info
.llq
= mDNSNULL
;
2962 question
->LongLived
= mDNSfalse
;
2965 mDNSexport mStatus
uDNS_StopQuery(mDNS
*const m
, DNSQuestion
*const question
)
2967 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
2968 DNSQuestion
*qptr
, *prev
= mDNSNULL
;
2971 qptr
= u
->ActiveQueries
;
2974 if (qptr
== question
)
2976 if (question
->LongLived
&& question
->uDNS_info
.llq
)
2977 stopLLQ(m
, question
);
2978 if (m
->uDNS_info
.CurrentQuery
== question
)
2979 m
->uDNS_info
.CurrentQuery
= m
->uDNS_info
.CurrentQuery
->next
;
2980 while (question
->uDNS_info
.knownAnswers
)
2982 ka
= question
->uDNS_info
.knownAnswers
;
2983 question
->uDNS_info
.knownAnswers
= question
->uDNS_info
.knownAnswers
->next
;
2986 if (prev
) prev
->next
= question
->next
;
2987 else u
->ActiveQueries
= question
->next
;
2988 return mStatus_NoError
;
2993 LogMsg("uDNS_StopQuery: no such active query (%##s)", question
->qname
.c
);
2994 return mStatus_UnknownErr
;
2997 mDNSlocal mStatus
startQuery(mDNS
*const m
, DNSQuestion
*const question
, mDNSBool internal
)
2999 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
3002 mStatus err
= mStatus_NoError
;
3005 //!!!KRS we should check if the question is already in our acivequestion list
3006 if (!ValidateDomainName(&question
->qname
))
3008 LogMsg("Attempt to start query with invalid qname %##s %##s", question
->qname
.c
, DNSTypeName(question
->qtype
));
3009 return mStatus_Invalid
;
3012 question
->next
= mDNSNULL
;
3013 question
->qnamehash
= DomainNameHashValue(&question
->qname
); // to do quick domain name comparisons
3014 question
->uDNS_info
.id
= newMessageID(u
);
3015 question
->uDNS_info
.Answered
= mDNSfalse
;
3017 // break here if its and LLQ
3018 if (question
->LongLived
) return startLLQ(m
, question
);
3020 // else send the query to our server
3021 err
= constructQueryMsg(&msg
, &endPtr
, question
);
3022 if (err
) return err
;
3024 question
->LastQTime
= mDNSPlatformTimeNow(m
);
3025 question
->ThisQInterval
= INIT_UCAST_POLL_INTERVAL
;
3026 // store the question/id in active question list
3027 question
->uDNS_info
.internal
= internal
;
3028 LinkActiveQuestion(u
, question
);
3029 question
->uDNS_info
.knownAnswers
= mDNSNULL
;
3030 if (GetServerForName(u
, &question
->qname
, &server
))
3032 err
= mDNSSendDNSMessage(m
, &msg
, endPtr
, mDNSInterface_Any
, &server
, UnicastDNSPort
, -1, mDNSNULL
);
3033 if (err
) { debugf("ERROR: startQuery - %ld (keeping question in list for retransmission", err
); }
3036 return mStatus_NoError
; // don't return transient errors to caller
3039 mDNSexport mStatus
uDNS_StartQuery(mDNS
*const m
, DNSQuestion
*const question
)
3041 ubzero(&question
->uDNS_info
, sizeof(uDNS_QuestionInfo
));
3042 question
->uDNS_info
.responseCallback
= simpleResponseHndlr
;
3043 question
->uDNS_info
.context
= mDNSNULL
;
3044 //LogOperation("uDNS_StartQuery %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
3045 return startQuery(m
, question
, 0);
3048 // explicitly set response handler
3049 mDNSlocal mStatus
startInternalQuery(DNSQuestion
*q
, mDNS
*m
, InternalResponseHndlr callback
, void *hndlrContext
)
3051 ubzero(&q
->uDNS_info
, sizeof(uDNS_QuestionInfo
));
3052 q
->QuestionContext
= hndlrContext
;
3053 q
->uDNS_info
.responseCallback
= callback
;
3054 q
->uDNS_info
.context
= hndlrContext
;
3055 return startQuery(m
, q
, 1);
3060 // ***************************************************************************
3061 #if COMPILER_LIKES_PRAGMA_MARK
3062 #pragma mark - Domain -> Name Server Conversion
3068 * Asynchronously find the address of the nameserver for the enclosing zone for a given domain name,
3069 * i.e. the server to which update and LLQ requests will be sent for a given name. Once the address is
3070 * derived, it will be passed to the callback, along with a context pointer. If the zone cannot
3071 * be determined or if an error occurs, an all-zeros address will be passed and a message will be
3072 * written to the syslog.
3074 * If the FindUpdatePort arg is set, the port on which the server accepts dynamic updates is determined
3075 * by querying for the _dns-update._udp.<zone>. SRV record. Likewise, if the FindLLQPort arg is set,
3076 * the port on which the server accepts long lived queries is determined by querying for
3077 * _dns-llq._udp.<zone>. record. If either of these queries fail, or flags are not specified,
3078 * the llqPort and updatePort fields in the result structure are set to zero.
3080 * Steps for deriving the zone name are as follows:
3082 * Query for an SOA record for the required domain. If we don't get an answer (or an SOA in the Authority
3083 * section), we strip the leading label from the name and repeat, until we get an answer.
3085 * The name of the SOA record is our enclosing zone. The mname field in the SOA rdata is the domain
3086 * name of the primary NS.
3088 * We verify that there is an NS record with this zone for a name and the mname for its rdata.
3089 * (!!!KRS this seems redundant, but BIND does this, and it should normally be zero-overhead since
3090 * the NS query will get us address records in the additionals section, which we'd otherwise have to
3091 * explicitly query for.)
3093 * We then query for the address record for this nameserver (if it is not in the addionals section of
3094 * the NS record response.)
3098 // state machine types and structs
3101 // state machine states
3116 // state machine actions
3119 smContinue
, // continue immediately to next state
3120 smBreak
, // break until next packet/timeout
3121 smError
// terminal error - cleanup and abort
3126 domainname origName
; // name we originally try to convert
3127 domainname
*curSOA
; // name we have an outstanding SOA query for
3128 ntaState state
; // determines what we do upon receiving a packet
3130 domainname zone
; // left-hand-side of SOA record
3132 domainname ns
; // mname in SOA rdata, verified in confirmNS state
3133 mDNSv4Addr addr
; // address of nameserver
3134 DNSQuestion question
; // storage for any active question
3135 DNSQuestion extraQuestion
; // additional storage
3136 mDNSBool questionActive
; // if true, StopQuery() can be called on the question field
3137 mDNSBool findUpdatePort
;
3138 mDNSBool findLLQPort
;
3139 mDNSIPPort updatePort
;
3141 AsyncOpCallback
*callback
; // caller specified function to be called upon completion
3146 // function prototypes (for routines that must be used as fn pointers prior to their definitions,
3147 // and allows states to be read top-to-bottom in logical order)
3148 mDNSlocal
void getZoneData(mDNS
*const m
, DNSMessage
*msg
, const mDNSu8
*end
, DNSQuestion
*question
, void *contextPtr
);
3149 mDNSlocal smAction
hndlLookupSOA(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
);
3150 mDNSlocal
void processSOA(ntaContext
*context
, ResourceRecord
*rr
);
3151 mDNSlocal smAction
confirmNS(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
);
3152 mDNSlocal smAction
lookupNSAddr(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
);
3153 mDNSlocal smAction
hndlLookupPorts(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
);
3156 mDNSlocal mStatus
startGetZoneData(domainname
*name
, mDNS
*m
, mDNSBool findUpdatePort
, mDNSBool findLLQPort
,
3157 AsyncOpCallback callback
, void *callbackInfo
)
3159 ntaContext
*context
= (ntaContext
*)umalloc(sizeof(ntaContext
));
3160 if (!context
) { LogMsg("ERROR: startGetZoneData - umalloc failed"); return mStatus_NoMemoryErr
; }
3161 ubzero(context
, sizeof(ntaContext
));
3162 AssignDomainName(context
->origName
, *name
);
3163 context
->state
= init
;
3165 context
->callback
= callback
;
3166 context
->callbackInfo
= callbackInfo
;
3167 context
->findUpdatePort
= findUpdatePort
;
3168 context
->findLLQPort
= findLLQPort
;
3169 getZoneData(m
, mDNSNULL
, mDNSNULL
, mDNSNULL
, context
);
3170 return mStatus_NoError
;
3173 // state machine entry routine
3174 mDNSlocal
void getZoneData(mDNS
*const m
, DNSMessage
*msg
, const mDNSu8
*end
, DNSQuestion
*question
, void *contextPtr
)
3176 AsyncOpResult result
;
3177 ntaContext
*context
= (ntaContext
*)contextPtr
;
3184 // stop any active question
3185 if (context
->questionActive
)
3187 uDNS_StopQuery(context
->m
, &context
->question
);
3188 context
->questionActive
= mDNSfalse
;
3191 if (msg
&& msg
->h
.flags
.b
[2] >> 4 && msg
->h
.flags
.b
[2] >> 4 != kDNSFlag1_RC_NXDomain
)
3193 // rcode non-zero, non-nxdomain
3194 LogMsg("ERROR: getZoneData - received response w/ rcode %d", msg
->h
.flags
.b
[2] >> 4);
3198 switch (context
->state
)
3202 action
= hndlLookupSOA(msg
, end
, context
);
3203 if (action
== smError
) goto error
;
3204 if (action
== smBreak
) return;
3207 action
= confirmNS(msg
, end
, context
);
3208 if (action
== smError
) goto error
;
3209 if (action
== smBreak
) return;
3212 action
= lookupNSAddr(msg
, end
, context
);
3213 if (action
== smError
) goto error
;
3214 if (action
== smBreak
) return;
3216 if (!context
->findUpdatePort
&& !context
->findLLQPort
)
3218 context
->state
= complete
;
3222 action
= hndlLookupPorts(msg
, end
, context
);
3223 if (action
== smError
) goto error
;
3224 if (action
== smBreak
) return;
3225 if (action
== smContinue
) context
->state
= complete
;
3227 case complete
: break;
3230 if (context
->state
!= complete
)
3232 LogMsg("ERROR: getZoneData - exited state machine with state %d", context
->state
);
3236 result
.type
= zoneDataResult
;
3237 result
.zoneData
.primaryAddr
.ip
.v4
.NotAnInteger
= context
->addr
.NotAnInteger
;
3238 result
.zoneData
.primaryAddr
.type
= mDNSAddrType_IPv4
;
3239 AssignDomainName(result
.zoneData
.zoneName
, context
->zone
);
3240 result
.zoneData
.zoneClass
= context
->zoneClass
;
3241 result
.zoneData
.llqPort
= context
->findLLQPort
? context
->llqPort
: zeroIPPort
;
3242 result
.zoneData
.updatePort
= context
->findUpdatePort
? context
->updatePort
: zeroIPPort
;
3243 context
->callback(mStatus_NoError
, context
->m
, context
->callbackInfo
, &result
);
3247 if (context
&& context
->callback
)
3248 context
->callback(mStatus_UnknownErr
, context
->m
, context
->callbackInfo
, mDNSNULL
);
3250 if (context
&& context
->questionActive
)
3252 uDNS_StopQuery(context
->m
, &context
->question
);
3253 context
->questionActive
= mDNSfalse
;
3255 if (context
) ufree(context
);
3258 mDNSlocal smAction
hndlLookupSOA(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
)
3261 LargeCacheRecord lcr
;
3262 ResourceRecord
*rr
= &lcr
.r
.resrec
;
3263 DNSQuestion
*query
= &context
->question
;
3268 // if msg contains SOA record in answer or authority sections, update context/state and return
3270 ptr
= LocateAnswers(msg
, end
);
3271 for (i
= 0; i
< msg
->h
.numAnswers
; i
++)
3273 ptr
= GetLargeResourceRecord(context
->m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
3274 if (!ptr
) { LogMsg("ERROR: hndlLookupSOA, Answers - GetLargeResourceRecord returned NULL"); return smError
; }
3275 if (rr
->rrtype
== kDNSType_SOA
&& SameDomainName(context
->curSOA
, &rr
->name
))
3277 processSOA(context
, rr
);
3281 ptr
= LocateAuthorities(msg
, end
);
3282 // SOA not in answers, check in authority
3283 for (i
= 0; i
< msg
->h
.numAuthorities
; i
++)
3285 ptr
= GetLargeResourceRecord(context
->m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
); ///!!!KRS using type PacketAns for auth
3286 if (!ptr
) { LogMsg("ERROR: hndlLookupSOA, Authority - GetLargeResourceRecord returned NULL"); return smError
; }
3287 if (rr
->rrtype
== kDNSType_SOA
)
3289 processSOA(context
, rr
);
3295 if (context
->state
!= init
&& !context
->curSOA
->c
[0])
3297 // we've gone down to the root and have not found an SOA
3298 LogMsg("ERROR: hndlLookupSOA - recursed to root label of %##s without finding SOA",
3299 context
->origName
.c
);
3303 ubzero(query
, sizeof(DNSQuestion
));
3304 // chop off leading label unless this is our first try
3305 if (context
->state
== init
) context
->curSOA
= &context
->origName
;
3306 else context
->curSOA
= (domainname
*)(context
->curSOA
->c
+ context
->curSOA
->c
[0]+1);
3308 context
->state
= lookupSOA
;
3309 AssignDomainName(query
->qname
, *context
->curSOA
);
3310 query
->qtype
= kDNSType_SOA
;
3311 query
->qclass
= kDNSClass_IN
;
3312 err
= startInternalQuery(query
, context
->m
, getZoneData
, context
);
3313 context
->questionActive
= mDNStrue
;
3314 if (err
) LogMsg("hndlLookupSOA: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err
);
3316 return smBreak
; // break from state machine until we receive another packet
3319 mDNSlocal
void processSOA(ntaContext
*context
, ResourceRecord
*rr
)
3321 AssignDomainName(context
->zone
, rr
->name
);
3322 context
->zoneClass
= rr
->rrclass
;
3323 AssignDomainName(context
->ns
, rr
->rdata
->u
.soa
.mname
);
3324 context
->state
= foundZone
;
3328 mDNSlocal smAction
confirmNS(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
)
3330 DNSQuestion
*query
= &context
->question
;
3332 LargeCacheRecord lcr
;
3333 const ResourceRecord
*const rr
= &lcr
.r
.resrec
;
3337 if (context
->state
== foundZone
)
3339 // we've just learned the zone. confirm that an NS record exists
3340 AssignDomainName(query
->qname
, context
->zone
);
3341 query
->qtype
= kDNSType_NS
;
3342 query
->qclass
= kDNSClass_IN
;
3343 err
= startInternalQuery(query
, context
->m
, getZoneData
, context
);
3344 context
->questionActive
= mDNStrue
;
3345 if (err
) LogMsg("confirmNS: startInternalQuery returned error %ld (breaking until next periodic retransmission", err
);
3346 context
->state
= lookupNS
;
3347 return smBreak
; // break from SM until we receive another packet
3349 else if (context
->state
== lookupNS
)
3351 ptr
= LocateAnswers(msg
, end
);
3352 for (i
= 0; i
< msg
->h
.numAnswers
; i
++)
3354 ptr
= GetLargeResourceRecord(context
->m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
3355 if (!ptr
) { LogMsg("ERROR: confirmNS, Answers - GetLargeResourceRecord returned NULL"); return smError
; }
3356 if (rr
->rrtype
== kDNSType_NS
&&
3357 SameDomainName(&context
->zone
, &rr
->name
) && SameDomainName(&context
->ns
, &rr
->rdata
->u
.name
))
3359 context
->state
= foundNS
;
3360 return smContinue
; // next routine will examine additionals section of A record
3363 LogMsg("ERROR: could not confirm existence of record %##s NS %##s", context
->zone
.c
, context
->ns
.c
);
3366 else { LogMsg("ERROR: confirmNS - bad state %d", context
->state
); return smError
; }
3369 mDNSlocal smAction
queryNSAddr(ntaContext
*context
)
3372 DNSQuestion
*query
= &context
->question
;
3374 AssignDomainName(query
->qname
, context
->ns
);
3375 query
->qtype
= kDNSType_A
;
3376 query
->qclass
= kDNSClass_IN
;
3377 err
= startInternalQuery(query
, context
->m
, getZoneData
, context
);
3378 context
->questionActive
= mDNStrue
;
3379 if (err
) LogMsg("confirmNS: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err
);
3380 context
->state
= lookupA
;
3384 mDNSlocal smAction
lookupNSAddr(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
)
3388 LargeCacheRecord lcr
;
3389 ResourceRecord
*rr
= &lcr
.r
.resrec
;
3391 if (context
->state
== foundNS
)
3393 // we just found the NS record - look for the corresponding A record in the Additionals section
3394 if (!msg
->h
.numAdditionals
) return queryNSAddr(context
);
3395 ptr
= LocateAdditionals(msg
, end
);
3398 LogMsg("ERROR: lookupNSAddr - LocateAdditionals returned NULL, expected %d additionals", msg
->h
.numAdditionals
);
3399 return queryNSAddr(context
);
3403 for (i
= 0; i
< msg
->h
.numAdditionals
; i
++)
3405 ptr
= GetLargeResourceRecord(context
->m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
3408 LogMsg("ERROR: lookupNSAddr, Additionals - GetLargeResourceRecord returned NULL");
3409 return queryNSAddr(context
);
3411 if (rr
->rrtype
== kDNSType_A
&& SameDomainName(&context
->ns
, &rr
->name
))
3413 context
->addr
.NotAnInteger
= rr
->rdata
->u
.ipv4
.NotAnInteger
;
3414 context
->state
= foundA
;
3419 // no A record in Additionals - query the server
3420 return queryNSAddr(context
);
3422 else if (context
->state
== lookupA
)
3424 ptr
= LocateAnswers(msg
, end
);
3425 if (!ptr
) { LogMsg("ERROR: lookupNSAddr: LocateAnswers returned NULL"); return smError
; }
3426 for (i
= 0; i
< msg
->h
.numAnswers
; i
++)
3428 ptr
= GetLargeResourceRecord(context
->m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
3429 if (!ptr
) { LogMsg("ERROR: lookupNSAddr, Answers - GetLargeResourceRecord returned NULL"); break; }
3430 if (rr
->rrtype
== kDNSType_A
&& SameDomainName(&context
->ns
, &rr
->name
))
3432 context
->addr
.NotAnInteger
= rr
->rdata
->u
.ipv4
.NotAnInteger
;
3433 context
->state
= foundA
;
3437 LogMsg("ERROR: lookupNSAddr: Address record not found in answer section");
3440 else { LogMsg("ERROR: lookupNSAddr - bad state %d", context
->state
); return smError
; }
3443 mDNSlocal smAction
lookupDNSPort(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
, char *portName
, mDNSIPPort
*port
)
3446 LargeCacheRecord lcr
;
3451 if (context
->state
== lookupPort
) // we've already issued the query
3453 if (!msg
) { LogMsg("ERROR: hndlLookupUpdatePort - NULL message"); return smError
; }
3454 ptr
= LocateAnswers(msg
, end
);
3455 for (i
= 0; i
< msg
->h
.numAnswers
; i
++)
3457 ptr
= GetLargeResourceRecord(context
->m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
3458 if (!ptr
) { LogMsg("ERROR: hndlLookupUpdatePort - GetLargeResourceRecord returned NULL"); return smError
; }
3459 if (ResourceRecordAnswersQuestion(&lcr
.r
.resrec
, &context
->question
))
3461 port
->NotAnInteger
= lcr
.r
.resrec
.rdata
->u
.srv
.port
.NotAnInteger
;
3462 context
->state
= foundPort
;
3466 debugf("hndlLookupUpdatePort - no answer for type %s", portName
);
3467 port
->NotAnInteger
= 0;
3468 context
->state
= foundPort
;
3472 // query the server for the update port for the zone
3473 context
->state
= lookupPort
;
3474 q
= &context
->question
;
3475 MakeDomainNameFromDNSNameString(&q
->qname
, portName
);
3476 AppendDomainName(&q
->qname
, &context
->zone
);
3477 q
->qtype
= kDNSType_SRV
;
3478 q
->qclass
= kDNSClass_IN
;
3479 err
= startInternalQuery(q
, context
->m
, getZoneData
, context
);
3480 context
->questionActive
= mDNStrue
;
3481 if (err
) LogMsg("hndlLookupSOA: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err
);
3482 return smBreak
; // break from state machine until we receive another packet
3485 mDNSlocal smAction
hndlLookupPorts(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
)
3489 if (context
->findUpdatePort
&& !context
->updatePort
.NotAnInteger
)
3491 action
= lookupDNSPort(msg
, end
, context
, UPDATE_PORT_NAME
, &context
->updatePort
);
3492 if (action
!= smContinue
) return action
;
3494 if (context
->findLLQPort
&& !context
->llqPort
.NotAnInteger
)
3495 return lookupDNSPort(msg
, end
, context
, LLQ_PORT_NAME
, &context
->llqPort
);
3501 // ***************************************************************************
3502 #if COMPILER_LIKES_PRAGMA_MARK
3503 #pragma mark - Truncation Handling
3508 DNSQuestion
*question
;
3515 // issue queries over a conected socket
3516 mDNSlocal
void conQueryCallback(int sd
, void *context
, mDNSBool ConnectionEstablished
)
3519 char msgbuf
[356]; // 96 (hdr) + 256 (domain) + 4 (class/type)
3522 tcpInfo_t
*info
= (tcpInfo_t
*)context
;
3523 DNSQuestion
*question
= info
->question
;
3529 if (ConnectionEstablished
)
3531 // connection is established - send the message
3532 msg
= (DNSMessage
*)&msgbuf
;
3533 err
= constructQueryMsg(msg
, &end
, question
);
3534 if (err
) { LogMsg("ERROR: conQueryCallback: constructQueryMsg - %ld", err
); goto error
; }
3535 err
= mDNSSendDNSMessage(m
, msg
, end
, mDNSInterface_Any
, &zeroAddr
, zeroIPPort
, sd
, mDNSNULL
);
3536 question
->LastQTime
= mDNSPlatformTimeNow(m
);
3537 if (err
) { LogMsg("ERROR: conQueryCallback: mDNSSendDNSMessage_tcp - %ld", err
); goto error
; }
3544 n
= mDNSPlatformReadTCP(sd
, &info
->replylen
, 2);
3547 LogMsg("ERROR:conQueryCallback - attempt to read message length failed (read returned %d)", n
);
3551 n
= mDNSPlatformReadTCP(sd
, ((char *)&info
->reply
) + info
->nread
, info
->replylen
- info
->nread
);
3552 if (n
< 0) { LogMsg("ERROR: conQueryCallback - read returned %d", n
); goto error
; }
3554 if (info
->nread
== info
->replylen
)
3556 // finished reading message
3557 uDNS_ReceiveMsg(m
, &info
->reply
, ((mDNSu8
*)&info
->reply
) + info
->replylen
, mDNSNULL
, zeroIPPort
, mDNSNULL
, zeroIPPort
, question
->InterfaceID
);
3558 mDNSPlatformTCPCloseConnection(sd
);
3567 mDNSPlatformTCPCloseConnection(sd
);
3572 mDNSlocal
void hndlTruncatedAnswer(DNSQuestion
*question
, const mDNSAddr
*src
, mDNS
*m
)
3574 mStatus connectionStatus
;
3575 uDNS_QuestionInfo
*info
= &question
->uDNS_info
;
3579 if (!src
) { LogMsg("hndlTruncatedAnswer: TCP DNS response had TC bit set: ignoring"); return; }
3581 context
= (tcpInfo_t
*)umalloc(sizeof(tcpInfo_t
));
3582 if (!context
) { LogMsg("ERROR: hndlTruncatedAnswer - memallocate failed"); return; }
3583 ubzero(context
, sizeof(tcpInfo_t
));
3584 context
->question
= question
;
3586 info
->id
= newMessageID(&m
->uDNS_info
);
3588 connectionStatus
= mDNSPlatformTCPConnect(src
, UnicastDNSPort
, question
->InterfaceID
, conQueryCallback
, context
, &sd
);
3589 if (connectionStatus
== mStatus_ConnEstablished
) // manually invoke callback if connection completes
3591 conQueryCallback(sd
, context
, mDNStrue
);
3594 if (connectionStatus
== mStatus_ConnPending
) return; // callback will be automatically invoked when connection completes
3595 LogMsg("hndlTruncatedAnswer: connection failed");
3596 uDNS_StopQuery(m
, question
); //!!!KRS can we really call this here?
3600 // ***************************************************************************
3601 #if COMPILER_LIKES_PRAGMA_MARK
3602 #pragma mark - Dynamic Updates
3607 mDNSlocal
void sendRecordRegistration(mDNS
*const m
, AuthRecord
*rr
)
3610 mDNSu8
*ptr
= msg
.data
;
3611 mDNSu8
*end
= (mDNSu8
*)&msg
+ sizeof(DNSMessage
);
3612 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
3614 uDNS_RegInfo
*regInfo
= &rr
->uDNS_info
;
3615 mStatus err
= mStatus_UnknownErr
;
3617 id
= newMessageID(u
);
3618 InitializeDNSMessage(&msg
.h
, id
, UpdateReqFlags
);
3619 rr
->uDNS_info
.id
.NotAnInteger
= id
.NotAnInteger
;
3622 ptr
= putZone(&msg
, ptr
, end
, ®Info
->zone
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
3623 if (!ptr
) goto error
;
3625 if (rr
->resrec
.RecordType
== kDNSRecordTypeKnownUnique
|| rr
->uDNS_info
.state
== regState_Refresh
)
3627 // KnownUnique means the record must ALREADY exist, as does refresh
3628 // prereq: record must exist (put record in prereq section w/ TTL 0)
3629 ptr
= PutResourceRecordTTLJumbo(&msg
, ptr
, &msg
.h
.mDNS_numPrereqs
, &rr
->resrec
, 0);
3630 if (!ptr
) goto error
;
3632 else if (rr
->resrec
.RecordType
!= kDNSRecordTypeShared
)
3634 ptr
= putPrereqNameNotInUse(&rr
->resrec
.name
, &msg
, ptr
, end
);
3635 if (!ptr
) goto error
;
3638 ptr
= PutResourceRecordTTLJumbo(&msg
, ptr
, &msg
.h
.mDNS_numUpdates
, &rr
->resrec
, rr
->resrec
.rroriginalttl
);
3639 if (!ptr
) goto error
;
3641 if (rr
->uDNS_info
.lease
)
3642 { ptr
= putUpdateLease(&msg
, ptr
, kLLQ_DefLease
); if (!ptr
) goto error
; }
3644 rr
->uDNS_info
.expire
= -1;
3646 err
= mDNSSendDNSMessage(m
, &msg
, ptr
, mDNSInterface_Any
, ®Info
->ns
, regInfo
->port
, -1, GetAuthInfoForZone(u
, ®Info
->zone
));
3647 if (err
) LogMsg("ERROR: sendRecordRegistration - mDNSSendDNSMessage - %ld", err
);
3649 SetRecordRetry(m
, rr
);
3651 if (regInfo
->state
!= regState_Refresh
) regInfo
->state
= regState_Pending
;
3655 LogMsg("sendRecordRegistration: Error formatting message");
3656 if (rr
->uDNS_info
.state
!= regState_Unregistered
)
3658 unlinkAR(&u
->RecordRegistrations
, rr
);
3659 rr
->uDNS_info
.state
= regState_Unregistered
;
3661 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
3662 if (rr
->RecordCallback
) rr
->RecordCallback(m
, rr
, err
);
3663 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
3664 // NOTE: not safe to touch any client structures here
3667 mDNSlocal
void RecordRegistrationCallback(mStatus err
, mDNS
*const m
, void *authPtr
, const AsyncOpResult
*result
)
3669 AuthRecord
*newRR
= (AuthRecord
*)authPtr
;
3670 const zoneData_t
*zoneData
= mDNSNULL
;
3671 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
3674 // make sure record is still in list
3675 for (ptr
= u
->RecordRegistrations
; ptr
; ptr
= ptr
->next
)
3676 if (ptr
== newRR
) break;
3677 if (!ptr
) { LogMsg("RecordRegistrationCallback - RR no longer in list. Discarding."); return; }
3679 // check error/result
3680 if (err
) { LogMsg("RecordRegistrationCallback: error %ld", err
); goto error
; }
3681 if (!result
) { LogMsg("ERROR: RecordRegistrationCallback invoked with NULL result and no error"); goto error
; }
3682 else zoneData
= &result
->zoneData
;
3684 if (newRR
->uDNS_info
.state
== regState_Cancelled
)
3686 //!!!KRS we should send a memfree callback here!
3687 debugf("Registration of %##s type %d cancelled prior to update",
3688 newRR
->resrec
.name
.c
, newRR
->resrec
.rrtype
);
3689 newRR
->uDNS_info
.state
= regState_Unregistered
;
3690 unlinkAR(&u
->RecordRegistrations
, newRR
);
3694 if (result
->type
!= zoneDataResult
)
3696 LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result
->type
);
3700 if (newRR
->resrec
.rrclass
!= zoneData
->zoneClass
)
3702 LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)",
3703 newRR
->resrec
.rrclass
, zoneData
->zoneClass
);
3708 AssignDomainName(newRR
->uDNS_info
.zone
, zoneData
->zoneName
);
3709 newRR
->uDNS_info
.ns
.type
= mDNSAddrType_IPv4
;
3710 newRR
->uDNS_info
.ns
.ip
.v4
.NotAnInteger
= zoneData
->primaryAddr
.ip
.v4
.NotAnInteger
;
3711 if (zoneData
->updatePort
.NotAnInteger
) newRR
->uDNS_info
.port
= zoneData
->updatePort
;
3714 debugf("Update port not advertised via SRV - guessing port 53, no lease option");
3715 newRR
->uDNS_info
.port
= UnicastDNSPort
;
3716 newRR
->uDNS_info
.lease
= mDNSfalse
;
3719 sendRecordRegistration(m
, newRR
);
3723 if (newRR
->uDNS_info
.state
!= regState_Unregistered
)
3725 unlinkAR(&u
->RecordRegistrations
, newRR
);
3726 newRR
->uDNS_info
.state
= regState_Unregistered
;
3728 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
3729 if (newRR
->RecordCallback
)
3730 newRR
->RecordCallback(m
, newRR
, err
);
3731 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
3732 // NOTE: not safe to touch any client structures here
3735 mDNSlocal
void SendServiceRegistration(mDNS
*m
, ServiceRecordSet
*srs
)
3738 mDNSu8
*ptr
= msg
.data
;
3739 mDNSu8
*end
= (mDNSu8
*)&msg
+ sizeof(DNSMessage
);
3740 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
3742 uDNS_RegInfo
*rInfo
= &srs
->uDNS_info
;
3743 mStatus err
= mStatus_UnknownErr
;
3744 mDNSIPPort privport
;
3745 NATTraversalInfo
*nat
= srs
->uDNS_info
.NATinfo
;
3746 mDNSBool mapped
= mDNSfalse
;
3748 AuthRecord
*srv
= &srs
->RR_SRV
;
3750 id
= newMessageID(u
);
3751 InitializeDNSMessage(&msg
.h
, id
, UpdateReqFlags
);
3753 // setup resource records
3754 SetNewRData(&srs
->RR_PTR
.resrec
, mDNSNULL
, 0);
3755 SetNewRData(&srs
->RR_TXT
.resrec
, mDNSNULL
, 0);
3757 // replace port w/ NAT mapping if necessary
3758 if (nat
&& nat
->PublicPort
.NotAnInteger
&&
3759 (nat
->state
== NATState_Established
|| nat
->state
== NATState_Refresh
|| nat
->state
== NATState_Legacy
))
3761 privport
= srv
->resrec
.rdata
->u
.srv
.port
;
3762 srv
->resrec
.rdata
->u
.srv
.port
= nat
->PublicPort
;
3766 // construct update packet
3768 ptr
= putZone(&msg
, ptr
, end
, &rInfo
->zone
, mDNSOpaque16fromIntVal(srv
->resrec
.rrclass
));
3769 if (!ptr
) goto error
;
3771 if (srs
->uDNS_info
.TestForSelfConflict
)
3773 // update w/ prereq that records already exist to make sure previous registration was ours
3774 if (!(ptr
= PutResourceRecordTTLJumbo(&msg
, ptr
, &msg
.h
.mDNS_numPrereqs
, &srs
->RR_SRV
.resrec
, 0))) goto error
;
3775 if (!(ptr
= PutResourceRecordTTLJumbo(&msg
, ptr
, &msg
.h
.mDNS_numPrereqs
, &srs
->RR_TXT
.resrec
, 0))) goto error
;
3778 else if (srs
->uDNS_info
.state
!= regState_Refresh
)
3780 // use SRV name for prereq
3781 ptr
= putPrereqNameNotInUse(&srv
->resrec
.name
, &msg
, ptr
, end
);
3782 if (!ptr
) goto error
;
3785 //!!!KRS Need to do bounds checking and use TCP if it won't fit!!!
3786 if (!(ptr
= PutResourceRecordTTLJumbo(&msg
, ptr
, &msg
.h
.mDNS_numUpdates
, &srs
->RR_PTR
.resrec
, srs
->RR_PTR
.resrec
.rroriginalttl
))) goto error
;
3787 if (!(ptr
= PutResourceRecordTTLJumbo(&msg
, ptr
, &msg
.h
.mDNS_numUpdates
, &srs
->RR_TXT
.resrec
, srs
->RR_TXT
.resrec
.rroriginalttl
))) goto error
;
3789 if (!GetServiceTarget(u
, srv
, &target
))
3791 debugf("Couldn't get target for service %##s", srv
->resrec
.name
.c
);
3792 rInfo
->state
= regState_NoTarget
;
3795 if (!SameDomainName(&target
, &srv
->resrec
.rdata
->u
.srv
.target
))
3797 AssignDomainName(srv
->resrec
.rdata
->u
.srv
.target
, target
);
3798 SetNewRData(&srv
->resrec
, mDNSNULL
, 0);
3801 ptr
= PutResourceRecordTTLJumbo(&msg
, ptr
, &msg
.h
.mDNS_numUpdates
, &srv
->resrec
, srv
->resrec
.rroriginalttl
);
3802 if (!ptr
) goto error
;
3803 // !!!KRS do subtypes/extras etc.
3805 if (srs
->uDNS_info
.lease
)
3806 { ptr
= putUpdateLease(&msg
, ptr
, kLLQ_DefLease
); if (!ptr
) goto error
; }
3808 srs
->uDNS_info
.expire
= -1;
3810 err
= mDNSSendDNSMessage(m
, &msg
, ptr
, mDNSInterface_Any
, &rInfo
->ns
, rInfo
->port
, -1, GetAuthInfoForZone(u
, &rInfo
->zone
));
3811 if (err
) { LogMsg("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %ld", err
); goto error
; }
3813 if (rInfo
->state
!= regState_Refresh
)
3814 rInfo
->state
= regState_Pending
;
3816 SetRecordRetry(m
, &srs
->RR_SRV
);
3817 rInfo
->id
.NotAnInteger
= id
.NotAnInteger
;
3818 if (mapped
) srv
->resrec
.rdata
->u
.srv
.port
= privport
;
3822 LogMsg("SendServiceRegistration - Error formatting message");
3823 if (mapped
) srv
->resrec
.rdata
->u
.srv
.port
= privport
;
3825 rInfo
->state
= regState_Unregistered
;
3826 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
3827 srs
->ServiceCallback(m
, srs
, err
);
3828 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
3829 //!!!KRS will mem still be free'd on error?
3830 // NOTE: not safe to touch any client structures here
3833 mDNSlocal
void serviceRegistrationCallback(mStatus err
, mDNS
*const m
, void *srsPtr
, const AsyncOpResult
*result
)
3835 ServiceRecordSet
*srs
= (ServiceRecordSet
*)srsPtr
;
3836 const zoneData_t
*zoneData
= mDNSNULL
;
3837 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
3839 if (err
) goto error
;
3840 if (!result
) { LogMsg("ERROR: serviceRegistrationCallback invoked with NULL result and no error"); goto error
; }
3841 else zoneData
= &result
->zoneData
;
3843 if (result
->type
!= zoneDataResult
)
3845 LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result
->type
);
3849 if (srs
->uDNS_info
.state
== regState_Cancelled
)
3851 // client cancelled registration while fetching zone data
3852 srs
->uDNS_info
.state
= regState_Unregistered
;
3854 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
3855 srs
->ServiceCallback(m
, srs
, mStatus_MemFree
);
3856 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
3860 if (srs
->RR_SRV
.resrec
.rrclass
!= zoneData
->zoneClass
)
3862 LogMsg("Service %##s - class does not match zone", srs
->RR_SRV
.resrec
.name
.c
);
3866 AssignDomainName(srs
->uDNS_info
.zone
, zoneData
->zoneName
);
3867 srs
->uDNS_info
.ns
.type
= mDNSAddrType_IPv4
;
3868 srs
->uDNS_info
.ns
= zoneData
->primaryAddr
;
3869 if (zoneData
->updatePort
.NotAnInteger
) srs
->uDNS_info
.port
= zoneData
->updatePort
;
3872 debugf("Update port not advertised via SRV - guessing port 53, no lease option");
3873 srs
->uDNS_info
.port
= UnicastDNSPort
;
3874 srs
->uDNS_info
.lease
= mDNSfalse
;
3876 SendServiceRegistration(m
, srs
);
3881 srs
->uDNS_info
.state
= regState_Unregistered
;
3882 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
3883 srs
->ServiceCallback(m
, srs
, err
);
3884 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
3885 //!!!KRS will mem still be free'd on error?
3886 // NOTE: not safe to touch any client structures here
3889 mDNSlocal mStatus
SetupRecordRegistration(mDNS
*m
, AuthRecord
*rr
)
3891 domainname
*target
= GetRRDomainNameTarget(&rr
->resrec
);
3892 AuthRecord
*ptr
= m
->uDNS_info
.RecordRegistrations
;
3894 while (ptr
&& ptr
!= rr
) ptr
= ptr
->next
;
3895 if (ptr
) { LogMsg("Error: SetupRecordRegistration - record %##s already in list!", rr
->resrec
.name
.c
); return mStatus_AlreadyRegistered
; }
3897 if (rr
->uDNS_info
.state
== regState_FetchingZoneData
||
3898 rr
->uDNS_info
.state
== regState_Pending
||
3899 rr
->uDNS_info
.state
== regState_Registered
)
3901 LogMsg("Requested double-registration of physical record %##s type %d",
3902 rr
->resrec
.name
.c
, rr
->resrec
.rrtype
);
3903 return mStatus_AlreadyRegistered
;
3906 rr
->resrec
.rdlength
= GetRDLength(&rr
->resrec
, mDNSfalse
);
3907 rr
->resrec
.rdestimate
= GetRDLength(&rr
->resrec
, mDNStrue
);
3909 if (!ValidateDomainName(&rr
->resrec
.name
))
3911 LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m
, rr
));
3912 return mStatus_Invalid
;
3915 // Don't do this until *after* we've set rr->resrec.rdlength
3916 if (!ValidateRData(rr
->resrec
.rrtype
, rr
->resrec
.rdlength
, rr
->resrec
.rdata
))
3918 LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m
, rr
));
3919 return mStatus_Invalid
;
3922 rr
->resrec
.namehash
= DomainNameHashValue(&rr
->resrec
.name
);
3923 rr
->resrec
.rdatahash
= RDataHashValue(rr
->resrec
.rdlength
, &rr
->resrec
.rdata
->u
);
3924 rr
->resrec
.rdnamehash
= target
? DomainNameHashValue(target
) : 0;
3926 rr
->uDNS_info
.state
= regState_FetchingZoneData
;
3927 rr
->next
= m
->uDNS_info
.RecordRegistrations
;
3928 m
->uDNS_info
.RecordRegistrations
= rr
;
3929 rr
->uDNS_info
.lease
= mDNStrue
;
3931 return mStatus_NoError
;
3934 mDNSexport mStatus
uDNS_RegisterRecord(mDNS
*const m
, AuthRecord
*const rr
)
3936 mStatus err
= SetupRecordRegistration(m
, rr
);
3937 if (err
) return err
;
3938 else return startGetZoneData(&rr
->resrec
.name
, m
, mDNStrue
, mDNSfalse
, RecordRegistrationCallback
, rr
);
3941 mDNSlocal
void SendRecordDeregistration(mDNS
*m
, AuthRecord
*rr
)
3943 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
3945 mDNSu8
*ptr
= msg
.data
;
3946 mDNSu8
*end
= (mDNSu8
*)&msg
+ sizeof(DNSMessage
);
3949 InitializeDNSMessage(&msg
.h
, rr
->uDNS_info
.id
, UpdateReqFlags
);
3951 ptr
= putZone(&msg
, ptr
, end
, &rr
->uDNS_info
.zone
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
3952 if (!ptr
) goto error
;
3953 if (!(ptr
= putDeletionRecord(&msg
, ptr
, &rr
->resrec
))) goto error
;
3955 err
= mDNSSendDNSMessage(m
, &msg
, ptr
, mDNSInterface_Any
, &rr
->uDNS_info
.ns
, rr
->uDNS_info
.port
, -1, GetAuthInfoForZone(u
, &rr
->uDNS_info
.zone
));
3956 if (err
) LogMsg("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %ld", err
);
3958 SetRecordRetry(m
, rr
);
3959 rr
->uDNS_info
.state
= regState_DeregPending
;
3963 LogMsg("Error: SendRecordDeregistration - could not contruct deregistration packet");
3964 unlinkAR(&u
->RecordRegistrations
, rr
);
3965 rr
->uDNS_info
.state
= regState_Unregistered
;
3970 mDNSexport mStatus
uDNS_DeregisterRecord(mDNS
*const m
, AuthRecord
*const rr
)
3972 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
3973 NATTraversalInfo
*n
= rr
->uDNS_info
.NATinfo
;
3975 switch (rr
->uDNS_info
.state
)
3977 case regState_NATMap
:
3978 // we're in the middle of a NAT traversal operation
3979 if (!n
) LogMsg("uDNS_DeregisterRecord: no NAT info context");
3980 else FreeNATInfo(m
, n
); // cause response to outstanding request to be ignored.
3981 // Note: normally here we're trying to determine our public address,
3982 //in which case there is not state to be torn down. For simplicity,
3983 //we allow other operations to expire.
3984 rr
->uDNS_info
.NATinfo
= mDNSNULL
;
3985 rr
->uDNS_info
.state
= regState_Unregistered
;
3987 case regState_ExtraQueued
:
3988 rr
->uDNS_info
.state
= regState_Unregistered
;
3990 case regState_FetchingZoneData
:
3991 rr
->uDNS_info
.state
= regState_Cancelled
;
3992 return mStatus_NoError
;
3993 case regState_Refresh
:
3994 case regState_Pending
:
3995 case regState_UpdatePending
:
3996 rr
->uDNS_info
.state
= regState_DeregDeferred
;
3997 LogMsg("Deferring deregistration of record %##s until registration completes", rr
->resrec
.name
.c
);
3998 return mStatus_NoError
;
3999 case regState_Registered
:
4000 case regState_DeregPending
:
4002 case regState_DeregDeferred
:
4003 case regState_Cancelled
:
4004 LogMsg("Double deregistration of record %##s type %d",
4005 rr
->resrec
.name
.c
, rr
->resrec
.rrtype
);
4006 return mStatus_UnknownErr
;
4007 case regState_Unregistered
:
4008 LogMsg("Requested deregistration of unregistered record %##s type %d",
4009 rr
->resrec
.name
.c
, rr
->resrec
.rrtype
);
4010 return mStatus_UnknownErr
;
4011 case regState_NoTarget
:
4012 LogMsg("ERROR: uDNS_DeregisterRecord called for record %##s with bad state (regState_NoTarget)", rr
->resrec
.name
.c
);
4013 return mStatus_UnknownErr
;
4016 if (rr
->uDNS_info
.state
== regState_Unregistered
)
4018 // unlink and deliver memfree
4020 unlinkAR(&u
->RecordRegistrations
, rr
);
4021 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
4022 if (rr
->RecordCallback
) rr
->RecordCallback(m
, rr
, mStatus_MemFree
);
4023 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
4024 return mStatus_NoError
;
4027 if (n
) FreeNATInfo(m
, n
);
4028 rr
->uDNS_info
.NATinfo
= mDNSNULL
;
4030 SendRecordDeregistration(m
, rr
);
4031 return mStatus_NoError
;
4034 // register a service already in list with initialized state
4035 mDNSlocal mStatus
RegisterService(mDNS
*m
, ServiceRecordSet
*srs
)
4037 uDNS_RegInfo
*info
= &srs
->uDNS_info
;
4039 srs
->RR_SRV
.resrec
.rroriginalttl
= 3;
4040 srs
->RR_TXT
.resrec
.rroriginalttl
= 3;
4041 srs
->RR_PTR
.resrec
.rroriginalttl
= 3;
4043 info
->lease
= mDNStrue
;
4045 if (srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
.NotAnInteger
&& MapServicePort(m
))
4047 // !!!KRS if interface is already in NATState_Legacy, don't try NATPMP
4048 info
->state
= regState_NATMap
;
4049 StartNATPortMap(m
, srs
);
4050 return mStatus_NoError
;
4053 info
->state
= regState_FetchingZoneData
;
4054 return startGetZoneData(&srs
->RR_SRV
.resrec
.name
, m
, mDNStrue
, mDNSfalse
, serviceRegistrationCallback
, srs
);
4057 mDNSexport mStatus
uDNS_RegisterService(mDNS
*const m
, ServiceRecordSet
*srs
)
4059 // Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery
4060 ServiceRecordSet
**p
= &m
->uDNS_info
.ServiceRegistrations
;
4061 while (*p
&& *p
!= srs
) p
=&(*p
)->next
;
4062 if (*p
) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs
, srs
->RR_SRV
.resrec
.name
.c
); return(mStatus_AlreadyRegistered
); }
4063 ubzero(&srs
->uDNS_info
, sizeof(uDNS_RegInfo
));
4064 srs
->uDNS_info
.state
= regState_Unregistered
;
4066 srs
->next
= mDNSNULL
;
4067 return RegisterService(m
, srs
);
4070 mDNSlocal
void SendServiceDeregistration(mDNS
*m
, ServiceRecordSet
*srs
)
4072 uDNS_RegInfo
*info
= &srs
->uDNS_info
;
4073 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
4076 mDNSu8
*ptr
= msg
.data
;
4077 mDNSu8
*end
= (mDNSu8
*)&msg
+ sizeof(DNSMessage
);
4078 mStatus err
= mStatus_UnknownErr
;
4080 id
= newMessageID(u
);
4081 InitializeDNSMessage(&msg
.h
, id
, UpdateReqFlags
);
4084 ptr
= putZone(&msg
, ptr
, end
, &info
->zone
, mDNSOpaque16fromIntVal(srs
->RR_SRV
.resrec
.rrclass
));
4085 if (!ptr
) { LogMsg("ERROR: SendServiceDeregistration - putZone"); goto error
; }
4087 if (!(ptr
= putDeleteAllRRSets(&msg
, ptr
, &srs
->RR_SRV
.resrec
.name
))) goto error
; // this deletes SRV, TXT, and Extras
4088 if (!(ptr
= putDeletionRecord(&msg
, ptr
, &srs
->RR_PTR
.resrec
))) goto error
;
4090 err
= mDNSSendDNSMessage(m
, &msg
, ptr
, mDNSInterface_Any
, &info
->ns
, info
->port
, -1, GetAuthInfoForZone(u
, &info
->zone
));
4091 if (err
) { LogMsg("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %ld", err
); goto error
; }
4093 SetRecordRetry(m
, &srs
->RR_SRV
);
4094 info
->id
.NotAnInteger
= id
.NotAnInteger
;
4095 info
->state
= regState_DeregPending
;
4101 info
->state
= regState_Unregistered
;
4104 mDNSexport mStatus
uDNS_DeregisterService(mDNS
*const m
, ServiceRecordSet
*srs
)
4106 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
4107 NATTraversalInfo
*nat
= srs
->uDNS_info
.NATinfo
;
4108 AuthRecord
**r
= &u
->RecordRegistrations
;
4109 char *errmsg
= "Unknown State";
4111 // We "silently" unlink any Extras from our RecordRegistration list, as they are implicitly deleted from
4112 // the server when we delete all RRSets for this name
4115 if (SameDomainName(&srs
->RR_SRV
.resrec
.name
, &(*r
)->resrec
.name
)) *r
= (*r
)->next
;
4116 else r
= &(*r
)->next
;
4119 // don't re-register with a new target following deregistration
4120 srs
->uDNS_info
.LostTarget
= srs
->uDNS_info
.SRVUpdateDeferred
= mDNSfalse
;
4122 switch (srs
->uDNS_info
.state
)
4124 case regState_NATMap
:
4125 // we're in the middle of nat mapping. clear ptr from NAT info to RR, unlink and give memfree
4126 if (!nat
) LogMsg("uDNS_DeregisterRecord: no NAT info context");
4127 else { nat
->reg
.ServiceRegistration
= mDNSNULL
; FreeNATInfo(m
, nat
); }
4129 srs
->uDNS_info
.state
= regState_Unregistered
;
4130 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
4131 srs
->ServiceCallback(m
, srs
, mStatus_MemFree
);
4132 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
4133 return mStatus_NoError
;
4134 case regState_Unregistered
:
4135 errmsg
= "service not registered";
4137 case regState_FetchingZoneData
:
4138 // let the async op complete, then terminate
4139 srs
->uDNS_info
.state
= regState_Cancelled
;
4140 return mStatus_NoError
; // deliver memfree upon completion of async op
4141 case regState_Pending
:
4142 case regState_Refresh
:
4143 case regState_UpdatePending
:
4144 // deregister following completion of in-flight operation
4145 srs
->uDNS_info
.state
= regState_DeregDeferred
;
4146 return mStatus_NoError
;
4147 case regState_DeregPending
:
4148 case regState_DeregDeferred
:
4149 case regState_Cancelled
:
4150 debugf("Double deregistration of service %##s", srs
->RR_SRV
.resrec
.name
.c
);
4151 return mStatus_NoError
;
4152 case regState_NoTarget
:
4154 srs
->uDNS_info
.state
= regState_Unregistered
;
4155 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
4156 srs
->ServiceCallback(m
, srs
, mStatus_MemFree
);
4157 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
4158 return mStatus_NoError
;
4159 case regState_Registered
:
4160 if (nat
) DeleteNATPortMapping(m
, nat
, srs
);
4161 srs
->uDNS_info
.state
= regState_DeregPending
;
4162 SendServiceDeregistration(m
, srs
);
4163 return mStatus_NoError
;
4164 case regState_ExtraQueued
: // only for record registrations
4165 errmsg
= "bad state (regState_ExtraQueued)";
4170 LogMsg("Error, uDNS_DeregisterService: %s", errmsg
);
4171 return mStatus_BadReferenceErr
;
4174 // note that the RegInfo will be either for the record, or for the parent ServiceRecordSet
4175 mDNSlocal
void SendRecordUpdate(mDNS
*m
, AuthRecord
*rr
, uDNS_RegInfo
*info
)
4178 mDNSu8
*ptr
= msg
.data
;
4179 mDNSu8
*end
= (mDNSu8
*)&msg
+ sizeof(DNSMessage
);
4180 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
4182 mStatus err
= mStatus_UnknownErr
;
4184 rr
->uDNS_info
.UpdateQueued
= mDNSfalse
; // if this was queued, clear flag
4185 id
= newMessageID(u
);
4186 InitializeDNSMessage(&msg
.h
, id
, UpdateReqFlags
);
4187 info
->id
.NotAnInteger
= id
.NotAnInteger
;
4190 ptr
= putZone(&msg
, ptr
, end
, &info
->zone
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
4191 if (!ptr
) goto error
;
4193 // delete the original record
4194 ptr
= putDeletionRecord(&msg
, ptr
, &rr
->resrec
);
4195 if (!ptr
) goto error
;
4197 // change the rdata, add the new record
4198 SwapRData(m
, rr
, mDNSfalse
);
4199 ptr
= PutResourceRecordTTLJumbo(&msg
, ptr
, &msg
.h
.mDNS_numUpdates
, &rr
->resrec
, rr
->resrec
.rroriginalttl
);
4200 SwapRData(m
, rr
, mDNSfalse
); // swap rdata back to original in case we need to retransmit
4201 if (!ptr
) goto error
; // (rdata gets changed permanently on success)
4204 { ptr
= putUpdateLease(&msg
, ptr
, kLLQ_DefLease
); if (!ptr
) goto error
; }
4206 // don't report send errors - retransmission will occurr if necessary
4207 err
= mDNSSendDNSMessage(m
, &msg
, ptr
, mDNSInterface_Any
, &info
->ns
, info
->port
, -1, GetAuthInfoForZone(u
, &info
->zone
));
4208 if (err
) debugf("ERROR: sendRecordRegistration - mDNSSendDNSMessage - %ld", err
);
4210 //!!! Update this when we implement retransmission for services
4211 SetRecordRetry(m
, rr
);
4213 rr
->uDNS_info
.state
= regState_UpdatePending
;
4214 if (&rr
->uDNS_info
!= info
) info
->state
= regState_UpdatePending
; // set parent SRS
4218 LogMsg("ERROR: SendRecordUpdate. Error formatting update message.");
4219 info
->state
= regState_Registered
;
4222 mDNSexport mStatus
uDNS_AddRecordToService(mDNS
*const m
, ServiceRecordSet
*sr
, ExtraResourceRecord
*extra
)
4224 mStatus err
= mStatus_UnknownErr
;
4226 extra
->r
.resrec
.RecordType
= kDNSRecordTypeShared
; // don't want it to conflict with the service name
4227 extra
->r
.RecordCallback
= mDNSNULL
; // don't generate callbacks for extra RRs
4229 if (sr
->uDNS_info
.state
== regState_Registered
|| sr
->uDNS_info
.state
== regState_Refresh
)
4230 err
= uDNS_RegisterRecord(m
, &extra
->r
);
4233 err
= SetupRecordRegistration(m
, &extra
->r
);
4234 extra
->r
.uDNS_info
.state
= regState_ExtraQueued
;
4239 extra
->next
= sr
->Extras
;
4245 mDNSexport mStatus
uDNS_UpdateRecord(mDNS
*m
, AuthRecord
*rr
)
4247 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
4248 ServiceRecordSet
*sptr
, *parent
= mDNSNULL
;
4250 uDNS_RegInfo
*info
= mDNSNULL
;
4252 // find the record in registered service list
4253 for (sptr
= u
->ServiceRegistrations
; sptr
; sptr
= sptr
->next
)
4254 if (&sptr
->RR_TXT
== rr
) { info
= &sptr
->uDNS_info
; parent
= sptr
; break; }
4258 // record not part of a service - check individual record registrations
4259 for (rptr
= u
->RecordRegistrations
; rptr
; rptr
= rptr
->next
)
4260 if (rptr
== rr
) { info
= &rr
->uDNS_info
; break; }
4263 if (!info
) goto unreg_error
;
4265 // uDNS-private pointers so that mDNS.c layer doesn't nuke rdata of an in-flight update
4266 rr
->uDNS_info
.UpdateRData
= rr
->NewRData
;
4267 rr
->uDNS_info
.UpdateRDLen
= rr
->newrdlength
;
4268 rr
->uDNS_info
.UpdateRDCallback
= rr
->UpdateCallback
;
4269 rr
->NewRData
= mDNSNULL
;
4273 case regState_DeregPending
:
4274 case regState_DeregDeferred
:
4275 case regState_Cancelled
:
4276 case regState_Unregistered
:
4277 // not actively registered
4280 case regState_FetchingZoneData
:
4281 case regState_NATMap
:
4282 case regState_ExtraQueued
:
4283 // change rdata directly since it hasn't been sent yet
4284 SwapRData(m
, rr
, mDNStrue
);
4285 return mStatus_NoError
;
4287 case regState_Pending
:
4288 case regState_Refresh
:
4289 case regState_UpdatePending
:
4290 // registration in-flight. mark for update after service registration completes
4291 rr
->uDNS_info
.UpdateQueued
= mDNStrue
; // note that we mark the record's Queued flag, not its parent's
4292 return mStatus_NoError
;
4294 case regState_Registered
:
4295 SendRecordUpdate(m
, rr
, info
);
4296 return mStatus_NoError
;
4298 case regState_NoTarget
:
4299 LogMsg("Bad state (regState_NoTarget)"); return mStatus_UnknownErr
; // state for service records only
4303 LogMsg("Requested update of record %##s type %d, part of service not currently registered",
4304 rr
->resrec
.name
.c
, rr
->resrec
.rrtype
);
4305 return mStatus_Invalid
;
4309 // ***************************************************************************
4310 #if COMPILER_LIKES_PRAGMA_MARK
4311 #pragma mark - Periodic Execution Routines
4315 mDNSlocal mDNSs32
CheckNATMappings(mDNS
*m
, mDNSs32 timenow
)
4317 NATTraversalInfo
*ptr
, *cur
;
4320 ptr
= m
->uDNS_info
.NATTraversals
;
4321 nextevent
= timenow
+ MIN_UCAST_PERIODIC_EXEC
;
4327 if (cur
->retry
- timenow
< 0)
4329 if (cur
->state
== NATState_Established
) RefreshNATMapping(cur
, m
);
4330 else if (cur
->state
== NATState_Request
|| cur
->state
== NATState_Refresh
)
4332 if (cur
->ntries
>= NATMAP_MAX_TRIES
) cur
->ReceiveResponse(cur
, m
, mDNSNULL
, 0); // may invalidate "cur"
4333 else SendNATMsg(cur
, m
);
4336 else if (cur
->retry
- nextevent
< 0) nextevent
= cur
->retry
;
4341 mDNSlocal mDNSs32
CheckQueries(mDNS
*m
, mDNSs32 timenow
)
4344 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
4347 mDNSs32 nextevent
= timenow
+ MIN_UCAST_PERIODIC_EXEC
;
4351 uDNS_QuestionInfo
*info
;
4353 u
->CurrentQuery
= u
->ActiveQueries
;
4354 while (u
->CurrentQuery
)
4356 q
= u
->CurrentQuery
;
4357 info
= &q
->uDNS_info
;
4360 if (!info
->internal
&& ((!q
->LongLived
&& !info
->Answered
) || (llq
&& llq
->state
< LLQ_Established
)) &&
4361 info
->RestartTime
+ RESTART_GOODBYE_DELAY
- timenow
< 0)
4363 // if we've been spinning on restart setup, and we have known answers, give goodbyes (they may be re-added later)
4364 while (info
->knownAnswers
)
4366 CacheRecord
*cr
= info
->knownAnswers
;
4367 info
->knownAnswers
= info
->knownAnswers
->next
;
4369 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
4370 q
->QuestionCallback(m
, q
, &cr
->resrec
, mDNSfalse
);
4371 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
4373 if (q
!= u
->CurrentQuery
) { debugf("CheckQueries - question removed via callback."); break; }
4376 if (q
!= u
->CurrentQuery
) continue;
4378 if (q
->LongLived
&& llq
->state
!= LLQ_Poll
)
4380 if (llq
->state
>= LLQ_InitialRequest
&& llq
->state
<= LLQ_Established
)
4382 if (llq
->retry
- timenow
< 0)
4384 // sanity check to avoid packet flood bugs
4386 LogMsg("ERROR: retry timer not set for LLQ %##s in state %d", q
->qname
.c
, llq
->state
);
4387 else if (llq
->state
== LLQ_Established
|| llq
->state
== LLQ_Refresh
)
4388 sendLLQRefresh(m
, q
, llq
->origLease
);
4389 else if (llq
->state
== LLQ_InitialRequest
)
4390 startLLQHandshake(m
, llq
, mDNSfalse
);
4391 else if (llq
->state
== LLQ_SecondaryRequest
)
4392 sendChallengeResponse(m
, q
, mDNSNULL
);
4393 else if (llq
->state
== LLQ_Retry
)
4394 { llq
->ntries
= 0; startLLQHandshake(m
, llq
, mDNSfalse
); }
4396 else if (llq
->retry
- nextevent
< 0) nextevent
= llq
->retry
;
4401 sendtime
= q
->LastQTime
+ q
->ThisQInterval
;
4402 if (sendtime
- timenow
< 0)
4405 if (GetServerForName(&m
->uDNS_info
, &q
->qname
, &server
))
4407 err
= constructQueryMsg(&msg
, &end
, q
);
4408 if (err
) LogMsg("Error: uDNS_Idle - constructQueryMsg. Skipping question %##s", q
->qname
.c
);
4411 err
= mDNSSendDNSMessage(m
, &msg
, end
, mDNSInterface_Any
, &server
, UnicastDNSPort
, -1, mDNSNULL
);
4412 if (err
) { debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %ld", err
); } // surpress syslog messages if we have no network
4413 q
->LastQTime
= timenow
;
4414 if (q
->ThisQInterval
< MAX_UCAST_POLL_INTERVAL
) q
->ThisQInterval
= q
->ThisQInterval
* 2;
4418 else if (sendtime
- nextevent
< 0) nextevent
= sendtime
;
4420 u
->CurrentQuery
= u
->CurrentQuery
->next
;
4425 mDNSlocal mDNSs32
CheckRecordRegistrations(mDNS
*m
, mDNSs32 timenow
)
4428 uDNS_RegInfo
*rInfo
;
4429 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
4430 mDNSs32 nextevent
= timenow
+ MIN_UCAST_PERIODIC_EXEC
;
4432 //!!!KRS list should be pre-sorted by expiration
4433 for (rr
= u
->RecordRegistrations
; rr
; rr
= rr
->next
)
4435 rInfo
= &rr
->uDNS_info
;
4436 if (rInfo
->state
== regState_Pending
|| rInfo
->state
== regState_DeregPending
|| rInfo
->state
== regState_UpdatePending
|| rInfo
->state
== regState_DeregDeferred
|| rInfo
->state
== regState_Refresh
)
4438 if (rr
->LastAPTime
+ rr
->ThisAPInterval
- timenow
< 0)
4441 char *op
= "(unknown operation)";
4442 if (rInfo
->state
== regState_Pending
) op
= "registration";
4443 else if (rInfo
->state
== regState_DeregPending
) op
= "deregistration";
4444 else if (rInfo
->state
== regState_Refresh
) op
= "refresh";
4445 debugf("Retransmit record %s %##s", op
, rr
->resrec
.name
.c
);
4447 //LogMsg("Retransmit record %##s", rr->resrec.name.c);
4448 if (rInfo
->state
== regState_DeregPending
) SendRecordDeregistration(m
, rr
);
4449 else if (rInfo
->state
== regState_UpdatePending
) SendRecordUpdate(m
, rr
, rInfo
);
4450 else sendRecordRegistration(m
, rr
);
4452 if (rr
->LastAPTime
+ rr
->ThisAPInterval
- nextevent
< 0) nextevent
= rr
->LastAPTime
+ rr
->ThisAPInterval
;
4454 if (rInfo
->lease
&& rInfo
->state
== regState_Registered
&& rInfo
->expire
> 0)
4456 if (rInfo
->expire
- timenow
< 0)
4458 debugf("refreshing record %##s", rr
->resrec
.name
.c
);
4459 rInfo
->state
= regState_Refresh
;
4460 sendRecordRegistration(m
, rr
);
4462 if (rInfo
->expire
- nextevent
< 0) nextevent
= rInfo
->expire
;
4468 mDNSlocal mDNSs32
CheckServiceRegistrations(mDNS
*m
, mDNSs32 timenow
)
4470 ServiceRecordSet
*s
= m
->uDNS_info
.ServiceRegistrations
;
4471 uDNS_RegInfo
*rInfo
;
4472 mDNSs32 nextevent
= timenow
+ MIN_UCAST_PERIODIC_EXEC
;
4474 // Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery
4477 ServiceRecordSet
*srs
= s
;
4478 // NOTE: Must advance s here -- SendServiceDeregistration may delete the object we're looking at,
4479 // and then if we tried to do srs = srs->next at the end we'd be referencing a dead object
4482 rInfo
= &srs
->uDNS_info
;
4483 if (rInfo
->state
== regState_Pending
|| rInfo
->state
== regState_DeregPending
|| rInfo
->state
== regState_DeregDeferred
|| rInfo
->state
== regState_Refresh
)
4485 if (srs
->RR_SRV
.LastAPTime
+ srs
->RR_SRV
.ThisAPInterval
- timenow
< 0)
4488 char *op
= "unknown";
4489 if (rInfo
->state
== regState_Pending
) op
= "registration";
4490 else if (rInfo
->state
== regState_DeregPending
) op
= "deregistration";
4491 else if (rInfo
->state
== regState_Refresh
) op
= "refresh";
4492 debugf("Retransmit service %s %##s", op
, srs
->RR_SRV
.resrec
.name
.c
);
4494 if (rInfo
->state
== regState_DeregPending
) { SendServiceDeregistration(m
, srs
); continue; }
4495 else SendServiceRegistration (m
, srs
);
4497 if (nextevent
- srs
->RR_SRV
.LastAPTime
+ srs
->RR_SRV
.ThisAPInterval
> 0)
4498 nextevent
= srs
->RR_SRV
.LastAPTime
+ srs
->RR_SRV
.ThisAPInterval
;
4501 if (rInfo
->lease
&& rInfo
->state
== regState_Registered
&& rInfo
->expire
> 0)
4503 if (rInfo
->expire
- timenow
< 0)
4505 debugf("refreshing service %##s", srs
->RR_SRV
.resrec
.name
.c
);
4506 rInfo
->state
= regState_Refresh
;
4507 SendServiceRegistration(m
, srs
);
4509 if (rInfo
->expire
- nextevent
< 0) nextevent
= rInfo
->expire
;
4515 mDNSexport
void uDNS_Execute(mDNS
*const m
)
4517 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
4518 mDNSs32 nexte
, timenow
= mDNSPlatformTimeNow(m
);
4520 u
->nextevent
= timenow
+ MIN_UCAST_PERIODIC_EXEC
;
4522 nexte
= CheckNATMappings(m
, timenow
);
4523 if (nexte
- u
->nextevent
< 0) u
->nextevent
= nexte
;
4525 nexte
= CheckQueries(m
, timenow
);
4526 if (nexte
- u
->nextevent
< 0) u
->nextevent
= nexte
;
4528 nexte
= CheckRecordRegistrations(m
, timenow
);
4529 if (nexte
- u
->nextevent
< 0) u
->nextevent
= nexte
;
4531 nexte
= CheckServiceRegistrations(m
, timenow
);
4532 if (nexte
- u
->nextevent
< 0) u
->nextevent
= nexte
;
4536 // ***************************************************************************
4537 #if COMPILER_LIKES_PRAGMA_MARK
4538 #pragma mark - Startup, Shutdown, and Sleep
4541 // DeregisterActive causes active LLQs to be removed from the server, e.g. before sleep. Pass false
4542 // following a location change, as the server will reject deletions from a source address different
4543 // from the address on which the LLQ was created.
4545 mDNSlocal
void SuspendLLQs(mDNS
*m
, mDNSBool DeregisterActive
)
4549 for (q
= m
->uDNS_info
.ActiveQueries
; q
; q
= q
->next
)
4551 llq
= q
->uDNS_info
.llq
;
4552 if (q
->LongLived
&& llq
)
4554 if (llq
->state
== LLQ_GetZoneInfo
)
4556 debugf("Marking %##s suspend-deferred", q
->qname
.c
);
4557 llq
->state
= LLQ_SuspendDeferred
; // suspend once we're done getting zone info
4559 else if (llq
->state
< LLQ_Suspended
)
4561 if (DeregisterActive
&& (llq
->state
== LLQ_Established
|| llq
->state
== LLQ_Refresh
))
4562 { debugf("Deleting LLQ %##s", q
->qname
.c
); sendLLQRefresh(m
, q
, 0); }
4563 debugf("Marking %##s suspended", q
->qname
.c
);
4564 llq
->state
= LLQ_Suspended
;
4567 else if (llq
->state
== LLQ_Poll
) { debugf("Marking %##s suspended-poll", q
->qname
.c
); llq
->state
= LLQ_SuspendedPoll
; }
4568 if (llq
->NATMap
) llq
->NATMap
= mDNSfalse
; // may not need nat mapping if we restart with new route
4571 CheckForUnreferencedLLQMapping(m
);
4574 mDNSlocal
void RestartQueries(mDNS
*m
)
4576 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
4579 mDNSs32 timenow
= mDNSPlatformTimeNow(m
);
4581 u
->CurrentQuery
= u
->ActiveQueries
;
4582 while (u
->CurrentQuery
)
4584 q
= u
->CurrentQuery
;
4585 u
->CurrentQuery
= u
->CurrentQuery
->next
;
4586 llqInfo
= q
->uDNS_info
.llq
;
4587 q
->uDNS_info
.RestartTime
= timenow
;
4588 q
->uDNS_info
.Answered
= mDNSfalse
;
4591 if (!llqInfo
) { LogMsg("Error: RestartQueries - %##s long-lived with NULL info", q
->qname
.c
); continue; }
4592 if (llqInfo
->state
== LLQ_Suspended
|| llqInfo
->state
== LLQ_NatMapWait
)
4594 llqInfo
->ntries
= -1;
4595 llqInfo
->deriveRemovesOnResume
= mDNStrue
;
4596 startLLQHandshake(m
, llqInfo
, mDNStrue
); // we set defer to true since several events that may generate restarts often arrive in rapid succession, and this cuts unnecessary packets
4598 else if (llqInfo
->state
== LLQ_SuspendDeferred
)
4599 llqInfo
->state
= LLQ_GetZoneInfo
; // we never finished getting zone data - proceed as usual
4600 else if (llqInfo
->state
== LLQ_SuspendedPoll
)
4602 // if we were polling, we may have had bad zone data due to firewall, etc. - refetch
4603 llqInfo
->ntries
= 0;
4604 llqInfo
->deriveRemovesOnResume
= mDNStrue
;
4605 llqInfo
->state
= LLQ_GetZoneInfo
;
4606 startGetZoneData(&q
->qname
, m
, mDNSfalse
, mDNStrue
, startLLQHandshakeCallback
, llqInfo
);
4609 else { q
->LastQTime
= timenow
; q
->ThisQInterval
= INIT_UCAST_POLL_INTERVAL
; } // trigger poll in 1 second (to reduce packet rate when restarts come in rapid succession)
4613 mDNSexport
void mDNS_UpdateLLQs(mDNS
*m
)
4615 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
4620 NATTraversalInfo
*nat
= u
->LLQNatInfo
;
4621 u
->LLQNatInfo
= mDNSNULL
;
4622 DeleteNATPortMapping(m
, nat
, mDNSNULL
);
4624 SuspendLLQs(m
, mDNStrue
);
4629 // simplest sleep logic - rather than having sleep states that must be dealt with explicitly in all parts of
4630 // the code, we simply send a deregistration, and put the service in Refresh state, with a timeout far enough
4631 // in the future that we'll sleep (or the sleep will be cancelled) before it is retransmitted. Then to wake,
4632 // we just move up the timers.
4636 mDNSlocal
void SleepRecordRegistrations(mDNS
*m
)
4639 AuthRecord
*rr
= m
->uDNS_info
.RecordRegistrations
;
4640 mDNSs32 timenow
= mDNSPlatformTimeNow(m
);
4644 if (rr
->uDNS_info
.state
== regState_Registered
||
4645 rr
->uDNS_info
.state
== regState_Refresh
)
4647 mDNSu8
*ptr
= msg
.data
, *end
= (mDNSu8
*)&msg
+ sizeof(DNSMessage
);
4648 InitializeDNSMessage(&msg
.h
, newMessageID(&m
->uDNS_info
), UpdateReqFlags
);
4650 // construct deletion update
4651 ptr
= putZone(&msg
, ptr
, end
, &rr
->uDNS_info
.zone
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
4652 if (!ptr
) { LogMsg("Error: SleepRecordRegistrations - could not put zone"); return; }
4653 ptr
= putDeletionRecord(&msg
, ptr
, &rr
->resrec
);
4654 if (!ptr
) { LogMsg("Error: SleepRecordRegistrations - could not put deletion record"); return; }
4656 mDNSSendDNSMessage(m
, &msg
, ptr
, mDNSInterface_Any
, &rr
->uDNS_info
.ns
, rr
->uDNS_info
.port
, -1, GetAuthInfoForZone(&m
->uDNS_info
, &rr
->uDNS_info
.zone
));
4657 rr
->uDNS_info
.state
= regState_Refresh
;
4658 rr
->LastAPTime
= timenow
;
4659 rr
->ThisAPInterval
= 300 * mDNSPlatformOneSecond
;
4665 mDNSlocal
void WakeRecordRegistrations(mDNS
*m
)
4667 mDNSs32 timenow
= mDNSPlatformTimeNow(m
);
4668 AuthRecord
*rr
= m
->uDNS_info
.RecordRegistrations
;
4672 if (rr
->uDNS_info
.state
== regState_Refresh
)
4674 // trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets)
4675 rr
->LastAPTime
= timenow
;
4676 rr
->ThisAPInterval
= INIT_UCAST_POLL_INTERVAL
;
4682 mDNSlocal
void SleepServiceRegistrations(mDNS
*m
)
4684 mDNSs32 timenow
= mDNSPlatformTimeNow(m
);
4685 ServiceRecordSet
*srs
= m
->uDNS_info
.ServiceRegistrations
;
4688 if (srs
->uDNS_info
.state
== regState_Registered
||
4689 srs
->uDNS_info
.state
== regState_Refresh
)
4691 mDNSOpaque16 origid
= srs
->uDNS_info
.id
;
4692 srs
->uDNS_info
.state
= regState_DeregPending
; // state expected by SendDereg()
4693 SendServiceDeregistration(m
, srs
);
4694 srs
->uDNS_info
.id
= origid
;
4695 srs
->uDNS_info
.state
= regState_Refresh
;
4696 srs
->RR_SRV
.LastAPTime
= timenow
;
4697 srs
->RR_SRV
.ThisAPInterval
= 300 * mDNSPlatformOneSecond
;
4703 mDNSlocal
void WakeServiceRegistrations(mDNS
*m
)
4705 mDNSs32 timenow
= mDNSPlatformTimeNow(m
);
4706 ServiceRecordSet
*srs
= m
->uDNS_info
.ServiceRegistrations
;
4709 if (srs
->uDNS_info
.state
== regState_Refresh
)
4711 // trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets)
4712 srs
->RR_SRV
.LastAPTime
= timenow
;
4713 srs
->RR_SRV
.ThisAPInterval
= INIT_UCAST_POLL_INTERVAL
;
4719 mDNSexport
void uDNS_Init(mDNS
*const m
)
4721 mDNSPlatformMemZero(&m
->uDNS_info
, sizeof(uDNS_GlobalInfo
));
4722 m
->uDNS_info
.nextevent
= m
->timenow_last
+ 0x78000000;
4725 mDNSexport
void uDNS_Sleep(mDNS
*m
)
4727 SuspendLLQs(m
, mDNStrue
);
4728 SleepServiceRegistrations(m
);
4729 SleepRecordRegistrations(m
);
4732 mDNSexport
void uDNS_Wake(mDNS
*m
)
4735 WakeServiceRegistrations(m
);
4736 WakeRecordRegistrations(m
);