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