1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
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
22 Change History (most recent first):
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
28 Revision 1.527 2007/11/01 16:08:51 cheshire
29 Tidy up alignment of "SetRecordRetry refresh" log messages
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
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
38 Revision 1.524 2007/10/30 20:10:47 cheshire
39 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
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
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
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
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
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
61 Revision 1.518 2007/10/26 23:41:29 cheshire
62 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
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
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
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
74 Revision 1.514 2007/10/25 20:48:47 cheshire
75 For naming consistency (with AuthRecord's UpdateServer) renamed 'ns' to 'SRSUpdateServer'
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
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
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
89 Revision 1.510 2007/10/24 22:40:06 cheshire
90 Renamed: RecordRegistrationCallback -> RecordRegistrationGotZoneData
91 Renamed: ServiceRegistrationZoneDataComplete -> ServiceRegistrationGotZoneData
93 Revision 1.509 2007/10/24 00:54:07 cheshire
94 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
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
100 Revision 1.507 2007/10/23 00:33:36 cheshire
101 Improved debugging messages
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
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
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
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
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
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
124 Revision 1.500 2007/10/17 21:53:51 cheshire
125 Improved debugging messages; renamed startLLQHandshakeCallback to LLQGotZoneData
127 Revision 1.499 2007/10/16 21:16:50 cheshire
128 Get rid of unused uDNS_Sleep() routine
130 Revision 1.498 2007/10/16 20:59:41 cheshire
131 Export SuspendLLQs/SleepServiceRegistrations/SleepRecordRegistrations so they're callable from other files
133 Revision 1.497 2007/10/05 18:09:44 cheshire
134 <rdar://problem/5524841> Services advertised with wrong target host
136 Revision 1.496 2007/10/04 22:38:59 cheshire
137 Added LogOperation message showing new q->ThisQInterval after sending uDNS query packet
139 Revision 1.495 2007/10/03 00:16:19 cheshire
140 In PrivateQueryGotZoneData, need to grab lock before calling SetNextQueryTime
142 Revision 1.494 2007/10/02 21:11:08 cheshire
143 <rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing
145 Revision 1.493 2007/10/02 19:50:23 cheshire
146 Improved debugging message
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
152 Revision 1.491 2007/09/29 01:33:45 cheshire
153 <rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
155 Revision 1.490 2007/09/29 01:06:17 mcguire
156 <rdar://problem/5507862> 9A564: mDNSResponder crash in mDNS_Execute
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
161 Revision 1.488 2007/09/27 21:20:17 cheshire
162 Improved debugging syslog messages
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
167 Revision 1.486 2007/09/27 17:42:49 cheshire
168 Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask"
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
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
177 Revision 1.483 2007/09/26 23:16:58 cheshire
178 <rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac
180 Revision 1.482 2007/09/26 22:06:02 cheshire
181 <rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
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
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
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
194 Revision 1.478 2007/09/21 19:29:14 cheshire
195 Added dump of uDNS questions when in MDNS_LOG_VERBOSE_DEBUG mode
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
200 Revision 1.476 2007/09/20 01:19:49 cheshire
201 Improve debugging messages: report startLLQHandshake errors; show state in uDNS_StopLongLivedQuery message
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
206 Revision 1.474 2007/09/19 20:32:09 cheshire
207 Export GetAuthInfoForName so it's callable from other files
209 Revision 1.473 2007/09/18 21:42:29 cheshire
210 To reduce programming mistakes, renamed ExtPort to RequestedPort
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
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.
219 Revision 1.470 2007/09/13 00:36:26 cheshire
220 <rdar://problem/5477360> NAT Reboot detection logic incorrect
222 Revision 1.469 2007/09/13 00:28:50 cheshire
223 <rdar://problem/5477354> Host records not updated on NAT address change
225 Revision 1.468 2007/09/13 00:16:41 cheshire
226 <rdar://problem/5468706> Miscellaneous NAT Traversal improvements
228 Revision 1.467 2007/09/12 23:03:08 cheshire
229 <rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
231 Revision 1.466 2007/09/12 22:19:29 cheshire
232 <rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
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
238 Revision 1.464 2007/09/12 01:22:13 cheshire
239 Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
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
245 Revision 1.462 2007/09/11 19:19:16 cheshire
246 Correct capitalization of "uPNP" to "UPnP"
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
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.
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
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)
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.
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
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
275 Revision 1.454 2007/09/05 02:32:55 cheshire
276 Fixed posix build error (mixed declarations and code)
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
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
286 Revision 1.451 2007/08/31 18:49:49 vazquez
287 <rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
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
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
295 Revision 1.448 2007/08/30 00:18:46 cheshire
296 <rdar://problem/5448804> Error messages: "SendServiceRegistration: Already have TCP connection..."
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
302 Revision 1.446 2007/08/28 23:58:42 cheshire
303 Rename HostTarget -> AutoTarget
305 Revision 1.445 2007/08/28 23:53:21 cheshire
306 Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
308 Revision 1.444 2007/08/27 20:29:20 cheshire
309 Additional debugging messages
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()
315 Revision 1.442 2007/08/24 22:43:06 cheshire
316 Tidied up coded layout
318 Revision 1.441 2007/08/24 01:20:55 cheshire
319 <rdar://problem/5434381> BTMM: Memory corruption in KeychainChanged event handling
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
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.
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.
334 Revision 1.437 2007/08/18 00:54:15 mcguire
335 <rdar://problem/5413147> BTMM: Should not register private addresses or zeros
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
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.
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.
350 Revision 1.433 2007/08/02 03:30:11 vazquez
351 <rdar://problem/5371843> BTMM: Private LLQs never fall back to polling
353 Revision 1.432 2007/08/01 18:15:19 cheshire
354 Fixed crash in tcpCallback; fixed some problems with LLQ setup behind NAT
356 Revision 1.431 2007/08/01 16:11:06 cheshire
357 Fixed "mixed declarations and code" compiler error in Posix build
359 Revision 1.430 2007/08/01 16:09:13 cheshire
360 Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
362 Revision 1.429 2007/08/01 03:09:22 cheshire
363 <rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
365 Revision 1.428 2007/08/01 01:43:36 cheshire
366 Need to do mDNS_DropLockBeforeCallback/ReclaimLock around invokation of NAT client callback
368 Revision 1.427 2007/08/01 01:31:13 cheshire
369 Need to initialize traversal->tcpInfo fields or code may crash
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
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
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
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
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
387 Revision 1.421 2007/07/28 00:04:14 cheshire
388 Various fixes for comments and debugging messages
390 Revision 1.420 2007/07/27 23:59:18 cheshire
391 Added compile-time structure size checks
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
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
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
403 Revision 1.416 2007/07/27 19:59:28 cheshire
404 MUST NOT touch m->CurrentQuestion (or q) after calling AnswerCurrentQuestionWithResourceRecord()
406 Revision 1.415 2007/07/27 19:51:01 cheshire
407 Use symbol QC_addnocache instead of literal constant "2"
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
413 Revision 1.413 2007/07/27 18:44:01 cheshire
414 Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
416 Revision 1.412 2007/07/27 18:38:56 cheshire
417 Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
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
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
426 Revision 1.409 2007/07/25 03:05:02 vazquez
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
432 Revision 1.408 2007/07/24 21:47:51 cheshire
433 Don't do mDNS_StopNATOperation() for operations we never started
435 Revision 1.407 2007/07/24 17:23:33 cheshire
436 <rdar://problem/5357133> Add list validation checks for debugging
438 Revision 1.406 2007/07/24 04:14:30 cheshire
439 <rdar://problem/5356281> LLQs not working in with NAT Traversal
441 Revision 1.405 2007/07/24 01:29:03 cheshire
442 <rdar://problem/5356026> DNSServiceNATPortMappingCreate() returns stale external address information
444 Revision 1.404 2007/07/20 23:10:51 cheshire
447 Revision 1.403 2007/07/20 20:12:37 cheshire
448 Rename "mDNS_DomainTypeBrowseLegacy" as "mDNS_DomainTypeBrowseAutomatic"
450 Revision 1.402 2007/07/20 00:54:20 cheshire
451 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
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
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)
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
464 Revision 1.398 2007/07/16 23:54:48 cheshire
465 <rdar://problem/5338850> Crash when removing or changing DNS keys
467 Revision 1.397 2007/07/16 20:13:31 vazquez
468 <rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
470 Revision 1.396 2007/07/14 00:33:04 cheshire
471 Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working
473 Revision 1.395 2007/07/12 23:56:23 cheshire
474 Change "GetZoneData GOT SRV" message to debugf to reduce verbosity in syslog
476 Revision 1.394 2007/07/12 23:36:08 cheshire
477 Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog
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
482 Revision 1.392 2007/07/12 02:51:27 cheshire
483 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
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
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
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
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
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
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
510 Revision 1.385 2007/07/09 23:50:18 cheshire
511 unlinkSRS needs to call mDNS_StopNATOperation_internal(), not mDNS_StopNATOperation()
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")
516 Revision 1.383 2007/07/06 18:59:59 cheshire
517 Avoid spinning in an infinite loop when uDNS_SendNATMsg() returns an error
519 Revision 1.382 2007/07/04 00:49:43 vazquez
520 Clean up extraneous comments
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
526 Revision 1.380 2007/07/02 22:08:47 cheshire
527 Fixed crash in "Received public IP address" message
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)
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.
536 Revision 1.377 2007/06/22 21:27:21 cheshire
537 Modified "could not convert shared secret from base64" log message
539 Revision 1.376 2007/06/20 01:10:12 cheshire
540 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
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
545 Revision 1.374 2007/06/12 02:15:26 cheshire
546 Fix incorrect "DNS Server passed" LogOperation message
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
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
554 Revision 1.371 2007/05/24 00:11:44 cheshire
555 Remove unnecessary lenbuf field from tcpInfo_t
557 Revision 1.370 2007/05/23 00:30:59 cheshire
558 Don't change question->TargetQID when repeating query over TCP
560 Revision 1.369 2007/05/21 18:04:40 cheshire
561 Updated comments -- port_mapping_create_reply renamed to port_mapping_reply
563 Revision 1.368 2007/05/17 19:12:16 cheshire
564 Updated comment about finding matching pair of sockets
566 Revision 1.367 2007/05/15 23:38:00 cheshire
567 Need to grab lock before calling SendRecordRegistration();
569 Revision 1.366 2007/05/15 00:43:05 cheshire
570 <rdar://problem/4983538> uDNS serviceRegistrationCallback locking failures
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)
576 Revision 1.364 2007/05/07 20:43:45 cheshire
577 <rdar://problem/4241419> Reduce the number of queries and announcements
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
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
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
591 Revision 1.360 2007/05/03 22:40:38 cheshire
592 <rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
594 Revision 1.359 2007/05/02 22:21:33 cheshire
595 <rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
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
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"
603 Revision 1.356 2007/04/30 21:51:06 cheshire
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
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
614 Revision 1.353 2007/04/28 01:28:25 cheshire
615 Fixed memory leak on error path in FoundDomain
617 Revision 1.352 2007/04/27 19:49:53 cheshire
618 In uDNS_ReceiveTestQuestionResponse, also check that srcport matches
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.)
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)"
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
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)"
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.)
641 Revision 1.346 2007/04/25 19:16:59 cheshire
642 Don't set SuppressStdPort53Queries unless we do actually send a DNS packet
644 Revision 1.345 2007/04/25 18:05:11 cheshire
645 Don't try to restart inactive (duplicate) queries
647 Revision 1.344 2007/04/25 17:54:07 cheshire
648 Don't cancel Private LLQs using a clear-text UDP packet
650 Revision 1.343 2007/04/25 16:40:08 cheshire
651 Add comment explaining uDNS_recvLLQResponse logic
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
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
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).
667 Revision 1.339 2007/04/22 06:02:03 cheshire
668 <rdar://problem/4615977> Query should immediately return failure when no server
670 Revision 1.338 2007/04/21 19:44:11 cheshire
671 Improve uDNS_HandleNATPortMapReply log message
673 Revision 1.337 2007/04/21 02:03:00 cheshire
674 Also need to set AddressRec->resrec.RecordType in the NAT case too
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
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
683 Revision 1.334 2007/04/19 23:21:51 cheshire
684 Fixed a couple of places where the StartGetZoneData check was backwards
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
689 Revision 1.332 2007/04/19 20:34:32 cheshire
690 Add debugging log message in uDNS_CheckQuery()
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)
695 Revision 1.330 2007/04/19 19:51:54 cheshire
696 Get rid of unnecessary initializeQuery() routine
698 Revision 1.329 2007/04/19 18:03:52 cheshire
699 Improved "mDNS_AddSearchDomain" log message
701 Revision 1.328 2007/04/18 20:57:20 cheshire
702 Commented out "GetAuthInfoForName none found" debugging message
704 Revision 1.327 2007/04/17 19:21:29 cheshire
705 <rdar://problem/5140339> Domain discovery not working over VPN
707 Revision 1.326 2007/04/16 20:49:39 cheshire
708 Fix compile errors for mDNSPosix build
710 Revision 1.325 2007/04/05 22:55:35 cheshire
711 <rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
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.
718 Revision 1.323 2007/04/04 21:48:52 cheshire
719 <rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
721 Revision 1.322 2007/04/03 19:53:06 cheshire
722 Use mDNSSameIPPort (and similar) instead of accessing internal fields directly
724 Revision 1.321 2007/04/02 23:44:09 cheshire
727 Revision 1.320 2007/03/31 01:26:13 cheshire
728 Take out GetAuthInfoForName syslog message
730 Revision 1.319 2007/03/31 01:10:53 cheshire
733 Revision 1.318 2007/03/31 00:17:11 cheshire
736 Revision 1.317 2007/03/29 00:09:31 cheshire
737 Improve "uDNS_InitLongLivedQuery" log message
739 Revision 1.316 2007/03/28 21:16:27 cheshire
740 Remove DumpPacket() call now that OPT pseudo-RR rrclass bug is fixed
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
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
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
752 Revision 1.312 2007/03/27 23:48:21 cheshire
753 Use mDNS_StopGetDomains(), not mDNS_StopQuery()
755 Revision 1.311 2007/03/27 22:47:51 cheshire
756 Remove unnecessary "*(long*)0 = 0;" to generate crash and stack trace
758 Revision 1.310 2007/03/24 01:24:13 cheshire
759 Add validator for uDNS data structures; fixed crash in RegisterSearchDomains()
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.
765 Revision 1.308 2007/03/24 00:41:33 cheshire
766 Minor code cleanup (move variable declarations to minimum enclosing scope)
768 Revision 1.307 2007/03/21 23:06:00 cheshire
769 Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
771 Revision 1.306 2007/03/21 00:30:03 cheshire
772 <rdar://problem/4789455> Multiple errors in DNameList-related code
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"
777 Revision 1.304 2007/03/17 00:02:11 cheshire
778 <rdar://problem/5067013> NAT-PMP: Lease TTL is being ignored
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
783 Revision 1.302 2007/03/10 02:29:58 cheshire
784 Added comments about NAT-PMP response functions
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
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)
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
797 Revision 1.298 2007/02/14 03:16:39 cheshire
798 <rdar://problem/4789477> Eliminate unnecessary malloc/free in mDNSCore code
800 Revision 1.297 2007/02/08 21:12:28 cheshire
801 <rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
803 Revision 1.296 2007/01/29 16:03:22 cheshire
804 Fix unused parameter warning
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
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.
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()
817 Revision 1.292 2007/01/20 01:32:40 cheshire
818 Update comments and debugging messages
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.
825 Revision 1.290 2007/01/19 23:41:45 cheshire
826 Need to clear m->rec.r.resrec.RecordType after calling GetLLQOptData()
828 Revision 1.289 2007/01/19 23:32:07 cheshire
829 Eliminate pointless timenow variable
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
834 Revision 1.287 2007/01/19 22:55:41 cheshire
835 Eliminate redundant identical parameters to GetZoneData_StartQuery()
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
840 Revision 1.285 2007/01/19 18:39:11 cheshire
841 Fix a bunch of parameters that should have been declared "const"
843 Revision 1.284 2007/01/19 18:28:28 cheshire
844 Improved debugging messages
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
851 Revision 1.282 2007/01/17 22:06:01 cheshire
852 Replace duplicated literal constant "{ { 0 } }" with symbol "zeroIPPort"
854 Revision 1.281 2007/01/17 21:58:13 cheshire
855 For clarity, rename ntaContext field "isPrivate" to "ntaPrivate"
857 Revision 1.280 2007/01/17 21:46:02 cheshire
858 Remove redundant duplicated "isPrivate" field from LLQ_Info
860 Revision 1.279 2007/01/17 21:35:31 cheshire
861 For clarity, rename zoneData_t field "isPrivate" to "zonePrivate"
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"
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
871 Revision 1.276 2007/01/10 02:09:30 cheshire
872 Better LogOperation record of keys read from System Keychain
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.
878 Revision 1.274 2007/01/09 01:16:32 cheshire
879 Improve "ERROR m->CurrentQuestion already set" debugging messages
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
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)
888 Revision 1.271 2007/01/05 06:34:03 cheshire
889 Improve "ERROR m->CurrentQuestion already set" debugging messages
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
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
899 Revision 1.268 2007/01/04 22:06:38 cheshire
900 Fixed crash in LLQNatMapComplete()
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
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
910 Revision 1.265 2007/01/04 20:47:17 cheshire
911 Fixed crash in CheckForUnreferencedLLQMapping()
913 Revision 1.264 2007/01/04 20:39:27 cheshire
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
919 Revision 1.262 2007/01/04 00:29:25 cheshire
920 Covert LogMsg() in GetAuthInfoForName to LogOperation()
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
926 Revision 1.260 2006/12/21 00:06:07 cheshire
927 Don't need to do mDNSPlatformMemZero() -- mDNS_SetupResourceRecord() does it for us
929 Revision 1.259 2006/12/20 04:07:36 cheshire
930 Remove uDNS_info substructure from AuthRecord_struct
932 Revision 1.258 2006/12/19 22:49:24 cheshire
933 Remove uDNS_info substructure from ServiceRecordSet_struct
935 Revision 1.257 2006/12/19 02:38:20 cheshire
936 Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
938 Revision 1.256 2006/12/19 02:18:48 cheshire
939 Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
941 Revision 1.255 2006/12/16 01:58:31 cheshire
942 <rdar://problem/4720673> uDNS: Need to start caching unicast records
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.
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.
952 Revision 1.252 2006/11/30 23:07:57 herscher
953 <rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
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
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
962 Revision 1.249 2006/11/10 07:44:04 herscher
963 <rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
965 Revision 1.248 2006/11/08 04:26:53 cheshire
966 Fix typo in debugging message
968 Revision 1.247 2006/10/20 05:35:04 herscher
969 <rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
971 Revision 1.246 2006/10/11 19:29:41 herscher
972 <rdar://problem/4744553> uDNS: mDNSResponder-111 using 100% CPU
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.
977 Revision 1.244 2006/10/04 21:51:27 herscher
978 Replace calls to mDNSPlatformTimeNow(m) with m->timenow
980 Revision 1.243 2006/10/04 21:38:59 herscher
981 Remove uDNS_info substructure from DNSQuestion_struct
983 Revision 1.242 2006/09/27 00:51:46 herscher
984 Fix compile error when _LEGACY_NAT_TRAVERSAL_ is not defined
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)
989 Revision 1.240 2006/09/15 21:20:15 cheshire
990 Remove uDNS_info substructure from mDNS_struct
992 Revision 1.239 2006/08/16 02:52:56 mkrochma
993 <rdar://problem/4104154> Actually fix it this time
995 Revision 1.238 2006/08/16 00:31:50 mkrochma
996 <rdar://problem/4386944> Get rid of NotAnInteger references
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
1001 Revision 1.236 2006/08/14 23:24:23 cheshire
1002 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
1004 Revision 1.235 2006/07/30 05:45:36 cheshire
1005 <rdar://problem/4304215> Eliminate MIN_UCAST_PERIODIC_EXEC
1007 Revision 1.234 2006/07/22 02:58:36 cheshire
1008 Code was clearing namehash twice instead of namehash and rdatahash
1010 Revision 1.233 2006/07/20 19:46:51 mkrochma
1011 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
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
1018 Revision 1.231 2006/07/05 23:28:22 cheshire
1019 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1021 Revision 1.230 2006/06/29 03:02:44 cheshire
1022 <rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
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
1028 Revision 1.228 2006/02/26 00:54:42 cheshire
1029 Fixes to avoid code generation warning/error on FreeBSD 7
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"
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)
1047 typedef struct tcpInfo_t
1053 DNSQuestion
*question
; // For queries
1054 ServiceRecordSet
*srs
; // For service record updates
1055 AuthRecord
*rr
; // For record updates
1060 unsigned long nread
;
1064 typedef struct SearchListElem
1066 struct SearchListElem
*next
;
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
;
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
;
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
;
1091 // ***************************************************************************
1092 #if COMPILER_LIKES_PRAGMA_MARK
1093 #pragma mark - General Utility Functions
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
)
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
;
1107 list
= &m
->DuplicateRecords
;
1108 while (*list
&& *list
!= rr
) list
= &(*list
)->next
;
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
);
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
)
1118 ServiceRecordSet
**p
;
1120 if (srs
->NATinfo
.clientContext
)
1122 mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
1123 srs
->NATinfo
.clientContext
= mDNSNULL
;
1126 for (p
= &m
->ServiceRegistrations
; *p
; p
= &(*p
)->uDNS_next
)
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
);
1139 LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list %##s", srs
->RR_SRV
.resrec
.name
->c
);
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
)
1146 mDNSs32 elapsed
= m
->timenow
- rr
->LastAPTime
;
1147 rr
->LastAPTime
= m
->timenow
;
1150 // Code for stress-testing registration renewal code
1151 if (rr
->expire
&& rr
->expire
- m
->timenow
> mDNSPlatformOneSecond
* 120)
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;
1159 if (rr
->expire
&& rr
->expire
- m
->timenow
> mDNSPlatformOneSecond
)
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
));
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
;
1181 LogOperation("SetRecordRetry retry in %4d for %s", rr
->ThisAPInterval
/ mDNSPlatformOneSecond
, ARDisplayString(m
, rr
));
1184 // ***************************************************************************
1185 #if COMPILER_LIKES_PRAGMA_MARK
1186 #pragma mark - Name Server List Management
1189 mDNSexport DNSServer
*mDNS_AddDNSServer(mDNS
*const m
, const domainname
*d
, const mDNSInterfaceID interface
, const mDNSAddr
*addr
, const mDNSIPPort port
)
1191 DNSServer
**p
= &m
->DNSServers
;
1193 if (!d
) d
= (const domainname
*)"";
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
);
1199 while (*p
) // Check if we already have this {server,domain} pair registered
1201 if ((*p
)->interface
== interface
&& (*p
)->teststate
!= DNSServer_Disabled
&&
1202 mDNSSameAddress(&(*p
)->addr
, addr
) && mDNSSameIPPort((*p
)->port
, port
) && SameDomainName(&(*p
)->domain
, d
))
1204 if (!(*p
)->del
) LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr
, d
->c
);
1205 (*p
)->del
= mDNSfalse
;
1211 // allocate, add to list
1212 *p
= mDNSPlatformMemAllocate(sizeof(**p
));
1213 if (!*p
) LogMsg("Error: mDNS_AddDNSServer - malloc");
1216 (*p
)->interface
= interface
;
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
;
1228 // ***************************************************************************
1229 #if COMPILER_LIKES_PRAGMA_MARK
1230 #pragma mark - authorization management
1233 mDNSlocal DomainAuthInfo
*GetAuthInfoForName_direct(mDNS
*m
, const domainname
*const name
)
1235 const domainname
*n
= name
;
1238 DomainAuthInfo
*ptr
;
1239 for (ptr
= m
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
1240 if (SameDomainName(&ptr
->domain
, n
))
1242 debugf("GetAuthInfoForName %##s Matched %##s Key name %##s", name
->c
, ptr
->domain
.c
, ptr
->keyname
.c
);
1245 n
= (const domainname
*)(n
->c
+ 1 + n
->c
[0]);
1247 //LogOperation("GetAuthInfoForName none found for %##s", name->c);
1251 // MUST be called with lock held
1252 mDNSexport DomainAuthInfo
*GetAuthInfoForName_internal(mDNS
*m
, const domainname
*const name
)
1254 DomainAuthInfo
**p
= &m
->AuthInfoList
;
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
);
1259 // First purge any dead keys from the list
1262 if ((*p
)->deltime
&& m
->timenow
- (*p
)->deltime
>= 0 && AutoTunnelUnregistered(*p
))
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
)
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
));
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
);
1286 return(GetAuthInfoForName_direct(m
, name
));
1289 mDNSexport DomainAuthInfo
*GetAuthInfoForName(mDNS
*m
, const domainname
*const name
)
1293 d
= GetAuthInfoForName_internal(m
, name
);
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
)
1303 DomainAuthInfo
**p
= &m
->AuthInfoList
;
1304 if (!info
|| !b64keydata
) { LogMsg("mDNS_SetSecretForDomain: ERROR: info %p b64keydata %p", info
, b64keydata
); return(mStatus_BadParamErr
); }
1306 LogOperation("mDNS_SetSecretForDomain: domain %##s key %##s%s", domain
->c
, keyname
->c
, AutoTunnel
? " AutoTunnel" : "");
1308 info
->AutoTunnel
= AutoTunnel
;
1309 AssignDomainName(&info
->domain
, domain
);
1310 AssignDomainName(&info
->keyname
, keyname
);
1311 mDNS_snprintf(info
->b64keydata
, sizeof(info
->b64keydata
), "%s", b64keydata
);
1313 if (DNSDigest_ConstructHMACKeyfromBase64(info
, b64keydata
) < 0)
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
);
1320 // Don't clear deltime until after we've ascertained that b64keydata is valid
1323 while (*p
&& (*p
) != info
) p
=&(*p
)->next
;
1324 if (*p
) return(mStatus_AlreadyRegistered
);
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
;
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
)
1340 DomainAuthInfo
*newinfo
= GetAuthInfoForQuestion(m
, q
);
1341 if (q
->AuthInfo
!= newinfo
)
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
;
1350 return(mStatus_NoError
);
1353 // ***************************************************************************
1354 #if COMPILER_LIKES_PRAGMA_MARK
1356 #pragma mark - NAT Traversal
1359 mDNSlocal mStatus
uDNS_SendNATMsg(mDNS
*m
, NATTraversalInfo
*info
)
1361 mStatus err
= mStatus_NoError
;
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
))
1366 union { NATAddrRequest NATAddrReq
; NATPortMapRequest NATPortReq
; } u
= { { NATMAP_VERS
, NATOp_AddrRequest
} } ;
1367 const mDNSu8
*end
= (mDNSu8
*)&u
+ sizeof(NATAddrRequest
);
1369 if (info
) // For NATOp_MapUDP and NATOp_MapTCP, fill in additional fields
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
);
1383 err
= mDNSPlatformSendUDP(m
, (mDNSu8
*)&u
, end
, 0, &m
->Router
, NATPMPPort
);
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_
1394 mDNSlocal
void RecreateNATMappings(mDNS
*const m
)
1396 NATTraversalInfo
*n
;
1397 for (n
= m
->NATTraversals
; n
; n
=n
->next
)
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_
1407 m
->NextScheduledNATOp
= m
->timenow
; // Need to send packets immediately
1410 #ifdef _LEGACY_NAT_TRAVERSAL_
1411 mDNSlocal
void ClearUPnPState(mDNS
*const m
)
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
1418 #define ClearUPnPState(X)
1419 #endif // _LEGACY_NAT_TRAVERSAL_
1421 mDNSexport
void natTraversalHandleAddressReply(mDNS
*const m
, mDNSu16 err
, mDNSv4Addr ExtAddr
)
1423 if (err
) LogMsg("Error getting external address %d", err
);
1424 else if (!mDNSSameIPv4Address(m
->ExternalAddress
, ExtAddr
))
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
1433 if (err
|| mDNSIPv4AddressIsZero(ExtAddr
)) m
->retryIntervalGetAddr
= NATMAP_INIT_RETRY
* 32; // 8 seconds
1434 else m
->retryIntervalGetAddr
= NATMAP_MAX_RETRY_INTERVAL
;
1436 m
->retryGetAddr
= m
->timenow
+ m
->retryIntervalGetAddr
;
1437 if (m
->NextScheduledNATOp
- m
->retryIntervalGetAddr
> 0)
1438 m
->NextScheduledNATOp
= m
->retryIntervalGetAddr
;
1441 // Both places that call NATSetNextRenewalTime() update m->NextScheduledNATOp correctly afterwards
1442 mDNSlocal
void NATSetNextRenewalTime(mDNS
*const m
, NATTraversalInfo
*n
)
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
;
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
)
1454 if (err
|| lease
== 0 || mDNSIPPortIsZero(extport
))
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
;
1465 if (lease
> 999999999UL / mDNSPlatformOneSecond
)
1466 lease
= 999999999UL / mDNSPlatformOneSecond
;
1467 n
->ExpiryTime
= NonZeroTime(m
->timenow
+ lease
* mDNSPlatformOneSecond
);
1469 if (!mDNSSameIPPort(n
->RequestedPort
, extport
))
1470 LogOperation("natTraversalHandlePortMapReply: public port changed from %d to %d", mDNSVal16(n
->RequestedPort
), mDNSVal16(extport
));
1472 n
->InterfaceID
= InterfaceID
;
1473 n
->RequestedPort
= extport
;
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
));
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
1484 // Must be called with the mDNS_Lock held
1485 mDNSexport mStatus
mDNS_StartNATOperation_internal(mDNS
*const m
, NATTraversalInfo
*traversal
)
1487 NATTraversalInfo
**n
;
1489 LogOperation("mDNS_StartNATOperation_internal %d %d %d %d",
1490 traversal
->Protocol
, mDNSVal16(traversal
->IntPort
), mDNSVal16(traversal
->RequestedPort
), traversal
->NATLease
);
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
); }
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
;
1508 // set default lease if necessary
1509 if (!traversal
->NATLease
) traversal
->NATLease
= NATMAP_DEFAULT_LEASE
;
1511 #ifdef _LEGACY_NAT_TRAVERSAL_
1512 mDNSPlatformMemZero(&traversal
->tcpInfo
, sizeof(traversal
->tcpInfo
));
1513 #endif _LEGACY_NAT_TRAVERSAL_
1515 if (!m
->NATTraversals
) // If this is our first NAT request, kick off an address request too
1517 m
->retryGetAddr
= m
->timenow
;
1518 m
->retryIntervalGetAddr
= NATMAP_INIT_RETRY
;
1521 m
->NextScheduledNATOp
= m
->timenow
; // This will always trigger sending the packet ASAP, and generate client callback if necessary
1523 *n
= traversal
; // Append new NATTraversalInfo to the end of our list
1525 return(mStatus_NoError
);
1528 // Must be called with the mDNS_Lock held
1529 mDNSexport mStatus
mDNS_StopNATOperation_internal(mDNS
*m
, NATTraversalInfo
*traversal
)
1531 NATTraversalInfo
**ptr
= &m
->NATTraversals
;
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
1537 LogMsg("mDNS_StopNATOperation: NATTraversalInfo %p not found in list", traversal
);
1538 return(mStatus_BadReferenceErr
);
1541 LogOperation("mDNS_StopNATOperation_internal %d %d %d %d",
1542 traversal
->Protocol
, mDNSVal16(traversal
->IntPort
), mDNSVal16(traversal
->RequestedPort
), traversal
->NATLease
);
1544 if (m
->CurrentNATTraversal
== traversal
)
1545 m
->CurrentNATTraversal
= m
->CurrentNATTraversal
->next
;
1547 if (traversal
->ExpiryTime
)
1549 traversal
->NATLease
= 0;
1550 traversal
->retryInterval
= 0;
1551 uDNS_SendNATMsg(m
, traversal
);
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_
1556 mStatus err
= LNT_UnmapPort(m
, traversal
);
1557 if (err
) LogMsg("Legacy NAT Traversal - unmap request failed with error %ld", err
);
1559 #endif // _LEGACY_NAT_TRAVERSAL_
1560 return(mStatus_NoError
);
1563 mDNSexport mStatus
mDNS_StartNATOperation(mDNS
*m
, NATTraversalInfo
*traversal
)
1567 status
= mDNS_StartNATOperation_internal(m
, traversal
);
1572 mDNSexport mStatus
mDNS_StopNATOperation(mDNS
*m
, NATTraversalInfo
*traversal
)
1576 status
= mDNS_StopNATOperation_internal(m
, traversal
);
1581 // ***************************************************************************
1582 #if COMPILER_LIKES_PRAGMA_MARK
1584 #pragma mark - Long-Lived Queries
1587 // Lock must be held -- otherwise m->timenow is undefined
1588 mDNSlocal
void StartLLQPolling(mDNS
*const m
, DNSQuestion
*q
)
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
);
1599 mDNSlocal mDNSu8
*putLLQ(DNSMessage
*const msg
, mDNSu8
*ptr
, const DNSQuestion
*const question
, const LLQOptData
*const data
, mDNSBool includeQuestion
)
1602 ResourceRecord
*opt
= &rr
.resrec
;
1605 //!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section
1606 if (includeQuestion
)
1608 ptr
= putQuestion(msg
, ptr
, msg
->data
+ AbsoluteMaxDNSMessageData
, &question
->qname
, question
->qtype
, question
->qclass
);
1609 if (!ptr
) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL
; }
1611 // locate OptRR if it exists, set pointer to end
1612 // !!!KRS implement me
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
;
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
; }
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.
1637 mDNSlocal mDNSu16
GetLLQEventPort(const mDNS
*const m
, const mDNSAddr
*const dst
)
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
));
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
)
1649 mDNSu8
*responsePtr
= m
->omsg
.data
;
1652 if (q
->ntries
++ == kLLQ_MAX_TRIES
)
1654 LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s", kLLQ_MAX_TRIES
, q
->qname
.c
);
1655 StartLLQPolling(m
,q
);
1659 if (!llq
) // Retransmission: need to make a new LLQOptData
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
1665 llqBuf
.llqlease
= q
->origLease
;
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
);
1673 // To simulate loss of challenge response packet, uncomment line below
1674 //if (q->ntries == 1) return;
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
);
1683 mDNSlocal
void SetLLQTimer(mDNS
*const m
, DNSQuestion
*const q
, const LLQOptData
*const llq
)
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
);
1693 mDNSlocal
void recvSetupResponse(mDNS
*const m
, mDNSu8 rcode
, DNSQuestion
*const q
, const LLQOptData
*const llq
)
1695 if (rcode
&& rcode
!= kDNSFlag1_RC_NXDomain
)
1696 { LogMsg("ERROR: recvSetupResponse %##s - rcode && rcode != kDNSFlag1_RC_NXDomain", q
->qname
.c
); return; }
1698 if (llq
->llqOp
!= kLLQOp_Setup
)
1699 { LogMsg("ERROR: recvSetupResponse %##s - bad op %d", q
->qname
.c
, llq
->llqOp
); return; }
1701 if (llq
->vers
!= kLLQ_Vers
)
1702 { LogMsg("ERROR: recvSetupResponse %##s - bad vers %d", q
->qname
.c
, llq
->vers
); return; }
1704 if (q
->state
== LLQ_InitialRequest
)
1706 //LogOperation("Got LLQ_InitialRequest");
1708 if (llq
->err
) { LogMsg("recvSetupResponse - received llq->err %d from server", llq
->err
); StartLLQPolling(m
,q
); return; }
1710 if (q
->origLease
!= llq
->llqlease
)
1711 debugf("recvSetupResponse: requested lease %lu, granted lease %lu", q
->origLease
, llq
->llqlease
);
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
);
1718 q
->state
= LLQ_SecondaryRequest
;
1720 q
->ntries
= 0; // first attempt to send response
1721 sendChallengeResponse(m
, q
, llq
);
1723 else if (q
->state
== LLQ_SecondaryRequest
)
1725 //LogOperation("Got LLQ_SecondaryRequest");
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.
1733 LogOperation("Private LLQ_SecondaryRequest; copying id %08X%08X", llq
->id
.l
[0], llq
->id
.l
[1]);
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
;
1742 SetLLQTimer(m
, q
, llq
);
1746 mDNSexport uDNS_LLQType
uDNS_recvLLQResponse(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
, const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
)
1748 DNSQuestion pktQ
, *q
;
1749 if (msg
->h
.numQuestions
&& getQuestion(msg
, msg
->data
, end
, 0, &pktQ
))
1751 const rdataOPT
*opt
= GetLLQOptData(m
, msg
, end
);
1753 for (q
= m
->Questions
; q
; q
= q
->next
)
1755 if (!mDNSOpaque16IsZero(q
->TargetQID
) && q
->LongLived
&& q
->qtype
== pktQ
.qtype
&& q
->qnamehash
== pktQ
.qnamehash
&& SameDomainName(&q
->qname
, &pktQ
.qname
))
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
)
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
1771 else if (opt
&& q
->state
== LLQ_Established
&& opt
->OptData
.llq
.llqOp
== kLLQOp_Event
&& mDNSSameOpaque64(&opt
->OptData
.llq
.id
, &q
->id
))
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
;
1782 if (opt
&& mDNSSameOpaque16(msg
->h
.id
, q
->TargetQID
))
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
)
1786 if (opt
->OptData
.llq
.err
!= LLQErr_NoError
) LogMsg("recvRefreshReply: received error %d from server", opt
->OptData
.llq
.err
);
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
);
1794 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
1795 return uDNS_LLQ_Ignore
;
1797 if (q
->state
< LLQ_Established
&& mDNSSameAddress(srcaddr
, &q
->servAddr
))
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
);
1814 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
1816 return uDNS_LLQ_Not
;
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
; /* ... */ };
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
)
1826 tcpInfo_t
*tcpInfo
= (tcpInfo_t
*)context
;
1827 mDNSBool closed
= mDNSfalse
;
1829 mDNS
*m
= tcpInfo
->m
;
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
);
1842 if (ConnectionEstablished
)
1844 DomainAuthInfo
*AuthInfo
;
1845 // connection is established - send the message
1846 if (tcpInfo
->question
&& tcpInfo
->question
->LongLived
&& tcpInfo
->question
->state
== LLQ_Established
)
1848 //LogMsg("tcpCallback calling sendLLQRefresh %##s (%s)", tcpInfo->question->qname.c, DNSTypeName(tcpInfo->question->qtype));
1850 sendLLQRefresh(m
, tcpInfo
->question
, tcpInfo
->question
->origLease
);
1854 else if (tcpInfo
->question
&& tcpInfo
->question
->LongLived
&& tcpInfo
->question
->state
!= LLQ_Poll
&& !mDNSIPPortIsZero(m
->LLQNAT
.ExternalPort
))
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
; }
1871 else if (tcpInfo
->question
)
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
);
1878 end
= ((mDNSu8
*) &tcpInfo
->request
) + tcpInfo
->requestLen
;
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;
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
;
1895 err
= mDNSSendDNSMessage(m
, &tcpInfo
->request
, end
, mDNSInterface_Any
, &tcpInfo
->Addr
, tcpInfo
->Port
, sock
, AuthInfo
);
1897 if (err
) { debugf("ERROR: tcpCallback: mDNSSendDNSMessage - %ld", err
); err
= mStatus_UnknownErr
; goto exit
; }
1899 // Record time we sent this question
1900 if (tcpInfo
->question
)
1903 tcpInfo
->question
->LastQTime
= m
->timenow
;
1904 tcpInfo
->question
->ThisQInterval
= MAX_UCAST_POLL_INTERVAL
;
1905 SetNextQueryTime(m
, tcpInfo
->question
);
1912 if (tcpInfo
->nread
< 2) // First read the two-byte length preceeding the DNS message
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
; }
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
;
1928 tcpInfo
->nread
+= n
;
1929 if (tcpInfo
->nread
< 2) goto exit
;
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
; }
1935 tcpInfo
->reply
= mDNSPlatformMemAllocate(tcpInfo
->replylen
);
1936 if (!tcpInfo
->reply
) { LogMsg("ERROR: tcpCallback - malloc failed"); err
= mStatus_NoMemoryErr
; goto exit
; }
1939 n
= mDNSPlatformReadTCP(sock
, ((char *)tcpInfo
->reply
) + (tcpInfo
->nread
- 2), tcpInfo
->replylen
- (tcpInfo
->nread
- 2), &closed
);
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
; }
1944 tcpInfo
->nread
+= n
;
1946 if ((tcpInfo
->nread
- 2) == tcpInfo
->replylen
)
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
1956 tcpInfo
->replylen
= 0;
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
); }
1961 if (rr
&& rr
->resrec
.RecordType
== kDNSRecordTypeDeregistering
)
1964 LogOperation("tcpCallback: CompleteDeregistration %s", ARDisplayString(m
, rr
));
1965 CompleteDeregistration(m
, rr
); // Don't touch rr after this
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
1972 mDNSPlatformMemFree(reply
);
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
;
1985 mDNS_Lock(m
); // Need to grab the lock to get m->timenow
1987 if (tcpInfo
->question
)
1989 DNSQuestion
*q
= tcpInfo
->question
;
1990 if (q
->ThisQInterval
== 0 || q
->LastQTime
+ q
->ThisQInterval
- m
->timenow
> MAX_UCAST_POLL_INTERVAL
)
1992 q
->LastQTime
= m
->timenow
;
1993 q
->ThisQInterval
= MAX_UCAST_POLL_INTERVAL
;
1994 SetNextQueryTime(m
, q
);
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
);
2001 if (tcpInfo
->rr
) SetRecordRetry(m
, tcpInfo
->rr
, mStatus_NoError
);
2003 if (tcpInfo
->srs
) SetRecordRetry(m
, &tcpInfo
->srs
->RR_SRV
, mStatus_NoError
);
2007 DisposeTCPConn(tcpInfo
);
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
)
2016 mDNSIPPort srcport
= zeroIPPort
;
2017 tcpInfo_t
*info
= (tcpInfo_t
*)mDNSPlatformMemAllocate(sizeof(tcpInfo_t
));
2018 if (!info
) { LogMsg("ERROR: MakeTCP - memallocate failed"); return(mDNSNULL
); }
2020 mDNSPlatformMemZero(info
, sizeof(tcpInfo_t
));
2024 info
->request
= *msg
;
2025 info
->requestLen
= (int) (end
- ((mDNSu8
*)msg
));
2027 info
->question
= question
;
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
);
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.
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
); }
2049 mDNSexport
void DisposeTCPConn(struct tcpInfo_t
*tcp
)
2051 mDNSPlatformTCPCloseConnection(tcp
->sock
);
2052 if (tcp
->reply
) mDNSPlatformMemFree(tcp
->reply
);
2053 mDNSPlatformMemFree(tcp
);
2056 // Lock must be held
2057 mDNSexport
void startLLQHandshake(mDNS
*m
, DNSQuestion
*q
)
2059 if (mDNSIPv4AddressIsOnes(m
->LLQNAT
.ExternalAddress
))
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
);
2068 if (mDNSIPPortIsZero(m
->LLQNAT
.ExternalPort
))
2070 LogOperation("startLLQHandshake: Cannot receive inbound packets; will poll for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
2071 StartLLQPolling(m
, q
);
2075 if (mDNSIPPortIsZero(q
->servPort
))
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
);
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
);
2094 q
->ThisQInterval
= mDNSPlatformOneSecond
* 5; // If TCP failed (transient networking glitch) try again in five seconds
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;
2101 q
->LastQTime
= m
->timenow
;
2102 SetNextQueryTime(m
, q
);
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
));
2111 if (q
->ntries
++ >= kLLQ_MAX_TRIES
)
2113 LogMsg("startLLQHandshake: %d failed attempts for LLQ %##s Polling.", kLLQ_MAX_TRIES
, q
->qname
.c
);
2114 StartLLQPolling(m
, q
);
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
;
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; }
2132 mDNSSendDNSMessage(m
, &m
->omsg
, end
, mDNSInterface_Any
, &q
->servAddr
, q
->servPort
, mDNSNULL
, mDNSNULL
);
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
);
2144 mDNSexport
const domainname
*GetServiceTarget(mDNS
*m
, ServiceRecordSet
*srs
)
2146 LogOperation("GetServiceTarget %##s", srs
->RR_SRV
.resrec
.name
->c
);
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
);
2152 #if APPLE_OSX_mDNSResponder
2153 DomainAuthInfo
*AuthInfo
= GetAuthInfoForName_internal(m
, srs
->RR_SRV
.resrec
.name
);
2154 if (AuthInfo
&& AuthInfo
->AutoTunnel
)
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
);
2164 #endif APPLE_OSX_mDNSResponder
2166 const int srvcount
= CountLabels(srs
->RR_SRV
.resrec
.name
);
2167 HostnameInfo
*besthi
= mDNSNULL
, *hi
;
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
)
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
; }
2179 if (besthi
) return(&besthi
->fqdn
);
2181 if (m
->StaticHostname
.c
[0]) return(&m
->StaticHostname
);
2186 // Called with lock held
2187 mDNSlocal
void SendServiceRegistration(mDNS
*m
, ServiceRecordSet
*srs
)
2189 mDNSu8
*ptr
= m
->omsg
.data
;
2190 mDNSu8
*end
= (mDNSu8
*)&m
->omsg
+ sizeof(DNSMessage
);
2192 mStatus err
= mStatus_NoError
;
2193 const domainname
*target
;
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
);
2199 if (mDNSIPv4AddressIsZero(srs
->SRSUpdateServer
.ip
.v4
)) // Don't know our UpdateServer yet
2201 srs
->RR_SRV
.LastAPTime
= m
->timenow
;
2202 if (srs
->RR_SRV
.ThisAPInterval
< mDNSPlatformOneSecond
* 5)
2203 srs
->RR_SRV
.ThisAPInterval
= mDNSPlatformOneSecond
* 5;
2207 if (srs
->state
== regState_Registered
) srs
->state
= regState_Refresh
;
2209 id
= mDNS_NewMessageID(m
);
2210 InitializeDNSMessage(&m
->omsg
.h
, id
, UpdateReqFlags
);
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
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
;
2220 // construct update packet
2222 ptr
= putZone(&m
->omsg
, ptr
, end
, &srs
->zone
, mDNSOpaque16fromIntVal(srs
->RR_SRV
.resrec
.rrclass
));
2223 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
2225 if (srs
->TestForSelfConflict
)
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
; }
2232 else if (srs
->state
!= regState_Refresh
&& srs
->state
!= regState_UpdatePending
)
2234 // use SRV name for prereq
2235 //ptr = putPrereqNameNotInUse(srs->RR_SRV.resrec.name, &m->omsg, ptr, end);
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
; }
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
; }
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
; }
2249 if (srs
->state
== regState_UpdatePending
) // we're updating the txt record
2251 AuthRecord
*txt
= &srs
->RR_TXT
;
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
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
; }
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
; }
2263 target
= GetServiceTarget(m
, srs
);
2264 if (!target
|| target
->c
[0] == 0)
2266 LogOperation("SendServiceRegistration - no target for %##s", srs
->RR_SRV
.resrec
.name
->c
);
2267 srs
->state
= regState_NoTarget
;
2271 if (!SameDomainName(target
, &srs
->RR_SRV
.resrec
.rdata
->u
.srv
.target
))
2273 AssignDomainName(&srs
->RR_SRV
.resrec
.rdata
->u
.srv
.target
, target
);
2274 SetNewRData(&srs
->RR_SRV
.resrec
, mDNSNULL
, 0); // Update rdlength, rdestimate, rdatahash
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
; }
2280 if (srs
->srs_uselease
)
2281 { ptr
= putUpdateLease(&m
->omsg
, ptr
, DEFAULT_UPDATE_LEASE
); if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; } }
2283 if (srs
->state
!= regState_Refresh
&& srs
->state
!= regState_DeregDeferred
&& srs
->state
!= regState_UpdatePending
)
2284 srs
->state
= regState_Pending
;
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;
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
);
2302 SetRecordRetry(m
, &srs
->RR_SRV
, err
);
2309 LogMsg("SendServiceRegistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
2312 srs
->state
= regState_Unregistered
;
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.
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";
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";
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*)"")
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
);
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
)
2341 ZoneData
*zd
= (ZoneData
*)question
->QuestionContext
;
2343 debugf("GetZoneData_QuestionCallback: %s %s", AddRecord
? "Add" : "Rmv", RRDisplayString(m
, answer
));
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
2349 if (answer
->rrtype
== kDNSType_SOA
)
2351 debugf("GetZoneData GOT SOA %s", RRDisplayString(m
, answer
));
2352 mDNS_StopQuery(m
, question
);
2353 if (answer
->rdlength
)
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
);
2360 else if (zd
->CurrentSOA
->c
[0])
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
);
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
);
2373 else if (answer
->rrtype
== kDNSType_SRV
)
2375 debugf("GetZoneData GOT SRV %s", RRDisplayString(m
, answer
));
2376 mDNS_StopQuery(m
, question
);
2377 if (!answer
->rdlength
&& zd
->ZonePrivate
&& zd
->ZoneService
!= ZoneServiceQuery
)
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
2384 if (answer
->rdlength
)
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
);
2393 zd
->ZonePrivate
= mDNSfalse
;
2395 zd
->Port
= zeroIPPort
;
2396 zd
->Addr
= zeroAddr
;
2397 zd
->ZoneDataCallback(m
, mStatus_NoError
, zd
);
2398 mDNSPlatformMemFree(zd
);
2402 else if (answer
->rrtype
== kDNSType_A
)
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
);
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
)
2416 if (qtype
== kDNSType_SRV
)
2418 AssignDomainName(&zd
->question
.qname
, ZoneDataSRV(zd
));
2419 AppendDomainName(&zd
->question
.qname
, &zd
->ZoneName
);
2420 LogOperation("lookupDNSPort %##s", zd
->question
.qname
.c
);
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
;
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
));
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
)
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;
2454 zd
->Port
= zeroIPPort
;
2455 zd
->Addr
= zeroAddr
;
2456 zd
->ZonePrivate
= AuthInfo
? mDNStrue
: mDNSfalse
;
2457 zd
->ZoneDataCallback
= callback
;
2458 zd
->ZoneDataContext
= ZoneDataContext
;
2460 zd
->question
.QuestionContext
= zd
;
2461 AssignDomainName(&zd
->question
.qname
, zd
->CurrentSOA
);
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();
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
2477 if (q
->QuestionCallback
== GetZoneData_QuestionCallback
) return(mDNSNULL
);
2478 if (q
->qtype
== kDNSType_SOA
) return(mDNSNULL
);
2479 return(GetAuthInfoForName_internal(m
, &q
->qname
));
2482 // ***************************************************************************
2483 #if COMPILER_LIKES_PRAGMA_MARK
2484 #pragma mark - host name and interface management
2487 // Called in normal client context (lock not held)
2488 mDNSlocal
void CompleteSRVNatMap(mDNS
*m
, NATTraversalInfo
*n
)
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
);
2493 if (!srs
) { LogMsg("CompleteSRVNatMap called with unknown ServiceRecordSet object"); return; }
2494 if (!n
->NATLease
) return;
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
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
);
2510 mDNSlocal
void StartSRVNatMap(mDNS
*m
, ServiceRecordSet
*srs
)
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; }
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
);
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
)
2530 ServiceRecordSet
*srs
= (ServiceRecordSet
*)zoneData
->ZoneDataContext
;
2532 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
)
2533 LogMsg("ServiceRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
2535 srs
->nta
= mDNSNULL
;
2537 if (err
|| !zoneData
) return;
2540 AssignDomainName(&srs
->zone
, &zoneData
->ZoneName
);
2541 srs
->SRSUpdateServer
.type
= mDNSAddrType_IPv4
;
2542 srs
->SRSUpdateServer
= zoneData
->Addr
;
2543 if (!mDNSIPPortIsZero(zoneData
->Port
))
2545 srs
->SRSUpdatePort
= zoneData
->Port
;
2546 srs
->Private
= zoneData
->ZonePrivate
;
2550 debugf("Update port not advertised via SRV - guessing port 53, no lease option");
2551 srs
->SRSUpdatePort
= UnicastDNSPort
;
2552 srs
->srs_uselease
= mDNSfalse
;
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
);
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
)
2564 srs
->state
= regState_NATMap
;
2565 LogOperation("ServiceRegistrationGotZoneData StartSRVNatMap");
2566 StartSRVNatMap(m
, srs
);
2571 SendServiceRegistration(m
, srs
);
2576 mDNSlocal
void SendServiceDeregistration(mDNS
*m
, ServiceRecordSet
*srs
)
2579 mDNSu8
*ptr
= m
->omsg
.data
;
2580 mDNSu8
*end
= (mDNSu8
*)&m
->omsg
+ sizeof(DNSMessage
);
2581 mStatus err
= mStatus_UnknownErr
;
2584 if (mDNSIPv4AddressIsZero(srs
->SRSUpdateServer
.ip
.v4
)) // Don't know our UpdateServer yet
2586 srs
->RR_SRV
.LastAPTime
= m
->timenow
;
2587 if (srs
->RR_SRV
.ThisAPInterval
< mDNSPlatformOneSecond
* 5)
2588 srs
->RR_SRV
.ThisAPInterval
= mDNSPlatformOneSecond
* 5;
2592 id
= mDNS_NewMessageID(m
);
2593 InitializeDNSMessage(&m
->omsg
.h
, id
, UpdateReqFlags
);
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
; }
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
; }
2605 srs
->state
= regState_DeregPending
;
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;
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
; }
2621 SetRecordRetry(m
, &srs
->RR_SRV
, err
);
2628 LogMsg("SendServiceDeregistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
2630 srs
->state
= regState_Unregistered
;
2634 // Called with lock held
2635 mDNSlocal
void UpdateSRV(mDNS
*m
, ServiceRecordSet
*srs
)
2637 ExtraResourceRecord
*e
;
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
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
);
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
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
);
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
);
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
);
2668 if (!TargetChanged
&& !NATChanged
) return;
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
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
;
2689 case regState_NATError
:
2690 if (!NATChanged
) return;
2691 // if nat changed, register if we have a target (below)
2693 case regState_NoTarget
:
2694 if (newtarget
->c
[0])
2696 debugf("UpdateSRV: %s service %##s", HaveZoneData
? (NATChanged
&& NowNeedNATMAP
? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs
->RR_SRV
.resrec
.name
->c
);
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
);
2705 if (srs
->NATinfo
.clientContext
&& (NATChanged
|| !NowNeedNATMAP
))
2707 mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
2708 srs
->NATinfo
.clientContext
= mDNSNULL
;
2710 if (NATChanged
&& NowNeedNATMAP
&& srs
->RR_SRV
.AutoTarget
== Target_AutoHostAndNATMAP
)
2711 { srs
->state
= regState_NATMap
; StartSRVNatMap(m
, srs
); }
2712 else SendServiceRegistration(m
, srs
);
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
);
2725 default: LogMsg("UpdateSRV: Unknown state %d for %##s", srs
->state
, srs
->RR_SRV
.resrec
.name
->c
);
2729 // Called with lock held
2730 mDNSlocal
void UpdateSRVRecords(mDNS
*m
)
2732 if (CurrentServiceRecordSet
)
2733 LogMsg("UpdateSRVRecords ERROR CurrentServiceRecordSet already set");
2734 CurrentServiceRecordSet
= m
->ServiceRegistrations
;
2736 while (CurrentServiceRecordSet
)
2738 ServiceRecordSet
*s
= CurrentServiceRecordSet
;
2739 CurrentServiceRecordSet
= CurrentServiceRecordSet
->uDNS_next
;
2744 // Forward reference: AdvertiseHostname references HostnameCallback, and HostnameCallback calls AdvertiseHostname
2745 mDNSlocal
void HostnameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
);
2747 // Called in normal client context (lock not held)
2748 mDNSlocal
void hostnameGetPublicAddressCallback(mDNS
*m
, NATTraversalInfo
*n
)
2750 HostnameInfo
*h
= (HostnameInfo
*)n
->clientContext
;
2752 if (!h
) { LogMsg("RegisterHostnameRecord: registration cancelled"); return; }
2756 if (mDNSIPv4AddressIsZero(n
->ExternalAddress
) || mDNSv4AddrIsRFC1918(&n
->ExternalAddress
)) return;
2758 if (h
->arv4
.resrec
.RecordType
)
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
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
);
2774 // register record or begin NAT traversal
2775 mDNSlocal
void AdvertiseHostname(mDNS
*m
, HostnameInfo
*h
)
2777 if (!mDNSIPv4AddressIsZero(m
->AdvertisedV4
.ip
.v4
) && h
->arv4
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
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
))
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
);
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
);
2803 if (!mDNSIPv6AddressIsZero(m
->AdvertisedV6
.ip
.v6
) && h
->arv6
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
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
);
2814 mDNSlocal
void HostnameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
2816 HostnameInfo
*hi
= (HostnameInfo
*)rr
->RecordContext
;
2818 if (result
== mStatus_MemFree
)
2822 // If we're still in the Hostnames list, update to new address
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; }
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
)
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
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
);
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!");
2851 if (hi
->arv4
.state
== regState_Unregistered
&&
2852 hi
->arv6
.state
== regState_Unregistered
)
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
;
2863 // register any pending services that require a target
2865 UpdateSRVRecords(m
);
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
);
2873 LogMsg("Registered hostname %##s IP %.16a", rr
->resrec
.name
->c
, &rr
->resrec
.rdata
->u
.ipv6
);
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
;
2881 mDNSlocal
void FoundStaticHostname(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
2883 const domainname
*pktname
= &answer
->rdata
->u
.name
;
2884 domainname
*storedname
= &m
->StaticHostname
;
2885 HostnameInfo
*h
= m
->Hostnames
;
2889 debugf("FoundStaticHostname: %##s -> %##s (%s)", question
->qname
.c
, answer
->rdata
->u
.name
.c
, AddRecord
? "added" : "removed");
2890 if (AddRecord
&& !SameDomainName(pktname
, storedname
))
2892 AssignDomainName(storedname
, pktname
);
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
)
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
));
2905 UpdateSRVRecords(m
);
2908 else if (!AddRecord
&& SameDomainName(pktname
, storedname
))
2911 storedname
->c
[0] = 0;
2912 UpdateSRVRecords(m
);
2917 // Called with lock held
2918 mDNSlocal
void GetStaticHostname(mDNS
*m
)
2920 char buf
[MAX_REVERSE_MAPPING_NAME_V4
];
2921 DNSQuestion
*q
= &m
->ReverseMap
;
2922 mDNSu8
*ip
= m
->AdvertisedV4
.ip
.v4
.b
;
2925 if (m
->ReverseMap
.ThisQInterval
!= -1) mDNS_StopQuery_internal(m
, q
);
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; }
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
;
2945 err
= mDNS_StartQuery_internal(m
, q
);
2946 if (err
) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err
);
2949 mDNSexport
void mDNS_AddDynDNSHostName(mDNS
*m
, const domainname
*fqdn
, mDNSRecordCallback
*StatusCallback
, const void *StatusContext
)
2951 HostnameInfo
**ptr
= &m
->Hostnames
;
2953 LogOperation("mDNS_AddDynDNSHostName %##s", fqdn
);
2955 while (*ptr
&& !SameDomainName(fqdn
, &(*ptr
)->fqdn
)) ptr
= &(*ptr
)->next
;
2956 if (*ptr
) { LogMsg("DynDNSHostName %##s already in list", fqdn
->c
); return; }
2958 // allocate and format new address record
2959 *ptr
= mDNSPlatformMemAllocate(sizeof(**ptr
));
2960 if (!*ptr
) { LogMsg("ERROR: mDNS_AddDynDNSHostName - malloc"); return; }
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
;
2969 AdvertiseHostname(m
, *ptr
);
2972 mDNSexport
void mDNS_RemoveDynDNSHostName(mDNS
*m
, const domainname
*fqdn
)
2974 HostnameInfo
**ptr
= &m
->Hostnames
;
2976 LogOperation("mDNS_RemoveDynDNSHostName %##s", fqdn
);
2978 while (*ptr
&& !SameDomainName(fqdn
, &(*ptr
)->fqdn
)) ptr
= &(*ptr
)->next
;
2979 if (!*ptr
) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn
->c
);
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
2994 UpdateSRVRecords(m
);
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
)
3001 mDNSBool v4Changed
, v6Changed
, RouterChanged
;
3003 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
)
3004 LogMsg("mDNS_SetPrimaryInterfaceInfo: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
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; }
3012 if (v4addr
&& !mDNSv4AddressIsLinkLocal(&v4addr
->ip
.v4
)) v6addr
= mDNSNULL
;
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
);
3018 if (v4addr
&& (v4Changed
|| RouterChanged
))
3019 debugf("mDNS_SetPrimaryInterfaceInfo: address changed from %#a to %#a", &m
->AdvertisedV4
, v4addr
);
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
3026 if (v4Changed
|| RouterChanged
|| v6Changed
)
3029 LogOperation("mDNS_SetPrimaryInterfaceInfo: %s%s%s%#a %#a %#a",
3030 v4Changed
? "v4Changed " : "",
3031 RouterChanged
? "RouterChanged " : "",
3032 v6Changed
? "v6Changed " : "", v4addr
, v6addr
, router
);
3034 for (i
= m
->Hostnames
; i
; i
= i
->next
)
3036 LogOperation("mDNS_SetPrimaryInterfaceInfo updating host name registrations for %##s", i
->fqdn
.c
);
3038 if (i
->arv4
.resrec
.RecordType
> kDNSRecordTypeDeregistering
&&
3039 !mDNSSameIPv4Address(i
->arv4
.resrec
.rdata
->u
.ipv4
, m
->AdvertisedV4
.ip
.v4
))
3041 LogOperation("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m
, &i
->arv4
));
3042 mDNS_Deregister_internal(m
, &i
->arv4
, mDNS_Dereg_normal
);
3045 if (i
->arv6
.resrec
.RecordType
> kDNSRecordTypeDeregistering
&&
3046 !mDNSSameIPv6Address(i
->arv6
.resrec
.rdata
->u
.ipv6
, m
->AdvertisedV6
.ip
.v6
))
3048 LogOperation("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m
, &i
->arv6
));
3049 mDNS_Deregister_internal(m
, &i
->arv6
, mDNS_Dereg_normal
);
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
);
3057 if (v4Changed
|| RouterChanged
)
3059 m
->ExternalAddress
= zerov4Addr
;
3060 m
->retryIntervalGetAddr
= NATMAP_INIT_RETRY
;
3061 m
->retryGetAddr
= m
->timenow
;
3062 m
->NextScheduledNATOp
= m
->timenow
;
3066 UpdateSRVRecords(m
);
3067 GetStaticHostname(m
); // look up reverse map record to find any static hostnames for our IP address
3073 // ***************************************************************************
3074 #if COMPILER_LIKES_PRAGMA_MARK
3075 #pragma mark - Incoming Message Processing
3078 mDNSlocal mStatus
ParseTSIGError(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
, const domainname
*const displayname
)
3081 mStatus err
= mStatus_NoError
;
3084 ptr
= LocateAdditionals(msg
, end
);
3085 if (!ptr
) goto finish
;
3087 for (i
= 0; i
< msg
->h
.numAdditionals
; i
++)
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
)
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
;
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
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
; }
3119 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
3123 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
3127 mDNSlocal mStatus
checkUpdateResult(mDNS
*const m
, const domainname
*const displayname
, const mDNSu8 rcode
, const DNSMessage
*const msg
, const mDNSu8
*const end
)
3129 (void)msg
; // currently unused, needed for TSIG errors
3130 if (!rcode
) return mStatus_NoError
;
3131 else if (rcode
== kDNSFlag1_RC_YXDomain
)
3133 debugf("name in use: %##s", displayname
->c
);
3134 return mStatus_NameConflict
;
3136 else if (rcode
== kDNSFlag1_RC_Refused
)
3138 LogMsg("Update %##s refused", displayname
->c
);
3139 return mStatus_Refused
;
3141 else if (rcode
== kDNSFlag1_RC_NXRRSet
)
3143 LogMsg("Reregister refused (NXRRSET): %##s", displayname
->c
);
3144 return mStatus_NoSuchRecord
;
3146 else if (rcode
== kDNSFlag1_RC_NotAuth
)
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
);
3152 LogMsg("Permission denied (NOAUTH): %##s", displayname
->c
);
3153 return mStatus_UnknownErr
;
3155 else return tsigerr
;
3157 else if (rcode
== kDNSFlag1_RC_FmtErr
)
3159 mStatus tsigerr
= ParseTSIGError(m
, msg
, end
, displayname
);
3162 LogMsg("Format Error: %##s", displayname
->c
);
3163 return mStatus_UnknownErr
;
3165 else return tsigerr
;
3169 LogMsg("Update %##s failed with rcode %d", displayname
->c
, rcode
);
3170 return mStatus_UnknownErr
;
3174 // Called with lock held
3175 mDNSlocal
void SendRecordRegistration(mDNS
*const m
, AuthRecord
*rr
)
3177 mDNSu8
*ptr
= m
->omsg
.data
;
3178 mDNSu8
*end
= (mDNSu8
*)&m
->omsg
+ sizeof(DNSMessage
);
3179 mStatus err
= mStatus_UnknownErr
;
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
);
3184 if (mDNSIPv4AddressIsZero(rr
->UpdateServer
.ip
.v4
)) // Don't know our UpdateServer yet
3186 rr
->LastAPTime
= m
->timenow
;
3187 if (rr
->ThisAPInterval
< mDNSPlatformOneSecond
* 5)
3188 rr
->ThisAPInterval
= mDNSPlatformOneSecond
* 5;
3192 rr
->RequireGoodbye
= mDNStrue
;
3193 rr
->id
= mDNS_NewMessageID(m
);
3194 InitializeDNSMessage(&m
->omsg
.h
, rr
->id
, UpdateReqFlags
);
3197 ptr
= putZone(&m
->omsg
, ptr
, end
, &rr
->zone
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
3198 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
3200 if (rr
->state
== regState_UpdatePending
)
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
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
; }
3213 if (rr
->resrec
.RecordType
== kDNSRecordTypeKnownUnique
)
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
; }
3220 else if (rr
->resrec
.RecordType
!= kDNSRecordTypeShared
)
3222 ptr
= putPrereqNameNotInUse(rr
->resrec
.name
, &m
->omsg
, ptr
, end
);
3223 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
3226 ptr
= PutResourceRecordTTLJumbo(&m
->omsg
, ptr
, &m
->omsg
.h
.mDNS_numUpdates
, &rr
->resrec
, rr
->resrec
.rroriginalttl
);
3227 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
3232 ptr
= putUpdateLease(&m
->omsg
, ptr
, DEFAULT_UPDATE_LEASE
); if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
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;
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
);
3250 SetRecordRetry(m
, rr
, err
);
3252 if (rr
->state
!= regState_Refresh
&& rr
->state
!= regState_DeregDeferred
&& rr
->state
!= regState_UpdatePending
)
3253 rr
->state
= regState_Pending
;
3258 LogMsg("SendRecordRegistration: Error formatting message for %s", ARDisplayString(m
, rr
));
3261 // Called with lock held
3262 mDNSlocal
void hndlServiceUpdateReply(mDNS
*const m
, ServiceRecordSet
*srs
, mStatus err
)
3264 mDNSBool InvokeCallback
= mDNSfalse
;
3265 ExtraResourceRecord
**e
= &srs
->Extras
;
3266 AuthRecord
*txt
= &srs
->RR_TXT
;
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
);
3271 SetRecordRetry(m
, &srs
->RR_SRV
, mStatus_NoError
);
3275 case regState_Pending
:
3276 if (err
== mStatus_NameConflict
&& !srs
->TestForSelfConflict
)
3278 srs
->TestForSelfConflict
= mDNStrue
;
3279 debugf("checking for self-conflict of service %##s", srs
->RR_SRV
.resrec
.name
->c
);
3280 SendServiceRegistration(m
, srs
);
3283 else if (srs
->TestForSelfConflict
)
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
;
3291 else if (srs
->srs_uselease
&& err
== mStatus_UnknownErr
&& mDNSSameIPPort(srs
->SRSUpdatePort
, UnicastDNSPort
))
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
);
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
;
3306 case regState_Refresh
:
3309 LogMsg("Error %ld for refresh of service %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
3310 InvokeCallback
= mDNStrue
;
3312 else srs
->state
= regState_Registered
;
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
)
3318 srs
->state
= regState_NoTarget
; // NoTarget will allow us to pick up new target OR nat traversal state
3321 err
= mStatus_MemFree
;
3322 InvokeCallback
= mDNStrue
;
3323 if (srs
->NATinfo
.clientContext
)
3325 // deletion completed
3326 mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
3327 srs
->NATinfo
.clientContext
= mDNSNULL
;
3329 srs
->state
= regState_Unregistered
;
3331 case regState_DeregDeferred
:
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
;
3342 debugf("Performing deferred deregistration of %##s", srs
->RR_SRV
.resrec
.name
->c
);
3343 srs
->state
= regState_Registered
;
3344 SendServiceDeregistration(m
, srs
);
3347 case regState_UpdatePending
:
3350 LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs
->RR_SRV
.resrec
.name
->c
);
3351 InvokeCallback
= mDNStrue
;
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
;
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
);
3376 if ((srs
->SRVChanged
|| srs
->SRVUpdateDeferred
) && (srs
->state
== regState_NoTarget
|| srs
->state
== regState_Registered
))
3378 LogOperation("hndlServiceUpdateReply: SRVChanged %d SRVUpdateDeferred %d state %d", srs
->SRVChanged
, srs
->SRVUpdateDeferred
, srs
->state
);
3381 srs
->ClientCallbackDeferred
= mDNStrue
;
3382 srs
->DeferredStatus
= err
;
3384 srs
->SRVChanged
= srs
->SRVUpdateDeferred
= mDNSfalse
;
3391 if ((*e
)->r
.state
== regState_ExtraQueued
)
3393 if (srs
->state
== regState_Registered
&& !err
)
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
);
3403 else if (err
&& (*e
)->r
.state
!= regState_Unregistered
)
3405 // unlink extra from list
3406 (*e
)->r
.state
= regState_Unregistered
;
3409 else e
= &(*e
)->next
;
3411 else e
= &(*e
)->next
;
3414 if (srs
->state
== regState_Unregistered
)
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
);
3421 else if (txt
->QueuedRData
&& srs
->state
== regState_Registered
)
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
;
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
);
3439 mDNS_DropLockBeforeCallback();
3441 srs
->ServiceCallback(m
, srs
, err
);
3442 else if (srs
->ClientCallbackDeferred
)
3444 srs
->ClientCallbackDeferred
= mDNSfalse
;
3445 srs
->ServiceCallback(m
, srs
, srs
->DeferredStatus
);
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.
3452 // Called with lock held
3453 mDNSlocal
void hndlRecordUpdateReply(mDNS
*m
, AuthRecord
*rr
, mStatus err
)
3455 mDNSBool InvokeCallback
= mDNStrue
;
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
);
3460 SetRecordRetry(m
, rr
, mStatus_NoError
);
3462 if (rr
->state
== regState_UpdatePending
)
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
;
3473 if (rr
->state
== regState_DeregPending
)
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
;
3482 if (rr
->state
== regState_DeregDeferred
)
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
;
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
);
3496 if (rr
->state
== regState_Pending
|| rr
->state
== regState_Refresh
)
3500 rr
->state
= regState_Registered
;
3501 if (rr
->state
== regState_Refresh
) InvokeCallback
= mDNSfalse
;
3505 if (rr
->uselease
&& err
== mStatus_UnknownErr
&& mDNSSameIPPort(rr
->UpdatePort
, UnicastDNSPort
))
3507 LogMsg("Re-trying update of record %##s without lease option", rr
->resrec
.name
->c
);
3508 rr
->uselease
= mDNSfalse
;
3509 SendRecordRegistration(m
, rr
);
3512 LogMsg("hndlRecordUpdateReply: Registration of record %##s type %d failed with error %ld", rr
->resrec
.name
->c
, rr
->resrec
.rrtype
, err
);
3517 if (rr
->state
== regState_Unregistered
) // Should never happen
3519 LogMsg("hndlRecordUpdateReply rr->state == regState_Unregistered %s", ARDisplayString(m
, rr
));
3523 if (rr
->QueuedRData
&& rr
->state
== regState_Registered
)
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
);
3535 if (InvokeCallback
&& rr
->RecordCallback
)
3537 mDNS_DropLockBeforeCallback();
3538 rr
->RecordCallback(m
, rr
, err
);
3539 mDNS_ReclaimLockAfterCallback();
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.
3545 mDNSexport
void uDNS_ReceiveNATPMPPacket(mDNS
*m
, const mDNSInterfaceID InterfaceID
, mDNSu8
*pkt
, mDNSu16 len
)
3547 NATTraversalInfo
*ptr
;
3548 NATAddrReply
*AddrReply
= (NATAddrReply
*)pkt
;
3549 NATPortMapReply
*PortMapReply
= (NATPortMapReply
*)pkt
;
3550 mDNSu32 nat_elapsed
, our_elapsed
;
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; }
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]);
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
);
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
); }
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
3578 if (AddrReply
->opcode
== NATOp_AddrResponse
)
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
);
3583 else if (AddrReply
->opcode
== NATOp_MapUDPResponse
|| AddrReply
->opcode
== NATOp_MapTCPResponse
)
3585 mDNSu8 Protocol
= AddrReply
->opcode
& 0x7F;
3586 if (!PortMapReply
->err
)
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]);
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
);
3596 else { LogMsg("Received NAT Traversal response with version unknown opcode 0x%X", AddrReply
->opcode
); return; }
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
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.
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.
3615 // 2. Any query that results in a large response with the TC bit set.
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.
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.
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.
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.
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";
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
)
3649 const mDNSu8
*ptr
= msg
->data
;
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
);
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
;
3666 result
= DNSServer_Passed
;
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
)
3673 if (s
->teststate
!= result
)
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
));
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
; }
3685 return(mDNStrue
); // Return mDNStrue to tell uDNS_ReceiveMsg it doesn't need to process this packet further
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
)
3692 mStatus err
= mStatus_NoError
;
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
);
3699 (void)srcport
; // Unused
3701 debugf("uDNS_ReceiveMsg from %#-15a with "
3702 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
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");
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
)
3716 if (!srcaddr
) LogMsg("uDNS_ReceiveMsg: TCP DNS response had TC bit set: ignoring");
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();
3727 else qptr
->tcp
= MakeTCPConn(m
, mDNSNULL
, mDNSNULL
, kTCPSocketFlags_Zero
, srcaddr
, srcport
, qptr
, mDNSNULL
, mDNSNULL
);
3731 if (QR_OP
== UpdateR
)
3733 mDNSu32 lease
= GetPktLease(m
, msg
, end
);
3734 mDNSs32 expire
= m
->timenow
+ (mDNSs32
)lease
* mDNSPlatformOneSecond
;
3736 //rcode = kDNSFlag1_RC_SrvErr; // Simulate server failure (rcode 2)
3738 if (CurrentServiceRecordSet
)
3739 LogMsg("uDNS_ReceiveMsg ERROR CurrentServiceRecordSet already set");
3740 CurrentServiceRecordSet
= m
->ServiceRegistrations
;
3742 while (CurrentServiceRecordSet
)
3744 ServiceRecordSet
*sptr
= CurrentServiceRecordSet
;
3745 CurrentServiceRecordSet
= CurrentServiceRecordSet
->uDNS_next
;
3747 if (mDNSSameOpaque16(sptr
->id
, msg
->h
.id
))
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
;
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
)
3764 AuthRecord
*rptr
= m
->CurrentRecord
;
3765 m
->CurrentRecord
= m
->CurrentRecord
->next
;
3766 if (mDNSSameOpaque16(rptr
->id
, msg
->h
.id
))
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
;
3778 debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg
->h
.id
));
3781 // ***************************************************************************
3782 #if COMPILER_LIKES_PRAGMA_MARK
3783 #pragma mark - Query Routines
3786 mDNSexport
void sendLLQRefresh(mDNS
*m
, DNSQuestion
*q
, mDNSu32 lease
)
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;
3797 if (q
->AuthInfo
&& !q
->tcp
)
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
);
3806 if ((q
->state
== LLQ_Established
&& q
->ntries
>= kLLQ_MAX_TRIES
) || q
->expire
- m
->timenow
< 0)
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
);
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
3817 llq
.llqlease
= lease
;
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; }
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
);
3828 debugf("sendLLQRefresh ntries %d %##s (%s)", q
->ntries
, q
->qname
.c
, DNSTypeName(q
->qtype
));
3830 q
->LastQTime
= m
->timenow
;
3831 SetNextQueryTime(m
, q
);
3834 mDNSexport
void LLQGotZoneData(mDNS
*const m
, mStatus err
, const ZoneData
*zoneInfo
)
3836 DNSQuestion
*q
= (DNSQuestion
*)zoneInfo
->ZoneDataContext
;
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).
3844 q
->servAddr
= zeroAddr
;
3845 q
->servPort
= zeroIPPort
;
3847 if (!err
&& zoneInfo
&& !mDNSIPPortIsZero(zoneInfo
->Port
))
3849 q
->servAddr
= zoneInfo
->Addr
;
3850 q
->servPort
= zoneInfo
->Port
;
3851 q
->AuthInfo
= zoneInfo
->ZonePrivate
? GetAuthInfoForName_internal(m
, &q
->qname
) : mDNSNULL
;
3853 LogOperation("LLQGotZoneData %#a:%d", &q
->servAddr
, mDNSVal16(q
->servPort
));
3854 startLLQHandshake(m
, q
);
3857 StartLLQPolling(m
,q
);
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
)
3865 DNSQuestion
*q
= (DNSQuestion
*) zoneInfo
->ZoneDataContext
;
3867 LogOperation("PrivateQueryGotZoneData %##s (%s) err %d Zone %##s Private %d", q
->qname
.c
, DNSTypeName(q
->qtype
), err
, zoneInfo
->ZoneName
.c
, zoneInfo
->ZonePrivate
);
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).
3876 LogMsg("ERROR: PrivateQueryGotZoneData %##s (%s) invoked with error code %ld", q
->qname
.c
, DNSTypeName(q
->qtype
), err
);
3880 if (!zoneInfo
->ZonePrivate
)
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
;
3887 SetNextQueryTime(m
, q
);
3890 // Next call to uDNS_CheckCurrentQuestion() will do this as a non-private query
3895 LogMsg("ERROR: PrivateQueryGotZoneData: cannot find credentials for q %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
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
);
3904 // ***************************************************************************
3905 #if COMPILER_LIKES_PRAGMA_MARK
3906 #pragma mark - Dynamic Updates
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
)
3912 AuthRecord
*newRR
= (AuthRecord
*)zoneData
->ZoneDataContext
;
3915 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
)
3916 LogMsg("RecordRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
3918 newRR
->nta
= mDNSNULL
;
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; }
3924 // check error/result
3927 if (err
!= mStatus_NoSuchNameErr
) LogMsg("RecordRegistrationGotZoneData: error %ld", err
);
3931 if (!zoneData
) { LogMsg("ERROR: RecordRegistrationGotZoneData invoked with NULL result and no error"); return; }
3933 if (newRR
->resrec
.rrclass
!= zoneData
->ZoneClass
)
3935 LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)", newRR
->resrec
.rrclass
, zoneData
->ZoneClass
);
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)
3944 LogOperation("RecordRegistrationGotZoneData: No name server found claiming responsibility for \"%##s\"!", newRR
->resrec
.name
->c
);
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
));
3956 if (mDNSIPPortIsZero(zoneData
->Port
) || mDNSAddressIsZero(&zoneData
->Addr
))
3958 LogOperation("RecordRegistrationGotZoneData: No _dns-update._udp service found for \"%##s\"!", newRR
->resrec
.name
->c
);
3962 mDNS_Lock(m
); // SendRecordRegistration expects to be called with the lock held
3963 SendRecordRegistration(m
, newRR
);
3967 mDNSlocal
void SendRecordDeregistration(mDNS
*m
, AuthRecord
*rr
)
3969 mDNSu8
*ptr
= m
->omsg
.data
;
3970 mDNSu8
*end
= (mDNSu8
*)&m
->omsg
+ sizeof(DNSMessage
);
3972 if (mDNSIPv4AddressIsZero(rr
->UpdateServer
.ip
.v4
)) // Don't know our UpdateServer yet
3974 rr
->LastAPTime
= m
->timenow
;
3975 if (rr
->ThisAPInterval
< mDNSPlatformOneSecond
* 5)
3976 rr
->ThisAPInterval
= mDNSPlatformOneSecond
* 5;
3980 InitializeDNSMessage(&m
->omsg
.h
, rr
->id
, UpdateReqFlags
);
3982 ptr
= putZone(&m
->omsg
, ptr
, end
, &rr
->zone
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
3983 if (ptr
) ptr
= putDeletionRecord(&m
->omsg
, ptr
, &rr
->resrec
);
3986 LogMsg("SendRecordDeregistration Error: could not contruct deregistration packet for %s", ARDisplayString(m
, rr
));
3987 if (rr
->state
== regState_DeregPending
) CompleteDeregistration(m
, rr
);
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
);
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
4010 mDNSexport mStatus
uDNS_DeregisterRecord(mDNS
*const m
, AuthRecord
*const rr
)
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
;
4029 if (rr
->state
!= regState_Unregistered
) { rr
->state
= regState_DeregPending
; SendRecordDeregistration(m
, rr
); }
4030 return mStatus_NoError
;
4033 // Called with lock held
4034 mDNSexport mStatus
uDNS_DeregisterService(mDNS
*const m
, ServiceRecordSet
*srs
)
4036 char *errmsg
= "Unknown State";
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
);
4041 // don't re-register with a new target following deregistration
4042 srs
->SRVChanged
= srs
->SRVUpdateDeferred
= mDNSfalse
;
4044 if (srs
->nta
) { CancelGetZoneData(m
, srs
->nta
); srs
->nta
= mDNSNULL
; }
4046 if (srs
->NATinfo
.clientContext
)
4048 mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
4049 srs
->NATinfo
.clientContext
= mDNSNULL
;
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
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)";
4081 default: LogMsg("uDNS_DeregisterService: Unknown state %d for %##s", srs
->state
, srs
->RR_SRV
.resrec
.name
->c
);
4085 LogMsg("Error, uDNS_DeregisterService: %s", errmsg
);
4086 return mStatus_BadReferenceErr
;
4089 mDNSexport mStatus
uDNS_UpdateRecord(mDNS
*m
, AuthRecord
*rr
)
4091 ServiceRecordSet
*parent
= mDNSNULL
;
4093 regState_t
*stateptr
= mDNSNULL
;
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; }
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
;
4109 case regState_DeregPending
:
4110 case regState_DeregDeferred
:
4111 case regState_Unregistered
:
4112 // not actively registered
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
;
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
;
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
;
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
4152 default: LogMsg("uDNS_UpdateRecord: Unknown state %d for %##s", *stateptr
, rr
->resrec
.name
->c
);
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
;
4161 // ***************************************************************************
4162 #if COMPILER_LIKES_PRAGMA_MARK
4163 #pragma mark - Periodic Execution Routines
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
)
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
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
);
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"));
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
)
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;
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)
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
))
4212 if (q
->qDNSServer
&& q
->qDNSServer
->teststate
!= DNSServer_Disabled
)
4214 mDNSu8
*end
= m
->omsg
.data
;
4215 mStatus err
= mStatus_NoError
;
4216 DomainAuthInfo
*private = mDNSNULL
;
4218 if (q
->qDNSServer
->teststate
!= DNSServer_Untested
|| NoTestQuery(q
))
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
;
4224 else if (m
->timenow
- q
->qDNSServer
->lasttest
>= INIT_UCAST_POLL_INTERVAL
) // Make sure at least three seconds has elapsed since last test query
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
);
4233 if (end
> m
->omsg
.data
&& (q
->qDNSServer
->teststate
!= DNSServer_Failed
|| NoTestQuery(q
)))
4235 //LogMsg("uDNS_CheckCurrentQuestion %d %p %##s (%s)", sendtime - m->timenow, private, q->qname.c, DNSTypeName(q->qtype));
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
;
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);
4249 if (err
) debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %ld", err
); // surpress syslog messages if we have no network
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
));
4257 q
->LastQTime
= m
->timenow
;
4258 SetNextQueryTime(m
, q
);
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.)
4272 const mDNSu32 slot
= HashSlot(&q
->qname
);
4273 CacheGroup
*const cg
= CacheGroupForName(m
, slot
, q
->qnamehash
, &q
->qname
);
4275 for (rr
= cg
->members
; rr
; rr
=rr
->next
)
4276 if (SameNameRecordAnswersQuestion(&rr
->resrec
, q
)) mDNS_PurgeCacheResourceRecord(m
, rr
);
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
);
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
4291 mDNSlocal
void CheckNATMappings(mDNS
*m
)
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;
4298 if (HaveRoutable
) m
->ExternalAddress
= m
->AdvertisedV4
.ip
.v4
;
4300 if (m
->NATTraversals
&& rfc1918
) // Do we need to open NAT-PMP socket to receive multicast announcements from router?
4302 if (m
->NATMcastRecvskt
== mDNSNULL
) // If we are behind a NAT and the socket hasn't been opened yet, open it
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");
4310 else // else, we don't want to listen for announcements, so close them if they're open
4312 if (m
->NATMcastRecvskt
) { mDNSPlatformUDPClose(m
->NATMcastRecvskt
); m
->NATMcastRecvskt
= mDNSNULL
; }
4313 if (m
->NATMcastRecvsk2
) { mDNSPlatformUDPClose(m
->NATMcastRecvsk2
); m
->NATMcastRecvsk2
= mDNSNULL
; }
4316 if (m
->NATTraversals
)
4318 if (m
->timenow
- m
->retryGetAddr
>= 0)
4320 err
= uDNS_SendNATMsg(m
, mDNSNULL
); // Will also do UPnP discovery for us, if necessary
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
;
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
;
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
;
4336 if (m
->CurrentNATTraversal
) LogMsg("WARNING m->CurrentNATTraversal already in use");
4337 m
->CurrentNATTraversal
= m
->NATTraversals
;
4339 while (m
->CurrentNATTraversal
)
4341 NATTraversalInfo
*cur
= m
->CurrentNATTraversal
;
4342 m
->CurrentNATTraversal
= m
->CurrentNATTraversal
->next
;
4344 if (HaveRoutable
) // If not RFC 1918 address, our own address and port are effectively our external address and port
4346 cur
->ExpiryTime
= 0;
4347 cur
->NewResult
= mStatus_NoError
;
4349 else if (cur
->Protocol
) // Check if it's time to send port mapping packets
4351 if (m
->timenow
- cur
->retryPortMap
>= 0) // Time to do something with this mapping
4353 if (cur
->ExpiryTime
&& cur
->ExpiryTime
- m
->timenow
< 0) // Mapping has expired
4355 cur
->ExpiryTime
= 0;
4356 cur
->retryInterval
= NATMAP_INIT_RETRY
;
4359 //LogMsg("uDNS_SendNATMsg");
4360 err
= uDNS_SendNATMsg(m
, cur
);
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
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
;
4373 if (m
->NextScheduledNATOp
- cur
->retryPortMap
> 0)
4374 m
->NextScheduledNATOp
= cur
->retryPortMap
;
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)
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
)
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
4409 mDNSlocal mDNSs32
CheckRecordRegistrations(mDNS
*m
)
4412 mDNSs32 nextevent
= m
->timenow
+ 0x3FFFFFFF;
4414 for (rr
= m
->ResourceRecords
; rr
; rr
= rr
->next
)
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
)
4419 if (rr
->LastAPTime
+ rr
->ThisAPInterval
- m
->timenow
< 0)
4421 if (rr
->tcp
) { DisposeTCPConn(rr
->tcp
); rr
->tcp
= mDNSNULL
; }
4422 if (rr
->state
== regState_DeregPending
) SendRecordDeregistration(m
, rr
);
4423 else SendRecordRegistration(m
, rr
);
4425 if (nextevent
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) > 0)
4426 nextevent
= (rr
->LastAPTime
+ rr
->ThisAPInterval
);
4432 mDNSlocal mDNSs32
CheckServiceRegistrations(mDNS
*m
)
4434 mDNSs32 nextevent
= m
->timenow
+ 0x3FFFFFFF;
4436 if (CurrentServiceRecordSet
)
4437 LogMsg("CheckServiceRegistrations ERROR CurrentServiceRecordSet already set");
4438 CurrentServiceRecordSet
= m
->ServiceRegistrations
;
4440 // Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery
4441 while (CurrentServiceRecordSet
)
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
)
4448 if (srs
->RR_SRV
.LastAPTime
+ srs
->RR_SRV
.ThisAPInterval
- m
->timenow
<= 0)
4450 if (srs
->tcp
) { DisposeTCPConn(srs
->tcp
); srs
->tcp
= mDNSNULL
; }
4451 if (srs
->state
== regState_DeregPending
) SendServiceDeregistration(m
, srs
);
4452 else SendServiceRegistration(m
, srs
);
4454 if (nextevent
- (srs
->RR_SRV
.LastAPTime
+ srs
->RR_SRV
.ThisAPInterval
) > 0)
4455 nextevent
= (srs
->RR_SRV
.LastAPTime
+ srs
->RR_SRV
.ThisAPInterval
);
4461 mDNSexport
void uDNS_Execute(mDNS
*const m
)
4465 m
->NextuDNSEvent
= m
->timenow
+ 0x3FFFFFFF;
4467 if (m
->NextSRVUpdate
&& m
->NextSRVUpdate
- m
->timenow
< 0)
4468 { m
->NextSRVUpdate
= 0; UpdateSRVRecords(m
); }
4470 CheckNATMappings(m
);
4472 if (m
->SuppressStdPort53Queries
&& m
->timenow
- m
->SuppressStdPort53Queries
>= 0)
4473 m
->SuppressStdPort53Queries
= 0; // If suppression time has passed, clear it
4475 nexte
= CheckRecordRegistrations(m
);
4476 if (nexte
- m
->NextuDNSEvent
< 0) m
->NextuDNSEvent
= nexte
;
4478 nexte
= CheckServiceRegistrations(m
);
4479 if (nexte
- m
->NextuDNSEvent
< 0) m
->NextuDNSEvent
= nexte
;
4482 // ***************************************************************************
4483 #if COMPILER_LIKES_PRAGMA_MARK
4484 #pragma mark - Startup, Shutdown, and Sleep
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.
4492 mDNSexport
void SleepRecordRegistrations(mDNS
*m
)
4494 AuthRecord
*rr
= m
->ResourceRecords
;
4498 if (rr
->state
== regState_Registered
||
4499 rr
->state
== regState_Refresh
)
4501 SendRecordDeregistration(m
, rr
);
4502 rr
->state
= regState_Refresh
;
4503 rr
->LastAPTime
= m
->timenow
;
4504 rr
->ThisAPInterval
= 300 * mDNSPlatformOneSecond
;
4510 mDNSlocal
void WakeRecordRegistrations(mDNS
*m
)
4512 AuthRecord
*rr
= m
->ResourceRecords
;
4516 if (rr
->state
== regState_Refresh
)
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
;
4526 mDNSexport
void SleepServiceRegistrations(mDNS
*m
)
4528 ServiceRecordSet
*srs
= m
->ServiceRegistrations
;
4531 if (srs
->nta
) { CancelGetZoneData(m
, srs
->nta
); srs
->nta
= mDNSNULL
; }
4533 if (srs
->NATinfo
.clientContext
)
4535 mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
4536 srs
->NATinfo
.clientContext
= mDNSNULL
;
4539 if (srs
->state
== regState_UpdatePending
)
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
;
4551 if (srs
->state
== regState_Registered
|| srs
->state
== regState_Refresh
)
4553 mDNSOpaque16 origid
= srs
->id
;
4554 srs
->state
= regState_DeregPending
; // state expected by SendDereg()
4555 SendServiceDeregistration(m
, srs
);
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;
4560 srs
= srs
->uDNS_next
;
4564 mDNSlocal
void WakeServiceRegistrations(mDNS
*m
)
4566 ServiceRecordSet
*srs
= m
->ServiceRegistrations
;
4569 if (srs
->state
== regState_Refresh
)
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
;
4575 srs
= srs
->uDNS_next
;
4579 mDNSexport
void mDNS_AddSearchDomain(const domainname
*const domain
)
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
))
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
);
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
);
4603 mDNSlocal
void FreeARElemCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
4606 if (result
== mStatus_MemFree
) mDNSPlatformMemFree(rr
->RecordContext
);
4609 mDNSlocal
void FoundDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
4611 SearchListElem
*slElem
= question
->QuestionContext
;
4614 if (answer
->rrtype
!= kDNSType_PTR
) return;
4615 if (answer
->RecordType
== kDNSRecordTypePacketNegative
) return;
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; }
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
;
4640 ARListElem
**ptr
= &slElem
->AuthRecs
;
4643 if (SameDomainName(&(*ptr
)->ar
.resrec
.rdata
->u
.name
, &answer
->rdata
->u
.name
))
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
4653 ptr
= &(*ptr
)->next
;
4658 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
4659 mDNSexport
void udns_validatelists(void *const v
)
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
);
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
);
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
);
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
);
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
);
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
);
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
4698 mDNSexport mStatus
uDNS_RegisterSearchDomains(mDNS
*const m
)
4700 SearchListElem
**p
= &SearchList
, *ptr
;
4703 // step 1: mark each element for removal (-1)
4704 for (ptr
= SearchList
; ptr
; ptr
= ptr
->next
) ptr
->flag
= -1;
4706 // Client has requested domain enumeration or automatic browse -- time to make sure we have the search domains from the platform layer
4708 m
->RegisterSearchDomains
= mDNStrue
;
4709 mDNSPlatformSetDNSConfig(m
, mDNSfalse
, m
->RegisterSearchDomains
, mDNSNULL
, mDNSNULL
, mDNSNULL
);
4712 // delete elems marked for removal, do queries for elems marked add
4716 debugf("RegisterSearchDomains %d %p %##s", ptr
->flag
, ptr
->AuthRecs
, ptr
->domain
.c
);
4717 if (ptr
->flag
== -1) // remove
4719 ARListElem
*arList
= ptr
->AuthRecs
;
4720 ptr
->AuthRecs
= mDNSNULL
;
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
);
4730 // deregister records generated from answers to the query
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
4743 if (ptr
->flag
== 1) // add
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
);
4762 if (ptr
->flag
) { LogMsg("RegisterSearchDomains - unknown flag %d. Skipping.", ptr
->flag
); }
4767 return mStatus_NoError
;
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)
4780 mDNSexport
void uDNS_Wake(mDNS
*const m
)
4782 WakeServiceRegistrations(m
);
4783 WakeRecordRegistrations(m
);
4786 struct CompileTimeAssertionChecks_uDNS
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];