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