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