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