]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSCore/uDNS.c
c4eda13b168bb6eeddbd544336dbc72d9fcf567a
[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.183 2005/01/27 22:57:55 cheshire
27 Fix compile errors on gcc4
28
29 Revision 1.182 2005/01/25 18:55:05 ksekar
30 Shortened log message
31
32 Revision 1.181 2005/01/25 02:17:32 cheshire
33 <rdar://problem/3971263> Don't use query ID zero in uDNS queries
34
35 Revision 1.180 2005/01/19 21:01:54 ksekar
36 <rdar://problem/3955355> uDNS needs to support subtype registration and browsing
37
38 Revision 1.179 2005/01/19 19:15:35 ksekar
39 Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
40
41 Revision 1.178 2005/01/17 23:47:58 cheshire
42 <rdar://problem/3904954> Wide-area services not found on little-endian
43
44 Revision 1.177 2005/01/17 23:41:26 cheshire
45 Fix compile errors
46
47 Revision 1.176 2005/01/17 21:03:04 cheshire
48 <rdar://problem/3904954> Wide-area services not found on little-endian
49
50 Revision 1.175 2005/01/15 00:56:41 ksekar
51 <rdar://problem/3954575> Unicast services don't disappear when logging
52 out of VPN
53
54 Revision 1.174 2005/01/14 18:44:28 ksekar
55 <rdar://problem/3954609> mDNSResponder is crashing when changing domains
56
57 Revision 1.173 2005/01/14 18:34:22 ksekar
58 <rdar://problem/3954571> Services registered outside of firewall don't succeed after location change
59
60 Revision 1.172 2005/01/11 22:50:52 ksekar
61 Fixed constant naming (was using kLLQ_DefLease for update leases)
62
63 Revision 1.171 2005/01/10 04:52:49 ksekar
64 Changed LogMsg to debugf
65
66 Revision 1.170 2005/01/08 00:50:05 ksekar
67 Fixed spelling mistake in log msg
68
69 Revision 1.169 2005/01/08 00:42:18 ksekar
70 <rdar://problem/3922758> Clean up syslog messages
71
72 Revision 1.168 2004/12/23 23:22:47 ksekar
73 <rdar://problem/3933606> Unicast known answers "name" pointers point to garbage stack memory
74
75 Revision 1.167 2004/12/22 22:25:47 ksekar
76 <rdar://problem/3734265> NATPMP: handle location changes
77
78 Revision 1.166 2004/12/22 00:04:12 ksekar
79 <rdar://problem/3930324> mDNSResponder crashing in ReceivePortMapReply
80
81 Revision 1.165 2004/12/18 03:14:22 cheshire
82 DblNAT -> DoubleNAT
83
84 Revision 1.164 2004/12/17 03:55:40 ksekar
85 Don't use -1 as special meaning for expiration timer (it is a valid
86 value, and is redundant with our state variables)
87
88 Revision 1.163 2004/12/17 03:51:53 ksekar
89 <rdar://problem/3920991> Don't update TXT record if service registration fails
90
91 Revision 1.162 2004/12/17 01:29:11 ksekar
92 <rdar://problem/3920598> Questions can go deaf on location changes
93
94 Revision 1.161 2004/12/16 20:42:02 cheshire
95 Fix compiler warnings
96
97 Revision 1.160 2004/12/16 20:13:00 cheshire
98 <rdar://problem/3324626> Cache memory management improvements
99
100 Revision 1.159 2004/12/15 02:11:22 ksekar
101 <rdar://problem/3917317> Don't check for Dynamic DNS hostname uniqueness
102
103 Revision 1.158 2004/12/15 02:04:28 ksekar
104 Refinement to previous checkin - we should still return NatTraversal error when the port mapping fails
105
106 Revision 1.157 2004/12/15 01:39:21 ksekar
107 Refinement to previous checkin - we should still return NatTraversal error when the port mapping fails
108
109 Revision 1.156 2004/12/15 01:18:57 ksekar
110 <rdar://problem/3825979> Call DeregisterService on nat port map failure
111
112 Revision 1.155 2004/12/14 21:21:20 ksekar
113 <rdar://problem/3825979> NAT-PMP: Update response format to contain "Seconds Since Boot"
114
115 Revision 1.154 2004/12/14 20:52:27 cheshire
116 Add question->qnamehash and cr->resrec.namehash to log message
117
118 Revision 1.153 2004/12/14 20:45:02 cheshire
119 Improved error logging in "unexpected answer" message
120
121 Revision 1.152 2004/12/14 03:02:10 ksekar
122 <rdar://problem/3919016> Rare race condition can cause crash
123
124 Revision 1.151 2004/12/13 21:45:08 ksekar
125 uDNS_DeregisterService should return NoError if called twice (to follow mDNS behavior expected by daemon layer)
126
127 Revision 1.150 2004/12/13 20:42:41 ksekar
128 Fixed LogMsg
129
130 Revision 1.149 2004/12/13 18:10:03 ksekar
131 Fixed LogMsg
132
133 Revision 1.148 2004/12/13 01:18:04 ksekar
134 Fixed unused variable warning for non-debug builds
135
136 Revision 1.147 2004/12/12 23:51:42 ksekar
137 <rdar://problem/3845683> Wide-area registrations should fallback to using DHCP hostname as target
138
139 Revision 1.146 2004/12/12 23:30:40 ksekar
140 <rdar://problem/3916987> Extra RRs not properly unlinked when parent service registration fails
141
142 Revision 1.145 2004/12/12 22:56:29 ksekar
143 <rdar://problem/3668508> Need to properly handle duplicate long-lived queries
144
145 Revision 1.144 2004/12/11 20:55:29 ksekar
146 <rdar://problem/3916479> Clean up registration state machines
147
148 Revision 1.143 2004/12/10 01:21:27 cheshire
149 <rdar://problem/3914089> Get rid of "LLQ Responses over TCP not currently supported" message
150
151 Revision 1.142 2004/12/08 02:03:31 ksekar
152 <rdar://problem/3865124> Looping on NAT Traversal error - check for
153 NULL RR on error
154
155 Revision 1.141 2004/12/07 01:39:28 cheshire
156 Don't fail if the same server is responsible for more than one domain
157 (e.g. the same DNS server may be responsible for both apple.com. and 17.in-addr.arpa.)
158
159 Revision 1.140 2004/12/06 21:15:22 ksekar
160 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
161
162 Revision 1.139 2004/12/06 19:08:03 cheshire
163 Add clarifying comment -- CountLabels() excludes the final root label.
164
165 Revision 1.138 2004/12/06 01:45:54 ksekar
166 Correct wording in LogMsg
167
168 Revision 1.137 2004/12/03 20:40:35 ksekar
169 <rdar://problem/3865124> Looping on NAT Traversal error
170
171 Revision 1.136 2004/12/03 07:20:50 ksekar
172 <rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
173
174 Revision 1.135 2004/12/03 05:18:33 ksekar
175 <rdar://problem/3810596> mDNSResponder needs to return more specific TSIG errors
176
177 Revision 1.134 2004/12/02 20:03:49 ksekar
178 <rdar://problem/3889647> Rendezvous still publishes wide-area domains even after switching to a local subnet
179
180 Revision 1.133 2004/12/02 18:37:52 ksekar
181 <rdar://problem/3758233> Registering with port number zero should not create a port mapping
182
183 Revision 1.132 2004/12/01 20:57:19 ksekar
184 <rdar://problem/3873921> Wide Area Rendezvous must be split-DNS aware
185
186 Revision 1.131 2004/12/01 19:59:27 cheshire
187 <rdar://problem/3882643> Crash in mDNSPlatformTCPConnect
188 If a TCP response has the TC bit set, don't respond by just trying another TCP connection
189
190 Revision 1.130 2004/12/01 02:43:23 cheshire
191 Don't call StatusCallback if function pointer is null
192
193 Revision 1.129 2004/11/30 23:51:06 cheshire
194 Remove double semicolons
195
196 Revision 1.128 2004/11/25 01:48:30 ksekar
197 <rdar://problem/3878991> Logging into VPN does not trigger registration of address record
198
199 Revision 1.127 2004/11/25 01:41:36 ksekar
200 Changed unnecessary LogMsgs to debugfs
201
202 Revision 1.126 2004/11/23 23:54:17 ksekar
203 <rdar://problem/3890318> Wide-Area DNSServiceRegisterRecord() failures
204 can crash mDNSResponder
205
206 Revision 1.125 2004/11/23 04:16:48 cheshire
207 Removed receiveMsg() routine.
208
209 Revision 1.124 2004/11/23 04:06:51 cheshire
210 Get rid of floating point constant -- in a small embedded device, bringing in all
211 the floating point libraries just to halve an integer value is a bit too heavyweight.
212
213 Revision 1.123 2004/11/22 17:16:20 ksekar
214 <rdar://problem/3854298> Unicast services don't disappear when you disable all networking
215
216 Revision 1.122 2004/11/19 18:00:34 ksekar
217 <rdar://problem/3682646> Security: use random ID for one-shot unicast queries
218
219 Revision 1.121 2004/11/19 04:24:08 ksekar
220 <rdar://problem/3682609> Security: Enforce a "window" on one-shot wide-area queries
221
222 Revision 1.120 2004/11/19 02:32:43 ksekar
223 <rdar://problem/3682608> Wide-Area Rendezvous Security: Add LLQ-ID to events
224
225 Revision 1.119 2004/11/18 23:21:24 ksekar
226 <rdar://problem/3764544> LLQ Security: Need to verify src port/address for LLQ handshake
227
228 Revision 1.118 2004/11/18 22:58:37 ksekar
229 Removed old comment.
230
231 Revision 1.117 2004/11/18 18:04:21 ksekar
232 Restore checkins lost due to repository disk failure: Update comments & <rdar://problem/3880688>
233
234 Revision 1.xxx 2004/11/17 06:17:57 cheshire
235 Update comments to show correct SRV names: _dns-update._udp.<zone>. and _dns-llq._udp.<zone>.
236
237 Revision 1.xxx 2004/11/17 00:45:28 ksekar
238 <rdar://problem/3880688> Result of putUpdateLease not error-checked
239
240 Revision 1.116 2004/11/16 01:41:47 ksekar
241 Fixed typo in debugf
242
243 Revision 1.115 2004/11/15 20:09:24 ksekar
244 <rdar://problem/3719050> Wide Area support for Add/Remove record
245
246 Revision 1.114 2004/11/13 02:32:47 ksekar
247 <rdar://problem/3868216> LLQ mobility fragile on non-primary interface
248 - fixed incorrect state comparison in CheckQueries
249
250 Revision 1.113 2004/11/13 02:29:52 ksekar
251 <rdar://problem/3878386> LLQ refreshes not reliable
252
253 Revision 1.112 2004/11/11 20:45:14 ksekar
254 <rdar://problem/3876052> self-conflict test not compatible with some BIND servers
255
256 Revision 1.111 2004/11/11 20:14:55 ksekar
257 <rdar://problem/3719574> Wide-Area registrations not deregistered on sleep
258
259 Revision 1.110 2004/11/10 23:53:53 ksekar
260 Remove no longer relevant comment
261
262 Revision 1.109 2004/11/10 20:40:53 ksekar
263 <rdar://problem/3868216> LLQ mobility fragile on non-primary interface
264
265 Revision 1.108 2004/11/01 20:36:16 ksekar
266 <rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
267
268 Revision 1.107 2004/10/26 06:11:41 cheshire
269 Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
270
271 Revision 1.106 2004/10/26 03:52:03 cheshire
272 Update checkin comments
273
274 Revision 1.105 2004/10/26 01:15:06 cheshire
275 Use "#if 0" instead of commenting out code
276
277 Revision 1.104 2004/10/25 21:41:38 ksekar
278 <rdar://problem/3852958> wide-area name conflicts can cause crash
279
280 Revision 1.103 2004/10/25 19:30:52 ksekar
281 <rdar://problem/3827956> Simplify dynamic host name structures
282
283 Revision 1.102 2004/10/23 01:16:00 cheshire
284 <rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
285
286 Revision 1.101 2004/10/22 20:52:07 ksekar
287 <rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
288
289 Revision 1.100 2004/10/20 02:16:41 cheshire
290 Improve "could not confirm existence of NS record" error message
291 Don't call newRR->RecordCallback if it is NULL
292
293 Revision 1.99 2004/10/19 21:33:18 cheshire
294 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
295 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
296 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
297
298 Revision 1.98 2004/10/16 00:16:59 cheshire
299 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
300
301 Revision 1.97 2004/10/15 23:00:18 ksekar
302 <rdar://problem/3799242> Need to update LLQs on location changes
303
304 Revision 1.96 2004/10/12 23:30:44 ksekar
305 <rdar://problem/3609944> mDNSResponder needs to follow CNAME referrals
306
307 Revision 1.95 2004/10/12 03:15:09 ksekar
308 <rdar://problem/3835612> mDNS_StartQuery shouldn't return transient no-server error
309
310 Revision 1.94 2004/10/12 02:49:20 ksekar
311 <rdar://problem/3831228> Clean up LLQ sleep/wake, error handling
312
313 Revision 1.93 2004/10/08 04:17:25 ksekar
314 <rdar://problem/3831819> Don't use DNS extensions if the server does not advertise required SRV record
315
316 Revision 1.92 2004/10/08 03:54:35 ksekar
317 <rdar://problem/3831802> Refine unicast polling intervals
318
319 Revision 1.91 2004/09/30 17:45:34 ksekar
320 <rdar://problem/3821119> lots of log messages: mDNS_SetPrimaryIP: IP address unchanged
321
322 Revision 1.90 2004/09/25 00:22:13 ksekar
323 <rdar://problem/3815534> Crash in uDNS_RegisterService
324
325 Revision 1.89 2004/09/24 19:14:53 cheshire
326 Remove unused "extern mDNS mDNSStorage"
327
328 Revision 1.88 2004/09/23 20:48:15 ksekar
329 Clarify retransmission debugf messages.
330
331 Revision 1.87 2004/09/22 00:41:59 cheshire
332 Move tcp connection status codes into the legal range allocated for mDNS use
333
334 Revision 1.86 2004/09/21 23:40:11 ksekar
335 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
336
337 Revision 1.85 2004/09/21 22:38:27 ksekar
338 <rdar://problem/3810286> PrimaryIP type uninitialized
339
340 Revision 1.84 2004/09/18 00:30:39 cheshire
341 <rdar://problem/3806643> Infinite loop in CheckServiceRegistrations
342
343 Revision 1.83 2004/09/17 00:31:51 cheshire
344 For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
345
346 Revision 1.82 2004/09/16 21:36:36 cheshire
347 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
348 Changes to add necessary locking calls around unicast DNS operations
349
350 Revision 1.81 2004/09/16 02:29:39 cheshire
351 Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
352 uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
353
354 Revision 1.80 2004/09/16 01:58:21 cheshire
355 Fix compiler warnings
356
357 Revision 1.79 2004/09/16 00:24:48 cheshire
358 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
359
360 Revision 1.78 2004/09/15 01:16:57 ksekar
361 <rdar://problem/3797598> mDNSResponder printing too many messages
362
363 Revision 1.77 2004/09/14 23:27:47 cheshire
364 Fix compile errors
365
366 Revision 1.76 2004/09/14 22:22:00 ksekar
367 <rdar://problem/3800920> Legacy browses broken against some BIND versions
368
369 Revision 1.75 2004/09/03 19:23:05 ksekar
370 <rdar://problem/3788460>: Need retransmission mechanism for wide-area service registrations
371
372 Revision 1.74 2004/09/02 17:49:04 ksekar
373 <rdar://problem/3785135>: 8A246: mDNSResponder crash while logging on restart
374 Fixed incorrect conversions, changed %s to %##s for all domain names.
375
376 Revision 1.73 2004/09/02 01:39:40 cheshire
377 For better readability, follow consistent convention that QR bit comes first, followed by OP bits
378
379 Revision 1.72 2004/09/01 03:59:29 ksekar
380 <rdar://problem/3783453>: Conditionally compile out uDNS code on Windows
381
382 Revision 1.71 2004/08/27 17:51:53 ksekar
383 Replaced unnecessary LogMsg with debugf.
384
385 Revision 1.70 2004/08/25 00:37:27 ksekar
386 <rdar://problem/3774635>: Cleanup DynDNS hostname registration code
387
388 Revision 1.69 2004/08/18 17:35:41 ksekar
389 <rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
390
391 Revision 1.68 2004/08/14 03:22:41 cheshire
392 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
393 Add GetUserSpecifiedDDNSName() routine
394 Convert ServiceRegDomain to domainname instead of C string
395 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
396
397 Revision 1.67 2004/08/13 23:46:58 cheshire
398 "asyncronous" -> "asynchronous"
399
400 Revision 1.66 2004/08/13 23:37:02 cheshire
401 Now that we do both uDNS and mDNS, global replace "uDNS_info.hostname" with
402 "uDNS_info.UnicastHostname" for clarity
403
404 Revision 1.65 2004/08/13 23:12:32 cheshire
405 Don't use strcpy() and strlen() on "struct domainname" objects;
406 use AssignDomainName() and DomainNameLength() instead
407 (A "struct domainname" is a collection of packed pascal strings, not a C string.)
408
409 Revision 1.64 2004/08/13 23:01:05 cheshire
410 Use platform-independent mDNSNULL instead of NULL
411
412 Revision 1.63 2004/08/12 00:32:36 ksekar
413 <rdar://problem/3759567>: LLQ Refreshes never terminate if unanswered
414
415 Revision 1.62 2004/08/10 23:19:14 ksekar
416 <rdar://problem/3722542>: DNS Extension daemon for Wide Area Rendezvous
417 Moved routines/constants to allow extern access for garbage collection daemon
418
419 Revision 1.61 2004/07/30 17:40:06 ksekar
420 <rdar://problem/3739115>: TXT Record updates not available for wide-area services
421
422 Revision 1.60 2004/07/29 19:40:05 ksekar
423 NATPMP Support - minor fixes and cleanup
424
425 Revision 1.59 2004/07/29 19:27:15 ksekar
426 NATPMP Support - minor fixes and cleanup
427
428 Revision 1.58 2004/07/27 07:35:38 shersche
429 fix syntax error, variables declared in the middle of a block
430
431 Revision 1.57 2004/07/26 22:49:30 ksekar
432 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
433
434 Revision 1.56 2004/07/26 19:14:44 ksekar
435 <rdar://problem/3737814>: 8A210: mDNSResponder crashed in startLLQHandshakeCallback
436
437 Revision 1.55 2004/07/15 19:01:33 ksekar
438 <rdar://problem/3681029>: Check for incorrect time comparisons
439
440 Revision 1.54 2004/06/22 02:10:53 ksekar
441 <rdar://problem/3705433>: Lighthouse failure causes packet flood to DNS
442
443 Revision 1.53 2004/06/17 20:49:09 ksekar
444 <rdar://problem/3690436>: mDNSResponder crash while location cycling
445
446 Revision 1.52 2004/06/17 01:13:11 ksekar
447 <rdar://problem/3696616>: polling interval too short
448
449 Revision 1.51 2004/06/10 04:36:44 cheshire
450 Fix compiler warning
451
452 Revision 1.50 2004/06/10 00:55:13 ksekar
453 <rdar://problem/3686213>: crash on network reconnect
454
455 Revision 1.49 2004/06/10 00:10:50 ksekar
456 <rdar://problem/3686174>: Infinite Loop in uDNS_Execute()
457
458 Revision 1.48 2004/06/09 20:03:37 ksekar
459 <rdar://problem/3686163>: Incorrect copying of resource record in deregistration
460
461 Revision 1.47 2004/06/09 03:48:28 ksekar
462 <rdar://problem/3685226>: nameserver address fails with prod. Lighthouse server
463
464 Revision 1.46 2004/06/09 01:44:30 ksekar
465 <rdar://problem/3681378> reworked Cache Record copy code
466
467 Revision 1.45 2004/06/08 18:54:47 ksekar
468 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
469
470 Revision 1.44 2004/06/05 00:33:51 cheshire
471 <rdar://problem/3681029>: Check for incorrect time comparisons
472
473 Revision 1.43 2004/06/05 00:14:44 cheshire
474 Fix signed/unsigned and other compiler warnings
475
476 Revision 1.42 2004/06/04 22:36:16 ksekar
477 Properly set u->nextevent in uDNS_Execute
478
479 Revision 1.41 2004/06/04 08:58:29 ksekar
480 <rdar://problem/3668624>: Keychain integration for secure dynamic update
481
482 Revision 1.40 2004/06/03 03:09:58 ksekar
483 <rdar://problem/3668626>: Garbage Collection for Dynamic Updates
484
485 Revision 1.39 2004/06/01 23:46:50 ksekar
486 <rdar://problem/3675149>: DynDNS: dynamically look up LLQ/Update ports
487
488 Revision 1.38 2004/05/31 22:19:44 ksekar
489 <rdar://problem/3258021>: Feature: DNS server->client notification on
490 record changes (#7805) - revert to polling mode on setup errors
491
492 Revision 1.37 2004/05/28 23:42:37 ksekar
493 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
494
495 Revision 1.36 2004/05/18 23:51:25 cheshire
496 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
497
498 Revision 1.35 2004/05/07 23:01:04 ksekar
499 Cleaned up list traversal in deriveGoodbyes - removed unnecessary
500 conditional assignment.
501
502 Revision 1.34 2004/05/05 18:26:12 ksekar
503 Periodically re-transmit questions if the send() fails. Include
504 internal questions in retransmission.
505
506 Revision 1.33 2004/05/05 17:40:06 ksekar
507 Removed prerequisite from deregistration update - it does not work for
508 shared records, and is unnecessary until we have more sophisticated
509 name conflict management.
510
511 Revision 1.32 2004/05/05 17:32:18 ksekar
512 Prevent registration of loopback interface caused by removal of
513 Multicast flag in interface structure.
514
515 Revision 1.31 2004/05/05 17:05:02 ksekar
516 Use LargeCacheRecord structs when pulling records off packets
517
518 Revision 1.30 2004/04/16 21:33:27 ksekar
519 Fixed bug in processing GetZoneData responses that do not use BIND formatting.
520
521 Revision 1.29 2004/04/15 20:03:13 ksekar
522 Clarified log message when pulling bad resource records off packet.
523
524 Revision 1.28 2004/04/15 00:51:28 bradley
525 Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers.
526 Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers.
527
528 Revision 1.27 2004/04/14 23:09:28 ksekar
529 Support for TSIG signed dynamic updates.
530
531 Revision 1.26 2004/04/14 19:36:05 ksekar
532 Fixed memory corruption error in deriveGoodbyes.
533
534 Revision 1.25 2004/04/14 04:07:11 ksekar
535 Fixed crash in IsActiveUnicastQuery(). Removed redundant checks in routine.
536
537 Revision 1.24 2004/04/08 09:41:40 bradley
538 Added const to AuthRecord in deadvertiseIfCallback to match callback typedef.
539
540 Revision 1.23 2004/03/24 00:29:45 ksekar
541 Make it safe to call StopQuery in a unicast question callback
542
543 Revision 1.22 2004/03/19 10:11:09 bradley
544 Added AuthRecord * cast from umalloc for C++ builds.
545
546 Revision 1.21 2004/03/15 02:03:45 bradley
547 Added const to params where needed to match prototypes. Changed SetNewRData calls to use 0 instead
548 of -1 for unused size to fix warning. Disable assignment within conditional warnings with Visual C++.
549
550 Revision 1.20 2004/03/13 02:07:26 ksekar
551 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
552
553 Revision 1.19 2004/03/13 01:57:33 ksekar
554 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
555
556 Revision 1.18 2004/02/21 08:34:15 bradley
557 Added casts from void * to specific type for C++ builds. Changed void * l-value cast
558 r-value cast to fix problems with VC++ builds. Removed empty switch to fix VC++ error.
559
560 Revision 1.17 2004/02/21 02:06:24 cheshire
561 Can't use anonymous unions -- they're non-standard and don't work on all compilers
562
563 Revision 1.16 2004/02/12 01:51:45 cheshire
564 Don't try to send uDNS queries unless we have at least one uDNS server available
565
566 Revision 1.15 2004/02/10 03:02:46 cheshire
567 Fix compiler warning
568
569 Revision 1.14 2004/02/06 23:04:19 ksekar
570 Basic Dynamic Update support via mDNS_Register (dissabled via
571 UNICAST_REGISTRATION #define)
572
573 Revision 1.13 2004/02/03 22:15:01 ksekar
574 Fixed nameToAddr error check: don't abort state machine on nxdomain error.
575
576 Revision 1.12 2004/02/03 19:47:36 ksekar
577 Added an asynchronous state machine mechanism to uDNS.c, including
578 calls to find the parent zone for a domain name. Changes include code
579 in repository previously dissabled via "#if 0 incomplete". Codepath
580 is currently unused, and will be called to create update records, etc.
581
582 Revision 1.11 2004/01/30 02:12:30 ksekar
583 Changed uDNS_ReceiveMsg() to correctly return void.
584
585 Revision 1.10 2004/01/29 02:59:17 ksekar
586 Unicast DNS: Changed from a resource record oriented question/response
587 matching to packet based matching. New callback architecture allows
588 collections of records in a response to be processed differently
589 depending on the nature of the request, and allows the same structure
590 to be used for internal and client-driven queries with different processing needs.
591
592 Revision 1.9 2004/01/28 20:20:45 ksekar
593 Unified ActiveQueries and ActiveInternalQueries lists, using a flag to
594 demux them. Check-in includes work-in-progress code, #ifdef'd out.
595
596 Revision 1.8 2004/01/28 02:30:07 ksekar
597 Added default Search Domains to unicast browsing, controlled via
598 Networking sharing prefs pane. Stopped sending unicast messages on
599 every interface. Fixed unicast resolving via mach-port API.
600
601 Revision 1.7 2004/01/27 20:15:22 cheshire
602 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
603
604 Revision 1.6 2004/01/24 23:47:17 cheshire
605 Use mDNSOpaque16fromIntVal() instead of shifting and masking
606
607 Revision 1.5 2004/01/24 04:59:15 cheshire
608 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
609
610 Revision 1.4 2004/01/24 04:19:26 cheshire
611 Restore overwritten checkin 1.2
612
613 Revision 1.3 2004/01/23 23:23:15 ksekar
614 Added TCP support for truncated unicast messages.
615
616 Revision 1.2 2004/01/22 03:48:41 cheshire
617 Make sure uDNS client doesn't accidentally use query ID zero
618
619 Revision 1.1 2003/12/13 03:05:27 ksekar
620 <rdar://problem/3192548>: DynDNS: Unicast query of service records
621
622 */
623
624 #include "uDNS.h"
625
626 #if(defined(_MSC_VER))
627 // Disable "assignment within conditional expression".
628 // Other compilers understand the convention that if you place the assignment expression within an extra pair
629 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
630 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
631 // to the compiler that the assignment is intentional, we have to just turn this warning off completely.
632 #pragma warning(disable:4706)
633 #endif
634
635 #define umalloc(x) mDNSPlatformMemAllocate(x) // short hands for common routines
636 #define ufree(x) mDNSPlatformMemFree(x)
637 #define ubzero(x,y) mDNSPlatformMemZero(x,y)
638 #define umemcpy(x, y, l) mDNSPlatformMemCopy(y, x, l) // uses memcpy(2) arg ordering
639
640 // Asynchronous operation types
641
642 typedef enum
643 {
644 zoneDataResult
645 // other async. operation names go here
646 } AsyncOpResultType;
647
648 typedef struct
649 {
650 domainname zoneName;
651 mDNSAddr primaryAddr;
652 mDNSu16 zoneClass;
653 mDNSIPPort llqPort;
654 mDNSIPPort updatePort;
655 } zoneData_t;
656
657 // other async. result struct defs go here
658
659 typedef struct
660 {
661 AsyncOpResultType type;
662 zoneData_t zoneData;
663 // other async result structs go here
664 } AsyncOpResult;
665
666 typedef void AsyncOpCallback(mStatus err, mDNS *const m, void *info, const AsyncOpResult *result);
667
668
669 // Private Function Prototypes
670 // Note: In general, functions are ordered such that they do not require forward declarations.
671 // However, prototypes are used where cyclic call graphs exist (e.g. foo calls bar, and bar calls
672 // foo), or when they aid in the grouping or readability of code (e.g. state machine code that is easier
673 // read top-to-bottom.)
674
675 mDNSlocal mDNSBool FreeNATInfo(mDNS *m, NATTraversalInfo *n);
676 mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question, const mDNSAddr *src, mDNS *m);
677 mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdatePort, mDNSBool findLLQPort, AsyncOpCallback callback, void *callbackInfo);
678 mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID);
679 mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr);
680 mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs);
681 mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs);
682 mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srsPtr, const AsyncOpResult *result);
683 mDNSlocal void SendRecordUpdate(mDNS *m, AuthRecord *rr, uDNS_RegInfo *info);
684 mDNSlocal void SuspendLLQs(mDNS *m, mDNSBool DeregisterActive);
685 mDNSlocal void RestartQueries(mDNS *m);
686 mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer);
687 mDNSlocal void llqResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *context);
688
689 // ***************************************************************************
690 #if COMPILER_LIKES_PRAGMA_MARK
691 #pragma mark - Temporary workaround
692 #endif
693
694 // 17 Places in this file directly call mDNSPlatformTimeNow(), which is unsafe
695 // The platform function is now called mDNSPlatformRawTime(), and
696 // mDNSPlatformTimeNow() is defined here as a temporary workaround.
697 // This is a gross hack, and after this change has been tested for a while,
698 // all these calls should be replaced by simple references to m->timenow
699
700 mDNSlocal mDNSs32 mDNSPlatformTimeNow(mDNS *m)
701 {
702 if (m->mDNS_busy && m->timenow) return(m->timenow);
703 LogMsg("ERROR: uDNS.c code executing without holding main mDNS lock");
704
705 // To get a quick and easy stack trace to find out *how* this routine
706 // is being called without holding main mDNS lock, uncomment the line below:
707 // *(long*)0=0;
708
709 return(mDNS_TimeNow(m));
710 }
711
712 // ***************************************************************************
713 #if COMPILER_LIKES_PRAGMA_MARK
714 #pragma mark - General Utility Functions
715 #endif
716
717 // CountLabels() returns number of labels in name, excluding final root label
718 // (e.g. for "apple.com." CountLabels returns 2.)
719 mDNSlocal int CountLabels(const domainname *d)
720 {
721 int count = 0;
722 const mDNSu8 *ptr;
723
724 for (ptr = d->c; *ptr; ptr = ptr + ptr[0] + 1) count++;
725 return count;
726 }
727
728 mDNSlocal mDNSOpaque16 newMessageID(uDNS_GlobalInfo *u)
729 {
730 static mDNSBool randomized = mDNSfalse;
731
732 if (!randomized) { u->NextMessageID = (mDNSu16)mDNSRandom(0xFFFF); randomized = mDNStrue; }
733 if (u->NextMessageID == 0) u->NextMessageID++;
734 return mDNSOpaque16fromIntVal(u->NextMessageID++);
735 }
736
737 // unlink an AuthRecord from a linked list
738 mDNSlocal mStatus unlinkAR(AuthRecord **list, AuthRecord *const rr)
739 {
740 AuthRecord *rptr, *prev = mDNSNULL;
741
742 for (rptr = *list; rptr; rptr = rptr->next)
743 {
744 if (rptr == rr)
745 {
746 if (prev) prev->next = rptr->next;
747 else *list = rptr->next;
748 rptr->next = mDNSNULL;
749 return mStatus_NoError;
750 }
751 prev = rptr;
752 }
753 LogMsg("ERROR: unlinkAR - no such active record");
754 return mStatus_UnknownErr;
755 }
756
757 mDNSlocal void unlinkSRS(mDNS *m, ServiceRecordSet *srs)
758 {
759 uDNS_GlobalInfo *u = &m->uDNS_info;
760 ServiceRecordSet **p;
761 NATTraversalInfo *n = u->NATTraversals;
762
763 // verify that no NAT objects reference this service
764 while (n)
765 {
766 if (n->reg.ServiceRegistration == srs)
767 {
768 NATTraversalInfo *tmp = n;
769 n = n->next;
770 LogMsg("ERROR: Unlinking service record set %##s still referenced by NAT traversal object!", srs->RR_SRV.resrec.name->c);
771 FreeNATInfo(m, tmp);
772 }
773 else n = n->next;
774 }
775
776 for (p = &u->ServiceRegistrations; *p; p = &(*p)->next)
777 if (*p == srs) { *p = srs->next; srs->next = mDNSNULL; return; }
778 LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list");
779 }
780
781 mDNSlocal void LinkActiveQuestion(uDNS_GlobalInfo *u, DNSQuestion *q)
782 {
783 if (uDNS_IsActiveQuery(q, u))
784 { LogMsg("LinkActiveQuestion - %##s (%d) already in list!", q->qname.c, q->qtype); return; }
785
786 q->next = u->ActiveQueries;
787 u->ActiveQueries = q;
788 }
789
790 mDNSlocal void SwapRData(mDNS *m, AuthRecord *rr, mDNSBool DeallocOld)
791 {
792 RData *oldrd = rr->resrec.rdata;
793 mDNSu16 oldrdlen = rr->resrec.rdlength;
794
795 if (!rr->uDNS_info.UpdateRData) { LogMsg("SwapRData invoked with NULL UpdateRData field"); return; }
796 SetNewRData(&rr->resrec, rr->uDNS_info.UpdateRData, rr->uDNS_info.UpdateRDLen);
797 if (DeallocOld)
798 {
799 rr->uDNS_info.UpdateRData = mDNSNULL; // Clear the NewRData pointer ...
800 if (rr->uDNS_info.UpdateRDCallback) rr->uDNS_info.UpdateRDCallback(m, rr, oldrd); // ... and let the client know
801 }
802 else
803 {
804 rr->uDNS_info.UpdateRData = oldrd;
805 rr->uDNS_info.UpdateRDLen = oldrdlen;
806 }
807 }
808
809 // set retry timestamp for record with exponential backoff
810 // (for service record sets, use RR_SRV as representative for time checks
811 mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr)
812 {
813 rr->LastAPTime = mDNSPlatformTimeNow(m);
814 if (rr->ThisAPInterval < INIT_UCAST_POLL_INTERVAL) { rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL; return; }
815 if (rr->ThisAPInterval*2 <= MAX_UCAST_POLL_INTERVAL) { rr->ThisAPInterval *= 2; return; }
816 if (rr->ThisAPInterval != MAX_UCAST_POLL_INTERVAL) { rr->ThisAPInterval = MAX_UCAST_POLL_INTERVAL; }
817 }
818
819
820 // ***************************************************************************
821 #if COMPILER_LIKES_PRAGMA_MARK
822 #pragma mark - Name Server List Management
823 #endif
824
825 mDNSexport void mDNS_AddDNSServer(mDNS *const m, const mDNSAddr *addr, const domainname *d)
826 {
827 uDNS_GlobalInfo *u = &m->uDNS_info;
828 DNSServer *s, **p = &u->Servers;
829
830 mDNS_Lock(m);
831 if (!d) d = (domainname *)"";
832
833 while (*p) // Check if we already have this {server,domain} pair registered
834 {
835 if (mDNSSameAddress(&(*p)->addr, addr) && SameDomainName(&(*p)->domain, d))
836 LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr, d->c);
837 p=&(*p)->next;
838 }
839
840 // allocate, add to list
841 s = umalloc(sizeof(*s));
842 if (!s) { LogMsg("Error: mDNS_AddDNSServer - malloc"); goto end; }
843 s->addr = *addr;
844 AssignDomainName(&s->domain, d);
845 s->next = mDNSNULL;
846 *p = s;
847
848 end:
849 mDNS_Unlock(m);
850 }
851
852 mDNSexport void mDNS_DeleteDNSServers(mDNS *const m)
853 {
854 DNSServer *s;
855 mDNS_Lock(m);
856
857 s = m->uDNS_info.Servers;
858 m->uDNS_info.Servers = mDNSNULL;
859 while (s)
860 {
861 DNSServer *tmp = s;
862 s = s->next;
863 ufree(tmp);
864 }
865
866 mDNS_Unlock(m);
867 }
868
869 // ***************************************************************************
870 #if COMPILER_LIKES_PRAGMA_MARK
871 #pragma mark - authorization management
872 #endif
873
874 mDNSlocal uDNS_AuthInfo *GetAuthInfoForZone(const uDNS_GlobalInfo *u, const domainname *zone)
875 {
876 uDNS_AuthInfo *ptr;
877 while (zone->c[0])
878 {
879 for (ptr = u->AuthInfoList; ptr; ptr = ptr->next)
880 if (SameDomainName(&ptr->zone, zone)) return(ptr);
881 zone = (const domainname *)(zone->c + 1 + zone->c[0]);
882 }
883 return mDNSNULL;
884 }
885
886 mDNSlocal void DeleteAuthInfoForZone(uDNS_GlobalInfo *u, const domainname *zone)
887 {
888 uDNS_AuthInfo *ptr, *prev = mDNSNULL;
889
890 for (ptr = u->AuthInfoList; ptr; ptr = ptr->next)
891 {
892 if (SameDomainName(&ptr->zone, zone))
893 {
894 if (prev) prev->next = ptr->next;
895 else u->AuthInfoList = ptr->next;
896 ufree(ptr);
897 return;
898 }
899 prev = ptr;
900 }
901 }
902
903 mDNSexport mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const domainname *key, const char *sharedSecret, mDNSu32 ssLen, mDNSBool base64)
904 {
905 uDNS_AuthInfo *info;
906 mDNSu8 keybuf[1024];
907 mDNSs32 keylen;
908 uDNS_GlobalInfo *u = &m->uDNS_info;
909 mStatus status = mStatus_NoError;
910
911 mDNS_Lock(m);
912
913 if (GetAuthInfoForZone(u, zone)) DeleteAuthInfoForZone(u, zone);
914 if (!key) goto exit;
915
916 info = (uDNS_AuthInfo*)umalloc(sizeof(uDNS_AuthInfo) + ssLen);
917 if (!info) { LogMsg("ERROR: umalloc"); status = mStatus_NoMemoryErr; goto exit; }
918 ubzero(info, sizeof(uDNS_AuthInfo));
919 AssignDomainName(&info->zone, zone);
920 AssignDomainName(&info->keyname, key);
921
922 if (base64)
923 {
924 keylen = DNSDigest_Base64ToBin(sharedSecret, keybuf, 1024);
925 if (keylen < 0)
926 {
927 LogMsg("ERROR: mDNS_UpdateDomainRequiresAuthentication - could not convert shared secret from base64");
928 ufree(info);
929 status = mStatus_UnknownErr;
930 goto exit;
931 }
932 DNSDigest_ConstructHMACKey(info, keybuf, (mDNSu32)keylen);
933 }
934 else DNSDigest_ConstructHMACKey(info, (mDNSu8*)sharedSecret, ssLen);
935
936 // link into list
937 info->next = m->uDNS_info.AuthInfoList;
938 m->uDNS_info.AuthInfoList = info;
939 exit:
940 mDNS_Unlock(m);
941 return status;
942 }
943
944 // ***************************************************************************
945 #if COMPILER_LIKES_PRAGMA_MARK
946 #pragma mark - NAT Traversal
947 #endif
948
949 mDNSlocal mDNSBool DomainContainsLabelString(const domainname *d, const char *str)
950 {
951 const domainlabel *l;
952 domainlabel buf;
953
954 if (!MakeDomainLabelFromLiteralString(&buf, str)) return mDNSfalse;
955
956 for (l = (const domainlabel *)d; l->c[0]; l = (const domainlabel *)(l->c + l->c[0]+1))
957 if (SameDomainLabel(l->c, buf.c)) return mDNStrue;
958 return mDNSfalse;
959 }
960
961 // allocate struct, link into global list, initialize
962 mDNSlocal NATTraversalInfo *AllocNATInfo(mDNS *const m, NATOp_t op, NATResponseHndlr callback)
963 {
964 uDNS_GlobalInfo *u = &m->uDNS_info;
965 NATTraversalInfo *info = umalloc(sizeof(NATTraversalInfo));
966 if (!info) { LogMsg("ERROR: malloc"); return mDNSNULL; }
967 ubzero(info, sizeof(NATTraversalInfo));
968 info->next = u->NATTraversals;
969 u->NATTraversals = info;
970 info->retry = mDNSPlatformTimeNow(m) + NATMAP_INIT_RETRY;
971 info->op = op;
972 info->state = NATState_Init;
973 info->ReceiveResponse = callback;
974 info->PublicPort.NotAnInteger = 0;
975 info->Router = u->Router;
976 return info;
977 }
978
979 // unlink from list, deallocate
980 mDNSlocal mDNSBool FreeNATInfo(mDNS *m, NATTraversalInfo *n)
981 {
982 NATTraversalInfo *ptr, *prev = mDNSNULL;
983 ServiceRecordSet *s = m->uDNS_info.ServiceRegistrations;
984
985 // Verify that object is not referenced by any services
986 while (s)
987 {
988 if (s->uDNS_info.NATinfo == n)
989 {
990 LogMsg("Error: Freeing NAT info object still referenced by Service Record Set %##s!", s->RR_SRV.resrec.name->c);
991 s->uDNS_info.NATinfo = mDNSNULL;
992 }
993 s = s->next;
994 }
995
996 if (n == m->uDNS_info.LLQNatInfo) m->uDNS_info.LLQNatInfo = mDNSNULL;
997 ptr = m->uDNS_info.NATTraversals;
998 while (ptr)
999 {
1000 if (ptr == n)
1001 {
1002 if (prev) prev->next = ptr->next;
1003 else m->uDNS_info.NATTraversals = ptr->next;
1004 ufree(n);
1005 return mDNStrue;
1006 }
1007 prev = ptr;
1008 ptr = ptr->next;
1009 }
1010 LogMsg("FreeNATInfo: NATTraversalInfo not found in list");
1011 return mDNSfalse;
1012 }
1013
1014 mDNSlocal void SendNATMsg(NATTraversalInfo *info, mDNS *m)
1015 {
1016 mStatus err;
1017 mDNSAddr dst;
1018 mDNSIPPort dstport;
1019 uDNS_GlobalInfo *u = &m->uDNS_info;
1020
1021 if (info->state != NATState_Request && info->state != NATState_Refresh)
1022 { LogMsg("SendNATMsg: Bad state %d", info->state); return; }
1023
1024 if (u->Router.ip.v4.NotAnInteger)
1025 {
1026 // send msg if we have a router
1027 const mDNSu8 *end = (mDNSu8 *)&info->request;
1028 if (info->op == NATOp_AddrRequest) end += sizeof(NATAddrRequest);
1029 else end += sizeof(NATPortMapRequest);
1030
1031 dst.type = u->Router.type;
1032 dst.ip.v4 = u->Router.ip.v4;
1033 dstport = mDNSOpaque16fromIntVal(NATMAP_PORT);
1034 err = mDNSPlatformSendUDP(m, &info->request, end, 0, &dst, dstport);
1035 if (!err) (info->ntries++); // don't increment attempt counter if the send failed
1036 }
1037
1038 // set retry
1039 if (info->RetryInterval < NATMAP_INIT_RETRY) info->RetryInterval = NATMAP_INIT_RETRY;
1040 else if (info->RetryInterval * 2 > NATMAP_MAX_RETRY) info->RetryInterval = NATMAP_MAX_RETRY;
1041 else info->RetryInterval *= 2;
1042 info->retry = mDNSPlatformTimeNow(m) + info->RetryInterval;
1043 }
1044
1045 mDNSlocal void ReceiveNATAddrResponse(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len)
1046 {
1047 mStatus err = mStatus_NoError;
1048 AuthRecord *rr = mDNSNULL;
1049 NATAddrReply *response = (NATAddrReply *)pkt;
1050 mDNSAddr addr;
1051
1052 if (n->state != NATState_Request)
1053 {
1054 LogMsg("ReceiveNATAddrResponse: bad state %d", n->state);
1055 err = mStatus_UnknownErr;
1056 goto end;
1057 }
1058
1059 rr = n->reg.RecordRegistration;
1060 if (!rr)
1061 {
1062 LogMsg("ReceiveNATAddrResponse: registration cancelled");
1063 err = mStatus_UnknownErr;
1064 goto end;
1065 }
1066
1067 addr.type = mDNSAddrType_IPv4;
1068 addr.ip.v4 = rr->resrec.rdata->u.ipv4;
1069
1070 if (!pkt) // timeout
1071 {
1072 #ifdef _LEGACY_NAT_TRAVERSAL_
1073 err = LNT_GetPublicIP(&addr.ip.v4);
1074 if (err) goto end;
1075 else n->state = NATState_Legacy;
1076 #else
1077 debugf("ReceiveNATAddrResponse: timeout");
1078 err = mStatus_NATTraversal;
1079 goto end;
1080 #endif // _LEGACY_NAT_TRAVERSAL_
1081 }
1082 else
1083 {
1084 if (len < sizeof(*response))
1085 {
1086 LogMsg("ReceiveNATAddrResponse: response too short (%d bytes)", len);
1087 err = mStatus_NATTraversal;
1088 goto end;
1089 }
1090 if (response->vers != NATMAP_VERS)
1091 {
1092 LogMsg("ReceiveNATAddrResponse: received version %d (expect version %d)", pkt[0], NATMAP_VERS);
1093 err = mStatus_NATTraversal;
1094 goto end;
1095 }
1096 if (response->opcode != (NATOp_AddrRequest | NATMAP_RESPONSE_MASK))
1097 {
1098 LogMsg("ReceiveNATAddrResponse: bad response code %d", response->opcode);
1099 err = mStatus_NATTraversal;
1100 goto end;
1101 }
1102 if (response->err.NotAnInteger)
1103 { LogMsg("ReceiveAddrResponse: received error %d", mDNSVal16(response->err)); err = mStatus_NATTraversal; goto end; }
1104
1105 addr.ip.v4 = response->PubAddr;
1106 n->state = NATState_Established;
1107 }
1108
1109 if (IsPrivateV4Addr(&addr))
1110 {
1111 LogMsg("ReceiveNATAddrResponse: Double NAT");
1112 err = mStatus_DoubleNAT;
1113 goto end;
1114 }
1115
1116 end:
1117 if (err)
1118 {
1119 FreeNATInfo(m, n);
1120 if (rr)
1121 {
1122 rr->uDNS_info.NATinfo = mDNSNULL;
1123 rr->uDNS_info.state = regState_Unregistered; // note that rr is not yet in global list
1124 rr->RecordCallback(m, rr, mStatus_NATTraversal);
1125 // note - unsafe to touch rr after callback
1126 }
1127 return;
1128 }
1129 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]);
1130 rr->resrec.rdata->u.ipv4 = addr.ip.v4; // replace rdata w/ public address
1131 uDNS_RegisterRecord(m, rr);
1132 }
1133
1134
1135 mDNSlocal void StartGetPublicAddr(mDNS *m, uDNS_HostnameInfo *hInfo)
1136 {
1137 NATAddrRequest *req;
1138 uDNS_GlobalInfo *u = &m->uDNS_info;
1139
1140 NATTraversalInfo *info = AllocNATInfo(m, NATOp_AddrRequest, ReceiveNATAddrResponse);
1141 if (!info) { uDNS_RegisterRecord(m, hInfo->ar); return; }
1142 hInfo->ar->uDNS_info.NATinfo = info;
1143 info->reg.RecordRegistration = hInfo->ar;
1144 info->state = NATState_Request;
1145
1146 // format message
1147 req = &info->request.AddrReq;
1148 req->vers = NATMAP_VERS;
1149 req->opcode = NATOp_AddrRequest;
1150
1151 if (!u->Router.ip.v4.NotAnInteger)
1152 {
1153 debugf("No router. Will retry NAT traversal in %ld ticks", NATMAP_INIT_RETRY);
1154 return;
1155 }
1156
1157 SendNATMsg(info, m);
1158 }
1159
1160
1161 mDNSlocal void RefreshNATMapping(NATTraversalInfo *n, mDNS *m)
1162 {
1163 n->state = NATState_Refresh;
1164 n->RetryInterval = NATMAP_INIT_RETRY;
1165 n->ntries = 0;
1166 SendNATMsg(n, m);
1167 }
1168
1169 mDNSlocal void LLQNatMapComplete(mDNS *m)
1170 {
1171 uDNS_GlobalInfo *u = &m->uDNS_info;
1172 LLQ_Info *llqInfo;
1173 NATTraversalInfo *n = u->LLQNatInfo;
1174
1175 if (!n) { LogMsg("Error: LLQNatMapComplete called with NULL LLQNatInfo"); return; }
1176 if (n->state != NATState_Established && n->state != NATState_Legacy && n->state != NATState_Error)
1177 { LogMsg("LLQNatMapComplete - bad nat state %d", n->state); return; }
1178
1179 u->CurrentQuery = u->ActiveQueries;
1180 while (u->CurrentQuery)
1181 {
1182 DNSQuestion *q = u->CurrentQuery;
1183 u->CurrentQuery = u->CurrentQuery->next;
1184 llqInfo = q->uDNS_info.llq;
1185 if (q->LongLived && llqInfo->state == LLQ_NatMapWait)
1186 {
1187 if (n->state == NATState_Error)
1188 {
1189 llqInfo->NATMap = mDNSfalse;
1190 llqInfo->question->uDNS_info.responseCallback = llqResponseHndlr;
1191 llqInfo->state = LLQ_Poll;
1192 llqInfo->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL); // trigger immediate poll
1193 llqInfo->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
1194 }
1195 else { llqInfo->state = LLQ_GetZoneInfo; startLLQHandshake(m, llqInfo, mDNSfalse); }
1196 }
1197 }
1198 }
1199
1200 mDNSlocal void ReceivePortMapReply(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len)
1201 {
1202 ServiceRecordSet *srs;
1203 mDNSIPPort priv;
1204 mDNSu32 lease;
1205 mDNSBool deletion;
1206 NATPortMapReply *reply = (NATPortMapReply *)pkt;
1207
1208 if (n->state != NATState_Request && n->state != NATState_Refresh)
1209 { LogMsg("ReceivePortMapReply: bad state %d", n->state); return; }
1210
1211 deletion = (!n->request.PortReq.lease.NotAnInteger);
1212 if (deletion) { n->state = NATState_Deleted; return; }
1213 // note that we explicitly ignore timeouts here
1214 // we keep the context struct around so that the SendServiceDeregistration code can reference
1215 // it to determine the public port to delete in the SRV record.
1216
1217 srs = n->reg.ServiceRegistration;
1218 if (!srs && n != m->uDNS_info.LLQNatInfo)
1219 {
1220 debugf("ReceivePortMapReply: registration cancelled");
1221 FreeNATInfo(m, n);
1222 return;
1223 }
1224
1225 priv = srs ? srs->RR_SRV.resrec.rdata->u.srv.port : m->UnicastPort4;
1226
1227 if (!pkt) // timeout
1228 {
1229 #ifdef _LEGACY_NAT_TRAVERSAL_
1230 mDNSIPPort pub;
1231 int ntries = 0;
1232 mStatus err;
1233 mDNSBool tcp = (srs && DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp"));
1234
1235 pub = priv; // initially request priv == pub
1236 while (1)
1237 {
1238 err = LNT_MapPort(priv, pub, tcp);
1239 if (!err)
1240 {
1241 n->PublicPort = pub;
1242 n->state = NATState_Legacy;
1243 goto end;
1244 }
1245 else if (err != mStatus_AlreadyRegistered || ++ntries > LEGACY_NATMAP_MAX_TRIES)
1246 {
1247 n->state = NATState_Error;
1248 goto end;
1249 }
1250 else
1251 {
1252 // the mapping we want is taken - try a random port
1253 mDNSu16 RandPort = mDNSRandom(DYN_PORT_MAX - DYN_PORT_MIN) + DYN_PORT_MIN;
1254 pub = mDNSOpaque16fromIntVal(RandPort);
1255 }
1256 }
1257 #else
1258 goto end;
1259 #endif // _LEGACY_NAT_TRAVERSAL_
1260 }
1261
1262 if (len < sizeof(*reply)) { LogMsg("ReceivePortMapReply: response too short (%d bytes)", len); goto end; }
1263 if (reply->vers != NATMAP_VERS) { LogMsg("ReceivePortMapReply: received version %d (expect version %d)", pkt[0], NATMAP_VERS); goto end; }
1264 if (reply->opcode != (n->op | NATMAP_RESPONSE_MASK)) { LogMsg("ReceivePortMapReply: bad response code %d", pkt[1]); goto end; }
1265 if (reply->err.NotAnInteger) { LogMsg("ReceivePortMapReply: received error %d", mDNSVal16(reply->err)); goto end; }
1266 if (priv.NotAnInteger != reply->priv.NotAnInteger)
1267 { LogMsg("ReceivePortMapReply: reply private port does not match requested private port"); goto end; }
1268
1269 lease = (mDNSu32)mDNSVal32(reply->lease);
1270 if (lease > 0x70000000UL / mDNSPlatformOneSecond) lease = 0x70000000UL / mDNSPlatformOneSecond;
1271
1272 if (n->state == NATState_Refresh && reply->pub.NotAnInteger != n->PublicPort.NotAnInteger)
1273 LogMsg("ReceivePortMapReply: NAT refresh changed public port from %d to %d", mDNSVal16(n->PublicPort), mDNSVal16(reply->pub));
1274 // !!!KRS we need to update the SRV here!
1275 n->PublicPort = reply->pub;
1276
1277 n->retry = mDNSPlatformTimeNow(m) + ((mDNSs32)lease * mDNSPlatformOneSecond / 2); // retry half way to expiration
1278
1279 if (n->state == NATState_Refresh) { n->state = NATState_Established; return; }
1280 n->state = NATState_Established;
1281
1282 end:
1283 if (n->state != NATState_Established && n->state != NATState_Legacy)
1284 {
1285 LogMsg("NAT Port Mapping: timeout");
1286 n->state = NATState_Error;
1287 if (srs) srs->uDNS_info.state = regState_NATError;
1288 else LLQNatMapComplete(m);
1289 return; // note - unsafe to touch srs here
1290 }
1291
1292 LogMsg("Mapped private port %d to public port %d", mDNSVal16(priv), mDNSVal16(n->PublicPort));
1293 if (!srs) { LLQNatMapComplete(m); return; }
1294
1295 if (srs->uDNS_info.ns.ip.v4.NotAnInteger) SendServiceRegistration(m, srs); // non-zero server address means we already have necessary zone data to send update
1296 else
1297 {
1298 srs->uDNS_info.state = regState_FetchingZoneData;
1299 startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
1300 }
1301 }
1302
1303 mDNSlocal void FormatPortMaprequest(NATTraversalInfo *info, mDNSIPPort port)
1304 {
1305 NATPortMapRequest *req = &info->request.PortReq;
1306
1307 req->vers = NATMAP_VERS;
1308 req->opcode = info->op;
1309 req->unused.NotAnInteger = 0;
1310 req->priv = port;
1311 req->pub = port;
1312 req->lease = mDNSOpaque32fromIntVal(NATMAP_DEFAULT_LEASE);
1313 }
1314
1315 mDNSlocal void SendInitialPMapReq(mDNS *m, NATTraversalInfo *info)
1316 {
1317 if (!m->uDNS_info.Router.ip.v4.NotAnInteger)
1318 {
1319 debugf("No router. Will retry NAT traversal in %ld seconds", NATMAP_INIT_RETRY);
1320 info->retry = mDNSPlatformTimeNow(m) + NATMAP_INIT_RETRY;
1321 info->RetryInterval = NATMAP_INIT_RETRY;
1322 return;
1323 }
1324 SendNATMsg(info, m);
1325 return;
1326 }
1327
1328 mDNSlocal void StartNATPortMap(mDNS *m, ServiceRecordSet *srs)
1329 {
1330 NATOp_t op;
1331 NATTraversalInfo *info;
1332
1333 if (DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp")) op = NATOp_MapTCP;
1334 else if (DomainContainsLabelString(srs->RR_PTR.resrec.name, "_udp")) op = NATOp_MapUDP;
1335 else { LogMsg("StartNATPortMap: could not determine transport protocol of service %##s", srs->RR_SRV.resrec.name->c); goto error; }
1336
1337 if (srs->uDNS_info.NATinfo) { LogMsg("Error: StartNATPortMap - NAT info already initialized!"); FreeNATInfo(m, srs->uDNS_info.NATinfo); }
1338 info = AllocNATInfo(m, op, ReceivePortMapReply);
1339 srs->uDNS_info.NATinfo = info;
1340 info->reg.ServiceRegistration = srs;
1341 info->state = NATState_Request;
1342
1343 FormatPortMaprequest(info, srs->RR_SRV.resrec.rdata->u.srv.port);
1344 SendInitialPMapReq(m, info);
1345 return;
1346
1347 error:
1348 startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
1349 }
1350
1351 mDNSlocal void DeleteNATPortMapping(mDNS *m, NATTraversalInfo *nat, ServiceRecordSet *srs)
1352 {
1353 if (nat->state == NATState_Established) // let other edge-case states expire for simplicity
1354 {
1355 // zero lease
1356 nat->request.PortReq.lease.NotAnInteger = 0;
1357 nat->state = NATState_Request;
1358 SendNATMsg(nat, m);
1359 }
1360 #ifdef _LEGACY_NAT_TRAVERSAL_
1361 else if (nat->state == NATState_Legacy)
1362 {
1363 mStatus err = mStatus_NoError;
1364 mDNSBool tcp = srs ? DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp") : mDNSfalse;
1365 err = LNT_UnmapPort(nat->PublicPort, tcp);
1366 if (err) LogMsg("Legacy NAT Traversal - unmap request failed with error %ld", err);
1367 }
1368 #else
1369 (void)srs; // unused
1370 #endif // _LEGACY_NAT_TRAVERSAL_
1371 }
1372
1373 mDNSlocal void StartLLQNatMap(mDNS *m)
1374 {
1375 NATTraversalInfo *info = AllocNATInfo(m, NATOp_MapUDP, ReceivePortMapReply);
1376 uDNS_GlobalInfo *u = &m->uDNS_info;
1377
1378 u->LLQNatInfo = info;
1379
1380 info->reg.RecordRegistration = mDNSNULL;
1381 info->reg.ServiceRegistration = mDNSNULL;
1382 info->state = NATState_Request;
1383 FormatPortMaprequest(info, m->UnicastPort4);
1384 SendInitialPMapReq(m, info);
1385 return;
1386 }
1387
1388 // if LLQ NAT context unreferenced, delete the mapping
1389 mDNSlocal void CheckForUnreferencedLLQMapping(mDNS *m)
1390 {
1391 NATTraversalInfo *nat = m->uDNS_info.LLQNatInfo;
1392 DNSQuestion *q;
1393
1394 if (!nat) return;
1395
1396 for (q = m->uDNS_info.ActiveQueries; q; q = q->next)
1397 if (q->LongLived && q->uDNS_info.llq->NATMap) return;
1398
1399 //to avoid race condition if we need to recreate before this finishes, we do one-shot deregistration
1400 if (nat->state == NATState_Established || nat->state == NATState_Legacy)
1401 DeleteNATPortMapping(m, nat, mDNSNULL); // for simplicity we allow other states to expire
1402 FreeNATInfo(m, nat); // note: this clears the global LLQNatInfo pointer
1403 }
1404
1405 // ***************************************************************************
1406 #if COMPILER_LIKES_PRAGMA_MARK
1407 #pragma mark - host name and interface management
1408 #endif
1409
1410 // if we ever want to refine support for multiple hostnames, we can add logic matching service names to a particular hostname
1411 // for now, we grab the first registered DynDNS name, if any, or a static name we learned via a reverse-map query
1412 mDNSlocal mDNSBool GetServiceTarget(uDNS_GlobalInfo *u, AuthRecord *srv, domainname *dst)
1413 {
1414 uDNS_HostnameInfo *hi = u->Hostnames;
1415 (void)srv; // unused
1416
1417 dst->c[0] = 0;
1418 while (hi)
1419 {
1420 if (hi->ar->uDNS_info.state == regState_Registered || hi->ar->uDNS_info.state == regState_Refresh)
1421 { AssignDomainName(dst, hi->ar->resrec.name); return mDNStrue; }
1422 hi = hi->next;
1423 }
1424
1425 if (u->StaticHostname.c[0]) { AssignDomainName(dst, &u->StaticHostname); return mDNStrue; }
1426 return mDNSfalse;
1427 }
1428
1429 mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs)
1430 {
1431 uDNS_GlobalInfo *u = &m->uDNS_info;
1432 ExtraResourceRecord *e;
1433
1434 // Target change if:
1435 // We have a target and were previously waiting for one, or
1436 // We had a target and no longer do, or
1437 // The target has changed
1438
1439 domainname newtarget;
1440 domainname *curtarget = &srs->RR_SRV.resrec.rdata->u.srv.target;
1441 mDNSBool HaveTarget = GetServiceTarget(u, &srs->RR_SRV, &newtarget);
1442 mDNSBool TargetChanged = (HaveTarget && srs->uDNS_info.state == regState_NoTarget) || (curtarget->c[0] && !HaveTarget) || !SameDomainName(curtarget, &newtarget);
1443 mDNSBool HaveZoneData = srs->uDNS_info.ns.ip.v4.NotAnInteger ? mDNStrue : mDNSfalse;
1444
1445 // Nat state change if:
1446 // We were behind a NAT, and now we are behind a new NAT, or
1447 // We're not behind a NAT but our port was previously mapped to a different public port
1448 // We were not behind a NAT and now we are
1449
1450 NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
1451 mDNSIPPort port = srs->RR_SRV.resrec.rdata->u.srv.port;
1452 mDNSBool NATChanged = mDNSfalse;
1453 mDNSBool NowBehindNAT = port.NotAnInteger && IsPrivateV4Addr(&u->PrimaryIP);
1454 mDNSBool WereBehindNAT = nat != mDNSNULL;
1455 mDNSBool NATRouterChanged = nat && nat->Router.ip.v4.NotAnInteger != u->Router.ip.v4.NotAnInteger;
1456 mDNSBool PortWasMapped = nat && (nat->state == NATState_Established || nat->state == NATState_Legacy) && nat->PublicPort.NotAnInteger != port.NotAnInteger;
1457
1458 if (WereBehindNAT && NowBehindNAT && NATRouterChanged) NATChanged = mDNStrue;
1459 else if (!NowBehindNAT && PortWasMapped) NATChanged = mDNStrue;
1460 else if (!WereBehindNAT && NowBehindNAT) NATChanged = mDNStrue;
1461
1462 if (!TargetChanged && !NATChanged) return;
1463
1464 debugf("UpdateSRV (%##s) HadZoneData=%d, TargetChanged=%d, HaveTarget=%d, NowBehindNAT=%d, WereBehindNAT=%d, NATRouterChanged=%d, PortWasMapped=%d",
1465 srs->RR_SRV.resrec.name->c, HaveZoneData, TargetChanged, HaveTarget, NowBehindNAT, WereBehindNAT, NATRouterChanged, PortWasMapped);
1466
1467 switch(srs->uDNS_info.state)
1468 {
1469 case regState_FetchingZoneData:
1470 case regState_Cancelled:
1471 case regState_DeregPending:
1472 case regState_DeregDeferred:
1473 case regState_Unregistered:
1474 case regState_NATMap:
1475 case regState_ExtraQueued:
1476 // In these states, the SRV has either not yet been registered (it will get up-to-date information when it is)
1477 // or is in the process of, or has already been, deregistered
1478 return;
1479
1480 case regState_Pending:
1481 case regState_Refresh:
1482 case regState_UpdatePending:
1483 // let the in-flight operation complete before updating
1484 srs->uDNS_info.SRVUpdateDeferred = mDNStrue;
1485 return;
1486
1487 case regState_NATError:
1488 if (!NATChanged) return;
1489 // if nat changed, register if we have a target (below)
1490
1491 case regState_NoTarget:
1492 if (HaveTarget)
1493 {
1494 debugf("UpdateSRV: %s service %##s", HaveZoneData ? (NATChanged && NowBehindNAT ? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs->RR_SRV.resrec.name->c);
1495 if (!HaveZoneData)
1496 {
1497 srs->uDNS_info.state = regState_FetchingZoneData;
1498 startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
1499 }
1500 else
1501 {
1502 if (nat && (NATChanged || !NowBehindNAT)) { srs->uDNS_info.NATinfo = mDNSNULL; FreeNATInfo(m, nat); }
1503 if (NATChanged && NowBehindNAT) { srs->uDNS_info.state = regState_NATMap; StartNATPortMap(m, srs); }
1504 else SendServiceRegistration(m, srs);
1505 }
1506 }
1507 return;
1508
1509 case regState_Registered:
1510 // target or nat changed. deregister service. upon completion, we'll look for a new target
1511 debugf("UpdateSRV: SRV record changed for service %##s - deregistering (will re-register with new SRV)", srs->RR_SRV.resrec.name->c);
1512 for (e = srs->Extras; e; e = e->next) e->r.uDNS_info.state = regState_ExtraQueued; // extra will be re-registed if the service is re-registered
1513 srs->uDNS_info.SRVChanged = mDNStrue;
1514 SendServiceDeregistration(m, srs);
1515 return;
1516 }
1517 }
1518
1519 mDNSlocal void UpdateSRVRecords(mDNS *m)
1520 {
1521 ServiceRecordSet *srs;
1522
1523 for (srs = m->uDNS_info.ServiceRegistrations; srs; srs = srs->next) UpdateSRV(m, srs);
1524 }
1525
1526 mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
1527 {
1528 uDNS_HostnameInfo *hi = (uDNS_HostnameInfo *)rr->RecordContext;
1529 mDNSu8 *ip = rr->resrec.rdata->u.ipv4.b;
1530
1531 if (result == mStatus_MemFree)
1532 {
1533 debugf("MemFree: %##s IP %d.%d.%d.%d", rr->resrec.name->c, ip[0], ip[1], ip[2], ip[3]);
1534 if (hi) ufree(hi);
1535 ufree(rr);
1536 return;
1537 }
1538
1539 if (result)
1540 {
1541 // don't unlink or free - we can retry when we get a new address/router
1542 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]);
1543 if (!hi) { ufree(rr); return; }
1544 if (hi->ar->uDNS_info.state != regState_Unregistered) LogMsg("Error: HostnameCallback invoked with error code for record not in regState_Unregistered!");
1545 rr->RecordContext = (void *)hi->StatusContext;
1546 if (hi->StatusCallback)
1547 hi->StatusCallback(m, rr, result); // client may NOT make API calls here
1548 rr->RecordContext = (void *)hi;
1549 return;
1550 }
1551
1552 // register any pending services that require a target
1553 UpdateSRVRecords(m);
1554
1555 // Deliver success to client
1556 if (!hi) { LogMsg("HostnameCallback invoked with orphaned address record"); return; }
1557 LogMsg("Registered hostname %##s IP %d.%d.%d.%d", rr->resrec.name->c, ip[0], ip[1], ip[2], ip[3]);
1558 rr->RecordContext = (void *)hi->StatusContext;
1559 if (hi->StatusCallback)
1560 hi->StatusCallback(m, rr, result); // client may NOT make API calls here
1561 rr->RecordContext = (void *)hi;
1562 }
1563
1564 // register record or begin NAT traversal
1565 mDNSlocal void AdvertiseHostname(mDNS *m, uDNS_HostnameInfo *h)
1566 {
1567 if (IsPrivateV4Addr(&m->uDNS_info.PrimaryIP))
1568 StartGetPublicAddr(m, h);
1569 else
1570 {
1571 mDNSu8 *ip = m->uDNS_info.PrimaryIP.ip.v4.b;
1572 LogMsg("Advertising %##s IP %d.%d.%d.%d", h->ar->resrec.name->c, ip[0], ip[1], ip[2], ip[3]);
1573 uDNS_RegisterRecord(m, h->ar);
1574 }
1575 }
1576
1577 mDNSlocal void FoundStaticHostname(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1578 {
1579 const domainname *pktname = &answer->rdata->u.name;
1580 domainname *storedname = &m->uDNS_info.StaticHostname;
1581 uDNS_HostnameInfo *h = m->uDNS_info.Hostnames;
1582
1583 (void)question;
1584
1585 debugf("FoundStaticHostname: %##s -> %##s (%s)", question->qname.c, answer->rdata->u.name.c, AddRecord ? "added" : "removed");
1586 if (AddRecord && !SameDomainName(pktname, storedname))
1587 {
1588 AssignDomainName(storedname, pktname);
1589 while (h)
1590 {
1591 if (h->ar && (h->ar->uDNS_info.state == regState_FetchingZoneData || h->ar->uDNS_info.state == regState_Pending || h->ar->uDNS_info.state == regState_NATMap))
1592 {
1593 // if we're in the process of registering a dynamic hostname, delay SRV update so we don't have to reregister services if the dynamic name succeeds
1594 m->uDNS_info.DelaySRVUpdate = mDNStrue;
1595 m->uDNS_info.NextSRVUpdate = mDNSPlatformTimeNow(m) + (5 * mDNSPlatformOneSecond);
1596 return;
1597 }
1598 h = h->next;
1599 }
1600 UpdateSRVRecords(m);
1601 }
1602 else if (!AddRecord && SameDomainName(pktname, storedname))
1603 {
1604 storedname->c[0] = 0;
1605 UpdateSRVRecords(m);
1606 }
1607 }
1608
1609 mDNSlocal void GetStaticHostname(mDNS *m)
1610 {
1611 char buf[MAX_ESCAPED_DOMAIN_NAME];
1612 DNSQuestion *q = &m->uDNS_info.ReverseMap;
1613 mDNSu8 *ip = m->uDNS_info.PrimaryIP.ip.v4.b;
1614 mStatus err;
1615
1616 if (m->uDNS_info.ReverseMapActive)
1617 {
1618 uDNS_StopQuery(m, q);
1619 m->uDNS_info.ReverseMapActive = mDNSfalse;
1620 }
1621
1622 m->uDNS_info.StaticHostname.c[0] = 0;
1623 if (!m->uDNS_info.PrimaryIP.ip.v4.NotAnInteger) return;
1624 ubzero(q, sizeof(*q));
1625 mDNS_snprintf(buf, MAX_ESCAPED_DOMAIN_NAME, "%d.%d.%d.%d.in-addr.arpa.", ip[3], ip[2], ip[1], ip[0]);
1626 if (!MakeDomainNameFromDNSNameString(&q->qname, buf)) { LogMsg("Error: GetStaticHostname - bad name %s", buf); return; }
1627
1628 q->InterfaceID = mDNSInterface_Any;
1629 q->Target = zeroAddr;
1630 q->qtype = kDNSType_PTR;
1631 q->qclass = kDNSClass_IN;
1632 q->LongLived = mDNSfalse;
1633 q->ExpectUnique = mDNSfalse;
1634 q->ForceMCast = mDNSfalse;
1635 q->QuestionCallback = FoundStaticHostname;
1636 q->QuestionContext = mDNSNULL;
1637
1638 err = uDNS_StartQuery(m, q);
1639 if (err) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err);
1640 else m->uDNS_info.ReverseMapActive = mDNStrue;
1641 }
1642
1643 // Deregister hostnames and register new names for each host domain with the current global
1644 // values for the hostlabel and primary IP address
1645 mDNSlocal void UpdateHostnameRegistrations(mDNS *m)
1646 {
1647 uDNS_GlobalInfo *u = &m->uDNS_info;
1648 AuthRecord *new;
1649 uDNS_HostnameInfo *i;
1650
1651 for (i = u->Hostnames; i; i = i->next)
1652 {
1653 // only allocate new record if existing record is actually registered (i.e. it wasn't pending the hostname or IP being set)
1654 if (i->ar->uDNS_info.state == regState_Unregistered) new = i->ar;
1655 else
1656 {
1657 new = umalloc(sizeof(AuthRecord));
1658 if (!new) { LogMsg("ERROR: UpdateHostnameRegistration - malloc"); return; }
1659 mDNS_SetupResourceRecord(new, mDNSNULL, 0, kDNSType_A, kWideAreaTTL, kDNSRecordTypeKnownUnique, HostnameCallback, i);
1660 }
1661
1662 // setup new record
1663 AssignDomainName(new->resrec.name, i->ar->resrec.name);
1664 new->resrec.rdata->u.ipv4 = u->PrimaryIP.ip.v4;
1665
1666 if (i->ar->uDNS_info.state != regState_Unregistered)
1667 {
1668 // delete old record
1669 i->ar->RecordContext = mDNSNULL; // clear backpointer to HostnameInfo
1670 uDNS_DeregisterRecord(m, i->ar);
1671 i->ar = new;
1672 }
1673
1674 // advertise new
1675 AdvertiseHostname(m, i);
1676 }
1677 }
1678
1679 mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
1680 {
1681 uDNS_GlobalInfo *u = &m->uDNS_info;
1682 uDNS_HostnameInfo *ptr, *new;
1683
1684 mDNS_Lock(m);
1685
1686 // check if domain already registered
1687 for (ptr = u->Hostnames; ptr; ptr = ptr->next)
1688 {
1689 if (SameDomainName(fqdn, ptr->ar->resrec.name))
1690 { LogMsg("Host Domain %##s already in list", fqdn->c); goto exit; }
1691 }
1692
1693 // allocate and format new address record
1694 new = umalloc(sizeof(*new));
1695 if (new) new->ar = umalloc(sizeof(AuthRecord));
1696 if (!new || !new->ar) { LogMsg("ERROR: mDNS_AddDynDNSHostname - malloc"); goto exit; }
1697 new->StatusCallback = StatusCallback;
1698 new->StatusContext = StatusContext;
1699 mDNS_SetupResourceRecord(new->ar, mDNSNULL, 0, kDNSType_A, 1, kDNSRecordTypeKnownUnique, HostnameCallback, new);
1700 AppendDomainName(new->ar->resrec.name, fqdn);
1701 new->next = u->Hostnames;
1702 u->Hostnames = new;
1703 if (u->PrimaryIP.ip.v4.NotAnInteger)
1704 {
1705 // only set RData if we have a valid IP
1706 if (u->MappedPrimaryIP.ip.v4.NotAnInteger) new->ar->resrec.rdata->u.ipv4 = u->MappedPrimaryIP.ip.v4; //!!!KRS implement code that caches this
1707 else new->ar->resrec.rdata->u.ipv4 = u->PrimaryIP.ip.v4;
1708 AdvertiseHostname(m, new);
1709 }
1710 else new->ar->uDNS_info.state = regState_Unregistered;
1711 exit:
1712 mDNS_Unlock(m);
1713 }
1714
1715 mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn)
1716 {
1717 uDNS_GlobalInfo *u = &m->uDNS_info;
1718 uDNS_HostnameInfo **ptr = &u->Hostnames;
1719
1720 mDNS_Lock(m);
1721
1722 while (*ptr && !SameDomainName(fqdn, (*ptr)->ar->resrec.name)) ptr = &(*ptr)->next;
1723 if (!*ptr) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn->c);
1724 else
1725 {
1726 uDNS_HostnameInfo *hi = *ptr;
1727 *ptr = (*ptr)->next; // unlink
1728 hi->ar->RecordContext = mDNSNULL; // about to free wrapper struct
1729 if (hi->ar->uDNS_info.state != regState_Unregistered) uDNS_DeregisterRecord(m, hi->ar);
1730 else { ufree(hi->ar); hi->ar = mDNSNULL; }
1731 ufree(hi);
1732 }
1733 UpdateSRVRecords(m);
1734 mDNS_Unlock(m);
1735 }
1736
1737 mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *addr, const mDNSAddr *router)
1738 {
1739 uDNS_GlobalInfo *u = &m->uDNS_info;
1740 mDNSBool AddrChanged, RouterChanged;
1741
1742 if (addr && addr->type !=mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-V4 address. Discarding."); return; }
1743 if (router && router->type !=mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-V4 address. Discarding."); return; }
1744 mDNS_Lock(m);
1745
1746 AddrChanged = ((addr ? addr ->ip.v4.NotAnInteger : 0) != u->PrimaryIP.ip.v4.NotAnInteger);
1747 RouterChanged = ((router ? router->ip.v4.NotAnInteger : 0) != u->Router .ip.v4.NotAnInteger);
1748
1749 #if MDNS_DEBUGMSGS
1750 if (addr && (AddrChanged || RouterChanged))
1751 LogMsg("mDNS_SetPrimaryInterfaceInfo: address changed from %d.%d.%d.%d to %d.%d.%d.%d:%d",
1752 u->PrimaryIP.ip.v4.b[0], u->PrimaryIP.ip.v4.b[1], u->PrimaryIP.ip.v4.b[2], u->PrimaryIP.ip.v4.b[3],
1753 addr->ip.v4.b[0], addr->ip.v4.b[1], addr->ip.v4.b[2], addr->ip.v4.b[3], mDNSVal16(m->UnicastPort4));
1754 #endif // MDNS_DEBUGMSGS
1755
1756 if (addr) u->PrimaryIP = *addr;
1757 if (router) u->Router = *router;
1758 else u->Router.ip.v4.NotAnInteger = 0; // setting router to zero indicates that nat mappings must be reestablished when router is reset
1759
1760 if ((AddrChanged || RouterChanged ) && (addr && router))
1761 {
1762 UpdateHostnameRegistrations(m);
1763 UpdateSRVRecords(m);
1764 GetStaticHostname(m); // look up reverse map record to find any static hostnames for our IP address
1765 }
1766
1767 mDNS_Unlock(m);
1768 }
1769
1770 // ***************************************************************************
1771 #if COMPILER_LIKES_PRAGMA_MARK
1772 #pragma mark - Incoming Message Processing
1773 #endif
1774
1775 mDNSlocal mDNSBool kaListContainsAnswer(DNSQuestion *question, CacheRecord *rr)
1776 {
1777 CacheRecord *ptr;
1778
1779 for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next)
1780 if (SameResourceRecord(&ptr->resrec, &rr->resrec)) return mDNStrue;
1781
1782 return mDNSfalse;
1783 }
1784
1785
1786 mDNSlocal void removeKnownAnswer(DNSQuestion *question, CacheRecord *rr)
1787 {
1788 CacheRecord *ptr, *prev = mDNSNULL;
1789
1790 for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next)
1791 {
1792 if (SameResourceRecord(&ptr->resrec, &rr->resrec))
1793 {
1794 if (prev) prev->next = ptr->next;
1795 else question->uDNS_info.knownAnswers = ptr->next;
1796 ufree(ptr);
1797 return;
1798 }
1799 prev = ptr;
1800 }
1801 LogMsg("removeKnownAnswer() called for record not in KA list");
1802 }
1803
1804
1805 mDNSlocal void addKnownAnswer(DNSQuestion *question, const CacheRecord *rr)
1806 {
1807 CacheRecord *newCR = mDNSNULL;
1808 mDNSu32 size;
1809
1810 size = sizeof(CacheRecord) + rr->resrec.rdlength - InlineCacheRDSize;
1811 newCR = (CacheRecord *)umalloc(size);
1812 if (!newCR) { LogMsg("ERROR: addKnownAnswer - malloc"); return; }
1813 umemcpy(newCR, rr, size);
1814 newCR->resrec.rdata = (RData*)&newCR->rdatastorage;
1815 newCR->resrec.rdata->MaxRDLength = rr->resrec.rdlength;
1816 newCR->resrec.name = &question->qname;
1817 newCR->next = question->uDNS_info.knownAnswers;
1818 question->uDNS_info.knownAnswers = newCR;
1819 }
1820
1821 mDNSlocal void deriveGoodbyes(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question)
1822 {
1823 const mDNSu8 *ptr;
1824 int i;
1825 CacheRecord *fptr, *ka, *cr, *answers = mDNSNULL, *prev = mDNSNULL;
1826 LargeCacheRecord *lcr;
1827
1828 if (question != m->uDNS_info.CurrentQuery) { LogMsg("ERROR: deriveGoodbyes called without CurrentQuery set!"); return; }
1829
1830 ptr = LocateAnswers(msg, end);
1831 if (!ptr) goto pkt_error;
1832
1833 if (!msg->h.numAnswers)
1834 {
1835 // delete the whole KA list
1836 ka = question->uDNS_info.knownAnswers;
1837 while (ka)
1838 {
1839 debugf("deriving goodbye for %##s", ka->resrec.name->c);
1840
1841 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
1842 question->QuestionCallback(m, question, &ka->resrec, mDNSfalse);
1843 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
1844 if (question != m->uDNS_info.CurrentQuery)
1845 {
1846 debugf("deriveGoodbyes - question removed via callback. returning.");
1847 return;
1848 }
1849 fptr = ka;
1850 ka = ka->next;
1851 ufree(fptr);
1852 }
1853 question->uDNS_info.knownAnswers = mDNSNULL;
1854 return;
1855 }
1856
1857 // make a list of all the new answers
1858 for (i = 0; i < msg->h.numAnswers; i++)
1859 {
1860 lcr = (LargeCacheRecord *)umalloc(sizeof(LargeCacheRecord));
1861 if (!lcr) goto malloc_error;
1862 ubzero(lcr, sizeof(LargeCacheRecord));
1863 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAns, lcr);
1864 if (!ptr) goto pkt_error;
1865 cr = &lcr->r;
1866 if (ResourceRecordAnswersQuestion(&cr->resrec, question))
1867 {
1868 cr->next = answers;
1869 answers = cr;
1870 }
1871 else ufree(cr);
1872 }
1873
1874 // make sure every known answer is in the answer list
1875 ka = question->uDNS_info.knownAnswers;
1876 while (ka)
1877 {
1878 for (cr = answers; cr; cr = cr->next)
1879 { if (SameResourceRecord(&ka->resrec, &cr->resrec)) break; }
1880 if (!cr)
1881 {
1882 // record is in KA list but not answer list - remove from KA list
1883 if (prev) prev->next = ka->next;
1884 else question->uDNS_info.knownAnswers = ka->next;
1885 debugf("deriving goodbye for %##s", ka->resrec.name->c);
1886 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
1887 question->QuestionCallback(m, question, &ka->resrec, mDNSfalse);
1888 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
1889 if (question != m->uDNS_info.CurrentQuery)
1890 {
1891 debugf("deriveGoodbyes - question removed via callback. returning.");
1892 return;
1893 }
1894 fptr = ka;
1895 ka = ka->next;
1896 ufree(fptr);
1897 }
1898 else
1899 {
1900 prev = ka;
1901 ka = ka->next;
1902 }
1903 }
1904
1905 // free temp answers list
1906 cr = answers;
1907 while (cr) { fptr = cr; cr = cr->next; ufree(fptr); }
1908
1909 return;
1910
1911 pkt_error:
1912 LogMsg("ERROR: deriveGoodbyes - received malformed response to query for %##s (%d)",
1913 question->qname.c, question->qtype);
1914 return;
1915
1916 malloc_error:
1917 LogMsg("ERROR: Malloc");
1918 }
1919
1920 mDNSlocal void pktResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, mDNSBool llq)
1921 {
1922 const mDNSu8 *ptr;
1923 int i;
1924 LargeCacheRecord lcr;
1925 CacheRecord *cr = &lcr.r;
1926 mDNSBool goodbye, inKAList, followedCName = mDNSfalse;
1927 LLQ_Info *llqInfo = question->uDNS_info.llq;
1928 domainname origname;
1929 origname.c[0] = 0;
1930
1931 if (question != m->uDNS_info.CurrentQuery)
1932 { LogMsg("ERROR: pktResponseHdnlr called without CurrentQuery ptr set!"); return; }
1933
1934 question->uDNS_info.Answered = mDNStrue;
1935
1936 ptr = LocateAnswers(msg, end);
1937 if (!ptr) goto pkt_error;
1938
1939 for (i = 0; i < msg->h.numAnswers; i++)
1940 {
1941 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
1942 if (!ptr) goto pkt_error;
1943 if (ResourceRecordAnswersQuestion(&cr->resrec, question))
1944 {
1945 if (cr->resrec.rrtype == kDNSType_CNAME)
1946 {
1947 if (followedCName) LogMsg("Error: multiple CNAME referals for question %##s", question->qname.c);
1948 else
1949 {
1950 debugf("Following cname %##s -> %##s", question->qname.c, cr->resrec.rdata->u.name.c);
1951 AssignDomainName(&origname, &question->qname);
1952 AssignDomainName(&question->qname, &cr->resrec.rdata->u.name);
1953 question->qnamehash = DomainNameHashValue(&question->qname);
1954 followedCName = mDNStrue;
1955 i = -1; // restart packet answer matching
1956 ptr = LocateAnswers(msg, end);
1957 continue;
1958 }
1959 }
1960
1961 goodbye = llq ? ((mDNSs32)cr->resrec.rroriginalttl == -1) : mDNSfalse;
1962 inKAList = kaListContainsAnswer(question, cr);
1963
1964 if ((goodbye && !inKAList) || (!goodbye && inKAList)) continue; // list up to date
1965 if (!inKAList) addKnownAnswer(question, cr);
1966 if (goodbye) removeKnownAnswer(question, cr);
1967 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
1968 question->QuestionCallback(m, question, &cr->resrec, !goodbye);
1969 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
1970 if (question != m->uDNS_info.CurrentQuery)
1971 {
1972 debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning");
1973 return;
1974 }
1975 }
1976 else if (!followedCName || !SameDomainName(cr->resrec.name, &origname))
1977 LogMsg("Question %##s %X %s %##s- unexpected answer %##s %X %s",
1978 question->qname.c, question->qnamehash, DNSTypeName(question->qtype), origname.c,
1979 cr->resrec.name->c, cr->resrec.namehash, DNSTypeName(cr->resrec.rrtype));
1980 }
1981
1982 if (!llq || llqInfo->state == LLQ_Poll || llqInfo->deriveRemovesOnResume)
1983 {
1984 deriveGoodbyes(m, msg, end,question);
1985 if (llq && llqInfo->deriveRemovesOnResume) llqInfo->deriveRemovesOnResume = mDNSfalse;
1986 }
1987
1988 // our interval may be set lower to recover from failures - now that we have an answer, fully back off retry
1989 if (question->ThisQInterval < MAX_UCAST_POLL_INTERVAL) question->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
1990 return;
1991
1992 pkt_error:
1993 LogMsg("ERROR: pktResponseHndlr - received malformed response to query for %##s (%d)",
1994 question->qname.c, question->qtype);
1995 return;
1996 }
1997
1998 mDNSlocal void simpleResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *context)
1999 {
2000 (void)context; // unused
2001 pktResponseHndlr(m, msg, end, question, mDNSfalse);
2002 }
2003
2004 mDNSlocal void llqResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *context)
2005 {
2006 (void)context; // unused
2007 pktResponseHndlr(m, msg, end, question, mDNStrue);
2008 }
2009
2010 mDNSlocal mStatus ParseTSIGError(mDNS *m, const DNSMessage *msg, const mDNSu8 *end, const domainname *displayname)
2011 {
2012 LargeCacheRecord lcr;
2013 const mDNSu8 *ptr;
2014 mStatus err = mStatus_NoError;
2015 int i;
2016
2017 ptr = LocateAdditionals(msg, end);
2018 if (!ptr) goto finish;
2019
2020 for (i = 0; i < msg->h.numAdditionals; i++)
2021 {
2022 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
2023 if (!ptr) goto finish;
2024 if (lcr.r.resrec.rrtype == kDNSType_TSIG)
2025 {
2026 mDNSu32 macsize;
2027 mDNSu8 *rd = lcr.r.resrec.rdata->u.data;
2028 mDNSu8 *rdend = rd + MaximumRDSize;
2029 int alglen = DomainNameLength(&lcr.r.resrec.rdata->u.name);
2030
2031 if (rd + alglen > rdend) goto finish;
2032 rd += alglen; // algorithm name
2033 if (rd + 6 > rdend) goto finish;
2034 rd += 6; // 48-bit timestamp
2035 if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
2036 rd += sizeof(mDNSOpaque16); // fudge
2037 if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
2038 macsize = mDNSVal16(*(mDNSOpaque16 *)rd);
2039 rd += sizeof(mDNSOpaque16); // MAC size
2040 if (rd + macsize > rdend) goto finish;
2041 rd += macsize;
2042 if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
2043 rd += sizeof(mDNSOpaque16); // orig id
2044 if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
2045 err = mDNSVal16(*(mDNSOpaque16 *)rd); // error code
2046
2047 if (err == TSIG_ErrBadSig) { LogMsg("%##s: bad signature", displayname->c); err = mStatus_BadSig; }
2048 else if (err == TSIG_ErrBadKey) { LogMsg("%##s: bad key", displayname->c); err = mStatus_BadKey; }
2049 else if (err == TSIG_ErrBadTime) { LogMsg("%##s: bad time", displayname->c); err = mStatus_BadTime; }
2050 else if (err) { LogMsg("%##s: unknown tsig error %d", displayname->c, err); err = mStatus_UnknownErr; }
2051 goto finish;
2052 }
2053 }
2054
2055 finish:
2056 return err;
2057 }
2058
2059 mDNSlocal mStatus checkUpdateResult(domainname *displayname, mDNSu8 rcode, mDNS *m, const DNSMessage *msg, const mDNSu8 *end)
2060 {
2061 (void)msg; // currently unused, needed for TSIG errors
2062 if (!rcode) return mStatus_NoError;
2063 else if (rcode == kDNSFlag1_RC_YXDomain)
2064 {
2065 LogMsg("name in use: %##s", displayname->c);
2066 return mStatus_NameConflict;
2067 }
2068 else if (rcode == kDNSFlag1_RC_Refused)
2069 {
2070 LogMsg("Update %##s refused", displayname->c);
2071 return mStatus_Refused;
2072 }
2073 else if (rcode == kDNSFlag1_RC_NXRRSet)
2074 {
2075 LogMsg("Reregister refused (NXRRSET): %##s", displayname->c);
2076 return mStatus_NoSuchRecord;
2077 }
2078 else if (rcode == kDNSFlag1_RC_NotAuth)
2079 {
2080 // TSIG errors should come with FmtErr as per RFC 2845, but BIND 9 sends them with NotAuth so we look here too
2081 mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
2082 if (!tsigerr)
2083 {
2084 LogMsg("Permission denied (NOAUTH): %##s", displayname->c);
2085 return mStatus_UnknownErr;
2086 }
2087 else return tsigerr;
2088 }
2089 else if (rcode == kDNSFlag1_RC_FmtErr)
2090 {
2091 mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
2092 if (!tsigerr)
2093 {
2094 LogMsg("Format Error: %##s", displayname->c);
2095 return mStatus_UnknownErr;
2096 }
2097 else return tsigerr;
2098 }
2099 else
2100 {
2101 LogMsg("Update %##s failed with rcode %d", displayname->c, rcode);
2102 return mStatus_UnknownErr;
2103 }
2104 }
2105
2106 mDNSlocal void hndlServiceUpdateReply(mDNS * const m, ServiceRecordSet *srs, mStatus err)
2107 {
2108 mDNSBool InvokeCallback = mDNSfalse;
2109 uDNS_RegInfo *info = &srs->uDNS_info;
2110 NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
2111 ExtraResourceRecord **e = &srs->Extras;
2112
2113 switch (info->state)
2114 {
2115 case regState_Pending:
2116 if (err == mStatus_NameConflict && !info->TestForSelfConflict)
2117 {
2118 info->TestForSelfConflict = mDNStrue;
2119 debugf("checking for self-conflict of service %##s", srs->RR_SRV.resrec.name->c);
2120 SendServiceRegistration(m, srs);
2121 return;
2122 }
2123 else if (info->TestForSelfConflict)
2124 {
2125 info->TestForSelfConflict = mDNSfalse;
2126 if (err == mStatus_NoSuchRecord) err = mStatus_NameConflict; // NoSuchRecord implies that our prereq was not met, so we actually have a name conflict
2127 if (err) info->state = regState_Unregistered;
2128 else info->state = regState_Registered;
2129 InvokeCallback = mDNStrue;
2130 break;
2131 }
2132 else if (err == mStatus_UnknownErr && info->lease)
2133 {
2134 LogMsg("Re-trying update of service %##s without lease option", srs->RR_SRV.resrec.name->c);
2135 info->lease = mDNSfalse;
2136 SendServiceRegistration(m, srs);
2137 return;
2138 }
2139 else
2140 {
2141 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
2142 else info->state = regState_Registered;
2143 InvokeCallback = mDNStrue;
2144 break;
2145 }
2146 case regState_Refresh:
2147 if (err)
2148 {
2149 LogMsg("Error %ld for refresh of service %##s", err, srs->RR_SRV.resrec.name->c);
2150 InvokeCallback = mDNStrue;
2151 info->state = regState_Unregistered;
2152 }
2153 else info->state = regState_Registered;
2154 break;
2155 case regState_DeregPending:
2156 if (err) LogMsg("Error %ld for deregistration of service %##s", err, srs->RR_SRV.resrec.name->c);
2157 if (info->SRVChanged)
2158 {
2159 info->state = regState_NoTarget; // NoTarget will allow us to pick up new target OR nat traversal state
2160 break;
2161 }
2162 err = mStatus_MemFree;
2163 InvokeCallback = mDNStrue;
2164 if (nat)
2165 {
2166 if (nat->state == NATState_Deleted) { FreeNATInfo(m, nat); info->NATinfo = mDNSNULL; } // deletion copmleted
2167 else nat->reg.ServiceRegistration = mDNSNULL; // allow mapping deletion to continue
2168 }
2169 info->state = regState_Unregistered;
2170 break;
2171 case regState_DeregDeferred:
2172 if (err)
2173 {
2174 debugf("Error %ld received prior to deferred derigstration of %##s", err, srs->RR_SRV.resrec.name->c);
2175 err = mStatus_MemFree;
2176 InvokeCallback = mDNStrue;
2177 info->state = regState_Unregistered;
2178 break;
2179 }
2180 else
2181 {
2182 debugf("Performing deferred deregistration of %##s", srs->RR_SRV.resrec.name->c);
2183 info->state = regState_Registered;
2184 SendServiceDeregistration(m, srs);
2185 return;
2186 }
2187 case regState_UpdatePending:
2188 // mDNS clients don't expect asyncronous UpdateRecord errors, so we just log (rare) failures
2189 if (err) LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs->RR_SRV.resrec.name->c);
2190 info->state = regState_Registered;
2191 SwapRData(m, &srs->RR_TXT, mDNStrue); // deallocate old rdata
2192 break;
2193 case regState_FetchingZoneData:
2194 case regState_Registered:
2195 case regState_Cancelled:
2196 case regState_Unregistered:
2197 case regState_NATMap:
2198 case regState_NoTarget:
2199 case regState_ExtraQueued:
2200 case regState_NATError:
2201 LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %ld. Unlinking.",
2202 srs->RR_SRV.resrec.name->c, info->state, err);
2203 err = mStatus_UnknownErr;
2204 }
2205
2206 if ((info->SRVChanged || info->SRVUpdateDeferred) && (info->state == regState_NoTarget || info->state == regState_Registered))
2207 {
2208 if (InvokeCallback)
2209 {
2210 info->ClientCallbackDeferred = mDNStrue;
2211 info->DeferredStatus = err;
2212 }
2213 info->SRVChanged = mDNSfalse;
2214 UpdateSRV(m, srs);
2215 return;
2216 }
2217
2218 while (*e)
2219 {
2220 uDNS_RegInfo *einfo = &(*e)->r.uDNS_info;
2221 if (einfo->state == regState_ExtraQueued)
2222 {
2223 if (info->state == regState_Registered && !err)
2224 {
2225 // extra resource record queued for this service - copy zone info and register
2226 AssignDomainName(&einfo->zone, &info->zone);
2227 einfo->ns = info->ns;
2228 einfo->port = info->port;
2229 einfo->lease = info->lease;
2230 sendRecordRegistration(m, &(*e)->r);
2231 e = &(*e)->next;
2232 }
2233 else if (err && einfo->state != regState_Unregistered)
2234 {
2235 // unlink extra from list
2236 einfo->state = regState_Unregistered;
2237 *e = (*e)->next;
2238 }
2239 else e = &(*e)->next;
2240 }
2241 else e = &(*e)->next;
2242 }
2243
2244 if (info->state == regState_Unregistered) unlinkSRS(m, srs);
2245 else if (srs->RR_TXT.uDNS_info.UpdateQueued && !err)
2246 {
2247 if (InvokeCallback)
2248 {
2249 // if we were supposed to give a client callback, we'll do it after we update the primary txt record
2250 info->ClientCallbackDeferred = mDNStrue;
2251 info->DeferredStatus = err;
2252 }
2253 srs->RR_TXT.uDNS_info.UpdateQueued = mDNSfalse;
2254 info->state = regState_UpdatePending;
2255 SendServiceRegistration(m, srs);
2256 return;
2257 }
2258 else srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL - 1; // reset retry delay for future refreshes, dereg, etc.
2259
2260 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2261 if (InvokeCallback) srs->ServiceCallback(m, srs, err);
2262 else if (info->ClientCallbackDeferred)
2263 {
2264 info->ClientCallbackDeferred = mDNSfalse;
2265 srs->ServiceCallback(m, srs, info->DeferredStatus);
2266 }
2267 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2268 // NOTE: do not touch structures after calling ServiceCallback
2269 }
2270
2271 mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
2272 {
2273 uDNS_GlobalInfo *u = &m->uDNS_info;
2274
2275 if (rr->uDNS_info.state == regState_UpdatePending)
2276 {
2277 if (err)
2278 {
2279 LogMsg("Update record failed for %##s (err %d)", rr->resrec.name->c, err);
2280 rr->uDNS_info.state = regState_Unregistered;
2281 }
2282 else
2283 {
2284 debugf("Update record %##s - success", rr->resrec.name->c);
2285 rr->uDNS_info.state = regState_Registered;
2286 SwapRData(m, rr, mDNStrue);
2287 }
2288 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2289 if (rr->RecordCallback) rr->RecordCallback(m, rr, err);
2290 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2291 return;
2292 }
2293
2294 if (rr->uDNS_info.state == regState_DeregPending)
2295 {
2296 debugf("Received reply for deregister record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype);
2297 if (err) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %ld",
2298 rr->resrec.name->c, rr->resrec.rrtype, err);
2299 err = mStatus_MemFree;
2300 if (unlinkAR(&m->uDNS_info.RecordRegistrations, rr))
2301 LogMsg("ERROR: Could not unlink resource record following deregistration");
2302 rr->uDNS_info.state = regState_Unregistered;
2303 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2304 if (rr->RecordCallback) rr->RecordCallback(m, rr, err);
2305 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2306 return;
2307 }
2308
2309 if (rr->uDNS_info.state == regState_DeregDeferred)
2310 {
2311 if (err)
2312 {
2313 LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %ld",
2314 rr->resrec.name->c, rr->resrec.rrtype, err);
2315 unlinkAR(&m->uDNS_info.RecordRegistrations, rr);
2316 rr->uDNS_info.state = regState_Unregistered;
2317 return;
2318 }
2319 LogMsg("Calling deferred deregistration of record %##s type %d",
2320 rr->resrec.name->c, rr->resrec.rrtype);
2321 rr->uDNS_info.state = regState_Registered;
2322 uDNS_DeregisterRecord(m, rr);
2323 return;
2324 }
2325
2326 if (rr->uDNS_info.state == regState_Pending || rr->uDNS_info.state == regState_Refresh)
2327 {
2328 if (err)
2329 {
2330 if (rr->uDNS_info.lease && err == mStatus_UnknownErr)
2331 {
2332 LogMsg("Re-trying update of record %##s without lease option", rr->resrec.name->c);
2333 rr->uDNS_info.lease = mDNSfalse;
2334 sendRecordRegistration(m, rr);
2335 return;
2336 }
2337
2338 LogMsg("Registration of record %##s type %d failed with error %ld",
2339 rr->resrec.name->c, rr->resrec.rrtype, err);
2340 unlinkAR(&u->RecordRegistrations, rr);
2341 rr->uDNS_info.state = regState_Unregistered;
2342 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2343 if (rr->RecordCallback) rr->RecordCallback(m, rr, err);
2344 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2345 return;
2346 }
2347 else
2348 {
2349 if (rr->uDNS_info.UpdateQueued)
2350 {
2351 debugf("%##s: sending queued update", rr->resrec.name->c);
2352 rr->uDNS_info.state = regState_Registered;
2353 SendRecordUpdate(m ,rr, &rr->uDNS_info);
2354 return;
2355 }
2356 if (rr->uDNS_info.state == regState_Refresh)
2357 rr->uDNS_info.state = regState_Registered;
2358 else
2359 {
2360 rr->uDNS_info.state = regState_Registered;
2361 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2362 if (rr->RecordCallback) rr->RecordCallback(m, rr, err);
2363 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2364 }
2365 return;
2366 }
2367 }
2368
2369 LogMsg("Received unexpected response for record %##s type %d, in state %d, with response error %ld",
2370 rr->resrec.name->c, rr->resrec.rrtype, rr->uDNS_info.state, err);
2371 }
2372
2373
2374 mDNSlocal void SetUpdateExpiration(mDNS *m, DNSMessage *msg, const mDNSu8 *end, uDNS_RegInfo *info)
2375 {
2376 LargeCacheRecord lcr;
2377 const mDNSu8 *ptr;
2378 int i;
2379 mDNSu32 lease = 0;
2380 mDNSs32 expire;
2381
2382 ptr = LocateAdditionals(msg, end);
2383
2384 if (info->lease && (ptr = LocateAdditionals(msg, end)))
2385 {
2386 for (i = 0; i < msg->h.numAdditionals; i++)
2387 {
2388 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
2389 if (!ptr) break;
2390 if (lcr.r.resrec.rrtype == kDNSType_OPT)
2391 {
2392 if (lcr.r.resrec.rdlength < LEASE_OPT_SIZE) continue;
2393 if (lcr.r.resrec.rdata->u.opt.opt != kDNSOpt_Lease) continue;
2394 lease = lcr.r.resrec.rdata->u.opt.OptData.lease;
2395 break;
2396 }
2397 }
2398 }
2399
2400 if (lease > 0)
2401 {
2402 expire = (mDNSPlatformTimeNow(m) + (((mDNSs32)lease * mDNSPlatformOneSecond)) * 3/4);
2403 if (info->state == regState_UpdatePending)
2404 // if updating individual record, the service record set may expire sooner
2405 { if (expire - info->expire < 0) info->expire = expire; }
2406 else info->expire = expire;
2407 }
2408 else info->lease = mDNSfalse;
2409 }
2410
2411 mDNSexport void uDNS_ReceiveNATMap(mDNS *m, mDNSu8 *pkt, mDNSu16 len)
2412 {
2413 uDNS_GlobalInfo *u = &m->uDNS_info;
2414 NATTraversalInfo *ptr, *cur;
2415 NATOp_t op;
2416
2417 // check length, version, opcode
2418 if (len < sizeof(NATPortMapReply) && len < sizeof(NATAddrReply)) { LogMsg("NAT Traversal message too short (%d bytes)", len); return; }
2419 if (pkt[0] != NATMAP_VERS) { LogMsg("Received NAT Traversal response with version %d (expect version %d)", pkt[0], NATMAP_VERS); return; }
2420 op = pkt[1];
2421 if (!(op & NATMAP_RESPONSE_MASK)) { LogMsg("Received NAT Traversal message that is not a response (opcode %d)", op); return; }
2422
2423 ptr = u->NATTraversals;
2424 while (ptr)
2425 {
2426 cur = ptr;
2427 ptr = ptr->next;
2428 if ((cur->state == NATState_Request || cur->state == NATState_Refresh) &&
2429 (cur->op | NATMAP_RESPONSE_MASK) == op)
2430 cur->ReceiveResponse(cur, m, pkt, len); // callback may delete "cur"
2431 // specific request/reply matching logic handled by callback - we don't know if this was a match, so we don't break here
2432 }
2433 }
2434
2435 mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
2436 const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr,
2437 const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID)
2438 {
2439 DNSQuestion *qptr;
2440 AuthRecord *rptr;
2441 ServiceRecordSet *sptr;
2442 mStatus err = mStatus_NoError;
2443 uDNS_GlobalInfo *u = &m->uDNS_info;
2444
2445 mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
2446 mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
2447 mDNSu8 QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
2448 mDNSu8 rcode = (mDNSu8)(msg->h.flags.b[1] & kDNSFlag1_RC);
2449
2450 mDNSs32 timenow = mDNSPlatformTimeNow(m);
2451
2452 // unused
2453 (void)dstaddr;
2454 (void)dstport;
2455 (void)InterfaceID;
2456
2457 if (QR_OP == StdR)
2458 {
2459 // !!!KRS we should to a table lookup here to see if it answers an LLQ or a 1-shot
2460 // LLQ Responses over TCP not currently supported
2461 if (srcaddr && recvLLQResponse(m, msg, end, srcaddr, srcport, InterfaceID)) return;
2462
2463 for (qptr = u->ActiveQueries; qptr; qptr = qptr->next)
2464 {
2465 //!!!KRS we should have a hashtable, hashed on message id
2466 if (qptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
2467 {
2468 if (timenow - (qptr->LastQTime + RESPONSE_WINDOW) > 0)
2469 { LogMsg("uDNS_ReceiveMsg - response received after maximum allowed window. Discarding"); return; }
2470 if (msg->h.flags.b[0] & kDNSFlag0_TC)
2471 { hndlTruncatedAnswer(qptr, srcaddr, m); return; }
2472 else
2473 {
2474 u->CurrentQuery = qptr;
2475 qptr->uDNS_info.responseCallback(m, msg, end, qptr, qptr->uDNS_info.context);
2476 u->CurrentQuery = mDNSNULL;
2477 // Note: responseCallback can invalidate qptr
2478 return;
2479 }
2480 }
2481 }
2482 }
2483 if (QR_OP == UpdateR)
2484 {
2485 for (sptr = u->ServiceRegistrations; sptr; sptr = sptr->next)
2486 {
2487 if (sptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
2488 {
2489 err = checkUpdateResult(sptr->RR_SRV.resrec.name, rcode, m, msg, end);
2490 if (!err) SetUpdateExpiration(m, msg, end, &sptr->uDNS_info);
2491 hndlServiceUpdateReply(m, sptr, err);
2492 return;
2493 }
2494 }
2495 for (rptr = u->RecordRegistrations; rptr; rptr = rptr->next)
2496 {
2497 if (rptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
2498 {
2499 err = checkUpdateResult(rptr->resrec.name, rcode, m, msg, end);
2500 if (!err) SetUpdateExpiration(m, msg, end, &rptr->uDNS_info);
2501 hndlRecordUpdateReply(m, rptr, err);
2502 return;
2503 }
2504 }
2505 }
2506 debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg->h.id));
2507 }
2508
2509 // lookup a DNS Server, matching by name in split-dns configurations. Result stored in addr parameter if successful
2510 mDNSlocal mDNSBool GetServerForName(uDNS_GlobalInfo *u, const domainname *name, mDNSAddr *addr)
2511 {
2512 DNSServer *curmatch = mDNSNULL, *p = u->Servers;
2513 int i, ncount, scount, curmatchlen = -1;
2514
2515 *addr = zeroAddr;
2516 ncount = name ? CountLabels(name) : 0;
2517 while (p)
2518 {
2519 scount = CountLabels(&p->domain);
2520 if (scount <= ncount && scount > curmatchlen)
2521 {
2522 // only inspect if server's domain is longer than current best match and shorter than the name itself
2523 const domainname *tail = name;
2524 for (i = 0; i < ncount - scount; i++)
2525 tail = (domainname *)(tail->c + 1 + tail->c[0]); // find "tail" (scount labels) of name
2526 if (SameDomainName(tail, &p->domain)) { curmatch = p; curmatchlen = scount; }
2527 }
2528 p = p->next;
2529 }
2530
2531 if (curmatch)
2532 {
2533 *addr = curmatch->addr;
2534 return mDNStrue;
2535 }
2536 else return mDNSfalse;
2537 }
2538
2539 // ***************************************************************************
2540 #if COMPILER_LIKES_PRAGMA_MARK
2541 #pragma mark - Query Routines
2542 #endif
2543
2544 #define sameID(x,y) mDNSPlatformMemSame(x,y,8)
2545
2546 mDNSlocal void initializeQuery(DNSMessage *msg, DNSQuestion *question)
2547 {
2548 mDNSOpaque16 flags = QueryFlags;
2549
2550 ubzero(msg, sizeof(msg));
2551 flags.b[0] |= kDNSFlag0_RD; // recursion desired
2552 InitializeDNSMessage(&msg->h, question->uDNS_info.id, flags);
2553 }
2554
2555 mDNSlocal mStatus constructQueryMsg(DNSMessage *msg, mDNSu8 **endPtr, DNSQuestion *const question)
2556 {
2557 initializeQuery(msg, question);
2558
2559 *endPtr = putQuestion(msg, msg->data, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
2560 if (!*endPtr)
2561 {
2562 LogMsg("ERROR: Unicast query out of space in packet");
2563 return mStatus_UnknownErr;
2564 }
2565 return mStatus_NoError;
2566 }
2567
2568 mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, DNSQuestion *question, LLQOptData *data, mDNSBool includeQuestion)
2569 {
2570 AuthRecord rr;
2571 ResourceRecord *opt = &rr.resrec;
2572 rdataOpt *optRD;
2573
2574 //!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section
2575 if (includeQuestion)
2576 {
2577 ptr = putQuestion(msg, ptr, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
2578 if (!ptr) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL; }
2579 }
2580 // locate OptRR if it exists, set pointer to end
2581 // !!!KRS implement me
2582
2583
2584 // format opt rr (fields not specified are zero-valued)
2585 ubzero(&rr, sizeof(AuthRecord));
2586 mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
2587 opt->rdlength = LLQ_OPT_SIZE;
2588 opt->rdestimate = LLQ_OPT_SIZE;
2589
2590 optRD = &rr.resrec.rdata->u.opt;
2591 optRD->opt = kDNSOpt_LLQ;
2592 optRD->optlen = sizeof(LLQOptData);
2593 umemcpy(&optRD->OptData.llq, data, sizeof(LLQOptData));
2594 ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.numAdditionals, opt, 0);
2595 if (!ptr) { LogMsg("ERROR: putLLQ - PutResourceRecordTTLJumbo"); return mDNSNULL; }
2596
2597 return ptr;
2598 }
2599
2600
2601 mDNSlocal mDNSBool getLLQAtIndex(mDNS *m, DNSMessage *msg, const mDNSu8 *end, LLQOptData *llq, int index)
2602 {
2603 LargeCacheRecord lcr;
2604 int i;
2605 const mDNSu8 *ptr;
2606
2607 ptr = LocateAdditionals(msg, end);
2608 if (!ptr) return mDNSfalse;
2609
2610 // find the last additional
2611 for (i = 0; i < msg->h.numAdditionals; i++)
2612 // { ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; }
2613 //!!!KRS workaround for LH server bug, which puts OPT as first additional
2614 { ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; if (lcr.r.resrec.rrtype == kDNSType_OPT) break; }
2615 if (lcr.r.resrec.rrtype != kDNSType_OPT) return mDNSfalse;
2616 if (lcr.r.resrec.rdlength < (index + 1) * LLQ_OPT_SIZE) return mDNSfalse; // rdata too small
2617 umemcpy(llq, (mDNSu8 *)&lcr.r.resrec.rdata->u.opt.OptData.llq + (index * sizeof(LLQOptData)), sizeof(LLQOptData)); // !!! Should convert to host byte order?
2618 return mDNStrue;
2619 }
2620
2621 mDNSlocal void recvRefreshReply(mDNS *m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *q)
2622 {
2623 LLQ_Info *qInfo;
2624 LLQOptData pktData;
2625
2626 qInfo = q->uDNS_info.llq;
2627 if (!getLLQAtIndex(m, msg, end, &pktData, 0)) { LogMsg("ERROR recvRefreshReply - getLLQAtIndex"); return; }
2628 if (pktData.llqOp != kLLQOp_Refresh) return;
2629 if (!sameID(pktData.id, qInfo->id)) { LogMsg("recvRefreshReply - ID mismatch. Discarding"); return; }
2630 if (pktData.err != LLQErr_NoError) { LogMsg("recvRefreshReply: received error %d from server", pktData.err); return; }
2631
2632 qInfo->expire = mDNSPlatformTimeNow(m) + ((mDNSs32)pktData.lease * mDNSPlatformOneSecond);
2633 qInfo->retry = qInfo->expire - ((mDNSs32)pktData.lease * mDNSPlatformOneSecond/2);
2634
2635 qInfo->origLease = pktData.lease;
2636 qInfo->state = LLQ_Established;
2637 }
2638
2639 mDNSlocal void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease)
2640 {
2641 DNSMessage msg;
2642 mDNSu8 *end;
2643 LLQOptData llq;
2644 LLQ_Info *info = q->uDNS_info.llq;
2645 mStatus err;
2646 mDNSs32 timenow;
2647
2648 timenow = mDNSPlatformTimeNow(m);
2649 if ((info->state == LLQ_Refresh && info->ntries >= kLLQ_MAX_TRIES) ||
2650 info->expire - timenow < 0)
2651 {
2652 LogMsg("Unable to refresh LLQ %##s - will retry in %d minutes", q->qname.c, kLLQ_DEF_RETRY/60);
2653 info->state = LLQ_Retry;
2654 info->retry = mDNSPlatformTimeNow(m) + kLLQ_DEF_RETRY * mDNSPlatformOneSecond;
2655 info->deriveRemovesOnResume = mDNStrue;
2656 return;
2657 //!!!KRS handle this - periodically try to re-establish
2658 }
2659
2660 llq.vers = kLLQ_Vers;
2661 llq.llqOp = kLLQOp_Refresh;
2662 llq.err = LLQErr_NoError;
2663 umemcpy(llq.id, info->id, 8);
2664 llq.lease = lease;
2665
2666 initializeQuery(&msg, q);
2667 end = putLLQ(&msg, msg.data, q, &llq, mDNStrue);
2668 if (!end) { LogMsg("ERROR: sendLLQRefresh - putLLQ"); return; }
2669
2670 err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL);
2671 if (err) LogMsg("ERROR: sendLLQRefresh - mDNSSendDNSMessage returned %ld", err);
2672
2673 if (info->state == LLQ_Established) info->ntries = 1;
2674 else info->ntries++;
2675 info->state = LLQ_Refresh;
2676 q->LastQTime = timenow;
2677 info->retry = (info->expire - q->LastQTime) / 2;
2678 }
2679
2680 mDNSlocal mDNSBool recvLLQEvent(mDNS *m, DNSQuestion *q, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, mDNSInterfaceID InterfaceID)
2681 {
2682 DNSMessage ack;
2683 mDNSu8 *ackEnd = ack.data;
2684 mStatus err;
2685 LLQOptData opt;
2686
2687 (void)InterfaceID; // unused
2688
2689 // find Opt RR, verify correct ID
2690 if (!getLLQAtIndex(m, msg, end, &opt, 0)) { debugf("Pkt does not contain LLQ Opt"); return mDNSfalse; }
2691 if (opt.llqOp != kLLQOp_Event) { LogMsg("recvLLQEvent - Bad LLQ Opcode %d", opt.llqOp); return mDNSfalse; }
2692 if (!q->uDNS_info.llq) { LogMsg("Error: recvLLQEvent - question object does not contain LLQ metadata"); return mDNSfalse; }
2693 if (!sameID(opt.id, q->uDNS_info.llq->id)) { return mDNSfalse; }
2694
2695 // invoke response handler
2696 m->uDNS_info.CurrentQuery = q;
2697 q->uDNS_info.responseCallback(m, msg, end, q, q->uDNS_info.context);
2698 if (m->uDNS_info.CurrentQuery != q) return mDNStrue;
2699
2700 // format and send ack
2701 InitializeDNSMessage(&ack.h, msg->h.id, ResponseFlags);
2702 ackEnd = putQuestion(&ack, ack.data, ack.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
2703 if (!ackEnd) { LogMsg("ERROR: recvLLQEvent - putQuestion"); return mDNSfalse; }
2704 err = mDNSSendDNSMessage(m, &ack, ackEnd, mDNSInterface_Any, srcaddr, srcport, -1, mDNSNULL);
2705 if (err) LogMsg("ERROR: recvLLQEvent - mDNSSendDNSMessage returned %ld", err);
2706 return mDNStrue;
2707 }
2708
2709
2710
2711 mDNSlocal void hndlChallengeResponseAck(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q)
2712 {
2713 LLQ_Info *info = q->uDNS_info.llq;
2714
2715 if (llq->err) { LogMsg("hndlChallengeResponseAck - received error %d from server", llq->err); goto error; }
2716 if (!sameID(info->id, llq->id)) { LogMsg("hndlChallengeResponseAck - ID changed. discarding"); return; } // this can happen rarely (on packet loss + reordering)
2717 info->expire = mDNSPlatformTimeNow(m) + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
2718 info->retry = info->expire - ((mDNSs32)llq->lease * mDNSPlatformOneSecond / 2);
2719
2720 info->origLease = llq->lease;
2721 info->state = LLQ_Established;
2722
2723 q->uDNS_info.responseCallback = llqResponseHndlr;
2724 llqResponseHndlr(m, pktMsg, end, q, mDNSNULL);
2725 return;
2726
2727 error:
2728 info->state = LLQ_Error;
2729 }
2730
2731 mDNSlocal void sendChallengeResponse(mDNS *m, DNSQuestion *q, LLQOptData *llq)
2732 {
2733 LLQ_Info *info = q->uDNS_info.llq;
2734 DNSMessage response;
2735 mDNSu8 *responsePtr = response.data;
2736 mStatus err;
2737 LLQOptData llqBuf;
2738 mDNSs32 timenow = mDNSPlatformTimeNow(m);
2739
2740 if (info->ntries++ == kLLQ_MAX_TRIES)
2741 {
2742 LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s. Will re-try in %d minutes",
2743 kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60);
2744 info->state = LLQ_Retry;
2745 info->retry = timenow + (kLLQ_DEF_RETRY * mDNSPlatformOneSecond);
2746 // !!!KRS give a callback error in these cases?
2747 return;
2748 }
2749
2750
2751 if (!llq)
2752 {
2753 llq = &llqBuf;
2754 llq->vers = kLLQ_Vers;
2755 llq->llqOp = kLLQOp_Setup;
2756 llq->err = LLQErr_NoError;
2757 umemcpy(llq->id, info->id, 8);
2758 llq->lease = info->origLease;
2759 }
2760
2761 q->LastQTime = timenow;
2762 info->retry = timenow + (kLLQ_INIT_RESEND * info->ntries * mDNSPlatformOneSecond);
2763
2764 if (constructQueryMsg(&response, &responsePtr, q)) goto error;
2765 responsePtr = putLLQ(&response, responsePtr, q, llq, mDNSfalse);
2766 if (!responsePtr) { LogMsg("ERROR: sendChallengeResponse - putLLQ"); goto error; }
2767
2768 err = mDNSSendDNSMessage(m, &response, responsePtr, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL);
2769 if (err) LogMsg("ERROR: sendChallengeResponse - mDNSSendDNSMessage returned %ld", err);
2770 // on error, we procede as normal and retry after the appropriate interval
2771
2772 return;
2773
2774 error:
2775 info->state = LLQ_Error;
2776 }
2777
2778
2779
2780 mDNSlocal void hndlRequestChallenge(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q)
2781 {
2782 LLQ_Info *info = q->uDNS_info.llq;
2783 mDNSs32 timenow = mDNSPlatformTimeNow(m);
2784 switch(llq->err)
2785 {
2786 case LLQErr_NoError: break;
2787 case LLQErr_ServFull:
2788 LogMsg("hndlRequestChallenge - received ServFull from server for LLQ %##s. Retry in %lu sec", q->qname.c, llq->lease);
2789 info->retry = timenow + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
2790 info->state = LLQ_Retry;
2791 simpleResponseHndlr(m, pktMsg, end, q, mDNSNULL); // get available answers
2792 info->deriveRemovesOnResume = mDNStrue;
2793 case LLQErr_Static:
2794 info->state = LLQ_Static;
2795 LogMsg("LLQ %##s: static", q->qname.c);
2796 simpleResponseHndlr(m, pktMsg, end, q, mDNSNULL);
2797 return;
2798 case LLQErr_FormErr:
2799 LogMsg("ERROR: hndlRequestChallenge - received FormErr from server for LLQ %##s", q->qname.c);
2800 goto error;
2801 case LLQErr_BadVers:
2802 LogMsg("ERROR: hndlRequestChallenge - received BadVers from server");
2803 goto error;
2804 case LLQErr_UnknownErr:
2805 LogMsg("ERROR: hndlRequestChallenge - received UnknownErr from server for LLQ %##s", q->qname.c);
2806 goto error;
2807 default:
2808 LogMsg("ERROR: hndlRequestChallenge - received invalid error %d for LLQ %##s", llq->err, q->qname.c);
2809 goto error;
2810 }
2811
2812 if (info->origLease != llq->lease)
2813 LogMsg("hndlRequestChallenge: requested lease %lu, granted lease %lu", info->origLease, llq->lease);
2814
2815 // cache expiration in case we go to sleep before finishing setup
2816 info->origLease = llq->lease;
2817 info->expire = timenow + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
2818
2819 // update state
2820 info->state = LLQ_SecondaryRequest;
2821 umemcpy(info->id, llq->id, 8);
2822 info->ntries = 0; // first attempt to send response
2823
2824 sendChallengeResponse(m, q, llq);
2825 return;
2826
2827
2828 error:
2829 info->state = LLQ_Error;
2830 }
2831
2832
2833 // response handler for initial and secondary setup responses
2834 mDNSlocal void recvSetupResponse(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, DNSQuestion *q, void *clientContext)
2835 {
2836 DNSQuestion pktQuestion;
2837 LLQOptData llq;
2838 const mDNSu8 *ptr = pktMsg->data;
2839 LLQ_Info *info = q->uDNS_info.llq;
2840 mDNSu8 rcode = (mDNSu8)(pktMsg->h.flags.b[1] & kDNSFlag1_RC);
2841
2842 (void)clientContext; // unused
2843
2844 if (rcode && rcode != kDNSFlag1_RC_NXDomain) goto poll;
2845
2846 ptr = getQuestion(pktMsg, ptr, end, 0, &pktQuestion);
2847 if (!ptr) { LogMsg("ERROR: recvSetupResponse - getQuestion"); goto poll; }
2848 if (!SameDomainName(&q->qname, &pktQuestion.qname))
2849 { LogMsg("ERROR: recvSetupResponse - mismatched question in response for llq setup %##s", q->qname.c); goto poll; }
2850
2851 if (!getLLQAtIndex(m, pktMsg, end, &llq, 0)) { debugf("recvSetupResponse - GetLLQAtIndex"); goto poll; }
2852 if (llq.llqOp != kLLQOp_Setup) { LogMsg("ERROR: recvSetupResponse - bad op %d", llq.llqOp); goto poll; }
2853 if (llq.vers != kLLQ_Vers) { LogMsg("ERROR: recvSetupResponse - bad vers %d", llq.vers); goto poll; }
2854
2855 if (info->state == LLQ_InitialRequest) { hndlRequestChallenge(m, pktMsg, end, &llq, q); return; }
2856 if (info->state == LLQ_SecondaryRequest) { hndlChallengeResponseAck(m, pktMsg, end, &llq, q); return; }
2857 LogMsg("recvSetupResponse - bad state %d", info->state);
2858
2859 poll:
2860 info->state = LLQ_Poll;
2861 q->uDNS_info.responseCallback = llqResponseHndlr;
2862 info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL); // trigger immediate poll
2863 info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
2864 }
2865
2866 mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer)
2867 {
2868 DNSMessage msg;
2869 mDNSu8 *end;
2870 LLQOptData llqData;
2871 DNSQuestion *q = info->question;
2872 mStatus err = mStatus_NoError;
2873 mDNSs32 timenow = mDNSPlatformTimeNow(m);
2874 uDNS_GlobalInfo *u = &m->uDNS_info;
2875
2876 if (IsPrivateV4Addr(&u->PrimaryIP))
2877 {
2878 if (!u->LLQNatInfo)
2879 {
2880 info->state = LLQ_NatMapWait;
2881 StartLLQNatMap(m);
2882 return;
2883 }
2884 if (u->LLQNatInfo->state == NATState_Error) goto poll;
2885 if (u->LLQNatInfo->state != NATState_Established && u->LLQNatInfo->state != NATState_Legacy)
2886 { info->state = LLQ_NatMapWait; info->NATMap = mDNStrue; return; }
2887 info->NATMap = mDNStrue; // this llq references the global llq nat mapping
2888 }
2889
2890 if (info->ntries++ >= kLLQ_MAX_TRIES)
2891 {
2892 debugf("startLLQHandshake: %d failed attempts for LLQ %##s. Polling.", kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60);
2893 goto poll;
2894 }
2895
2896 // set llq rdata
2897 llqData.vers = kLLQ_Vers;
2898 llqData.llqOp = kLLQOp_Setup;
2899 llqData.err = LLQErr_NoError;
2900 ubzero(llqData.id, 8);
2901 llqData.lease = kLLQ_DefLease;
2902
2903 initializeQuery(&msg, q);
2904 end = putLLQ(&msg, msg.data, q, &llqData, mDNStrue);
2905 if (!end)
2906 {
2907 LogMsg("ERROR: startLLQHandshake - putLLQ");
2908 info->state = LLQ_Error;
2909 return;
2910 }
2911
2912 if (!defer) // if we are to defer, we simply set the retry timers so the request goes out in the future
2913 {
2914 err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL);
2915 if (err) LogMsg("ERROR: startLLQHandshake - mDNSSendDNSMessage returned %ld", err);
2916 // on error, we procede as normal and retry after the appropriate interval
2917 }
2918
2919 // update question/info state
2920 info->state = LLQ_InitialRequest;
2921 info->origLease = kLLQ_DefLease;
2922 info->retry = timenow + (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
2923 q->LastQTime = timenow;
2924 q->uDNS_info.responseCallback = recvSetupResponse;
2925 q->uDNS_info.internal = mDNStrue;
2926 return;
2927
2928 poll:
2929 info->question->uDNS_info.responseCallback = llqResponseHndlr;
2930 info->state = LLQ_Poll;
2931 info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL); // trigger immediate poll
2932 info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
2933 }
2934
2935 // wrapper for startLLQHandshake, invoked by async op callback
2936 mDNSlocal void startLLQHandshakeCallback(mStatus err, mDNS *const m, void *llqInfo, const AsyncOpResult *result)
2937 {
2938 LLQ_Info *info = (LLQ_Info *)llqInfo;
2939 const zoneData_t *zoneInfo = mDNSNULL;
2940
2941 // check state first to make sure it is OK to touch question object
2942 if (info->state == LLQ_Cancelled)
2943 {
2944 // StopQuery was called while we were getting the zone info
2945 debugf("startLLQHandshake - LLQ Cancelled.");
2946 info->question = mDNSNULL; // question may be deallocated
2947 ufree(info);
2948 return;
2949 }
2950
2951 if (!info->question)
2952 { LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL question"); goto error; }
2953
2954 if (info->state != LLQ_GetZoneInfo)
2955 { LogMsg("ERROR: startLLQHandshake - bad state %d", info->state); goto error; }
2956
2957 if (err)
2958 { LogMsg("ERROR: startLLQHandshakeCallback invoked with error code %ld", err); goto poll; }
2959
2960 if (!result)
2961 { LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL result and no error code"); goto error; }
2962
2963 zoneInfo = &result->zoneData;
2964
2965 if (!zoneInfo->llqPort.NotAnInteger)
2966 { debugf("LLQ port lookup failed - reverting to polling"); goto poll; }
2967
2968 // cache necessary zone data
2969 info->servAddr.type = zoneInfo->primaryAddr.type;
2970 info->servAddr.ip.v4.NotAnInteger = zoneInfo->primaryAddr.ip.v4.NotAnInteger;
2971 info->servPort.NotAnInteger = zoneInfo->llqPort.NotAnInteger;
2972 info->ntries = 0;
2973
2974 if (info->state == LLQ_SuspendDeferred) info->state = LLQ_Suspended;
2975 else startLLQHandshake(m, info, mDNSfalse);
2976 return;
2977
2978 poll:
2979 info->question->uDNS_info.responseCallback = llqResponseHndlr;
2980 info->state = LLQ_Poll;
2981 info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL); // trigger immediate poll
2982 info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
2983 return;
2984
2985 error:
2986 info->state = LLQ_Error;
2987 }
2988
2989 mDNSlocal mStatus startLLQ(mDNS *m, DNSQuestion *question)
2990 {
2991 LLQ_Info *info;
2992 mStatus err = mStatus_NoError;
2993
2994 // allocate / init info struct
2995 info = umalloc(sizeof(LLQ_Info));
2996 if (!info) { LogMsg("ERROR: startLLQ - malloc"); return mStatus_NoMemoryErr; }
2997 ubzero(info, sizeof(LLQ_Info));
2998 info->state = LLQ_GetZoneInfo;
2999
3000 // link info/question
3001 info->question = question;
3002 question->uDNS_info.llq = info;
3003
3004 question->uDNS_info.responseCallback = llqResponseHndlr;
3005
3006 err = startGetZoneData(&question->qname, m, mDNSfalse, mDNStrue, startLLQHandshakeCallback, info);
3007 if (err)
3008 {
3009 LogMsg("ERROR: startLLQ - startGetZoneData returned %ld", err);
3010 info->question = mDNSNULL;
3011 ufree(info);
3012 question->uDNS_info.llq = mDNSNULL;
3013 return err;
3014 }
3015
3016 LinkActiveQuestion(&m->uDNS_info, question);
3017 return err;
3018 }
3019
3020 mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID)
3021 {
3022 DNSQuestion pktQ, *q;
3023 uDNS_GlobalInfo *u = &m->uDNS_info;
3024 const mDNSu8 *ptr = msg->data;
3025 LLQ_Info *llqInfo;
3026
3027 if (!msg->h.numQuestions) return mDNSfalse;
3028
3029 ptr = getQuestion(msg, ptr, end, 0, &pktQ);
3030 if (!ptr) return mDNSfalse;
3031 pktQ.uDNS_info.id = msg->h.id;
3032
3033 q = u->ActiveQueries;
3034 while (q)
3035 {
3036 llqInfo = q->uDNS_info.llq;
3037 if (q->LongLived &&
3038 llqInfo &&
3039 q->qnamehash == pktQ.qnamehash &&
3040 q->qtype == pktQ.qtype &&
3041 SameDomainName(&q->qname, &pktQ.qname))
3042 {
3043 u->CurrentQuery = q;
3044 if (llqInfo->state == LLQ_Established || (llqInfo->state == LLQ_Refresh && msg->h.numAnswers))
3045 { if (recvLLQEvent(m, q, msg, end, srcaddr, srcport, InterfaceID)) return mDNStrue; }
3046 else if (msg->h.id.NotAnInteger == q->uDNS_info.id.NotAnInteger)
3047 {
3048 if (llqInfo->state == LLQ_Refresh && msg->h.numAdditionals && !msg->h.numAnswers)
3049 { recvRefreshReply(m, msg, end, q); return mDNStrue; }
3050 if (llqInfo->state < LLQ_Static)
3051 {
3052 if ((llqInfo->state != LLQ_InitialRequest && llqInfo->state != LLQ_SecondaryRequest) || mDNSSameAddress(srcaddr, &llqInfo->servAddr))
3053 { q->uDNS_info.responseCallback(m, msg, end, q, q->uDNS_info.context); return mDNStrue; }
3054 }
3055 }
3056 }
3057 q = q->next;
3058 }
3059 return mDNSfalse;
3060 }
3061
3062 mDNSexport mDNSBool uDNS_IsActiveQuery(DNSQuestion *const question, uDNS_GlobalInfo *u)
3063 {
3064 DNSQuestion *q;
3065
3066 for (q = u->ActiveQueries; q; q = q->next)
3067 {
3068 if (q == question)
3069 {
3070 if (!question->uDNS_info.id.NotAnInteger || question->InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&question->qname))
3071 LogMsg("Warning: Question %##s in Active Unicast Query list with id %d, interfaceID %p",
3072 question->qname.c, question->uDNS_info.id.NotAnInteger, question->InterfaceID);
3073 return mDNStrue;
3074 }
3075 }
3076 return mDNSfalse;
3077 }
3078
3079 // stopLLQ happens IN ADDITION to stopQuery
3080 mDNSlocal void stopLLQ(mDNS *m, DNSQuestion *question)
3081 {
3082 LLQ_Info *info = question->uDNS_info.llq;
3083 (void)m; // unused
3084
3085 if (!question->LongLived) { LogMsg("ERROR: stopLLQ - LongLived flag not set"); return; }
3086 if (!info) { LogMsg("ERROR: stopLLQ - llq info is NULL"); return; }
3087
3088 switch (info->state)
3089 {
3090 case LLQ_UnInit:
3091 LogMsg("ERROR: stopLLQ - state LLQ_UnInit");
3092 //!!!KRS should we unlink info<->question here?
3093 return;
3094 case LLQ_GetZoneInfo:
3095 case LLQ_SuspendDeferred:
3096 info->question = mDNSNULL; // remove ref to question, as it may be freed when we get called back from async op
3097 info->state = LLQ_Cancelled;
3098 return;
3099 case LLQ_Established:
3100 case LLQ_Refresh:
3101 // refresh w/ lease 0
3102 sendLLQRefresh(m, question, 0);
3103 goto end;
3104 default:
3105 debugf("stopLLQ - silently discarding LLQ in state %d", info->state);
3106 goto end;
3107 }
3108
3109 end:
3110 if (info->NATMap) info->NATMap = mDNSfalse;
3111 CheckForUnreferencedLLQMapping(m);
3112 info->question = mDNSNULL;
3113 ufree(info);
3114 question->uDNS_info.llq = mDNSNULL;
3115 question->LongLived = mDNSfalse;
3116 }
3117
3118 mDNSexport mStatus uDNS_StopQuery(mDNS *const m, DNSQuestion *const question)
3119 {
3120 uDNS_GlobalInfo *u = &m->uDNS_info;
3121 DNSQuestion *qptr, *prev = mDNSNULL;
3122 CacheRecord *ka;
3123
3124 qptr = u->ActiveQueries;
3125 while (qptr)
3126 {
3127 if (qptr == question)
3128 {
3129 if (question->LongLived && question->uDNS_info.llq)
3130 stopLLQ(m, question);
3131 if (m->uDNS_info.CurrentQuery == question)
3132 m->uDNS_info.CurrentQuery = m->uDNS_info.CurrentQuery->next;
3133 while (question->uDNS_info.knownAnswers)
3134 {
3135 ka = question->uDNS_info.knownAnswers;
3136 question->uDNS_info.knownAnswers = question->uDNS_info.knownAnswers->next;
3137 ufree(ka);
3138 }
3139 if (prev) prev->next = question->next;
3140 else u->ActiveQueries = question->next;
3141 return mStatus_NoError;
3142 }
3143 prev = qptr;
3144 qptr = qptr->next;
3145 }
3146 LogMsg("uDNS_StopQuery: no such active query (%##s)", question->qname.c);
3147 return mStatus_UnknownErr;
3148 }
3149
3150 mDNSlocal mStatus startQuery(mDNS *const m, DNSQuestion *const question, mDNSBool internal)
3151 {
3152 uDNS_GlobalInfo *u = &m->uDNS_info;
3153 DNSMessage msg;
3154 mDNSu8 *endPtr;
3155 mStatus err = mStatus_NoError;
3156 mDNSAddr server;
3157
3158 //!!!KRS we should check if the question is already in our acivequestion list
3159 if (!ValidateDomainName(&question->qname))
3160 {
3161 LogMsg("Attempt to start query with invalid qname %##s %##s", question->qname.c, DNSTypeName(question->qtype));
3162 return mStatus_Invalid;
3163 }
3164
3165 question->next = mDNSNULL;
3166 question->qnamehash = DomainNameHashValue(&question->qname); // to do quick domain name comparisons
3167 question->uDNS_info.id = newMessageID(u);
3168 question->uDNS_info.Answered = mDNSfalse;
3169
3170 // break here if its and LLQ
3171 if (question->LongLived) return startLLQ(m, question);
3172
3173 // else send the query to our server
3174 err = constructQueryMsg(&msg, &endPtr, question);
3175 if (err) return err;
3176
3177 question->LastQTime = mDNSPlatformTimeNow(m);
3178 question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
3179 // store the question/id in active question list
3180 question->uDNS_info.internal = internal;
3181 LinkActiveQuestion(u, question);
3182 question->uDNS_info.knownAnswers = mDNSNULL;
3183 if (GetServerForName(u, &question->qname, &server))
3184 {
3185 err = mDNSSendDNSMessage(m, &msg, endPtr, mDNSInterface_Any, &server, UnicastDNSPort, -1, mDNSNULL);
3186 if (err) { debugf("ERROR: startQuery - %ld (keeping question in list for retransmission", err); }
3187 }
3188
3189 return mStatus_NoError; // don't return transient errors to caller
3190 }
3191
3192 mDNSexport mStatus uDNS_StartQuery(mDNS *const m, DNSQuestion *const question)
3193 {
3194 ubzero(&question->uDNS_info, sizeof(uDNS_QuestionInfo));
3195 question->uDNS_info.responseCallback = simpleResponseHndlr;
3196 question->uDNS_info.context = mDNSNULL;
3197 //LogOperation("uDNS_StartQuery %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
3198 return startQuery(m, question, 0);
3199 }
3200
3201 // explicitly set response handler
3202 mDNSlocal mStatus startInternalQuery(DNSQuestion *q, mDNS *m, InternalResponseHndlr callback, void *hndlrContext)
3203 {
3204 ubzero(&q->uDNS_info, sizeof(uDNS_QuestionInfo));
3205 q->QuestionContext = hndlrContext;
3206 q->uDNS_info.responseCallback = callback;
3207 q->uDNS_info.context = hndlrContext;
3208 return startQuery(m, q, 1);
3209 }
3210
3211
3212
3213 // ***************************************************************************
3214 #if COMPILER_LIKES_PRAGMA_MARK
3215 #pragma mark - Domain -> Name Server Conversion
3216 #endif
3217
3218
3219 /* startGetZoneData
3220 *
3221 * Asynchronously find the address of the nameserver for the enclosing zone for a given domain name,
3222 * i.e. the server to which update and LLQ requests will be sent for a given name. Once the address is
3223 * derived, it will be passed to the callback, along with a context pointer. If the zone cannot
3224 * be determined or if an error occurs, an all-zeros address will be passed and a message will be
3225 * written to the syslog.
3226 *
3227 * If the FindUpdatePort arg is set, the port on which the server accepts dynamic updates is determined
3228 * by querying for the _dns-update._udp.<zone>. SRV record. Likewise, if the FindLLQPort arg is set,
3229 * the port on which the server accepts long lived queries is determined by querying for
3230 * _dns-llq._udp.<zone>. record. If either of these queries fail, or flags are not specified,
3231 * the llqPort and updatePort fields in the result structure are set to zero.
3232 *
3233 * Steps for deriving the zone name are as follows:
3234 *
3235 * Query for an SOA record for the required domain. If we don't get an answer (or an SOA in the Authority
3236 * section), we strip the leading label from the name and repeat, until we get an answer.
3237 *
3238 * The name of the SOA record is our enclosing zone. The mname field in the SOA rdata is the domain
3239 * name of the primary NS.
3240 *
3241 * We verify that there is an NS record with this zone for a name and the mname for its rdata.
3242 * (!!!KRS this seems redundant, but BIND does this, and it should normally be zero-overhead since
3243 * the NS query will get us address records in the additionals section, which we'd otherwise have to
3244 * explicitly query for.)
3245 *
3246 * We then query for the address record for this nameserver (if it is not in the addionals section of
3247 * the NS record response.)
3248 */
3249
3250
3251 // state machine types and structs
3252 //
3253
3254 // state machine states
3255 typedef enum
3256 {
3257 init,
3258 lookupSOA,
3259 foundZone,
3260 lookupNS,
3261 foundNS,
3262 lookupA,
3263 foundA,
3264 lookupPort,
3265 foundPort,
3266 complete
3267 } ntaState;
3268
3269 // state machine actions
3270 typedef enum
3271 {
3272 smContinue, // continue immediately to next state
3273 smBreak, // break until next packet/timeout
3274 smError // terminal error - cleanup and abort
3275 } smAction;
3276
3277 typedef struct
3278 {
3279 domainname origName; // name we originally try to convert
3280 domainname *curSOA; // name we have an outstanding SOA query for
3281 ntaState state; // determines what we do upon receiving a packet
3282 mDNS *m;
3283 domainname zone; // left-hand-side of SOA record
3284 mDNSu16 zoneClass;
3285 domainname ns; // mname in SOA rdata, verified in confirmNS state
3286 mDNSv4Addr addr; // address of nameserver
3287 DNSQuestion question; // storage for any active question
3288 DNSQuestion extraQuestion; // additional storage
3289 mDNSBool questionActive; // if true, StopQuery() can be called on the question field
3290 mDNSBool findUpdatePort;
3291 mDNSBool findLLQPort;
3292 mDNSIPPort updatePort;
3293 mDNSIPPort llqPort;
3294 AsyncOpCallback *callback; // caller specified function to be called upon completion
3295 void *callbackInfo;
3296 } ntaContext;
3297
3298
3299 // function prototypes (for routines that must be used as fn pointers prior to their definitions,
3300 // and allows states to be read top-to-bottom in logical order)
3301 mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *contextPtr);
3302 mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
3303 mDNSlocal void processSOA(ntaContext *context, ResourceRecord *rr);
3304 mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
3305 mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
3306 mDNSlocal smAction hndlLookupPorts(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
3307
3308 // initialization
3309 mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdatePort, mDNSBool findLLQPort,
3310 AsyncOpCallback callback, void *callbackInfo)
3311 {
3312 ntaContext *context = (ntaContext*)umalloc(sizeof(ntaContext));
3313 if (!context) { LogMsg("ERROR: startGetZoneData - umalloc failed"); return mStatus_NoMemoryErr; }
3314 ubzero(context, sizeof(ntaContext));
3315 AssignDomainName(&context->origName, name);
3316 context->state = init;
3317 context->m = m;
3318 context->callback = callback;
3319 context->callbackInfo = callbackInfo;
3320 context->findUpdatePort = findUpdatePort;
3321 context->findLLQPort = findLLQPort;
3322 getZoneData(m, mDNSNULL, mDNSNULL, mDNSNULL, context);
3323 return mStatus_NoError;
3324 }
3325
3326 // state machine entry routine
3327 mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *contextPtr)
3328 {
3329 AsyncOpResult result;
3330 ntaContext *context = (ntaContext*)contextPtr;
3331 smAction action;
3332
3333 // unused
3334 (void)m;
3335 (void)question;
3336
3337 // stop any active question
3338 if (context->questionActive)
3339 {
3340 uDNS_StopQuery(context->m, &context->question);
3341 context->questionActive = mDNSfalse;
3342 }
3343
3344 if (msg && msg->h.flags.b[2] >> 4 && msg->h.flags.b[2] >> 4 != kDNSFlag1_RC_NXDomain)
3345 {
3346 // rcode non-zero, non-nxdomain
3347 LogMsg("ERROR: getZoneData - received response w/ rcode %d", msg->h.flags.b[2] >> 4);
3348 goto error;
3349 }
3350
3351 switch (context->state)
3352 {
3353 case init:
3354 case lookupSOA:
3355 action = hndlLookupSOA(msg, end, context);
3356 if (action == smError) goto error;
3357 if (action == smBreak) return;
3358 case foundZone:
3359 case lookupNS:
3360 action = confirmNS(msg, end, context);
3361 if (action == smError) goto error;
3362 if (action == smBreak) return;
3363 case foundNS:
3364 case lookupA:
3365 action = lookupNSAddr(msg, end, context);
3366 if (action == smError) goto error;
3367 if (action == smBreak) return;
3368 case foundA:
3369 if (!context->findUpdatePort && !context->findLLQPort)
3370 {
3371 context->state = complete;
3372 break;
3373 }
3374 case lookupPort:
3375 action = hndlLookupPorts(msg, end, context);
3376 if (action == smError) goto error;
3377 if (action == smBreak) return;
3378 if (action == smContinue) context->state = complete;
3379 case foundPort:
3380 case complete: break;
3381 }
3382
3383 if (context->state != complete)
3384 {
3385 LogMsg("ERROR: getZoneData - exited state machine with state %d", context->state);
3386 goto error;
3387 }
3388
3389 result.type = zoneDataResult;
3390 result.zoneData.primaryAddr.ip.v4.NotAnInteger = context->addr.NotAnInteger;
3391 result.zoneData.primaryAddr.type = mDNSAddrType_IPv4;
3392 AssignDomainName(&result.zoneData.zoneName, &context->zone);
3393 result.zoneData.zoneClass = context->zoneClass;
3394 result.zoneData.llqPort = context->findLLQPort ? context->llqPort : zeroIPPort;
3395 result.zoneData.updatePort = context->findUpdatePort ? context->updatePort : zeroIPPort;
3396 context->callback(mStatus_NoError, context->m, context->callbackInfo, &result);
3397 goto cleanup;
3398
3399 error:
3400 if (context && context->callback)
3401 context->callback(mStatus_UnknownErr, context->m, context->callbackInfo, mDNSNULL);
3402 cleanup:
3403 if (context && context->questionActive)
3404 {
3405 uDNS_StopQuery(context->m, &context->question);
3406 context->questionActive = mDNSfalse;
3407 }
3408 if (context) ufree(context);
3409 }
3410
3411 mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
3412 {
3413 mStatus err;
3414 LargeCacheRecord lcr;
3415 ResourceRecord *rr = &lcr.r.resrec;
3416 DNSQuestion *query = &context->question;
3417 const mDNSu8 *ptr;
3418
3419 if (msg)
3420 {
3421 // if msg contains SOA record in answer or authority sections, update context/state and return
3422 int i;
3423 ptr = LocateAnswers(msg, end);
3424 for (i = 0; i < msg->h.numAnswers; i++)
3425 {
3426 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
3427 if (!ptr) { LogMsg("ERROR: hndlLookupSOA, Answers - GetLargeResourceRecord returned NULL"); return smError; }
3428 if (rr->rrtype == kDNSType_SOA && SameDomainName(context->curSOA, rr->name))
3429 {
3430 processSOA(context, rr);
3431 return smContinue;
3432 }
3433 }
3434 ptr = LocateAuthorities(msg, end);
3435 // SOA not in answers, check in authority
3436 for (i = 0; i < msg->h.numAuthorities; i++)
3437 {
3438 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); ///!!!KRS using type PacketAns for auth
3439 if (!ptr) { LogMsg("ERROR: hndlLookupSOA, Authority - GetLargeResourceRecord returned NULL"); return smError; }
3440 if (rr->rrtype == kDNSType_SOA)
3441 {
3442 processSOA(context, rr);
3443 return smContinue;
3444 }
3445 }
3446 }
3447
3448 if (context->state != init && !context->curSOA->c[0])
3449 {
3450 // we've gone down to the root and have not found an SOA
3451 LogMsg("ERROR: hndlLookupSOA - recursed to root label of %##s without finding SOA",
3452 context->origName.c);
3453 return smError;
3454 }
3455
3456 ubzero(query, sizeof(DNSQuestion));
3457 // chop off leading label unless this is our first try
3458 if (context->state == init) context->curSOA = &context->origName;
3459 else context->curSOA = (domainname *)(context->curSOA->c + context->curSOA->c[0]+1);
3460
3461 context->state = lookupSOA;
3462 AssignDomainName(&query->qname, context->curSOA);
3463 query->qtype = kDNSType_SOA;
3464 query->qclass = kDNSClass_IN;
3465 err = startInternalQuery(query, context->m, getZoneData, context);
3466 context->questionActive = mDNStrue;
3467 if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err);
3468
3469 return smBreak; // break from state machine until we receive another packet
3470 }
3471
3472 mDNSlocal void processSOA(ntaContext *context, ResourceRecord *rr)
3473 {
3474 AssignDomainName(&context->zone, rr->name);
3475 context->zoneClass = rr->rrclass;
3476 AssignDomainName(&context->ns, &rr->rdata->u.soa.mname);
3477 context->state = foundZone;
3478 }
3479
3480
3481 mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
3482 {
3483 DNSQuestion *query = &context->question;
3484 mStatus err;
3485 LargeCacheRecord lcr;
3486 const ResourceRecord *const rr = &lcr.r.resrec;
3487 const mDNSu8 *ptr;
3488 int i;
3489
3490 if (context->state == foundZone)
3491 {
3492 // we've just learned the zone. confirm that an NS record exists
3493 AssignDomainName(&query->qname, &context->zone);
3494 query->qtype = kDNSType_NS;
3495 query->qclass = kDNSClass_IN;
3496 err = startInternalQuery(query, context->m, getZoneData, context);
3497 context->questionActive = mDNStrue;
3498 if (err) LogMsg("confirmNS: startInternalQuery returned error %ld (breaking until next periodic retransmission", err);
3499 context->state = lookupNS;
3500 return smBreak; // break from SM until we receive another packet
3501 }
3502 else if (context->state == lookupNS)
3503 {
3504 ptr = LocateAnswers(msg, end);
3505 for (i = 0; i < msg->h.numAnswers; i++)
3506 {
3507 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
3508 if (!ptr) { LogMsg("ERROR: confirmNS, Answers - GetLargeResourceRecord returned NULL"); return smError; }
3509 if (rr->rrtype == kDNSType_NS &&
3510 SameDomainName(&context->zone, rr->name) && SameDomainName(&context->ns, &rr->rdata->u.name))
3511 {
3512 context->state = foundNS;
3513 return smContinue; // next routine will examine additionals section of A record
3514 }
3515 }
3516 LogMsg("ERROR: could not confirm existence of record %##s NS %##s", context->zone.c, context->ns.c);
3517 return smError;
3518 }
3519 else { LogMsg("ERROR: confirmNS - bad state %d", context->state); return smError; }
3520 }
3521
3522 mDNSlocal smAction queryNSAddr(ntaContext *context)
3523 {
3524 mStatus err;
3525 DNSQuestion *query = &context->question;
3526
3527 AssignDomainName(&query->qname, &context->ns);
3528 query->qtype = kDNSType_A;
3529 query->qclass = kDNSClass_IN;
3530 err = startInternalQuery(query, context->m, getZoneData, context);
3531 context->questionActive = mDNStrue;
3532 if (err) LogMsg("confirmNS: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err);
3533 context->state = lookupA;
3534 return smBreak;
3535 }
3536
3537 mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
3538 {
3539 const mDNSu8 *ptr;
3540 int i;
3541 LargeCacheRecord lcr;
3542 ResourceRecord *rr = &lcr.r.resrec;
3543
3544 if (context->state == foundNS)
3545 {
3546 // we just found the NS record - look for the corresponding A record in the Additionals section
3547 if (!msg->h.numAdditionals) return queryNSAddr(context);
3548 ptr = LocateAdditionals(msg, end);
3549 if (!ptr)
3550 {
3551 LogMsg("ERROR: lookupNSAddr - LocateAdditionals returned NULL, expected %d additionals", msg->h.numAdditionals);
3552 return queryNSAddr(context);
3553 }
3554 else
3555 {
3556 for (i = 0; i < msg->h.numAdditionals; i++)
3557 {
3558 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
3559 if (!ptr)
3560 {
3561 LogMsg("ERROR: lookupNSAddr, Additionals - GetLargeResourceRecord returned NULL");
3562 return queryNSAddr(context);
3563 }
3564 if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, rr->name))
3565 {
3566 context->addr.NotAnInteger = rr->rdata->u.ipv4.NotAnInteger;
3567 context->state = foundA;
3568 return smContinue;
3569 }
3570 }
3571 }
3572 // no A record in Additionals - query the server
3573 return queryNSAddr(context);
3574 }
3575 else if (context->state == lookupA)
3576 {
3577 ptr = LocateAnswers(msg, end);
3578 if (!ptr) { LogMsg("ERROR: lookupNSAddr: LocateAnswers returned NULL"); return smError; }
3579 for (i = 0; i < msg->h.numAnswers; i++)
3580 {
3581 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
3582 if (!ptr) { LogMsg("ERROR: lookupNSAddr, Answers - GetLargeResourceRecord returned NULL"); break; }
3583 if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, rr->name))
3584 {
3585 context->addr.NotAnInteger = rr->rdata->u.ipv4.NotAnInteger;
3586 context->state = foundA;
3587 return smContinue;
3588 }
3589 }
3590 LogMsg("ERROR: lookupNSAddr: Address record not found in answer section");
3591 return smError;
3592 }
3593 else { LogMsg("ERROR: lookupNSAddr - bad state %d", context->state); return smError; }
3594 }
3595
3596 mDNSlocal smAction lookupDNSPort(DNSMessage *msg, const mDNSu8 *end, ntaContext *context, char *portName, mDNSIPPort *port)
3597 {
3598 int i;
3599 LargeCacheRecord lcr;
3600 const mDNSu8 *ptr;
3601 DNSQuestion *q;
3602 mStatus err;
3603
3604 if (context->state == lookupPort) // we've already issued the query
3605 {
3606 if (!msg) { LogMsg("ERROR: hndlLookupUpdatePort - NULL message"); return smError; }
3607 ptr = LocateAnswers(msg, end);
3608 for (i = 0; i < msg->h.numAnswers; i++)
3609 {
3610 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
3611 if (!ptr) { LogMsg("ERROR: hndlLookupUpdatePort - GetLargeResourceRecord returned NULL"); return smError; }
3612 if (ResourceRecordAnswersQuestion(&lcr.r.resrec, &context->question))
3613 {
3614 port->NotAnInteger = lcr.r.resrec.rdata->u.srv.port.NotAnInteger;
3615 context->state = foundPort;
3616 return smContinue;
3617 }
3618 }
3619 debugf("hndlLookupUpdatePort - no answer for type %s", portName);
3620 port->NotAnInteger = 0;
3621 context->state = foundPort;
3622 return smContinue;
3623 }
3624
3625 // query the server for the update port for the zone
3626 context->state = lookupPort;
3627 q = &context->question;
3628 MakeDomainNameFromDNSNameString(&q->qname, portName);
3629 AppendDomainName(&q->qname, &context->zone);
3630 q->qtype = kDNSType_SRV;
3631 q->qclass = kDNSClass_IN;
3632 err = startInternalQuery(q, context->m, getZoneData, context);
3633 context->questionActive = mDNStrue;
3634 if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err);
3635 return smBreak; // break from state machine until we receive another packet
3636 }
3637
3638 mDNSlocal smAction hndlLookupPorts(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
3639 {
3640 smAction action;
3641
3642 if (context->findUpdatePort && !context->updatePort.NotAnInteger)
3643 {
3644 action = lookupDNSPort(msg, end, context, UPDATE_PORT_NAME, &context->updatePort);
3645 if (action != smContinue) return action;
3646 }
3647 if (context->findLLQPort && !context->llqPort.NotAnInteger)
3648 return lookupDNSPort(msg, end, context, LLQ_PORT_NAME, &context->llqPort);
3649
3650 return smContinue;
3651 }
3652
3653
3654 // ***************************************************************************
3655 #if COMPILER_LIKES_PRAGMA_MARK
3656 #pragma mark - Truncation Handling
3657 #endif
3658
3659 typedef struct
3660 {
3661 DNSQuestion *question;
3662 DNSMessage reply;
3663 mDNSu16 replylen;
3664 int nread;
3665 mDNS *m;
3666 } tcpInfo_t;
3667
3668 // issue queries over a conected socket
3669 mDNSlocal void conQueryCallback(int sd, void *context, mDNSBool ConnectionEstablished)
3670 {
3671 mStatus err = 0;
3672 char msgbuf[356]; // 96 (hdr) + 256 (domain) + 4 (class/type)
3673 DNSMessage *msg;
3674 mDNSu8 *end;
3675 tcpInfo_t *info = (tcpInfo_t *)context;
3676 DNSQuestion *question = info->question;
3677 int n;
3678 mDNS *m = info->m;
3679
3680 mDNS_Lock(m);
3681
3682 if (ConnectionEstablished)
3683 {
3684 // connection is established - send the message
3685 msg = (DNSMessage *)&msgbuf;
3686 err = constructQueryMsg(msg, &end, question);
3687 if (err) { LogMsg("ERROR: conQueryCallback: constructQueryMsg - %ld", err); goto error; }
3688 err = mDNSSendDNSMessage(m, msg, end, mDNSInterface_Any, &zeroAddr, zeroIPPort, sd, mDNSNULL);
3689 question->LastQTime = mDNSPlatformTimeNow(m);
3690 if (err) { LogMsg("ERROR: conQueryCallback: mDNSSendDNSMessage_tcp - %ld", err); goto error; }
3691 }
3692 else
3693 {
3694 if (!info->nread)
3695 {
3696 // read msg len
3697 mDNSu8 lenbuf[2];
3698 n = mDNSPlatformReadTCP(sd, lenbuf, 2);
3699 if (n != 2)
3700 {
3701 LogMsg("ERROR:conQueryCallback - attempt to read message length failed (read returned %d)", n);
3702 goto error;
3703 }
3704 info->replylen = (mDNSu16)((mDNSu16)lenbuf[0] << 8 | lenbuf[1]);
3705 }
3706 n = mDNSPlatformReadTCP(sd, ((char *)&info->reply) + info->nread, info->replylen - info->nread);
3707 if (n < 0) { LogMsg("ERROR: conQueryCallback - read returned %d", n); goto error; }
3708 info->nread += n;
3709 if (info->nread == info->replylen)
3710 {
3711 // Finished reading message; convert the integer parts which are in IETF byte-order (MSB first, LSB second)
3712 DNSMessage *msg = &info->reply;
3713 mDNSu8 *ptr = (mDNSu8 *)&msg->h.numQuestions;
3714 msg->h.numQuestions = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
3715 msg->h.numAnswers = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
3716 msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]);
3717 msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]);
3718 uDNS_ReceiveMsg(m, msg, (mDNSu8 *)msg + info->replylen, mDNSNULL, zeroIPPort, mDNSNULL, zeroIPPort, question->InterfaceID);
3719 mDNSPlatformTCPCloseConnection(sd);
3720 ufree(info);
3721 }
3722 }
3723
3724 mDNS_Unlock(m);
3725 return;
3726
3727 error:
3728 mDNSPlatformTCPCloseConnection(sd);
3729 ufree(info);
3730 mDNS_Unlock(m);
3731 }
3732
3733 mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question, const mDNSAddr *src, mDNS *m)
3734 {
3735 mStatus connectionStatus;
3736 uDNS_QuestionInfo *info = &question->uDNS_info;
3737 int sd;
3738 tcpInfo_t *context;
3739
3740 if (!src) { LogMsg("hndlTruncatedAnswer: TCP DNS response had TC bit set: ignoring"); return; }
3741
3742 context = (tcpInfo_t *)umalloc(sizeof(tcpInfo_t));
3743 if (!context) { LogMsg("ERROR: hndlTruncatedAnswer - memallocate failed"); return; }
3744 ubzero(context, sizeof(tcpInfo_t));
3745 context->question = question;
3746 context->m = m;
3747 info->id = newMessageID(&m->uDNS_info);
3748
3749 connectionStatus = mDNSPlatformTCPConnect(src, UnicastDNSPort, question->InterfaceID, conQueryCallback, context, &sd);
3750 if (connectionStatus == mStatus_ConnEstablished) // manually invoke callback if connection completes
3751 {
3752 conQueryCallback(sd, context, mDNStrue);
3753 return;
3754 }
3755 if (connectionStatus == mStatus_ConnPending) return; // callback will be automatically invoked when connection completes
3756 LogMsg("hndlTruncatedAnswer: connection failed");
3757 uDNS_StopQuery(m, question); //!!!KRS can we really call this here?
3758 }
3759
3760
3761 // ***************************************************************************
3762 #if COMPILER_LIKES_PRAGMA_MARK
3763 #pragma mark - Dynamic Updates
3764 #endif
3765
3766
3767
3768 mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr)
3769 {
3770 DNSMessage msg;
3771 mDNSu8 *ptr = msg.data;
3772 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
3773 uDNS_GlobalInfo *u = &m->uDNS_info;
3774 mDNSOpaque16 id;
3775 uDNS_RegInfo *regInfo = &rr->uDNS_info;
3776 mStatus err = mStatus_UnknownErr;
3777
3778 id = newMessageID(u);
3779 InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
3780 rr->uDNS_info.id.NotAnInteger = id.NotAnInteger;
3781
3782 // set zone
3783 ptr = putZone(&msg, ptr, end, &regInfo->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
3784 if (!ptr) goto error;
3785
3786 if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
3787 {
3788 // KnownUnique: Delete any previous value
3789 ptr = putDeleteRRSet(&msg, ptr, rr->resrec.name, rr->resrec.rrtype);
3790 if (!ptr) goto error;
3791 }
3792
3793 else if (rr->resrec.RecordType != kDNSRecordTypeShared)
3794 {
3795 ptr = putPrereqNameNotInUse(rr->resrec.name, &msg, ptr, end);
3796 if (!ptr) goto error;
3797 }
3798
3799 ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl);
3800 if (!ptr) goto error;
3801
3802 if (rr->uDNS_info.lease)
3803 { ptr = putUpdateLease(&msg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) goto error; }
3804
3805 err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &regInfo->ns, regInfo->port, -1, GetAuthInfoForZone(u, &regInfo->zone));
3806 if (err) LogMsg("ERROR: sendRecordRegistration - mDNSSendDNSMessage - %ld", err);
3807
3808 SetRecordRetry(m, rr);
3809
3810 if (regInfo->state != regState_Refresh && regInfo->state != regState_DeregDeferred) regInfo->state = regState_Pending;
3811 return;
3812
3813 error:
3814 LogMsg("sendRecordRegistration: Error formatting message");
3815 if (rr->uDNS_info.state != regState_Unregistered)
3816 {
3817 unlinkAR(&u->RecordRegistrations, rr);
3818 rr->uDNS_info.state = regState_Unregistered;
3819 }
3820 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
3821 if (rr->RecordCallback) rr->RecordCallback(m, rr, err);
3822 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
3823 // NOTE: not safe to touch any client structures here
3824 }
3825
3826 mDNSlocal void RecordRegistrationCallback(mStatus err, mDNS *const m, void *authPtr, const AsyncOpResult *result)
3827 {
3828 AuthRecord *newRR = (AuthRecord*)authPtr;
3829 const zoneData_t *zoneData = mDNSNULL;
3830 uDNS_GlobalInfo *u = &m->uDNS_info;
3831 AuthRecord *ptr;
3832
3833 // make sure record is still in list
3834 for (ptr = u->RecordRegistrations; ptr; ptr = ptr->next)
3835 if (ptr == newRR) break;
3836 if (!ptr) { LogMsg("RecordRegistrationCallback - RR no longer in list. Discarding."); return; }
3837
3838 // check error/result
3839 if (err) { LogMsg("RecordRegistrationCallback: error %ld", err); goto error; }
3840 if (!result) { LogMsg("ERROR: RecordRegistrationCallback invoked with NULL result and no error"); goto error; }
3841 else zoneData = &result->zoneData;
3842
3843 if (newRR->uDNS_info.state == regState_Cancelled)
3844 {
3845 //!!!KRS we should send a memfree callback here!
3846 debugf("Registration of %##s type %d cancelled prior to update",
3847 newRR->resrec.name->c, newRR->resrec.rrtype);
3848 newRR->uDNS_info.state = regState_Unregistered;
3849 unlinkAR(&u->RecordRegistrations, newRR);
3850 return;
3851 }
3852
3853 if (result->type != zoneDataResult)
3854 {
3855 LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type);
3856 goto error;
3857 }
3858
3859 if (newRR->resrec.rrclass != zoneData->zoneClass)
3860 {
3861 LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)",
3862 newRR->resrec.rrclass, zoneData->zoneClass);
3863 goto error;
3864 }
3865
3866 // cache zone data
3867 AssignDomainName(&newRR->uDNS_info.zone, &zoneData->zoneName);
3868 newRR->uDNS_info.ns.type = mDNSAddrType_IPv4;
3869 newRR->uDNS_info.ns.ip.v4.NotAnInteger = zoneData->primaryAddr.ip.v4.NotAnInteger;
3870 if (zoneData->updatePort.NotAnInteger) newRR->uDNS_info.port = zoneData->updatePort;
3871 else
3872 {
3873 debugf("Update port not advertised via SRV - guessing port 53, no lease option");
3874 newRR->uDNS_info.port = UnicastDNSPort;
3875 newRR->uDNS_info.lease = mDNSfalse;
3876 }
3877
3878 sendRecordRegistration(m, newRR);
3879 return;
3880
3881 error:
3882 if (newRR->uDNS_info.state != regState_Unregistered)
3883 {
3884 unlinkAR(&u->RecordRegistrations, newRR);
3885 newRR->uDNS_info.state = regState_Unregistered;
3886 }
3887 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
3888 if (newRR->RecordCallback)
3889 newRR->RecordCallback(m, newRR, err);
3890 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
3891 // NOTE: not safe to touch any client structures here
3892 }
3893
3894 mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs)
3895 {
3896 DNSMessage msg;
3897 mDNSu8 *ptr = msg.data;
3898 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
3899 uDNS_GlobalInfo *u = &m->uDNS_info;
3900 mDNSOpaque16 id;
3901 uDNS_RegInfo *rInfo = &srs->uDNS_info;
3902 mStatus err = mStatus_UnknownErr;
3903 mDNSIPPort privport;
3904 NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
3905 mDNSBool mapped = mDNSfalse;
3906 domainname target;
3907 AuthRecord *srv = &srs->RR_SRV;
3908 mDNSu32 i;
3909
3910 if (!rInfo->ns.ip.v4.NotAnInteger) { LogMsg("SendServiceRegistration - NS not set!"); return; }
3911
3912 id = newMessageID(u);
3913 InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
3914
3915 // setup resource records
3916 SetNewRData(&srs->RR_PTR.resrec, mDNSNULL, 0);
3917 SetNewRData(&srs->RR_TXT.resrec, mDNSNULL, 0);
3918
3919 // replace port w/ NAT mapping if necessary
3920 if (nat && nat->PublicPort.NotAnInteger &&
3921 (nat->state == NATState_Established || nat->state == NATState_Refresh || nat->state == NATState_Legacy))
3922 {
3923 privport = srv->resrec.rdata->u.srv.port;
3924 srv->resrec.rdata->u.srv.port = nat->PublicPort;
3925 mapped = mDNStrue;
3926 }
3927
3928 // construct update packet
3929 // set zone
3930 ptr = putZone(&msg, ptr, end, &rInfo->zone, mDNSOpaque16fromIntVal(srv->resrec.rrclass));
3931 if (!ptr) goto error;
3932
3933 if (srs->uDNS_info.TestForSelfConflict)
3934 {
3935 // update w/ prereq that SRV already exist to make sure previous registration was ours, and delete any stale TXT records
3936 if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numPrereqs, &srs->RR_SRV.resrec, 0))) goto error;
3937 if (!(ptr = putDeleteRRSet(&msg, ptr, srs->RR_TXT.resrec.name, srs->RR_TXT.resrec.rrtype))) goto error;
3938 }
3939
3940 else if (srs->uDNS_info.state != regState_Refresh && srs->uDNS_info.state != regState_UpdatePending)
3941 {
3942 // use SRV name for prereq
3943 ptr = putPrereqNameNotInUse(srv->resrec.name, &msg, ptr, end);
3944 if (!ptr) goto error;
3945 }
3946
3947 //!!!KRS Need to do bounds checking and use TCP if it won't fit!!!
3948 if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_PTR.resrec, srs->RR_PTR.resrec.rroriginalttl))) goto error;
3949
3950 for (i = 0; i < srs->NumSubTypes; i++)
3951 if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->SubTypes[i].resrec, srs->SubTypes[i].resrec.rroriginalttl))) goto error;
3952
3953 if (rInfo->state == regState_UpdatePending)
3954 {
3955 // we're updating the txt record - delete old, add new
3956 if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_TXT.resrec))) goto error; // delete old rdata
3957 SwapRData(m, &srs->RR_TXT, mDNSfalse); // add the new rdata
3958 if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) goto error;
3959 SwapRData(m, &srs->RR_TXT, mDNSfalse); // replace old rdata in case we need to retransmit
3960 }
3961 else
3962 if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) goto error;
3963
3964 if (!GetServiceTarget(u, srv, &target))
3965 {
3966 debugf("Couldn't get target for service %##s", srv->resrec.name->c);
3967 rInfo->state = regState_NoTarget;
3968 return;
3969 }
3970
3971 if (!SameDomainName(&target, &srv->resrec.rdata->u.srv.target))
3972 {
3973 AssignDomainName(&srv->resrec.rdata->u.srv.target, &target);
3974 SetNewRData(&srv->resrec, mDNSNULL, 0);
3975 }
3976
3977 ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srv->resrec, srv->resrec.rroriginalttl);
3978 if (!ptr) goto error;
3979
3980 if (srs->uDNS_info.lease)
3981 { ptr = putUpdateLease(&msg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) goto error; }
3982
3983 err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rInfo->ns, rInfo->port, -1, GetAuthInfoForZone(u, &rInfo->zone));
3984 if (err) { LogMsg("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %ld", err); goto error; }
3985
3986 if (rInfo->state != regState_Refresh && rInfo->state != regState_DeregDeferred && srs->uDNS_info.state != regState_UpdatePending)
3987 rInfo->state = regState_Pending;
3988
3989 SetRecordRetry(m, &srs->RR_SRV);
3990 rInfo->id.NotAnInteger = id.NotAnInteger;
3991 if (mapped) srv->resrec.rdata->u.srv.port = privport;
3992 return;
3993
3994 error:
3995 LogMsg("SendServiceRegistration - Error formatting message");
3996 if (mapped) srv->resrec.rdata->u.srv.port = privport;
3997 unlinkSRS(m, srs);
3998 rInfo->state = regState_Unregistered;
3999 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4000 srs->ServiceCallback(m, srs, err);
4001 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4002 //!!!KRS will mem still be free'd on error?
4003 // NOTE: not safe to touch any client structures here
4004 }
4005
4006 mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srsPtr, const AsyncOpResult *result)
4007 {
4008 ServiceRecordSet *srs = (ServiceRecordSet *)srsPtr;
4009 const zoneData_t *zoneData = mDNSNULL;
4010
4011 if (err) goto error;
4012 if (!result) { LogMsg("ERROR: serviceRegistrationCallback invoked with NULL result and no error"); goto error; }
4013 else zoneData = &result->zoneData;
4014
4015 if (result->type != zoneDataResult)
4016 {
4017 LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type);
4018 goto error;
4019 }
4020
4021 if (srs->uDNS_info.state == regState_Cancelled)
4022 {
4023 // client cancelled registration while fetching zone data
4024 srs->uDNS_info.state = regState_Unregistered;
4025 unlinkSRS(m, srs);
4026 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4027 srs->ServiceCallback(m, srs, mStatus_MemFree);
4028 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4029 return;
4030 }
4031
4032 if (srs->RR_SRV.resrec.rrclass != zoneData->zoneClass)
4033 {
4034 LogMsg("Service %##s - class does not match zone", srs->RR_SRV.resrec.name->c);
4035 goto error;
4036 }
4037
4038 // cache zone data
4039 AssignDomainName(&srs->uDNS_info.zone, &zoneData->zoneName);
4040 srs->uDNS_info.ns.type = mDNSAddrType_IPv4;
4041 srs->uDNS_info.ns = zoneData->primaryAddr;
4042 if (zoneData->updatePort.NotAnInteger) srs->uDNS_info.port = zoneData->updatePort;
4043 else
4044 {
4045 debugf("Update port not advertised via SRV - guessing port 53, no lease option");
4046 srs->uDNS_info.port = UnicastDNSPort;
4047 srs->uDNS_info.lease = mDNSfalse;
4048 }
4049
4050 if (srs->RR_SRV.resrec.rdata->u.srv.port.NotAnInteger && IsPrivateV4Addr(&m->uDNS_info.PrimaryIP))
4051 { srs->uDNS_info.state = regState_NATMap; StartNATPortMap(m, srs); }
4052 else SendServiceRegistration(m, srs);
4053 return;
4054
4055 error:
4056 unlinkSRS(m, srs);
4057 srs->uDNS_info.state = regState_Unregistered;
4058 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4059 srs->ServiceCallback(m, srs, err);
4060 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4061 // NOTE: not safe to touch any client structures here
4062 }
4063
4064 mDNSlocal mStatus SetupRecordRegistration(mDNS *m, AuthRecord *rr)
4065 {
4066 domainname *target = GetRRDomainNameTarget(&rr->resrec);
4067 AuthRecord *ptr = m->uDNS_info.RecordRegistrations;
4068
4069 while (ptr && ptr != rr) ptr = ptr->next;
4070 if (ptr) { LogMsg("Error: SetupRecordRegistration - record %##s already in list!", rr->resrec.name->c); return mStatus_AlreadyRegistered; }
4071
4072 if (rr->uDNS_info.state == regState_FetchingZoneData ||
4073 rr->uDNS_info.state == regState_Pending ||
4074 rr->uDNS_info.state == regState_Registered)
4075 {
4076 LogMsg("Requested double-registration of physical record %##s type %d",
4077 rr->resrec.name->c, rr->resrec.rrtype);
4078 return mStatus_AlreadyRegistered;
4079 }
4080
4081 rr->resrec.rdlength = GetRDLength(&rr->resrec, mDNSfalse);
4082 rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue);
4083
4084 if (!ValidateDomainName(rr->resrec.name))
4085 {
4086 LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr));
4087 return mStatus_Invalid;
4088 }
4089
4090 // Don't do this until *after* we've set rr->resrec.rdlength
4091 if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata))
4092 {
4093 LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr));
4094 return mStatus_Invalid;
4095 }
4096
4097 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
4098 rr->resrec.rdatahash = RDataHashValue(rr->resrec.rdlength, &rr->resrec.rdata->u);
4099 rr->resrec.rdnamehash = target ? DomainNameHashValue(target) : 0;
4100
4101 rr->uDNS_info.state = regState_FetchingZoneData;
4102 rr->next = m->uDNS_info.RecordRegistrations;
4103 m->uDNS_info.RecordRegistrations = rr;
4104 rr->uDNS_info.lease = mDNStrue;
4105
4106 return mStatus_NoError;
4107 }
4108
4109 mDNSexport mStatus uDNS_RegisterRecord(mDNS *const m, AuthRecord *const rr)
4110 {
4111 mStatus err = SetupRecordRegistration(m, rr);
4112 if (err) return err;
4113 else return startGetZoneData(rr->resrec.name, m, mDNStrue, mDNSfalse, RecordRegistrationCallback, rr);
4114 }
4115
4116 mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
4117 {
4118 uDNS_GlobalInfo *u = &m->uDNS_info;
4119 DNSMessage msg;
4120 mDNSu8 *ptr = msg.data;
4121 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
4122 mStatus err;
4123
4124 InitializeDNSMessage(&msg.h, rr->uDNS_info.id, UpdateReqFlags);
4125
4126 ptr = putZone(&msg, ptr, end, &rr->uDNS_info.zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
4127 if (!ptr) goto error;
4128 if (!(ptr = putDeletionRecord(&msg, ptr, &rr->resrec))) goto error;
4129
4130 err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rr->uDNS_info.ns, rr->uDNS_info.port, -1, GetAuthInfoForZone(u, &rr->uDNS_info.zone));
4131 if (err) LogMsg("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %ld", err);
4132
4133 SetRecordRetry(m, rr);
4134 rr->uDNS_info.state = regState_DeregPending;
4135 return;
4136
4137 error:
4138 LogMsg("Error: SendRecordDeregistration - could not contruct deregistration packet");
4139 unlinkAR(&u->RecordRegistrations, rr);
4140 rr->uDNS_info.state = regState_Unregistered;
4141 }
4142
4143
4144
4145 mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr)
4146 {
4147 uDNS_GlobalInfo *u = &m->uDNS_info;
4148 NATTraversalInfo *n = rr->uDNS_info.NATinfo;
4149
4150 switch (rr->uDNS_info.state)
4151 {
4152 case regState_NATMap:
4153 // we're in the middle of a NAT traversal operation
4154 if (!n) LogMsg("uDNS_DeregisterRecord: no NAT info context");
4155 else FreeNATInfo(m, n); // cause response to outstanding request to be ignored.
4156 // Note: normally here we're trying to determine our public address,
4157 //in which case there is not state to be torn down. For simplicity,
4158 //we allow other operations to expire.
4159 rr->uDNS_info.NATinfo = mDNSNULL;
4160 rr->uDNS_info.state = regState_Unregistered;
4161 break;
4162 case regState_ExtraQueued:
4163 rr->uDNS_info.state = regState_Unregistered;
4164 break;
4165 case regState_FetchingZoneData:
4166 rr->uDNS_info.state = regState_Cancelled;
4167 return mStatus_NoError;
4168 case regState_Refresh:
4169 case regState_Pending:
4170 case regState_UpdatePending:
4171 rr->uDNS_info.state = regState_DeregDeferred;
4172 LogMsg("Deferring deregistration of record %##s until registration completes", rr->resrec.name->c);
4173 return mStatus_NoError;
4174 case regState_Registered:
4175 case regState_DeregPending:
4176 break;
4177 case regState_DeregDeferred:
4178 case regState_Cancelled:
4179 LogMsg("Double deregistration of record %##s type %d",
4180 rr->resrec.name->c, rr->resrec.rrtype);
4181 return mStatus_UnknownErr;
4182 case regState_Unregistered:
4183 LogMsg("Requested deregistration of unregistered record %##s type %d",
4184 rr->resrec.name->c, rr->resrec.rrtype);
4185 return mStatus_UnknownErr;
4186 case regState_NATError:
4187 case regState_NoTarget:
4188 LogMsg("ERROR: uDNS_DeregisterRecord called for record %##s with bad state %s", rr->resrec.name->c, rr->uDNS_info.state == regState_NoTarget ? "regState_NoTarget" : "regState_NATError");
4189 return mStatus_UnknownErr;
4190 }
4191
4192 if (rr->uDNS_info.state == regState_Unregistered)
4193 {
4194 // unlink and deliver memfree
4195
4196 unlinkAR(&u->RecordRegistrations, rr);
4197 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4198 if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_MemFree);
4199 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4200 return mStatus_NoError;
4201 }
4202
4203 if (n) FreeNATInfo(m, n);
4204 rr->uDNS_info.NATinfo = mDNSNULL;
4205
4206 SendRecordDeregistration(m, rr);
4207 return mStatus_NoError;
4208 }
4209
4210 mDNSexport mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs)
4211 {
4212 mDNSu32 i;
4213 domainname target;
4214 uDNS_RegInfo *info = &srs->uDNS_info;
4215 ServiceRecordSet **p = &m->uDNS_info.ServiceRegistrations;
4216 while (*p && *p != srs) p=&(*p)->next;
4217 if (*p) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs, srs->RR_SRV.resrec.name->c); return(mStatus_AlreadyRegistered); }
4218 ubzero(info, sizeof(*info));
4219 *p = srs;
4220 srs->next = mDNSNULL;
4221
4222 srs->RR_SRV.resrec.rroriginalttl = kWideAreaTTL;
4223 srs->RR_TXT.resrec.rroriginalttl = kWideAreaTTL;
4224 srs->RR_PTR.resrec.rroriginalttl = kWideAreaTTL;
4225 for (i = 0; i < srs->NumSubTypes;i++) srs->SubTypes[i].resrec.rroriginalttl = kWideAreaTTL;
4226
4227 info->lease = mDNStrue;
4228
4229 srs->RR_SRV.resrec.rdata->u.srv.target.c[0] = 0;
4230 if (!GetServiceTarget(&m->uDNS_info, &srs->RR_SRV, &target))
4231 {
4232 // defer registration until we've got a target
4233 LogMsg("uDNS_RegisterService - no target for %##s", srs->RR_SRV.resrec.name->c);
4234 info->state = regState_NoTarget;
4235 return mStatus_NoError;
4236 }
4237
4238 info->state = regState_FetchingZoneData;
4239 return startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
4240 }
4241
4242 mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
4243 {
4244 uDNS_RegInfo *info = &srs->uDNS_info;
4245 uDNS_GlobalInfo *u = &m->uDNS_info;
4246 DNSMessage msg;
4247 mDNSOpaque16 id;
4248 mDNSu8 *ptr = msg.data;
4249 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
4250 mStatus err = mStatus_UnknownErr;
4251 mDNSu32 i;
4252
4253 id = newMessageID(u);
4254 InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
4255
4256 // put zone
4257 ptr = putZone(&msg, ptr, end, &info->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
4258 if (!ptr) { LogMsg("ERROR: SendServiceDeregistration - putZone"); goto error; }
4259
4260 if (!(ptr = putDeleteAllRRSets(&msg, ptr, srs->RR_SRV.resrec.name))) goto error; // this deletes SRV, TXT, and Extras
4261 if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_PTR.resrec))) goto error;
4262 for (i = 0; i < srs->NumSubTypes; i++)
4263 if (!(ptr = putDeletionRecord(&msg, ptr, &srs->SubTypes[i].resrec))) goto error;
4264
4265
4266 err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &info->ns, info->port, -1, GetAuthInfoForZone(u, &info->zone));
4267 if (err) { LogMsg("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %ld", err); goto error; }
4268
4269 SetRecordRetry(m, &srs->RR_SRV);
4270 info->id.NotAnInteger = id.NotAnInteger;
4271 info->state = regState_DeregPending;
4272
4273 return;
4274
4275 error:
4276 unlinkSRS(m, srs);
4277 info->state = regState_Unregistered;
4278 }
4279
4280 mDNSexport mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs)
4281 {
4282 uDNS_GlobalInfo *u = &m->uDNS_info;
4283 NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
4284 AuthRecord **r = &u->RecordRegistrations;
4285 char *errmsg = "Unknown State";
4286
4287 // We "silently" unlink any Extras from our RecordRegistration list, as they are implicitly deleted from
4288 // the server when we delete all RRSets for this name
4289 while (*r)
4290 {
4291 if (SameDomainName(srs->RR_SRV.resrec.name, (*r)->resrec.name)) *r = (*r)->next;
4292 else r = &(*r)->next;
4293 }
4294
4295 // don't re-register with a new target following deregistration
4296 srs->uDNS_info.SRVChanged = srs->uDNS_info.SRVUpdateDeferred = mDNSfalse;
4297
4298 if (nat)
4299 {
4300 if (nat->state == NATState_Established || nat->state == NATState_Refresh || nat->state == NATState_Legacy)
4301 DeleteNATPortMapping(m, nat, srs);
4302 nat->reg.ServiceRegistration = mDNSNULL;
4303 srs->uDNS_info.NATinfo = mDNSNULL;
4304 FreeNATInfo(m, nat);
4305 }
4306
4307 switch (srs->uDNS_info.state)
4308 {
4309 case regState_Unregistered:
4310 debugf("uDNS_DeregisterService - service %##s not registered", srs->RR_SRV.resrec.name->c);
4311 return mStatus_BadReferenceErr;
4312 case regState_FetchingZoneData:
4313 // let the async op complete, then terminate
4314 srs->uDNS_info.state = regState_Cancelled;
4315 return mStatus_NoError; // deliver memfree upon completion of async op
4316 case regState_Pending:
4317 case regState_Refresh:
4318 case regState_UpdatePending:
4319 // deregister following completion of in-flight operation
4320 srs->uDNS_info.state = regState_DeregDeferred;
4321 return mStatus_NoError;
4322 case regState_DeregPending:
4323 case regState_DeregDeferred:
4324 case regState_Cancelled:
4325 debugf("Double deregistration of service %##s", srs->RR_SRV.resrec.name->c);
4326 return mStatus_NoError;
4327 case regState_NATError: // not registered
4328 case regState_NATMap: // not registered
4329 case regState_NoTarget: // not registered
4330 unlinkSRS(m, srs);
4331 srs->uDNS_info.state = regState_Unregistered;
4332 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4333 srs->ServiceCallback(m, srs, mStatus_MemFree);
4334 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4335 return mStatus_NoError;
4336 case regState_Registered:
4337 srs->uDNS_info.state = regState_DeregPending;
4338 SendServiceDeregistration(m, srs);
4339 return mStatus_NoError;
4340 case regState_ExtraQueued: // only for record registrations
4341 errmsg = "bad state (regState_ExtraQueued)";
4342 goto error;
4343 }
4344
4345 error:
4346 LogMsg("Error, uDNS_DeregisterService: %s", errmsg);
4347 return mStatus_BadReferenceErr;
4348 }
4349
4350 mDNSlocal void SendRecordUpdate(mDNS *m, AuthRecord *rr, uDNS_RegInfo *info)
4351 {
4352 DNSMessage msg;
4353 mDNSu8 *ptr = msg.data;
4354 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
4355 uDNS_GlobalInfo *u = &m->uDNS_info;
4356 mDNSOpaque16 id;
4357 mStatus err = mStatus_UnknownErr;
4358
4359 if (info != &rr->uDNS_info) LogMsg("ERROR: SendRecordUpdate - incorrect info struct!");
4360 rr->uDNS_info.UpdateQueued = mDNSfalse; // if this was queued, clear flag
4361 id = newMessageID(u);
4362 InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
4363 info->id.NotAnInteger = id.NotAnInteger;
4364
4365 // set zone
4366 ptr = putZone(&msg, ptr, end, &info->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
4367 if (!ptr) goto error;
4368
4369 // delete the original record
4370 ptr = putDeletionRecord(&msg, ptr, &rr->resrec);
4371 if (!ptr) goto error;
4372
4373 // change the rdata, add the new record
4374 SwapRData(m, rr, mDNSfalse);
4375 ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl);
4376 SwapRData(m, rr, mDNSfalse); // swap rdata back to original in case we need to retransmit
4377 if (!ptr) goto error; // (rdata gets changed permanently on success)
4378
4379 if (info->lease)
4380 { ptr = putUpdateLease(&msg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) goto error; }
4381
4382 // don't report send errors - retransmission will occurr if necessary
4383 err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &info->ns, info->port, -1, GetAuthInfoForZone(u, &info->zone));
4384 if (err) debugf("ERROR: sendRecordRegistration - mDNSSendDNSMessage - %ld", err);
4385
4386 //!!! Update this when we implement retransmission for services
4387 SetRecordRetry(m, rr);
4388
4389 rr->uDNS_info.state = regState_UpdatePending;
4390 if (&rr->uDNS_info != info) info->state = regState_UpdatePending; // set parent SRS
4391 return;
4392
4393 error:
4394 LogMsg("ERROR: SendRecordUpdate. Error formatting update message.");
4395 info ->state = regState_Registered;
4396 }
4397
4398 mDNSexport mStatus uDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra)
4399 {
4400 mStatus err = mStatus_UnknownErr;
4401
4402 extra->r.resrec.RecordType = kDNSRecordTypeShared; // don't want it to conflict with the service name
4403 extra->r.RecordCallback = mDNSNULL; // don't generate callbacks for extra RRs
4404
4405 if (sr->uDNS_info.state == regState_Registered || sr->uDNS_info.state == regState_Refresh)
4406 err = uDNS_RegisterRecord(m, &extra->r);
4407 else
4408 {
4409 err = SetupRecordRegistration(m, &extra->r);
4410 extra->r.uDNS_info.state = regState_ExtraQueued;
4411 }
4412
4413 if (!err)
4414 {
4415 extra->next = sr->Extras;
4416 sr->Extras = extra;
4417 }
4418 return err;
4419 }
4420
4421 mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr)
4422 {
4423 uDNS_GlobalInfo *u = &m->uDNS_info;
4424 ServiceRecordSet *sptr, *parent = mDNSNULL;
4425 AuthRecord *rptr;
4426 uDNS_RegInfo *info = mDNSNULL;
4427
4428 // find the record in registered service list
4429 for (sptr = u->ServiceRegistrations; sptr; sptr = sptr->next)
4430 if (&sptr->RR_TXT == rr) { info = &sptr->uDNS_info; parent = sptr; break; }
4431
4432 if (!parent)
4433 {
4434 // record not part of a service - check individual record registrations
4435 for (rptr = u->RecordRegistrations; rptr; rptr = rptr->next)
4436 if (rptr == rr) { info = &rr->uDNS_info; break; }
4437 }
4438
4439 if (!info) goto unreg_error;
4440
4441 // uDNS-private pointers so that mDNS.c layer doesn't nuke rdata of an in-flight update
4442 rr->uDNS_info.UpdateRData = rr->NewRData;
4443 rr->uDNS_info.UpdateRDLen = rr->newrdlength;
4444 rr->uDNS_info.UpdateRDCallback = rr->UpdateCallback;
4445 rr->NewRData = mDNSNULL;
4446
4447 switch(info->state)
4448 {
4449 case regState_DeregPending:
4450 case regState_DeregDeferred:
4451 case regState_Cancelled:
4452 case regState_Unregistered:
4453 // not actively registered
4454 goto unreg_error;
4455
4456 case regState_FetchingZoneData:
4457 case regState_NATMap:
4458 case regState_ExtraQueued:
4459 // change rdata directly since it hasn't been sent yet
4460 SwapRData(m, rr, mDNStrue);
4461 return mStatus_NoError;
4462
4463 case regState_Pending:
4464 case regState_Refresh:
4465 case regState_UpdatePending:
4466 // registration in-flight. mark for update after service registration completes
4467 rr->uDNS_info.UpdateQueued = mDNStrue; // note that we mark the record's Queued flag, not its parent's
4468 return mStatus_NoError;
4469
4470 case regState_Registered:
4471 if (parent) { info->state = regState_UpdatePending; SendServiceRegistration(m, parent); }
4472 else SendRecordUpdate(m, rr, info);
4473 return mStatus_NoError;
4474
4475 case regState_NATError:
4476 case regState_NoTarget:
4477 LogMsg("ERROR: uDNS_UpdateRecord called for record %##s with bad state %s", rr->resrec.name->c, rr->uDNS_info.state == regState_NoTarget ? "regState_NoTarget" : "regState_NATError");
4478 return mStatus_UnknownErr; // states for service records only
4479 }
4480
4481 unreg_error:
4482 LogMsg("Requested update of record %##s type %d, part of service not currently registered",
4483 rr->resrec.name->c, rr->resrec.rrtype);
4484 return mStatus_Invalid;
4485 }
4486
4487
4488 // ***************************************************************************
4489 #if COMPILER_LIKES_PRAGMA_MARK
4490 #pragma mark - Periodic Execution Routines
4491 #endif
4492
4493
4494 mDNSlocal mDNSs32 CheckNATMappings(mDNS *m, mDNSs32 timenow)
4495 {
4496 NATTraversalInfo *ptr, *cur;
4497 mDNSs32 nextevent;
4498
4499 ptr = m->uDNS_info.NATTraversals;
4500 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4501
4502 while (ptr)
4503 {
4504 cur = ptr;
4505 ptr = ptr->next;
4506 if (cur->op != NATOp_AddrRequest || cur->state != NATState_Established) // no refresh necessary for established Add requests
4507 {
4508 if (cur->retry - timenow < 0)
4509 {
4510 if (cur->state == NATState_Established) RefreshNATMapping(cur, m);
4511 else if (cur->state == NATState_Request || cur->state == NATState_Refresh)
4512 {
4513 if (cur->ntries >= NATMAP_MAX_TRIES) cur->ReceiveResponse(cur, m, mDNSNULL, 0); // may invalidate "cur"
4514 else SendNATMsg(cur, m);
4515 }
4516 }
4517 else if (cur->retry - nextevent < 0) nextevent = cur->retry;
4518 }
4519 }
4520 return nextevent;
4521 }
4522
4523 mDNSlocal mDNSs32 CheckQueries(mDNS *m, mDNSs32 timenow)
4524 {
4525 DNSQuestion *q;
4526 uDNS_GlobalInfo *u = &m->uDNS_info;
4527 LLQ_Info *llq;
4528 mDNSs32 sendtime;
4529 mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4530 DNSMessage msg;
4531 mStatus err;
4532 mDNSu8 *end;
4533 uDNS_QuestionInfo *info;
4534
4535 u->CurrentQuery = u->ActiveQueries;
4536 while (u->CurrentQuery)
4537 {
4538 q = u->CurrentQuery;
4539 info = &q->uDNS_info;
4540 llq = info->llq;
4541
4542 if (!info->internal && ((!q->LongLived && !info->Answered) || (llq && llq->state < LLQ_Established)) &&
4543 info->RestartTime + RESTART_GOODBYE_DELAY - timenow < 0)
4544 {
4545 // if we've been spinning on restart setup, and we have known answers, give goodbyes (they may be re-added later)
4546 while (info->knownAnswers)
4547 {
4548 CacheRecord *cr = info->knownAnswers;
4549 info->knownAnswers = info->knownAnswers->next;
4550
4551 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4552 q->QuestionCallback(m, q, &cr->resrec, mDNSfalse);
4553 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4554 ufree(cr);
4555 if (q != u->CurrentQuery) { debugf("CheckQueries - question removed via callback."); break; }
4556 }
4557 }
4558 if (q != u->CurrentQuery) continue;
4559
4560 if (q->LongLived && llq->state != LLQ_Poll)
4561 {
4562 if (llq->state >= LLQ_InitialRequest && llq->state <= LLQ_Established)
4563 {
4564 if (llq->retry - timenow < 0)
4565 {
4566 // sanity check to avoid packet flood bugs
4567 if (!llq->retry)
4568 LogMsg("ERROR: retry timer not set for LLQ %##s in state %d", q->qname.c, llq->state);
4569 else if (llq->state == LLQ_Established || llq->state == LLQ_Refresh)
4570 sendLLQRefresh(m, q, llq->origLease);
4571 else if (llq->state == LLQ_InitialRequest)
4572 startLLQHandshake(m, llq, mDNSfalse);
4573 else if (llq->state == LLQ_SecondaryRequest)
4574 sendChallengeResponse(m, q, mDNSNULL);
4575 else if (llq->state == LLQ_Retry)
4576 { llq->ntries = 0; startLLQHandshake(m, llq, mDNSfalse); }
4577 }
4578 else if (llq->retry - nextevent < 0) nextevent = llq->retry;
4579 }
4580 }
4581 else
4582 {
4583 sendtime = q->LastQTime + q->ThisQInterval;
4584 if (sendtime - timenow < 0)
4585 {
4586 mDNSAddr server;
4587 if (GetServerForName(&m->uDNS_info, &q->qname, &server))
4588 {
4589 err = constructQueryMsg(&msg, &end, q);
4590 if (err) LogMsg("Error: uDNS_Idle - constructQueryMsg. Skipping question %##s", q->qname.c);
4591 else
4592 {
4593 err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &server, UnicastDNSPort, -1, mDNSNULL);
4594 if (err) { debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %ld", err); } // surpress syslog messages if we have no network
4595 q->LastQTime = timenow;
4596 if (q->ThisQInterval < MAX_UCAST_POLL_INTERVAL) q->ThisQInterval = q->ThisQInterval * 2;
4597 }
4598 }
4599 }
4600 else if (sendtime - nextevent < 0) nextevent = sendtime;
4601 }
4602 u->CurrentQuery = u->CurrentQuery->next;
4603 }
4604 return nextevent;
4605 }
4606
4607 mDNSlocal mDNSs32 CheckRecordRegistrations(mDNS *m, mDNSs32 timenow)
4608 {
4609 AuthRecord *rr;
4610 uDNS_RegInfo *rInfo;
4611 uDNS_GlobalInfo *u = &m->uDNS_info;
4612 mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4613
4614 //!!!KRS list should be pre-sorted by expiration
4615 for (rr = u->RecordRegistrations; rr; rr = rr->next)
4616 {
4617 rInfo = &rr->uDNS_info;
4618 if (rInfo->state == regState_Pending || rInfo->state == regState_DeregPending || rInfo->state == regState_UpdatePending || rInfo->state == regState_DeregDeferred || rInfo->state == regState_Refresh)
4619 {
4620 if (rr->LastAPTime + rr->ThisAPInterval - timenow < 0)
4621 {
4622 #if MDNS_DEBUGMSGS
4623 char *op = "(unknown operation)";
4624 if (rInfo->state == regState_Pending) op = "registration";
4625 else if (rInfo->state == regState_DeregPending) op = "deregistration";
4626 else if (rInfo->state == regState_Refresh) op = "refresh";
4627 debugf("Retransmit record %s %##s", op, rr->resrec.name->c);
4628 #endif
4629 //LogMsg("Retransmit record %##s", rr->resrec.name->c);
4630 if (rInfo->state == regState_DeregPending) SendRecordDeregistration(m, rr);
4631 else if (rInfo->state == regState_UpdatePending) SendRecordUpdate(m, rr, rInfo);
4632 else sendRecordRegistration(m, rr);
4633 }
4634 if (rr->LastAPTime + rr->ThisAPInterval - nextevent < 0) nextevent = rr->LastAPTime + rr->ThisAPInterval;
4635 }
4636 if (rInfo->lease && rInfo->state == regState_Registered)
4637 {
4638 if (rInfo->expire - timenow < 0)
4639 {
4640 debugf("refreshing record %##s", rr->resrec.name->c);
4641 rInfo->state = regState_Refresh;
4642 sendRecordRegistration(m, rr);
4643 }
4644 if (rInfo->expire - nextevent < 0) nextevent = rInfo->expire;
4645 }
4646 }
4647 return nextevent;
4648 }
4649
4650 mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m, mDNSs32 timenow)
4651 {
4652 ServiceRecordSet *s = m->uDNS_info.ServiceRegistrations;
4653 uDNS_RegInfo *rInfo;
4654 mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4655
4656 // Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery
4657 while (s)
4658 {
4659 ServiceRecordSet *srs = s;
4660 // NOTE: Must advance s here -- SendServiceDeregistration may delete the object we're looking at,
4661 // and then if we tried to do srs = srs->next at the end we'd be referencing a dead object
4662 s = s->next;
4663
4664 rInfo = &srs->uDNS_info;
4665 if (rInfo->state == regState_Pending || rInfo->state == regState_DeregPending || rInfo->state == regState_DeregDeferred || rInfo->state == regState_Refresh || rInfo->state == regState_UpdatePending)
4666 {
4667 if (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval - timenow < 0)
4668 {
4669 #if MDNS_DEBUGMSGS
4670 char *op = "unknown";
4671 if (rInfo->state == regState_Pending) op = "registration";
4672 else if (rInfo->state == regState_DeregPending) op = "deregistration";
4673 else if (rInfo->state == regState_Refresh) op = "refresh";
4674 else if (rInfo->state == regState_UpdatePending) op = "txt record update";
4675 debugf("Retransmit service %s %##s", op, srs->RR_SRV.resrec.name->c);
4676 #endif
4677 if (rInfo->state == regState_DeregPending) { SendServiceDeregistration(m, srs); continue; }
4678 else SendServiceRegistration (m, srs);
4679 }
4680 if (nextevent - srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval > 0)
4681 nextevent = srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval;
4682 }
4683
4684 if (rInfo->lease && rInfo->state == regState_Registered)
4685 {
4686 if (rInfo->expire - timenow < 0)
4687 {
4688 debugf("refreshing service %##s", srs->RR_SRV.resrec.name->c);
4689 rInfo->state = regState_Refresh;
4690 SendServiceRegistration(m, srs);
4691 }
4692 if (rInfo->expire - nextevent < 0) nextevent = rInfo->expire;
4693 }
4694 }
4695 return nextevent;
4696 }
4697
4698 mDNSexport void uDNS_Execute(mDNS *const m)
4699 {
4700 uDNS_GlobalInfo *u = &m->uDNS_info;
4701 mDNSs32 nexte, timenow = mDNSPlatformTimeNow(m);
4702
4703 u->nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4704
4705 if (u->DelaySRVUpdate && u->NextSRVUpdate - timenow < 0)
4706 {
4707 u->DelaySRVUpdate = mDNSfalse;
4708 UpdateSRVRecords(m);
4709 }
4710
4711 nexte = CheckNATMappings(m, timenow);
4712 if (nexte - u->nextevent < 0) u->nextevent = nexte;
4713
4714 nexte = CheckQueries(m, timenow);
4715 if (nexte - u->nextevent < 0) u->nextevent = nexte;
4716
4717 nexte = CheckRecordRegistrations(m, timenow);
4718 if (nexte - u->nextevent < 0) u->nextevent = nexte;
4719
4720 nexte = CheckServiceRegistrations(m, timenow);
4721 if (nexte - u->nextevent < 0) u->nextevent = nexte;
4722
4723 }
4724
4725 // ***************************************************************************
4726 #if COMPILER_LIKES_PRAGMA_MARK
4727 #pragma mark - Startup, Shutdown, and Sleep
4728 #endif
4729
4730 // DeregisterActive causes active LLQs to be removed from the server, e.g. before sleep. Pass false
4731 // following a location change, as the server will reject deletions from a source address different
4732 // from the address on which the LLQ was created.
4733
4734 mDNSlocal void SuspendLLQs(mDNS *m, mDNSBool DeregisterActive)
4735 {
4736 DNSQuestion *q;
4737 LLQ_Info *llq;
4738 for (q = m->uDNS_info.ActiveQueries; q; q = q->next)
4739 {
4740 llq = q->uDNS_info.llq;
4741 if (q->LongLived && llq)
4742 {
4743 if (llq->state == LLQ_GetZoneInfo)
4744 {
4745 debugf("Marking %##s suspend-deferred", q->qname.c);
4746 llq->state = LLQ_SuspendDeferred; // suspend once we're done getting zone info
4747 }
4748 else if (llq->state < LLQ_Suspended)
4749 {
4750 if (DeregisterActive && (llq->state == LLQ_Established || llq->state == LLQ_Refresh))
4751 { debugf("Deleting LLQ %##s", q->qname.c); sendLLQRefresh(m, q, 0); }
4752 debugf("Marking %##s suspended", q->qname.c);
4753 llq->state = LLQ_Suspended;
4754 ubzero(llq->id, 8);
4755 }
4756 else if (llq->state == LLQ_Poll) { debugf("Marking %##s suspended-poll", q->qname.c); llq->state = LLQ_SuspendedPoll; }
4757 if (llq->NATMap) llq->NATMap = mDNSfalse; // may not need nat mapping if we restart with new route
4758 }
4759 }
4760 CheckForUnreferencedLLQMapping(m);
4761 }
4762
4763 mDNSlocal void RestartQueries(mDNS *m)
4764 {
4765 uDNS_GlobalInfo *u = &m->uDNS_info;
4766 DNSQuestion *q;
4767 LLQ_Info *llqInfo;
4768 mDNSs32 timenow = mDNSPlatformTimeNow(m);
4769
4770 u->CurrentQuery = u->ActiveQueries;
4771 while (u->CurrentQuery)
4772 {
4773 q = u->CurrentQuery;
4774 u->CurrentQuery = u->CurrentQuery->next;
4775 llqInfo = q->uDNS_info.llq;
4776 q->uDNS_info.RestartTime = timenow;
4777 q->uDNS_info.Answered = mDNSfalse;
4778 if (q->LongLived)
4779 {
4780 if (!llqInfo) { LogMsg("Error: RestartQueries - %##s long-lived with NULL info", q->qname.c); continue; }
4781 if (llqInfo->state == LLQ_Suspended || llqInfo->state == LLQ_NatMapWait)
4782 {
4783 llqInfo->ntries = -1;
4784 llqInfo->deriveRemovesOnResume = mDNStrue;
4785 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
4786 }
4787 else if (llqInfo->state == LLQ_SuspendDeferred)
4788 llqInfo->state = LLQ_GetZoneInfo; // we never finished getting zone data - proceed as usual
4789 else if (llqInfo->state == LLQ_SuspendedPoll)
4790 {
4791 // if we were polling, we may have had bad zone data due to firewall, etc. - refetch
4792 llqInfo->ntries = 0;
4793 llqInfo->deriveRemovesOnResume = mDNStrue;
4794 llqInfo->state = LLQ_GetZoneInfo;
4795 startGetZoneData(&q->qname, m, mDNSfalse, mDNStrue, startLLQHandshakeCallback, llqInfo);
4796 }
4797 }
4798 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)
4799 }
4800 }
4801
4802 mDNSexport void mDNS_UpdateLLQs(mDNS *m)
4803 {
4804 uDNS_GlobalInfo *u = &m->uDNS_info;
4805
4806 mDNS_Lock(m);
4807 if (u->LLQNatInfo)
4808 {
4809 NATTraversalInfo *nat = u->LLQNatInfo;
4810 u->LLQNatInfo = mDNSNULL;
4811 DeleteNATPortMapping(m, nat, mDNSNULL);
4812 }
4813 SuspendLLQs(m, mDNStrue);
4814 RestartQueries(m);
4815 mDNS_Unlock(m);
4816 }
4817
4818 // simplest sleep logic - rather than having sleep states that must be dealt with explicitly in all parts of
4819 // the code, we simply send a deregistration, and put the service in Refresh state, with a timeout far enough
4820 // in the future that we'll sleep (or the sleep will be cancelled) before it is retransmitted. Then to wake,
4821 // we just move up the timers.
4822
4823
4824
4825 mDNSlocal void SleepRecordRegistrations(mDNS *m)
4826 {
4827 DNSMessage msg;
4828 AuthRecord *rr = m->uDNS_info.RecordRegistrations;
4829 mDNSs32 timenow = mDNSPlatformTimeNow(m);
4830
4831 while (rr)
4832 {
4833 if (rr->uDNS_info.state == regState_Registered ||
4834 rr->uDNS_info.state == regState_Refresh)
4835 {
4836 mDNSu8 *ptr = msg.data, *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
4837 InitializeDNSMessage(&msg.h, newMessageID(&m->uDNS_info), UpdateReqFlags);
4838
4839 // construct deletion update
4840 ptr = putZone(&msg, ptr, end, &rr->uDNS_info.zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
4841 if (!ptr) { LogMsg("Error: SleepRecordRegistrations - could not put zone"); return; }
4842 ptr = putDeletionRecord(&msg, ptr, &rr->resrec);
4843 if (!ptr) { LogMsg("Error: SleepRecordRegistrations - could not put deletion record"); return; }
4844
4845 mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rr->uDNS_info.ns, rr->uDNS_info.port, -1, GetAuthInfoForZone(&m->uDNS_info, &rr->uDNS_info.zone));
4846 rr->uDNS_info.state = regState_Refresh;
4847 rr->LastAPTime = timenow;
4848 rr->ThisAPInterval = 300 * mDNSPlatformOneSecond;
4849 }
4850 rr = rr->next;
4851 }
4852 }
4853
4854 mDNSlocal void WakeRecordRegistrations(mDNS *m)
4855 {
4856 mDNSs32 timenow = mDNSPlatformTimeNow(m);
4857 AuthRecord *rr = m->uDNS_info.RecordRegistrations;
4858
4859 while (rr)
4860 {
4861 if (rr->uDNS_info.state == regState_Refresh)
4862 {
4863 // trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets)
4864 rr->LastAPTime = timenow;
4865 rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
4866 }
4867 rr = rr->next;
4868 }
4869 }
4870
4871 mDNSlocal void SleepServiceRegistrations(mDNS *m)
4872 {
4873 mDNSs32 timenow = mDNSPlatformTimeNow(m);
4874 ServiceRecordSet *srs = m->uDNS_info.ServiceRegistrations;
4875 while(srs)
4876 {
4877 if (srs->uDNS_info.state == regState_Registered ||
4878 srs->uDNS_info.state == regState_Refresh)
4879 {
4880 mDNSOpaque16 origid = srs->uDNS_info.id;
4881 srs->uDNS_info.state = regState_DeregPending; // state expected by SendDereg()
4882 SendServiceDeregistration(m, srs);
4883 srs->uDNS_info.id = origid;
4884 srs->uDNS_info.state = regState_Refresh;
4885 srs->RR_SRV.LastAPTime = timenow;
4886 srs->RR_SRV.ThisAPInterval = 300 * mDNSPlatformOneSecond;
4887 }
4888 srs = srs->next;
4889 }
4890 }
4891
4892 mDNSlocal void WakeServiceRegistrations(mDNS *m)
4893 {
4894 mDNSs32 timenow = mDNSPlatformTimeNow(m);
4895 ServiceRecordSet *srs = m->uDNS_info.ServiceRegistrations;
4896 while(srs)
4897 {
4898 if (srs->uDNS_info.state == regState_Refresh)
4899 {
4900 // trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets)
4901 srs->RR_SRV.LastAPTime = timenow;
4902 srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
4903 }
4904 srs = srs->next;
4905 }
4906 }
4907
4908 mDNSexport void uDNS_Init(mDNS *const m)
4909 {
4910 mDNSPlatformMemZero(&m->uDNS_info, sizeof(uDNS_GlobalInfo));
4911 m->uDNS_info.nextevent = m->timenow_last + 0x78000000;
4912 }
4913
4914 mDNSexport void uDNS_Sleep(mDNS *m)
4915 {
4916 SuspendLLQs(m, mDNStrue);
4917 SleepServiceRegistrations(m);
4918 SleepRecordRegistrations(m);
4919 }
4920
4921 mDNSexport void uDNS_Wake(mDNS *m)
4922 {
4923 RestartQueries(m);
4924 WakeServiceRegistrations(m);
4925 WakeRecordRegistrations(m);
4926 }