]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSCore/uDNS.c
mDNSResponder-87.tar.gz
[apple/mdnsresponder.git] / mDNSCore / uDNS.c
1 /*
2 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
25 $Log: uDNS.c,v $
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)
28
29 Revision 1.150 2004/12/13 20:42:41 ksekar
30 Fixed LogMsg
31
32 Revision 1.149 2004/12/13 18:10:03 ksekar
33 Fixed LogMsg
34
35 Revision 1.148 2004/12/13 01:18:04 ksekar
36 Fixed unused variable warning for non-debug builds
37
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
40
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
43
44 Revision 1.145 2004/12/12 22:56:29 ksekar
45 <rdar://problem/3668508> Need to properly handle duplicate long-lived queries
46
47 Revision 1.144 2004/12/11 20:55:29 ksekar
48 <rdar://problem/3916479> Clean up registration state machines
49
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
52
53 Revision 1.142 2004/12/08 02:03:31 ksekar
54 <rdar://problem/3865124> Looping on NAT Traversal error - check for
55 NULL RR on error
56
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.)
60
61 Revision 1.140 2004/12/06 21:15:22 ksekar
62 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
63
64 Revision 1.139 2004/12/06 19:08:03 cheshire
65 Add clarifying comment -- CountLabels() excludes the final root label.
66
67 Revision 1.138 2004/12/06 01:45:54 ksekar
68 Correct wording in LogMsg
69
70 Revision 1.137 2004/12/03 20:40:35 ksekar
71 <rdar://problem/3865124> Looping on NAT Traversal error
72
73 Revision 1.136 2004/12/03 07:20:50 ksekar
74 <rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
75
76 Revision 1.135 2004/12/03 05:18:33 ksekar
77 <rdar://problem/3810596> mDNSResponder needs to return more specific TSIG errors
78
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
81
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
84
85 Revision 1.132 2004/12/01 20:57:19 ksekar
86 <rdar://problem/3873921> Wide Area Rendezvous must be split-DNS aware
87
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
91
92 Revision 1.130 2004/12/01 02:43:23 cheshire
93 Don't call StatusCallback if function pointer is null
94
95 Revision 1.129 2004/11/30 23:51:06 cheshire
96 Remove double semicolons
97
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
100
101 Revision 1.127 2004/11/25 01:41:36 ksekar
102 Changed unnecessary LogMsgs to debugfs
103
104 Revision 1.126 2004/11/23 23:54:17 ksekar
105 <rdar://problem/3890318> Wide-Area DNSServiceRegisterRecord() failures
106 can crash mDNSResponder
107
108 Revision 1.125 2004/11/23 04:16:48 cheshire
109 Removed receiveMsg() routine.
110
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.
114
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
117
118 Revision 1.122 2004/11/19 18:00:34 ksekar
119 <rdar://problem/3682646> Security: use random ID for one-shot unicast queries
120
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
123
124 Revision 1.120 2004/11/19 02:32:43 ksekar
125 <rdar://problem/3682608> Wide-Area Rendezvous Security: Add LLQ-ID to events
126
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
129
130 Revision 1.118 2004/11/18 22:58:37 ksekar
131 Removed old comment.
132
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>
135
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>.
138
139 Revision 1.xxx 2004/11/17 00:45:28 ksekar
140 <rdar://problem/3880688> Result of putUpdateLease not error-checked
141
142 Revision 1.116 2004/11/16 01:41:47 ksekar
143 Fixed typo in debugf
144
145 Revision 1.115 2004/11/15 20:09:24 ksekar
146 <rdar://problem/3719050> Wide Area support for Add/Remove record
147
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
151
152 Revision 1.113 2004/11/13 02:29:52 ksekar
153 <rdar://problem/3878386> LLQ refreshes not reliable
154
155 Revision 1.112 2004/11/11 20:45:14 ksekar
156 <rdar://problem/3876052> self-conflict test not compatible with some BIND servers
157
158 Revision 1.111 2004/11/11 20:14:55 ksekar
159 <rdar://problem/3719574> Wide-Area registrations not deregistered on sleep
160
161 Revision 1.110 2004/11/10 23:53:53 ksekar
162 Remove no longer relevant comment
163
164 Revision 1.109 2004/11/10 20:40:53 ksekar
165 <rdar://problem/3868216> LLQ mobility fragile on non-primary interface
166
167 Revision 1.108 2004/11/01 20:36:16 ksekar
168 <rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
169
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
172
173 Revision 1.106 2004/10/26 03:52:03 cheshire
174 Update checkin comments
175
176 Revision 1.105 2004/10/26 01:15:06 cheshire
177 Use "#if 0" instead of commenting out code
178
179 Revision 1.104 2004/10/25 21:41:38 ksekar
180 <rdar://problem/3852958> wide-area name conflicts can cause crash
181
182 Revision 1.103 2004/10/25 19:30:52 ksekar
183 <rdar://problem/3827956> Simplify dynamic host name structures
184
185 Revision 1.102 2004/10/23 01:16:00 cheshire
186 <rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
187
188 Revision 1.101 2004/10/22 20:52:07 ksekar
189 <rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
190
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
194
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
199
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
202
203 Revision 1.97 2004/10/15 23:00:18 ksekar
204 <rdar://problem/3799242> Need to update LLQs on location changes
205
206 Revision 1.96 2004/10/12 23:30:44 ksekar
207 <rdar://problem/3609944> mDNSResponder needs to follow CNAME referrals
208
209 Revision 1.95 2004/10/12 03:15:09 ksekar
210 <rdar://problem/3835612> mDNS_StartQuery shouldn't return transient no-server error
211
212 Revision 1.94 2004/10/12 02:49:20 ksekar
213 <rdar://problem/3831228> Clean up LLQ sleep/wake, error handling
214
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
217
218 Revision 1.92 2004/10/08 03:54:35 ksekar
219 <rdar://problem/3831802> Refine unicast polling intervals
220
221 Revision 1.91 2004/09/30 17:45:34 ksekar
222 <rdar://problem/3821119> lots of log messages: mDNS_SetPrimaryIP: IP address unchanged
223
224 Revision 1.90 2004/09/25 00:22:13 ksekar
225 <rdar://problem/3815534> Crash in uDNS_RegisterService
226
227 Revision 1.89 2004/09/24 19:14:53 cheshire
228 Remove unused "extern mDNS mDNSStorage"
229
230 Revision 1.88 2004/09/23 20:48:15 ksekar
231 Clarify retransmission debugf messages.
232
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
235
236 Revision 1.86 2004/09/21 23:40:11 ksekar
237 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
238
239 Revision 1.85 2004/09/21 22:38:27 ksekar
240 <rdar://problem/3810286> PrimaryIP type uninitialized
241
242 Revision 1.84 2004/09/18 00:30:39 cheshire
243 <rdar://problem/3806643> Infinite loop in CheckServiceRegistrations
244
245 Revision 1.83 2004/09/17 00:31:51 cheshire
246 For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
247
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
251
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
255
256 Revision 1.80 2004/09/16 01:58:21 cheshire
257 Fix compiler warnings
258
259 Revision 1.79 2004/09/16 00:24:48 cheshire
260 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
261
262 Revision 1.78 2004/09/15 01:16:57 ksekar
263 <rdar://problem/3797598> mDNSResponder printing too many messages
264
265 Revision 1.77 2004/09/14 23:27:47 cheshire
266 Fix compile errors
267
268 Revision 1.76 2004/09/14 22:22:00 ksekar
269 <rdar://problem/3800920> Legacy browses broken against some BIND versions
270
271 Revision 1.75 2004/09/03 19:23:05 ksekar
272 <rdar://problem/3788460>: Need retransmission mechanism for wide-area service registrations
273
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.
277
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
280
281 Revision 1.72 2004/09/01 03:59:29 ksekar
282 <rdar://problem/3783453>: Conditionally compile out uDNS code on Windows
283
284 Revision 1.71 2004/08/27 17:51:53 ksekar
285 Replaced unnecessary LogMsg with debugf.
286
287 Revision 1.70 2004/08/25 00:37:27 ksekar
288 <rdar://problem/3774635>: Cleanup DynDNS hostname registration code
289
290 Revision 1.69 2004/08/18 17:35:41 ksekar
291 <rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
292
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
298
299 Revision 1.67 2004/08/13 23:46:58 cheshire
300 "asyncronous" -> "asynchronous"
301
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
305
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.)
310
311 Revision 1.64 2004/08/13 23:01:05 cheshire
312 Use platform-independent mDNSNULL instead of NULL
313
314 Revision 1.63 2004/08/12 00:32:36 ksekar
315 <rdar://problem/3759567>: LLQ Refreshes never terminate if unanswered
316
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
320
321 Revision 1.61 2004/07/30 17:40:06 ksekar
322 <rdar://problem/3739115>: TXT Record updates not available for wide-area services
323
324 Revision 1.60 2004/07/29 19:40:05 ksekar
325 NATPMP Support - minor fixes and cleanup
326
327 Revision 1.59 2004/07/29 19:27:15 ksekar
328 NATPMP Support - minor fixes and cleanup
329
330 Revision 1.58 2004/07/27 07:35:38 shersche
331 fix syntax error, variables declared in the middle of a block
332
333 Revision 1.57 2004/07/26 22:49:30 ksekar
334 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
335
336 Revision 1.56 2004/07/26 19:14:44 ksekar
337 <rdar://problem/3737814>: 8A210: mDNSResponder crashed in startLLQHandshakeCallback
338
339 Revision 1.55 2004/07/15 19:01:33 ksekar
340 <rdar://problem/3681029>: Check for incorrect time comparisons
341
342 Revision 1.54 2004/06/22 02:10:53 ksekar
343 <rdar://problem/3705433>: Lighthouse failure causes packet flood to DNS
344
345 Revision 1.53 2004/06/17 20:49:09 ksekar
346 <rdar://problem/3690436>: mDNSResponder crash while location cycling
347
348 Revision 1.52 2004/06/17 01:13:11 ksekar
349 <rdar://problem/3696616>: polling interval too short
350
351 Revision 1.51 2004/06/10 04:36:44 cheshire
352 Fix compiler warning
353
354 Revision 1.50 2004/06/10 00:55:13 ksekar
355 <rdar://problem/3686213>: crash on network reconnect
356
357 Revision 1.49 2004/06/10 00:10:50 ksekar
358 <rdar://problem/3686174>: Infinite Loop in uDNS_Execute()
359
360 Revision 1.48 2004/06/09 20:03:37 ksekar
361 <rdar://problem/3686163>: Incorrect copying of resource record in deregistration
362
363 Revision 1.47 2004/06/09 03:48:28 ksekar
364 <rdar://problem/3685226>: nameserver address fails with prod. Lighthouse server
365
366 Revision 1.46 2004/06/09 01:44:30 ksekar
367 <rdar://problem/3681378> reworked Cache Record copy code
368
369 Revision 1.45 2004/06/08 18:54:47 ksekar
370 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
371
372 Revision 1.44 2004/06/05 00:33:51 cheshire
373 <rdar://problem/3681029>: Check for incorrect time comparisons
374
375 Revision 1.43 2004/06/05 00:14:44 cheshire
376 Fix signed/unsigned and other compiler warnings
377
378 Revision 1.42 2004/06/04 22:36:16 ksekar
379 Properly set u->nextevent in uDNS_Execute
380
381 Revision 1.41 2004/06/04 08:58:29 ksekar
382 <rdar://problem/3668624>: Keychain integration for secure dynamic update
383
384 Revision 1.40 2004/06/03 03:09:58 ksekar
385 <rdar://problem/3668626>: Garbage Collection for Dynamic Updates
386
387 Revision 1.39 2004/06/01 23:46:50 ksekar
388 <rdar://problem/3675149>: DynDNS: dynamically look up LLQ/Update ports
389
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
393
394 Revision 1.37 2004/05/28 23:42:37 ksekar
395 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
396
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
399
400 Revision 1.35 2004/05/07 23:01:04 ksekar
401 Cleaned up list traversal in deriveGoodbyes - removed unnecessary
402 conditional assignment.
403
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.
407
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.
412
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.
416
417 Revision 1.31 2004/05/05 17:05:02 ksekar
418 Use LargeCacheRecord structs when pulling records off packets
419
420 Revision 1.30 2004/04/16 21:33:27 ksekar
421 Fixed bug in processing GetZoneData responses that do not use BIND formatting.
422
423 Revision 1.29 2004/04/15 20:03:13 ksekar
424 Clarified log message when pulling bad resource records off packet.
425
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.
429
430 Revision 1.27 2004/04/14 23:09:28 ksekar
431 Support for TSIG signed dynamic updates.
432
433 Revision 1.26 2004/04/14 19:36:05 ksekar
434 Fixed memory corruption error in deriveGoodbyes.
435
436 Revision 1.25 2004/04/14 04:07:11 ksekar
437 Fixed crash in IsActiveUnicastQuery(). Removed redundant checks in routine.
438
439 Revision 1.24 2004/04/08 09:41:40 bradley
440 Added const to AuthRecord in deadvertiseIfCallback to match callback typedef.
441
442 Revision 1.23 2004/03/24 00:29:45 ksekar
443 Make it safe to call StopQuery in a unicast question callback
444
445 Revision 1.22 2004/03/19 10:11:09 bradley
446 Added AuthRecord * cast from umalloc for C++ builds.
447
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++.
451
452 Revision 1.20 2004/03/13 02:07:26 ksekar
453 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
454
455 Revision 1.19 2004/03/13 01:57:33 ksekar
456 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
457
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.
461
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
464
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
467
468 Revision 1.15 2004/02/10 03:02:46 cheshire
469 Fix compiler warning
470
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)
474
475 Revision 1.13 2004/02/03 22:15:01 ksekar
476 Fixed nameToAddr error check: don't abort state machine on nxdomain error.
477
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.
483
484 Revision 1.11 2004/01/30 02:12:30 ksekar
485 Changed uDNS_ReceiveMsg() to correctly return void.
486
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.
493
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.
497
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.
502
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
505
506 Revision 1.6 2004/01/24 23:47:17 cheshire
507 Use mDNSOpaque16fromIntVal() instead of shifting and masking
508
509 Revision 1.5 2004/01/24 04:59:15 cheshire
510 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
511
512 Revision 1.4 2004/01/24 04:19:26 cheshire
513 Restore overwritten checkin 1.2
514
515 Revision 1.3 2004/01/23 23:23:15 ksekar
516 Added TCP support for truncated unicast messages.
517
518 Revision 1.2 2004/01/22 03:48:41 cheshire
519 Make sure uDNS client doesn't accidentally use query ID zero
520
521 Revision 1.1 2003/12/13 03:05:27 ksekar
522 <rdar://problem/3192548>: DynDNS: Unicast query of service records
523
524 */
525
526 #include "uDNS.h"
527
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)
535 #endif
536
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
541
542 // Asynchronous operation types
543
544 typedef enum
545 {
546 zoneDataResult
547 // other async. operation names go here
548 } AsyncOpResultType;
549
550 typedef struct
551 {
552 domainname zoneName;
553 mDNSAddr primaryAddr;
554 mDNSu16 zoneClass;
555 mDNSIPPort llqPort;
556 mDNSIPPort updatePort;
557 } zoneData_t;
558
559 // other async. result struct defs go here
560
561 typedef struct
562 {
563 AsyncOpResultType type;
564 zoneData_t zoneData;
565 // other async result structs go here
566 } AsyncOpResult;
567
568 typedef void AsyncOpCallback(mStatus err, mDNS *const m, void *info, const AsyncOpResult *result);
569
570
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.)
576
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);
590
591 // ***************************************************************************
592 #if COMPILER_LIKES_PRAGMA_MARK
593 #pragma mark - Temporary workaround
594 #endif
595
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
601
602 mDNSlocal mDNSs32 mDNSPlatformTimeNow(mDNS *m)
603 {
604 if (m->mDNS_busy && m->timenow) return(m->timenow);
605 LogMsg("ERROR: uDNS.c code executing without holding main mDNS lock");
606
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:
609 // *(long*)0=0;
610
611 return(mDNS_TimeNow(m));
612 }
613
614 // ***************************************************************************
615 #if COMPILER_LIKES_PRAGMA_MARK
616 #pragma mark - General Utility Functions
617 #endif
618
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)
622 {
623 int count = 0;
624 const mDNSu8 *ptr;
625
626 for (ptr = d->c; *ptr; ptr = ptr + ptr[0] + 1) count++;
627 return count;
628 }
629
630 mDNSlocal mDNSOpaque16 newMessageID(uDNS_GlobalInfo *u)
631 {
632 static mDNSBool randomized = mDNSfalse;
633
634 if (!randomized) { u->NextMessageID = mDNSRandom(~0); randomized = mDNStrue; }
635 return mDNSOpaque16fromIntVal(u->NextMessageID++);
636 }
637
638 // unlink an AuthRecord from a linked list
639 mDNSlocal mStatus unlinkAR(AuthRecord **list, AuthRecord *const rr)
640 {
641 AuthRecord *rptr, *prev = mDNSNULL;
642
643 for (rptr = *list; rptr; rptr = rptr->next)
644 {
645 if (rptr == rr)
646 {
647 if (prev) prev->next = rptr->next;
648 else *list = rptr->next;
649 rptr->next = mDNSNULL;
650 return mStatus_NoError;
651 }
652 prev = rptr;
653 }
654 LogMsg("ERROR: unlinkAR - no such active record");
655 return mStatus_UnknownErr;
656 }
657
658 mDNSlocal void unlinkSRS(uDNS_GlobalInfo *u, ServiceRecordSet *srs)
659 {
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");
664 }
665
666 mDNSlocal void LinkActiveQuestion(uDNS_GlobalInfo *u, DNSQuestion *q)
667 {
668 if (uDNS_IsActiveQuery(q, u))
669 { LogMsg("LinkActiveQuestion - %##s (%d) already in list!", q->qname.c, q->qtype); return; }
670
671 q->next = u->ActiveQueries;
672 u->ActiveQueries = q;
673 }
674
675 mDNSlocal void SwapRData(mDNS *m, AuthRecord *rr, mDNSBool DeallocOld)
676 {
677 RData *oldrd = rr->resrec.rdata;
678 mDNSu16 oldrdlen = rr->resrec.rdlength;
679
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);
682 if (DeallocOld)
683 {
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
686 }
687 else
688 {
689 rr->uDNS_info.UpdateRData = oldrd;
690 rr->uDNS_info.UpdateRDLen = oldrdlen;
691 }
692 }
693
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)
697 {
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; }
702 }
703
704
705 // ***************************************************************************
706 #if COMPILER_LIKES_PRAGMA_MARK
707 #pragma mark - Name Server List Management
708 #endif
709
710 mDNSexport void mDNS_AddDNSServer(mDNS *const m, const mDNSAddr *addr, const domainname *d)
711 {
712 uDNS_GlobalInfo *u = &m->uDNS_info;
713 DNSServer *s, **p = &u->Servers;
714
715 mDNS_Lock(m);
716 if (!d) d = (domainname *)"";
717
718 while (*p) // Check if we already have this {server,domain} pair registered
719 {
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);
722 p=&(*p)->next;
723 }
724
725 // allocate, add to list
726 s = umalloc(sizeof(*s));
727 if (!s) { LogMsg("Error: mDNS_AddDNSServer - malloc"); goto end; }
728 s->addr = *addr;
729 AssignDomainName(s->domain, *d);
730 s->next = mDNSNULL;
731 *p = s;
732
733 end:
734 mDNS_Unlock(m);
735 }
736
737 mDNSexport void mDNS_DeleteDNSServers(mDNS *const m)
738 {
739 DNSServer *s;
740 mDNS_Lock(m);
741
742 s = m->uDNS_info.Servers;
743 m->uDNS_info.Servers = mDNSNULL;
744 while (s)
745 {
746 DNSServer *tmp = s;
747 s = s->next;
748 ufree(tmp);
749 }
750
751 mDNS_Unlock(m);
752 }
753
754 // ***************************************************************************
755 #if COMPILER_LIKES_PRAGMA_MARK
756 #pragma mark - authorization management
757 #endif
758
759 mDNSlocal uDNS_AuthInfo *GetAuthInfoForZone(const uDNS_GlobalInfo *u, const domainname *zone)
760 {
761 uDNS_AuthInfo *ptr;
762 while (zone->c[0])
763 {
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]);
767 }
768 return mDNSNULL;
769 }
770
771 mDNSlocal void DeleteAuthInfoForZone(uDNS_GlobalInfo *u, const domainname *zone)
772 {
773 uDNS_AuthInfo *ptr, *prev = mDNSNULL;
774
775 for (ptr = u->AuthInfoList; ptr; ptr = ptr->next)
776 {
777 if (SameDomainName(&ptr->zone, zone))
778 {
779 if (prev) prev->next = ptr->next;
780 else u->AuthInfoList = ptr->next;
781 ufree(ptr);
782 return;
783 }
784 prev = ptr;
785 }
786 }
787
788 mDNSexport mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const domainname *key, const mDNSu8 *sharedSecret, mDNSu32 ssLen, mDNSBool base64)
789 {
790 uDNS_AuthInfo *info;
791 mDNSu8 keybuf[1024];
792 mDNSs32 keylen;
793 uDNS_GlobalInfo *u = &m->uDNS_info;
794 mStatus status = mStatus_NoError;
795
796 mDNS_Lock(m);
797
798 if (GetAuthInfoForZone(u, zone)) DeleteAuthInfoForZone(u, zone);
799 if (!key) goto exit;
800
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);
806
807 if (base64)
808 {
809 keylen = DNSDigest_Base64ToBin((const char*)sharedSecret, keybuf, 1024);
810 if (keylen < 0)
811 {
812 LogMsg("ERROR: mDNS_UpdateDomainRequiresAuthentication - could not convert shared secret from base64");
813 ufree(info);
814 status = mStatus_UnknownErr;
815 goto exit;
816 }
817 DNSDigest_ConstructHMACKey(info, keybuf, (mDNSu32)keylen);
818 }
819 else DNSDigest_ConstructHMACKey(info, sharedSecret, ssLen);
820
821 // link into list
822 info->next = m->uDNS_info.AuthInfoList;
823 m->uDNS_info.AuthInfoList = info;
824 exit:
825 mDNS_Unlock(m);
826 return status;
827 }
828
829 // ***************************************************************************
830 #if COMPILER_LIKES_PRAGMA_MARK
831 #pragma mark - NAT Traversal
832 #endif
833
834 mDNSlocal mDNSBool MapServicePort(mDNS *m)
835 {
836 uDNS_HostnameInfo *i;
837
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;
841
842 return mDNSfalse;
843 }
844
845 mDNSlocal mDNSBool DomainContainsLabelString(const domainname *d, const char *str)
846 {
847 const domainlabel *l;
848 domainlabel buf;
849
850 if (!MakeDomainLabelFromLiteralString(&buf, str)) return mDNSfalse;
851
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;
854 return mDNSfalse;
855 }
856
857 // allocate struct, link into global list, initialize
858 mDNSlocal NATTraversalInfo *AllocNATInfo(mDNS *const m, NATOp_t op, NATResponseHndlr callback)
859 {
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;
867 info->op = op;
868 info->state = NATState_Init;
869 info->ReceiveResponse = callback;
870 info->PublicPort.NotAnInteger = 0;
871 return info;
872 }
873
874 // unlink from list, deallocate
875 mDNSlocal mDNSBool FreeNATInfo(mDNS *m, NATTraversalInfo *n)
876 {
877 NATTraversalInfo *ptr, *prev = mDNSNULL;
878
879 if (n == m->uDNS_info.LLQNatInfo) m->uDNS_info.LLQNatInfo = mDNSNULL;
880 ptr = m->uDNS_info.NATTraversals;
881 while (ptr)
882 {
883 if (ptr == n)
884 {
885 if (prev) prev->next = ptr->next;
886 else m->uDNS_info.NATTraversals = ptr->next;
887 ufree(n);
888 return mDNStrue;
889 }
890 prev = ptr;
891 ptr = ptr->next;
892 }
893 LogMsg("FreeNATInfo: NATTraversalInfo not found in list");
894 return mDNSfalse;
895 }
896
897 mDNSlocal void SendNATMsg(NATTraversalInfo *info, mDNS *m)
898 {
899 mStatus err;
900 mDNSAddr dst;
901 mDNSIPPort dstport;
902 uDNS_GlobalInfo *u = &m->uDNS_info;
903
904 if (info->state != NATState_Request && info->state != NATState_Refresh)
905 { LogMsg("SendNATMsg: Bad state %d", info->state); return; }
906
907 if (u->Router.ip.v4.NotAnInteger)
908 {
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
915 }
916
917 // set retry
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;
922 }
923
924 mDNSlocal void ReceiveNATAddrResponse(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len)
925 {
926 NATErr_t NatErr = NATErr_None;
927 mStatus err = mStatus_NoError;
928 AuthRecord *rr = mDNSNULL;
929 mDNSAddr addr;
930
931 if (n->state != NATState_Request)
932 {
933 LogMsg("ReceiveNATAddrResponse: bad state %d", n->state);
934 err = mStatus_UnknownErr;
935 goto end;
936 }
937
938 rr = n->reg.RecordRegistration;
939 if (!rr)
940 {
941 LogMsg("ReceiveNATAddrResponse: registration cancelled");
942 err = mStatus_UnknownErr;
943 goto end;
944 }
945
946 addr.type = mDNSAddrType_IPv4;
947 addr.ip.v4 = rr->resrec.rdata->u.ipv4;
948
949 if (!pkt) // timeout
950 {
951 #ifdef _LEGACY_NAT_TRAVERSAL_
952 err = LNT_GetPublicIP(&addr.ip.v4);
953 if (err) goto end;
954 else n->state = NATState_Legacy;
955 #else
956 debugf("ReceiveNATAddrResponse: timeout");
957 err = mStatus_NATTraversal;
958 goto end;
959 #endif // _LEGACY_NAT_TRAVERSAL_
960 }
961 else
962 {
963 if (len < ADDR_REPLY_PKTLEN)
964 {
965 LogMsg("ReceiveNATAddrResponse: response too short (%d bytes)", len);
966 err = mStatus_NATTraversal;
967 goto end;
968 }
969 if (pkt[0] != NATMAP_VERS)
970 {
971 LogMsg("ReceiveNATAddrResponse: received version %d (expect version %d)", pkt[0], NATMAP_VERS);
972 err = mStatus_NATTraversal;
973 goto end;
974 }
975 if (pkt[1] != (NATOp_AddrRequest | NATMAP_RESPONSE_MASK))
976 {
977 LogMsg("ReceiveNATAddrResponse: bad response code %d", pkt[1]);
978 err = mStatus_NATTraversal;
979 goto end;
980 }
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; }
983
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;
989 }
990
991 if (IsPrivateV4Addr(&addr))
992 {
993 LogMsg("ReceiveNATAddrResponse: Double NAT");
994 err = mStatus_DblNAT;
995 goto end;
996 }
997
998 end:
999 if (err)
1000 {
1001 FreeNATInfo(m, n);
1002 if (rr)
1003 {
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
1008 }
1009 return;
1010 }
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);
1014 }
1015
1016
1017 mDNSlocal void StartGetPublicAddr(mDNS *m, uDNS_HostnameInfo *hInfo)
1018 {
1019 mDNSu8 *msg;
1020 uDNS_GlobalInfo *u = &m->uDNS_info;
1021
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;
1027
1028 // format message
1029 msg = info->request;
1030 msg[0] = NATMAP_VERS;
1031 msg[1] = NATOp_AddrRequest;
1032 info->requestlen = ADDR_REQUEST_PKTLEN;
1033
1034 if (!u->Router.ip.v4.NotAnInteger)
1035 {
1036 debugf("No router. Will retry NAT traversal in %ld ticks", NATMAP_INIT_RETRY);
1037 return;
1038 }
1039
1040 SendNATMsg(info, m);
1041 }
1042
1043
1044 mDNSlocal void RefreshNATMapping(NATTraversalInfo *n, mDNS *m)
1045 {
1046 n->state = NATState_Refresh;
1047 n->RetryInterval = NATMAP_INIT_RETRY;
1048 n->ntries = 0;
1049 SendNATMsg(n, m);
1050 }
1051
1052 mDNSlocal void LLQNatMapComplete(mDNS *m)
1053 {
1054 uDNS_GlobalInfo *u = &m->uDNS_info;
1055 LLQ_Info *llqInfo;
1056 NATTraversalInfo *n = u->LLQNatInfo;
1057
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; }
1061
1062 u->CurrentQuery = u->ActiveQueries;
1063 while (u->CurrentQuery)
1064 {
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)
1069 {
1070 if (n->state == NATState_Error)
1071 {
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;
1077 }
1078 else { llqInfo->state = LLQ_GetZoneInfo; startLLQHandshake(m, llqInfo, mDNSfalse); }
1079 }
1080 }
1081 }
1082
1083 mDNSlocal void ReceivePortMapReply(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len)
1084 {
1085 NATErr_t err;
1086 ServiceRecordSet *srs;
1087 mDNSIPPort priv, pktpriv, pub;
1088 mDNSu32 lease;
1089 mDNSBool deletion;
1090
1091 if (n->state != NATState_Request && n->state != NATState_Refresh)
1092 { LogMsg("ReceivePortMapReply: bad state %d", n->state); return; }
1093
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.
1099
1100 srs = n->reg.ServiceRegistration;
1101 if (!srs && n != m->uDNS_info.LLQNatInfo)
1102 {
1103 debugf("ReceivePortMapReply: registration cancelled");
1104 FreeNATInfo(m, n);
1105 return;
1106 }
1107
1108 priv = srs ? srs->RR_SRV.resrec.rdata->u.srv.port : m->UnicastPort4;
1109
1110 if (!pkt) // timeout
1111 {
1112 #ifdef _LEGACY_NAT_TRAVERSAL_
1113 int ntries = 0;
1114 mStatus err;
1115 mDNSBool tcp = (srs && DomainContainsLabelString(&srs->RR_PTR.resrec.name, "_tcp"));
1116
1117 pub = priv; // initially request priv == pub
1118 while (1)
1119 {
1120 err = LNT_MapPort(priv, pub, tcp);
1121 if (!err)
1122 {
1123 n->PublicPort = pub;
1124 n->state = NATState_Legacy;
1125 goto end;
1126 }
1127 else if (err != mStatus_AlreadyRegistered || ++ntries > LEGACY_NATMAP_MAX_TRIES)
1128 {
1129 n->state = NATState_Error;
1130 goto end;
1131 }
1132 else
1133 {
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);
1137 }
1138 }
1139 #else
1140 goto end;
1141 #endif // _LEGACY_NAT_TRAVERSAL_
1142 }
1143
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; }
1149
1150 pktpriv.b[0] = pkt[4];
1151 pktpriv.b[1] = pkt[5];
1152 pub.b[0] = pkt[6];
1153 pub.b[1] = pkt[7];
1154
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;
1158
1159 if (priv.NotAnInteger != pktpriv.NotAnInteger)
1160 { LogMsg("ReceivePortMapReply: reply private port does not match requested private port"); goto end; }
1161
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;
1166
1167 n->retry = mDNSPlatformTimeNow(m) + ((mDNSs32)lease * mDNSPlatformOneSecond/2); // retry half way to expiration
1168
1169 if (n->state == NATState_Refresh) { n->state = NATState_Established; return; }
1170 n->state = NATState_Established;
1171
1172 end:
1173 if (n->state != NATState_Established && n->state != NATState_Legacy)
1174 {
1175 LogMsg("NAT Port Mapping: timeout");
1176 n->state = NATState_Error;
1177 if (!srs) { LLQNatMapComplete(m); return; }
1178 FreeNATInfo(m, n);
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
1184 }
1185
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);
1190 }
1191
1192 mDNSlocal void FormatPortMaprequest(NATTraversalInfo *info, mDNSIPPort port)
1193 {
1194 mDNSu8 *msg = info->request;
1195 mDNSOpaque32 lease = mDNSOpaque32fromIntVal(NATMAP_DEFAULT_LEASE);
1196
1197 msg[0] = NATMAP_VERS;
1198 msg[1] = info->op;
1199 msg[2] = 0; // reserved
1200 msg[3] = 0; // reserved
1201 msg[4] = port.b[0]; // private port
1202 msg[5] = port.b[1];
1203 msg[6] = port.b[0]; // requested pub. port
1204 msg[7] = port.b[1];
1205
1206 msg[8] = lease.b[0];
1207 msg[9] = lease.b[1];
1208 msg[10] = lease.b[2];
1209 msg[11] = lease.b[3];
1210 }
1211
1212 mDNSlocal void SendInitialPMapReq(mDNS *m, NATTraversalInfo *info)
1213 {
1214 if (!m->uDNS_info.Router.ip.v4.NotAnInteger)
1215 {
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;
1219 return;
1220 }
1221 SendNATMsg(info, m);
1222 return;
1223 }
1224
1225 mDNSlocal void StartNATPortMap(mDNS *m, ServiceRecordSet *srs)
1226 {
1227 NATOp_t op;
1228 NATTraversalInfo *info;
1229
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; }
1233
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;
1239
1240 FormatPortMaprequest(info, srs->RR_SRV.resrec.rdata->u.srv.port);
1241 SendInitialPMapReq(m, info);
1242 return;
1243
1244 error:
1245 startGetZoneData(&srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
1246 }
1247
1248 mDNSlocal void DeleteNATPortMapping(mDNS *m, NATTraversalInfo *nat, ServiceRecordSet *srs)
1249 {
1250 if (nat->state == NATState_Established) // let other edge-case states expire for simplicity
1251 {
1252 // zero lease
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;
1258 SendNATMsg(nat, m);
1259 }
1260 #ifdef _LEGACY_NAT_TRAVERSAL_
1261 else if (nat->state == NATState_Legacy)
1262 {
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);
1267 }
1268 #else
1269 (void)srs; // unused
1270 #endif // _LEGACY_NAT_TRAVERSAL_
1271 }
1272
1273 mDNSlocal void StartLLQNatMap(mDNS *m)
1274 {
1275 NATTraversalInfo *info = AllocNATInfo(m, NATOp_MapUDP, ReceivePortMapReply);
1276 uDNS_GlobalInfo *u = &m->uDNS_info;
1277
1278 u->LLQNatInfo = info;
1279
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);
1286 return;
1287 }
1288
1289 // if LLQ NAT context unreferenced, delete the mapping
1290 mDNSlocal void CheckForUnreferencedLLQMapping(mDNS *m)
1291 {
1292 NATTraversalInfo *nat = m->uDNS_info.LLQNatInfo;
1293 DNSQuestion *q;
1294
1295 if (!nat) return;
1296
1297 for (q = m->uDNS_info.ActiveQueries; q; q = q->next)
1298 if (q->LongLived && q->uDNS_info.llq->NATMap) return;
1299
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
1304 }
1305
1306 // ***************************************************************************
1307 #if COMPILER_LIKES_PRAGMA_MARK
1308 #pragma mark - host name and interface management
1309 #endif
1310
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)
1314 {
1315 uDNS_HostnameInfo *hi = u->Hostnames;
1316 (void)srv; // unused
1317
1318 dst->c[0] = 0;
1319 while (hi)
1320 {
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; }
1323 hi = hi->next;
1324 }
1325
1326 if (u->StaticHostname.c[0]) { AssignDomainName(*dst, u->StaticHostname); return mDNStrue; }
1327 return mDNSfalse;
1328 }
1329
1330 mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs)
1331 {
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);
1337
1338 if ((!havetarget && srs->uDNS_info.state == regState_NoTarget) || (havetarget && SameDomainName(curtarget, &newtarget))) return; // target unchanged
1339
1340 switch(srs->uDNS_info.state)
1341 {
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
1351 return;
1352
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;
1358 return;
1359
1360 case regState_NoTarget:
1361 // Service has not been registered due to lack of a target hostname
1362 if (havetarget) SendServiceRegistration(m, srs);
1363 return;
1364
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;
1369
1370 srs->uDNS_info.LostTarget = mDNStrue;
1371 SendServiceDeregistration(m, srs);
1372 return;
1373 }
1374 }
1375
1376 mDNSlocal void UpdateSRVRecords(mDNS *m)
1377 {
1378 ServiceRecordSet *srs;
1379
1380 for (srs = m->uDNS_info.ServiceRegistrations; srs; srs = srs->next) UpdateSRV(m, srs);
1381 }
1382
1383 mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
1384 {
1385 uDNS_HostnameInfo *hi = (uDNS_HostnameInfo *)rr->RecordContext;
1386 mDNSu8 *ip = rr->resrec.rdata->u.ipv4.b;
1387
1388 if (result == mStatus_MemFree)
1389 {
1390 debugf("MemFree: %##s IP %d.%d.%d.%d", rr->resrec.name.c, ip[0], ip[1], ip[2], ip[3]);
1391 if (hi) ufree(hi);
1392 ufree(rr);
1393 return;
1394 }
1395
1396 if (result == mStatus_NameConflict && rr->resrec.RecordType == kDNSRecordTypeUnique)
1397 {
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);
1402 return;
1403 }
1404
1405 if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
1406 {
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;
1410 }
1411
1412 if (result)
1413 {
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;
1422 return;
1423 }
1424
1425 // register any pending services that require a target
1426 UpdateSRVRecords(m);
1427
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;
1435 }
1436
1437 // register record or begin NAT traversal
1438 mDNSlocal void AdvertiseHostname(mDNS *m, uDNS_HostnameInfo *h)
1439 {
1440 if (IsPrivateV4Addr(&m->uDNS_info.PrimaryIP))
1441 StartGetPublicAddr(m, h);
1442 else
1443 {
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);
1447 }
1448 }
1449
1450 mDNSlocal void FoundStaticHostname(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1451 {
1452 const domainname *pktname = &answer->rdata->u.name;
1453 domainname *storedname = &m->uDNS_info.StaticHostname;
1454 (void)question;
1455
1456 debugf("FoundStaticHostname: %##s -> %##s (%s)", question->qname.c, answer->rdata->u.name.c, AddRecord ? "added" : "removed");
1457 if (AddRecord && !SameDomainName(pktname, storedname))
1458 {
1459 AssignDomainName(*storedname, *pktname);
1460 UpdateSRVRecords(m);
1461 }
1462 else if (!AddRecord && SameDomainName(pktname, storedname))
1463 {
1464 storedname->c[0] = 0;
1465 UpdateSRVRecords(m);
1466 }
1467 }
1468
1469 mDNSlocal void GetStaticHostname(mDNS *m)
1470 {
1471 char buf[MAX_ESCAPED_DOMAIN_NAME];
1472 DNSQuestion *q = &m->uDNS_info.ReverseMap;
1473 mDNSu8 *ip = m->uDNS_info.PrimaryIP.ip.v4.b;
1474 mStatus err;
1475
1476 ubzero(q, sizeof(*q));
1477
1478 if (m->uDNS_info.ReverseMapActive)
1479 {
1480 uDNS_StopQuery(m, q);
1481 m->uDNS_info.ReverseMapActive = mDNSfalse;
1482 }
1483
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; }
1487
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;
1497
1498 err = uDNS_StartQuery(m, q);
1499 if (err) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err);
1500 else m->uDNS_info.ReverseMapActive = mDNStrue;
1501 }
1502
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)
1506 {
1507 uDNS_GlobalInfo *u = &m->uDNS_info;
1508 AuthRecord *new;
1509 uDNS_HostnameInfo *i;
1510
1511 for (i = u->Hostnames; i; i = i->next)
1512 {
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;
1515 else
1516 {
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);
1520 }
1521
1522 // setup new record
1523 AssignDomainName(new->resrec.name, i->ar->resrec.name);
1524 new->resrec.rdata->u.ipv4 = u->PrimaryIP.ip.v4;
1525
1526 if (i->ar->uDNS_info.state != regState_Unregistered)
1527 {
1528 // delete old record
1529 i->ar->RecordContext = mDNSNULL; // clear backpointer to HostnameInfo
1530 uDNS_DeregisterRecord(m, i->ar);
1531 i->ar = new;
1532 }
1533
1534 // advertise new
1535 AdvertiseHostname(m, i);
1536 }
1537 }
1538
1539 mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
1540 {
1541 uDNS_GlobalInfo *u = &m->uDNS_info;
1542 uDNS_HostnameInfo *ptr, *new;
1543
1544 mDNS_Lock(m);
1545
1546 // check if domain already registered
1547 for (ptr = u->Hostnames; ptr; ptr = ptr->next)
1548 {
1549 if (SameDomainName(fqdn, &ptr->ar->resrec.name))
1550 { LogMsg("Host Domain %##s already in list", fqdn->c); goto exit; }
1551 }
1552
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;
1562 u->Hostnames = new;
1563 if (u->PrimaryIP.ip.v4.NotAnInteger)
1564 {
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);
1569 }
1570 else new->ar->uDNS_info.state = regState_Unregistered;
1571 exit:
1572 mDNS_Unlock(m);
1573 }
1574
1575 mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn)
1576 {
1577 uDNS_GlobalInfo *u = &m->uDNS_info;
1578 uDNS_HostnameInfo **ptr = &u->Hostnames;
1579
1580 mDNS_Lock(m);
1581
1582 while (*ptr && !SameDomainName(fqdn, &(*ptr)->ar->resrec.name)) ptr = &(*ptr)->next;
1583 if (!*ptr) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn->c);
1584 else
1585 {
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; }
1591 ufree(hi);
1592 }
1593 UpdateSRVRecords(m);
1594 mDNS_Unlock(m);
1595 }
1596
1597 mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *addr, const mDNSAddr *router)
1598 {
1599 uDNS_GlobalInfo *u = &m->uDNS_info;
1600 mDNSBool AddrChanged, RouterChanged;
1601
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; }
1604 mDNS_Lock(m);
1605
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;
1608
1609 #if MDNS_DEBUGMSGS
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
1615
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
1619
1620 if (AddrChanged)
1621 {
1622 if (addr)
1623 {
1624 UpdateHostnameRegistrations(m);
1625 UpdateSRVRecords(m);
1626 }
1627 GetStaticHostname(m); // look up reverse map record to find any static hostnames for our IP address
1628 }
1629
1630 mDNS_Unlock(m);
1631 }
1632
1633 // ***************************************************************************
1634 #if COMPILER_LIKES_PRAGMA_MARK
1635 #pragma mark - Incoming Message Processing
1636 #endif
1637
1638 mDNSlocal mDNSBool kaListContainsAnswer(DNSQuestion *question, CacheRecord *rr)
1639 {
1640 CacheRecord *ptr;
1641
1642 for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next)
1643 if (SameResourceRecord(&ptr->resrec, &rr->resrec)) return mDNStrue;
1644
1645 return mDNSfalse;
1646 }
1647
1648
1649 mDNSlocal void removeKnownAnswer(DNSQuestion *question, CacheRecord *rr)
1650 {
1651 CacheRecord *ptr, *prev = mDNSNULL;
1652
1653 for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next)
1654 {
1655 if (SameResourceRecord(&ptr->resrec, &rr->resrec))
1656 {
1657 if (prev) prev->next = ptr->next;
1658 else question->uDNS_info.knownAnswers = ptr->next;
1659 ufree(ptr);
1660 return;
1661 }
1662 prev = ptr;
1663 }
1664 LogMsg("removeKnownAnswer() called for record not in KA list");
1665 }
1666
1667
1668 mDNSlocal void addKnownAnswer(DNSQuestion *question, const CacheRecord *rr)
1669 {
1670 CacheRecord *newCR = mDNSNULL;
1671 mDNSu32 size;
1672
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;
1681 }
1682
1683 mDNSlocal void deriveGoodbyes(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question)
1684 {
1685 const mDNSu8 *ptr;
1686 int i;
1687 CacheRecord *fptr, *ka, *cr, *answers = mDNSNULL, *prev = mDNSNULL;
1688 LargeCacheRecord *lcr;
1689
1690 if (question != m->uDNS_info.CurrentQuery) { LogMsg("ERROR: deriveGoodbyes called without CurrentQuery set!"); return; }
1691
1692 ptr = LocateAnswers(msg, end);
1693 if (!ptr) goto pkt_error;
1694
1695 if (!msg->h.numAnswers)
1696 {
1697 // delete the whole KA list
1698 ka = question->uDNS_info.knownAnswers;
1699 while (ka)
1700 {
1701 debugf("deriving goodbye for %##s", ka->resrec.name.c);
1702
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)
1707 {
1708 debugf("deriveGoodbyes - question removed via callback. returning.");
1709 return;
1710 }
1711 fptr = ka;
1712 ka = ka->next;
1713 ufree(fptr);
1714 }
1715 question->uDNS_info.knownAnswers = mDNSNULL;
1716 return;
1717 }
1718
1719 // make a list of all the new answers
1720 for (i = 0; i < msg->h.numAnswers; i++)
1721 {
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;
1727 cr = &lcr->r;
1728 if (ResourceRecordAnswersQuestion(&cr->resrec, question))
1729 {
1730 cr->next = answers;
1731 answers = cr;
1732 }
1733 else ufree(cr);
1734 }
1735
1736 // make sure every known answer is in the answer list
1737 ka = question->uDNS_info.knownAnswers;
1738 while (ka)
1739 {
1740 for (cr = answers; cr; cr = cr->next)
1741 { if (SameResourceRecord(&ka->resrec, &cr->resrec)) break; }
1742 if (!cr)
1743 {
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)
1752 {
1753 debugf("deriveGoodbyes - question removed via callback. returning.");
1754 return;
1755 }
1756 fptr = ka;
1757 ka = ka->next;
1758 ufree(fptr);
1759 }
1760 else
1761 {
1762 prev = ka;
1763 ka = ka->next;
1764 }
1765 }
1766
1767 // free temp answers list
1768 cr = answers;
1769 while (cr) { fptr = cr; cr = cr->next; ufree(fptr); }
1770
1771 return;
1772
1773 pkt_error:
1774 LogMsg("ERROR: deriveGoodbyes - received malformed response to query for %##s (%d)",
1775 question->qname.c, question->qtype);
1776 return;
1777
1778 malloc_error:
1779 LogMsg("ERROR: Malloc");
1780 }
1781
1782 mDNSlocal void pktResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, mDNSBool llq)
1783 {
1784 const mDNSu8 *ptr;
1785 int i;
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;
1791
1792 if (question != m->uDNS_info.CurrentQuery)
1793 { LogMsg("ERROR: pktResponseHdnlr called without CurrentQuery ptr set!"); return; }
1794
1795 question->uDNS_info.Answered = mDNStrue;
1796
1797 ptr = LocateAnswers(msg, end);
1798 if (!ptr) goto pkt_error;
1799
1800 for (i = 0; i < msg->h.numAnswers; i++)
1801 {
1802 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
1803 if (!ptr) goto pkt_error;
1804 if (ResourceRecordAnswersQuestion(&cr->resrec, question))
1805 {
1806 if (cr->resrec.rrtype == kDNSType_CNAME)
1807 {
1808 if (followedCName) LogMsg("Error: multiple CNAME referals for question %##s", question->qname.c);
1809 else
1810 {
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);
1818 continue;
1819 }
1820 }
1821
1822 goodbye = llq ? ((mDNSs32)cr->resrec.rroriginalttl == -1) : mDNSfalse;
1823 inKAList = kaListContainsAnswer(question, cr);
1824
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)
1832 {
1833 debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning");
1834 return;
1835 }
1836 }
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);
1839 }
1840
1841 if (!llq || llqInfo->state == LLQ_Poll || llqInfo->deriveRemovesOnResume)
1842 {
1843 deriveGoodbyes(m, msg, end,question);
1844 if (llq && llqInfo->deriveRemovesOnResume) llqInfo->deriveRemovesOnResume = mDNSfalse;
1845 }
1846
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;
1849 return;
1850
1851 pkt_error:
1852 LogMsg("ERROR: pktResponseHndlr - received malformed response to query for %##s (%d)",
1853 question->qname.c, question->qtype);
1854 return;
1855 }
1856
1857 mDNSlocal void simpleResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *context)
1858 {
1859 (void)context; // unused
1860 pktResponseHndlr(m, msg, end, question, mDNSfalse);
1861 }
1862
1863 mDNSlocal void llqResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *context)
1864 {
1865 (void)context; // unused
1866 pktResponseHndlr(m, msg, end, question, mDNStrue);
1867 }
1868
1869 mDNSlocal mStatus ParseTSIGError(mDNS *m, const DNSMessage *msg, const mDNSu8 *end, const domainname *displayname)
1870 {
1871 LargeCacheRecord lcr;
1872 const mDNSu8 *ptr;
1873 mStatus err = mStatus_NoError;
1874 int i;
1875
1876 ptr = LocateAdditionals(msg, end);
1877 if (!ptr) goto finish;
1878
1879 for (i = 0; i < msg->h.numAdditionals; i++)
1880 {
1881 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);;
1882 if (!ptr) goto finish;
1883 if (lcr.r.resrec.rrtype == kDNSType_TSIG)
1884 {
1885 mDNSu32 macsize;
1886 mDNSu8 *rd = lcr.r.resrec.rdata->u.data;
1887 mDNSu8 *rdend = rd + MaximumRDSize;
1888 int alglen = DomainNameLength(&lcr.r.resrec.rdata->u.name);
1889
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;
1900 rd += macsize;
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
1905
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; }
1910 goto finish;
1911 }
1912 }
1913
1914 finish:
1915 return err;
1916 }
1917
1918 mDNSlocal mStatus checkUpdateResult(domainname *displayname, mDNSu8 rcode, mDNS *m, const DNSMessage *msg, const mDNSu8 *end)
1919 {
1920 (void)msg; // currently unused, needed for TSIG errors
1921 if (!rcode) return mStatus_NoError;
1922 else if (rcode == kDNSFlag1_RC_YXDomain)
1923 {
1924 LogMsg("name in use: %##s", displayname->c);
1925 return mStatus_NameConflict;
1926 }
1927 else if (rcode == kDNSFlag1_RC_Refused)
1928 {
1929 LogMsg("Update %##s refused", displayname->c);
1930 return mStatus_Refused;
1931 }
1932 else if (rcode == kDNSFlag1_RC_NXRRSet)
1933 {
1934 LogMsg("Reregister refused (NXRRSET): %##s", displayname->c);
1935 return mStatus_NoSuchRecord;
1936 }
1937 else if (rcode == kDNSFlag1_RC_NotAuth)
1938 {
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);
1941 if (!tsigerr)
1942 {
1943 LogMsg("Permission denied (NOAUTH): %##s", displayname->c);
1944 return mStatus_UnknownErr;
1945 }
1946 else return tsigerr;
1947 }
1948 else if (rcode == kDNSFlag1_RC_FmtErr)
1949 {
1950 mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
1951 if (!tsigerr)
1952 {
1953 LogMsg("Format Error: %##s", displayname->c);
1954 return mStatus_UnknownErr;
1955 }
1956 else return tsigerr;
1957 }
1958 else
1959 {
1960 LogMsg("Update %##s failed with rcode %d", displayname->c, rcode);
1961 return mStatus_UnknownErr;
1962 }
1963 }
1964
1965 mDNSlocal void hndlServiceUpdateReply(mDNS * const m, ServiceRecordSet *srs, mStatus err)
1966 {
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;
1972
1973 switch (info->state)
1974 {
1975 case regState_Pending:
1976 if (err == mStatus_NameConflict && !info->TestForSelfConflict)
1977 {
1978 info->TestForSelfConflict = mDNStrue;
1979 debugf("checking for self-conflict of service %##s", srs->RR_SRV.resrec.name.c);
1980 SendServiceRegistration(m, srs);
1981 return;
1982 }
1983 else if (info->TestForSelfConflict)
1984 {
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;
1990 break;
1991 }
1992 else if (err == mStatus_UnknownErr && info->lease)
1993 {
1994 LogMsg("Re-trying update of service %##s without lease option", srs->RR_SRV.resrec.name.c);
1995 info->lease = mDNSfalse;
1996 info->expire = -1;
1997 SendServiceRegistration(m, srs);
1998 return;
1999 }
2000 else
2001 {
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;
2005 break;
2006 }
2007 case regState_Refresh:
2008 if (err)
2009 {
2010 LogMsg("Error %ld for refresh of service %##s", err, srs->RR_SRV.resrec.name.c);
2011 InvokeCallback = mDNStrue;
2012 info->state = regState_Unregistered;
2013 }
2014 else info->state = regState_Registered;
2015 break;
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)
2019 {
2020 info->state = regState_NoTarget;
2021 break;
2022 }
2023 err = mStatus_MemFree;
2024 InvokeCallback = mDNStrue;
2025 if (nat)
2026 {
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
2029 }
2030 info->state = regState_Unregistered;
2031 break;
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);
2037 return;
2038 case regState_UpdatePending:
2039 // find the record being updated
2040 UpdateR = &srs->RR_TXT;
2041 if (err)
2042 {
2043 LogMsg("hndlServiceUpdateReply: error updating resource record");
2044 UpdateR->uDNS_info.state = regState_Unregistered;
2045 InvokeCallback = mDNStrue; // signal error via service callback
2046 }
2047 else
2048 {
2049 UpdateR->uDNS_info.state = regState_Registered;
2050 SwapRData(m, UpdateR, mDNStrue);
2051 }
2052 info->state = regState_Registered;
2053 break;
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;
2064 }
2065
2066 if ((info->LostTarget || info->SRVUpdateDeferred) && (info->state == regState_NoTarget || info->state == regState_Registered))
2067 {
2068 UpdateSRV(m, srs);
2069 return;
2070 }
2071
2072 while (*e)
2073 {
2074 uDNS_RegInfo *einfo = &(*e)->r.uDNS_info;
2075 if (einfo->state == regState_ExtraQueued)
2076 {
2077 if (info->state == regState_Registered && !err)
2078 {
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);
2085 e = &(*e)->next;
2086 }
2087 else if (err && einfo->state != regState_Unregistered)
2088 {
2089 // unlink extra from list
2090 einfo->state = regState_Unregistered;
2091 *e = (*e)->next;
2092 }
2093 else e = &(*e)->next;
2094 }
2095 else e = &(*e)->next;
2096 }
2097
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);
2100
2101 if (info->state == regState_Unregistered) unlinkSRS(&m->uDNS_info, srs);
2102
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)
2106 {
2107 info->ClientCallbackDeferred = mDNSfalse;
2108 srs->ServiceCallback(m, srs, info->DeferredStatus);
2109 }
2110 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2111 // NOTE: do not touch structures after calling ServiceCallback
2112 }
2113
2114 mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
2115 {
2116 uDNS_GlobalInfo *u = &m->uDNS_info;
2117
2118 if (rr->uDNS_info.state == regState_UpdatePending)
2119 {
2120 if (err)
2121 {
2122 LogMsg("Update record failed for %##s (err %d)", rr->resrec.name.c, err);
2123 rr->uDNS_info.state = regState_Unregistered;
2124 }
2125 else
2126 {
2127 debugf("Update record %##s - success", rr->resrec.name.c);
2128 rr->uDNS_info.state = regState_Registered;
2129 SwapRData(m, rr, mDNStrue);
2130 }
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
2134 return;
2135 }
2136
2137 if (rr->uDNS_info.state == regState_DeregPending)
2138 {
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
2149 return;
2150 }
2151
2152 if (rr->uDNS_info.state == regState_DeregDeferred)
2153 {
2154 if (err)
2155 {
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;
2160 return;
2161 }
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);
2166 return;
2167 }
2168
2169 if (rr->uDNS_info.state == regState_Pending || rr->uDNS_info.state == regState_Refresh)
2170 {
2171 if (err)
2172 {
2173 if (rr->uDNS_info.lease && err == mStatus_UnknownErr)
2174 {
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);
2179 return;
2180 }
2181
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
2189 return;
2190 }
2191 else
2192 {
2193 if (rr->uDNS_info.UpdateQueued)
2194 {
2195 debugf("%##s: sending queued update", rr->resrec.name.c);
2196 rr->uDNS_info.state = regState_Registered;
2197 SendRecordUpdate(m ,rr, &rr->uDNS_info);
2198 return;
2199 }
2200 if (rr->uDNS_info.state == regState_Refresh)
2201 rr->uDNS_info.state = regState_Registered;
2202 else
2203 {
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
2208 }
2209 return;
2210 }
2211 }
2212
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);
2215 }
2216
2217
2218 mDNSlocal void SetUpdateExpiration(mDNS *m, DNSMessage *msg, const mDNSu8 *end, uDNS_RegInfo *info)
2219 {
2220 LargeCacheRecord lcr;
2221 const mDNSu8 *ptr;
2222 int i;
2223 mDNSu32 lease = 0;
2224 mDNSs32 expire;
2225
2226 ptr = LocateAdditionals(msg, end);
2227
2228 if (info->lease && (ptr = LocateAdditionals(msg, end)))
2229 {
2230 for (i = 0; i < msg->h.numAdditionals; i++)
2231 {
2232 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
2233 if (!ptr) break;
2234 if (lcr.r.resrec.rrtype == kDNSType_OPT)
2235 {
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;
2239 break;
2240 }
2241 }
2242 }
2243
2244 if (lease > 0)
2245 {
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;
2251 }
2252 else info->expire = -1;
2253 }
2254
2255 mDNSexport void uDNS_ReceiveNATMap(mDNS *m, mDNSu8 *pkt, mDNSu16 len)
2256 {
2257 uDNS_GlobalInfo *u = &m->uDNS_info;
2258 NATTraversalInfo *ptr, *cur;
2259 NATOp_t op;
2260
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; }
2264 op = pkt[1];
2265 if (!(op & NATMAP_RESPONSE_MASK)) { LogMsg("Received NAT Traversal message that is not a response (opcode %d)", op); return; }
2266
2267 ptr = u->NATTraversals;
2268 while (ptr)
2269 {
2270 cur = ptr;
2271 ptr = ptr->next;
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
2276 }
2277 }
2278
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)
2282 {
2283 DNSQuestion *qptr;
2284 AuthRecord *rptr;
2285 ServiceRecordSet *sptr;
2286 mStatus err = mStatus_NoError;
2287 uDNS_GlobalInfo *u = &m->uDNS_info;
2288
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);
2293
2294 mDNSs32 timenow = mDNSPlatformTimeNow(m);
2295
2296 // unused
2297 (void)dstaddr;
2298 (void)dstport;
2299 (void)InterfaceID;
2300
2301 if (QR_OP == StdR)
2302 {
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;
2306
2307 for (qptr = u->ActiveQueries; qptr; qptr = qptr->next)
2308 {
2309 //!!!KRS we should have a hashtable, hashed on message id
2310 if (qptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
2311 {
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; }
2316 else
2317 {
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
2322 return;
2323 }
2324 }
2325 }
2326 }
2327 if (QR_OP == UpdateR)
2328 {
2329 for (sptr = u->ServiceRegistrations; sptr; sptr = sptr->next)
2330 {
2331 if (sptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
2332 {
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);
2336 return;
2337 }
2338 }
2339 for (rptr = u->RecordRegistrations; rptr; rptr = rptr->next)
2340 {
2341 if (rptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
2342 {
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);
2346 return;
2347 }
2348 }
2349 }
2350 debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg->h.id));
2351 }
2352
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)
2355 {
2356 DNSServer *curmatch = mDNSNULL, *p = u->Servers;
2357 int i, ncount, scount, curmatchlen = -1;
2358
2359 *addr = zeroAddr;
2360 ncount = name ? CountLabels(name) : 0;
2361 while (p)
2362 {
2363 scount = CountLabels(&p->domain);
2364 if (scount <= ncount && scount > curmatchlen)
2365 {
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; }
2371 }
2372 p = p->next;
2373 }
2374
2375 if (curmatch)
2376 {
2377 *addr = curmatch->addr;
2378 return mDNStrue;
2379 }
2380 else return mDNSfalse;
2381 }
2382
2383 // ***************************************************************************
2384 #if COMPILER_LIKES_PRAGMA_MARK
2385 #pragma mark - Query Routines
2386 #endif
2387
2388 #define sameID(x,y) mDNSPlatformMemSame(x,y,8)
2389
2390 mDNSlocal void initializeQuery(DNSMessage *msg, DNSQuestion *question)
2391 {
2392 mDNSOpaque16 flags = QueryFlags;
2393
2394 ubzero(msg, sizeof(msg));
2395 flags.b[0] |= kDNSFlag0_RD; // recursion desired
2396 InitializeDNSMessage(&msg->h, question->uDNS_info.id, flags);
2397 }
2398
2399 mDNSlocal mStatus constructQueryMsg(DNSMessage *msg, mDNSu8 **endPtr, DNSQuestion *const question)
2400 {
2401 initializeQuery(msg, question);
2402
2403 *endPtr = putQuestion(msg, msg->data, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
2404 if (!*endPtr)
2405 {
2406 LogMsg("ERROR: Unicast query out of space in packet");
2407 return mStatus_UnknownErr;
2408 }
2409 return mStatus_NoError;
2410 }
2411
2412 mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, DNSQuestion *question, LLQOptData *data, mDNSBool includeQuestion)
2413 {
2414 AuthRecord rr;
2415 ResourceRecord *opt = &rr.resrec;
2416 rdataOpt *optRD;
2417
2418 //!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section
2419 if (includeQuestion)
2420 {
2421 ptr = putQuestion(msg, ptr, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
2422 if (!ptr) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL; }
2423 }
2424 // locate OptRR if it exists, set pointer to end
2425 // !!!KRS implement me
2426
2427
2428 // format opt rr (fields not specified are zero-valued)
2429 ubzero(&rr, sizeof(AuthRecord));
2430 opt->rdata = &rr.rdatastorage;
2431
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;
2436
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; }
2443
2444 return ptr;
2445 }
2446
2447
2448 mDNSlocal mDNSBool getLLQAtIndex(mDNS *m, DNSMessage *msg, const mDNSu8 *end, LLQOptData *llq, int index)
2449 {
2450 LargeCacheRecord lcr;
2451 int i;
2452 const mDNSu8 *ptr;
2453
2454 ptr = LocateAdditionals(msg, end);
2455 if (!ptr) return mDNSfalse;
2456
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?
2465 return mDNStrue;
2466 }
2467
2468 mDNSlocal void recvRefreshReply(mDNS *m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *q)
2469 {
2470 LLQ_Info *qInfo;
2471 LLQOptData pktData;
2472
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; }
2478
2479 qInfo->expire = mDNSPlatformTimeNow(m) + ((mDNSs32)pktData.lease * mDNSPlatformOneSecond);
2480 qInfo->retry = qInfo->expire - ((mDNSs32)pktData.lease * mDNSPlatformOneSecond/2);
2481
2482 qInfo->origLease = pktData.lease;
2483 qInfo->state = LLQ_Established;
2484 }
2485
2486 mDNSlocal void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease)
2487 {
2488 DNSMessage msg;
2489 mDNSu8 *end;
2490 LLQOptData llq;
2491 LLQ_Info *info = q->uDNS_info.llq;
2492 mStatus err;
2493 mDNSs32 timenow;
2494
2495 timenow = mDNSPlatformTimeNow(m);
2496 if ((info->state == LLQ_Refresh && info->ntries >= kLLQ_MAX_TRIES) ||
2497 info->expire - timenow < 0)
2498 {
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;
2503 return;
2504 //!!!KRS handle this - periodically try to re-establish
2505 }
2506
2507 llq.vers = kLLQ_Vers;
2508 llq.llqOp = kLLQOp_Refresh;
2509 llq.err = LLQErr_NoError;
2510 umemcpy(llq.id, info->id, 8);
2511 llq.lease = lease;
2512
2513 initializeQuery(&msg, q);
2514 end = putLLQ(&msg, msg.data, q, &llq, mDNStrue);
2515 if (!end) { LogMsg("ERROR: sendLLQRefresh - putLLQ"); return; }
2516
2517 err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL);
2518 if (err) LogMsg("ERROR: sendLLQRefresh - mDNSSendDNSMessage returned %ld", err);
2519
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;
2525 }
2526
2527 mDNSlocal mDNSBool recvLLQEvent(mDNS *m, DNSQuestion *q, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, mDNSInterfaceID InterfaceID)
2528 {
2529 DNSMessage ack;
2530 mDNSu8 *ackEnd = ack.data;
2531 mStatus err;
2532 LLQOptData opt;
2533
2534 (void)InterfaceID; // unused
2535
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; }
2541
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;
2546
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);
2553 return mDNStrue;
2554 }
2555
2556
2557
2558 mDNSlocal void hndlChallengeResponseAck(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q)
2559 {
2560 LLQ_Info *info = q->uDNS_info.llq;
2561
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);
2566
2567 info->origLease = llq->lease;
2568 info->state = LLQ_Established;
2569
2570 q->uDNS_info.responseCallback = llqResponseHndlr;
2571 llqResponseHndlr(m, pktMsg, end, q, mDNSNULL);
2572 return;
2573
2574 error:
2575 info->state = LLQ_Error;
2576 }
2577
2578 mDNSlocal void sendChallengeResponse(mDNS *m, DNSQuestion *q, LLQOptData *llq)
2579 {
2580 LLQ_Info *info = q->uDNS_info.llq;
2581 DNSMessage response;
2582 mDNSu8 *responsePtr = response.data;
2583 mStatus err;
2584 LLQOptData llqBuf;
2585 mDNSs32 timenow = mDNSPlatformTimeNow(m);
2586
2587 if (info->ntries++ == kLLQ_MAX_TRIES)
2588 {
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?
2594 return;
2595 }
2596
2597
2598 if (!llq)
2599 {
2600 llq = &llqBuf;
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;
2606 }
2607
2608 q->LastQTime = timenow;
2609 info->retry = timenow + (kLLQ_INIT_RESEND * info->ntries * mDNSPlatformOneSecond);
2610
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; }
2614
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
2618
2619 return;
2620
2621 error:
2622 info->state = LLQ_Error;
2623 }
2624
2625
2626
2627 mDNSlocal void hndlRequestChallenge(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q)
2628 {
2629 LLQ_Info *info = q->uDNS_info.llq;
2630 mDNSs32 timenow = mDNSPlatformTimeNow(m);
2631 switch(llq->err)
2632 {
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;
2640 case LLQErr_Static:
2641 info->state = LLQ_Static;
2642 LogMsg("LLQ %##s: static", q->qname.c);
2643 simpleResponseHndlr(m, pktMsg, end, q, mDNSNULL);
2644 return;
2645 case LLQErr_FormErr:
2646 LogMsg("ERROR: hndlRequestChallenge - received FormErr from server for LLQ %##s", q->qname.c);
2647 goto error;
2648 case LLQErr_BadVers:
2649 LogMsg("ERROR: hndlRequestChallenge - received BadVers from server");
2650 goto error;
2651 case LLQErr_UnknownErr:
2652 LogMsg("ERROR: hndlRequestChallenge - received UnknownErr from server for LLQ %##s", q->qname.c);
2653 goto error;
2654 default:
2655 LogMsg("ERROR: hndlRequestChallenge - received invalid error %d for LLQ %##s", llq->err, q->qname.c);
2656 goto error;
2657 }
2658
2659 if (info->origLease != llq->lease)
2660 LogMsg("hndlRequestChallenge: requested lease %lu, granted lease %lu", info->origLease, llq->lease);
2661
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);
2665
2666 // update state
2667 info->state = LLQ_SecondaryRequest;
2668 umemcpy(info->id, llq->id, 8);
2669 info->ntries = 0; // first attempt to send response
2670
2671 sendChallengeResponse(m, q, llq);
2672 return;
2673
2674
2675 error:
2676 info->state = LLQ_Error;
2677 }
2678
2679
2680 // response handler for initial and secondary setup responses
2681 mDNSlocal void recvSetupResponse(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, DNSQuestion *q, void *clientContext)
2682 {
2683 DNSQuestion pktQuestion;
2684 LLQOptData llq;
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);
2688
2689 (void)clientContext; // unused
2690
2691 if (rcode && rcode != kDNSFlag1_RC_NXDomain) goto poll;
2692
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; }
2697
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; }
2701
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);
2705
2706 poll:
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;
2711 }
2712
2713 mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer)
2714 {
2715 DNSMessage msg;
2716 mDNSu8 *end;
2717 LLQOptData llqData;
2718 DNSQuestion *q = info->question;
2719 mStatus err = mStatus_NoError;
2720 mDNSs32 timenow = mDNSPlatformTimeNow(m);
2721 uDNS_GlobalInfo *u = &m->uDNS_info;
2722
2723 if (IsPrivateV4Addr(&u->PrimaryIP))
2724 {
2725 if (!u->LLQNatInfo)
2726 {
2727 info->state = LLQ_NatMapWait;
2728 StartLLQNatMap(m);
2729 return;
2730 }
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
2735 }
2736
2737 if (info->ntries++ >= kLLQ_MAX_TRIES)
2738 {
2739 debugf("startLLQHandshake: %d failed attempts for LLQ %##s. Polling.", kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60);
2740 goto poll;
2741 }
2742
2743 // set llq rdata
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;
2749
2750 initializeQuery(&msg, q);
2751 end = putLLQ(&msg, msg.data, q, &llqData, mDNStrue);
2752 if (!end)
2753 {
2754 LogMsg("ERROR: startLLQHandshake - putLLQ");
2755 info->state = LLQ_Error;
2756 return;
2757 }
2758
2759 if (!defer) // if we are to defer, we simply set the retry timers so the request goes out in the future
2760 {
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
2764 }
2765
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;
2773 return;
2774
2775 poll:
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;
2780 }
2781
2782 // wrapper for startLLQHandshake, invoked by async op callback
2783 mDNSlocal void startLLQHandshakeCallback(mStatus err, mDNS *const m, void *llqInfo, const AsyncOpResult *result)
2784 {
2785 LLQ_Info *info = (LLQ_Info *)llqInfo;
2786 const zoneData_t *zoneInfo = mDNSNULL;
2787
2788 // check state first to make sure it is OK to touch question object
2789 if (info->state == LLQ_Cancelled)
2790 {
2791 // StopQuery was called while we were getting the zone info
2792 debugf("startLLQHandshake - LLQ Cancelled.");
2793 info->question = mDNSNULL; // question may be deallocated
2794 ufree(info);
2795 return;
2796 }
2797
2798 if (!info->question)
2799 { LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL question"); goto error; }
2800
2801 if (info->state != LLQ_GetZoneInfo)
2802 { LogMsg("ERROR: startLLQHandshake - bad state %d", info->state); goto error; }
2803
2804 if (err)
2805 { LogMsg("ERROR: startLLQHandshakeCallback invoked with error code %ld", err); goto poll; }
2806
2807 if (!result)
2808 { LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL result and no error code"); goto error; }
2809
2810 zoneInfo = &result->zoneData;
2811
2812 if (!zoneInfo->llqPort.NotAnInteger)
2813 { debugf("LLQ port lookup failed - reverting to polling"); goto poll; }
2814
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;
2819 info->ntries = 0;
2820
2821 if (info->state == LLQ_SuspendDeferred) info->state = LLQ_Suspended;
2822 else startLLQHandshake(m, info, mDNSfalse);
2823 return;
2824
2825 poll:
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;
2830 return;
2831
2832 error:
2833 info->state = LLQ_Error;
2834 }
2835
2836 mDNSlocal mStatus startLLQ(mDNS *m, DNSQuestion *question)
2837 {
2838 LLQ_Info *info;
2839 mStatus err = mStatus_NoError;
2840
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;
2846
2847 // link info/question
2848 info->question = question;
2849 question->uDNS_info.llq = info;
2850
2851 question->uDNS_info.responseCallback = llqResponseHndlr;
2852
2853 err = startGetZoneData(&question->qname, m, mDNSfalse, mDNStrue, startLLQHandshakeCallback, info);
2854 if (err)
2855 {
2856 LogMsg("ERROR: startLLQ - startGetZoneData returned %ld", err);
2857 info->question = mDNSNULL;
2858 ufree(info);
2859 question->uDNS_info.llq = mDNSNULL;
2860 return err;
2861 }
2862
2863 LinkActiveQuestion(&m->uDNS_info, question);
2864 return err;
2865 }
2866
2867 mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID)
2868 {
2869 DNSQuestion pktQ, *q;
2870 uDNS_GlobalInfo *u = &m->uDNS_info;
2871 const mDNSu8 *ptr = msg->data;
2872 LLQ_Info *llqInfo;
2873
2874 if (!msg->h.numQuestions) return mDNSfalse;
2875
2876 ptr = getQuestion(msg, ptr, end, 0, &pktQ);
2877 if (!ptr) return mDNSfalse;
2878 pktQ.uDNS_info.id = msg->h.id;
2879
2880 q = u->ActiveQueries;
2881 while (q)
2882 {
2883 llqInfo = q->uDNS_info.llq;
2884 if (q->LongLived &&
2885 llqInfo &&
2886 q->qnamehash == pktQ.qnamehash &&
2887 q->qtype == pktQ.qtype &&
2888 SameDomainName(&q->qname, &pktQ.qname))
2889 {
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)
2894 {
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)
2898 {
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; }
2901 }
2902 }
2903 }
2904 q = q->next;
2905 }
2906 return mDNSfalse;
2907 }
2908
2909 mDNSexport mDNSBool uDNS_IsActiveQuery(DNSQuestion *const question, uDNS_GlobalInfo *u)
2910 {
2911 DNSQuestion *q;
2912
2913 for (q = u->ActiveQueries; q; q = q->next)
2914 {
2915 if (q == question)
2916 {
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);
2920 return mDNStrue;
2921 }
2922 }
2923 return mDNSfalse;
2924 }
2925
2926 // stopLLQ happens IN ADDITION to stopQuery
2927 mDNSlocal void stopLLQ(mDNS *m, DNSQuestion *question)
2928 {
2929 LLQ_Info *info = question->uDNS_info.llq;
2930 (void)m; // unused
2931
2932 if (!question->LongLived) { LogMsg("ERROR: stopLLQ - LongLived flag not set"); return; }
2933 if (!info) { LogMsg("ERROR: stopLLQ - llq info is NULL"); return; }
2934
2935 switch (info->state)
2936 {
2937 case LLQ_UnInit:
2938 LogMsg("ERROR: stopLLQ - state LLQ_UnInit");
2939 //!!!KRS should we unlink info<->question here?
2940 return;
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;
2945 return;
2946 case LLQ_Established:
2947 case LLQ_Refresh:
2948 // refresh w/ lease 0
2949 sendLLQRefresh(m, question, 0);
2950 goto end;
2951 default:
2952 debugf("stopLLQ - silently discarding LLQ in state %d", info->state);
2953 goto end;
2954 }
2955
2956 end:
2957 if (info->NATMap) info->NATMap = mDNSfalse;
2958 CheckForUnreferencedLLQMapping(m);
2959 info->question = mDNSNULL;
2960 ufree(info);
2961 question->uDNS_info.llq = mDNSNULL;
2962 question->LongLived = mDNSfalse;
2963 }
2964
2965 mDNSexport mStatus uDNS_StopQuery(mDNS *const m, DNSQuestion *const question)
2966 {
2967 uDNS_GlobalInfo *u = &m->uDNS_info;
2968 DNSQuestion *qptr, *prev = mDNSNULL;
2969 CacheRecord *ka;
2970
2971 qptr = u->ActiveQueries;
2972 while (qptr)
2973 {
2974 if (qptr == question)
2975 {
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)
2981 {
2982 ka = question->uDNS_info.knownAnswers;
2983 question->uDNS_info.knownAnswers = question->uDNS_info.knownAnswers->next;
2984 ufree(ka);
2985 }
2986 if (prev) prev->next = question->next;
2987 else u->ActiveQueries = question->next;
2988 return mStatus_NoError;
2989 }
2990 prev = qptr;
2991 qptr = qptr->next;
2992 }
2993 LogMsg("uDNS_StopQuery: no such active query (%##s)", question->qname.c);
2994 return mStatus_UnknownErr;
2995 }
2996
2997 mDNSlocal mStatus startQuery(mDNS *const m, DNSQuestion *const question, mDNSBool internal)
2998 {
2999 uDNS_GlobalInfo *u = &m->uDNS_info;
3000 DNSMessage msg;
3001 mDNSu8 *endPtr;
3002 mStatus err = mStatus_NoError;
3003 mDNSAddr server;
3004
3005 //!!!KRS we should check if the question is already in our acivequestion list
3006 if (!ValidateDomainName(&question->qname))
3007 {
3008 LogMsg("Attempt to start query with invalid qname %##s %##s", question->qname.c, DNSTypeName(question->qtype));
3009 return mStatus_Invalid;
3010 }
3011
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;
3016
3017 // break here if its and LLQ
3018 if (question->LongLived) return startLLQ(m, question);
3019
3020 // else send the query to our server
3021 err = constructQueryMsg(&msg, &endPtr, question);
3022 if (err) return err;
3023
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))
3031 {
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); }
3034 }
3035
3036 return mStatus_NoError; // don't return transient errors to caller
3037 }
3038
3039 mDNSexport mStatus uDNS_StartQuery(mDNS *const m, DNSQuestion *const question)
3040 {
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);
3046 }
3047
3048 // explicitly set response handler
3049 mDNSlocal mStatus startInternalQuery(DNSQuestion *q, mDNS *m, InternalResponseHndlr callback, void *hndlrContext)
3050 {
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);
3056 }
3057
3058
3059
3060 // ***************************************************************************
3061 #if COMPILER_LIKES_PRAGMA_MARK
3062 #pragma mark - Domain -> Name Server Conversion
3063 #endif
3064
3065
3066 /* startGetZoneData
3067 *
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.
3073 *
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.
3079 *
3080 * Steps for deriving the zone name are as follows:
3081 *
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.
3084 *
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.
3087 *
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.)
3092 *
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.)
3095 */
3096
3097
3098 // state machine types and structs
3099 //
3100
3101 // state machine states
3102 typedef enum
3103 {
3104 init,
3105 lookupSOA,
3106 foundZone,
3107 lookupNS,
3108 foundNS,
3109 lookupA,
3110 foundA,
3111 lookupPort,
3112 foundPort,
3113 complete
3114 } ntaState;
3115
3116 // state machine actions
3117 typedef enum
3118 {
3119 smContinue, // continue immediately to next state
3120 smBreak, // break until next packet/timeout
3121 smError // terminal error - cleanup and abort
3122 } smAction;
3123
3124 typedef struct
3125 {
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
3129 mDNS *m;
3130 domainname zone; // left-hand-side of SOA record
3131 mDNSu16 zoneClass;
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;
3140 mDNSIPPort llqPort;
3141 AsyncOpCallback *callback; // caller specified function to be called upon completion
3142 void *callbackInfo;
3143 } ntaContext;
3144
3145
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);
3154
3155 // initialization
3156 mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdatePort, mDNSBool findLLQPort,
3157 AsyncOpCallback callback, void *callbackInfo)
3158 {
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;
3164 context->m = m;
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;
3171 }
3172
3173 // state machine entry routine
3174 mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *contextPtr)
3175 {
3176 AsyncOpResult result;
3177 ntaContext *context = (ntaContext*)contextPtr;
3178 smAction action;
3179
3180 // unused
3181 (void)m;
3182 (void)question;
3183
3184 // stop any active question
3185 if (context->questionActive)
3186 {
3187 uDNS_StopQuery(context->m, &context->question);
3188 context->questionActive = mDNSfalse;
3189 }
3190
3191 if (msg && msg->h.flags.b[2] >> 4 && msg->h.flags.b[2] >> 4 != kDNSFlag1_RC_NXDomain)
3192 {
3193 // rcode non-zero, non-nxdomain
3194 LogMsg("ERROR: getZoneData - received response w/ rcode %d", msg->h.flags.b[2] >> 4);
3195 goto error;
3196 }
3197
3198 switch (context->state)
3199 {
3200 case init:
3201 case lookupSOA:
3202 action = hndlLookupSOA(msg, end, context);
3203 if (action == smError) goto error;
3204 if (action == smBreak) return;
3205 case foundZone:
3206 case lookupNS:
3207 action = confirmNS(msg, end, context);
3208 if (action == smError) goto error;
3209 if (action == smBreak) return;
3210 case foundNS:
3211 case lookupA:
3212 action = lookupNSAddr(msg, end, context);
3213 if (action == smError) goto error;
3214 if (action == smBreak) return;
3215 case foundA:
3216 if (!context->findUpdatePort && !context->findLLQPort)
3217 {
3218 context->state = complete;
3219 break;
3220 }
3221 case lookupPort:
3222 action = hndlLookupPorts(msg, end, context);
3223 if (action == smError) goto error;
3224 if (action == smBreak) return;
3225 if (action == smContinue) context->state = complete;
3226 case foundPort:
3227 case complete: break;
3228 }
3229
3230 if (context->state != complete)
3231 {
3232 LogMsg("ERROR: getZoneData - exited state machine with state %d", context->state);
3233 goto error;
3234 }
3235
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);
3244 goto cleanup;
3245
3246 error:
3247 if (context && context->callback)
3248 context->callback(mStatus_UnknownErr, context->m, context->callbackInfo, mDNSNULL);
3249 cleanup:
3250 if (context && context->questionActive)
3251 {
3252 uDNS_StopQuery(context->m, &context->question);
3253 context->questionActive = mDNSfalse;
3254 }
3255 if (context) ufree(context);
3256 }
3257
3258 mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
3259 {
3260 mStatus err;
3261 LargeCacheRecord lcr;
3262 ResourceRecord *rr = &lcr.r.resrec;
3263 DNSQuestion *query = &context->question;
3264 const mDNSu8 *ptr;
3265
3266 if (msg)
3267 {
3268 // if msg contains SOA record in answer or authority sections, update context/state and return
3269 int i;
3270 ptr = LocateAnswers(msg, end);
3271 for (i = 0; i < msg->h.numAnswers; i++)
3272 {
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))
3276 {
3277 processSOA(context, rr);
3278 return smContinue;
3279 }
3280 }
3281 ptr = LocateAuthorities(msg, end);
3282 // SOA not in answers, check in authority
3283 for (i = 0; i < msg->h.numAuthorities; i++)
3284 {
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)
3288 {
3289 processSOA(context, rr);
3290 return smContinue;
3291 }
3292 }
3293 }
3294
3295 if (context->state != init && !context->curSOA->c[0])
3296 {
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);
3300 return smError;
3301 }
3302
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);
3307
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);
3315
3316 return smBreak; // break from state machine until we receive another packet
3317 }
3318
3319 mDNSlocal void processSOA(ntaContext *context, ResourceRecord *rr)
3320 {
3321 AssignDomainName(context->zone, rr->name);
3322 context->zoneClass = rr->rrclass;
3323 AssignDomainName(context->ns, rr->rdata->u.soa.mname);
3324 context->state = foundZone;
3325 }
3326
3327
3328 mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
3329 {
3330 DNSQuestion *query = &context->question;
3331 mStatus err;
3332 LargeCacheRecord lcr;
3333 const ResourceRecord *const rr = &lcr.r.resrec;
3334 const mDNSu8 *ptr;
3335 int i;
3336
3337 if (context->state == foundZone)
3338 {
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
3348 }
3349 else if (context->state == lookupNS)
3350 {
3351 ptr = LocateAnswers(msg, end);
3352 for (i = 0; i < msg->h.numAnswers; i++)
3353 {
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))
3358 {
3359 context->state = foundNS;
3360 return smContinue; // next routine will examine additionals section of A record
3361 }
3362 }
3363 LogMsg("ERROR: could not confirm existence of record %##s NS %##s", context->zone.c, context->ns.c);
3364 return smError;
3365 }
3366 else { LogMsg("ERROR: confirmNS - bad state %d", context->state); return smError; }
3367 }
3368
3369 mDNSlocal smAction queryNSAddr(ntaContext *context)
3370 {
3371 mStatus err;
3372 DNSQuestion *query = &context->question;
3373
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;
3381 return smBreak;
3382 }
3383
3384 mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
3385 {
3386 const mDNSu8 *ptr;
3387 int i;
3388 LargeCacheRecord lcr;
3389 ResourceRecord *rr = &lcr.r.resrec;
3390
3391 if (context->state == foundNS)
3392 {
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);
3396 if (!ptr)
3397 {
3398 LogMsg("ERROR: lookupNSAddr - LocateAdditionals returned NULL, expected %d additionals", msg->h.numAdditionals);
3399 return queryNSAddr(context);
3400 }
3401 else
3402 {
3403 for (i = 0; i < msg->h.numAdditionals; i++)
3404 {
3405 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
3406 if (!ptr)
3407 {
3408 LogMsg("ERROR: lookupNSAddr, Additionals - GetLargeResourceRecord returned NULL");
3409 return queryNSAddr(context);
3410 }
3411 if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, &rr->name))
3412 {
3413 context->addr.NotAnInteger = rr->rdata->u.ipv4.NotAnInteger;
3414 context->state = foundA;
3415 return smContinue;
3416 }
3417 }
3418 }
3419 // no A record in Additionals - query the server
3420 return queryNSAddr(context);
3421 }
3422 else if (context->state == lookupA)
3423 {
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++)
3427 {
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))
3431 {
3432 context->addr.NotAnInteger = rr->rdata->u.ipv4.NotAnInteger;
3433 context->state = foundA;
3434 return smContinue;
3435 }
3436 }
3437 LogMsg("ERROR: lookupNSAddr: Address record not found in answer section");
3438 return smError;
3439 }
3440 else { LogMsg("ERROR: lookupNSAddr - bad state %d", context->state); return smError; }
3441 }
3442
3443 mDNSlocal smAction lookupDNSPort(DNSMessage *msg, const mDNSu8 *end, ntaContext *context, char *portName, mDNSIPPort *port)
3444 {
3445 int i;
3446 LargeCacheRecord lcr;
3447 const mDNSu8 *ptr;
3448 DNSQuestion *q;
3449 mStatus err;
3450
3451 if (context->state == lookupPort) // we've already issued the query
3452 {
3453 if (!msg) { LogMsg("ERROR: hndlLookupUpdatePort - NULL message"); return smError; }
3454 ptr = LocateAnswers(msg, end);
3455 for (i = 0; i < msg->h.numAnswers; i++)
3456 {
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))
3460 {
3461 port->NotAnInteger = lcr.r.resrec.rdata->u.srv.port.NotAnInteger;
3462 context->state = foundPort;
3463 return smContinue;
3464 }
3465 }
3466 debugf("hndlLookupUpdatePort - no answer for type %s", portName);
3467 port->NotAnInteger = 0;
3468 context->state = foundPort;
3469 return smContinue;
3470 }
3471
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
3483 }
3484
3485 mDNSlocal smAction hndlLookupPorts(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
3486 {
3487 smAction action;
3488
3489 if (context->findUpdatePort && !context->updatePort.NotAnInteger)
3490 {
3491 action = lookupDNSPort(msg, end, context, UPDATE_PORT_NAME, &context->updatePort);
3492 if (action != smContinue) return action;
3493 }
3494 if (context->findLLQPort && !context->llqPort.NotAnInteger)
3495 return lookupDNSPort(msg, end, context, LLQ_PORT_NAME, &context->llqPort);
3496
3497 return smContinue;
3498 }
3499
3500
3501 // ***************************************************************************
3502 #if COMPILER_LIKES_PRAGMA_MARK
3503 #pragma mark - Truncation Handling
3504 #endif
3505
3506 typedef struct
3507 {
3508 DNSQuestion *question;
3509 DNSMessage reply;
3510 mDNSu16 replylen;
3511 int nread;
3512 mDNS *m;
3513 } tcpInfo_t;
3514
3515 // issue queries over a conected socket
3516 mDNSlocal void conQueryCallback(int sd, void *context, mDNSBool ConnectionEstablished)
3517 {
3518 mStatus err = 0;
3519 char msgbuf[356]; // 96 (hdr) + 256 (domain) + 4 (class/type)
3520 DNSMessage *msg;
3521 mDNSu8 *end;
3522 tcpInfo_t *info = (tcpInfo_t *)context;
3523 DNSQuestion *question = info->question;
3524 int n;
3525 mDNS *m = info->m;
3526
3527 mDNS_Lock(m);
3528
3529 if (ConnectionEstablished)
3530 {
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; }
3538 }
3539 else
3540 {
3541 if (!info->nread)
3542 {
3543 // read msg len
3544 n = mDNSPlatformReadTCP(sd, &info->replylen, 2);
3545 if (n != 2)
3546 {
3547 LogMsg("ERROR:conQueryCallback - attempt to read message length failed (read returned %d)", n);
3548 goto error;
3549 }
3550 }
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; }
3553 info->nread += n;
3554 if (info->nread == info->replylen)
3555 {
3556 // finished reading message
3557 uDNS_ReceiveMsg(m, &info->reply, ((mDNSu8 *)&info->reply) + info->replylen, mDNSNULL, zeroIPPort, mDNSNULL, zeroIPPort, question->InterfaceID);
3558 mDNSPlatformTCPCloseConnection(sd);
3559 ufree(info);
3560 }
3561 }
3562
3563 mDNS_Unlock(m);
3564 return;
3565
3566 error:
3567 mDNSPlatformTCPCloseConnection(sd);
3568 ufree(info);
3569 mDNS_Unlock(m);
3570 }
3571
3572 mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question, const mDNSAddr *src, mDNS *m)
3573 {
3574 mStatus connectionStatus;
3575 uDNS_QuestionInfo *info = &question->uDNS_info;
3576 int sd;
3577 tcpInfo_t *context;
3578
3579 if (!src) { LogMsg("hndlTruncatedAnswer: TCP DNS response had TC bit set: ignoring"); return; }
3580
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;
3585 context->m = m;
3586 info->id = newMessageID(&m->uDNS_info);
3587
3588 connectionStatus = mDNSPlatformTCPConnect(src, UnicastDNSPort, question->InterfaceID, conQueryCallback, context, &sd);
3589 if (connectionStatus == mStatus_ConnEstablished) // manually invoke callback if connection completes
3590 {
3591 conQueryCallback(sd, context, mDNStrue);
3592 return;
3593 }
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?
3597 }
3598
3599
3600 // ***************************************************************************
3601 #if COMPILER_LIKES_PRAGMA_MARK
3602 #pragma mark - Dynamic Updates
3603 #endif
3604
3605
3606
3607 mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr)
3608 {
3609 DNSMessage msg;
3610 mDNSu8 *ptr = msg.data;
3611 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
3612 uDNS_GlobalInfo *u = &m->uDNS_info;
3613 mDNSOpaque16 id;
3614 uDNS_RegInfo *regInfo = &rr->uDNS_info;
3615 mStatus err = mStatus_UnknownErr;
3616
3617 id = newMessageID(u);
3618 InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
3619 rr->uDNS_info.id.NotAnInteger = id.NotAnInteger;
3620
3621 // set zone
3622 ptr = putZone(&msg, ptr, end, &regInfo->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
3623 if (!ptr) goto error;
3624
3625 if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique || rr->uDNS_info.state == regState_Refresh)
3626 {
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;
3631 }
3632 else if (rr->resrec.RecordType != kDNSRecordTypeShared)
3633 {
3634 ptr = putPrereqNameNotInUse(&rr->resrec.name, &msg, ptr, end);
3635 if (!ptr) goto error;
3636 }
3637
3638 ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl);
3639 if (!ptr) goto error;
3640
3641 if (rr->uDNS_info.lease)
3642 { ptr = putUpdateLease(&msg, ptr, kLLQ_DefLease); if (!ptr) goto error; }
3643
3644 rr->uDNS_info.expire = -1;
3645
3646 err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &regInfo->ns, regInfo->port, -1, GetAuthInfoForZone(u, &regInfo->zone));
3647 if (err) LogMsg("ERROR: sendRecordRegistration - mDNSSendDNSMessage - %ld", err);
3648
3649 SetRecordRetry(m, rr);
3650
3651 if (regInfo->state != regState_Refresh) regInfo->state = regState_Pending;
3652 return;
3653
3654 error:
3655 LogMsg("sendRecordRegistration: Error formatting message");
3656 if (rr->uDNS_info.state != regState_Unregistered)
3657 {
3658 unlinkAR(&u->RecordRegistrations, rr);
3659 rr->uDNS_info.state = regState_Unregistered;
3660 }
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
3665 }
3666
3667 mDNSlocal void RecordRegistrationCallback(mStatus err, mDNS *const m, void *authPtr, const AsyncOpResult *result)
3668 {
3669 AuthRecord *newRR = (AuthRecord*)authPtr;
3670 const zoneData_t *zoneData = mDNSNULL;
3671 uDNS_GlobalInfo *u = &m->uDNS_info;
3672 AuthRecord *ptr;
3673
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; }
3678
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;
3683
3684 if (newRR->uDNS_info.state == regState_Cancelled)
3685 {
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);
3691 return;
3692 }
3693
3694 if (result->type != zoneDataResult)
3695 {
3696 LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type);
3697 goto error;
3698 }
3699
3700 if (newRR->resrec.rrclass != zoneData->zoneClass)
3701 {
3702 LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)",
3703 newRR->resrec.rrclass, zoneData->zoneClass);
3704 goto error;
3705 }
3706
3707 // cache zone data
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;
3712 else
3713 {
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;
3717 }
3718
3719 sendRecordRegistration(m, newRR);
3720 return;
3721
3722 error:
3723 if (newRR->uDNS_info.state != regState_Unregistered)
3724 {
3725 unlinkAR(&u->RecordRegistrations, newRR);
3726 newRR->uDNS_info.state = regState_Unregistered;
3727 }
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
3733 }
3734
3735 mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs)
3736 {
3737 DNSMessage msg;
3738 mDNSu8 *ptr = msg.data;
3739 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
3740 uDNS_GlobalInfo *u = &m->uDNS_info;
3741 mDNSOpaque16 id;
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;
3747 domainname target;
3748 AuthRecord *srv = &srs->RR_SRV;
3749
3750 id = newMessageID(u);
3751 InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
3752
3753 // setup resource records
3754 SetNewRData(&srs->RR_PTR.resrec, mDNSNULL, 0);
3755 SetNewRData(&srs->RR_TXT.resrec, mDNSNULL, 0);
3756
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))
3760 {
3761 privport = srv->resrec.rdata->u.srv.port;
3762 srv->resrec.rdata->u.srv.port = nat->PublicPort;
3763 mapped = mDNStrue;
3764 }
3765
3766 // construct update packet
3767 // set zone
3768 ptr = putZone(&msg, ptr, end, &rInfo->zone, mDNSOpaque16fromIntVal(srv->resrec.rrclass));
3769 if (!ptr) goto error;
3770
3771 if (srs->uDNS_info.TestForSelfConflict)
3772 {
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;
3776 }
3777
3778 else if (srs->uDNS_info.state != regState_Refresh)
3779 {
3780 // use SRV name for prereq
3781 ptr = putPrereqNameNotInUse(&srv->resrec.name, &msg, ptr, end);
3782 if (!ptr) goto error;
3783 }
3784
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;
3788
3789 if (!GetServiceTarget(u, srv, &target))
3790 {
3791 debugf("Couldn't get target for service %##s", srv->resrec.name.c);
3792 rInfo->state = regState_NoTarget;
3793 return;
3794 }
3795 if (!SameDomainName(&target, &srv->resrec.rdata->u.srv.target))
3796 {
3797 AssignDomainName(srv->resrec.rdata->u.srv.target, target);
3798 SetNewRData(&srv->resrec, mDNSNULL, 0);
3799 }
3800
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.
3804
3805 if (srs->uDNS_info.lease)
3806 { ptr = putUpdateLease(&msg, ptr, kLLQ_DefLease); if (!ptr) goto error; }
3807
3808 srs->uDNS_info.expire = -1;
3809
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; }
3812
3813 if (rInfo->state != regState_Refresh)
3814 rInfo->state = regState_Pending;
3815
3816 SetRecordRetry(m, &srs->RR_SRV);
3817 rInfo->id.NotAnInteger = id.NotAnInteger;
3818 if (mapped) srv->resrec.rdata->u.srv.port = privport;
3819 return;
3820
3821 error:
3822 LogMsg("SendServiceRegistration - Error formatting message");
3823 if (mapped) srv->resrec.rdata->u.srv.port = privport;
3824 unlinkSRS(u, srs);
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
3831 }
3832
3833 mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srsPtr, const AsyncOpResult *result)
3834 {
3835 ServiceRecordSet *srs = (ServiceRecordSet *)srsPtr;
3836 const zoneData_t *zoneData = mDNSNULL;
3837 uDNS_GlobalInfo *u = &m->uDNS_info;
3838
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;
3842
3843 if (result->type != zoneDataResult)
3844 {
3845 LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type);
3846 goto error;
3847 }
3848
3849 if (srs->uDNS_info.state == regState_Cancelled)
3850 {
3851 // client cancelled registration while fetching zone data
3852 srs->uDNS_info.state = regState_Unregistered;
3853 unlinkSRS(u, srs);
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
3857 return;
3858 }
3859
3860 if (srs->RR_SRV.resrec.rrclass != zoneData->zoneClass)
3861 {
3862 LogMsg("Service %##s - class does not match zone", srs->RR_SRV.resrec.name.c);
3863 goto error;
3864 }
3865 // cache zone data
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;
3870 else
3871 {
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;
3875 }
3876 SendServiceRegistration(m, srs);
3877 return;
3878
3879 error:
3880 unlinkSRS(u, 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
3887 }
3888
3889 mDNSlocal mStatus SetupRecordRegistration(mDNS *m, AuthRecord *rr)
3890 {
3891 domainname *target = GetRRDomainNameTarget(&rr->resrec);
3892 AuthRecord *ptr = m->uDNS_info.RecordRegistrations;
3893
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; }
3896
3897 if (rr->uDNS_info.state == regState_FetchingZoneData ||
3898 rr->uDNS_info.state == regState_Pending ||
3899 rr->uDNS_info.state == regState_Registered)
3900 {
3901 LogMsg("Requested double-registration of physical record %##s type %d",
3902 rr->resrec.name.c, rr->resrec.rrtype);
3903 return mStatus_AlreadyRegistered;
3904 }
3905
3906 rr->resrec.rdlength = GetRDLength(&rr->resrec, mDNSfalse);
3907 rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue);
3908
3909 if (!ValidateDomainName(&rr->resrec.name))
3910 {
3911 LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr));
3912 return mStatus_Invalid;
3913 }
3914
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))
3917 {
3918 LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr));
3919 return mStatus_Invalid;
3920 }
3921
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;
3925
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;
3930
3931 return mStatus_NoError;
3932 }
3933
3934 mDNSexport mStatus uDNS_RegisterRecord(mDNS *const m, AuthRecord *const rr)
3935 {
3936 mStatus err = SetupRecordRegistration(m, rr);
3937 if (err) return err;
3938 else return startGetZoneData(&rr->resrec.name, m, mDNStrue, mDNSfalse, RecordRegistrationCallback, rr);
3939 }
3940
3941 mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
3942 {
3943 uDNS_GlobalInfo *u = &m->uDNS_info;
3944 DNSMessage msg;
3945 mDNSu8 *ptr = msg.data;
3946 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
3947 mStatus err;
3948
3949 InitializeDNSMessage(&msg.h, rr->uDNS_info.id, UpdateReqFlags);
3950
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;
3954
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);
3957
3958 SetRecordRetry(m, rr);
3959 rr->uDNS_info.state = regState_DeregPending;
3960 return;
3961
3962 error:
3963 LogMsg("Error: SendRecordDeregistration - could not contruct deregistration packet");
3964 unlinkAR(&u->RecordRegistrations, rr);
3965 rr->uDNS_info.state = regState_Unregistered;
3966 }
3967
3968
3969
3970 mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr)
3971 {
3972 uDNS_GlobalInfo *u = &m->uDNS_info;
3973 NATTraversalInfo *n = rr->uDNS_info.NATinfo;
3974
3975 switch (rr->uDNS_info.state)
3976 {
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;
3986 break;
3987 case regState_ExtraQueued:
3988 rr->uDNS_info.state = regState_Unregistered;
3989 break;
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:
4001 break;
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;
4014 }
4015
4016 if (rr->uDNS_info.state == regState_Unregistered)
4017 {
4018 // unlink and deliver memfree
4019
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;
4025 }
4026
4027 if (n) FreeNATInfo(m, n);
4028 rr->uDNS_info.NATinfo = mDNSNULL;
4029
4030 SendRecordDeregistration(m, rr);
4031 return mStatus_NoError;
4032 }
4033
4034 // register a service already in list with initialized state
4035 mDNSlocal mStatus RegisterService(mDNS *m, ServiceRecordSet *srs)
4036 {
4037 uDNS_RegInfo *info = &srs->uDNS_info;
4038
4039 srs->RR_SRV.resrec.rroriginalttl = 3;
4040 srs->RR_TXT.resrec.rroriginalttl = 3;
4041 srs->RR_PTR.resrec.rroriginalttl = 3;
4042
4043 info->lease = mDNStrue;
4044
4045 if (srs->RR_SRV.resrec.rdata->u.srv.port.NotAnInteger && MapServicePort(m))
4046 {
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;
4051 }
4052
4053 info->state = regState_FetchingZoneData;
4054 return startGetZoneData(&srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
4055 }
4056
4057 mDNSexport mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs)
4058 {
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;
4065 *p = srs;
4066 srs->next = mDNSNULL;
4067 return RegisterService(m, srs);
4068 }
4069
4070 mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
4071 {
4072 uDNS_RegInfo *info = &srs->uDNS_info;
4073 uDNS_GlobalInfo *u = &m->uDNS_info;
4074 DNSMessage msg;
4075 mDNSOpaque16 id;
4076 mDNSu8 *ptr = msg.data;
4077 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
4078 mStatus err = mStatus_UnknownErr;
4079
4080 id = newMessageID(u);
4081 InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
4082
4083 // put zone
4084 ptr = putZone(&msg, ptr, end, &info->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
4085 if (!ptr) { LogMsg("ERROR: SendServiceDeregistration - putZone"); goto error; }
4086
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;
4089
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; }
4092
4093 SetRecordRetry(m, &srs->RR_SRV);
4094 info->id.NotAnInteger = id.NotAnInteger;
4095 info->state = regState_DeregPending;
4096
4097 return;
4098
4099 error:
4100 unlinkSRS(u, srs);
4101 info->state = regState_Unregistered;
4102 }
4103
4104 mDNSexport mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs)
4105 {
4106 uDNS_GlobalInfo *u = &m->uDNS_info;
4107 NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
4108 AuthRecord **r = &u->RecordRegistrations;
4109 char *errmsg = "Unknown State";
4110
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
4113 while (*r)
4114 {
4115 if (SameDomainName(&srs->RR_SRV.resrec.name, &(*r)->resrec.name)) *r = (*r)->next;
4116 else r = &(*r)->next;
4117 }
4118
4119 // don't re-register with a new target following deregistration
4120 srs->uDNS_info.LostTarget = srs->uDNS_info.SRVUpdateDeferred = mDNSfalse;
4121
4122 switch (srs->uDNS_info.state)
4123 {
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); }
4128 unlinkSRS(u, srs);
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";
4136 goto error;
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:
4153 unlinkSRS(u, srs);
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)";
4166 goto error;
4167 }
4168
4169 error:
4170 LogMsg("Error, uDNS_DeregisterService: %s", errmsg);
4171 return mStatus_BadReferenceErr;
4172 }
4173
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)
4176 {
4177 DNSMessage msg;
4178 mDNSu8 *ptr = msg.data;
4179 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
4180 uDNS_GlobalInfo *u = &m->uDNS_info;
4181 mDNSOpaque16 id;
4182 mStatus err = mStatus_UnknownErr;
4183
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;
4188
4189 // set zone
4190 ptr = putZone(&msg, ptr, end, &info->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
4191 if (!ptr) goto error;
4192
4193 // delete the original record
4194 ptr = putDeletionRecord(&msg, ptr, &rr->resrec);
4195 if (!ptr) goto error;
4196
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)
4202
4203 if (info->lease)
4204 { ptr = putUpdateLease(&msg, ptr, kLLQ_DefLease); if (!ptr) goto error; }
4205
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);
4209
4210 //!!! Update this when we implement retransmission for services
4211 SetRecordRetry(m, rr);
4212
4213 rr->uDNS_info.state = regState_UpdatePending;
4214 if (&rr->uDNS_info != info) info->state = regState_UpdatePending; // set parent SRS
4215 return;
4216
4217 error:
4218 LogMsg("ERROR: SendRecordUpdate. Error formatting update message.");
4219 info ->state = regState_Registered;
4220 }
4221
4222 mDNSexport mStatus uDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra)
4223 {
4224 mStatus err = mStatus_UnknownErr;
4225
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
4228
4229 if (sr->uDNS_info.state == regState_Registered || sr->uDNS_info.state == regState_Refresh)
4230 err = uDNS_RegisterRecord(m, &extra->r);
4231 else
4232 {
4233 err = SetupRecordRegistration(m, &extra->r);
4234 extra->r.uDNS_info.state = regState_ExtraQueued;
4235 }
4236
4237 if (!err)
4238 {
4239 extra->next = sr->Extras;
4240 sr->Extras = extra;
4241 }
4242 return err;
4243 }
4244
4245 mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr)
4246 {
4247 uDNS_GlobalInfo *u = &m->uDNS_info;
4248 ServiceRecordSet *sptr, *parent = mDNSNULL;
4249 AuthRecord *rptr;
4250 uDNS_RegInfo *info = mDNSNULL;
4251
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; }
4255
4256 if (!parent)
4257 {
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; }
4261 }
4262
4263 if (!info) goto unreg_error;
4264
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;
4270
4271 switch(info->state)
4272 {
4273 case regState_DeregPending:
4274 case regState_DeregDeferred:
4275 case regState_Cancelled:
4276 case regState_Unregistered:
4277 // not actively registered
4278 goto unreg_error;
4279
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;
4286
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;
4293
4294 case regState_Registered:
4295 SendRecordUpdate(m, rr, info);
4296 return mStatus_NoError;
4297
4298 case regState_NoTarget:
4299 LogMsg("Bad state (regState_NoTarget)"); return mStatus_UnknownErr; // state for service records only
4300 }
4301
4302 unreg_error:
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;
4306 }
4307
4308
4309 // ***************************************************************************
4310 #if COMPILER_LIKES_PRAGMA_MARK
4311 #pragma mark - Periodic Execution Routines
4312 #endif
4313
4314
4315 mDNSlocal mDNSs32 CheckNATMappings(mDNS *m, mDNSs32 timenow)
4316 {
4317 NATTraversalInfo *ptr, *cur;
4318 mDNSs32 nextevent;
4319
4320 ptr = m->uDNS_info.NATTraversals;
4321 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4322
4323 while (ptr)
4324 {
4325 cur = ptr;
4326 ptr = ptr->next;
4327 if (cur->retry - timenow < 0)
4328 {
4329 if (cur->state == NATState_Established) RefreshNATMapping(cur, m);
4330 else if (cur->state == NATState_Request || cur->state == NATState_Refresh)
4331 {
4332 if (cur->ntries >= NATMAP_MAX_TRIES) cur->ReceiveResponse(cur, m, mDNSNULL, 0); // may invalidate "cur"
4333 else SendNATMsg(cur, m);
4334 }
4335 }
4336 else if (cur->retry - nextevent < 0) nextevent = cur->retry;
4337 }
4338 return nextevent;
4339 }
4340
4341 mDNSlocal mDNSs32 CheckQueries(mDNS *m, mDNSs32 timenow)
4342 {
4343 DNSQuestion *q;
4344 uDNS_GlobalInfo *u = &m->uDNS_info;
4345 LLQ_Info *llq;
4346 mDNSs32 sendtime;
4347 mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4348 DNSMessage msg;
4349 mStatus err;
4350 mDNSu8 *end;
4351 uDNS_QuestionInfo *info;
4352
4353 u->CurrentQuery = u->ActiveQueries;
4354 while (u->CurrentQuery)
4355 {
4356 q = u->CurrentQuery;
4357 info = &q->uDNS_info;
4358 llq = info->llq;
4359
4360 if (!info->internal && ((!q->LongLived && !info->Answered) || (llq && llq->state < LLQ_Established)) &&
4361 info->RestartTime + RESTART_GOODBYE_DELAY - timenow < 0)
4362 {
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)
4365 {
4366 CacheRecord *cr = info->knownAnswers;
4367 info->knownAnswers = info->knownAnswers->next;
4368
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
4372 ufree(cr);
4373 if (q != u->CurrentQuery) { debugf("CheckQueries - question removed via callback."); break; }
4374 }
4375 }
4376 if (q != u->CurrentQuery) continue;
4377
4378 if (q->LongLived && llq->state != LLQ_Poll)
4379 {
4380 if (llq->state >= LLQ_InitialRequest && llq->state <= LLQ_Established)
4381 {
4382 if (llq->retry - timenow < 0)
4383 {
4384 // sanity check to avoid packet flood bugs
4385 if (!llq->retry)
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); }
4395 }
4396 else if (llq->retry - nextevent < 0) nextevent = llq->retry;
4397 }
4398 }
4399 else
4400 {
4401 sendtime = q->LastQTime + q->ThisQInterval;
4402 if (sendtime - timenow < 0)
4403 {
4404 mDNSAddr server;
4405 if (GetServerForName(&m->uDNS_info, &q->qname, &server))
4406 {
4407 err = constructQueryMsg(&msg, &end, q);
4408 if (err) LogMsg("Error: uDNS_Idle - constructQueryMsg. Skipping question %##s", q->qname.c);
4409 else
4410 {
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;
4415 }
4416 }
4417 }
4418 else if (sendtime - nextevent < 0) nextevent = sendtime;
4419 }
4420 u->CurrentQuery = u->CurrentQuery->next;
4421 }
4422 return nextevent;
4423 }
4424
4425 mDNSlocal mDNSs32 CheckRecordRegistrations(mDNS *m, mDNSs32 timenow)
4426 {
4427 AuthRecord *rr;
4428 uDNS_RegInfo *rInfo;
4429 uDNS_GlobalInfo *u = &m->uDNS_info;
4430 mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4431
4432 //!!!KRS list should be pre-sorted by expiration
4433 for (rr = u->RecordRegistrations; rr; rr = rr->next)
4434 {
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)
4437 {
4438 if (rr->LastAPTime + rr->ThisAPInterval - timenow < 0)
4439 {
4440 #if MDNS_DEBUGMSGS
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);
4446 #endif
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);
4451 }
4452 if (rr->LastAPTime + rr->ThisAPInterval - nextevent < 0) nextevent = rr->LastAPTime + rr->ThisAPInterval;
4453 }
4454 if (rInfo->lease && rInfo->state == regState_Registered && rInfo->expire > 0)
4455 {
4456 if (rInfo->expire - timenow < 0)
4457 {
4458 debugf("refreshing record %##s", rr->resrec.name.c);
4459 rInfo->state = regState_Refresh;
4460 sendRecordRegistration(m, rr);
4461 }
4462 if (rInfo->expire - nextevent < 0) nextevent = rInfo->expire;
4463 }
4464 }
4465 return nextevent;
4466 }
4467
4468 mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m, mDNSs32 timenow)
4469 {
4470 ServiceRecordSet *s = m->uDNS_info.ServiceRegistrations;
4471 uDNS_RegInfo *rInfo;
4472 mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4473
4474 // Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery
4475 while (s)
4476 {
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
4480 s = s->next;
4481
4482 rInfo = &srs->uDNS_info;
4483 if (rInfo->state == regState_Pending || rInfo->state == regState_DeregPending || rInfo->state == regState_DeregDeferred || rInfo->state == regState_Refresh)
4484 {
4485 if (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval - timenow < 0)
4486 {
4487 #if MDNS_DEBUGMSGS
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);
4493 #endif
4494 if (rInfo->state == regState_DeregPending) { SendServiceDeregistration(m, srs); continue; }
4495 else SendServiceRegistration (m, srs);
4496 }
4497 if (nextevent - srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval > 0)
4498 nextevent = srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval;
4499 }
4500
4501 if (rInfo->lease && rInfo->state == regState_Registered && rInfo->expire > 0)
4502 {
4503 if (rInfo->expire - timenow < 0)
4504 {
4505 debugf("refreshing service %##s", srs->RR_SRV.resrec.name.c);
4506 rInfo->state = regState_Refresh;
4507 SendServiceRegistration(m, srs);
4508 }
4509 if (rInfo->expire - nextevent < 0) nextevent = rInfo->expire;
4510 }
4511 }
4512 return nextevent;
4513 }
4514
4515 mDNSexport void uDNS_Execute(mDNS *const m)
4516 {
4517 uDNS_GlobalInfo *u = &m->uDNS_info;
4518 mDNSs32 nexte, timenow = mDNSPlatformTimeNow(m);
4519
4520 u->nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4521
4522 nexte = CheckNATMappings(m, timenow);
4523 if (nexte - u->nextevent < 0) u->nextevent = nexte;
4524
4525 nexte = CheckQueries(m, timenow);
4526 if (nexte - u->nextevent < 0) u->nextevent = nexte;
4527
4528 nexte = CheckRecordRegistrations(m, timenow);
4529 if (nexte - u->nextevent < 0) u->nextevent = nexte;
4530
4531 nexte = CheckServiceRegistrations(m, timenow);
4532 if (nexte - u->nextevent < 0) u->nextevent = nexte;
4533
4534 }
4535
4536 // ***************************************************************************
4537 #if COMPILER_LIKES_PRAGMA_MARK
4538 #pragma mark - Startup, Shutdown, and Sleep
4539 #endif
4540
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.
4544
4545 mDNSlocal void SuspendLLQs(mDNS *m, mDNSBool DeregisterActive)
4546 {
4547 DNSQuestion *q;
4548 LLQ_Info *llq;
4549 for (q = m->uDNS_info.ActiveQueries; q; q = q->next)
4550 {
4551 llq = q->uDNS_info.llq;
4552 if (q->LongLived && llq)
4553 {
4554 if (llq->state == LLQ_GetZoneInfo)
4555 {
4556 debugf("Marking %##s suspend-deferred", q->qname.c);
4557 llq->state = LLQ_SuspendDeferred; // suspend once we're done getting zone info
4558 }
4559 else if (llq->state < LLQ_Suspended)
4560 {
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;
4565 ubzero(llq->id, 8);
4566 }
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
4569 }
4570 }
4571 CheckForUnreferencedLLQMapping(m);
4572 }
4573
4574 mDNSlocal void RestartQueries(mDNS *m)
4575 {
4576 uDNS_GlobalInfo *u = &m->uDNS_info;
4577 DNSQuestion *q;
4578 LLQ_Info *llqInfo;
4579 mDNSs32 timenow = mDNSPlatformTimeNow(m);
4580
4581 u->CurrentQuery = u->ActiveQueries;
4582 while (u->CurrentQuery)
4583 {
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;
4589 if (q->LongLived)
4590 {
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)
4593 {
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
4597 }
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)
4601 {
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);
4607 }
4608 }
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)
4610 }
4611 }
4612
4613 mDNSexport void mDNS_UpdateLLQs(mDNS *m)
4614 {
4615 uDNS_GlobalInfo *u = &m->uDNS_info;
4616
4617 mDNS_Lock(m);
4618 if (u->LLQNatInfo)
4619 {
4620 NATTraversalInfo *nat = u->LLQNatInfo;
4621 u->LLQNatInfo = mDNSNULL;
4622 DeleteNATPortMapping(m, nat, mDNSNULL);
4623 }
4624 SuspendLLQs(m, mDNStrue);
4625 RestartQueries(m);
4626 mDNS_Unlock(m);
4627 }
4628
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.
4633
4634
4635
4636 mDNSlocal void SleepRecordRegistrations(mDNS *m)
4637 {
4638 DNSMessage msg;
4639 AuthRecord *rr = m->uDNS_info.RecordRegistrations;
4640 mDNSs32 timenow = mDNSPlatformTimeNow(m);
4641
4642 while (rr)
4643 {
4644 if (rr->uDNS_info.state == regState_Registered ||
4645 rr->uDNS_info.state == regState_Refresh)
4646 {
4647 mDNSu8 *ptr = msg.data, *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
4648 InitializeDNSMessage(&msg.h, newMessageID(&m->uDNS_info), UpdateReqFlags);
4649
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; }
4655
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;
4660 }
4661 rr = rr->next;
4662 }
4663 }
4664
4665 mDNSlocal void WakeRecordRegistrations(mDNS *m)
4666 {
4667 mDNSs32 timenow = mDNSPlatformTimeNow(m);
4668 AuthRecord *rr = m->uDNS_info.RecordRegistrations;
4669
4670 while (rr)
4671 {
4672 if (rr->uDNS_info.state == regState_Refresh)
4673 {
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;
4677 }
4678 rr = rr->next;
4679 }
4680 }
4681
4682 mDNSlocal void SleepServiceRegistrations(mDNS *m)
4683 {
4684 mDNSs32 timenow = mDNSPlatformTimeNow(m);
4685 ServiceRecordSet *srs = m->uDNS_info.ServiceRegistrations;
4686 while(srs)
4687 {
4688 if (srs->uDNS_info.state == regState_Registered ||
4689 srs->uDNS_info.state == regState_Refresh)
4690 {
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;
4698 }
4699 srs = srs->next;
4700 }
4701 }
4702
4703 mDNSlocal void WakeServiceRegistrations(mDNS *m)
4704 {
4705 mDNSs32 timenow = mDNSPlatformTimeNow(m);
4706 ServiceRecordSet *srs = m->uDNS_info.ServiceRegistrations;
4707 while(srs)
4708 {
4709 if (srs->uDNS_info.state == regState_Refresh)
4710 {
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;
4714 }
4715 srs = srs->next;
4716 }
4717 }
4718
4719 mDNSexport void uDNS_Init(mDNS *const m)
4720 {
4721 mDNSPlatformMemZero(&m->uDNS_info, sizeof(uDNS_GlobalInfo));
4722 m->uDNS_info.nextevent = m->timenow_last + 0x78000000;
4723 }
4724
4725 mDNSexport void uDNS_Sleep(mDNS *m)
4726 {
4727 SuspendLLQs(m, mDNStrue);
4728 SleepServiceRegistrations(m);
4729 SleepRecordRegistrations(m);
4730 }
4731
4732 mDNSexport void uDNS_Wake(mDNS *m)
4733 {
4734 RestartQueries(m);
4735 WakeServiceRegistrations(m);
4736 WakeRecordRegistrations(m);
4737 }