]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSCore/uDNS.c
d6fddfa1b4a4e8b439c0652c398d6129aa0b47c4
[apple/mdnsresponder.git] / mDNSCore / uDNS.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16
17 * To Do:
18 * Elimate all mDNSPlatformMemAllocate/mDNSPlatformMemFree from this code -- the core code
19 * is supposed to be malloc-free so that it runs in constant memory determined at compile-time.
20 * Any dynamic run-time requirements should be handled by the platform layer below or client layer above
21
22 Change History (most recent first):
23
24 $Log: uDNS.c,v $
25 Revision 1.528 2007/11/02 21:32:30 cheshire
26 <rdar://problem/5575593> BTMM: Deferring deregistration of record log messages on sleep/wake
27
28 Revision 1.527 2007/11/01 16:08:51 cheshire
29 Tidy up alignment of "SetRecordRetry refresh" log messages
30
31 Revision 1.526 2007/10/31 19:26:55 cheshire
32 Don't need to log "Permanently abandoning service registration" message when we're intentionally deleting a service
33
34 Revision 1.525 2007/10/30 23:58:59 cheshire
35 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
36 After failure, double retry interval up to maximum of 30 minutes
37
38 Revision 1.524 2007/10/30 20:10:47 cheshire
39 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
40
41 Revision 1.523 2007/10/30 00:54:31 cheshire
42 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
43 Fixed timing logic to double retry interval properly
44
45 Revision 1.522 2007/10/30 00:04:43 cheshire
46 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
47 Made the code not give up and abandon the record when it gets an error in regState_UpdatePending state
48
49 Revision 1.521 2007/10/29 23:58:52 cheshire
50 <rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
51 Use standard "if (mDNSIPv4AddressIsOnes(....ExternalAddress))" mechanism to determine whether callback has been invoked yet
52
53 Revision 1.520 2007/10/29 21:48:36 cheshire
54 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
55 Added 10% random variation on LLQ renewal time, to reduce unintended timing correlation between multiple machines
56
57 Revision 1.519 2007/10/29 21:37:00 cheshire
58 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
59 Added 10% random variation on record refresh time, to reduce accidental timing correlation between multiple machines
60
61 Revision 1.518 2007/10/26 23:41:29 cheshire
62 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
63
64 Revision 1.517 2007/10/25 23:30:12 cheshire
65 Private DNS registered records now deregistered on sleep and re-registered on wake
66
67 Revision 1.516 2007/10/25 22:53:52 cheshire
68 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
69 Don't unlinkSRS and permanently give up at the first sign of trouble
70
71 Revision 1.515 2007/10/25 21:08:07 cheshire
72 Don't try to send record registrations/deletions before we have our server address
73
74 Revision 1.514 2007/10/25 20:48:47 cheshire
75 For naming consistency (with AuthRecord's UpdateServer) renamed 'ns' to 'SRSUpdateServer'
76
77 Revision 1.513 2007/10/25 20:06:13 cheshire
78 Don't try to do SOA queries using private DNS (TLS over TCP) queries
79
80 Revision 1.512 2007/10/25 18:25:15 cheshire
81 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
82 Don't need a NAT mapping for autotunnel services
83
84 Revision 1.511 2007/10/25 00:16:23 cheshire
85 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
86 Fixed retry timing logic; when DNS server returns an error code, we should retry later,
87 instead of just deleting our record ("UnlinkAuthRecord") and completely giving up
88
89 Revision 1.510 2007/10/24 22:40:06 cheshire
90 Renamed: RecordRegistrationCallback -> RecordRegistrationGotZoneData
91 Renamed: ServiceRegistrationZoneDataComplete -> ServiceRegistrationGotZoneData
92
93 Revision 1.509 2007/10/24 00:54:07 cheshire
94 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
95
96 Revision 1.508 2007/10/24 00:05:03 cheshire
97 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
98 When sending TLS/TCP LLQ setup request over VPN, need to set EventPort to 5353, not zero
99
100 Revision 1.507 2007/10/23 00:33:36 cheshire
101 Improved debugging messages
102
103 Revision 1.506 2007/10/22 19:54:13 cheshire
104 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
105 Only put EventPort in LLQ request when sending from an RFC 1918 source address, not when sending over VPN
106
107 Revision 1.505 2007/10/19 22:08:49 cheshire
108 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
109 Additional fixes and refinements
110
111 Revision 1.504 2007/10/18 23:06:43 cheshire
112 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
113 Additional fixes and refinements
114
115 Revision 1.503 2007/10/18 20:23:17 cheshire
116 Moved SuspendLLQs into mDNS.c, since it's only called from one place
117
118 Revision 1.502 2007/10/17 22:49:54 cheshire
119 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
120
121 Revision 1.501 2007/10/17 22:37:23 cheshire
122 <rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
123
124 Revision 1.500 2007/10/17 21:53:51 cheshire
125 Improved debugging messages; renamed startLLQHandshakeCallback to LLQGotZoneData
126
127 Revision 1.499 2007/10/16 21:16:50 cheshire
128 Get rid of unused uDNS_Sleep() routine
129
130 Revision 1.498 2007/10/16 20:59:41 cheshire
131 Export SuspendLLQs/SleepServiceRegistrations/SleepRecordRegistrations so they're callable from other files
132
133 Revision 1.497 2007/10/05 18:09:44 cheshire
134 <rdar://problem/5524841> Services advertised with wrong target host
135
136 Revision 1.496 2007/10/04 22:38:59 cheshire
137 Added LogOperation message showing new q->ThisQInterval after sending uDNS query packet
138
139 Revision 1.495 2007/10/03 00:16:19 cheshire
140 In PrivateQueryGotZoneData, need to grab lock before calling SetNextQueryTime
141
142 Revision 1.494 2007/10/02 21:11:08 cheshire
143 <rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing
144
145 Revision 1.493 2007/10/02 19:50:23 cheshire
146 Improved debugging message
147
148 Revision 1.492 2007/09/29 03:15:43 cheshire
149 <rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
150 Use AutoTunnelUnregistered macro instead of checking record state directly
151
152 Revision 1.491 2007/09/29 01:33:45 cheshire
153 <rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
154
155 Revision 1.490 2007/09/29 01:06:17 mcguire
156 <rdar://problem/5507862> 9A564: mDNSResponder crash in mDNS_Execute
157
158 Revision 1.489 2007/09/27 22:02:33 cheshire
159 <rdar://problem/5464941> BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord
160
161 Revision 1.488 2007/09/27 21:20:17 cheshire
162 Improved debugging syslog messages
163
164 Revision 1.487 2007/09/27 18:55:11 cheshire
165 <rdar://problem/5477165> BTMM: Multiple SRV records get registered after changing Computer Name
166
167 Revision 1.486 2007/09/27 17:42:49 cheshire
168 Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask"
169
170 Revision 1.485 2007/09/27 02:16:30 cheshire
171 <rdar://problem/5500111> BTMM: LLQ refreshes being sent in the clear to the wrong port
172
173 Revision 1.484 2007/09/27 00:25:39 cheshire
174 Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
175 <rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
176
177 Revision 1.483 2007/09/26 23:16:58 cheshire
178 <rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac
179
180 Revision 1.482 2007/09/26 22:06:02 cheshire
181 <rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
182
183 Revision 1.481 2007/09/26 00:49:46 cheshire
184 Improve packet logging to show sent and received packets,
185 transport protocol (UDP/TCP/TLS) and source/destination address:port
186
187 Revision 1.480 2007/09/21 21:08:52 cheshire
188 Get rid of unnecessary DumpPacket() calls -- it makes more sense
189 to do this in mDNSSendDNSMessage and mDNSCoreReceive instead
190
191 Revision 1.479 2007/09/21 20:01:17 cheshire
192 <rdar://problem/5496750> BTMM: Skip directly to member name in SOA queries to avoid sending names in the clear
193
194 Revision 1.478 2007/09/21 19:29:14 cheshire
195 Added dump of uDNS questions when in MDNS_LOG_VERBOSE_DEBUG mode
196
197 Revision 1.477 2007/09/20 02:29:37 cheshire
198 <rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
199
200 Revision 1.476 2007/09/20 01:19:49 cheshire
201 Improve debugging messages: report startLLQHandshake errors; show state in uDNS_StopLongLivedQuery message
202
203 Revision 1.475 2007/09/19 23:51:26 cheshire
204 <rdar://problem/5480517> BTMM: Need to log a message when NAT port mapping fails
205
206 Revision 1.474 2007/09/19 20:32:09 cheshire
207 Export GetAuthInfoForName so it's callable from other files
208
209 Revision 1.473 2007/09/18 21:42:29 cheshire
210 To reduce programming mistakes, renamed ExtPort to RequestedPort
211
212 Revision 1.472 2007/09/14 21:26:08 cheshire
213 <rdar://problem/5482627> BTMM: Need to manually avoid port conflicts when using UPnP gateways
214
215 Revision 1.471 2007/09/14 01:07:10 cheshire
216 If UPnP NAT gateway returns 0.0.0.0 as external address (e.g. because it hasn't
217 got a DHCP address yet) then retry periodically until it gives us a real address.
218
219 Revision 1.470 2007/09/13 00:36:26 cheshire
220 <rdar://problem/5477360> NAT Reboot detection logic incorrect
221
222 Revision 1.469 2007/09/13 00:28:50 cheshire
223 <rdar://problem/5477354> Host records not updated on NAT address change
224
225 Revision 1.468 2007/09/13 00:16:41 cheshire
226 <rdar://problem/5468706> Miscellaneous NAT Traversal improvements
227
228 Revision 1.467 2007/09/12 23:03:08 cheshire
229 <rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
230
231 Revision 1.466 2007/09/12 22:19:29 cheshire
232 <rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
233
234 Revision 1.465 2007/09/12 19:22:19 cheshire
235 Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
236 Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
237
238 Revision 1.464 2007/09/12 01:22:13 cheshire
239 Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
240
241 Revision 1.463 2007/09/11 20:23:28 vazquez
242 <rdar://problem/5466719> CrashTracer: 3 crashes in mDNSResponder at mDNSResponder: natTraversalHandlePortMapReply + 107
243 Make sure we clean up NATTraversals before free'ing HostnameInfo
244
245 Revision 1.462 2007/09/11 19:19:16 cheshire
246 Correct capitalization of "uPNP" to "UPnP"
247
248 Revision 1.461 2007/09/10 22:08:17 cheshire
249 Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
250
251 Revision 1.460 2007/09/07 21:47:43 vazquez
252 <rdar://problem/5460210> BTMM: SetupSocket 5351 failed; Can't allocate UDP multicast socket spew on wake from sleep with internet sharing on
253 Try to allocate using port 5350 if we get a failure, and only log message if that fails too.
254
255 Revision 1.459 2007/09/07 01:01:05 cheshire
256 <rdar://problem/5464844> BTMM: Services being registered and deregistered in a loop
257 In hndlServiceUpdateReply, need to clear SRVUpdateDeferred
258
259 Revision 1.458 2007/09/06 19:14:33 cheshire
260 Fixed minor error introduced in 1.379 (an "if" statement was deleted but the "else" following it was left there)
261
262 Revision 1.457 2007/09/05 21:48:01 cheshire
263 <rdar://problem/5385864> BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone.
264 Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance cod needs
265 to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
266 otherwise those records will expire and vanish from the cache.
267
268 Revision 1.456 2007/09/05 21:00:17 cheshire
269 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
270 Additional refinement: ThisQInterval needs to be restored in tcpCallback, not in PrivateQueryGotZoneData
271
272 Revision 1.455 2007/09/05 20:53:06 cheshire
273 Tidied up alignment of code layout; code was clearing m->tcpAddrInfo.sock instead of m->tcpDeviceInfo.sock
274
275 Revision 1.454 2007/09/05 02:32:55 cheshire
276 Fixed posix build error (mixed declarations and code)
277
278 Revision 1.453 2007/09/05 02:26:57 cheshire
279 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
280 In PrivateQueryGotZoneData, restore q->ThisQInterval to non-zero value after GetZoneData completes
281
282 Revision 1.452 2007/08/31 22:58:22 cheshire
283 If we have an existing TCP connection we should re-use it instead of just bailing out
284 After receiving dnsbugtest response, need to set m->NextScheduledQuery to cause queries to be re-issued
285
286 Revision 1.451 2007/08/31 18:49:49 vazquez
287 <rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
288
289 Revision 1.450 2007/08/30 22:50:04 mcguire
290 <rdar://problem/5430628> BTMM: Tunneled services are registered when autotunnel can't be setup
291
292 Revision 1.449 2007/08/30 00:43:17 cheshire
293 Need to clear m->rec.r.resrec.RecordType before returning from uDNS_recvLLQResponse
294
295 Revision 1.448 2007/08/30 00:18:46 cheshire
296 <rdar://problem/5448804> Error messages: "SendServiceRegistration: Already have TCP connection..."
297
298 Revision 1.447 2007/08/29 01:18:33 cheshire
299 <rdar://problem/5400181> BTMM: Tunneled services do not need NAT port mappings
300 Only create NAT mappings for SRV records with AutoTarget set to Target_AutoHostAndNATMAP
301
302 Revision 1.446 2007/08/28 23:58:42 cheshire
303 Rename HostTarget -> AutoTarget
304
305 Revision 1.445 2007/08/28 23:53:21 cheshire
306 Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
307
308 Revision 1.444 2007/08/27 20:29:20 cheshire
309 Additional debugging messages
310
311 Revision 1.443 2007/08/24 23:18:28 cheshire
312 mDNS_SetSecretForDomain is called with lock held; needs to use
313 GetAuthInfoForName_internal() instead of external version GetAuthInfoForName()
314
315 Revision 1.442 2007/08/24 22:43:06 cheshire
316 Tidied up coded layout
317
318 Revision 1.441 2007/08/24 01:20:55 cheshire
319 <rdar://problem/5434381> BTMM: Memory corruption in KeychainChanged event handling
320
321 Revision 1.440 2007/08/24 00:15:20 cheshire
322 Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
323
324 Revision 1.439 2007/08/23 21:47:09 vazquez
325 <rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
326 make sure we clean up port mappings on base stations by sending a lease value of 0,
327 and only send NAT-PMP packets on private networks; also save some memory by
328 not using packet structs in NATTraversals.
329
330 Revision 1.438 2007/08/22 17:50:08 vazquez
331 <rdar://problem/5399276> Need to handle errors returned by NAT-PMP routers properly
332 Propagate router errors to clients, and stop logging spurious "message too short" logs.
333
334 Revision 1.437 2007/08/18 00:54:15 mcguire
335 <rdar://problem/5413147> BTMM: Should not register private addresses or zeros
336
337 Revision 1.436 2007/08/08 21:07:48 vazquez
338 <rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
339
340 Revision 1.435 2007/08/03 02:04:09 vazquez
341 <rdar://problem/5371843> BTMM: Private LLQs never fall back to polling
342 Fix case where NAT-PMP returns an external address but does not support
343 port mappings. Undo previous change and now, if the router returns an
344 error in the reply packet we respect it.
345
346 Revision 1.434 2007/08/02 21:03:05 vazquez
347 Change NAT logic to fix case where base station with port mapping turned off
348 returns an external address but does not make port mappings.
349
350 Revision 1.433 2007/08/02 03:30:11 vazquez
351 <rdar://problem/5371843> BTMM: Private LLQs never fall back to polling
352
353 Revision 1.432 2007/08/01 18:15:19 cheshire
354 Fixed crash in tcpCallback; fixed some problems with LLQ setup behind NAT
355
356 Revision 1.431 2007/08/01 16:11:06 cheshire
357 Fixed "mixed declarations and code" compiler error in Posix build
358
359 Revision 1.430 2007/08/01 16:09:13 cheshire
360 Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
361
362 Revision 1.429 2007/08/01 03:09:22 cheshire
363 <rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
364
365 Revision 1.428 2007/08/01 01:43:36 cheshire
366 Need to do mDNS_DropLockBeforeCallback/ReclaimLock around invokation of NAT client callback
367
368 Revision 1.427 2007/08/01 01:31:13 cheshire
369 Need to initialize traversal->tcpInfo fields or code may crash
370
371 Revision 1.426 2007/08/01 01:15:57 cheshire
372 <rdar://problem/5375791> Need to invoke NAT client callback when not on RFC1918 private network
373
374 Revision 1.425 2007/08/01 00:04:14 cheshire
375 <rdar://problem/5261696> Crash in tcpKQSocketCallback
376 Half-open TCP connections were not being cancelled properly
377
378 Revision 1.424 2007/07/31 02:28:35 vazquez
379 <rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
380
381 Revision 1.423 2007/07/30 23:31:26 cheshire
382 Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
383
384 Revision 1.422 2007/07/28 01:25:57 cheshire
385 <rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
386
387 Revision 1.421 2007/07/28 00:04:14 cheshire
388 Various fixes for comments and debugging messages
389
390 Revision 1.420 2007/07/27 23:59:18 cheshire
391 Added compile-time structure size checks
392
393 Revision 1.419 2007/07/27 20:52:29 cheshire
394 Made uDNS_recvLLQResponse() return tri-state result: LLQ_Not, LLQ_First, or LLQ_Events
395
396 Revision 1.418 2007/07/27 20:32:05 vazquez
397 Flag a UPnP NAT traversal before starting a UPnP port mapping, and make sure all
398 calls to mDNS_StopNATOperation() go through the UPnP code
399
400 Revision 1.417 2007/07/27 20:19:42 cheshire
401 Use MDNS_LOG_VERBOSE_DEBUG for dumping out packets instead of MDNS_LOG_DEBUG
402
403 Revision 1.416 2007/07/27 19:59:28 cheshire
404 MUST NOT touch m->CurrentQuestion (or q) after calling AnswerCurrentQuestionWithResourceRecord()
405
406 Revision 1.415 2007/07/27 19:51:01 cheshire
407 Use symbol QC_addnocache instead of literal constant "2"
408
409 Revision 1.414 2007/07/27 19:30:39 cheshire
410 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
411 to properly reflect tri-state nature of the possible responses
412
413 Revision 1.413 2007/07/27 18:44:01 cheshire
414 Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
415
416 Revision 1.412 2007/07/27 18:38:56 cheshire
417 Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
418
419 Revision 1.411 2007/07/27 00:57:13 cheshire
420 Create hostname address records using standard kHostNameTTL (2 minutes) instead of 1 second
421
422 Revision 1.410 2007/07/25 21:41:00 vazquez
423 Make sure we clean up opened sockets when there are network transitions and when changing
424 port mappings
425
426 Revision 1.409 2007/07/25 03:05:02 vazquez
427 Fixes for:
428 <rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
429 <rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
430 and a myriad of other security problems
431
432 Revision 1.408 2007/07/24 21:47:51 cheshire
433 Don't do mDNS_StopNATOperation() for operations we never started
434
435 Revision 1.407 2007/07/24 17:23:33 cheshire
436 <rdar://problem/5357133> Add list validation checks for debugging
437
438 Revision 1.406 2007/07/24 04:14:30 cheshire
439 <rdar://problem/5356281> LLQs not working in with NAT Traversal
440
441 Revision 1.405 2007/07/24 01:29:03 cheshire
442 <rdar://problem/5356026> DNSServiceNATPortMappingCreate() returns stale external address information
443
444 Revision 1.404 2007/07/20 23:10:51 cheshire
445 Fix code layout
446
447 Revision 1.403 2007/07/20 20:12:37 cheshire
448 Rename "mDNS_DomainTypeBrowseLegacy" as "mDNS_DomainTypeBrowseAutomatic"
449
450 Revision 1.402 2007/07/20 00:54:20 cheshire
451 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
452
453 Revision 1.401 2007/07/18 03:23:33 cheshire
454 In GetServiceTarget, need to call SetupLocalAutoTunnelInterface_internal to bring up tunnel on demand, if necessary
455
456 Revision 1.400 2007/07/18 02:30:25 cheshire
457 Defer AutoTunnel server record advertising until we have at least one service to advertise
458 Do AutoTunnel target host selection in GetServiceTarget (instead of uDNS_RegisterService)
459
460 Revision 1.399 2007/07/18 01:02:28 cheshire
461 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
462 Declare records as kDNSRecordTypeKnownUnique so we don't get name conflicts with ourselves
463
464 Revision 1.398 2007/07/16 23:54:48 cheshire
465 <rdar://problem/5338850> Crash when removing or changing DNS keys
466
467 Revision 1.397 2007/07/16 20:13:31 vazquez
468 <rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
469
470 Revision 1.396 2007/07/14 00:33:04 cheshire
471 Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working
472
473 Revision 1.395 2007/07/12 23:56:23 cheshire
474 Change "GetZoneData GOT SRV" message to debugf to reduce verbosity in syslog
475
476 Revision 1.394 2007/07/12 23:36:08 cheshire
477 Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog
478
479 Revision 1.393 2007/07/12 22:15:10 cheshire
480 Modified mDNS_SetSecretForDomain() so it can be called to update an existing entry
481
482 Revision 1.392 2007/07/12 02:51:27 cheshire
483 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
484
485 Revision 1.391 2007/07/11 23:16:31 cheshire
486 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
487 Need to prepend _autotunnel._udp to start of AutoTunnel SRV record name
488
489 Revision 1.390 2007/07/11 22:47:55 cheshire
490 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
491 In mDNS_SetSecretForDomain(), don't register records until after we've validated the parameters
492
493 Revision 1.389 2007/07/11 21:33:10 cheshire
494 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
495 Set up and register AutoTunnelTarget and AutoTunnelService DNS records
496
497 Revision 1.388 2007/07/11 19:27:10 cheshire
498 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
499 For temporary testing fake up an IPv4LL address instead of IPv6 ULA
500
501 Revision 1.387 2007/07/11 03:04:08 cheshire
502 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
503 Add AutoTunnel parameter to mDNS_SetSecretForDomain; Set up AutoTunnel information for domains that require it
504
505 Revision 1.386 2007/07/10 01:57:28 cheshire
506 <rdar://problem/5196524> uDNS: mDNSresponder is leaking TCP connections to DNS server
507 Turned vast chunks of replicated code into a subroutine MakeTCPConn(...);
508 Made routines hold on to the reference it returns instead of leaking it
509
510 Revision 1.385 2007/07/09 23:50:18 cheshire
511 unlinkSRS needs to call mDNS_StopNATOperation_internal(), not mDNS_StopNATOperation()
512
513 Revision 1.384 2007/07/06 21:20:21 cheshire
514 Fix scheduling error (was causing "Task Scheduling Error: Continuously busy for more than a second")
515
516 Revision 1.383 2007/07/06 18:59:59 cheshire
517 Avoid spinning in an infinite loop when uDNS_SendNATMsg() returns an error
518
519 Revision 1.382 2007/07/04 00:49:43 vazquez
520 Clean up extraneous comments
521
522 Revision 1.381 2007/07/03 00:41:14 vazquez
523 More changes for <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
524 Safely deal with packet replies and client callbacks
525
526 Revision 1.380 2007/07/02 22:08:47 cheshire
527 Fixed crash in "Received public IP address" message
528
529 Revision 1.379 2007/06/29 00:08:49 vazquez
530 <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
531
532 Revision 1.378 2007/06/27 20:25:10 cheshire
533 Expanded dnsbugtest comment, explaining requirement that we also need these
534 test queries to black-hole before they get to the root name servers.
535
536 Revision 1.377 2007/06/22 21:27:21 cheshire
537 Modified "could not convert shared secret from base64" log message
538
539 Revision 1.376 2007/06/20 01:10:12 cheshire
540 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
541
542 Revision 1.375 2007/06/15 21:54:51 cheshire
543 <rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
544
545 Revision 1.374 2007/06/12 02:15:26 cheshire
546 Fix incorrect "DNS Server passed" LogOperation message
547
548 Revision 1.373 2007/05/31 00:25:43 cheshire
549 <rdar://problem/5238688> Only send dnsbugtest query for questions where it's warranted
550
551 Revision 1.372 2007/05/25 17:03:45 cheshire
552 lenptr needs to be declared unsigned, otherwise sign extension can mess up the shifting and ORing operations
553
554 Revision 1.371 2007/05/24 00:11:44 cheshire
555 Remove unnecessary lenbuf field from tcpInfo_t
556
557 Revision 1.370 2007/05/23 00:30:59 cheshire
558 Don't change question->TargetQID when repeating query over TCP
559
560 Revision 1.369 2007/05/21 18:04:40 cheshire
561 Updated comments -- port_mapping_create_reply renamed to port_mapping_reply
562
563 Revision 1.368 2007/05/17 19:12:16 cheshire
564 Updated comment about finding matching pair of sockets
565
566 Revision 1.367 2007/05/15 23:38:00 cheshire
567 Need to grab lock before calling SendRecordRegistration();
568
569 Revision 1.366 2007/05/15 00:43:05 cheshire
570 <rdar://problem/4983538> uDNS serviceRegistrationCallback locking failures
571
572 Revision 1.365 2007/05/10 21:19:18 cheshire
573 Rate-limit DNS test queries to at most one per three seconds
574 (useful when we have a dozen active WAB queries, and then we join a new network)
575
576 Revision 1.364 2007/05/07 20:43:45 cheshire
577 <rdar://problem/4241419> Reduce the number of queries and announcements
578
579 Revision 1.363 2007/05/04 22:12:48 cheshire
580 Work towards solving <rdar://problem/5176892> "uDNS_CheckQuery: LastQTime" log messages
581 When code gets in this invalid state, double ThisQInterval each time, to avoid excessive logging
582
583 Revision 1.362 2007/05/04 21:23:05 cheshire
584 <rdar://problem/5167263> Private DNS always returns no answers in the initial LLQ setup response
585 Preparatory work to enable us to do a four-way LLQ handshake over TCP, if we decide that's what we want
586
587 Revision 1.361 2007/05/03 23:50:48 cheshire
588 <rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
589 In the case of negative answers for the address record, set the server address to zerov4Addr
590
591 Revision 1.360 2007/05/03 22:40:38 cheshire
592 <rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
593
594 Revision 1.359 2007/05/02 22:21:33 cheshire
595 <rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
596
597 Revision 1.358 2007/05/01 21:46:31 cheshire
598 Move GetLLQOptData/GetPktLease from uDNS.c into DNSCommon.c so that dnsextd can use them
599
600 Revision 1.357 2007/05/01 01:33:49 cheshire
601 Removed "#define LLQ_Info DNSQuestion" and manually reconciled code that was still referring to "LLQ_Info"
602
603 Revision 1.356 2007/04/30 21:51:06 cheshire
604 Updated comments
605
606 Revision 1.355 2007/04/30 21:33:38 cheshire
607 Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
608 is iterating through the m->ServiceRegistrations list
609
610 Revision 1.354 2007/04/30 01:30:04 cheshire
611 GetZoneData_QuestionCallback needs to call client callback function on error, so client knows operation is finished
612 RecordRegistrationCallback and serviceRegistrationCallback need to clear nta reference when they're invoked
613
614 Revision 1.353 2007/04/28 01:28:25 cheshire
615 Fixed memory leak on error path in FoundDomain
616
617 Revision 1.352 2007/04/27 19:49:53 cheshire
618 In uDNS_ReceiveTestQuestionResponse, also check that srcport matches
619
620 Revision 1.351 2007/04/27 19:28:02 cheshire
621 Any code that calls StartGetZoneData needs to keep a handle to the structure, so
622 it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
623 -- it would start a query and then quickly cancel it, and then when
624 StartGetZoneData completed, it had a dangling pointer and crashed.)
625
626 Revision 1.350 2007/04/26 22:47:14 cheshire
627 Defensive coding: tcpCallback only needs to check "if (closed)", not "if (!n && closed)"
628
629 Revision 1.349 2007/04/26 16:04:06 cheshire
630 In mDNS_AddDNSServer, check whether port matches
631 In uDNS_CheckQuery, handle case where startLLQHandshake changes q->llq->state to LLQ_Poll
632
633 Revision 1.348 2007/04/26 04:01:59 cheshire
634 Copy-and-paste error: Test should be "if (result == DNSServer_Passed)" not "if (result == DNSServer_Failed)"
635
636 Revision 1.347 2007/04/26 00:35:15 cheshire
637 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
638 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
639 inside the firewall may give answers where a public one gives none, and vice versa.)
640
641 Revision 1.346 2007/04/25 19:16:59 cheshire
642 Don't set SuppressStdPort53Queries unless we do actually send a DNS packet
643
644 Revision 1.345 2007/04/25 18:05:11 cheshire
645 Don't try to restart inactive (duplicate) queries
646
647 Revision 1.344 2007/04/25 17:54:07 cheshire
648 Don't cancel Private LLQs using a clear-text UDP packet
649
650 Revision 1.343 2007/04/25 16:40:08 cheshire
651 Add comment explaining uDNS_recvLLQResponse logic
652
653 Revision 1.342 2007/04/25 02:14:38 cheshire
654 <rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
655 Additional fixes to make LLQs work properly
656
657 Revision 1.341 2007/04/24 02:07:42 cheshire
658 <rdar://problem/4246187> Identical client queries should reference a single shared core query
659 Deleted some more redundant code
660
661 Revision 1.340 2007/04/23 22:01:23 cheshire
662 <rdar://problem/5094009> IPv6 filtering in AirPort base station breaks Wide-Area Bonjour
663 As of March 2007, AirPort base stations now block incoming IPv6 connections by default, so there's no point
664 advertising IPv6 addresses in DNS any more -- we have to assume that most of the time a host's IPv6 address
665 probably won't work for incoming connections (but its IPv4 address probably will, using NAT-PMP).
666
667 Revision 1.339 2007/04/22 06:02:03 cheshire
668 <rdar://problem/4615977> Query should immediately return failure when no server
669
670 Revision 1.338 2007/04/21 19:44:11 cheshire
671 Improve uDNS_HandleNATPortMapReply log message
672
673 Revision 1.337 2007/04/21 02:03:00 cheshire
674 Also need to set AddressRec->resrec.RecordType in the NAT case too
675
676 Revision 1.336 2007/04/20 21:16:12 cheshire
677 Fixed bogus double-registration of host name -- was causing these warning messages in syslog:
678 Error! Tried to register AuthRecord 0181FB0C host.example.com. (Addr) that's already in the list
679
680 Revision 1.335 2007/04/19 23:57:20 cheshire
681 Temporary workaround for some AirPort base stations that don't seem to like us requesting public port zero
682
683 Revision 1.334 2007/04/19 23:21:51 cheshire
684 Fixed a couple of places where the StartGetZoneData check was backwards
685
686 Revision 1.333 2007/04/19 22:50:53 cheshire
687 <rdar://problem/4246187> Identical client queries should reference a single shared core query
688
689 Revision 1.332 2007/04/19 20:34:32 cheshire
690 Add debugging log message in uDNS_CheckQuery()
691
692 Revision 1.331 2007/04/19 20:06:41 cheshire
693 Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
694
695 Revision 1.330 2007/04/19 19:51:54 cheshire
696 Get rid of unnecessary initializeQuery() routine
697
698 Revision 1.329 2007/04/19 18:03:52 cheshire
699 Improved "mDNS_AddSearchDomain" log message
700
701 Revision 1.328 2007/04/18 20:57:20 cheshire
702 Commented out "GetAuthInfoForName none found" debugging message
703
704 Revision 1.327 2007/04/17 19:21:29 cheshire
705 <rdar://problem/5140339> Domain discovery not working over VPN
706
707 Revision 1.326 2007/04/16 20:49:39 cheshire
708 Fix compile errors for mDNSPosix build
709
710 Revision 1.325 2007/04/05 22:55:35 cheshire
711 <rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
712
713 Revision 1.324 2007/04/05 20:43:30 cheshire
714 Collapse sprawling code onto one line -- this is part of a bigger block of identical
715 code that has been copied-and-pasted into six different places in the same file.
716 This really needs to be turned into a subroutine.
717
718 Revision 1.323 2007/04/04 21:48:52 cheshire
719 <rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
720
721 Revision 1.322 2007/04/03 19:53:06 cheshire
722 Use mDNSSameIPPort (and similar) instead of accessing internal fields directly
723
724 Revision 1.321 2007/04/02 23:44:09 cheshire
725 Minor code tidying
726
727 Revision 1.320 2007/03/31 01:26:13 cheshire
728 Take out GetAuthInfoForName syslog message
729
730 Revision 1.319 2007/03/31 01:10:53 cheshire
731 Add debugging
732
733 Revision 1.318 2007/03/31 00:17:11 cheshire
734 Remove some LogMsgs
735
736 Revision 1.317 2007/03/29 00:09:31 cheshire
737 Improve "uDNS_InitLongLivedQuery" log message
738
739 Revision 1.316 2007/03/28 21:16:27 cheshire
740 Remove DumpPacket() call now that OPT pseudo-RR rrclass bug is fixed
741
742 Revision 1.315 2007/03/28 21:02:18 cheshire
743 <rdar://problem/3810563> Wide-Area Bonjour should work on multi-subnet private network
744
745 Revision 1.314 2007/03/28 15:56:37 cheshire
746 <rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
747
748 Revision 1.313 2007/03/28 01:27:32 cheshire
749 <rdar://problem/4996439> Unicast DNS polling server every three seconds
750 StartLLQPolling was using INIT_UCAST_POLL_INTERVAL instead of LLQ_POLL_INTERVAL for the retry interval
751
752 Revision 1.312 2007/03/27 23:48:21 cheshire
753 Use mDNS_StopGetDomains(), not mDNS_StopQuery()
754
755 Revision 1.311 2007/03/27 22:47:51 cheshire
756 Remove unnecessary "*(long*)0 = 0;" to generate crash and stack trace
757
758 Revision 1.310 2007/03/24 01:24:13 cheshire
759 Add validator for uDNS data structures; fixed crash in RegisterSearchDomains()
760
761 Revision 1.309 2007/03/24 00:47:53 cheshire
762 <rdar://problem/4983538> serviceRegistrationCallback: Locking Failure! mDNS_busy (1) != mDNS_reentrancy (2)
763 Locking in this file is all messed up. For now we'll just work around the issue.
764
765 Revision 1.308 2007/03/24 00:41:33 cheshire
766 Minor code cleanup (move variable declarations to minimum enclosing scope)
767
768 Revision 1.307 2007/03/21 23:06:00 cheshire
769 Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
770
771 Revision 1.306 2007/03/21 00:30:03 cheshire
772 <rdar://problem/4789455> Multiple errors in DNameList-related code
773
774 Revision 1.305 2007/03/20 17:07:15 cheshire
775 Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
776
777 Revision 1.304 2007/03/17 00:02:11 cheshire
778 <rdar://problem/5067013> NAT-PMP: Lease TTL is being ignored
779
780 Revision 1.303 2007/03/10 03:26:44 cheshire
781 <rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
782
783 Revision 1.302 2007/03/10 02:29:58 cheshire
784 Added comments about NAT-PMP response functions
785
786 Revision 1.301 2007/03/10 02:02:58 cheshire
787 <rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
788 Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
789
790 Revision 1.300 2007/03/08 18:56:00 cheshire
791 Fixed typo: "&v4.ip.v4.b[0]" is always non-zero (ampersand should not be there)
792
793 Revision 1.299 2007/02/28 01:45:47 cheshire
794 <rdar://problem/4683261> NAT-PMP: Port mapping refreshes should contain actual public port
795 <rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
796
797 Revision 1.298 2007/02/14 03:16:39 cheshire
798 <rdar://problem/4789477> Eliminate unnecessary malloc/free in mDNSCore code
799
800 Revision 1.297 2007/02/08 21:12:28 cheshire
801 <rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
802
803 Revision 1.296 2007/01/29 16:03:22 cheshire
804 Fix unused parameter warning
805
806 Revision 1.295 2007/01/27 03:34:27 cheshire
807 Made GetZoneData use standard queries (and cached results);
808 eliminated GetZoneData_Callback() packet response handler
809
810 Revision 1.294 2007/01/25 00:40:16 cheshire
811 Unified CNAME-following functionality into cache management code (which means CNAME-following
812 should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine.
813
814 Revision 1.293 2007/01/23 02:56:11 cheshire
815 Store negative results in the cache, instead of generating them out of pktResponseHndlr()
816
817 Revision 1.292 2007/01/20 01:32:40 cheshire
818 Update comments and debugging messages
819
820 Revision 1.291 2007/01/20 00:07:02 cheshire
821 When we have credentials in the keychain for a domain, we attempt private queries, but
822 if the authoritative server is not set up for private queries (i.e. no _dns-query-tls
823 or _dns-llq-tls record) then we need to fall back to conventional non-private queries.
824
825 Revision 1.290 2007/01/19 23:41:45 cheshire
826 Need to clear m->rec.r.resrec.RecordType after calling GetLLQOptData()
827
828 Revision 1.289 2007/01/19 23:32:07 cheshire
829 Eliminate pointless timenow variable
830
831 Revision 1.288 2007/01/19 23:26:08 cheshire
832 Right now tcpCallback does not run holding the lock, so no need to drop the lock before invoking callbacks
833
834 Revision 1.287 2007/01/19 22:55:41 cheshire
835 Eliminate redundant identical parameters to GetZoneData_StartQuery()
836
837 Revision 1.286 2007/01/19 21:17:33 cheshire
838 StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
839
840 Revision 1.285 2007/01/19 18:39:11 cheshire
841 Fix a bunch of parameters that should have been declared "const"
842
843 Revision 1.284 2007/01/19 18:28:28 cheshire
844 Improved debugging messages
845
846 Revision 1.283 2007/01/19 18:09:33 cheshire
847 Fixed getLLQAtIndex (now called GetLLQOptData):
848 1. It incorrectly assumed all EDNS0 OPT records are the same size (it ignored optlen)
849 2. It used inefficient memory copying instead of just returning a pointer
850
851 Revision 1.282 2007/01/17 22:06:01 cheshire
852 Replace duplicated literal constant "{ { 0 } }" with symbol "zeroIPPort"
853
854 Revision 1.281 2007/01/17 21:58:13 cheshire
855 For clarity, rename ntaContext field "isPrivate" to "ntaPrivate"
856
857 Revision 1.280 2007/01/17 21:46:02 cheshire
858 Remove redundant duplicated "isPrivate" field from LLQ_Info
859
860 Revision 1.279 2007/01/17 21:35:31 cheshire
861 For clarity, rename zoneData_t field "isPrivate" to "zonePrivate"
862
863 Revision 1.278 2007/01/16 03:04:16 cheshire
864 <rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
865 Don't cache result of ntaContextSRV(context) in a local variable --
866 the macro evaluates to a different result after we clear "context->isPrivate"
867
868 Revision 1.277 2007/01/10 22:51:58 cheshire
869 <rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
870
871 Revision 1.276 2007/01/10 02:09:30 cheshire
872 Better LogOperation record of keys read from System Keychain
873
874 Revision 1.275 2007/01/09 22:37:18 cheshire
875 Provide ten-second grace period for deleted keys, to give mDNSResponder
876 time to delete host name before it gives up access to the required key.
877
878 Revision 1.274 2007/01/09 01:16:32 cheshire
879 Improve "ERROR m->CurrentQuestion already set" debugging messages
880
881 Revision 1.273 2007/01/08 23:58:00 cheshire
882 Don't request regDomain and browseDomains in uDNS_SetupDNSConfig() -- it just ignores those results
883
884 Revision 1.272 2007/01/05 08:30:42 cheshire
885 Trim excessive "$Log" checkin history from before 2006
886 (checkin history still available via "cvs log ..." of course)
887
888 Revision 1.271 2007/01/05 06:34:03 cheshire
889 Improve "ERROR m->CurrentQuestion already set" debugging messages
890
891 Revision 1.270 2007/01/05 05:44:33 cheshire
892 Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c,
893 so that mDNSPosix embedded clients will compile again
894
895 Revision 1.269 2007/01/04 23:11:13 cheshire
896 <rdar://problem/4720673> uDNS: Need to start caching unicast records
897 When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
898
899 Revision 1.268 2007/01/04 22:06:38 cheshire
900 Fixed crash in LLQNatMapComplete()
901
902 Revision 1.267 2007/01/04 21:45:20 cheshire
903 Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
904 to do additional lock sanity checking around callback invocations
905
906 Revision 1.266 2007/01/04 21:01:20 cheshire
907 <rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
908 Only return NXDOMAIN results to clients that request them using kDNSServiceFlagsReturnIntermediates
909
910 Revision 1.265 2007/01/04 20:47:17 cheshire
911 Fixed crash in CheckForUnreferencedLLQMapping()
912
913 Revision 1.264 2007/01/04 20:39:27 cheshire
914 Fix locking mismatch
915
916 Revision 1.263 2007/01/04 02:39:53 cheshire
917 <rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
918
919 Revision 1.262 2007/01/04 00:29:25 cheshire
920 Covert LogMsg() in GetAuthInfoForName to LogOperation()
921
922 Revision 1.261 2006/12/22 20:59:49 cheshire
923 <rdar://problem/4742742> Read *all* DNS keys from keychain,
924 not just key for the system-wide default registration domain
925
926 Revision 1.260 2006/12/21 00:06:07 cheshire
927 Don't need to do mDNSPlatformMemZero() -- mDNS_SetupResourceRecord() does it for us
928
929 Revision 1.259 2006/12/20 04:07:36 cheshire
930 Remove uDNS_info substructure from AuthRecord_struct
931
932 Revision 1.258 2006/12/19 22:49:24 cheshire
933 Remove uDNS_info substructure from ServiceRecordSet_struct
934
935 Revision 1.257 2006/12/19 02:38:20 cheshire
936 Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
937
938 Revision 1.256 2006/12/19 02:18:48 cheshire
939 Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
940
941 Revision 1.255 2006/12/16 01:58:31 cheshire
942 <rdar://problem/4720673> uDNS: Need to start caching unicast records
943
944 Revision 1.254 2006/12/15 19:23:39 cheshire
945 Use new DomainNameLengthLimit() function, to be more defensive against malformed
946 data received from the network.
947
948 Revision 1.253 2006/12/01 07:43:34 herscher
949 Fix byte ordering problem for one-shot TCP queries.
950 Iterate more intelligently over duplicates in uDNS_ReceiveMsg to avoid spin loops.
951
952 Revision 1.252 2006/11/30 23:07:57 herscher
953 <rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
954
955 Revision 1.251 2006/11/28 21:42:11 mkrochma
956 Work around a crashing bug that was introduced by uDNS and mDNS code unification
957
958 Revision 1.250 2006/11/18 05:01:30 cheshire
959 Preliminary support for unifying the uDNS and mDNS code,
960 including caching of uDNS answers
961
962 Revision 1.249 2006/11/10 07:44:04 herscher
963 <rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
964
965 Revision 1.248 2006/11/08 04:26:53 cheshire
966 Fix typo in debugging message
967
968 Revision 1.247 2006/10/20 05:35:04 herscher
969 <rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
970
971 Revision 1.246 2006/10/11 19:29:41 herscher
972 <rdar://problem/4744553> uDNS: mDNSResponder-111 using 100% CPU
973
974 Revision 1.245 2006/10/04 22:21:15 herscher
975 Tidy up references to mDNS_struct introduced when the embedded uDNS_info struct was removed.
976
977 Revision 1.244 2006/10/04 21:51:27 herscher
978 Replace calls to mDNSPlatformTimeNow(m) with m->timenow
979
980 Revision 1.243 2006/10/04 21:38:59 herscher
981 Remove uDNS_info substructure from DNSQuestion_struct
982
983 Revision 1.242 2006/09/27 00:51:46 herscher
984 Fix compile error when _LEGACY_NAT_TRAVERSAL_ is not defined
985
986 Revision 1.241 2006/09/26 01:54:47 herscher
987 <rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
988
989 Revision 1.240 2006/09/15 21:20:15 cheshire
990 Remove uDNS_info substructure from mDNS_struct
991
992 Revision 1.239 2006/08/16 02:52:56 mkrochma
993 <rdar://problem/4104154> Actually fix it this time
994
995 Revision 1.238 2006/08/16 00:31:50 mkrochma
996 <rdar://problem/4386944> Get rid of NotAnInteger references
997
998 Revision 1.237 2006/08/15 23:38:17 mkrochma
999 <rdar://problem/4104154> Requested Public Port field should be set to zero on mapping deletion
1000
1001 Revision 1.236 2006/08/14 23:24:23 cheshire
1002 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
1003
1004 Revision 1.235 2006/07/30 05:45:36 cheshire
1005 <rdar://problem/4304215> Eliminate MIN_UCAST_PERIODIC_EXEC
1006
1007 Revision 1.234 2006/07/22 02:58:36 cheshire
1008 Code was clearing namehash twice instead of namehash and rdatahash
1009
1010 Revision 1.233 2006/07/20 19:46:51 mkrochma
1011 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1012 Fix Private DNS
1013
1014 Revision 1.232 2006/07/15 02:01:29 cheshire
1015 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1016 Fix broken "empty string" browsing
1017
1018 Revision 1.231 2006/07/05 23:28:22 cheshire
1019 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1020
1021 Revision 1.230 2006/06/29 03:02:44 cheshire
1022 <rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
1023
1024 Revision 1.229 2006/03/02 22:03:41 cheshire
1025 <rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
1026 Refinement: m->rec.r.resrec.RecordType needs to be cleared *every* time around for loop, not just once at the end
1027
1028 Revision 1.228 2006/02/26 00:54:42 cheshire
1029 Fixes to avoid code generation warning/error on FreeBSD 7
1030
1031 Revision 1.227 2006/01/09 20:47:05 cheshire
1032 <rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
1033
1034 */
1035
1036 #include "uDNS.h"
1037
1038 #if(defined(_MSC_VER))
1039 // Disable "assignment within conditional expression".
1040 // Other compilers understand the convention that if you place the assignment expression within an extra pair
1041 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
1042 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
1043 // to the compiler that the assignment is intentional, we have to just turn this warning off completely.
1044 #pragma warning(disable:4706)
1045 #endif
1046
1047 typedef struct tcpInfo_t
1048 {
1049 mDNS *m;
1050 TCPSocket *sock;
1051 DNSMessage request;
1052 int requestLen;
1053 DNSQuestion *question; // For queries
1054 ServiceRecordSet *srs; // For service record updates
1055 AuthRecord *rr; // For record updates
1056 mDNSAddr Addr;
1057 mDNSIPPort Port;
1058 DNSMessage *reply;
1059 mDNSu16 replylen;
1060 unsigned long nread;
1061 int numReplies;
1062 } tcpInfo_t;
1063
1064 typedef struct SearchListElem
1065 {
1066 struct SearchListElem *next;
1067 domainname domain;
1068 int flag; // -1 means delete, 0 means unchanged, +1 means newly added
1069 DNSQuestion BrowseQ;
1070 DNSQuestion DefBrowseQ;
1071 DNSQuestion AutomaticBrowseQ;
1072 DNSQuestion RegisterQ;
1073 DNSQuestion DefRegisterQ;
1074 ARListElem *AuthRecs;
1075 } SearchListElem;
1076
1077 // For domain enumeration and automatic browsing
1078 // This is the user's DNS search list.
1079 // In each of these domains we search for our special pointer records (lb._dns-sd._udp.<domain>, etc.)
1080 // to discover recommended domains for domain enumeration (browse, default browse, registration,
1081 // default registration) and possibly one or more recommended automatic browsing domains.
1082 static SearchListElem *SearchList = mDNSNULL;
1083
1084 // Temporary workaround to make ServiceRecordSet list management safe.
1085 // Ideally a ServiceRecordSet shouldn't be a special entity that's given special treatment by the uDNS code
1086 // -- it should just be a grouping of records that are treated the same as any other registered records.
1087 // In that case it may no longer be necessary to keep an explicit list of ServiceRecordSets, which in turn
1088 // would avoid the perils of modifying that list cleanly while some other piece of code is iterating through it.
1089 static ServiceRecordSet *CurrentServiceRecordSet = mDNSNULL;
1090
1091 // ***************************************************************************
1092 #if COMPILER_LIKES_PRAGMA_MARK
1093 #pragma mark - General Utility Functions
1094 #endif
1095
1096 // Unlink an AuthRecord from the m->ResourceRecords list.
1097 // This seems risky. Probably some (or maybe all) of the places calling UnlinkAuthRecord to directly
1098 // remove a record from the list should actually be using mDNS_Deregister/mDNS_Deregister_internal.
1099 mDNSlocal mStatus UnlinkAuthRecord(mDNS *const m, AuthRecord *const rr)
1100 {
1101 AuthRecord **list = &m->ResourceRecords;
1102 if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next;
1103 if (m->CurrentRecord == rr) m->CurrentRecord = rr->next;
1104 while (*list && *list != rr) list = &(*list)->next;
1105 if (!*list)
1106 {
1107 list = &m->DuplicateRecords;
1108 while (*list && *list != rr) list = &(*list)->next;
1109 }
1110 if (*list) { *list = rr->next; rr->next = mDNSNULL; return(mStatus_NoError); }
1111 LogMsg("ERROR: UnlinkAuthRecord - no such active record %##s", rr->resrec.name->c);
1112 return(mStatus_NoSuchRecord);
1113 }
1114
1115 // unlinkSRS is an internal routine (i.e. must be called with the lock already held)
1116 mDNSlocal void unlinkSRS(mDNS *const m, ServiceRecordSet *srs)
1117 {
1118 ServiceRecordSet **p;
1119
1120 if (srs->NATinfo.clientContext)
1121 {
1122 mDNS_StopNATOperation_internal(m, &srs->NATinfo);
1123 srs->NATinfo.clientContext = mDNSNULL;
1124 }
1125
1126 for (p = &m->ServiceRegistrations; *p; p = &(*p)->uDNS_next)
1127 if (*p == srs)
1128 {
1129 ExtraResourceRecord *e;
1130 *p = srs->uDNS_next;
1131 if (CurrentServiceRecordSet == srs)
1132 CurrentServiceRecordSet = srs->uDNS_next;
1133 srs->uDNS_next = mDNSNULL;
1134 for (e=srs->Extras; e; e=e->next)
1135 if (UnlinkAuthRecord(m, &e->r))
1136 LogMsg("unlinkSRS: extra record %##s not found", e->r.resrec.name->c);
1137 return;
1138 }
1139 LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list %##s", srs->RR_SRV.resrec.name->c);
1140 }
1141
1142 // set retry timestamp for record with exponential backoff
1143 // (for service record sets, use RR_SRV as representative for time checks
1144 mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mStatus SendErr)
1145 {
1146 mDNSs32 elapsed = m->timenow - rr->LastAPTime;
1147 rr->LastAPTime = m->timenow;
1148
1149 #if 0
1150 // Code for stress-testing registration renewal code
1151 if (rr->expire && rr->expire - m->timenow > mDNSPlatformOneSecond * 120)
1152 {
1153 LogOperation("Adjusting expiry from %d to 120 seconds for %s",
1154 (rr->expire - m->timenow) / mDNSPlatformOneSecond, ARDisplayString(m, rr));
1155 rr->expire = m->timenow + mDNSPlatformOneSecond * 120;
1156 }
1157 #endif
1158
1159 if (rr->expire && rr->expire - m->timenow > mDNSPlatformOneSecond)
1160 {
1161 mDNSs32 remaining = rr->expire - m->timenow;
1162 rr->ThisAPInterval = remaining/2 + mDNSRandom(remaining/10);
1163 LogOperation("SetRecordRetry refresh in %4d of %4d for %s",
1164 rr->ThisAPInterval / mDNSPlatformOneSecond,
1165 (rr->expire - m->timenow) / mDNSPlatformOneSecond,
1166 ARDisplayString(m, rr));
1167 return;
1168 }
1169
1170 rr->expire = 0;
1171
1172 // If at least half our our time interval has elapsed, it's time to double rr->ThisAPInterval
1173 // If resulting interval is too small, set to at least INIT_UCAST_POLL_INTERVAL (3 seconds)
1174 // If resulting interval is too large, set to at most 30 minutes
1175 if (rr->ThisAPInterval / 2 <= elapsed) rr->ThisAPInterval *= 2;
1176 if (rr->ThisAPInterval < INIT_UCAST_POLL_INTERVAL || SendErr == mStatus_TransientErr)
1177 rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
1178 if (rr->ThisAPInterval > 30 * 60 * mDNSPlatformOneSecond)
1179 rr->ThisAPInterval = 30 * 60 * mDNSPlatformOneSecond;
1180
1181 LogOperation("SetRecordRetry retry in %4d for %s", rr->ThisAPInterval / mDNSPlatformOneSecond, ARDisplayString(m, rr));
1182 }
1183
1184 // ***************************************************************************
1185 #if COMPILER_LIKES_PRAGMA_MARK
1186 #pragma mark - Name Server List Management
1187 #endif
1188
1189 mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port)
1190 {
1191 DNSServer **p = &m->DNSServers;
1192
1193 if (!d) d = (const domainname *)"";
1194
1195 LogOperation("mDNS_AddDNSServer: Adding %#a for %##s", addr, d->c);
1196 if (m->mDNS_busy != m->mDNS_reentrancy+1)
1197 LogMsg("mDNS_AddDNSServer: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
1198
1199 while (*p) // Check if we already have this {server,domain} pair registered
1200 {
1201 if ((*p)->interface == interface && (*p)->teststate != DNSServer_Disabled &&
1202 mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d))
1203 {
1204 if (!(*p)->del) LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr, d->c);
1205 (*p)->del = mDNSfalse;
1206 return(*p);
1207 }
1208 p=&(*p)->next;
1209 }
1210
1211 // allocate, add to list
1212 *p = mDNSPlatformMemAllocate(sizeof(**p));
1213 if (!*p) LogMsg("Error: mDNS_AddDNSServer - malloc");
1214 else
1215 {
1216 (*p)->interface = interface;
1217 (*p)->addr = *addr;
1218 (*p)->port = port;
1219 (*p)->del = mDNSfalse;
1220 (*p)->teststate = DNSServer_Untested;
1221 (*p)->lasttest = m->timenow - INIT_UCAST_POLL_INTERVAL;
1222 AssignDomainName(&(*p)->domain, d);
1223 (*p)->next = mDNSNULL;
1224 }
1225 return(*p);
1226 }
1227
1228 // ***************************************************************************
1229 #if COMPILER_LIKES_PRAGMA_MARK
1230 #pragma mark - authorization management
1231 #endif
1232
1233 mDNSlocal DomainAuthInfo *GetAuthInfoForName_direct(mDNS *m, const domainname *const name)
1234 {
1235 const domainname *n = name;
1236 while (n->c[0])
1237 {
1238 DomainAuthInfo *ptr;
1239 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
1240 if (SameDomainName(&ptr->domain, n))
1241 {
1242 debugf("GetAuthInfoForName %##s Matched %##s Key name %##s", name->c, ptr->domain.c, ptr->keyname.c);
1243 return(ptr);
1244 }
1245 n = (const domainname *)(n->c + 1 + n->c[0]);
1246 }
1247 //LogOperation("GetAuthInfoForName none found for %##s", name->c);
1248 return mDNSNULL;
1249 }
1250
1251 // MUST be called with lock held
1252 mDNSexport DomainAuthInfo *GetAuthInfoForName_internal(mDNS *m, const domainname *const name)
1253 {
1254 DomainAuthInfo **p = &m->AuthInfoList;
1255
1256 if (m->mDNS_busy != m->mDNS_reentrancy+1)
1257 LogMsg("GetAuthInfoForName_internal: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
1258
1259 // First purge any dead keys from the list
1260 while (*p)
1261 {
1262 if ((*p)->deltime && m->timenow - (*p)->deltime >= 0 && AutoTunnelUnregistered(*p))
1263 {
1264 DNSQuestion *q;
1265 DomainAuthInfo *info = *p;
1266 LogOperation("GetAuthInfoForName_internal deleting expired key %##s %##s", info->domain.c, info->keyname.c);
1267 *p = info->next; // Cut DomainAuthInfo from list *before* scanning our question list updating AuthInfo pointers
1268 for (q = m->Questions; q; q=q->next)
1269 if (q->AuthInfo == info)
1270 {
1271 q->AuthInfo = GetAuthInfoForName_direct(m, &q->qname);
1272 debugf("GetAuthInfoForName_internal updated q->AuthInfo from %##s to %##s for %##s (%s)",
1273 info->domain.c, q->AuthInfo ? q->AuthInfo->domain.c : mDNSNULL, q->qname.c, DNSTypeName(q->qtype));
1274 }
1275
1276 // Probably not essential, but just to be safe, zero out the secret key data
1277 // so we don't leave it hanging around in memory
1278 // (where it could potentially get exposed via some other bug)
1279 mDNSPlatformMemZero(info, sizeof(*info));
1280 mDNSPlatformMemFree(info);
1281 }
1282 else
1283 p = &(*p)->next;
1284 }
1285
1286 return(GetAuthInfoForName_direct(m, name));
1287 }
1288
1289 mDNSexport DomainAuthInfo *GetAuthInfoForName(mDNS *m, const domainname *const name)
1290 {
1291 DomainAuthInfo *d;
1292 mDNS_Lock(m);
1293 d = GetAuthInfoForName_internal(m, name);
1294 mDNS_Unlock(m);
1295 return(d);
1296 }
1297
1298 // MUST be called with the lock held
1299 mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
1300 const domainname *domain, const domainname *keyname, const char *b64keydata, mDNSBool AutoTunnel)
1301 {
1302 DNSQuestion *q;
1303 DomainAuthInfo **p = &m->AuthInfoList;
1304 if (!info || !b64keydata) { LogMsg("mDNS_SetSecretForDomain: ERROR: info %p b64keydata %p", info, b64keydata); return(mStatus_BadParamErr); }
1305
1306 LogOperation("mDNS_SetSecretForDomain: domain %##s key %##s%s", domain->c, keyname->c, AutoTunnel ? " AutoTunnel" : "");
1307
1308 info->AutoTunnel = AutoTunnel;
1309 AssignDomainName(&info->domain, domain);
1310 AssignDomainName(&info->keyname, keyname);
1311 mDNS_snprintf(info->b64keydata, sizeof(info->b64keydata), "%s", b64keydata);
1312
1313 if (DNSDigest_ConstructHMACKeyfromBase64(info, b64keydata) < 0)
1314 {
1315 LogMsg("mDNS_SetSecretForDomain: ERROR: Could not convert shared secret from base64: domain %##s key %##s %s",
1316 domain->c, keyname->c, LogAllOperations ? b64keydata : "");
1317 return(mStatus_BadParamErr);
1318 }
1319
1320 // Don't clear deltime until after we've ascertained that b64keydata is valid
1321 info->deltime = 0;
1322
1323 while (*p && (*p) != info) p=&(*p)->next;
1324 if (*p) return(mStatus_AlreadyRegistered);
1325
1326 // Caution: Only zero AutoTunnelHostRecord.namestorage and AutoTunnelNAT.clientContext AFTER we've determined that this is a NEW DomainAuthInfo
1327 // being added to the list. Otherwise we risk smashing our AutoTunnel host records and NATOperation that are already active and in use.
1328 info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
1329 info->AutoTunnelHostRecord.namestorage.c[0] = 0;
1330 info->AutoTunnelTarget .resrec.RecordType = kDNSRecordTypeUnregistered;
1331 info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeUnregistered;
1332 info->AutoTunnelService .resrec.RecordType = kDNSRecordTypeUnregistered;
1333 info->AutoTunnelNAT.clientContext = mDNSNULL;
1334 info->next = mDNSNULL;
1335 *p = info;
1336
1337 // Check to see if adding this new DomainAuthInfo has changed the credentials for any of our questions
1338 for (q = m->Questions; q; q=q->next)
1339 {
1340 DomainAuthInfo *newinfo = GetAuthInfoForQuestion(m, q);
1341 if (q->AuthInfo != newinfo)
1342 {
1343 debugf("mDNS_SetSecretForDomain updating q->AuthInfo from %##s to %##s for %##s (%s)",
1344 q->AuthInfo ? q->AuthInfo->domain.c : mDNSNULL,
1345 newinfo ? newinfo ->domain.c : mDNSNULL, q->qname.c, DNSTypeName(q->qtype));
1346 q->AuthInfo = newinfo;
1347 }
1348 }
1349
1350 return(mStatus_NoError);
1351 }
1352
1353 // ***************************************************************************
1354 #if COMPILER_LIKES_PRAGMA_MARK
1355 #pragma mark -
1356 #pragma mark - NAT Traversal
1357 #endif
1358
1359 mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info)
1360 {
1361 mStatus err = mStatus_NoError;
1362
1363 // send msg if we have a router and it is a private address
1364 if (!mDNSIPv4AddressIsZero(m->Router.ip.v4) && mDNSv4AddrIsRFC1918(&m->Router.ip.v4))
1365 {
1366 union { NATAddrRequest NATAddrReq; NATPortMapRequest NATPortReq; } u = { { NATMAP_VERS, NATOp_AddrRequest } } ;
1367 const mDNSu8 *end = (mDNSu8 *)&u + sizeof(NATAddrRequest);
1368
1369 if (info) // For NATOp_MapUDP and NATOp_MapTCP, fill in additional fields
1370 {
1371 mDNSu8 *p = (mDNSu8 *)&u.NATPortReq.NATReq_lease;
1372 u.NATPortReq.opcode = info->Protocol;
1373 u.NATPortReq.unused = zeroID;
1374 u.NATPortReq.intport = info->IntPort;
1375 u.NATPortReq.extport = info->RequestedPort;
1376 p[0] = (mDNSu8)((info->NATLease >> 24) & 0xFF);
1377 p[1] = (mDNSu8)((info->NATLease >> 16) & 0xFF);
1378 p[2] = (mDNSu8)((info->NATLease >> 8) & 0xFF);
1379 p[3] = (mDNSu8)( info->NATLease & 0xFF);
1380 end = (mDNSu8 *)&u + sizeof(NATPortMapRequest);
1381 }
1382
1383 err = mDNSPlatformSendUDP(m, (mDNSu8 *)&u, end, 0, &m->Router, NATPMPPort);
1384
1385 #ifdef _LEGACY_NAT_TRAVERSAL_
1386 if (mDNSIPPortIsZero(m->UPnPSOAPPort)) LNT_SendDiscoveryMsg(m);
1387 else if (info) err = LNT_MapPort(m, info);
1388 else err = LNT_GetExternalAddress(m);
1389 #endif // _LEGACY_NAT_TRAVERSAL_
1390 }
1391 return(err);
1392 }
1393
1394 mDNSlocal void RecreateNATMappings(mDNS *const m)
1395 {
1396 NATTraversalInfo *n;
1397 for (n = m->NATTraversals; n; n=n->next)
1398 {
1399 n->ExpiryTime = 0; // Mark this mapping as expired
1400 n->retryInterval = NATMAP_INIT_RETRY;
1401 n->retryPortMap = m->timenow;
1402 #ifdef _LEGACY_NAT_TRAVERSAL_
1403 if (n->tcpInfo.sock) { mDNSPlatformTCPCloseConnection(n->tcpInfo.sock); n->tcpInfo.sock = mDNSNULL; }
1404 #endif // _LEGACY_NAT_TRAVERSAL_
1405 }
1406
1407 m->NextScheduledNATOp = m->timenow; // Need to send packets immediately
1408 }
1409
1410 #ifdef _LEGACY_NAT_TRAVERSAL_
1411 mDNSlocal void ClearUPnPState(mDNS *const m)
1412 {
1413 if (m->tcpAddrInfo.sock) { mDNSPlatformTCPCloseConnection(m->tcpAddrInfo.sock); m->tcpAddrInfo.sock = mDNSNULL; }
1414 if (m->tcpDeviceInfo.sock) { mDNSPlatformTCPCloseConnection(m->tcpDeviceInfo.sock); m->tcpDeviceInfo.sock = mDNSNULL; }
1415 m->UPnPSOAPPort = m->UPnPRouterPort = zeroIPPort; // Reset UPnP ports
1416 }
1417 #else
1418 #define ClearUPnPState(X)
1419 #endif // _LEGACY_NAT_TRAVERSAL_
1420
1421 mDNSexport void natTraversalHandleAddressReply(mDNS *const m, mDNSu16 err, mDNSv4Addr ExtAddr)
1422 {
1423 if (err) LogMsg("Error getting external address %d", err);
1424 else if (!mDNSSameIPv4Address(m->ExternalAddress, ExtAddr))
1425 {
1426 LogOperation("Received external IP address %.4a from NAT", &ExtAddr);
1427 if (mDNSv4AddrIsRFC1918(&ExtAddr))
1428 LogMsg("Double NAT (external NAT gateway address %.4a is also a private RFC 1918 address)", &ExtAddr);
1429 m->ExternalAddress = ExtAddr;
1430 RecreateNATMappings(m); // Also sets NextScheduledNATOp for us
1431 }
1432
1433 if (err || mDNSIPv4AddressIsZero(ExtAddr)) m->retryIntervalGetAddr = NATMAP_INIT_RETRY * 32; // 8 seconds
1434 else m->retryIntervalGetAddr = NATMAP_MAX_RETRY_INTERVAL;
1435
1436 m->retryGetAddr = m->timenow + m->retryIntervalGetAddr;
1437 if (m->NextScheduledNATOp - m->retryIntervalGetAddr > 0)
1438 m->NextScheduledNATOp = m->retryIntervalGetAddr;
1439 }
1440
1441 // Both places that call NATSetNextRenewalTime() update m->NextScheduledNATOp correctly afterwards
1442 mDNSlocal void NATSetNextRenewalTime(mDNS *const m, NATTraversalInfo *n)
1443 {
1444 n->retryInterval = (n->ExpiryTime - m->timenow)/2;
1445 if (n->retryInterval < NATMAP_MIN_RETRY_INTERVAL) // Min retry interval is 2 seconds
1446 n->retryInterval = NATMAP_MIN_RETRY_INTERVAL;
1447 n->retryPortMap = m->timenow + n->retryInterval;
1448 }
1449
1450 // Note: When called from handleLNTPortMappingResponse() only pkt->err, pkt->extport and pkt->NATRep_lease fields are filled in
1451 mDNSexport void natTraversalHandlePortMapReply(mDNS *const m, NATTraversalInfo *n, const mDNSInterfaceID InterfaceID, mDNSu16 err, mDNSIPPort extport, mDNSu32 lease)
1452 {
1453 n->NewResult = err;
1454 if (err || lease == 0 || mDNSIPPortIsZero(extport))
1455 {
1456 LogOperation("natTraversalHandlePortMapReply: received error making port mapping error %d port %d", err, mDNSVal16(extport));
1457 n->retryInterval = NATMAP_MAX_RETRY_INTERVAL;
1458 n->retryPortMap = m->timenow + NATMAP_MAX_RETRY_INTERVAL;
1459 // No need to set m->NextScheduledNATOp here, since we're only ever extending the m->retryPortMap time
1460 if (err == NATErr_Refused) n->NewResult = mStatus_NATPortMappingDisabled;
1461 else if (err > NATErr_None && err <= NATErr_Opcode) n->NewResult = mStatus_NATPortMappingUnsupported;
1462 }
1463 else
1464 {
1465 if (lease > 999999999UL / mDNSPlatformOneSecond)
1466 lease = 999999999UL / mDNSPlatformOneSecond;
1467 n->ExpiryTime = NonZeroTime(m->timenow + lease * mDNSPlatformOneSecond);
1468
1469 if (!mDNSSameIPPort(n->RequestedPort, extport))
1470 LogOperation("natTraversalHandlePortMapReply: public port changed from %d to %d", mDNSVal16(n->RequestedPort), mDNSVal16(extport));
1471
1472 n->InterfaceID = InterfaceID;
1473 n->RequestedPort = extport;
1474
1475 LogOperation("natTraversalHandlePortMapReply %p %s Internal Port %d External Port %d", n,
1476 n->Protocol == NATOp_MapUDP ? "UDP Response" :
1477 n->Protocol == NATOp_MapTCP ? "TCP Response" : "?", mDNSVal16(n->IntPort), mDNSVal16(n->RequestedPort));
1478
1479 NATSetNextRenewalTime(m, n); // Got our port mapping; now set timer to renew it at halfway point
1480 m->NextScheduledNATOp = m->timenow; // May need to invoke client callback immediately
1481 }
1482 }
1483
1484 // Must be called with the mDNS_Lock held
1485 mDNSexport mStatus mDNS_StartNATOperation_internal(mDNS *const m, NATTraversalInfo *traversal)
1486 {
1487 NATTraversalInfo **n;
1488
1489 LogOperation("mDNS_StartNATOperation_internal %d %d %d %d",
1490 traversal->Protocol, mDNSVal16(traversal->IntPort), mDNSVal16(traversal->RequestedPort), traversal->NATLease);
1491
1492 // Note: It important that new traversal requests are appended at the *end* of the list, not prepended at the start
1493 n = &m->NATTraversals;
1494 while (*n && *n != traversal) n=&(*n)->next;
1495 if (*n) { LogMsg("Error! Tried to add a NAT traversal that's already in the active list"); return(mStatus_AlreadyRegistered); }
1496
1497 // Initialize necessary fields
1498 traversal->next = mDNSNULL;
1499 traversal->ExpiryTime = 0;
1500 traversal->retryInterval = NATMAP_INIT_RETRY;
1501 traversal->retryPortMap = m->timenow;
1502 traversal->NewResult = mStatus_NoError;
1503 traversal->ExternalAddress = onesIPv4Addr;
1504 traversal->ExternalPort = zeroIPPort;
1505 traversal->Lifetime = 0;
1506 traversal->Result = mStatus_NoError;
1507
1508 // set default lease if necessary
1509 if (!traversal->NATLease) traversal->NATLease = NATMAP_DEFAULT_LEASE;
1510
1511 #ifdef _LEGACY_NAT_TRAVERSAL_
1512 mDNSPlatformMemZero(&traversal->tcpInfo, sizeof(traversal->tcpInfo));
1513 #endif _LEGACY_NAT_TRAVERSAL_
1514
1515 if (!m->NATTraversals) // If this is our first NAT request, kick off an address request too
1516 {
1517 m->retryGetAddr = m->timenow;
1518 m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
1519 }
1520
1521 m->NextScheduledNATOp = m->timenow; // This will always trigger sending the packet ASAP, and generate client callback if necessary
1522
1523 *n = traversal; // Append new NATTraversalInfo to the end of our list
1524
1525 return(mStatus_NoError);
1526 }
1527
1528 // Must be called with the mDNS_Lock held
1529 mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *traversal)
1530 {
1531 NATTraversalInfo **ptr = &m->NATTraversals;
1532
1533 while (*ptr && *ptr != traversal) ptr=&(*ptr)->next;
1534 if (*ptr) *ptr = (*ptr)->next; // If we found it, cut this NATTraversalInfo struct from our list
1535 else
1536 {
1537 LogMsg("mDNS_StopNATOperation: NATTraversalInfo %p not found in list", traversal);
1538 return(mStatus_BadReferenceErr);
1539 }
1540
1541 LogOperation("mDNS_StopNATOperation_internal %d %d %d %d",
1542 traversal->Protocol, mDNSVal16(traversal->IntPort), mDNSVal16(traversal->RequestedPort), traversal->NATLease);
1543
1544 if (m->CurrentNATTraversal == traversal)
1545 m->CurrentNATTraversal = m->CurrentNATTraversal->next;
1546
1547 if (traversal->ExpiryTime)
1548 {
1549 traversal->NATLease = 0;
1550 traversal->retryInterval = 0;
1551 uDNS_SendNATMsg(m, traversal);
1552 }
1553 // Even if we DIDN'T make a successful UPnP mapping yet, we might still have a partially-open TCP connection we need to clean up
1554 #ifdef _LEGACY_NAT_TRAVERSAL_
1555 {
1556 mStatus err = LNT_UnmapPort(m, traversal);
1557 if (err) LogMsg("Legacy NAT Traversal - unmap request failed with error %ld", err);
1558 }
1559 #endif // _LEGACY_NAT_TRAVERSAL_
1560 return(mStatus_NoError);
1561 }
1562
1563 mDNSexport mStatus mDNS_StartNATOperation(mDNS *m, NATTraversalInfo *traversal)
1564 {
1565 mStatus status;
1566 mDNS_Lock(m);
1567 status = mDNS_StartNATOperation_internal(m, traversal);
1568 mDNS_Unlock(m);
1569 return(status);
1570 }
1571
1572 mDNSexport mStatus mDNS_StopNATOperation(mDNS *m, NATTraversalInfo *traversal)
1573 {
1574 mStatus status;
1575 mDNS_Lock(m);
1576 status = mDNS_StopNATOperation_internal(m, traversal);
1577 mDNS_Unlock(m);
1578 return(status);
1579 }
1580
1581 // ***************************************************************************
1582 #if COMPILER_LIKES_PRAGMA_MARK
1583 #pragma mark -
1584 #pragma mark - Long-Lived Queries
1585 #endif
1586
1587 // Lock must be held -- otherwise m->timenow is undefined
1588 mDNSlocal void StartLLQPolling(mDNS *const m, DNSQuestion *q)
1589 {
1590 LogOperation("StartLLQPolling: %##s", q->qname.c);
1591 q->state = LLQ_Poll;
1592 q->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
1593 // We want to send our poll query ASAP, but the "+ 1" is because if we set the time to now,
1594 // we risk causing spurious "SendQueries didn't send all its queries" log messages
1595 q->LastQTime = m->timenow - q->ThisQInterval + 1;
1596 SetNextQueryTime(m, q);
1597 }
1598
1599 mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, const DNSQuestion *const question, const LLQOptData *const data, mDNSBool includeQuestion)
1600 {
1601 AuthRecord rr;
1602 ResourceRecord *opt = &rr.resrec;
1603 rdataOPT *optRD;
1604
1605 //!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section
1606 if (includeQuestion)
1607 {
1608 ptr = putQuestion(msg, ptr, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
1609 if (!ptr) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL; }
1610 }
1611 // locate OptRR if it exists, set pointer to end
1612 // !!!KRS implement me
1613
1614 // format opt rr (fields not specified are zero-valued)
1615 mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
1616 opt->rdlength = LLQ_OPT_RDLEN;
1617 opt->rdestimate = LLQ_OPT_RDLEN;
1618
1619 optRD = &rr.resrec.rdata->u.opt;
1620 optRD->opt = kDNSOpt_LLQ;
1621 optRD->optlen = LLQ_OPTLEN;
1622 optRD->OptData.llq = *data;
1623 ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.numAdditionals, opt, 0);
1624 if (!ptr) { LogMsg("ERROR: putLLQ - PutResourceRecordTTLJumbo"); return mDNSNULL; }
1625
1626 return ptr;
1627 }
1628
1629 // Normally we'd just request event packets be sent directly to m->LLQNAT.ExternalPort, except...
1630 // with LLQs over TLS/TCP we're doing a weird thing where instead of requesting packets be sent to ExternalAddress:ExternalPort
1631 // we're requesting that packets be sent to ExternalPort, but at the source address of our outgoing TCP connection.
1632 // Normally, after going through the NAT gateway, the source address of our outgoing TCP connection is the same as ExternalAddress,
1633 // so this is fine, except when the TCP connection ends up going over a VPN tunnel instead.
1634 // To work around this, if we find that the source address for our TCP connection is not a private address, we tell the Dot Mac
1635 // LLQ server to send events to us directly at port 5353 on that address, instead of at our mapped external NAT port.
1636
1637 mDNSlocal mDNSu16 GetLLQEventPort(const mDNS *const m, const mDNSAddr *const dst)
1638 {
1639 mDNSAddr src;
1640 mDNSPlatformSourceAddrForDest(&src, dst);
1641 //LogMsg("GetLLQEventPort: src %#a for dst %#a (%d)", &src, dst, mDNSv4AddrIsRFC1918(&src.ip.v4) ? mDNSVal16(m->LLQNAT.ExternalPort) : 0);
1642 return(mDNSv4AddrIsRFC1918(&src.ip.v4) ? mDNSVal16(m->LLQNAT.ExternalPort) : mDNSVal16(MulticastDNSPort));
1643 }
1644
1645 // Normally called with llq set.
1646 // May be called with llq NULL, when retransmitting a lost Challenge Response
1647 mDNSlocal void sendChallengeResponse(mDNS *const m, DNSQuestion *const q, const LLQOptData *llq)
1648 {
1649 mDNSu8 *responsePtr = m->omsg.data;
1650 LLQOptData llqBuf;
1651
1652 if (q->ntries++ == kLLQ_MAX_TRIES)
1653 {
1654 LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s", kLLQ_MAX_TRIES, q->qname.c);
1655 StartLLQPolling(m,q);
1656 return;
1657 }
1658
1659 if (!llq) // Retransmission: need to make a new LLQOptData
1660 {
1661 llqBuf.vers = kLLQ_Vers;
1662 llqBuf.llqOp = kLLQOp_Setup;
1663 llqBuf.err = LLQErr_NoError; // Don't need to tell server UDP notification port when sending over UDP
1664 llqBuf.id = q->id;
1665 llqBuf.llqlease = q->origLease;
1666 llq = &llqBuf;
1667 }
1668
1669 q->LastQTime = m->timenow;
1670 q->ThisQInterval = q->tcp ? 0 : (kLLQ_INIT_RESEND * q->ntries * mDNSPlatformOneSecond); // If using TCP, don't need to retransmit
1671 SetNextQueryTime(m, q);
1672
1673 // To simulate loss of challenge response packet, uncomment line below
1674 //if (q->ntries == 1) return;
1675
1676 InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
1677 responsePtr = putQuestion(&m->omsg, responsePtr, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
1678 if (responsePtr) responsePtr = putLLQ(&m->omsg, responsePtr, q, llq, mDNSfalse);
1679 if (responsePtr) mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, q->AuthInfo);
1680 else StartLLQPolling(m,q);
1681 }
1682
1683 mDNSlocal void SetLLQTimer(mDNS *const m, DNSQuestion *const q, const LLQOptData *const llq)
1684 {
1685 mDNSs32 lease = (mDNSs32)llq->llqlease * mDNSPlatformOneSecond;
1686 q->origLease = llq->llqlease;
1687 q->LastQTime = m->timenow;
1688 q->expire = m->timenow + lease;
1689 q->ThisQInterval = lease/2 + mDNSRandom(lease/10);
1690 SetNextQueryTime(m, q);
1691 }
1692
1693 mDNSlocal void recvSetupResponse(mDNS *const m, mDNSu8 rcode, DNSQuestion *const q, const LLQOptData *const llq)
1694 {
1695 if (rcode && rcode != kDNSFlag1_RC_NXDomain)
1696 { LogMsg("ERROR: recvSetupResponse %##s - rcode && rcode != kDNSFlag1_RC_NXDomain", q->qname.c); return; }
1697
1698 if (llq->llqOp != kLLQOp_Setup)
1699 { LogMsg("ERROR: recvSetupResponse %##s - bad op %d", q->qname.c, llq->llqOp); return; }
1700
1701 if (llq->vers != kLLQ_Vers)
1702 { LogMsg("ERROR: recvSetupResponse %##s - bad vers %d", q->qname.c, llq->vers); return; }
1703
1704 if (q->state == LLQ_InitialRequest)
1705 {
1706 //LogOperation("Got LLQ_InitialRequest");
1707
1708 if (llq->err) { LogMsg("recvSetupResponse - received llq->err %d from server", llq->err); StartLLQPolling(m,q); return; }
1709
1710 if (q->origLease != llq->llqlease)
1711 debugf("recvSetupResponse: requested lease %lu, granted lease %lu", q->origLease, llq->llqlease);
1712
1713 // cache expiration in case we go to sleep before finishing setup
1714 q->origLease = llq->llqlease;
1715 q->expire = m->timenow + ((mDNSs32)llq->llqlease * mDNSPlatformOneSecond);
1716
1717 // update state
1718 q->state = LLQ_SecondaryRequest;
1719 q->id = llq->id;
1720 q->ntries = 0; // first attempt to send response
1721 sendChallengeResponse(m, q, llq);
1722 }
1723 else if (q->state == LLQ_SecondaryRequest)
1724 {
1725 //LogOperation("Got LLQ_SecondaryRequest");
1726
1727 // Fix this immediately if not sooner. Copy the id from the LLQOptData into our DNSQuestion struct. This is only
1728 // an issue for private LLQs, because we skip parts 2 and 3 of the handshake. This is related to a bigger
1729 // problem of the current implementation of TCP LLQ setup: we're not handling state transitions correctly
1730 // if the server sends back SERVFULL or STATIC.
1731 if (q->AuthInfo)
1732 {
1733 LogOperation("Private LLQ_SecondaryRequest; copying id %08X%08X", llq->id.l[0], llq->id.l[1]);
1734 q->id = llq->id;
1735 }
1736
1737 if (llq->err) { LogMsg("ERROR: recvSetupResponse %##s code %d from server", q->qname.c, llq->err); StartLLQPolling(m,q); return; }
1738 if (!mDNSSameOpaque64(&q->id, &llq->id))
1739 { LogMsg("recvSetupResponse - ID changed. discarding"); return; } // this can happen rarely (on packet loss + reordering)
1740 q->state = LLQ_Established;
1741 q->ntries = 0;
1742 SetLLQTimer(m, q, llq);
1743 }
1744 }
1745
1746 mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport)
1747 {
1748 DNSQuestion pktQ, *q;
1749 if (msg->h.numQuestions && getQuestion(msg, msg->data, end, 0, &pktQ))
1750 {
1751 const rdataOPT *opt = GetLLQOptData(m, msg, end);
1752
1753 for (q = m->Questions; q; q = q->next)
1754 {
1755 if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->qtype == pktQ.qtype && q->qnamehash == pktQ.qnamehash && SameDomainName(&q->qname, &pktQ.qname))
1756 {
1757 debugf("uDNS_recvLLQResponse found %##s (%s) %d %#a %#a %X %X %X %X %d",
1758 q->qname.c, DNSTypeName(q->qtype), q->state, srcaddr, &q->servAddr,
1759 opt->OptData.llq.id.l[0], opt->OptData.llq.id.l[1], q->id.l[0], q->id.l[1], opt->OptData.llq.llqOp);
1760 if (q->state == LLQ_Poll)
1761 {
1762 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
1763 LogOperation("uDNS_recvLLQResponse got poll response; moving to LLQ_InitialRequest for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
1764 q->state = LLQ_InitialRequest;
1765 q->servPort = zeroIPPort; // Clear servPort so that startLLQHandshake will retry the GetZoneData processing
1766 q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10); // Retry LLQ setup in approx 15 minutes
1767 q->LastQTime = m->timenow;
1768 SetNextQueryTime(m, q);
1769 return uDNS_LLQ_Entire; // uDNS_LLQ_Entire means flush stale records; assume a large effective TTL
1770 }
1771 else if (opt && q->state == LLQ_Established && opt->OptData.llq.llqOp == kLLQOp_Event && mDNSSameOpaque64(&opt->OptData.llq.id, &q->id))
1772 {
1773 mDNSu8 *ackEnd;
1774 if (q->ThisQInterval < MAX_UCAST_POLL_INTERVAL) q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
1775 //debugf("Sending LLQ ack for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
1776 InitializeDNSMessage(&m->omsg.h, msg->h.id, ResponseFlags);
1777 ackEnd = putLLQ(&m->omsg, m->omsg.data, mDNSNULL, &opt->OptData.llq, mDNSfalse);
1778 if (ackEnd) mDNSSendDNSMessage(m, &m->omsg, ackEnd, mDNSInterface_Any, srcaddr, srcport, mDNSNULL, mDNSNULL);
1779 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
1780 return uDNS_LLQ_Events;
1781 }
1782 if (opt && mDNSSameOpaque16(msg->h.id, q->TargetQID))
1783 {
1784 if (q->state == LLQ_Established && opt->OptData.llq.llqOp == kLLQOp_Refresh && mDNSSameOpaque64(&opt->OptData.llq.id, &q->id) && msg->h.numAdditionals && !msg->h.numAnswers)
1785 {
1786 if (opt->OptData.llq.err != LLQErr_NoError) LogMsg("recvRefreshReply: received error %d from server", opt->OptData.llq.err);
1787 else
1788 {
1789 //LogOperation("Received refresh confirmation ntries %d for %##s (%s)", q->ntries, q->qname.c, DNSTypeName(q->qtype));
1790 GrantCacheExtensions(m, q, opt->OptData.llq.llqlease);
1791 SetLLQTimer(m, q, &opt->OptData.llq);
1792 q->ntries = 0;
1793 }
1794 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
1795 return uDNS_LLQ_Ignore;
1796 }
1797 if (q->state < LLQ_Established && mDNSSameAddress(srcaddr, &q->servAddr))
1798 {
1799 LLQ_State oldstate = q->state;
1800 recvSetupResponse(m, msg->h.flags.b[1] & kDNSFlag1_RC_Mask, q, &opt->OptData.llq);
1801 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
1802 // We have a protocol anomaly here in the LLQ definition.
1803 // Both the challenge packet from the server and the ack+answers packet have opt->OptData.llq.llqOp == kLLQOp_Setup.
1804 // However, we need to treat them differently:
1805 // The challenge packet has no answers in it, and tells us nothing about whether our cache entries
1806 // are still valid, so this packet should not cause us to do anything that messes with our cache.
1807 // The ack+answers packet gives us the whole truth, so we should handle it by updating our cache
1808 // to match the answers in the packet, and only the answers in the packet.
1809 return (oldstate == LLQ_SecondaryRequest ? uDNS_LLQ_Entire : uDNS_LLQ_Ignore);
1810 }
1811 }
1812 }
1813 }
1814 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
1815 }
1816 return uDNS_LLQ_Not;
1817 }
1818
1819 // Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
1820 struct TCPSocket_struct { TCPSocketFlags flags; /* ... */ };
1821
1822 // tcpCallback is called to handle events (e.g. connection opening and data reception) on TCP connections for
1823 // Private DNS operations -- private queries, private LLQs, private record updates and private service updates
1824 mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err)
1825 {
1826 tcpInfo_t *tcpInfo = (tcpInfo_t *)context;
1827 mDNSBool closed = mDNSfalse;
1828 mDNSu8 *end;
1829 mDNS *m = tcpInfo->m;
1830
1831 tcpInfo_t **backpointer =
1832 tcpInfo->question ? &tcpInfo->question->tcp :
1833 tcpInfo->srs ? &tcpInfo->srs->tcp :
1834 tcpInfo->rr ? &tcpInfo->rr->tcp : mDNSNULL;
1835 if (!backpointer) LogMsg("tcpCallback: Purpose of connection unidentified");
1836 else if (*backpointer != tcpInfo)
1837 LogMsg("tcpCallback: %d backpointer %p incorrect tcpInfo %p question %p srs %p rr %p",
1838 mDNSPlatformTCPGetFD(tcpInfo->sock), *backpointer, tcpInfo, tcpInfo->question, tcpInfo->srs, tcpInfo->rr);
1839
1840 if (err) goto exit;
1841
1842 if (ConnectionEstablished)
1843 {
1844 DomainAuthInfo *AuthInfo;
1845 // connection is established - send the message
1846 if (tcpInfo->question && tcpInfo->question->LongLived && tcpInfo->question->state == LLQ_Established)
1847 {
1848 //LogMsg("tcpCallback calling sendLLQRefresh %##s (%s)", tcpInfo->question->qname.c, DNSTypeName(tcpInfo->question->qtype));
1849 mDNS_Lock(m);
1850 sendLLQRefresh(m, tcpInfo->question, tcpInfo->question->origLease);
1851 mDNS_Unlock(m);
1852 return;
1853 }
1854 else if (tcpInfo->question && tcpInfo->question->LongLived && tcpInfo->question->state != LLQ_Poll && !mDNSIPPortIsZero(m->LLQNAT.ExternalPort))
1855 {
1856 // Notes:
1857 // If we have a NAT port mapping, ExternalPort is the external port
1858 // If we have a routable address so we don't need a port mapping, ExternalPort is the same as our own internal port
1859 // If we need a NAT port mapping but can't get one, then ExternalPort is zero
1860 LLQOptData llqData; // set llq rdata
1861 llqData.vers = kLLQ_Vers;
1862 llqData.llqOp = kLLQOp_Setup;
1863 llqData.err = GetLLQEventPort(m, &tcpInfo->Addr); // We're using TCP; tell server what UDP port to send notifications to
1864 LogOperation("tcpCallback: eventPort %d", llqData.err);
1865 llqData.id = zeroOpaque64;
1866 llqData.llqlease = kLLQ_DefLease;
1867 InitializeDNSMessage(&tcpInfo->request.h, tcpInfo->question->TargetQID, uQueryFlags);
1868 end = putLLQ(&tcpInfo->request, tcpInfo->request.data, tcpInfo->question, &llqData, mDNStrue);
1869 if (!end) { LogMsg("ERROR: tcpCallback - putLLQ"); err = mStatus_UnknownErr; goto exit; }
1870 }
1871 else if (tcpInfo->question)
1872 {
1873 DNSQuestion *q = tcpInfo->question;
1874 InitializeDNSMessage(&tcpInfo->request.h, q->TargetQID, uQueryFlags);
1875 end = putQuestion(&tcpInfo->request, tcpInfo->request.data, tcpInfo->request.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
1876 }
1877 else
1878 end = ((mDNSu8*) &tcpInfo->request) + tcpInfo->requestLen;
1879
1880 // Defensive coding for <rdar://problem/5546824> Crash in mDNSResponder at GetAuthInfoForName_internal + 366
1881 // Don't know yet what's causing this, but at least we can be cautious and try to avoid crashing if we find our pointers in an unexpected state
1882 if (tcpInfo->srs && tcpInfo->srs->RR_SRV.resrec.name != &tcpInfo->srs->RR_SRV.namestorage)
1883 LogMsg("tcpCallback: ERROR: tcpInfo->srs->RR_SRV.resrec.name %p != &tcpInfo->srs->RR_SRV.namestorage %p",
1884 tcpInfo->srs->RR_SRV.resrec.name, &tcpInfo->srs->RR_SRV.namestorage);
1885 if (tcpInfo->rr && tcpInfo->rr->resrec.name != &tcpInfo->rr->namestorage)
1886 LogMsg("tcpCallback: ERROR: tcpInfo->rr->resrec.name %p != &tcpInfo->rr->namestorage %p",
1887 tcpInfo->rr->resrec.name, &tcpInfo->rr->namestorage);
1888 if (tcpInfo->srs && tcpInfo->srs->RR_SRV.resrec.name != &tcpInfo->srs->RR_SRV.namestorage) return;
1889 if (tcpInfo->rr && tcpInfo->rr-> resrec.name != &tcpInfo->rr-> namestorage) return;
1890
1891 AuthInfo = tcpInfo->question ? tcpInfo->question->AuthInfo :
1892 tcpInfo->srs ? GetAuthInfoForName(m, tcpInfo->srs->RR_SRV.resrec.name) :
1893 tcpInfo->rr ? GetAuthInfoForName(m, tcpInfo->rr->resrec.name) : mDNSNULL;
1894
1895 err = mDNSSendDNSMessage(m, &tcpInfo->request, end, mDNSInterface_Any, &tcpInfo->Addr, tcpInfo->Port, sock, AuthInfo);
1896
1897 if (err) { debugf("ERROR: tcpCallback: mDNSSendDNSMessage - %ld", err); err = mStatus_UnknownErr; goto exit; }
1898
1899 // Record time we sent this question
1900 if (tcpInfo->question)
1901 {
1902 mDNS_Lock(m);
1903 tcpInfo->question->LastQTime = m->timenow;
1904 tcpInfo->question->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
1905 SetNextQueryTime(m, tcpInfo->question);
1906 mDNS_Unlock(m);
1907 }
1908 }
1909 else
1910 {
1911 long n;
1912 if (tcpInfo->nread < 2) // First read the two-byte length preceeding the DNS message
1913 {
1914 mDNSu8 *lenptr = (mDNSu8 *)&tcpInfo->replylen;
1915 n = mDNSPlatformReadTCP(sock, lenptr + tcpInfo->nread, 2 - tcpInfo->nread, &closed);
1916 if (n < 0) { LogMsg("ERROR:tcpCallback - attempt to read message length failed (%d)", n); err = mStatus_ConnFailed; goto exit; }
1917 else if (closed)
1918 {
1919 // It's perfectly fine for this socket to close after the first reply. The server might
1920 // be sending gratuitous replies using UDP and doesn't have a need to leave the TCP socket open.
1921 // We'll only log this event if we've never received a reply before.
1922 // BIND 9 appears to close an idle connection after 30 seconds.
1923 if (tcpInfo->numReplies == 0) LogMsg("ERROR: socket closed prematurely %d", tcpInfo->nread);
1924 err = mStatus_ConnFailed;
1925 goto exit;
1926 }
1927
1928 tcpInfo->nread += n;
1929 if (tcpInfo->nread < 2) goto exit;
1930
1931 tcpInfo->replylen = (mDNSu16)((mDNSu16)lenptr[0] << 8 | lenptr[1]);
1932 if (tcpInfo->replylen < sizeof(DNSMessageHeader))
1933 { LogMsg("ERROR: tcpCallback - length too short (%d bytes)", tcpInfo->replylen); err = mStatus_UnknownErr; goto exit; }
1934
1935 tcpInfo->reply = mDNSPlatformMemAllocate(tcpInfo->replylen);
1936 if (!tcpInfo->reply) { LogMsg("ERROR: tcpCallback - malloc failed"); err = mStatus_NoMemoryErr; goto exit; }
1937 }
1938
1939 n = mDNSPlatformReadTCP(sock, ((char *)tcpInfo->reply) + (tcpInfo->nread - 2), tcpInfo->replylen - (tcpInfo->nread - 2), &closed);
1940
1941 if (n < 0) { LogMsg("ERROR: tcpCallback - read returned %d", n); err = mStatus_ConnFailed; goto exit; }
1942 else if (closed) { LogMsg("ERROR: socket closed prematurely %d", tcpInfo->nread); err = mStatus_ConnFailed; goto exit; }
1943
1944 tcpInfo->nread += n;
1945
1946 if ((tcpInfo->nread - 2) == tcpInfo->replylen)
1947 {
1948 AuthRecord *rr = tcpInfo->rr;
1949 DNSMessage *reply = tcpInfo->reply;
1950 mDNSu8 *end = (mDNSu8 *)tcpInfo->reply + tcpInfo->replylen;
1951 mDNSAddr Addr = tcpInfo->Addr;
1952 mDNSIPPort Port = tcpInfo->Port;
1953 tcpInfo->numReplies++;
1954 tcpInfo->reply = mDNSNULL; // Detach reply buffer from tcpInfo_t, to make sure client callback can't cause it to be disposed
1955 tcpInfo->nread = 0;
1956 tcpInfo->replylen = 0;
1957
1958 // If we're going to dispose this connection, do it FIRST, before calling client callback
1959 if (!tcpInfo->question || !tcpInfo->question->LongLived) { *backpointer = mDNSNULL; DisposeTCPConn(tcpInfo); }
1960
1961 if (rr && rr->resrec.RecordType == kDNSRecordTypeDeregistering)
1962 {
1963 mDNS_Lock(m);
1964 LogOperation("tcpCallback: CompleteDeregistration %s", ARDisplayString(m, rr));
1965 CompleteDeregistration(m, rr); // Don't touch rr after this
1966 mDNS_Unlock(m);
1967 }
1968 else
1969 mDNSCoreReceive(m, reply, end, &Addr, Port, (sock->flags & kTCPSocketFlags_UseTLS) ? (mDNSAddr *)1 : mDNSNULL, zeroIPPort, 0);
1970 // USE CAUTION HERE: Invoking mDNSCoreReceive may have caused the environment to change, including canceling this operation itself
1971
1972 mDNSPlatformMemFree(reply);
1973 return;
1974 }
1975 }
1976
1977 exit:
1978
1979 if (err)
1980 {
1981 // Clear client backpointer FIRST -- that way if one of the callbacks cancels its operation
1982 // we won't end up double-disposing our tcpInfo_t
1983 *backpointer = mDNSNULL;
1984
1985 mDNS_Lock(m); // Need to grab the lock to get m->timenow
1986
1987 if (tcpInfo->question)
1988 {
1989 DNSQuestion *q = tcpInfo->question;
1990 if (q->ThisQInterval == 0 || q->LastQTime + q->ThisQInterval - m->timenow > MAX_UCAST_POLL_INTERVAL)
1991 {
1992 q->LastQTime = m->timenow;
1993 q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
1994 SetNextQueryTime(m, q);
1995 }
1996 // ConnFailed is actually okay. It just means that the server closed the connection but the LLQ is still okay.
1997 // If the error isn't ConnFailed, then the LLQ is in bad shape.
1998 if (err != mStatus_ConnFailed) StartLLQPolling(m, tcpInfo->question);
1999 }
2000
2001 if (tcpInfo->rr) SetRecordRetry(m, tcpInfo->rr, mStatus_NoError);
2002
2003 if (tcpInfo->srs) SetRecordRetry(m, &tcpInfo->srs->RR_SRV, mStatus_NoError);
2004
2005 mDNS_Unlock(m);
2006
2007 DisposeTCPConn(tcpInfo);
2008 }
2009 }
2010
2011 mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
2012 TCPSocketFlags flags, const mDNSAddr *const Addr, const mDNSIPPort Port,
2013 DNSQuestion *const question, ServiceRecordSet *const srs, AuthRecord *const rr)
2014 {
2015 mStatus err;
2016 mDNSIPPort srcport = zeroIPPort;
2017 tcpInfo_t *info = (tcpInfo_t *)mDNSPlatformMemAllocate(sizeof(tcpInfo_t));
2018 if (!info) { LogMsg("ERROR: MakeTCP - memallocate failed"); return(mDNSNULL); }
2019
2020 mDNSPlatformMemZero(info, sizeof(tcpInfo_t));
2021 info->m = m;
2022 if (msg)
2023 {
2024 info->request = *msg;
2025 info->requestLen = (int) (end - ((mDNSu8*)msg));
2026 }
2027 info->question = question;
2028 info->srs = srs;
2029 info->rr = rr;
2030 info->Addr = *Addr;
2031 info->Port = Port;
2032
2033 info->sock = mDNSPlatformTCPSocket(m, flags, &srcport);
2034 if (!info->sock) { LogMsg("SendServiceRegistration: uanble to create TCP socket"); mDNSPlatformMemFree(info); return(mDNSNULL); }
2035 err = mDNSPlatformTCPConnect(info->sock, Addr, Port, 0, tcpCallback, info);
2036
2037 // Probably suboptimal here.
2038 // Instead of returning mDNSNULL here on failure, we should probably invoke the callback with an error code.
2039 // That way clients can put all the error handling and retry/recovery code in one place,
2040 // instead of having to handle immediate errors in one place and async errors in another.
2041 // Also: "err == mStatus_ConnEstablished" probably never happens.
2042
2043 // Don't need to log "connection failed" in customer builds -- it happens quite often during sleep, wake, configuration changes, etc.
2044 if (err == mStatus_ConnEstablished) { tcpCallback(info->sock, info, mDNStrue, mStatus_NoError); }
2045 else if (err != mStatus_ConnPending ) { LogOperation("MakeTCPConnection: connection failed"); mDNSPlatformMemFree(info); return(mDNSNULL); }
2046 return(info);
2047 }
2048
2049 mDNSexport void DisposeTCPConn(struct tcpInfo_t *tcp)
2050 {
2051 mDNSPlatformTCPCloseConnection(tcp->sock);
2052 if (tcp->reply) mDNSPlatformMemFree(tcp->reply);
2053 mDNSPlatformMemFree(tcp);
2054 }
2055
2056 // Lock must be held
2057 mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q)
2058 {
2059 if (mDNSIPv4AddressIsOnes(m->LLQNAT.ExternalAddress))
2060 {
2061 LogOperation("startLLQHandshake: waiting for NAT status for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
2062 q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10); // Retry in approx 15 minutes
2063 q->LastQTime = m->timenow;
2064 SetNextQueryTime(m, q);
2065 return;
2066 }
2067
2068 if (mDNSIPPortIsZero(m->LLQNAT.ExternalPort))
2069 {
2070 LogOperation("startLLQHandshake: Cannot receive inbound packets; will poll for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
2071 StartLLQPolling(m, q);
2072 return;
2073 }
2074
2075 if (mDNSIPPortIsZero(q->servPort))
2076 {
2077 LogOperation("startLLQHandshake: StartGetZoneData for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
2078 q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10); // Retry in approx 15 minutes
2079 q->LastQTime = m->timenow;
2080 SetNextQueryTime(m, q);
2081 q->servAddr = zeroAddr;
2082 q->servPort = zeroIPPort;
2083 if (q->nta) CancelGetZoneData(m, q->nta);
2084 q->nta = StartGetZoneData(m, &q->qname, ZoneServiceLLQ, LLQGotZoneData, q);
2085 return;
2086 }
2087
2088 if (q->AuthInfo)
2089 {
2090 if (q->tcp) LogOperation("startLLQHandshake: Disposing existing TCP connection for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
2091 if (q->tcp) DisposeTCPConn(q->tcp);
2092 q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, q, mDNSNULL, mDNSNULL);
2093 if (!q->tcp)
2094 q->ThisQInterval = mDNSPlatformOneSecond * 5; // If TCP failed (transient networking glitch) try again in five seconds
2095 else
2096 {
2097 q->state = LLQ_SecondaryRequest; // Right now, for private DNS, we skip the four-way LLQ handshake
2098 q->origLease = kLLQ_DefLease;
2099 q->ThisQInterval = 0;
2100 }
2101 q->LastQTime = m->timenow;
2102 SetNextQueryTime(m, q);
2103 }
2104 else
2105 {
2106 LogOperation("startLLQHandshake m->AdvertisedV4 %#a%s Server %#a:%d%s %##s (%s)",
2107 &m->AdvertisedV4, mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) ? " (RFC 1918)" : "",
2108 &q->servAddr, mDNSVal16(q->servPort), mDNSAddrIsRFC1918(&q->servAddr) ? " (RFC 1918)" : "",
2109 q->qname.c, DNSTypeName(q->qtype));
2110
2111 if (q->ntries++ >= kLLQ_MAX_TRIES)
2112 {
2113 LogMsg("startLLQHandshake: %d failed attempts for LLQ %##s Polling.", kLLQ_MAX_TRIES, q->qname.c);
2114 StartLLQPolling(m, q);
2115 }
2116 else
2117 {
2118 mDNSu8 *end;
2119 LLQOptData llqData;
2120
2121 // set llq rdata
2122 llqData.vers = kLLQ_Vers;
2123 llqData.llqOp = kLLQOp_Setup;
2124 llqData.err = LLQErr_NoError; // Don't need to tell server UDP notification port when sending over UDP
2125 llqData.id = zeroOpaque64;
2126 llqData.llqlease = kLLQ_DefLease;
2127
2128 InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
2129 end = putLLQ(&m->omsg, m->omsg.data, q, &llqData, mDNStrue);
2130 if (!end) { LogMsg("ERROR: startLLQHandshake - putLLQ"); StartLLQPolling(m,q); return; }
2131
2132 mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, &q->servAddr, q->servPort, mDNSNULL, mDNSNULL);
2133
2134 // update question state
2135 q->state = LLQ_InitialRequest;
2136 q->origLease = kLLQ_DefLease;
2137 q->ThisQInterval = (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
2138 q->LastQTime = m->timenow;
2139 SetNextQueryTime(m, q);
2140 }
2141 }
2142 }
2143
2144 mDNSexport const domainname *GetServiceTarget(mDNS *m, ServiceRecordSet *srs)
2145 {
2146 LogOperation("GetServiceTarget %##s", srs->RR_SRV.resrec.name->c);
2147
2148 if (!srs->RR_SRV.AutoTarget) // If not automatically tracking this host's current name, just return the existing target
2149 return(&srs->RR_SRV.resrec.rdata->u.srv.target);
2150 else
2151 {
2152 #if APPLE_OSX_mDNSResponder
2153 DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name);
2154 if (AuthInfo && AuthInfo->AutoTunnel)
2155 {
2156 // If this AutoTunnel is not yet active, start it now (which entails activating its NAT Traversal request,
2157 // which will subsequently advertise the appropriate records when the NAT Traversal returns a result)
2158 if (!AuthInfo->AutoTunnelNAT.clientContext && m->AutoTunnelHostAddr.b[0])
2159 SetupLocalAutoTunnelInterface_internal(m);
2160 if (AuthInfo->AutoTunnelHostRecord.namestorage.c[0] == 0) return(mDNSNULL);
2161 return(&AuthInfo->AutoTunnelHostRecord.namestorage);
2162 }
2163 else
2164 #endif APPLE_OSX_mDNSResponder
2165 {
2166 const int srvcount = CountLabels(srs->RR_SRV.resrec.name);
2167 HostnameInfo *besthi = mDNSNULL, *hi;
2168 int best = 0;
2169 for (hi = m->Hostnames; hi; hi = hi->next)
2170 if (hi->arv4.state == regState_Registered || hi->arv4.state == regState_Refresh ||
2171 hi->arv6.state == regState_Registered || hi->arv6.state == regState_Refresh)
2172 {
2173 int x, hostcount = CountLabels(&hi->fqdn);
2174 for (x = hostcount < srvcount ? hostcount : srvcount; x > 0 && x > best; x--)
2175 if (SameDomainName(SkipLeadingLabels(srs->RR_SRV.resrec.name, srvcount - x), SkipLeadingLabels(&hi->fqdn, hostcount - x)))
2176 { best = x; besthi = hi; }
2177 }
2178
2179 if (besthi) return(&besthi->fqdn);
2180 }
2181 if (m->StaticHostname.c[0]) return(&m->StaticHostname);
2182 return(mDNSNULL);
2183 }
2184 }
2185
2186 // Called with lock held
2187 mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs)
2188 {
2189 mDNSu8 *ptr = m->omsg.data;
2190 mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
2191 mDNSOpaque16 id;
2192 mStatus err = mStatus_NoError;
2193 const domainname *target;
2194 mDNSu32 i;
2195
2196 if (m->mDNS_busy != m->mDNS_reentrancy+1)
2197 LogMsg("SendServiceRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
2198
2199 if (mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4)) // Don't know our UpdateServer yet
2200 {
2201 srs->RR_SRV.LastAPTime = m->timenow;
2202 if (srs->RR_SRV.ThisAPInterval < mDNSPlatformOneSecond * 5)
2203 srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5;
2204 return;
2205 }
2206
2207 if (srs->state == regState_Registered) srs->state = regState_Refresh;
2208
2209 id = mDNS_NewMessageID(m);
2210 InitializeDNSMessage(&m->omsg.h, id, UpdateReqFlags);
2211
2212 // setup resource records
2213 SetNewRData(&srs->RR_PTR.resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash
2214 SetNewRData(&srs->RR_TXT.resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash
2215
2216 // replace port w/ NAT mapping if necessary
2217 if (srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP && !mDNSIPPortIsZero(srs->NATinfo.ExternalPort))
2218 srs->RR_SRV.resrec.rdata->u.srv.port = srs->NATinfo.ExternalPort;
2219
2220 // construct update packet
2221 // set zone
2222 ptr = putZone(&m->omsg, ptr, end, &srs->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
2223 if (!ptr) { err = mStatus_UnknownErr; goto exit; }
2224
2225 if (srs->TestForSelfConflict)
2226 {
2227 // update w/ prereq that SRV already exist to make sure previous registration was ours, and delete any stale TXT records
2228 if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numPrereqs, &srs->RR_SRV.resrec, 0))) { err = mStatus_UnknownErr; goto exit; }
2229 if (!(ptr = putDeleteRRSet(&m->omsg, ptr, srs->RR_TXT.resrec.name, srs->RR_TXT.resrec.rrtype))) { err = mStatus_UnknownErr; goto exit; }
2230 }
2231
2232 else if (srs->state != regState_Refresh && srs->state != regState_UpdatePending)
2233 {
2234 // use SRV name for prereq
2235 //ptr = putPrereqNameNotInUse(srs->RR_SRV.resrec.name, &m->omsg, ptr, end);
2236
2237 // For now, until we implement RFC 4701 (DHCID RR) to detect whether an existing record is someone else using the name, or just a
2238 // stale echo of our own previous registration before we changed our host name, we just overwrite whatever may have already been there
2239 ptr = putDeleteRRSet(&m->omsg, ptr, srs->RR_SRV.resrec.name, kDNSQType_ANY);
2240 if (!ptr) { err = mStatus_UnknownErr; goto exit; }
2241 }
2242
2243 //!!!KRS Need to do bounds checking and use TCP if it won't fit!!!
2244 if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_PTR.resrec, srs->RR_PTR.resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
2245
2246 for (i = 0; i < srs->NumSubTypes; i++)
2247 if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->SubTypes[i].resrec, srs->SubTypes[i].resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
2248
2249 if (srs->state == regState_UpdatePending) // we're updating the txt record
2250 {
2251 AuthRecord *txt = &srs->RR_TXT;
2252 // delete old RData
2253 SetNewRData(&txt->resrec, txt->OrigRData, txt->OrigRDLen);
2254 if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->RR_TXT.resrec))) { err = mStatus_UnknownErr; goto exit; } // delete old rdata
2255
2256 // add new RData
2257 SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen);
2258 if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
2259 }
2260 else
2261 if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
2262
2263 target = GetServiceTarget(m, srs);
2264 if (!target || target->c[0] == 0)
2265 {
2266 LogOperation("SendServiceRegistration - no target for %##s", srs->RR_SRV.resrec.name->c);
2267 srs->state = regState_NoTarget;
2268 return;
2269 }
2270
2271 if (!SameDomainName(target, &srs->RR_SRV.resrec.rdata->u.srv.target))
2272 {
2273 AssignDomainName(&srs->RR_SRV.resrec.rdata->u.srv.target, target);
2274 SetNewRData(&srs->RR_SRV.resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash
2275 }
2276
2277 ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_SRV.resrec, srs->RR_SRV.resrec.rroriginalttl);
2278 if (!ptr) { err = mStatus_UnknownErr; goto exit; }
2279
2280 if (srs->srs_uselease)
2281 { ptr = putUpdateLease(&m->omsg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) { err = mStatus_UnknownErr; goto exit; } }
2282
2283 if (srs->state != regState_Refresh && srs->state != regState_DeregDeferred && srs->state != regState_UpdatePending)
2284 srs->state = regState_Pending;
2285
2286 srs->id = id;
2287
2288 if (srs->Private)
2289 {
2290 if (srs->tcp) LogOperation("SendServiceRegistration: Disposing existing TCP connection for %s", ARDisplayString(m, &srs->RR_SRV));
2291 if (srs->tcp) DisposeTCPConn(srs->tcp);
2292 srs->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, srs, mDNSNULL);
2293 if (!srs->tcp) srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2)
2294 else if (srs->RR_SRV.ThisAPInterval < mDNSPlatformOneSecond * 30) srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 30;
2295 }
2296 else
2297 {
2298 err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name));
2299 if (err) debugf("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %ld", err);
2300 }
2301
2302 SetRecordRetry(m, &srs->RR_SRV, err);
2303 return;
2304
2305 exit:
2306
2307 if (err)
2308 {
2309 LogMsg("SendServiceRegistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err, srs->RR_SRV.resrec.name->c);
2310
2311 unlinkSRS(m, srs);
2312 srs->state = regState_Unregistered;
2313
2314 mDNS_DropLockBeforeCallback();
2315 srs->ServiceCallback(m, srs, err);
2316 mDNS_ReclaimLockAfterCallback();
2317 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
2318 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
2319 }
2320 }
2321
2322 mDNSlocal const domainname *PUBLIC_UPDATE_SERVICE_TYPE = (const domainname*)"\x0B_dns-update" "\x04_udp";
2323 mDNSlocal const domainname *PUBLIC_LLQ_SERVICE_TYPE = (const domainname*)"\x08_dns-llq" "\x04_udp";
2324
2325 mDNSlocal const domainname *PRIVATE_UPDATE_SERVICE_TYPE = (const domainname*)"\x0F_dns-update-tls" "\x04_tcp";
2326 mDNSlocal const domainname *PRIVATE_QUERY_SERVICE_TYPE = (const domainname*)"\x0E_dns-query-tls" "\x04_tcp";
2327 mDNSlocal const domainname *PRIVATE_LLQ_SERVICE_TYPE = (const domainname*)"\x0C_dns-llq-tls" "\x04_tcp";
2328
2329 #define ZoneDataSRV(X) (\
2330 (X)->ZoneService == ZoneServiceUpdate ? ((X)->ZonePrivate ? PRIVATE_UPDATE_SERVICE_TYPE : PUBLIC_UPDATE_SERVICE_TYPE) : \
2331 (X)->ZoneService == ZoneServiceQuery ? ((X)->ZonePrivate ? PRIVATE_QUERY_SERVICE_TYPE : (const domainname*)"" ) : \
2332 (X)->ZoneService == ZoneServiceLLQ ? ((X)->ZonePrivate ? PRIVATE_LLQ_SERVICE_TYPE : PUBLIC_LLQ_SERVICE_TYPE ) : (const domainname*)"")
2333
2334 // Forward reference: GetZoneData_StartQuery references GetZoneData_QuestionCallback, and
2335 // GetZoneData_QuestionCallback calls GetZoneData_StartQuery
2336 mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qtype);
2337
2338 // GetZoneData_QuestionCallback is called from normal client callback context (core API calls allowed)
2339 mDNSlocal void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
2340 {
2341 ZoneData *zd = (ZoneData*)question->QuestionContext;
2342
2343 debugf("GetZoneData_QuestionCallback: %s %s", AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
2344
2345 if (!AddRecord) return; // Don't care about REMOVE events
2346 if (AddRecord == QC_addnocache && answer->rdlength == 0) return; // Don't care about transient failure indications
2347 if (answer->rrtype != question->qtype) return; // Don't care about CNAMEs
2348
2349 if (answer->rrtype == kDNSType_SOA)
2350 {
2351 debugf("GetZoneData GOT SOA %s", RRDisplayString(m, answer));
2352 mDNS_StopQuery(m, question);
2353 if (answer->rdlength)
2354 {
2355 AssignDomainName(&zd->ZoneName, answer->name);
2356 zd->ZoneClass = answer->rrclass;
2357 AssignDomainName(&zd->question.qname, &zd->ZoneName);
2358 GetZoneData_StartQuery(m, zd, kDNSType_SRV);
2359 }
2360 else if (zd->CurrentSOA->c[0])
2361 {
2362 zd->CurrentSOA = (domainname *)(zd->CurrentSOA->c + zd->CurrentSOA->c[0]+1);
2363 AssignDomainName(&zd->question.qname, zd->CurrentSOA);
2364 GetZoneData_StartQuery(m, zd, kDNSType_SOA);
2365 }
2366 else
2367 {
2368 LogOperation("GetZoneData recursed to root label of %##s without finding SOA", zd->ChildName.c);
2369 zd->ZoneDataCallback(m, mStatus_NoSuchNameErr, zd);
2370 mDNSPlatformMemFree(zd);
2371 }
2372 }
2373 else if (answer->rrtype == kDNSType_SRV)
2374 {
2375 debugf("GetZoneData GOT SRV %s", RRDisplayString(m, answer));
2376 mDNS_StopQuery(m, question);
2377 if (!answer->rdlength && zd->ZonePrivate && zd->ZoneService != ZoneServiceQuery)
2378 {
2379 zd->ZonePrivate = mDNSfalse; // Causes ZoneDataSRV() to yield a different SRV name when building the query
2380 GetZoneData_StartQuery(m, zd, kDNSType_SRV); // Try again, non-private this time
2381 }
2382 else
2383 {
2384 if (answer->rdlength)
2385 {
2386 AssignDomainName(&zd->Host, &answer->rdata->u.srv.target);
2387 zd->Port = answer->rdata->u.srv.port;
2388 AssignDomainName(&zd->question.qname, &zd->Host);
2389 GetZoneData_StartQuery(m, zd, kDNSType_A);
2390 }
2391 else
2392 {
2393 zd->ZonePrivate = mDNSfalse;
2394 zd->Host.c[0] = 0;
2395 zd->Port = zeroIPPort;
2396 zd->Addr = zeroAddr;
2397 zd->ZoneDataCallback(m, mStatus_NoError, zd);
2398 mDNSPlatformMemFree(zd);
2399 }
2400 }
2401 }
2402 else if (answer->rrtype == kDNSType_A)
2403 {
2404 debugf("GetZoneData GOT A %s", RRDisplayString(m, answer));
2405 mDNS_StopQuery(m, question);
2406 zd->Addr.type = mDNSAddrType_IPv4;
2407 zd->Addr.ip.v4 = (answer->rdlength == 4) ? answer->rdata->u.ipv4 : zerov4Addr;
2408 zd->ZoneDataCallback(m, mStatus_NoError, zd);
2409 mDNSPlatformMemFree(zd);
2410 }
2411 }
2412
2413 // GetZoneData_StartQuery is called from normal client context (lock not held, or client callback)
2414 mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qtype)
2415 {
2416 if (qtype == kDNSType_SRV)
2417 {
2418 AssignDomainName(&zd->question.qname, ZoneDataSRV(zd));
2419 AppendDomainName(&zd->question.qname, &zd->ZoneName);
2420 LogOperation("lookupDNSPort %##s", zd->question.qname.c);
2421 }
2422
2423 zd->question.ThisQInterval = -1; // So that GetZoneData_QuestionCallback() knows whether to cancel this question (Is this necessary?)
2424 zd->question.InterfaceID = mDNSInterface_Any;
2425 zd->question.Target = zeroAddr;
2426 //zd->question.qname.c[0] = 0; // Already set
2427 zd->question.qtype = qtype;
2428 zd->question.qclass = kDNSClass_IN;
2429 zd->question.LongLived = mDNSfalse;
2430 zd->question.ExpectUnique = mDNStrue;
2431 zd->question.ForceMCast = mDNSfalse;
2432 zd->question.ReturnIntermed = mDNStrue;
2433 zd->question.QuestionCallback = GetZoneData_QuestionCallback;
2434 zd->question.QuestionContext = zd;
2435
2436 //LogMsg("GetZoneData_StartQuery %##s (%s) %p", zd->question.qname.c, DNSTypeName(zd->question.qtype), zd->question.Private);
2437 return(mDNS_StartQuery(m, &zd->question));
2438 }
2439
2440 // StartGetZoneData is an internal routine (i.e. must be called with the lock already held)
2441 mDNSexport ZoneData *StartGetZoneData(mDNS *const m, const domainname *const name, const ZoneService target, ZoneDataCallback callback, void *ZoneDataContext)
2442 {
2443 DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, name);
2444 int initialskip = (AuthInfo && AuthInfo->AutoTunnel) ? DomainNameLength(name) - DomainNameLength(&AuthInfo->domain) : 0;
2445 ZoneData *zd = (ZoneData*)mDNSPlatformMemAllocate(sizeof(ZoneData));
2446 if (!zd) { LogMsg("ERROR: StartGetZoneData - mDNSPlatformMemAllocate failed"); return mDNSNULL; }
2447 mDNSPlatformMemZero(zd, sizeof(ZoneData));
2448 AssignDomainName(&zd->ChildName, name);
2449 zd->ZoneService = target;
2450 zd->CurrentSOA = (domainname *)(&zd->ChildName.c[initialskip]);
2451 zd->ZoneName.c[0] = 0;
2452 zd->ZoneClass = 0;
2453 zd->Host.c[0] = 0;
2454 zd->Port = zeroIPPort;
2455 zd->Addr = zeroAddr;
2456 zd->ZonePrivate = AuthInfo ? mDNStrue : mDNSfalse;
2457 zd->ZoneDataCallback = callback;
2458 zd->ZoneDataContext = ZoneDataContext;
2459
2460 zd->question.QuestionContext = zd;
2461 AssignDomainName(&zd->question.qname, zd->CurrentSOA);
2462
2463 mDNS_DropLockBeforeCallback(); // GetZoneData_StartQuery expects to be called from a normal callback, so we emulate that here
2464 GetZoneData_StartQuery(m, zd, kDNSType_SOA);
2465 mDNS_ReclaimLockAfterCallback();
2466
2467 return zd;
2468 }
2469
2470 // GetZoneData queries are a special case -- even if we have a key for them, we don't do them privately,
2471 // because that would result in an infinite loop (i.e. to do a private query we first need to get
2472 // the _dns-query-tls SRV record for the zone, and we can't do *that* privately because to do so
2473 // we'd need to already know the _dns-query-tls SRV record.
2474 // Also, as a general rule, we never do SOA queries privately
2475 mDNSexport DomainAuthInfo *GetAuthInfoForQuestion(mDNS *m, const DNSQuestion *const q) // Must be called with lock held
2476 {
2477 if (q->QuestionCallback == GetZoneData_QuestionCallback) return(mDNSNULL);
2478 if (q->qtype == kDNSType_SOA ) return(mDNSNULL);
2479 return(GetAuthInfoForName_internal(m, &q->qname));
2480 }
2481
2482 // ***************************************************************************
2483 #if COMPILER_LIKES_PRAGMA_MARK
2484 #pragma mark - host name and interface management
2485 #endif
2486
2487 // Called in normal client context (lock not held)
2488 mDNSlocal void CompleteSRVNatMap(mDNS *m, NATTraversalInfo *n)
2489 {
2490 ServiceRecordSet *srs = (ServiceRecordSet *)n->clientContext;
2491 LogOperation("SRVNatMap complete %.4a %u %u TTL %u", &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), n->NATLease);
2492
2493 if (!srs) { LogMsg("CompleteSRVNatMap called with unknown ServiceRecordSet object"); return; }
2494 if (!n->NATLease) return;
2495
2496 mDNS_Lock(m);
2497 if (!mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4))
2498 SendServiceRegistration(m, srs); // non-zero server address means we already have necessary zone data to send update
2499 else
2500 {
2501 // SHOULD NEVER HAPPEN!
2502 LogOperation("ERROR: CompleteSRVNatMap called but srs->SRSUpdateServer.ip.v4 is zero!");
2503 srs->state = regState_FetchingZoneData;
2504 if (srs->nta) CancelGetZoneData(m, srs->nta); // Make sure we cancel old one before we start a new one
2505 srs->nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs);
2506 }
2507 mDNS_Unlock(m);
2508 }
2509
2510 mDNSlocal void StartSRVNatMap(mDNS *m, ServiceRecordSet *srs)
2511 {
2512 mDNSu8 *p = srs->RR_PTR.resrec.name->c;
2513 if (p[0]) p += 1 + p[0];
2514 if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp")) srs->NATinfo.Protocol = NATOp_MapTCP;
2515 else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) srs->NATinfo.Protocol = NATOp_MapUDP;
2516 else { LogMsg("StartSRVNatMap: could not determine transport protocol of service %##s", srs->RR_SRV.resrec.name->c); return; }
2517
2518 if (srs->NATinfo.clientContext) mDNS_StopNATOperation_internal(m, &srs->NATinfo);
2519 srs->NATinfo.IntPort = srs->RR_SRV.resrec.rdata->u.srv.port;
2520 srs->NATinfo.RequestedPort = srs->RR_SRV.resrec.rdata->u.srv.port;
2521 srs->NATinfo.NATLease = 0; // Request default lease
2522 srs->NATinfo.clientCallback = CompleteSRVNatMap;
2523 srs->NATinfo.clientContext = srs;
2524 mDNS_StartNATOperation_internal(m, &srs->NATinfo);
2525 }
2526
2527 // Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
2528 mDNSexport void ServiceRegistrationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneData)
2529 {
2530 ServiceRecordSet *srs = (ServiceRecordSet *)zoneData->ZoneDataContext;
2531
2532 if (m->mDNS_busy != m->mDNS_reentrancy)
2533 LogMsg("ServiceRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
2534
2535 srs->nta = mDNSNULL;
2536
2537 if (err || !zoneData) return;
2538
2539 // cache zone data
2540 AssignDomainName(&srs->zone, &zoneData->ZoneName);
2541 srs->SRSUpdateServer.type = mDNSAddrType_IPv4;
2542 srs->SRSUpdateServer = zoneData->Addr;
2543 if (!mDNSIPPortIsZero(zoneData->Port))
2544 {
2545 srs->SRSUpdatePort = zoneData->Port;
2546 srs->Private = zoneData->ZonePrivate;
2547 }
2548 else
2549 {
2550 debugf("Update port not advertised via SRV - guessing port 53, no lease option");
2551 srs->SRSUpdatePort = UnicastDNSPort;
2552 srs->srs_uselease = mDNSfalse;
2553 }
2554
2555 LogOperation("ServiceRegistrationGotZoneData My IPv4 %#a%s Server %#a:%d%s for %##s",
2556 &m->AdvertisedV4, mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) ? " (RFC1918)" : "",
2557 &srs->SRSUpdateServer, mDNSVal16(srs->SRSUpdatePort), mDNSAddrIsRFC1918(&srs->SRSUpdateServer) ? " (RFC1918)" : "",
2558 srs->RR_SRV.resrec.name->c);
2559
2560 if (!mDNSIPPortIsZero(srs->RR_SRV.resrec.rdata->u.srv.port) &&
2561 mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&srs->SRSUpdateServer) &&
2562 srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP)
2563 {
2564 srs->state = regState_NATMap;
2565 LogOperation("ServiceRegistrationGotZoneData StartSRVNatMap");
2566 StartSRVNatMap(m, srs);
2567 }
2568 else
2569 {
2570 mDNS_Lock(m);
2571 SendServiceRegistration(m, srs);
2572 mDNS_Unlock(m);
2573 }
2574 }
2575
2576 mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
2577 {
2578 mDNSOpaque16 id;
2579 mDNSu8 *ptr = m->omsg.data;
2580 mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
2581 mStatus err = mStatus_UnknownErr;
2582 mDNSu32 i;
2583
2584 if (mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4)) // Don't know our UpdateServer yet
2585 {
2586 srs->RR_SRV.LastAPTime = m->timenow;
2587 if (srs->RR_SRV.ThisAPInterval < mDNSPlatformOneSecond * 5)
2588 srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5;
2589 return;
2590 }
2591
2592 id = mDNS_NewMessageID(m);
2593 InitializeDNSMessage(&m->omsg.h, id, UpdateReqFlags);
2594
2595 // put zone
2596 ptr = putZone(&m->omsg, ptr, end, &srs->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
2597 if (!ptr) { LogMsg("ERROR: SendServiceDeregistration - putZone"); err = mStatus_UnknownErr; goto exit; }
2598
2599 if (!(ptr = putDeleteAllRRSets(&m->omsg, ptr, srs->RR_SRV.resrec.name))) { err = mStatus_UnknownErr; goto exit; } // this deletes SRV, TXT, and Extras
2600 if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->RR_PTR.resrec))) { err = mStatus_UnknownErr; goto exit; }
2601 for (i = 0; i < srs->NumSubTypes; i++)
2602 if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->SubTypes[i].resrec))) { err = mStatus_UnknownErr; goto exit; }
2603
2604 srs->id = id;
2605 srs->state = regState_DeregPending;
2606
2607 if (srs->Private)
2608 {
2609 if (srs->tcp) LogOperation("SendServiceDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m, &srs->RR_SRV));
2610 if (srs->tcp) DisposeTCPConn(srs->tcp);
2611 srs->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, srs, mDNSNULL);
2612 if (!srs->tcp) srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2)
2613 else if (srs->RR_SRV.ThisAPInterval < mDNSPlatformOneSecond * 30) srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 30;
2614 }
2615 else
2616 {
2617 err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name));
2618 if (err && err != mStatus_TransientErr) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %ld", err); goto exit; }
2619 }
2620
2621 SetRecordRetry(m, &srs->RR_SRV, err);
2622 return;
2623
2624 exit:
2625
2626 if (err)
2627 {
2628 LogMsg("SendServiceDeregistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err, srs->RR_SRV.resrec.name->c);
2629 unlinkSRS(m, srs);
2630 srs->state = regState_Unregistered;
2631 }
2632 }
2633
2634 // Called with lock held
2635 mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs)
2636 {
2637 ExtraResourceRecord *e;
2638
2639 // Target change if:
2640 // We have a target and were previously waiting for one, or
2641 // We had a target and no longer do, or
2642 // The target has changed
2643
2644 domainname *curtarget = &srs->RR_SRV.resrec.rdata->u.srv.target;
2645 const domainname *const nt = GetServiceTarget(m, srs);
2646 const domainname *const newtarget = nt ? nt : (domainname*)"";
2647 mDNSBool TargetChanged = (newtarget->c[0] && srs->state == regState_NoTarget) || !SameDomainName(curtarget, newtarget);
2648 mDNSBool HaveZoneData = !mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4);
2649
2650 // Nat state change if:
2651 // We were behind a NAT, and now we are behind a new NAT, or
2652 // We're not behind a NAT but our port was previously mapped to a different public port
2653 // We were not behind a NAT and now we are
2654
2655 mDNSIPPort port = srs->RR_SRV.resrec.rdata->u.srv.port;
2656 mDNSBool NowNeedNATMAP = (srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP && !mDNSIPPortIsZero(port) && mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&srs->SRSUpdateServer));
2657 mDNSBool WereBehindNAT = (srs->NATinfo.clientContext != mDNSNULL);
2658 mDNSBool PortWasMapped = (srs->NATinfo.clientContext && !mDNSSameIPPort(srs->NATinfo.RequestedPort, port)); // I think this is always false -- SC Sept 07
2659 mDNSBool NATChanged = (!WereBehindNAT && NowNeedNATMAP) || (!NowNeedNATMAP && PortWasMapped);
2660
2661 LogOperation("UpdateSRV %##s newtarget %##s TargetChanged %d HaveZoneData %d port %d NowNeedNATMAP %d WereBehindNAT %d PortWasMapped %d NATChanged %d",
2662 srs->RR_SRV.resrec.name->c, newtarget,
2663 TargetChanged, HaveZoneData, mDNSVal16(port), NowNeedNATMAP, WereBehindNAT, PortWasMapped, NATChanged);
2664
2665 if (m->mDNS_busy != m->mDNS_reentrancy+1)
2666 LogMsg("UpdateSRV: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
2667
2668 if (!TargetChanged && !NATChanged) return;
2669
2670 switch(srs->state)
2671 {
2672 case regState_FetchingZoneData:
2673 case regState_DeregPending:
2674 case regState_DeregDeferred:
2675 case regState_Unregistered:
2676 case regState_NATMap:
2677 case regState_ExtraQueued:
2678 // In these states, the SRV has either not yet been registered (it will get up-to-date information when it is)
2679 // or is in the process of, or has already been, deregistered
2680 return;
2681
2682 case regState_Pending:
2683 case regState_Refresh:
2684 case regState_UpdatePending:
2685 // let the in-flight operation complete before updating
2686 srs->SRVUpdateDeferred = mDNStrue;
2687 return;
2688
2689 case regState_NATError:
2690 if (!NATChanged) return;
2691 // if nat changed, register if we have a target (below)
2692
2693 case regState_NoTarget:
2694 if (newtarget->c[0])
2695 {
2696 debugf("UpdateSRV: %s service %##s", HaveZoneData ? (NATChanged && NowNeedNATMAP ? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs->RR_SRV.resrec.name->c);
2697 if (!HaveZoneData)
2698 {
2699 srs->state = regState_FetchingZoneData;
2700 if (srs->nta) CancelGetZoneData(m, srs->nta); // Make sure we cancel old one before we start a new one
2701 srs->nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs);
2702 }
2703 else
2704 {
2705 if (srs->NATinfo.clientContext && (NATChanged || !NowNeedNATMAP))
2706 {
2707 mDNS_StopNATOperation_internal(m, &srs->NATinfo);
2708 srs->NATinfo.clientContext = mDNSNULL;
2709 }
2710 if (NATChanged && NowNeedNATMAP && srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP)
2711 { srs->state = regState_NATMap; StartSRVNatMap(m, srs); }
2712 else SendServiceRegistration(m, srs);
2713 }
2714 }
2715 return;
2716
2717 case regState_Registered:
2718 // target or nat changed. deregister service. upon completion, we'll look for a new target
2719 debugf("UpdateSRV: SRV record changed for service %##s - deregistering (will re-register with new SRV)", srs->RR_SRV.resrec.name->c);
2720 for (e = srs->Extras; e; e = e->next) e->r.state = regState_ExtraQueued; // extra will be re-registed if the service is re-registered
2721 srs->SRVChanged = mDNStrue;
2722 SendServiceDeregistration(m, srs);
2723 return;
2724
2725 default: LogMsg("UpdateSRV: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c);
2726 }
2727 }
2728
2729 // Called with lock held
2730 mDNSlocal void UpdateSRVRecords(mDNS *m)
2731 {
2732 if (CurrentServiceRecordSet)
2733 LogMsg("UpdateSRVRecords ERROR CurrentServiceRecordSet already set");
2734 CurrentServiceRecordSet = m->ServiceRegistrations;
2735
2736 while (CurrentServiceRecordSet)
2737 {
2738 ServiceRecordSet *s = CurrentServiceRecordSet;
2739 CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next;
2740 UpdateSRV(m, s);
2741 }
2742 }
2743
2744 // Forward reference: AdvertiseHostname references HostnameCallback, and HostnameCallback calls AdvertiseHostname
2745 mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
2746
2747 // Called in normal client context (lock not held)
2748 mDNSlocal void hostnameGetPublicAddressCallback(mDNS *m, NATTraversalInfo *n)
2749 {
2750 HostnameInfo *h = (HostnameInfo *)n->clientContext;
2751
2752 if (!h) { LogMsg("RegisterHostnameRecord: registration cancelled"); return; }
2753
2754 if (!n->Result)
2755 {
2756 if (mDNSIPv4AddressIsZero(n->ExternalAddress) || mDNSv4AddrIsRFC1918(&n->ExternalAddress)) return;
2757
2758 if (h->arv4.resrec.RecordType)
2759 {
2760 if (mDNSSameIPv4Address(h->arv4.resrec.rdata->u.ipv4, n->ExternalAddress)) return; // If address unchanged, do nothing
2761 LogMsg("Updating hostname %##s IPv4 from %.4a to %.4a (NAT gateway's external address)", h->arv4.resrec.name->c, &h->arv4.resrec.rdata->u.ipv4, &n->ExternalAddress);
2762 mDNS_Deregister(m, &h->arv4); // mStatus_MemFree callback will re-register with new address
2763 }
2764 else
2765 {
2766 LogMsg("Advertising hostname %##s IPv4 %.4a (NAT gateway's external address)", h->arv4.resrec.name->c, &n->ExternalAddress);
2767 h->arv4.resrec.RecordType = kDNSRecordTypeKnownUnique;
2768 h->arv4.resrec.rdata->u.ipv4 = n->ExternalAddress;
2769 mDNS_Register(m, &h->arv4);
2770 }
2771 }
2772 }
2773
2774 // register record or begin NAT traversal
2775 mDNSlocal void AdvertiseHostname(mDNS *m, HostnameInfo *h)
2776 {
2777 if (!mDNSIPv4AddressIsZero(m->AdvertisedV4.ip.v4) && h->arv4.resrec.RecordType == kDNSRecordTypeUnregistered)
2778 {
2779 mDNS_SetupResourceRecord(&h->arv4, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnregistered, HostnameCallback, h);
2780 AssignDomainName(&h->arv4.namestorage, &h->fqdn);
2781 h->arv4.resrec.rdata->u.ipv4 = m->AdvertisedV4.ip.v4;
2782 h->arv4.state = regState_Unregistered;
2783 if (mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4))
2784 {
2785 // If we already have a NAT query active, stop it and restart it to make sure we get another callback
2786 if (h->natinfo.clientContext) mDNS_StopNATOperation_internal(m, &h->natinfo);
2787 h->natinfo.Protocol = 0;
2788 h->natinfo.IntPort = zeroIPPort;
2789 h->natinfo.RequestedPort = zeroIPPort;
2790 h->natinfo.NATLease = 0;
2791 h->natinfo.clientCallback = hostnameGetPublicAddressCallback;
2792 h->natinfo.clientContext = h;
2793 mDNS_StartNATOperation_internal(m, &h->natinfo);
2794 }
2795 else
2796 {
2797 LogMsg("Advertising hostname %##s IPv4 %.4a", h->arv4.resrec.name->c, &m->AdvertisedV4.ip.v4);
2798 h->arv4.resrec.RecordType = kDNSRecordTypeKnownUnique;
2799 mDNS_Register_internal(m, &h->arv4);
2800 }
2801 }
2802
2803 if (!mDNSIPv6AddressIsZero(m->AdvertisedV6.ip.v6) && h->arv6.resrec.RecordType == kDNSRecordTypeUnregistered)
2804 {
2805 mDNS_SetupResourceRecord(&h->arv6, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL, kDNSRecordTypeKnownUnique, HostnameCallback, h);
2806 AssignDomainName(&h->arv6.namestorage, &h->fqdn);
2807 h->arv6.resrec.rdata->u.ipv6 = m->AdvertisedV6.ip.v6;
2808 h->arv6.state = regState_Unregistered;
2809 LogMsg("Advertising hostname %##s IPv6 %.16a", h->arv6.resrec.name->c, &m->AdvertisedV6.ip.v6);
2810 mDNS_Register_internal(m, &h->arv6);
2811 }
2812 }
2813
2814 mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
2815 {
2816 HostnameInfo *hi = (HostnameInfo *)rr->RecordContext;
2817
2818 if (result == mStatus_MemFree)
2819 {
2820 if (hi)
2821 {
2822 // If we're still in the Hostnames list, update to new address
2823 HostnameInfo *i;
2824 LogOperation("HostnameCallback: Got mStatus_MemFree for %p %p %s", hi, rr, ARDisplayString(m, rr));
2825 for (i = m->Hostnames; i; i = i->next)
2826 if (rr == &i->arv4 || rr == &i->arv6)
2827 { mDNS_Lock(m); AdvertiseHostname(m, i); mDNS_Unlock(m); return; }
2828
2829 // Else, we're not still in the Hostnames list, so free the memory
2830 if (hi->arv4.resrec.RecordType == kDNSRecordTypeUnregistered &&
2831 hi->arv6.resrec.RecordType == kDNSRecordTypeUnregistered)
2832 {
2833 if (hi->natinfo.clientContext) mDNS_StopNATOperation_internal(m, &hi->natinfo);
2834 hi->natinfo.clientContext = mDNSNULL;
2835 mDNSPlatformMemFree(hi); // free hi when both v4 and v6 AuthRecs deallocated
2836 }
2837 }
2838 return;
2839 }
2840
2841 if (result)
2842 {
2843 // don't unlink or free - we can retry when we get a new address/router
2844 if (rr->resrec.rrtype == kDNSType_A)
2845 LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.4a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv4);
2846 else
2847 LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.16a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
2848 if (!hi) { mDNSPlatformMemFree(rr); return; }
2849 if (rr->state != regState_Unregistered) LogMsg("Error: HostnameCallback invoked with error code for record not in regState_Unregistered!");
2850
2851 if (hi->arv4.state == regState_Unregistered &&
2852 hi->arv6.state == regState_Unregistered)
2853 {
2854 // only deliver status if both v4 and v6 fail
2855 rr->RecordContext = (void *)hi->StatusContext;
2856 if (hi->StatusCallback)
2857 hi->StatusCallback(m, rr, result); // client may NOT make API calls here
2858 rr->RecordContext = (void *)hi;
2859 }
2860 return;
2861 }
2862
2863 // register any pending services that require a target
2864 mDNS_Lock(m);
2865 UpdateSRVRecords(m);
2866 mDNS_Unlock(m);
2867
2868 // Deliver success to client
2869 if (!hi) { LogMsg("HostnameCallback invoked with orphaned address record"); return; }
2870 if (rr->resrec.rrtype == kDNSType_A)
2871 LogMsg("Registered hostname %##s IP %.4a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv4);
2872 else
2873 LogMsg("Registered hostname %##s IP %.16a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
2874
2875 rr->RecordContext = (void *)hi->StatusContext;
2876 if (hi->StatusCallback)
2877 hi->StatusCallback(m, rr, result); // client may NOT make API calls here
2878 rr->RecordContext = (void *)hi;
2879 }
2880
2881 mDNSlocal void FoundStaticHostname(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
2882 {
2883 const domainname *pktname = &answer->rdata->u.name;
2884 domainname *storedname = &m->StaticHostname;
2885 HostnameInfo *h = m->Hostnames;
2886
2887 (void)question;
2888
2889 debugf("FoundStaticHostname: %##s -> %##s (%s)", question->qname.c, answer->rdata->u.name.c, AddRecord ? "added" : "removed");
2890 if (AddRecord && !SameDomainName(pktname, storedname))
2891 {
2892 AssignDomainName(storedname, pktname);
2893 while (h)
2894 {
2895 if (h->arv4.state == regState_FetchingZoneData || h->arv4.state == regState_Pending || h->arv4.state == regState_NATMap ||
2896 h->arv6.state == regState_FetchingZoneData || h->arv6.state == regState_Pending)
2897 {
2898 // 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
2899 m->NextSRVUpdate = NonZeroTime(m->timenow + (5 * mDNSPlatformOneSecond));
2900 return;
2901 }
2902 h = h->next;
2903 }
2904 mDNS_Lock(m);
2905 UpdateSRVRecords(m);
2906 mDNS_Unlock(m);
2907 }
2908 else if (!AddRecord && SameDomainName(pktname, storedname))
2909 {
2910 mDNS_Lock(m);
2911 storedname->c[0] = 0;
2912 UpdateSRVRecords(m);
2913 mDNS_Unlock(m);
2914 }
2915 }
2916
2917 // Called with lock held
2918 mDNSlocal void GetStaticHostname(mDNS *m)
2919 {
2920 char buf[MAX_REVERSE_MAPPING_NAME_V4];
2921 DNSQuestion *q = &m->ReverseMap;
2922 mDNSu8 *ip = m->AdvertisedV4.ip.v4.b;
2923 mStatus err;
2924
2925 if (m->ReverseMap.ThisQInterval != -1) mDNS_StopQuery_internal(m, q);
2926
2927 m->StaticHostname.c[0] = 0;
2928 if (mDNSIPv4AddressIsZero(m->AdvertisedV4.ip.v4)) return;
2929 mDNSPlatformMemZero(q, sizeof(*q));
2930 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
2931 mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", ip[3], ip[2], ip[1], ip[0]);
2932 if (!MakeDomainNameFromDNSNameString(&q->qname, buf)) { LogMsg("Error: GetStaticHostname - bad name %s", buf); return; }
2933
2934 q->InterfaceID = mDNSInterface_Any;
2935 q->Target = zeroAddr;
2936 q->qtype = kDNSType_PTR;
2937 q->qclass = kDNSClass_IN;
2938 q->LongLived = mDNSfalse;
2939 q->ExpectUnique = mDNSfalse;
2940 q->ForceMCast = mDNSfalse;
2941 q->ReturnIntermed = mDNStrue;
2942 q->QuestionCallback = FoundStaticHostname;
2943 q->QuestionContext = mDNSNULL;
2944
2945 err = mDNS_StartQuery_internal(m, q);
2946 if (err) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err);
2947 }
2948
2949 mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
2950 {
2951 HostnameInfo **ptr = &m->Hostnames;
2952
2953 LogOperation("mDNS_AddDynDNSHostName %##s", fqdn);
2954
2955 while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next;
2956 if (*ptr) { LogMsg("DynDNSHostName %##s already in list", fqdn->c); return; }
2957
2958 // allocate and format new address record
2959 *ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
2960 if (!*ptr) { LogMsg("ERROR: mDNS_AddDynDNSHostName - malloc"); return; }
2961
2962 mDNSPlatformMemZero(*ptr, sizeof(**ptr));
2963 AssignDomainName(&(*ptr)->fqdn, fqdn);
2964 (*ptr)->arv4.state = regState_Unregistered;
2965 (*ptr)->arv6.state = regState_Unregistered;
2966 (*ptr)->StatusCallback = StatusCallback;
2967 (*ptr)->StatusContext = StatusContext;
2968
2969 AdvertiseHostname(m, *ptr);
2970 }
2971
2972 mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn)
2973 {
2974 HostnameInfo **ptr = &m->Hostnames;
2975
2976 LogOperation("mDNS_RemoveDynDNSHostName %##s", fqdn);
2977
2978 while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next;
2979 if (!*ptr) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn->c);
2980 else
2981 {
2982 HostnameInfo *hi = *ptr;
2983 // We do it this way because, if we have no active v6 record, the "mDNS_Deregister_internal(m, &hi->arv4);"
2984 // below could free the memory, and we have to make sure we don't touch hi fields after that.
2985 mDNSBool f4 = hi->arv4.resrec.RecordType != kDNSRecordTypeUnregistered && hi->arv4.state != regState_Unregistered;
2986 mDNSBool f6 = hi->arv6.resrec.RecordType != kDNSRecordTypeUnregistered && hi->arv6.state != regState_Unregistered;
2987 if (f4) LogOperation("mDNS_RemoveDynDNSHostName removing v4 %##s", fqdn);
2988 if (f6) LogOperation("mDNS_RemoveDynDNSHostName removing v6 %##s", fqdn);
2989 *ptr = (*ptr)->next; // unlink
2990 if (f4) mDNS_Deregister_internal(m, &hi->arv4, mDNS_Dereg_normal);
2991 if (f6) mDNS_Deregister_internal(m, &hi->arv6, mDNS_Dereg_normal);
2992 // When both deregistrations complete we'll free the memory in the mStatus_MemFree callback
2993 }
2994 UpdateSRVRecords(m);
2995 }
2996
2997 // Currently called without holding the lock
2998 // Maybe we should change that?
2999 mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router)
3000 {
3001 mDNSBool v4Changed, v6Changed, RouterChanged;
3002
3003 if (m->mDNS_busy != m->mDNS_reentrancy)
3004 LogMsg("mDNS_SetPrimaryInterfaceInfo: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
3005
3006 if (v4addr && v4addr->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo v4 address - incorrect type. Discarding. %#a", v4addr); return; }
3007 if (v6addr && v6addr->type != mDNSAddrType_IPv6) { LogMsg("mDNS_SetPrimaryInterfaceInfo v6 address - incorrect type. Discarding. %#a", v6addr); return; }
3008 if (router && router->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-v4 router. Discarding. %#a", router); return; }
3009
3010 mDNS_Lock(m);
3011
3012 if (v4addr && !mDNSv4AddressIsLinkLocal(&v4addr->ip.v4)) v6addr = mDNSNULL;
3013
3014 v4Changed = !mDNSSameIPv4Address(m->AdvertisedV4.ip.v4, v4addr ? v4addr->ip.v4 : zerov4Addr);
3015 v6Changed = !mDNSSameIPv6Address(m->AdvertisedV6.ip.v6, v6addr ? v6addr->ip.v6 : zerov6Addr);
3016 RouterChanged = !mDNSSameIPv4Address(m->Router.ip.v4, router ? router->ip.v4 : zerov4Addr);
3017
3018 if (v4addr && (v4Changed || RouterChanged))
3019 debugf("mDNS_SetPrimaryInterfaceInfo: address changed from %#a to %#a", &m->AdvertisedV4, v4addr);
3020
3021 if (v4addr) m->AdvertisedV4 = *v4addr; else m->AdvertisedV4.ip.v4 = zerov4Addr;
3022 if (v6addr) m->AdvertisedV6 = *v6addr; else m->AdvertisedV6.ip.v6 = zerov6Addr;
3023 if (router) m->Router = *router; else m->Router .ip.v4 = zerov4Addr;
3024 // setting router to zero indicates that nat mappings must be reestablished when router is reset
3025
3026 if (v4Changed || RouterChanged || v6Changed)
3027 {
3028 HostnameInfo *i;
3029 LogOperation("mDNS_SetPrimaryInterfaceInfo: %s%s%s%#a %#a %#a",
3030 v4Changed ? "v4Changed " : "",
3031 RouterChanged ? "RouterChanged " : "",
3032 v6Changed ? "v6Changed " : "", v4addr, v6addr, router);
3033
3034 for (i = m->Hostnames; i; i = i->next)
3035 {
3036 LogOperation("mDNS_SetPrimaryInterfaceInfo updating host name registrations for %##s", i->fqdn.c);
3037
3038 if (i->arv4.resrec.RecordType > kDNSRecordTypeDeregistering &&
3039 !mDNSSameIPv4Address(i->arv4.resrec.rdata->u.ipv4, m->AdvertisedV4.ip.v4))
3040 {
3041 LogOperation("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m, &i->arv4));
3042 mDNS_Deregister_internal(m, &i->arv4, mDNS_Dereg_normal);
3043 }
3044
3045 if (i->arv6.resrec.RecordType > kDNSRecordTypeDeregistering &&
3046 !mDNSSameIPv6Address(i->arv6.resrec.rdata->u.ipv6, m->AdvertisedV6.ip.v6))
3047 {
3048 LogOperation("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m, &i->arv6));
3049 mDNS_Deregister_internal(m, &i->arv6, mDNS_Dereg_normal);
3050 }
3051
3052 // AdvertiseHostname will only register new address records.
3053 // For records still in the process of deregistering it will ignore them, and let the mStatus_MemFree callback handle them.
3054 AdvertiseHostname(m, i);
3055 }
3056
3057 if (v4Changed || RouterChanged)
3058 {
3059 m->ExternalAddress = zerov4Addr;
3060 m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
3061 m->retryGetAddr = m->timenow;
3062 m->NextScheduledNATOp = m->timenow;
3063 ClearUPnPState(m);
3064 }
3065
3066 UpdateSRVRecords(m);
3067 GetStaticHostname(m); // look up reverse map record to find any static hostnames for our IP address
3068 }
3069
3070 mDNS_Unlock(m);
3071 }
3072
3073 // ***************************************************************************
3074 #if COMPILER_LIKES_PRAGMA_MARK
3075 #pragma mark - Incoming Message Processing
3076 #endif
3077
3078 mDNSlocal mStatus ParseTSIGError(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const domainname *const displayname)
3079 {
3080 const mDNSu8 *ptr;
3081 mStatus err = mStatus_NoError;
3082 int i;
3083
3084 ptr = LocateAdditionals(msg, end);
3085 if (!ptr) goto finish;
3086
3087 for (i = 0; i < msg->h.numAdditionals; i++)
3088 {
3089 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
3090 if (!ptr) goto finish;
3091 if (m->rec.r.resrec.rrtype == kDNSType_TSIG)
3092 {
3093 mDNSu32 macsize;
3094 mDNSu8 *rd = m->rec.r.resrec.rdata->u.data;
3095 mDNSu8 *rdend = rd + m->rec.r.resrec.rdlength;
3096 int alglen = DomainNameLengthLimit(&m->rec.r.resrec.rdata->u.name, rdend);
3097 if (alglen > MAX_DOMAIN_NAME) goto finish;
3098 rd += alglen; // algorithm name
3099 if (rd + 6 > rdend) goto finish;
3100 rd += 6; // 48-bit timestamp
3101 if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
3102 rd += sizeof(mDNSOpaque16); // fudge
3103 if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
3104 macsize = mDNSVal16(*(mDNSOpaque16 *)rd);
3105 rd += sizeof(mDNSOpaque16); // MAC size
3106 if (rd + macsize > rdend) goto finish;
3107 rd += macsize;
3108 if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
3109 rd += sizeof(mDNSOpaque16); // orig id
3110 if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
3111 err = mDNSVal16(*(mDNSOpaque16 *)rd); // error code
3112
3113 if (err == TSIG_ErrBadSig) { LogMsg("%##s: bad signature", displayname->c); err = mStatus_BadSig; }
3114 else if (err == TSIG_ErrBadKey) { LogMsg("%##s: bad key", displayname->c); err = mStatus_BadKey; }
3115 else if (err == TSIG_ErrBadTime) { LogMsg("%##s: bad time", displayname->c); err = mStatus_BadTime; }
3116 else if (err) { LogMsg("%##s: unknown tsig error %d", displayname->c, err); err = mStatus_UnknownErr; }
3117 goto finish;
3118 }
3119 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
3120 }
3121
3122 finish:
3123 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
3124 return err;
3125 }
3126
3127 mDNSlocal mStatus checkUpdateResult(mDNS *const m, const domainname *const displayname, const mDNSu8 rcode, const DNSMessage *const msg, const mDNSu8 *const end)
3128 {
3129 (void)msg; // currently unused, needed for TSIG errors
3130 if (!rcode) return mStatus_NoError;
3131 else if (rcode == kDNSFlag1_RC_YXDomain)
3132 {
3133 debugf("name in use: %##s", displayname->c);
3134 return mStatus_NameConflict;
3135 }
3136 else if (rcode == kDNSFlag1_RC_Refused)
3137 {
3138 LogMsg("Update %##s refused", displayname->c);
3139 return mStatus_Refused;
3140 }
3141 else if (rcode == kDNSFlag1_RC_NXRRSet)
3142 {
3143 LogMsg("Reregister refused (NXRRSET): %##s", displayname->c);
3144 return mStatus_NoSuchRecord;
3145 }
3146 else if (rcode == kDNSFlag1_RC_NotAuth)
3147 {
3148 // TSIG errors should come with FmtErr as per RFC 2845, but BIND 9 sends them with NotAuth so we look here too
3149 mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
3150 if (!tsigerr)
3151 {
3152 LogMsg("Permission denied (NOAUTH): %##s", displayname->c);
3153 return mStatus_UnknownErr;
3154 }
3155 else return tsigerr;
3156 }
3157 else if (rcode == kDNSFlag1_RC_FmtErr)
3158 {
3159 mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
3160 if (!tsigerr)
3161 {
3162 LogMsg("Format Error: %##s", displayname->c);
3163 return mStatus_UnknownErr;
3164 }
3165 else return tsigerr;
3166 }
3167 else
3168 {
3169 LogMsg("Update %##s failed with rcode %d", displayname->c, rcode);
3170 return mStatus_UnknownErr;
3171 }
3172 }
3173
3174 // Called with lock held
3175 mDNSlocal void SendRecordRegistration(mDNS *const m, AuthRecord *rr)
3176 {
3177 mDNSu8 *ptr = m->omsg.data;
3178 mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
3179 mStatus err = mStatus_UnknownErr;
3180
3181 if (m->mDNS_busy != m->mDNS_reentrancy+1)
3182 LogMsg("SendRecordRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
3183
3184 if (mDNSIPv4AddressIsZero(rr->UpdateServer.ip.v4)) // Don't know our UpdateServer yet
3185 {
3186 rr->LastAPTime = m->timenow;
3187 if (rr->ThisAPInterval < mDNSPlatformOneSecond * 5)
3188 rr->ThisAPInterval = mDNSPlatformOneSecond * 5;
3189 return;
3190 }
3191
3192 rr->RequireGoodbye = mDNStrue;
3193 rr->id = mDNS_NewMessageID(m);
3194 InitializeDNSMessage(&m->omsg.h, rr->id, UpdateReqFlags);
3195
3196 // set zone
3197 ptr = putZone(&m->omsg, ptr, end, &rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
3198 if (!ptr) { err = mStatus_UnknownErr; goto exit; }
3199
3200 if (rr->state == regState_UpdatePending)
3201 {
3202 // delete old RData
3203 SetNewRData(&rr->resrec, rr->OrigRData, rr->OrigRDLen);
3204 if (!(ptr = putDeletionRecord(&m->omsg, ptr, &rr->resrec))) { err = mStatus_UnknownErr; goto exit; } // delete old rdata
3205
3206 // add new RData
3207 SetNewRData(&rr->resrec, rr->InFlightRData, rr->InFlightRDLen);
3208 if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
3209 }
3210
3211 else
3212 {
3213 if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
3214 {
3215 // KnownUnique: Delete any previous value
3216 ptr = putDeleteRRSet(&m->omsg, ptr, rr->resrec.name, rr->resrec.rrtype);
3217 if (!ptr) { err = mStatus_UnknownErr; goto exit; }
3218 }
3219
3220 else if (rr->resrec.RecordType != kDNSRecordTypeShared)
3221 {
3222 ptr = putPrereqNameNotInUse(rr->resrec.name, &m->omsg, ptr, end);
3223 if (!ptr) { err = mStatus_UnknownErr; goto exit; }
3224 }
3225
3226 ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl);
3227 if (!ptr) { err = mStatus_UnknownErr; goto exit; }
3228 }
3229
3230 if (rr->uselease)
3231 {
3232 ptr = putUpdateLease(&m->omsg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) { err = mStatus_UnknownErr; goto exit; }
3233 }
3234
3235 if (rr->Private)
3236 {
3237 LogOperation("SendRecordRegistration TCP %p %s", rr->tcp, ARDisplayString(m, rr));
3238 if (rr->tcp) LogOperation("SendRecordRegistration: Disposing existing TCP connection for %s", ARDisplayString(m, rr));
3239 if (rr->tcp) DisposeTCPConn(rr->tcp);
3240 rr->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, mDNSNULL, rr);
3241 if (!rr->tcp) rr->ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2)
3242 else if (rr->ThisAPInterval < mDNSPlatformOneSecond * 30) rr->ThisAPInterval = mDNSPlatformOneSecond * 30;
3243 }
3244 else
3245 {
3246 err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name));
3247 if (err) debugf("ERROR: SendRecordRegistration - mDNSSendDNSMessage - %ld", err);
3248 }
3249
3250 SetRecordRetry(m, rr, err);
3251
3252 if (rr->state != regState_Refresh && rr->state != regState_DeregDeferred && rr->state != regState_UpdatePending)
3253 rr->state = regState_Pending;
3254
3255 return;
3256
3257 exit:
3258 LogMsg("SendRecordRegistration: Error formatting message for %s", ARDisplayString(m, rr));
3259 }
3260
3261 // Called with lock held
3262 mDNSlocal void hndlServiceUpdateReply(mDNS *const m, ServiceRecordSet *srs, mStatus err)
3263 {
3264 mDNSBool InvokeCallback = mDNSfalse;
3265 ExtraResourceRecord **e = &srs->Extras;
3266 AuthRecord *txt = &srs->RR_TXT;
3267
3268 if (m->mDNS_busy != m->mDNS_reentrancy+1)
3269 LogMsg("hndlServiceUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
3270
3271 SetRecordRetry(m, &srs->RR_SRV, mStatus_NoError);
3272
3273 switch (srs->state)
3274 {
3275 case regState_Pending:
3276 if (err == mStatus_NameConflict && !srs->TestForSelfConflict)
3277 {
3278 srs->TestForSelfConflict = mDNStrue;
3279 debugf("checking for self-conflict of service %##s", srs->RR_SRV.resrec.name->c);
3280 SendServiceRegistration(m, srs);
3281 return;
3282 }
3283 else if (srs->TestForSelfConflict)
3284 {
3285 srs->TestForSelfConflict = mDNSfalse;
3286 if (err == mStatus_NoSuchRecord) err = mStatus_NameConflict; // NoSuchRecord implies that our prereq was not met, so we actually have a name conflict
3287 if (!err) srs->state = regState_Registered;
3288 InvokeCallback = mDNStrue;
3289 break;
3290 }
3291 else if (srs->srs_uselease && err == mStatus_UnknownErr && mDNSSameIPPort(srs->SRSUpdatePort, UnicastDNSPort))
3292 {
3293 LogMsg("Re-trying update of service %##s without lease option", srs->RR_SRV.resrec.name->c);
3294 srs->srs_uselease = mDNSfalse;
3295 SendServiceRegistration(m, srs);
3296 return;
3297 }
3298 else
3299 {
3300 //!!!KRS make sure all structs will still get cleaned up when client calls DeregisterService with this state
3301 if (err) LogMsg("Error %ld for registration of service %##s", err, srs->RR_SRV.resrec.name->c);
3302 else srs->state = regState_Registered;
3303 InvokeCallback = mDNStrue;
3304 break;
3305 }
3306 case regState_Refresh:
3307 if (err)
3308 {
3309 LogMsg("Error %ld for refresh of service %##s", err, srs->RR_SRV.resrec.name->c);
3310 InvokeCallback = mDNStrue;
3311 }
3312 else srs->state = regState_Registered;
3313 break;
3314 case regState_DeregPending:
3315 if (err) LogMsg("Error %ld for deregistration of service %##s", err, srs->RR_SRV.resrec.name->c);
3316 if (srs->SRVChanged)
3317 {
3318 srs->state = regState_NoTarget; // NoTarget will allow us to pick up new target OR nat traversal state
3319 break;
3320 }
3321 err = mStatus_MemFree;
3322 InvokeCallback = mDNStrue;
3323 if (srs->NATinfo.clientContext)
3324 {
3325 // deletion completed
3326 mDNS_StopNATOperation_internal(m, &srs->NATinfo);
3327 srs->NATinfo.clientContext = mDNSNULL;
3328 }
3329 srs->state = regState_Unregistered;
3330 break;
3331 case regState_DeregDeferred:
3332 if (err)
3333 {
3334 debugf("Error %ld received prior to deferred derigstration of %##s", err, srs->RR_SRV.resrec.name->c);
3335 err = mStatus_MemFree;
3336 InvokeCallback = mDNStrue;
3337 srs->state = regState_Unregistered;
3338 break;
3339 }
3340 else
3341 {
3342 debugf("Performing deferred deregistration of %##s", srs->RR_SRV.resrec.name->c);
3343 srs->state = regState_Registered;
3344 SendServiceDeregistration(m, srs);
3345 return;
3346 }
3347 case regState_UpdatePending:
3348 if (err)
3349 {
3350 LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs->RR_SRV.resrec.name->c);
3351 InvokeCallback = mDNStrue;
3352 }
3353 else
3354 {
3355 srs->state = regState_Registered;
3356 // deallocate old RData
3357 if (txt->UpdateCallback) txt->UpdateCallback(m, txt, txt->OrigRData);
3358 SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen);
3359 txt->OrigRData = mDNSNULL;
3360 txt->InFlightRData = mDNSNULL;
3361 }
3362 break;
3363 case regState_FetchingZoneData:
3364 case regState_Registered:
3365 case regState_Unregistered:
3366 case regState_NATMap:
3367 case regState_NoTarget:
3368 case regState_ExtraQueued:
3369 case regState_NATError:
3370 LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %ld. Unlinking.",
3371 srs->RR_SRV.resrec.name->c, srs->state, err);
3372 err = mStatus_UnknownErr;
3373 default: LogMsg("hndlServiceUpdateReply: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c);
3374 }
3375
3376 if ((srs->SRVChanged || srs->SRVUpdateDeferred) && (srs->state == regState_NoTarget || srs->state == regState_Registered))
3377 {
3378 LogOperation("hndlServiceUpdateReply: SRVChanged %d SRVUpdateDeferred %d state %d", srs->SRVChanged, srs->SRVUpdateDeferred, srs->state);
3379 if (InvokeCallback)
3380 {
3381 srs->ClientCallbackDeferred = mDNStrue;
3382 srs->DeferredStatus = err;
3383 }
3384 srs->SRVChanged = srs->SRVUpdateDeferred = mDNSfalse;
3385 UpdateSRV(m, srs);
3386 return;
3387 }
3388
3389 while (*e)
3390 {
3391 if ((*e)->r.state == regState_ExtraQueued)
3392 {
3393 if (srs->state == regState_Registered && !err)
3394 {
3395 // extra resource record queued for this service - copy zone srs and register
3396 AssignDomainName(&(*e)->r.zone, &srs->zone);
3397 (*e)->r.UpdateServer = srs->SRSUpdateServer;
3398 (*e)->r.UpdatePort = srs->SRSUpdatePort;
3399 (*e)->r.uselease = srs->srs_uselease;
3400 SendRecordRegistration(m, &(*e)->r);
3401 e = &(*e)->next;
3402 }
3403 else if (err && (*e)->r.state != regState_Unregistered)
3404 {
3405 // unlink extra from list
3406 (*e)->r.state = regState_Unregistered;
3407 *e = (*e)->next;
3408 }
3409 else e = &(*e)->next;
3410 }
3411 else e = &(*e)->next;
3412 }
3413
3414 if (srs->state == regState_Unregistered)
3415 {
3416 if (err != mStatus_MemFree)
3417 LogMsg("hndlServiceUpdateReply ERROR! state == regState_Unregistered but err != mStatus_MemFree. Permanently abandoning service registration %##s",
3418 srs->RR_SRV.resrec.name->c);
3419 unlinkSRS(m, srs);
3420 }
3421 else if (txt->QueuedRData && srs->state == regState_Registered)
3422 {
3423 if (InvokeCallback)
3424 {
3425 // if we were supposed to give a client callback, we'll do it after we update the primary txt record
3426 srs->ClientCallbackDeferred = mDNStrue;
3427 srs->DeferredStatus = err;
3428 }
3429 srs->state = regState_UpdatePending;
3430 txt->InFlightRData = txt->QueuedRData;
3431 txt->InFlightRDLen = txt->QueuedRDLen;
3432 txt->OrigRData = txt->resrec.rdata;
3433 txt->OrigRDLen = txt->resrec.rdlength;
3434 txt->QueuedRData = mDNSNULL;
3435 SendServiceRegistration(m, srs);
3436 return;
3437 }
3438
3439 mDNS_DropLockBeforeCallback();
3440 if (InvokeCallback)
3441 srs->ServiceCallback(m, srs, err);
3442 else if (srs->ClientCallbackDeferred)
3443 {
3444 srs->ClientCallbackDeferred = mDNSfalse;
3445 srs->ServiceCallback(m, srs, srs->DeferredStatus);
3446 }
3447 mDNS_ReclaimLockAfterCallback();
3448 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
3449 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
3450 }
3451
3452 // Called with lock held
3453 mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
3454 {
3455 mDNSBool InvokeCallback = mDNStrue;
3456
3457 if (m->mDNS_busy != m->mDNS_reentrancy+1)
3458 LogMsg("hndlRecordUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
3459
3460 SetRecordRetry(m, rr, mStatus_NoError);
3461
3462 if (rr->state == regState_UpdatePending)
3463 {
3464 if (err) LogMsg("Update record failed for %##s (err %d)", rr->resrec.name->c, err);
3465 rr->state = regState_Registered;
3466 // deallocate old RData
3467 if (rr->UpdateCallback) rr->UpdateCallback(m, rr, rr->OrigRData);
3468 SetNewRData(&rr->resrec, rr->InFlightRData, rr->InFlightRDLen);
3469 rr->OrigRData = mDNSNULL;
3470 rr->InFlightRData = mDNSNULL;
3471 }
3472
3473 if (rr->state == regState_DeregPending)
3474 {
3475 debugf("Received reply for deregister record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype);
3476 if (err) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %ld",
3477 rr->resrec.name->c, rr->resrec.rrtype, err);
3478 err = mStatus_MemFree;
3479 rr->state = regState_Unregistered;
3480 }
3481
3482 if (rr->state == regState_DeregDeferred)
3483 {
3484 if (err)
3485 {
3486 LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %ld",
3487 rr->resrec.name->c, rr->resrec.rrtype, err);
3488 rr->state = regState_Unregistered;
3489 }
3490 debugf("Calling deferred deregistration of record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype);
3491 rr->state = regState_Registered;
3492 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
3493 return;
3494 }
3495
3496 if (rr->state == regState_Pending || rr->state == regState_Refresh)
3497 {
3498 if (!err)
3499 {
3500 rr->state = regState_Registered;
3501 if (rr->state == regState_Refresh) InvokeCallback = mDNSfalse;
3502 }
3503 else
3504 {
3505 if (rr->uselease && err == mStatus_UnknownErr && mDNSSameIPPort(rr->UpdatePort, UnicastDNSPort))
3506 {
3507 LogMsg("Re-trying update of record %##s without lease option", rr->resrec.name->c);
3508 rr->uselease = mDNSfalse;
3509 SendRecordRegistration(m, rr);
3510 return;
3511 }
3512 LogMsg("hndlRecordUpdateReply: Registration of record %##s type %d failed with error %ld", rr->resrec.name->c, rr->resrec.rrtype, err);
3513 return;
3514 }
3515 }
3516
3517 if (rr->state == regState_Unregistered) // Should never happen
3518 {
3519 LogMsg("hndlRecordUpdateReply rr->state == regState_Unregistered %s", ARDisplayString(m, rr));
3520 return;
3521 }
3522
3523 if (rr->QueuedRData && rr->state == regState_Registered)
3524 {
3525 rr->state = regState_UpdatePending;
3526 rr->InFlightRData = rr->QueuedRData;
3527 rr->InFlightRDLen = rr->QueuedRDLen;
3528 rr->OrigRData = rr->resrec.rdata;
3529 rr->OrigRDLen = rr->resrec.rdlength;
3530 rr->QueuedRData = mDNSNULL;
3531 SendRecordRegistration(m, rr);
3532 return;
3533 }
3534
3535 if (InvokeCallback && rr->RecordCallback)
3536 {
3537 mDNS_DropLockBeforeCallback();
3538 rr->RecordCallback(m, rr, err);
3539 mDNS_ReclaimLockAfterCallback();
3540 }
3541 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
3542 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
3543 }
3544
3545 mDNSexport void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 *pkt, mDNSu16 len)
3546 {
3547 NATTraversalInfo *ptr;
3548 NATAddrReply *AddrReply = (NATAddrReply *)pkt;
3549 NATPortMapReply *PortMapReply = (NATPortMapReply *)pkt;
3550 mDNSu32 nat_elapsed, our_elapsed;
3551
3552 // Minimum packet is vers (1) opcode (1) err (2) upseconds (4) = 8 bytes
3553 if (!AddrReply->err && len < 8) { LogMsg("NAT Traversal message too short (%d bytes)", len); return; }
3554 if (AddrReply->vers != NATMAP_VERS) { LogMsg("Received NAT Traversal response with version %d (expected %d)", pkt[0], NATMAP_VERS); return; }
3555
3556 // Read multi-byte numeric values (fields are identical in a NATPortMapReply)
3557 AddrReply->err = (mDNSu16) ( (mDNSu16)pkt[2] << 8 | pkt[3]);
3558 AddrReply->upseconds = (mDNSs32) ((mDNSs32)pkt[4] << 24 | (mDNSs32)pkt[5] << 16 | (mDNSs32)pkt[6] << 8 | pkt[7]);
3559
3560 nat_elapsed = AddrReply->upseconds - m->LastNATupseconds;
3561 our_elapsed = (m->timenow - m->LastNATReplyLocalTime) / mDNSPlatformOneSecond;
3562 LogOperation("uDNS_ReceiveNATPMPPacket %X upseconds %u nat_elapsed %d our_elapsed %d", AddrReply->opcode, AddrReply->upseconds, nat_elapsed, our_elapsed);
3563
3564 // We compute a conservative estimate of how much the NAT gateways's clock should have advanced
3565 // 1. We subtract 12.5% from our own measured elapsed time, to allow for NAT gateways that have an inacurate clock that runs slowly
3566 // 2. We add a two-second safety margin to allow for rounding errors:
3567 // -- e.g. if NAT gateway sends a packet at t=2.00 seconds, then one at t=7.99, that's virtually 6 seconds,
3568 // but based on the values in the packet (2,7) the apparent difference is only 5 seconds
3569 // -- similarly, if we're slow handling packets and/or we have coarse clock granularity, we could over-estimate the true interval
3570 // (e.g. t=1.99 seconds rounded to 1, and t=8.01 rounded to 8, gives an apparent difference of 7 seconds)
3571 if (AddrReply->upseconds < m->LastNATupseconds || nat_elapsed + 2 < our_elapsed - our_elapsed/8)
3572 { LogMsg("NAT gateway %#a rebooted", &m->Router); RecreateNATMappings(m); }
3573
3574 m->LastNATupseconds = AddrReply->upseconds;
3575 m->LastNATReplyLocalTime = m->timenow;
3576 ClearUPnPState(m); // We know this is a NAT-PMP base station, so discard any prior UPnP state
3577
3578 if (AddrReply->opcode == NATOp_AddrResponse)
3579 {
3580 if (!AddrReply->err && len < sizeof(NATAddrReply)) { LogMsg("NAT Traversal AddrResponse message too short (%d bytes)", len); return; }
3581 natTraversalHandleAddressReply(m, AddrReply->err, AddrReply->ExtAddr);
3582 }
3583 else if (AddrReply->opcode == NATOp_MapUDPResponse || AddrReply->opcode == NATOp_MapTCPResponse)
3584 {
3585 mDNSu8 Protocol = AddrReply->opcode & 0x7F;
3586 if (!PortMapReply->err)
3587 {
3588 if (len < sizeof(NATPortMapReply)) { LogMsg("NAT Traversal PortMapReply message too short (%d bytes)", len); return; }
3589 PortMapReply->NATRep_lease = (mDNSu32) ((mDNSu32)pkt[12] << 24 | (mDNSu32)pkt[13] << 16 | (mDNSu32)pkt[14] << 8 | pkt[15]);
3590 }
3591
3592 for (ptr = m->NATTraversals; ptr; ptr=ptr->next)
3593 if (ptr->Protocol == Protocol && mDNSSameIPPort(ptr->IntPort, PortMapReply->intport))
3594 natTraversalHandlePortMapReply(m, ptr, InterfaceID, PortMapReply->err, PortMapReply->extport, PortMapReply->NATRep_lease);
3595 }
3596 else { LogMsg("Received NAT Traversal response with version unknown opcode 0x%X", AddrReply->opcode); return; }
3597 }
3598
3599 // <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
3600 // <rdar://problem/4288449> Add check to avoid crashing NAT gateways that have buggy DNS relay code
3601 //
3602 // We know of bugs in home NAT gateways that cause them to crash if they receive certain DNS queries.
3603 // The DNS queries that make them crash are perfectly legal DNS queries, but even if they weren't,
3604 // the gateway shouldn't crash -- in today's world of viruses and network attacks, software has to
3605 // be written assuming that a malicious attacker could send them any packet, properly-formed or not.
3606 // Still, we don't want to be crashing people's home gateways, so we go out of our way to avoid
3607 // the queries that crash them.
3608 //
3609 // Some examples:
3610 //
3611 // 1. Any query where the name ends in ".in-addr.arpa." and the text before this is 32 or more bytes.
3612 // The query type does not need to be PTR -- the gateway will crash for any query type.
3613 // e.g. "ping long-name-crashes-the-buggy-router.in-addr.arpa" will crash one of these.
3614 //
3615 // 2. Any query that results in a large response with the TC bit set.
3616 //
3617 // 3. Any PTR query that doesn't begin with four decimal numbers.
3618 // These gateways appear to assume that the only possible PTR query is a reverse-mapping query
3619 // (e.g. "1.0.168.192.in-addr.arpa") and if they ever get a PTR query where the first four
3620 // labels are not all decimal numbers in the range 0-255, they handle that by crashing.
3621 // These gateways also ignore the remainder of the name following the four decimal numbers
3622 // -- whether or not it actually says in-addr.arpa, they just make up an answer anyway.
3623 //
3624 // The challenge therefore is to craft a query that will discern whether the DNS server
3625 // is one of these buggy ones, without crashing it. Furthermore we don't want our test
3626 // queries making it all the way to the root name servers, putting extra load on those
3627 // name servers and giving Apple a bad reputation. To this end we send this query:
3628 // dig -t ptr 1.0.0.127.dnsbugtest.1.0.0.127.in-addr.arpa.
3629 //
3630 // The text preceding the ".in-addr.arpa." is under 32 bytes, so it won't cause crash (1).
3631 // It will not yield a large response with the TC bit set, so it won't cause crash (2).
3632 // It starts with four decimal numbers, so it won't cause crash (3).
3633 // The name falls within the "1.0.0.127.in-addr.arpa." domain, the reverse-mapping name for the local
3634 // loopback address, and therefore the query will black-hole at the first properly-configured DNS server
3635 // it reaches, making it highly unlikely that this query will make it all the way to the root.
3636 //
3637 // Finally, the correct response to this query is NXDOMAIN or a similar error, but the
3638 // gateways that ignore the remainder of the name following the four decimal numbers
3639 // give themselves away by actually returning a result for this nonsense query.
3640
3641 mDNSlocal const domainname *DNSRelayTestQuestion = (const domainname*)
3642 "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\xa" "dnsbugtest"
3643 "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\x7" "in-addr" "\x4" "arpa";
3644
3645 // Returns mDNStrue if response was handled
3646 mDNSlocal mDNSBool uDNS_ReceiveTestQuestionResponse(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
3647 const mDNSAddr *const srcaddr, const mDNSIPPort srcport)
3648 {
3649 const mDNSu8 *ptr = msg->data;
3650 DNSQuestion q;
3651 DNSServer *s;
3652 mDNSu32 result = 0;
3653
3654 // 1. Find out if this is an answer to one of our test questions
3655 if (msg->h.numQuestions != 1) return(mDNSfalse);
3656 ptr = getQuestion(msg, ptr, end, mDNSInterface_Any, &q);
3657 if (!ptr) return(mDNSfalse);
3658 if (q.qtype != kDNSType_PTR || q.qclass != kDNSClass_IN) return(mDNSfalse);
3659 if (!SameDomainName(&q.qname, DNSRelayTestQuestion)) return(mDNSfalse);
3660
3661 // 2. If the DNS relay gave us a positive response, then it's got buggy firmware
3662 // else, if the DNS relay gave us an error or no-answer response, it passed our test
3663 if ((msg->h.flags.b[1] & kDNSFlag1_RC_Mask) == kDNSFlag1_RC_NoErr && msg->h.numAnswers > 0)
3664 result = DNSServer_Failed;
3665 else
3666 result = DNSServer_Passed;
3667
3668 // 3. Find occurrences of this server in our list, and mark them appropriately
3669 for (s = m->DNSServers; s; s = s->next)
3670 if (mDNSSameAddress(srcaddr, &s->addr) && mDNSSameIPPort(srcport, s->port) && s->teststate != result)
3671 {
3672 DNSQuestion *q;
3673 if (s->teststate != result)
3674 {
3675 s->teststate = result;
3676 if (result == DNSServer_Passed) LogOperation("DNS Server %#a:%d passed", srcaddr, mDNSVal16(srcport));
3677 else LogMsg("NOTE: Wide-Area Service Discovery disabled to avoid crashing defective DNS relay %#a:%d", srcaddr, mDNSVal16(srcport));
3678 }
3679 if (result == DNSServer_Passed) // Unblock any questions that were waiting for this result
3680 for (q = m->Questions; q; q=q->next)
3681 if (q->qDNSServer == s)
3682 { q->LastQTime = m->timenow - q->ThisQInterval; m->NextScheduledQuery = m->timenow; }
3683 }
3684
3685 return(mDNStrue); // Return mDNStrue to tell uDNS_ReceiveMsg it doesn't need to process this packet further
3686 }
3687
3688 // Called from mDNSCoreReceive with the lock held
3689 mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport)
3690 {
3691 DNSQuestion *qptr;
3692 mStatus err = mStatus_NoError;
3693
3694 mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
3695 mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
3696 mDNSu8 QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
3697 mDNSu8 rcode = (mDNSu8)(msg->h.flags.b[1] & kDNSFlag1_RC_Mask);
3698
3699 (void)srcport; // Unused
3700
3701 debugf("uDNS_ReceiveMsg from %#-15a with "
3702 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
3703 srcaddr,
3704 msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,",
3705 msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,",
3706 msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,",
3707 msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
3708
3709 if (QR_OP == StdR)
3710 {
3711 //if (srcaddr && recvLLQResponse(m, msg, end, srcaddr, srcport)) return;
3712 if (uDNS_ReceiveTestQuestionResponse(m, msg, end, srcaddr, srcport)) return;
3713 for (qptr = m->Questions; qptr; qptr = qptr->next)
3714 if (msg->h.flags.b[0] & kDNSFlag0_TC && mDNSSameOpaque16(qptr->TargetQID, msg->h.id) && m->timenow - qptr->LastQTime < RESPONSE_WINDOW)
3715 {
3716 if (!srcaddr) LogMsg("uDNS_ReceiveMsg: TCP DNS response had TC bit set: ignoring");
3717 else if (qptr->tcp)
3718 {
3719 // There may be a race condition here, if the server decides to drop the connection just as we decide to reuse it
3720 // For now it should not be serious because our normal retry logic (as used to handle UDP packet loss)
3721 // should take care of it but later we may want to look at handling this case explicitly
3722 LogOperation("uDNS_ReceiveMsg: Using existing TCP connection for %##s (%s)", qptr->qname.c, DNSTypeName(qptr->qtype));
3723 mDNS_DropLockBeforeCallback();
3724 tcpCallback(qptr->tcp->sock, qptr->tcp, mDNStrue, mStatus_NoError);
3725 mDNS_ReclaimLockAfterCallback();
3726 }
3727 else qptr->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_Zero, srcaddr, srcport, qptr, mDNSNULL, mDNSNULL);
3728 }
3729 }
3730
3731 if (QR_OP == UpdateR)
3732 {
3733 mDNSu32 lease = GetPktLease(m, msg, end);
3734 mDNSs32 expire = m->timenow + (mDNSs32)lease * mDNSPlatformOneSecond;
3735
3736 //rcode = kDNSFlag1_RC_SrvErr; // Simulate server failure (rcode 2)
3737
3738 if (CurrentServiceRecordSet)
3739 LogMsg("uDNS_ReceiveMsg ERROR CurrentServiceRecordSet already set");
3740 CurrentServiceRecordSet = m->ServiceRegistrations;
3741
3742 while (CurrentServiceRecordSet)
3743 {
3744 ServiceRecordSet *sptr = CurrentServiceRecordSet;
3745 CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next;
3746
3747 if (mDNSSameOpaque16(sptr->id, msg->h.id))
3748 {
3749 err = checkUpdateResult(m, sptr->RR_SRV.resrec.name, rcode, msg, end);
3750 if (!err && sptr->srs_uselease && lease)
3751 if (sptr->RR_SRV.expire - expire >= 0 || sptr->state != regState_UpdatePending)
3752 sptr->RR_SRV.expire = expire;
3753 hndlServiceUpdateReply(m, sptr, err);
3754 CurrentServiceRecordSet = mDNSNULL;
3755 return;
3756 }
3757 }
3758
3759 if (m->CurrentRecord)
3760 LogMsg("uDNS_ReceiveMsg ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
3761 m->CurrentRecord = m->ResourceRecords;
3762 while (m->CurrentRecord)
3763 {
3764 AuthRecord *rptr = m->CurrentRecord;
3765 m->CurrentRecord = m->CurrentRecord->next;
3766 if (mDNSSameOpaque16(rptr->id, msg->h.id))
3767 {
3768 err = checkUpdateResult(m, rptr->resrec.name, rcode, msg, end);
3769 if (!err && rptr->uselease && lease)
3770 if (rptr->expire - expire >= 0 || rptr->state != regState_UpdatePending)
3771 rptr->expire = expire;
3772 hndlRecordUpdateReply(m, rptr, err);
3773 m->CurrentRecord = mDNSNULL;
3774 return;
3775 }
3776 }
3777 }
3778 debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg->h.id));
3779 }
3780
3781 // ***************************************************************************
3782 #if COMPILER_LIKES_PRAGMA_MARK
3783 #pragma mark - Query Routines
3784 #endif
3785
3786 mDNSexport void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease)
3787 {
3788 mDNSu8 *end;
3789 LLQOptData llq;
3790 mStatus err;
3791
3792 // If this is supposed to be a private question and the server dropped the TCP connection,
3793 // we don't want to cancel it with a clear-text UDP packet, and and it's not worth the expense of
3794 // setting up a new TLS session just to cancel the outstanding LLQ, so we just let it expire naturally
3795 if (lease == 0 && q->AuthInfo && !q->tcp) return;
3796
3797 if (q->AuthInfo && !q->tcp)
3798 {
3799 //LogOperation("sendLLQRefresh setting up new TLS session %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3800 q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, q, mDNSNULL, mDNSNULL);
3801 q->LastQTime = m->timenow;
3802 SetNextQueryTime(m, q);
3803 return;
3804 }
3805
3806 if ((q->state == LLQ_Established && q->ntries >= kLLQ_MAX_TRIES) || q->expire - m->timenow < 0)
3807 {
3808 LogMsg("Unable to refresh LLQ %##s (%s) - will retry in %d minutes", q->qname.c, DNSTypeName(q->qtype), LLQ_POLL_INTERVAL/3600);
3809 StartLLQPolling(m,q);
3810 return;
3811 }
3812
3813 llq.vers = kLLQ_Vers;
3814 llq.llqOp = kLLQOp_Refresh;
3815 llq.err = q->tcp ? GetLLQEventPort(m, &q->servAddr) : LLQErr_NoError; // If using TCP tell server what UDP port to send notifications to
3816 llq.id = q->id;
3817 llq.llqlease = lease;
3818
3819 InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
3820 end = putLLQ(&m->omsg, m->omsg.data, q, &llq, mDNStrue);
3821 if (!end) { LogMsg("ERROR: sendLLQRefresh - putLLQ"); return; }
3822
3823 err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, q->AuthInfo);
3824 if (err) debugf("ERROR: sendLLQRefresh - mDNSSendDNSMessage returned %ld", err);
3825
3826 q->ntries++;
3827
3828 debugf("sendLLQRefresh ntries %d %##s (%s)", q->ntries, q->qname.c, DNSTypeName(q->qtype));
3829
3830 q->LastQTime = m->timenow;
3831 SetNextQueryTime(m, q);
3832 }
3833
3834 mDNSexport void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
3835 {
3836 DNSQuestion *q = (DNSQuestion *)zoneInfo->ZoneDataContext;
3837
3838 mDNS_Lock(m);
3839
3840 // If we get here it means that the GetZoneData operation has completed, and is is about to cancel
3841 // its question and free the ZoneData memory. We no longer need to hold onto our pointer (which
3842 // we use for cleaning up if our LLQ is cancelled *before* the GetZoneData operation has completes).
3843 q->nta = mDNSNULL;
3844 q->servAddr = zeroAddr;
3845 q->servPort = zeroIPPort;
3846
3847 if (!err && zoneInfo && !mDNSIPPortIsZero(zoneInfo->Port))
3848 {
3849 q->servAddr = zoneInfo->Addr;
3850 q->servPort = zoneInfo->Port;
3851 q->AuthInfo = zoneInfo->ZonePrivate ? GetAuthInfoForName_internal(m, &q->qname) : mDNSNULL;
3852 q->ntries = 0;
3853 LogOperation("LLQGotZoneData %#a:%d", &q->servAddr, mDNSVal16(q->servPort));
3854 startLLQHandshake(m, q);
3855 }
3856 else
3857 StartLLQPolling(m,q);
3858
3859 mDNS_Unlock(m);
3860 }
3861
3862 // Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
3863 mDNSlocal void PrivateQueryGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
3864 {
3865 DNSQuestion *q = (DNSQuestion *) zoneInfo->ZoneDataContext;
3866
3867 LogOperation("PrivateQueryGotZoneData %##s (%s) err %d Zone %##s Private %d", q->qname.c, DNSTypeName(q->qtype), err, zoneInfo->ZoneName.c, zoneInfo->ZonePrivate);
3868
3869 // If we get here it means that the GetZoneData operation has completed, and is is about to cancel
3870 // its question and free the ZoneData memory. We no longer need to hold onto our pointer (which
3871 // we use for cleaning up if our LLQ is cancelled *before* the GetZoneData operation has completes).
3872 q->nta = mDNSNULL;
3873
3874 if (err)
3875 {
3876 LogMsg("ERROR: PrivateQueryGotZoneData %##s (%s) invoked with error code %ld", q->qname.c, DNSTypeName(q->qtype), err);
3877 return;
3878 }
3879
3880 if (!zoneInfo->ZonePrivate)
3881 {
3882 debugf("Private port lookup failed -- retrying without TLS -- %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3883 q->AuthInfo = mDNSNULL; // Clear AuthInfo so we try again non-private
3884 q->ThisQInterval = InitialQuestionInterval;
3885 q->LastQTime = m->timenow - q->ThisQInterval;
3886 mDNS_Lock(m);
3887 SetNextQueryTime(m, q);
3888 mDNS_Unlock(m);
3889 return;
3890 // Next call to uDNS_CheckCurrentQuestion() will do this as a non-private query
3891 }
3892
3893 if (!q->AuthInfo)
3894 {
3895 LogMsg("ERROR: PrivateQueryGotZoneData: cannot find credentials for q %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3896 return;
3897 }
3898
3899 q->TargetQID = mDNS_NewMessageID(m);
3900 if (q->tcp) DisposeTCPConn(q->tcp);
3901 q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &zoneInfo->Addr, zoneInfo->Port, q, mDNSNULL, mDNSNULL);
3902 }
3903
3904 // ***************************************************************************
3905 #if COMPILER_LIKES_PRAGMA_MARK
3906 #pragma mark - Dynamic Updates
3907 #endif
3908
3909 // Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
3910 mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneData)
3911 {
3912 AuthRecord *newRR = (AuthRecord*)zoneData->ZoneDataContext;
3913 AuthRecord *ptr;
3914
3915 if (m->mDNS_busy != m->mDNS_reentrancy)
3916 LogMsg("RecordRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
3917
3918 newRR->nta = mDNSNULL;
3919
3920 // make sure record is still in list (!!!)
3921 for (ptr = m->ResourceRecords; ptr; ptr = ptr->next) if (ptr == newRR) break;
3922 if (!ptr) { LogMsg("RecordRegistrationGotZoneData - RR no longer in list. Discarding."); return; }
3923
3924 // check error/result
3925 if (err)
3926 {
3927 if (err != mStatus_NoSuchNameErr) LogMsg("RecordRegistrationGotZoneData: error %ld", err);
3928 return;
3929 }
3930
3931 if (!zoneData) { LogMsg("ERROR: RecordRegistrationGotZoneData invoked with NULL result and no error"); return; }
3932
3933 if (newRR->resrec.rrclass != zoneData->ZoneClass)
3934 {
3935 LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)", newRR->resrec.rrclass, zoneData->ZoneClass);
3936 return;
3937 }
3938
3939 // Don't try to do updates to the root name server.
3940 // We might be tempted also to block updates to any single-label name server (e.g. com, edu, net, etc.) but some
3941 // organizations use their own private pseudo-TLD, like ".home", etc, and we don't want to block that.
3942 if (zoneData->ZoneName.c[0] == 0)
3943 {
3944 LogOperation("RecordRegistrationGotZoneData: No name server found claiming responsibility for \"%##s\"!", newRR->resrec.name->c);
3945 return;
3946 }
3947
3948 // Store discovered zone data
3949 AssignDomainName(&newRR->zone, &zoneData->ZoneName);
3950 newRR->UpdateServer = zoneData->Addr;
3951 newRR->UpdatePort = zoneData->Port;
3952 newRR->Private = zoneData->ZonePrivate;
3953 debugf("RecordRegistrationGotZoneData: Set newRR->UpdateServer %##s %##s to %#a:%d",
3954 newRR->resrec.name->c, zoneData->ZoneName.c, &newRR->UpdateServer, mDNSVal16(newRR->UpdatePort));
3955
3956 if (mDNSIPPortIsZero(zoneData->Port) || mDNSAddressIsZero(&zoneData->Addr))
3957 {
3958 LogOperation("RecordRegistrationGotZoneData: No _dns-update._udp service found for \"%##s\"!", newRR->resrec.name->c);
3959 return;
3960 }
3961
3962 mDNS_Lock(m); // SendRecordRegistration expects to be called with the lock held
3963 SendRecordRegistration(m, newRR);
3964 mDNS_Unlock(m);
3965 }
3966
3967 mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
3968 {
3969 mDNSu8 *ptr = m->omsg.data;
3970 mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
3971
3972 if (mDNSIPv4AddressIsZero(rr->UpdateServer.ip.v4)) // Don't know our UpdateServer yet
3973 {
3974 rr->LastAPTime = m->timenow;
3975 if (rr->ThisAPInterval < mDNSPlatformOneSecond * 5)
3976 rr->ThisAPInterval = mDNSPlatformOneSecond * 5;
3977 return;
3978 }
3979
3980 InitializeDNSMessage(&m->omsg.h, rr->id, UpdateReqFlags);
3981
3982 ptr = putZone(&m->omsg, ptr, end, &rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
3983 if (ptr) ptr = putDeletionRecord(&m->omsg, ptr, &rr->resrec);
3984 if (!ptr)
3985 {
3986 LogMsg("SendRecordDeregistration Error: could not contruct deregistration packet for %s", ARDisplayString(m, rr));
3987 if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr);
3988 }
3989 else
3990 {
3991 if (rr->Private)
3992 {
3993 LogOperation("SendRecordDeregistration TCP %p %s", rr->tcp, ARDisplayString(m, rr));
3994 if (rr->tcp) LogOperation("SendRecordDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m, rr));
3995 if (rr->tcp) DisposeTCPConn(rr->tcp);
3996 rr->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, mDNSNULL, rr);
3997 if (!rr->tcp) rr->ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2)
3998 else if (rr->ThisAPInterval < mDNSPlatformOneSecond * 30) rr->ThisAPInterval = mDNSPlatformOneSecond * 30;
3999 SetRecordRetry(m, rr, mStatus_NoError);
4000 }
4001 else
4002 {
4003 mStatus err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name));
4004 if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %ld", err);
4005 if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr); // Don't touch rr after this
4006 }
4007 }
4008 }
4009
4010 mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr)
4011 {
4012 switch (rr->state)
4013 {
4014 case regState_NATMap: LogMsg("regState_NATMap %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
4015 case regState_ExtraQueued: rr->state = regState_Unregistered; break;
4016 case regState_Refresh:
4017 case regState_Pending:
4018 case regState_UpdatePending:
4019 case regState_FetchingZoneData:
4020 case regState_Registered: break;
4021 case regState_DeregPending: break;
4022 case regState_DeregDeferred: LogMsg("regState_DeregDeferred %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
4023 case regState_Unregistered: LogMsg("regState_Unregistered %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
4024 case regState_NATError: LogMsg("regState_NATError %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
4025 case regState_NoTarget: LogMsg("regState_NoTarget %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
4026 default: LogMsg("uDNS_DeregisterRecord: State %d for %##s type %s", rr->state, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
4027 }
4028
4029 if (rr->state != regState_Unregistered) { rr->state = regState_DeregPending; SendRecordDeregistration(m, rr); }
4030 return mStatus_NoError;
4031 }
4032
4033 // Called with lock held
4034 mDNSexport mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs)
4035 {
4036 char *errmsg = "Unknown State";
4037
4038 if (m->mDNS_busy != m->mDNS_reentrancy+1)
4039 LogMsg("uDNS_DeregisterService: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
4040
4041 // don't re-register with a new target following deregistration
4042 srs->SRVChanged = srs->SRVUpdateDeferred = mDNSfalse;
4043
4044 if (srs->nta) { CancelGetZoneData(m, srs->nta); srs->nta = mDNSNULL; }
4045
4046 if (srs->NATinfo.clientContext)
4047 {
4048 mDNS_StopNATOperation_internal(m, &srs->NATinfo);
4049 srs->NATinfo.clientContext = mDNSNULL;
4050 }
4051
4052 switch (srs->state)
4053 {
4054 case regState_Unregistered:
4055 debugf("uDNS_DeregisterService - service %##s not registered", srs->RR_SRV.resrec.name->c);
4056 return mStatus_BadReferenceErr;
4057 case regState_DeregPending:
4058 case regState_DeregDeferred:
4059 debugf("Double deregistration of service %##s", srs->RR_SRV.resrec.name->c);
4060 return mStatus_NoError;
4061 case regState_NATError: // not registered
4062 case regState_NATMap: // not registered
4063 case regState_NoTarget: // not registered
4064 unlinkSRS(m, srs);
4065 srs->state = regState_Unregistered;
4066 mDNS_DropLockBeforeCallback();
4067 srs->ServiceCallback(m, srs, mStatus_MemFree);
4068 mDNS_ReclaimLockAfterCallback();
4069 return mStatus_NoError;
4070 case regState_Pending:
4071 case regState_Refresh:
4072 case regState_UpdatePending:
4073 case regState_FetchingZoneData:
4074 case regState_Registered:
4075 srs->state = regState_DeregPending;
4076 SendServiceDeregistration(m, srs);
4077 return mStatus_NoError;
4078 case regState_ExtraQueued: // only for record registrations
4079 errmsg = "bad state (regState_ExtraQueued)";
4080 goto error;
4081 default: LogMsg("uDNS_DeregisterService: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c);
4082 }
4083
4084 error:
4085 LogMsg("Error, uDNS_DeregisterService: %s", errmsg);
4086 return mStatus_BadReferenceErr;
4087 }
4088
4089 mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr)
4090 {
4091 ServiceRecordSet *parent = mDNSNULL;
4092 AuthRecord *rptr;
4093 regState_t *stateptr = mDNSNULL;
4094
4095 // find the record in registered service list
4096 for (parent = m->ServiceRegistrations; parent; parent = parent->uDNS_next)
4097 if (&parent->RR_TXT == rr) { stateptr = &parent->state; break; }
4098
4099 if (!parent)
4100 {
4101 // record not part of a service - check individual record registrations
4102 for (rptr = m->ResourceRecords; rptr; rptr = rptr->next)
4103 if (rptr == rr) { stateptr = &rr->state; break; }
4104 if (!rptr) goto unreg_error;
4105 }
4106
4107 switch(*stateptr)
4108 {
4109 case regState_DeregPending:
4110 case regState_DeregDeferred:
4111 case regState_Unregistered:
4112 // not actively registered
4113 goto unreg_error;
4114
4115 case regState_FetchingZoneData:
4116 case regState_NATMap:
4117 case regState_ExtraQueued:
4118 case regState_NoTarget:
4119 // change rdata directly since it hasn't been sent yet
4120 if (rr->UpdateCallback) rr->UpdateCallback(m, rr, rr->resrec.rdata);
4121 SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
4122 rr->NewRData = mDNSNULL;
4123 return mStatus_NoError;
4124
4125 case regState_Pending:
4126 case regState_Refresh:
4127 case regState_UpdatePending:
4128 // registration in-flight. queue rdata and return
4129 if (rr->QueuedRData && rr->UpdateCallback)
4130 // if unsent rdata is already queued, free it before we replace it
4131 rr->UpdateCallback(m, rr, rr->QueuedRData);
4132 rr->QueuedRData = rr->NewRData;
4133 rr->QueuedRDLen = rr->newrdlength;
4134 rr->NewRData = mDNSNULL;
4135 return mStatus_NoError;
4136
4137 case regState_Registered:
4138 rr->OrigRData = rr->resrec.rdata;
4139 rr->OrigRDLen = rr->resrec.rdlength;
4140 rr->InFlightRData = rr->NewRData;
4141 rr->InFlightRDLen = rr->newrdlength;
4142 rr->NewRData = mDNSNULL;
4143 *stateptr = regState_UpdatePending;
4144 if (parent) SendServiceRegistration(m, parent);
4145 else SendRecordRegistration(m, rr);
4146 return mStatus_NoError;
4147
4148 case regState_NATError:
4149 LogMsg("ERROR: uDNS_UpdateRecord called for record %##s with bad state regState_NATError", rr->resrec.name->c);
4150 return mStatus_UnknownErr; // states for service records only
4151
4152 default: LogMsg("uDNS_UpdateRecord: Unknown state %d for %##s", *stateptr, rr->resrec.name->c);
4153 }
4154
4155 unreg_error:
4156 LogMsg("Requested update of record %##s type %d, part of service not currently registered",
4157 rr->resrec.name->c, rr->resrec.rrtype);
4158 return mStatus_Invalid;
4159 }
4160
4161 // ***************************************************************************
4162 #if COMPILER_LIKES_PRAGMA_MARK
4163 #pragma mark - Periodic Execution Routines
4164 #endif
4165
4166 // See comments above for DNSRelayTestQuestion
4167 // If this is the kind of query that has the risk of crashing buggy DNS servers, we do a test question first
4168 mDNSlocal mDNSBool NoTestQuery(DNSQuestion *q)
4169 {
4170 int i;
4171 mDNSu8 *p = q->qname.c;
4172 if (q->AuthInfo) return(mDNStrue); // Don't need a test query for private queries sent directly to authoritative server over TLS/TCP
4173 if (q->qtype != kDNSType_PTR) return(mDNStrue); // Don't need a test query for any non-PTR queries
4174 for (i=0; i<4; i++) // If qname does not begin with num.num.num.num, can't skip the test query
4175 {
4176 if (p[0] < 1 || p[0] > 3) return(mDNSfalse);
4177 if ( p[1] < '0' || p[1] > '9' ) return(mDNSfalse);
4178 if (p[0] >= 2 && (p[2] < '0' || p[2] > '9')) return(mDNSfalse);
4179 if (p[0] >= 3 && (p[3] < '0' || p[3] > '9')) return(mDNSfalse);
4180 p += 1 + p[0];
4181 }
4182 // If remainder of qname is ".in-addr.arpa.", this is a vanilla reverse-mapping query and
4183 // we can safely do it without needing a test query first, otherwise we need the test query.
4184 return(SameDomainName((domainname*)p, (const domainname*)"\x7" "in-addr" "\x4" "arpa"));
4185 }
4186
4187 // The question to be checked is not passed in as an explicit parameter;
4188 // instead it is implicit that the question to be checked is m->CurrentQuestion.
4189 mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
4190 {
4191 DNSQuestion *q = m->CurrentQuestion;
4192 mDNSs32 sendtime = q->LastQTime + q->ThisQInterval;
4193 // Don't allow sendtime to be earlier than SuppressStdPort53Queries
4194 if (!q->LongLived && m->SuppressStdPort53Queries && sendtime - m->SuppressStdPort53Queries < 0)
4195 sendtime = m->SuppressStdPort53Queries;
4196 if (m->timenow - sendtime < 0) return;
4197
4198 if (q->LongLived)
4199 {
4200 switch (q->state)
4201 {
4202 case LLQ_InitialRequest: startLLQHandshake(m, q); break;
4203 case LLQ_SecondaryRequest: sendChallengeResponse(m, q, mDNSNULL); break;
4204 case LLQ_Established: sendLLQRefresh(m, q, q->origLease); break;
4205 case LLQ_Poll: break; // Do nothing (handled below)
4206 }
4207 }
4208
4209 // We repeat the check above (rather than just making this the "else" case) because startLLQHandshake can change q->state to LLQ_Poll
4210 if (!(q->LongLived && q->state != LLQ_Poll))
4211 {
4212 if (q->qDNSServer && q->qDNSServer->teststate != DNSServer_Disabled)
4213 {
4214 mDNSu8 *end = m->omsg.data;
4215 mStatus err = mStatus_NoError;
4216 DomainAuthInfo *private = mDNSNULL;
4217
4218 if (q->qDNSServer->teststate != DNSServer_Untested || NoTestQuery(q))
4219 {
4220 InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
4221 end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
4222 private = q->AuthInfo;
4223 }
4224 else if (m->timenow - q->qDNSServer->lasttest >= INIT_UCAST_POLL_INTERVAL) // Make sure at least three seconds has elapsed since last test query
4225 {
4226 LogOperation("Sending DNS test query to %#a:%d", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port));
4227 q->ThisQInterval = INIT_UCAST_POLL_INTERVAL / QuestionIntervalStep;
4228 q->qDNSServer->lasttest = m->timenow;
4229 InitializeDNSMessage(&m->omsg.h, mDNS_NewMessageID(m), uQueryFlags);
4230 end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, DNSRelayTestQuestion, kDNSType_PTR, kDNSClass_IN);
4231 }
4232
4233 if (end > m->omsg.data && (q->qDNSServer->teststate != DNSServer_Failed || NoTestQuery(q)))
4234 {
4235 //LogMsg("uDNS_CheckCurrentQuestion %d %p %##s (%s)", sendtime - m->timenow, private, q->qname.c, DNSTypeName(q->qtype));
4236 if (private)
4237 {
4238 if (q->nta) CancelGetZoneData(m, q->nta);
4239 q->nta = StartGetZoneData(m, &q->qname, q->LongLived ? ZoneServiceLLQ : ZoneServiceQuery, PrivateQueryGotZoneData, q);
4240 q->ThisQInterval = (LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10)) / QuestionIntervalStep;
4241 }
4242 else
4243 {
4244 err = mDNSSendDNSMessage(m, &m->omsg, end, q->qDNSServer->interface, &q->qDNSServer->addr, q->qDNSServer->port, mDNSNULL, mDNSNULL);
4245 m->SuppressStdPort53Queries = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+99)/100);
4246 }
4247 }
4248
4249 if (err) debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %ld", err); // surpress syslog messages if we have no network
4250 else
4251 {
4252 q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep; // Only increase interval if send succeeded
4253 if (q->ThisQInterval > MAX_UCAST_POLL_INTERVAL)
4254 q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
4255 LogOperation("Increased ThisQInterval to %d for %##s (%s)", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype));
4256 }
4257 q->LastQTime = m->timenow;
4258 SetNextQueryTime(m, q);
4259 }
4260 else
4261 {
4262 // If we have no server for this query, or the only server is a disabled one, then we deliver
4263 // a transient failure indication to the client. This is important for things like iPhone
4264 // where we want to return timely feedback to the user when no network is available.
4265 // After calling MakeNegativeCacheRecord() we store the resulting record in the
4266 // cache so that it will be visible to other clients asking the same question.
4267 // (When we have a group of identical questions, only the active representative of the group gets
4268 // passed to uDNS_CheckCurrentQuestion -- we only want one set of query packets hitting the wire --
4269 // but we want *all* of the questions to get answer callbacks.)
4270
4271 CacheRecord *rr;
4272 const mDNSu32 slot = HashSlot(&q->qname);
4273 CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
4274 if (cg)
4275 for (rr = cg->members; rr; rr=rr->next)
4276 if (SameNameRecordAnswersQuestion(&rr->resrec, q)) mDNS_PurgeCacheResourceRecord(m, rr);
4277
4278 if (!q->qDNSServer) LogOperation("uDNS_CheckCurrentQuestion no DNS server for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4279 else LogMsg("uDNS_CheckCurrentQuestion DNS server %#a:%d for %##s is disabled", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qname.c);
4280
4281 MakeNegativeCacheRecord(m, &q->qname, q->qnamehash, q->qtype, q->qclass, 60);
4282 // Inactivate this question until the next change of DNS servers (do this before AnswerCurrentQuestionWithResourceRecord)
4283 q->ThisQInterval = 0;
4284 CreateNewCacheEntry(m, slot, cg);
4285 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
4286 // MUST NOT touch m->CurrentQuestion (or q) after this -- client callback could have deleted it
4287 }
4288 }
4289 }
4290
4291 mDNSlocal void CheckNATMappings(mDNS *m)
4292 {
4293 mStatus err = mStatus_NoError;
4294 mDNSBool rfc1918 = mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4);
4295 mDNSBool HaveRoutable = !rfc1918 && !mDNSIPv4AddressIsZero(m->AdvertisedV4.ip.v4);
4296 m->NextScheduledNATOp = m->timenow + 0x3FFFFFFF;
4297
4298 if (HaveRoutable) m->ExternalAddress = m->AdvertisedV4.ip.v4;
4299
4300 if (m->NATTraversals && rfc1918) // Do we need to open NAT-PMP socket to receive multicast announcements from router?
4301 {
4302 if (m->NATMcastRecvskt == mDNSNULL) // If we are behind a NAT and the socket hasn't been opened yet, open it
4303 {
4304 m->NATMcastRecvskt = mDNSPlatformUDPSocket(m, NATPMPAnnouncementPort);
4305 m->NATMcastRecvsk2 = mDNSPlatformUDPSocket(m, NATPMPPort); // For backwards compatibility with older base stations that announce on 5351
4306 if (!m->NATMcastRecvskt) LogMsg("CheckNATMappings: Failed to allocate port 5350 UDP multicast socket for NAT-PMP announcements");
4307 if (!m->NATMcastRecvsk2) LogOperation("CheckNATMappings: Failed to allocate port 5351 UDP multicast socket for NAT-PMP announcements");
4308 }
4309 }
4310 else // else, we don't want to listen for announcements, so close them if they're open
4311 {
4312 if (m->NATMcastRecvskt) { mDNSPlatformUDPClose(m->NATMcastRecvskt); m->NATMcastRecvskt = mDNSNULL; }
4313 if (m->NATMcastRecvsk2) { mDNSPlatformUDPClose(m->NATMcastRecvsk2); m->NATMcastRecvsk2 = mDNSNULL; }
4314 }
4315
4316 if (m->NATTraversals)
4317 {
4318 if (m->timenow - m->retryGetAddr >= 0)
4319 {
4320 err = uDNS_SendNATMsg(m, mDNSNULL); // Will also do UPnP discovery for us, if necessary
4321 if (!err)
4322 {
4323 if (m->retryIntervalGetAddr < NATMAP_INIT_RETRY) m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
4324 else if (m->retryIntervalGetAddr < NATMAP_MAX_RETRY_INTERVAL / 2) m->retryIntervalGetAddr *= 2;
4325 else m->retryIntervalGetAddr = NATMAP_MAX_RETRY_INTERVAL;
4326 }
4327 // Always update m->retryGetAddr, even if we fail to send the packet. Otherwise in cases where we can't send the packet
4328 // (like when we have no active interfaces) we'll spin in an infinite loop repeatedly failing to send the packet
4329 m->retryGetAddr = m->timenow + m->retryIntervalGetAddr;
4330 }
4331 // Even when we didn't send the GetAddr packet, still need to make sure NextScheduledNATOp is set correctly
4332 if (m->NextScheduledNATOp - m->retryGetAddr > 0)
4333 m->NextScheduledNATOp = m->retryGetAddr;
4334 }
4335
4336 if (m->CurrentNATTraversal) LogMsg("WARNING m->CurrentNATTraversal already in use");
4337 m->CurrentNATTraversal = m->NATTraversals;
4338
4339 while (m->CurrentNATTraversal)
4340 {
4341 NATTraversalInfo *cur = m->CurrentNATTraversal;
4342 m->CurrentNATTraversal = m->CurrentNATTraversal->next;
4343
4344 if (HaveRoutable) // If not RFC 1918 address, our own address and port are effectively our external address and port
4345 {
4346 cur->ExpiryTime = 0;
4347 cur->NewResult = mStatus_NoError;
4348 }
4349 else if (cur->Protocol) // Check if it's time to send port mapping packets
4350 {
4351 if (m->timenow - cur->retryPortMap >= 0) // Time to do something with this mapping
4352 {
4353 if (cur->ExpiryTime && cur->ExpiryTime - m->timenow < 0) // Mapping has expired
4354 {
4355 cur->ExpiryTime = 0;
4356 cur->retryInterval = NATMAP_INIT_RETRY;
4357 }
4358
4359 //LogMsg("uDNS_SendNATMsg");
4360 err = uDNS_SendNATMsg(m, cur);
4361
4362 if (cur->ExpiryTime) // If have active mapping then set next renewal time halfway to expiry
4363 NATSetNextRenewalTime(m, cur);
4364 else // else no mapping; use exponential backoff sequence
4365 {
4366 if (cur->retryInterval < NATMAP_INIT_RETRY ) cur->retryInterval = NATMAP_INIT_RETRY;
4367 else if (cur->retryInterval < NATMAP_MAX_RETRY_INTERVAL / 2) cur->retryInterval *= 2;
4368 else cur->retryInterval = NATMAP_MAX_RETRY_INTERVAL;
4369 cur->retryPortMap = m->timenow + cur->retryInterval;
4370 }
4371 }
4372
4373 if (m->NextScheduledNATOp - cur->retryPortMap > 0)
4374 m->NextScheduledNATOp = cur->retryPortMap;
4375 }
4376
4377 // Notify the client if necessary. We invoke the callback if:
4378 // (1) we have an ExternalAddress, or we've tried and failed a couple of times to discover it
4379 // and (2) the client doesn't want a mapping, or the client won't need a mapping, or the client has a successful mapping, or we've tried and failed a couple of times
4380 // and (3) we have new data to give the client that's changed since the last callback
4381 if (!mDNSIPv4AddressIsZero(m->ExternalAddress) || m->retryIntervalGetAddr > NATMAP_INIT_RETRY * 8)
4382 {
4383 const mDNSIPPort ExternalPort = HaveRoutable ? cur->IntPort :
4384 !mDNSIPv4AddressIsZero(m->ExternalAddress) && cur->ExpiryTime ? cur->RequestedPort : zeroIPPort;
4385 if (!cur->Protocol || HaveRoutable || cur->ExpiryTime || cur->retryInterval > NATMAP_INIT_RETRY * 8)
4386 if (!mDNSSameIPv4Address(cur->ExternalAddress, m->ExternalAddress) ||
4387 !mDNSSameIPPort (cur->ExternalPort, ExternalPort) ||
4388 cur->Result != cur->NewResult)
4389 {
4390 //LogMsg("NAT callback %d %d %d", cur->Protocol, cur->ExpiryTime, cur->retryInterval);
4391 if (cur->Protocol && mDNSIPPortIsZero(ExternalPort) && !mDNSIPv4AddressIsZero(m->Router.ip.v4))
4392 LogMsg("Failed to obtain NAT port mapping from router %#a external address %.4a internal port %d",
4393 &m->Router, &m->ExternalAddress, mDNSVal16(cur->IntPort));
4394 cur->ExternalAddress = m->ExternalAddress;
4395 cur->ExternalPort = ExternalPort;
4396 cur->Lifetime = cur->ExpiryTime && !mDNSIPPortIsZero(ExternalPort) ?
4397 (cur->ExpiryTime - m->timenow + mDNSPlatformOneSecond/2) / mDNSPlatformOneSecond : 0;
4398 cur->Result = cur->NewResult;
4399 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
4400 if (cur->clientCallback)
4401 cur->clientCallback(m, cur);
4402 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
4403 // MUST NOT touch cur after invoking the callback
4404 }
4405 }
4406 }
4407 }
4408
4409 mDNSlocal mDNSs32 CheckRecordRegistrations(mDNS *m)
4410 {
4411 AuthRecord *rr;
4412 mDNSs32 nextevent = m->timenow + 0x3FFFFFFF;
4413
4414 for (rr = m->ResourceRecords; rr; rr = rr->next)
4415 {
4416 if (rr->state == regState_Pending || rr->state == regState_DeregPending || rr->state == regState_UpdatePending ||
4417 rr->state == regState_DeregDeferred || rr->state == regState_Refresh || rr->state == regState_Registered)
4418 {
4419 if (rr->LastAPTime + rr->ThisAPInterval - m->timenow < 0)
4420 {
4421 if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
4422 if (rr->state == regState_DeregPending) SendRecordDeregistration(m, rr);
4423 else SendRecordRegistration(m, rr);
4424 }
4425 if (nextevent - (rr->LastAPTime + rr->ThisAPInterval) > 0)
4426 nextevent = (rr->LastAPTime + rr->ThisAPInterval);
4427 }
4428 }
4429 return nextevent;
4430 }
4431
4432 mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m)
4433 {
4434 mDNSs32 nextevent = m->timenow + 0x3FFFFFFF;
4435
4436 if (CurrentServiceRecordSet)
4437 LogMsg("CheckServiceRegistrations ERROR CurrentServiceRecordSet already set");
4438 CurrentServiceRecordSet = m->ServiceRegistrations;
4439
4440 // Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery
4441 while (CurrentServiceRecordSet)
4442 {
4443 ServiceRecordSet *srs = CurrentServiceRecordSet;
4444 CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next;
4445 if (srs->state == regState_Pending || srs->state == regState_DeregPending || srs->state == regState_DeregDeferred ||
4446 srs->state == regState_Refresh || srs->state == regState_UpdatePending || srs->state == regState_Registered)
4447 {
4448 if (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval - m->timenow <= 0)
4449 {
4450 if (srs->tcp) { DisposeTCPConn(srs->tcp); srs->tcp = mDNSNULL; }
4451 if (srs->state == regState_DeregPending) SendServiceDeregistration(m, srs);
4452 else SendServiceRegistration(m, srs);
4453 }
4454 if (nextevent - (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval) > 0)
4455 nextevent = (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval);
4456 }
4457 }
4458 return nextevent;
4459 }
4460
4461 mDNSexport void uDNS_Execute(mDNS *const m)
4462 {
4463 mDNSs32 nexte;
4464
4465 m->NextuDNSEvent = m->timenow + 0x3FFFFFFF;
4466
4467 if (m->NextSRVUpdate && m->NextSRVUpdate - m->timenow < 0)
4468 { m->NextSRVUpdate = 0; UpdateSRVRecords(m); }
4469
4470 CheckNATMappings(m);
4471
4472 if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0)
4473 m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it
4474
4475 nexte = CheckRecordRegistrations(m);
4476 if (nexte - m->NextuDNSEvent < 0) m->NextuDNSEvent = nexte;
4477
4478 nexte = CheckServiceRegistrations(m);
4479 if (nexte - m->NextuDNSEvent < 0) m->NextuDNSEvent = nexte;
4480 }
4481
4482 // ***************************************************************************
4483 #if COMPILER_LIKES_PRAGMA_MARK
4484 #pragma mark - Startup, Shutdown, and Sleep
4485 #endif
4486
4487 // simplest sleep logic - rather than having sleep states that must be dealt with explicitly in all parts of
4488 // the code, we simply send a deregistration, and put the service in Refresh state, with a timeout far enough
4489 // in the future that we'll sleep (or the sleep will be cancelled) before it is retransmitted. Then to wake,
4490 // we just move up the timers.
4491
4492 mDNSexport void SleepRecordRegistrations(mDNS *m)
4493 {
4494 AuthRecord *rr = m->ResourceRecords;
4495
4496 while (rr)
4497 {
4498 if (rr->state == regState_Registered ||
4499 rr->state == regState_Refresh)
4500 {
4501 SendRecordDeregistration(m, rr);
4502 rr->state = regState_Refresh;
4503 rr->LastAPTime = m->timenow;
4504 rr->ThisAPInterval = 300 * mDNSPlatformOneSecond;
4505 }
4506 rr = rr->next;
4507 }
4508 }
4509
4510 mDNSlocal void WakeRecordRegistrations(mDNS *m)
4511 {
4512 AuthRecord *rr = m->ResourceRecords;
4513
4514 while (rr)
4515 {
4516 if (rr->state == regState_Refresh)
4517 {
4518 // trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets)
4519 rr->LastAPTime = m->timenow;
4520 rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
4521 }
4522 rr = rr->next;
4523 }
4524 }
4525
4526 mDNSexport void SleepServiceRegistrations(mDNS *m)
4527 {
4528 ServiceRecordSet *srs = m->ServiceRegistrations;
4529 while (srs)
4530 {
4531 if (srs->nta) { CancelGetZoneData(m, srs->nta); srs->nta = mDNSNULL; }
4532
4533 if (srs->NATinfo.clientContext)
4534 {
4535 mDNS_StopNATOperation_internal(m, &srs->NATinfo);
4536 srs->NATinfo.clientContext = mDNSNULL;
4537 }
4538
4539 if (srs->state == regState_UpdatePending)
4540 {
4541 // act as if the update succeeded, since we're about to delete the name anyway
4542 AuthRecord *txt = &srs->RR_TXT;
4543 srs->state = regState_Registered;
4544 // deallocate old RData
4545 if (txt->UpdateCallback) txt->UpdateCallback(m, txt, txt->OrigRData);
4546 SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen);
4547 txt->OrigRData = mDNSNULL;
4548 txt->InFlightRData = mDNSNULL;
4549 }
4550
4551 if (srs->state == regState_Registered || srs->state == regState_Refresh)
4552 {
4553 mDNSOpaque16 origid = srs->id;
4554 srs->state = regState_DeregPending; // state expected by SendDereg()
4555 SendServiceDeregistration(m, srs);
4556 srs->id = origid;
4557 srs->state = regState_NoTarget; // when we wake, we'll re-register (and optionally nat-map) once our address record completes
4558 srs->RR_SRV.resrec.rdata->u.srv.target.c[0] = 0;
4559 }
4560 srs = srs->uDNS_next;
4561 }
4562 }
4563
4564 mDNSlocal void WakeServiceRegistrations(mDNS *m)
4565 {
4566 ServiceRecordSet *srs = m->ServiceRegistrations;
4567 while (srs)
4568 {
4569 if (srs->state == regState_Refresh)
4570 {
4571 // trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets)
4572 srs->RR_SRV.LastAPTime = m->timenow;
4573 srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
4574 }
4575 srs = srs->uDNS_next;
4576 }
4577 }
4578
4579 mDNSexport void mDNS_AddSearchDomain(const domainname *const domain)
4580 {
4581 SearchListElem **p;
4582
4583 // Check to see if we already have this domain in our list
4584 for (p = &SearchList; *p; p = &(*p)->next)
4585 if (SameDomainName(&(*p)->domain, domain))
4586 {
4587 // If domain is already in list, and marked for deletion, change it to "leave alone"
4588 if ((*p)->flag == -1) (*p)->flag = 0;
4589 LogOperation("mDNS_AddSearchDomain already in list %##s", domain->c);
4590 return;
4591 }
4592
4593 // if domain not in list, add to list, mark as add (1)
4594 *p = mDNSPlatformMemAllocate(sizeof(SearchListElem));
4595 if (!*p) { LogMsg("ERROR: mDNS_AddSearchDomain - malloc"); return; }
4596 mDNSPlatformMemZero(*p, sizeof(SearchListElem));
4597 AssignDomainName(&(*p)->domain, domain);
4598 (*p)->flag = 1; // add
4599 (*p)->next = mDNSNULL;
4600 LogOperation("mDNS_AddSearchDomain created new %##s", domain->c);
4601 }
4602
4603 mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
4604 {
4605 (void)m; // unused
4606 if (result == mStatus_MemFree) mDNSPlatformMemFree(rr->RecordContext);
4607 }
4608
4609 mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
4610 {
4611 SearchListElem *slElem = question->QuestionContext;
4612 mStatus err;
4613
4614 if (answer->rrtype != kDNSType_PTR) return;
4615 if (answer->RecordType == kDNSRecordTypePacketNegative) return;
4616
4617 if (AddRecord)
4618 {
4619 const char *name;
4620 ARListElem *arElem = mDNSPlatformMemAllocate(sizeof(ARListElem));
4621 if (!arElem) { LogMsg("ERROR: malloc"); return; }
4622 mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, arElem);
4623 if (question == &slElem->BrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowse];
4624 else if (question == &slElem->DefBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault];
4625 else if (question == &slElem->AutomaticBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseAutomatic];
4626 else if (question == &slElem->RegisterQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistration];
4627 else if (question == &slElem->DefRegisterQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistrationDefault];
4628 else { LogMsg("FoundDomain - unknown question"); mDNSPlatformMemFree(arElem); return; }
4629
4630 MakeDomainNameFromDNSNameString(&arElem->ar.namestorage, name);
4631 AppendDNSNameString (&arElem->ar.namestorage, "local");
4632 AssignDomainName(&arElem->ar.resrec.rdata->u.name, &answer->rdata->u.name);
4633 err = mDNS_Register(m, &arElem->ar);
4634 if (err) { LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err); mDNSPlatformMemFree(arElem); return; }
4635 arElem->next = slElem->AuthRecs;
4636 slElem->AuthRecs = arElem;
4637 }
4638 else
4639 {
4640 ARListElem **ptr = &slElem->AuthRecs;
4641 while (*ptr)
4642 {
4643 if (SameDomainName(&(*ptr)->ar.resrec.rdata->u.name, &answer->rdata->u.name))
4644 {
4645 ARListElem *dereg = *ptr;
4646 *ptr = (*ptr)->next;
4647 debugf("Deregistering PTR %##s -> %##s", dereg->ar.resrec.name->c, dereg->ar.resrec.rdata->u.name.c);
4648 err = mDNS_Deregister(m, &dereg->ar);
4649 if (err) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err);
4650 // Memory will be freed in the FreeARElemCallback
4651 }
4652 else
4653 ptr = &(*ptr)->next;
4654 }
4655 }
4656 }
4657
4658 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
4659 mDNSexport void udns_validatelists(void *const v)
4660 {
4661 mDNS *const m = v;
4662
4663 ServiceRecordSet *s;
4664 for (s = m->ServiceRegistrations; s; s=s->uDNS_next)
4665 if (s->uDNS_next == (ServiceRecordSet*)~0)
4666 LogMemCorruption("m->ServiceRegistrations: %p is garbage (%lX)", s, s->uDNS_next);
4667
4668 NATTraversalInfo *n;
4669 for (n = m->NATTraversals; n; n=n->next)
4670 if (n->next == (NATTraversalInfo *)~0 || n->clientCallback == (NATTraversalClientCallback)~0)
4671 LogMemCorruption("m->NATTraversals: %p is garbage", n);
4672
4673 DNSServer *d;
4674 for (d = m->DNSServers; d; d=d->next)
4675 if (d->next == (DNSServer *)~0 || d->teststate > DNSServer_Disabled)
4676 LogMemCorruption("m->DNSServers: %p is garbage (%d)", d, d->teststate);
4677
4678 DomainAuthInfo *info;
4679 for (info = m->AuthInfoList; info; info = info->next)
4680 if (info->next == (DomainAuthInfo *)~0 || info->AutoTunnel == (mDNSBool)~0)
4681 LogMemCorruption("m->AuthInfoList: %p is garbage (%X)", info, info->AutoTunnel);
4682
4683 HostnameInfo *hi;
4684 for (hi = m->Hostnames; hi; hi = hi->next)
4685 if (hi->next == (HostnameInfo *)~0 || hi->StatusCallback == (mDNSRecordCallback*)~0)
4686 LogMemCorruption("m->Hostnames: %p is garbage", n);
4687
4688 SearchListElem *ptr;
4689 for (ptr = SearchList; ptr; ptr = ptr->next)
4690 if (ptr->next == (SearchListElem *)~0 || ptr->AuthRecs == (void*)~0)
4691 LogMemCorruption("SearchList: %p is garbage (%X)", ptr, ptr->AuthRecs);
4692 }
4693 #endif
4694
4695 // This should probably move to the UDS daemon -- the concept of legacy clients and automatic registration / automatic browsing
4696 // is really a UDS API issue, not something intrinsic to uDNS
4697
4698 mDNSexport mStatus uDNS_RegisterSearchDomains(mDNS *const m)
4699 {
4700 SearchListElem **p = &SearchList, *ptr;
4701 mStatus err;
4702
4703 // step 1: mark each element for removal (-1)
4704 for (ptr = SearchList; ptr; ptr = ptr->next) ptr->flag = -1;
4705
4706 // Client has requested domain enumeration or automatic browse -- time to make sure we have the search domains from the platform layer
4707 mDNS_Lock(m);
4708 m->RegisterSearchDomains = mDNStrue;
4709 mDNSPlatformSetDNSConfig(m, mDNSfalse, m->RegisterSearchDomains, mDNSNULL, mDNSNULL, mDNSNULL);
4710 mDNS_Unlock(m);
4711
4712 // delete elems marked for removal, do queries for elems marked add
4713 while (*p)
4714 {
4715 ptr = *p;
4716 debugf("RegisterSearchDomains %d %p %##s", ptr->flag, ptr->AuthRecs, ptr->domain.c);
4717 if (ptr->flag == -1) // remove
4718 {
4719 ARListElem *arList = ptr->AuthRecs;
4720 ptr->AuthRecs = mDNSNULL;
4721 *p = ptr->next;
4722
4723 mDNS_StopGetDomains(m, &ptr->BrowseQ);
4724 mDNS_StopGetDomains(m, &ptr->RegisterQ);
4725 mDNS_StopGetDomains(m, &ptr->DefBrowseQ);
4726 mDNS_StopGetDomains(m, &ptr->DefRegisterQ);
4727 mDNS_StopGetDomains(m, &ptr->AutomaticBrowseQ);
4728 mDNSPlatformMemFree(ptr);
4729
4730 // deregister records generated from answers to the query
4731 while (arList)
4732 {
4733 ARListElem *dereg = arList;
4734 arList = arList->next;
4735 debugf("Deregistering PTR %##s -> %##s", dereg->ar.resrec.name->c, dereg->ar.resrec.rdata->u.name.c);
4736 err = mDNS_Deregister(m, &dereg->ar);
4737 if (err) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err);
4738 // Memory will be freed in the FreeARElemCallback
4739 }
4740 continue;
4741 }
4742
4743 if (ptr->flag == 1) // add
4744 {
4745 mStatus err1, err2, err3, err4, err5;
4746 err1 = mDNS_GetDomains(m, &ptr->BrowseQ, mDNS_DomainTypeBrowse, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
4747 err2 = mDNS_GetDomains(m, &ptr->DefBrowseQ, mDNS_DomainTypeBrowseDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
4748 err3 = mDNS_GetDomains(m, &ptr->RegisterQ, mDNS_DomainTypeRegistration, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
4749 err4 = mDNS_GetDomains(m, &ptr->DefRegisterQ, mDNS_DomainTypeRegistrationDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
4750 err5 = mDNS_GetDomains(m, &ptr->AutomaticBrowseQ, mDNS_DomainTypeBrowseAutomatic, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
4751 if (err1 || err2 || err3 || err4 || err5)
4752 LogMsg("GetDomains for domain %##s returned error(s):\n"
4753 "%d (mDNS_DomainTypeBrowse)\n"
4754 "%d (mDNS_DomainTypeBrowseDefault)\n"
4755 "%d (mDNS_DomainTypeRegistration)\n"
4756 "%d (mDNS_DomainTypeRegistrationDefault)"
4757 "%d (mDNS_DomainTypeBrowseAutomatic)\n",
4758 ptr->domain.c, err1, err2, err3, err4, err5);
4759 ptr->flag = 0;
4760 }
4761
4762 if (ptr->flag) { LogMsg("RegisterSearchDomains - unknown flag %d. Skipping.", ptr->flag); }
4763
4764 p = &ptr->next;
4765 }
4766
4767 return mStatus_NoError;
4768 }
4769
4770 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
4771 // 1) query for b._dns-sd._udp.local on LocalOnly interface
4772 // (.local manually generated via explicit callback)
4773 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
4774 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
4775 // 4) result above should generate a callback from question in (1). result added to global list
4776 // 5) global list delivered to client via GetSearchDomainList()
4777 // 6) client calls to enumerate domains now go over LocalOnly interface
4778 // (!!!KRS may add outgoing interface in addition)
4779
4780 mDNSexport void uDNS_Wake(mDNS *const m)
4781 {
4782 WakeServiceRegistrations(m);
4783 WakeRecordRegistrations(m);
4784 }
4785
4786 struct CompileTimeAssertionChecks_uDNS
4787 {
4788 // Check our structures are reasonable sizes. Including overly-large buffers, or embedding
4789 // other overly-large structures instead of having a pointer to them, can inadvertently
4790 // cause structure sizes (and therefore memory usage) to balloon unreasonably.
4791 char sizecheck_tcpInfo_t [(sizeof(tcpInfo_t) <= 9100) ? 1 : -1];
4792 char sizecheck_SearchListElem[(sizeof(SearchListElem) <= 3800) ? 1 : -1];
4793 };