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.545 2007/12/22 02:25:29 cheshire
26 <rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep
28 Revision 1.544 2007/12/18 00:40:11 cheshire
29 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
30 Reordered code to avoid double-TSIGs in some cases
32 Revision 1.543 2007/12/17 23:57:43 cheshire
33 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
34 Need to include TSIG signature when sending LLQ cancellations over TLS
36 Revision 1.542 2007/12/15 01:12:27 cheshire
37 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
39 Revision 1.541 2007/12/15 00:18:51 cheshire
40 Renamed question->origLease to question->ReqLease
42 Revision 1.540 2007/12/14 23:55:28 cheshire
43 Moved "struct tcpInfo_t" definition from uDNS.c to mDNSEmbeddedAPI.h
45 Revision 1.539 2007/12/14 20:44:24 cheshire
46 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
47 SleepRecordRegistrations/WakeRecordRegistrations should only operate on uDNS records
49 Revision 1.538 2007/12/14 01:13:40 cheshire
50 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
51 Additional fixes (existing code to deregister private records and services didn't work at all)
53 Revision 1.537 2007/12/11 00:18:25 cheshire
54 <rdar://problem/5569316> BTMM: My iMac has a "ghost" ID associated with it
55 There were cases where the code was incorrectly clearing the "uselease" flag, and never resetting it.
57 Revision 1.536 2007/12/10 23:07:00 cheshire
58 Removed some unnecessary log messages
60 Revision 1.535 2007/12/06 00:22:27 mcguire
61 <rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
63 Revision 1.534 2007/12/04 00:49:37 cheshire
64 <rdar://problem/5607082> BTMM: mDNSResponder taking 100 percent CPU after upgrading to 10.5.1
66 Revision 1.533 2007/12/01 01:21:27 jgraessley
67 <rdar://problem/5623140> mDNSResponder unicast DNS improvements
69 Revision 1.532 2007/11/30 20:16:44 cheshire
70 Fixed compile warning: declaration of 'end' shadows a previous local
72 Revision 1.531 2007/11/28 22:00:09 cheshire
73 In StartSRVNatMap, change "mDNSu8 *p" to "const mDNSu8 *p"
75 Revision 1.530 2007/11/16 22:19:40 cheshire
76 <rdar://problem/5547474> mDNSResponder leaks on network changes
77 The "connection failed" code path in MakeTCPConn was not disposing of the TCPSocket it had created
79 Revision 1.529 2007/11/15 22:52:29 cheshire
80 <rdar://problem/5589039> ERROR: mDNSPlatformWriteTCP - send Broken pipe
82 Revision 1.528 2007/11/02 21:32:30 cheshire
83 <rdar://problem/5575593> BTMM: Deferring deregistration of record log messages on sleep/wake
85 Revision 1.527 2007/11/01 16:08:51 cheshire
86 Tidy up alignment of "SetRecordRetry refresh" log messages
88 Revision 1.526 2007/10/31 19:26:55 cheshire
89 Don't need to log "Permanently abandoning service registration" message when we're intentionally deleting a service
91 Revision 1.525 2007/10/30 23:58:59 cheshire
92 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
93 After failure, double retry interval up to maximum of 30 minutes
95 Revision 1.524 2007/10/30 20:10:47 cheshire
96 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
98 Revision 1.523 2007/10/30 00:54:31 cheshire
99 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
100 Fixed timing logic to double retry interval properly
102 Revision 1.522 2007/10/30 00:04:43 cheshire
103 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
104 Made the code not give up and abandon the record when it gets an error in regState_UpdatePending state
106 Revision 1.521 2007/10/29 23:58:52 cheshire
107 <rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
108 Use standard "if (mDNSIPv4AddressIsOnes(....ExternalAddress))" mechanism to determine whether callback has been invoked yet
110 Revision 1.520 2007/10/29 21:48:36 cheshire
111 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
112 Added 10% random variation on LLQ renewal time, to reduce unintended timing correlation between multiple machines
114 Revision 1.519 2007/10/29 21:37:00 cheshire
115 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
116 Added 10% random variation on record refresh time, to reduce accidental timing correlation between multiple machines
118 Revision 1.518 2007/10/26 23:41:29 cheshire
119 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
121 Revision 1.517 2007/10/25 23:30:12 cheshire
122 Private DNS registered records now deregistered on sleep and re-registered on wake
124 Revision 1.516 2007/10/25 22:53:52 cheshire
125 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
126 Don't unlinkSRS and permanently give up at the first sign of trouble
128 Revision 1.515 2007/10/25 21:08:07 cheshire
129 Don't try to send record registrations/deletions before we have our server address
131 Revision 1.514 2007/10/25 20:48:47 cheshire
132 For naming consistency (with AuthRecord's UpdateServer) renamed 'ns' to 'SRSUpdateServer'
134 Revision 1.513 2007/10/25 20:06:13 cheshire
135 Don't try to do SOA queries using private DNS (TLS over TCP) queries
137 Revision 1.512 2007/10/25 18:25:15 cheshire
138 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
139 Don't need a NAT mapping for autotunnel services
141 Revision 1.511 2007/10/25 00:16:23 cheshire
142 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
143 Fixed retry timing logic; when DNS server returns an error code, we should retry later,
144 instead of just deleting our record ("UnlinkAuthRecord") and completely giving up
146 Revision 1.510 2007/10/24 22:40:06 cheshire
147 Renamed: RecordRegistrationCallback -> RecordRegistrationGotZoneData
148 Renamed: ServiceRegistrationZoneDataComplete -> ServiceRegistrationGotZoneData
150 Revision 1.509 2007/10/24 00:54:07 cheshire
151 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
153 Revision 1.508 2007/10/24 00:05:03 cheshire
154 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
155 When sending TLS/TCP LLQ setup request over VPN, need to set EventPort to 5353, not zero
157 Revision 1.507 2007/10/23 00:33:36 cheshire
158 Improved debugging messages
160 Revision 1.506 2007/10/22 19:54:13 cheshire
161 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
162 Only put EventPort in LLQ request when sending from an RFC 1918 source address, not when sending over VPN
164 Revision 1.505 2007/10/19 22:08:49 cheshire
165 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
166 Additional fixes and refinements
168 Revision 1.504 2007/10/18 23:06:43 cheshire
169 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
170 Additional fixes and refinements
172 Revision 1.503 2007/10/18 20:23:17 cheshire
173 Moved SuspendLLQs into mDNS.c, since it's only called from one place
175 Revision 1.502 2007/10/17 22:49:54 cheshire
176 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
178 Revision 1.501 2007/10/17 22:37:23 cheshire
179 <rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
181 Revision 1.500 2007/10/17 21:53:51 cheshire
182 Improved debugging messages; renamed startLLQHandshakeCallback to LLQGotZoneData
184 Revision 1.499 2007/10/16 21:16:50 cheshire
185 Get rid of unused uDNS_Sleep() routine
187 Revision 1.498 2007/10/16 20:59:41 cheshire
188 Export SuspendLLQs/SleepServiceRegistrations/SleepRecordRegistrations so they're callable from other files
190 Revision 1.497 2007/10/05 18:09:44 cheshire
191 <rdar://problem/5524841> Services advertised with wrong target host
193 Revision 1.496 2007/10/04 22:38:59 cheshire
194 Added LogOperation message showing new q->ThisQInterval after sending uDNS query packet
196 Revision 1.495 2007/10/03 00:16:19 cheshire
197 In PrivateQueryGotZoneData, need to grab lock before calling SetNextQueryTime
199 Revision 1.494 2007/10/02 21:11:08 cheshire
200 <rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing
202 Revision 1.493 2007/10/02 19:50:23 cheshire
203 Improved debugging message
205 Revision 1.492 2007/09/29 03:15:43 cheshire
206 <rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
207 Use AutoTunnelUnregistered macro instead of checking record state directly
209 Revision 1.491 2007/09/29 01:33:45 cheshire
210 <rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
212 Revision 1.490 2007/09/29 01:06:17 mcguire
213 <rdar://problem/5507862> 9A564: mDNSResponder crash in mDNS_Execute
215 Revision 1.489 2007/09/27 22:02:33 cheshire
216 <rdar://problem/5464941> BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord
218 Revision 1.488 2007/09/27 21:20:17 cheshire
219 Improved debugging syslog messages
221 Revision 1.487 2007/09/27 18:55:11 cheshire
222 <rdar://problem/5477165> BTMM: Multiple SRV records get registered after changing Computer Name
224 Revision 1.486 2007/09/27 17:42:49 cheshire
225 Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask"
227 Revision 1.485 2007/09/27 02:16:30 cheshire
228 <rdar://problem/5500111> BTMM: LLQ refreshes being sent in the clear to the wrong port
230 Revision 1.484 2007/09/27 00:25:39 cheshire
231 Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
232 <rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
234 Revision 1.483 2007/09/26 23:16:58 cheshire
235 <rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac
237 Revision 1.482 2007/09/26 22:06:02 cheshire
238 <rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
240 Revision 1.481 2007/09/26 00:49:46 cheshire
241 Improve packet logging to show sent and received packets,
242 transport protocol (UDP/TCP/TLS) and source/destination address:port
244 Revision 1.480 2007/09/21 21:08:52 cheshire
245 Get rid of unnecessary DumpPacket() calls -- it makes more sense
246 to do this in mDNSSendDNSMessage and mDNSCoreReceive instead
248 Revision 1.479 2007/09/21 20:01:17 cheshire
249 <rdar://problem/5496750> BTMM: Skip directly to member name in SOA queries to avoid sending names in the clear
251 Revision 1.478 2007/09/21 19:29:14 cheshire
252 Added dump of uDNS questions when in MDNS_LOG_VERBOSE_DEBUG mode
254 Revision 1.477 2007/09/20 02:29:37 cheshire
255 <rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
257 Revision 1.476 2007/09/20 01:19:49 cheshire
258 Improve debugging messages: report startLLQHandshake errors; show state in uDNS_StopLongLivedQuery message
260 Revision 1.475 2007/09/19 23:51:26 cheshire
261 <rdar://problem/5480517> BTMM: Need to log a message when NAT port mapping fails
263 Revision 1.474 2007/09/19 20:32:09 cheshire
264 Export GetAuthInfoForName so it's callable from other files
266 Revision 1.473 2007/09/18 21:42:29 cheshire
267 To reduce programming mistakes, renamed ExtPort to RequestedPort
269 Revision 1.472 2007/09/14 21:26:08 cheshire
270 <rdar://problem/5482627> BTMM: Need to manually avoid port conflicts when using UPnP gateways
272 Revision 1.471 2007/09/14 01:07:10 cheshire
273 If UPnP NAT gateway returns 0.0.0.0 as external address (e.g. because it hasn't
274 got a DHCP address yet) then retry periodically until it gives us a real address.
276 Revision 1.470 2007/09/13 00:36:26 cheshire
277 <rdar://problem/5477360> NAT Reboot detection logic incorrect
279 Revision 1.469 2007/09/13 00:28:50 cheshire
280 <rdar://problem/5477354> Host records not updated on NAT address change
282 Revision 1.468 2007/09/13 00:16:41 cheshire
283 <rdar://problem/5468706> Miscellaneous NAT Traversal improvements
285 Revision 1.467 2007/09/12 23:03:08 cheshire
286 <rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
288 Revision 1.466 2007/09/12 22:19:29 cheshire
289 <rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
291 Revision 1.465 2007/09/12 19:22:19 cheshire
292 Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
293 Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
295 Revision 1.464 2007/09/12 01:22:13 cheshire
296 Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
298 Revision 1.463 2007/09/11 20:23:28 vazquez
299 <rdar://problem/5466719> CrashTracer: 3 crashes in mDNSResponder at mDNSResponder: natTraversalHandlePortMapReply + 107
300 Make sure we clean up NATTraversals before free'ing HostnameInfo
302 Revision 1.462 2007/09/11 19:19:16 cheshire
303 Correct capitalization of "uPNP" to "UPnP"
305 Revision 1.461 2007/09/10 22:08:17 cheshire
306 Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
308 Revision 1.460 2007/09/07 21:47:43 vazquez
309 <rdar://problem/5460210> BTMM: SetupSocket 5351 failed; Can't allocate UDP multicast socket spew on wake from sleep with internet sharing on
310 Try to allocate using port 5350 if we get a failure, and only log message if that fails too.
312 Revision 1.459 2007/09/07 01:01:05 cheshire
313 <rdar://problem/5464844> BTMM: Services being registered and deregistered in a loop
314 In hndlServiceUpdateReply, need to clear SRVUpdateDeferred
316 Revision 1.458 2007/09/06 19:14:33 cheshire
317 Fixed minor error introduced in 1.379 (an "if" statement was deleted but the "else" following it was left there)
319 Revision 1.457 2007/09/05 21:48:01 cheshire
320 <rdar://problem/5385864> BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone.
321 Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance cod needs
322 to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
323 otherwise those records will expire and vanish from the cache.
325 Revision 1.456 2007/09/05 21:00:17 cheshire
326 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
327 Additional refinement: ThisQInterval needs to be restored in tcpCallback, not in PrivateQueryGotZoneData
329 Revision 1.455 2007/09/05 20:53:06 cheshire
330 Tidied up alignment of code layout; code was clearing m->tcpAddrInfo.sock instead of m->tcpDeviceInfo.sock
332 Revision 1.454 2007/09/05 02:32:55 cheshire
333 Fixed posix build error (mixed declarations and code)
335 Revision 1.453 2007/09/05 02:26:57 cheshire
336 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
337 In PrivateQueryGotZoneData, restore q->ThisQInterval to non-zero value after GetZoneData completes
339 Revision 1.452 2007/08/31 22:58:22 cheshire
340 If we have an existing TCP connection we should re-use it instead of just bailing out
341 After receiving dnsbugtest response, need to set m->NextScheduledQuery to cause queries to be re-issued
343 Revision 1.451 2007/08/31 18:49:49 vazquez
344 <rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
346 Revision 1.450 2007/08/30 22:50:04 mcguire
347 <rdar://problem/5430628> BTMM: Tunneled services are registered when autotunnel can't be setup
349 Revision 1.449 2007/08/30 00:43:17 cheshire
350 Need to clear m->rec.r.resrec.RecordType before returning from uDNS_recvLLQResponse
352 Revision 1.448 2007/08/30 00:18:46 cheshire
353 <rdar://problem/5448804> Error messages: "SendServiceRegistration: Already have TCP connection..."
355 Revision 1.447 2007/08/29 01:18:33 cheshire
356 <rdar://problem/5400181> BTMM: Tunneled services do not need NAT port mappings
357 Only create NAT mappings for SRV records with AutoTarget set to Target_AutoHostAndNATMAP
359 Revision 1.446 2007/08/28 23:58:42 cheshire
360 Rename HostTarget -> AutoTarget
362 Revision 1.445 2007/08/28 23:53:21 cheshire
363 Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
365 Revision 1.444 2007/08/27 20:29:20 cheshire
366 Additional debugging messages
368 Revision 1.443 2007/08/24 23:18:28 cheshire
369 mDNS_SetSecretForDomain is called with lock held; needs to use
370 GetAuthInfoForName_internal() instead of external version GetAuthInfoForName()
372 Revision 1.442 2007/08/24 22:43:06 cheshire
373 Tidied up coded layout
375 Revision 1.441 2007/08/24 01:20:55 cheshire
376 <rdar://problem/5434381> BTMM: Memory corruption in KeychainChanged event handling
378 Revision 1.440 2007/08/24 00:15:20 cheshire
379 Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
381 Revision 1.439 2007/08/23 21:47:09 vazquez
382 <rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
383 make sure we clean up port mappings on base stations by sending a lease value of 0,
384 and only send NAT-PMP packets on private networks; also save some memory by
385 not using packet structs in NATTraversals.
387 Revision 1.438 2007/08/22 17:50:08 vazquez
388 <rdar://problem/5399276> Need to handle errors returned by NAT-PMP routers properly
389 Propagate router errors to clients, and stop logging spurious "message too short" logs.
391 Revision 1.437 2007/08/18 00:54:15 mcguire
392 <rdar://problem/5413147> BTMM: Should not register private addresses or zeros
394 Revision 1.436 2007/08/08 21:07:48 vazquez
395 <rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
397 Revision 1.435 2007/08/03 02:04:09 vazquez
398 <rdar://problem/5371843> BTMM: Private LLQs never fall back to polling
399 Fix case where NAT-PMP returns an external address but does not support
400 port mappings. Undo previous change and now, if the router returns an
401 error in the reply packet we respect it.
403 Revision 1.434 2007/08/02 21:03:05 vazquez
404 Change NAT logic to fix case where base station with port mapping turned off
405 returns an external address but does not make port mappings.
407 Revision 1.433 2007/08/02 03:30:11 vazquez
408 <rdar://problem/5371843> BTMM: Private LLQs never fall back to polling
410 Revision 1.432 2007/08/01 18:15:19 cheshire
411 Fixed crash in tcpCallback; fixed some problems with LLQ setup behind NAT
413 Revision 1.431 2007/08/01 16:11:06 cheshire
414 Fixed "mixed declarations and code" compiler error in Posix build
416 Revision 1.430 2007/08/01 16:09:13 cheshire
417 Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
419 Revision 1.429 2007/08/01 03:09:22 cheshire
420 <rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
422 Revision 1.428 2007/08/01 01:43:36 cheshire
423 Need to do mDNS_DropLockBeforeCallback/ReclaimLock around invokation of NAT client callback
425 Revision 1.427 2007/08/01 01:31:13 cheshire
426 Need to initialize traversal->tcpInfo fields or code may crash
428 Revision 1.426 2007/08/01 01:15:57 cheshire
429 <rdar://problem/5375791> Need to invoke NAT client callback when not on RFC1918 private network
431 Revision 1.425 2007/08/01 00:04:14 cheshire
432 <rdar://problem/5261696> Crash in tcpKQSocketCallback
433 Half-open TCP connections were not being cancelled properly
435 Revision 1.424 2007/07/31 02:28:35 vazquez
436 <rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
438 Revision 1.423 2007/07/30 23:31:26 cheshire
439 Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
441 Revision 1.422 2007/07/28 01:25:57 cheshire
442 <rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
444 Revision 1.421 2007/07/28 00:04:14 cheshire
445 Various fixes for comments and debugging messages
447 Revision 1.420 2007/07/27 23:59:18 cheshire
448 Added compile-time structure size checks
450 Revision 1.419 2007/07/27 20:52:29 cheshire
451 Made uDNS_recvLLQResponse() return tri-state result: LLQ_Not, LLQ_First, or LLQ_Events
453 Revision 1.418 2007/07/27 20:32:05 vazquez
454 Flag a UPnP NAT traversal before starting a UPnP port mapping, and make sure all
455 calls to mDNS_StopNATOperation() go through the UPnP code
457 Revision 1.417 2007/07/27 20:19:42 cheshire
458 Use MDNS_LOG_VERBOSE_DEBUG for dumping out packets instead of MDNS_LOG_DEBUG
460 Revision 1.416 2007/07/27 19:59:28 cheshire
461 MUST NOT touch m->CurrentQuestion (or q) after calling AnswerCurrentQuestionWithResourceRecord()
463 Revision 1.415 2007/07/27 19:51:01 cheshire
464 Use symbol QC_addnocache instead of literal constant "2"
466 Revision 1.414 2007/07/27 19:30:39 cheshire
467 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
468 to properly reflect tri-state nature of the possible responses
470 Revision 1.413 2007/07/27 18:44:01 cheshire
471 Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
473 Revision 1.412 2007/07/27 18:38:56 cheshire
474 Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
476 Revision 1.411 2007/07/27 00:57:13 cheshire
477 Create hostname address records using standard kHostNameTTL (2 minutes) instead of 1 second
479 Revision 1.410 2007/07/25 21:41:00 vazquez
480 Make sure we clean up opened sockets when there are network transitions and when changing
483 Revision 1.409 2007/07/25 03:05:02 vazquez
485 <rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
486 <rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
487 and a myriad of other security problems
489 Revision 1.408 2007/07/24 21:47:51 cheshire
490 Don't do mDNS_StopNATOperation() for operations we never started
492 Revision 1.407 2007/07/24 17:23:33 cheshire
493 <rdar://problem/5357133> Add list validation checks for debugging
495 Revision 1.406 2007/07/24 04:14:30 cheshire
496 <rdar://problem/5356281> LLQs not working in with NAT Traversal
498 Revision 1.405 2007/07/24 01:29:03 cheshire
499 <rdar://problem/5356026> DNSServiceNATPortMappingCreate() returns stale external address information
501 Revision 1.404 2007/07/20 23:10:51 cheshire
504 Revision 1.403 2007/07/20 20:12:37 cheshire
505 Rename "mDNS_DomainTypeBrowseLegacy" as "mDNS_DomainTypeBrowseAutomatic"
507 Revision 1.402 2007/07/20 00:54:20 cheshire
508 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
510 Revision 1.401 2007/07/18 03:23:33 cheshire
511 In GetServiceTarget, need to call SetupLocalAutoTunnelInterface_internal to bring up tunnel on demand, if necessary
513 Revision 1.400 2007/07/18 02:30:25 cheshire
514 Defer AutoTunnel server record advertising until we have at least one service to advertise
515 Do AutoTunnel target host selection in GetServiceTarget (instead of uDNS_RegisterService)
517 Revision 1.399 2007/07/18 01:02:28 cheshire
518 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
519 Declare records as kDNSRecordTypeKnownUnique so we don't get name conflicts with ourselves
521 Revision 1.398 2007/07/16 23:54:48 cheshire
522 <rdar://problem/5338850> Crash when removing or changing DNS keys
524 Revision 1.397 2007/07/16 20:13:31 vazquez
525 <rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
527 Revision 1.396 2007/07/14 00:33:04 cheshire
528 Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working
530 Revision 1.395 2007/07/12 23:56:23 cheshire
531 Change "GetZoneData GOT SRV" message to debugf to reduce verbosity in syslog
533 Revision 1.394 2007/07/12 23:36:08 cheshire
534 Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog
536 Revision 1.393 2007/07/12 22:15:10 cheshire
537 Modified mDNS_SetSecretForDomain() so it can be called to update an existing entry
539 Revision 1.392 2007/07/12 02:51:27 cheshire
540 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
542 Revision 1.391 2007/07/11 23:16:31 cheshire
543 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
544 Need to prepend _autotunnel._udp to start of AutoTunnel SRV record name
546 Revision 1.390 2007/07/11 22:47:55 cheshire
547 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
548 In mDNS_SetSecretForDomain(), don't register records until after we've validated the parameters
550 Revision 1.389 2007/07/11 21:33:10 cheshire
551 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
552 Set up and register AutoTunnelTarget and AutoTunnelService DNS records
554 Revision 1.388 2007/07/11 19:27:10 cheshire
555 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
556 For temporary testing fake up an IPv4LL address instead of IPv6 ULA
558 Revision 1.387 2007/07/11 03:04:08 cheshire
559 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
560 Add AutoTunnel parameter to mDNS_SetSecretForDomain; Set up AutoTunnel information for domains that require it
562 Revision 1.386 2007/07/10 01:57:28 cheshire
563 <rdar://problem/5196524> uDNS: mDNSresponder is leaking TCP connections to DNS server
564 Turned vast chunks of replicated code into a subroutine MakeTCPConn(...);
565 Made routines hold on to the reference it returns instead of leaking it
567 Revision 1.385 2007/07/09 23:50:18 cheshire
568 unlinkSRS needs to call mDNS_StopNATOperation_internal(), not mDNS_StopNATOperation()
570 Revision 1.384 2007/07/06 21:20:21 cheshire
571 Fix scheduling error (was causing "Task Scheduling Error: Continuously busy for more than a second")
573 Revision 1.383 2007/07/06 18:59:59 cheshire
574 Avoid spinning in an infinite loop when uDNS_SendNATMsg() returns an error
576 Revision 1.382 2007/07/04 00:49:43 vazquez
577 Clean up extraneous comments
579 Revision 1.381 2007/07/03 00:41:14 vazquez
580 More changes for <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
581 Safely deal with packet replies and client callbacks
583 Revision 1.380 2007/07/02 22:08:47 cheshire
584 Fixed crash in "Received public IP address" message
586 Revision 1.379 2007/06/29 00:08:49 vazquez
587 <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
589 Revision 1.378 2007/06/27 20:25:10 cheshire
590 Expanded dnsbugtest comment, explaining requirement that we also need these
591 test queries to black-hole before they get to the root name servers.
593 Revision 1.377 2007/06/22 21:27:21 cheshire
594 Modified "could not convert shared secret from base64" log message
596 Revision 1.376 2007/06/20 01:10:12 cheshire
597 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
599 Revision 1.375 2007/06/15 21:54:51 cheshire
600 <rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
602 Revision 1.374 2007/06/12 02:15:26 cheshire
603 Fix incorrect "DNS Server passed" LogOperation message
605 Revision 1.373 2007/05/31 00:25:43 cheshire
606 <rdar://problem/5238688> Only send dnsbugtest query for questions where it's warranted
608 Revision 1.372 2007/05/25 17:03:45 cheshire
609 lenptr needs to be declared unsigned, otherwise sign extension can mess up the shifting and ORing operations
611 Revision 1.371 2007/05/24 00:11:44 cheshire
612 Remove unnecessary lenbuf field from tcpInfo_t
614 Revision 1.370 2007/05/23 00:30:59 cheshire
615 Don't change question->TargetQID when repeating query over TCP
617 Revision 1.369 2007/05/21 18:04:40 cheshire
618 Updated comments -- port_mapping_create_reply renamed to port_mapping_reply
620 Revision 1.368 2007/05/17 19:12:16 cheshire
621 Updated comment about finding matching pair of sockets
623 Revision 1.367 2007/05/15 23:38:00 cheshire
624 Need to grab lock before calling SendRecordRegistration();
626 Revision 1.366 2007/05/15 00:43:05 cheshire
627 <rdar://problem/4983538> uDNS serviceRegistrationCallback locking failures
629 Revision 1.365 2007/05/10 21:19:18 cheshire
630 Rate-limit DNS test queries to at most one per three seconds
631 (useful when we have a dozen active WAB queries, and then we join a new network)
633 Revision 1.364 2007/05/07 20:43:45 cheshire
634 <rdar://problem/4241419> Reduce the number of queries and announcements
636 Revision 1.363 2007/05/04 22:12:48 cheshire
637 Work towards solving <rdar://problem/5176892> "uDNS_CheckQuery: LastQTime" log messages
638 When code gets in this invalid state, double ThisQInterval each time, to avoid excessive logging
640 Revision 1.362 2007/05/04 21:23:05 cheshire
641 <rdar://problem/5167263> Private DNS always returns no answers in the initial LLQ setup response
642 Preparatory work to enable us to do a four-way LLQ handshake over TCP, if we decide that's what we want
644 Revision 1.361 2007/05/03 23:50:48 cheshire
645 <rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
646 In the case of negative answers for the address record, set the server address to zerov4Addr
648 Revision 1.360 2007/05/03 22:40:38 cheshire
649 <rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
651 Revision 1.359 2007/05/02 22:21:33 cheshire
652 <rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
654 Revision 1.358 2007/05/01 21:46:31 cheshire
655 Move GetLLQOptData/GetPktLease from uDNS.c into DNSCommon.c so that dnsextd can use them
657 Revision 1.357 2007/05/01 01:33:49 cheshire
658 Removed "#define LLQ_Info DNSQuestion" and manually reconciled code that was still referring to "LLQ_Info"
660 Revision 1.356 2007/04/30 21:51:06 cheshire
663 Revision 1.355 2007/04/30 21:33:38 cheshire
664 Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
665 is iterating through the m->ServiceRegistrations list
667 Revision 1.354 2007/04/30 01:30:04 cheshire
668 GetZoneData_QuestionCallback needs to call client callback function on error, so client knows operation is finished
669 RecordRegistrationCallback and serviceRegistrationCallback need to clear nta reference when they're invoked
671 Revision 1.353 2007/04/28 01:28:25 cheshire
672 Fixed memory leak on error path in FoundDomain
674 Revision 1.352 2007/04/27 19:49:53 cheshire
675 In uDNS_ReceiveTestQuestionResponse, also check that srcport matches
677 Revision 1.351 2007/04/27 19:28:02 cheshire
678 Any code that calls StartGetZoneData needs to keep a handle to the structure, so
679 it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
680 -- it would start a query and then quickly cancel it, and then when
681 StartGetZoneData completed, it had a dangling pointer and crashed.)
683 Revision 1.350 2007/04/26 22:47:14 cheshire
684 Defensive coding: tcpCallback only needs to check "if (closed)", not "if (!n && closed)"
686 Revision 1.349 2007/04/26 16:04:06 cheshire
687 In mDNS_AddDNSServer, check whether port matches
688 In uDNS_CheckQuery, handle case where startLLQHandshake changes q->llq->state to LLQ_Poll
690 Revision 1.348 2007/04/26 04:01:59 cheshire
691 Copy-and-paste error: Test should be "if (result == DNSServer_Passed)" not "if (result == DNSServer_Failed)"
693 Revision 1.347 2007/04/26 00:35:15 cheshire
694 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
695 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
696 inside the firewall may give answers where a public one gives none, and vice versa.)
698 Revision 1.346 2007/04/25 19:16:59 cheshire
699 Don't set SuppressStdPort53Queries unless we do actually send a DNS packet
701 Revision 1.345 2007/04/25 18:05:11 cheshire
702 Don't try to restart inactive (duplicate) queries
704 Revision 1.344 2007/04/25 17:54:07 cheshire
705 Don't cancel Private LLQs using a clear-text UDP packet
707 Revision 1.343 2007/04/25 16:40:08 cheshire
708 Add comment explaining uDNS_recvLLQResponse logic
710 Revision 1.342 2007/04/25 02:14:38 cheshire
711 <rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
712 Additional fixes to make LLQs work properly
714 Revision 1.341 2007/04/24 02:07:42 cheshire
715 <rdar://problem/4246187> Identical client queries should reference a single shared core query
716 Deleted some more redundant code
718 Revision 1.340 2007/04/23 22:01:23 cheshire
719 <rdar://problem/5094009> IPv6 filtering in AirPort base station breaks Wide-Area Bonjour
720 As of March 2007, AirPort base stations now block incoming IPv6 connections by default, so there's no point
721 advertising IPv6 addresses in DNS any more -- we have to assume that most of the time a host's IPv6 address
722 probably won't work for incoming connections (but its IPv4 address probably will, using NAT-PMP).
724 Revision 1.339 2007/04/22 06:02:03 cheshire
725 <rdar://problem/4615977> Query should immediately return failure when no server
727 Revision 1.338 2007/04/21 19:44:11 cheshire
728 Improve uDNS_HandleNATPortMapReply log message
730 Revision 1.337 2007/04/21 02:03:00 cheshire
731 Also need to set AddressRec->resrec.RecordType in the NAT case too
733 Revision 1.336 2007/04/20 21:16:12 cheshire
734 Fixed bogus double-registration of host name -- was causing these warning messages in syslog:
735 Error! Tried to register AuthRecord 0181FB0C host.example.com. (Addr) that's already in the list
737 Revision 1.335 2007/04/19 23:57:20 cheshire
738 Temporary workaround for some AirPort base stations that don't seem to like us requesting public port zero
740 Revision 1.334 2007/04/19 23:21:51 cheshire
741 Fixed a couple of places where the StartGetZoneData check was backwards
743 Revision 1.333 2007/04/19 22:50:53 cheshire
744 <rdar://problem/4246187> Identical client queries should reference a single shared core query
746 Revision 1.332 2007/04/19 20:34:32 cheshire
747 Add debugging log message in uDNS_CheckQuery()
749 Revision 1.331 2007/04/19 20:06:41 cheshire
750 Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
752 Revision 1.330 2007/04/19 19:51:54 cheshire
753 Get rid of unnecessary initializeQuery() routine
755 Revision 1.329 2007/04/19 18:03:52 cheshire
756 Improved "mDNS_AddSearchDomain" log message
758 Revision 1.328 2007/04/18 20:57:20 cheshire
759 Commented out "GetAuthInfoForName none found" debugging message
761 Revision 1.327 2007/04/17 19:21:29 cheshire
762 <rdar://problem/5140339> Domain discovery not working over VPN
764 Revision 1.326 2007/04/16 20:49:39 cheshire
765 Fix compile errors for mDNSPosix build
767 Revision 1.325 2007/04/05 22:55:35 cheshire
768 <rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
770 Revision 1.324 2007/04/05 20:43:30 cheshire
771 Collapse sprawling code onto one line -- this is part of a bigger block of identical
772 code that has been copied-and-pasted into six different places in the same file.
773 This really needs to be turned into a subroutine.
775 Revision 1.323 2007/04/04 21:48:52 cheshire
776 <rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
778 Revision 1.322 2007/04/03 19:53:06 cheshire
779 Use mDNSSameIPPort (and similar) instead of accessing internal fields directly
781 Revision 1.321 2007/04/02 23:44:09 cheshire
784 Revision 1.320 2007/03/31 01:26:13 cheshire
785 Take out GetAuthInfoForName syslog message
787 Revision 1.319 2007/03/31 01:10:53 cheshire
790 Revision 1.318 2007/03/31 00:17:11 cheshire
793 Revision 1.317 2007/03/29 00:09:31 cheshire
794 Improve "uDNS_InitLongLivedQuery" log message
796 Revision 1.316 2007/03/28 21:16:27 cheshire
797 Remove DumpPacket() call now that OPT pseudo-RR rrclass bug is fixed
799 Revision 1.315 2007/03/28 21:02:18 cheshire
800 <rdar://problem/3810563> Wide-Area Bonjour should work on multi-subnet private network
802 Revision 1.314 2007/03/28 15:56:37 cheshire
803 <rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
805 Revision 1.313 2007/03/28 01:27:32 cheshire
806 <rdar://problem/4996439> Unicast DNS polling server every three seconds
807 StartLLQPolling was using INIT_UCAST_POLL_INTERVAL instead of LLQ_POLL_INTERVAL for the retry interval
809 Revision 1.312 2007/03/27 23:48:21 cheshire
810 Use mDNS_StopGetDomains(), not mDNS_StopQuery()
812 Revision 1.311 2007/03/27 22:47:51 cheshire
813 Remove unnecessary "*(long*)0 = 0;" to generate crash and stack trace
815 Revision 1.310 2007/03/24 01:24:13 cheshire
816 Add validator for uDNS data structures; fixed crash in RegisterSearchDomains()
818 Revision 1.309 2007/03/24 00:47:53 cheshire
819 <rdar://problem/4983538> serviceRegistrationCallback: Locking Failure! mDNS_busy (1) != mDNS_reentrancy (2)
820 Locking in this file is all messed up. For now we'll just work around the issue.
822 Revision 1.308 2007/03/24 00:41:33 cheshire
823 Minor code cleanup (move variable declarations to minimum enclosing scope)
825 Revision 1.307 2007/03/21 23:06:00 cheshire
826 Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
828 Revision 1.306 2007/03/21 00:30:03 cheshire
829 <rdar://problem/4789455> Multiple errors in DNameList-related code
831 Revision 1.305 2007/03/20 17:07:15 cheshire
832 Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
834 Revision 1.304 2007/03/17 00:02:11 cheshire
835 <rdar://problem/5067013> NAT-PMP: Lease TTL is being ignored
837 Revision 1.303 2007/03/10 03:26:44 cheshire
838 <rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
840 Revision 1.302 2007/03/10 02:29:58 cheshire
841 Added comments about NAT-PMP response functions
843 Revision 1.301 2007/03/10 02:02:58 cheshire
844 <rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
845 Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
847 Revision 1.300 2007/03/08 18:56:00 cheshire
848 Fixed typo: "&v4.ip.v4.b[0]" is always non-zero (ampersand should not be there)
850 Revision 1.299 2007/02/28 01:45:47 cheshire
851 <rdar://problem/4683261> NAT-PMP: Port mapping refreshes should contain actual public port
852 <rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
854 Revision 1.298 2007/02/14 03:16:39 cheshire
855 <rdar://problem/4789477> Eliminate unnecessary malloc/free in mDNSCore code
857 Revision 1.297 2007/02/08 21:12:28 cheshire
858 <rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
860 Revision 1.296 2007/01/29 16:03:22 cheshire
861 Fix unused parameter warning
863 Revision 1.295 2007/01/27 03:34:27 cheshire
864 Made GetZoneData use standard queries (and cached results);
865 eliminated GetZoneData_Callback() packet response handler
867 Revision 1.294 2007/01/25 00:40:16 cheshire
868 Unified CNAME-following functionality into cache management code (which means CNAME-following
869 should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine.
871 Revision 1.293 2007/01/23 02:56:11 cheshire
872 Store negative results in the cache, instead of generating them out of pktResponseHndlr()
874 Revision 1.292 2007/01/20 01:32:40 cheshire
875 Update comments and debugging messages
877 Revision 1.291 2007/01/20 00:07:02 cheshire
878 When we have credentials in the keychain for a domain, we attempt private queries, but
879 if the authoritative server is not set up for private queries (i.e. no _dns-query-tls
880 or _dns-llq-tls record) then we need to fall back to conventional non-private queries.
882 Revision 1.290 2007/01/19 23:41:45 cheshire
883 Need to clear m->rec.r.resrec.RecordType after calling GetLLQOptData()
885 Revision 1.289 2007/01/19 23:32:07 cheshire
886 Eliminate pointless timenow variable
888 Revision 1.288 2007/01/19 23:26:08 cheshire
889 Right now tcpCallback does not run holding the lock, so no need to drop the lock before invoking callbacks
891 Revision 1.287 2007/01/19 22:55:41 cheshire
892 Eliminate redundant identical parameters to GetZoneData_StartQuery()
894 Revision 1.286 2007/01/19 21:17:33 cheshire
895 StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
897 Revision 1.285 2007/01/19 18:39:11 cheshire
898 Fix a bunch of parameters that should have been declared "const"
900 Revision 1.284 2007/01/19 18:28:28 cheshire
901 Improved debugging messages
903 Revision 1.283 2007/01/19 18:09:33 cheshire
904 Fixed getLLQAtIndex (now called GetLLQOptData):
905 1. It incorrectly assumed all EDNS0 OPT records are the same size (it ignored optlen)
906 2. It used inefficient memory copying instead of just returning a pointer
908 Revision 1.282 2007/01/17 22:06:01 cheshire
909 Replace duplicated literal constant "{ { 0 } }" with symbol "zeroIPPort"
911 Revision 1.281 2007/01/17 21:58:13 cheshire
912 For clarity, rename ntaContext field "isPrivate" to "ntaPrivate"
914 Revision 1.280 2007/01/17 21:46:02 cheshire
915 Remove redundant duplicated "isPrivate" field from LLQ_Info
917 Revision 1.279 2007/01/17 21:35:31 cheshire
918 For clarity, rename zoneData_t field "isPrivate" to "zonePrivate"
920 Revision 1.278 2007/01/16 03:04:16 cheshire
921 <rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
922 Don't cache result of ntaContextSRV(context) in a local variable --
923 the macro evaluates to a different result after we clear "context->isPrivate"
925 Revision 1.277 2007/01/10 22:51:58 cheshire
926 <rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
928 Revision 1.276 2007/01/10 02:09:30 cheshire
929 Better LogOperation record of keys read from System Keychain
931 Revision 1.275 2007/01/09 22:37:18 cheshire
932 Provide ten-second grace period for deleted keys, to give mDNSResponder
933 time to delete host name before it gives up access to the required key.
935 Revision 1.274 2007/01/09 01:16:32 cheshire
936 Improve "ERROR m->CurrentQuestion already set" debugging messages
938 Revision 1.273 2007/01/08 23:58:00 cheshire
939 Don't request regDomain and browseDomains in uDNS_SetupDNSConfig() -- it just ignores those results
941 Revision 1.272 2007/01/05 08:30:42 cheshire
942 Trim excessive "$Log" checkin history from before 2006
943 (checkin history still available via "cvs log ..." of course)
945 Revision 1.271 2007/01/05 06:34:03 cheshire
946 Improve "ERROR m->CurrentQuestion already set" debugging messages
948 Revision 1.270 2007/01/05 05:44:33 cheshire
949 Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c,
950 so that mDNSPosix embedded clients will compile again
952 Revision 1.269 2007/01/04 23:11:13 cheshire
953 <rdar://problem/4720673> uDNS: Need to start caching unicast records
954 When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
956 Revision 1.268 2007/01/04 22:06:38 cheshire
957 Fixed crash in LLQNatMapComplete()
959 Revision 1.267 2007/01/04 21:45:20 cheshire
960 Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
961 to do additional lock sanity checking around callback invocations
963 Revision 1.266 2007/01/04 21:01:20 cheshire
964 <rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
965 Only return NXDOMAIN results to clients that request them using kDNSServiceFlagsReturnIntermediates
967 Revision 1.265 2007/01/04 20:47:17 cheshire
968 Fixed crash in CheckForUnreferencedLLQMapping()
970 Revision 1.264 2007/01/04 20:39:27 cheshire
973 Revision 1.263 2007/01/04 02:39:53 cheshire
974 <rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
976 Revision 1.262 2007/01/04 00:29:25 cheshire
977 Covert LogMsg() in GetAuthInfoForName to LogOperation()
979 Revision 1.261 2006/12/22 20:59:49 cheshire
980 <rdar://problem/4742742> Read *all* DNS keys from keychain,
981 not just key for the system-wide default registration domain
983 Revision 1.260 2006/12/21 00:06:07 cheshire
984 Don't need to do mDNSPlatformMemZero() -- mDNS_SetupResourceRecord() does it for us
986 Revision 1.259 2006/12/20 04:07:36 cheshire
987 Remove uDNS_info substructure from AuthRecord_struct
989 Revision 1.258 2006/12/19 22:49:24 cheshire
990 Remove uDNS_info substructure from ServiceRecordSet_struct
992 Revision 1.257 2006/12/19 02:38:20 cheshire
993 Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
995 Revision 1.256 2006/12/19 02:18:48 cheshire
996 Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
998 Revision 1.255 2006/12/16 01:58:31 cheshire
999 <rdar://problem/4720673> uDNS: Need to start caching unicast records
1001 Revision 1.254 2006/12/15 19:23:39 cheshire
1002 Use new DomainNameLengthLimit() function, to be more defensive against malformed
1003 data received from the network.
1005 Revision 1.253 2006/12/01 07:43:34 herscher
1006 Fix byte ordering problem for one-shot TCP queries.
1007 Iterate more intelligently over duplicates in uDNS_ReceiveMsg to avoid spin loops.
1009 Revision 1.252 2006/11/30 23:07:57 herscher
1010 <rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
1012 Revision 1.251 2006/11/28 21:42:11 mkrochma
1013 Work around a crashing bug that was introduced by uDNS and mDNS code unification
1015 Revision 1.250 2006/11/18 05:01:30 cheshire
1016 Preliminary support for unifying the uDNS and mDNS code,
1017 including caching of uDNS answers
1019 Revision 1.249 2006/11/10 07:44:04 herscher
1020 <rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
1022 Revision 1.248 2006/11/08 04:26:53 cheshire
1023 Fix typo in debugging message
1025 Revision 1.247 2006/10/20 05:35:04 herscher
1026 <rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
1028 Revision 1.246 2006/10/11 19:29:41 herscher
1029 <rdar://problem/4744553> uDNS: mDNSResponder-111 using 100% CPU
1031 Revision 1.245 2006/10/04 22:21:15 herscher
1032 Tidy up references to mDNS_struct introduced when the embedded uDNS_info struct was removed.
1034 Revision 1.244 2006/10/04 21:51:27 herscher
1035 Replace calls to mDNSPlatformTimeNow(m) with m->timenow
1037 Revision 1.243 2006/10/04 21:38:59 herscher
1038 Remove uDNS_info substructure from DNSQuestion_struct
1040 Revision 1.242 2006/09/27 00:51:46 herscher
1041 Fix compile error when _LEGACY_NAT_TRAVERSAL_ is not defined
1043 Revision 1.241 2006/09/26 01:54:47 herscher
1044 <rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
1046 Revision 1.240 2006/09/15 21:20:15 cheshire
1047 Remove uDNS_info substructure from mDNS_struct
1049 Revision 1.239 2006/08/16 02:52:56 mkrochma
1050 <rdar://problem/4104154> Actually fix it this time
1052 Revision 1.238 2006/08/16 00:31:50 mkrochma
1053 <rdar://problem/4386944> Get rid of NotAnInteger references
1055 Revision 1.237 2006/08/15 23:38:17 mkrochma
1056 <rdar://problem/4104154> Requested Public Port field should be set to zero on mapping deletion
1058 Revision 1.236 2006/08/14 23:24:23 cheshire
1059 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
1061 Revision 1.235 2006/07/30 05:45:36 cheshire
1062 <rdar://problem/4304215> Eliminate MIN_UCAST_PERIODIC_EXEC
1064 Revision 1.234 2006/07/22 02:58:36 cheshire
1065 Code was clearing namehash twice instead of namehash and rdatahash
1067 Revision 1.233 2006/07/20 19:46:51 mkrochma
1068 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1071 Revision 1.232 2006/07/15 02:01:29 cheshire
1072 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1073 Fix broken "empty string" browsing
1075 Revision 1.231 2006/07/05 23:28:22 cheshire
1076 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1078 Revision 1.230 2006/06/29 03:02:44 cheshire
1079 <rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
1081 Revision 1.229 2006/03/02 22:03:41 cheshire
1082 <rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
1083 Refinement: m->rec.r.resrec.RecordType needs to be cleared *every* time around for loop, not just once at the end
1085 Revision 1.228 2006/02/26 00:54:42 cheshire
1086 Fixes to avoid code generation warning/error on FreeBSD 7
1088 Revision 1.227 2006/01/09 20:47:05 cheshire
1089 <rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
1095 #if(defined(_MSC_VER))
1096 // Disable "assignment within conditional expression".
1097 // Other compilers understand the convention that if you place the assignment expression within an extra pair
1098 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
1099 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
1100 // to the compiler that the assignment is intentional, we have to just turn this warning off completely.
1101 #pragma warning(disable:4706)
1104 typedef struct SearchListElem
1106 struct SearchListElem
*next
;
1108 int flag
; // -1 means delete, 0 means unchanged, +1 means newly added
1109 DNSQuestion BrowseQ
;
1110 DNSQuestion DefBrowseQ
;
1111 DNSQuestion AutomaticBrowseQ
;
1112 DNSQuestion RegisterQ
;
1113 DNSQuestion DefRegisterQ
;
1114 ARListElem
*AuthRecs
;
1117 // For domain enumeration and automatic browsing
1118 // This is the user's DNS search list.
1119 // In each of these domains we search for our special pointer records (lb._dns-sd._udp.<domain>, etc.)
1120 // to discover recommended domains for domain enumeration (browse, default browse, registration,
1121 // default registration) and possibly one or more recommended automatic browsing domains.
1122 static SearchListElem
*SearchList
= mDNSNULL
;
1124 // Temporary workaround to make ServiceRecordSet list management safe.
1125 // Ideally a ServiceRecordSet shouldn't be a special entity that's given special treatment by the uDNS code
1126 // -- it should just be a grouping of records that are treated the same as any other registered records.
1127 // In that case it may no longer be necessary to keep an explicit list of ServiceRecordSets, which in turn
1128 // would avoid the perils of modifying that list cleanly while some other piece of code is iterating through it.
1129 ServiceRecordSet
*CurrentServiceRecordSet
= mDNSNULL
;
1131 // ***************************************************************************
1132 #if COMPILER_LIKES_PRAGMA_MARK
1133 #pragma mark - General Utility Functions
1136 // Unlink an AuthRecord from the m->ResourceRecords list.
1137 // This seems risky. Probably some (or maybe all) of the places calling UnlinkAuthRecord to directly
1138 // remove a record from the list should actually be using mDNS_Deregister/mDNS_Deregister_internal.
1139 mDNSlocal mStatus
UnlinkAuthRecord(mDNS
*const m
, AuthRecord
*const rr
)
1141 AuthRecord
**list
= &m
->ResourceRecords
;
1142 if (m
->NewLocalRecords
== rr
) m
->NewLocalRecords
= rr
->next
;
1143 if (m
->CurrentRecord
== rr
) m
->CurrentRecord
= rr
->next
;
1144 while (*list
&& *list
!= rr
) list
= &(*list
)->next
;
1147 list
= &m
->DuplicateRecords
;
1148 while (*list
&& *list
!= rr
) list
= &(*list
)->next
;
1150 if (*list
) { *list
= rr
->next
; rr
->next
= mDNSNULL
; return(mStatus_NoError
); }
1151 LogMsg("ERROR: UnlinkAuthRecord - no such active record %##s", rr
->resrec
.name
->c
);
1152 return(mStatus_NoSuchRecord
);
1155 // unlinkSRS is an internal routine (i.e. must be called with the lock already held)
1156 mDNSlocal
void unlinkSRS(mDNS
*const m
, ServiceRecordSet
*srs
)
1158 ServiceRecordSet
**p
;
1160 if (srs
->NATinfo
.clientContext
)
1162 mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
1163 srs
->NATinfo
.clientContext
= mDNSNULL
;
1166 for (p
= &m
->ServiceRegistrations
; *p
; p
= &(*p
)->uDNS_next
)
1169 ExtraResourceRecord
*e
;
1170 *p
= srs
->uDNS_next
;
1171 if (CurrentServiceRecordSet
== srs
)
1172 CurrentServiceRecordSet
= srs
->uDNS_next
;
1173 srs
->uDNS_next
= mDNSNULL
;
1174 for (e
=srs
->Extras
; e
; e
=e
->next
)
1175 if (UnlinkAuthRecord(m
, &e
->r
))
1176 LogMsg("unlinkSRS: extra record %##s not found", e
->r
.resrec
.name
->c
);
1179 LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list %##s", srs
->RR_SRV
.resrec
.name
->c
);
1182 // set retry timestamp for record with exponential backoff
1183 // (for service record sets, use RR_SRV as representative for time checks
1184 mDNSlocal
void SetRecordRetry(mDNS
*const m
, AuthRecord
*rr
, mStatus SendErr
)
1186 mDNSs32 elapsed
= m
->timenow
- rr
->LastAPTime
;
1187 rr
->LastAPTime
= m
->timenow
;
1190 // Code for stress-testing registration renewal code
1191 if (rr
->expire
&& rr
->expire
- m
->timenow
> mDNSPlatformOneSecond
* 120)
1193 LogOperation("Adjusting expiry from %d to 120 seconds for %s",
1194 (rr
->expire
- m
->timenow
) / mDNSPlatformOneSecond
, ARDisplayString(m
, rr
));
1195 rr
->expire
= m
->timenow
+ mDNSPlatformOneSecond
* 120;
1199 if (rr
->expire
&& rr
->expire
- m
->timenow
> mDNSPlatformOneSecond
)
1201 mDNSs32 remaining
= rr
->expire
- m
->timenow
;
1202 rr
->ThisAPInterval
= remaining
/2 + mDNSRandom(remaining
/10);
1203 LogOperation("SetRecordRetry refresh in %4d of %4d for %s",
1204 rr
->ThisAPInterval
/ mDNSPlatformOneSecond
,
1205 (rr
->expire
- m
->timenow
) / mDNSPlatformOneSecond
,
1206 ARDisplayString(m
, rr
));
1212 // If at least half our our time interval has elapsed, it's time to double rr->ThisAPInterval
1213 // If resulting interval is too small, set to at least INIT_UCAST_POLL_INTERVAL (3 seconds)
1214 // If resulting interval is too large, set to at most 30 minutes
1215 if (rr
->ThisAPInterval
/ 2 <= elapsed
) rr
->ThisAPInterval
*= 2;
1216 if (rr
->ThisAPInterval
< INIT_UCAST_POLL_INTERVAL
|| SendErr
== mStatus_TransientErr
)
1217 rr
->ThisAPInterval
= INIT_UCAST_POLL_INTERVAL
;
1218 rr
->ThisAPInterval
+= mDNSRandom(rr
->ThisAPInterval
/20);
1219 if (rr
->ThisAPInterval
> 30 * 60 * mDNSPlatformOneSecond
)
1220 rr
->ThisAPInterval
= 30 * 60 * mDNSPlatformOneSecond
;
1222 LogOperation("SetRecordRetry retry in %4d for %s", rr
->ThisAPInterval
/ mDNSPlatformOneSecond
, ARDisplayString(m
, rr
));
1225 // ***************************************************************************
1226 #if COMPILER_LIKES_PRAGMA_MARK
1227 #pragma mark - Name Server List Management
1230 mDNSexport DNSServer
*mDNS_AddDNSServer(mDNS
*const m
, const domainname
*d
, const mDNSInterfaceID interface
, const mDNSAddr
*addr
, const mDNSIPPort port
)
1232 DNSServer
**p
= &m
->DNSServers
;
1234 if (!d
) d
= (const domainname
*)"";
1236 LogOperation("mDNS_AddDNSServer: Adding %#a for %##s", addr
, d
->c
);
1237 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
1238 LogMsg("mDNS_AddDNSServer: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
1240 while (*p
) // Check if we already have this {server,domain} pair registered
1242 if ((*p
)->interface
== interface
&& (*p
)->teststate
!= DNSServer_Disabled
&&
1243 mDNSSameAddress(&(*p
)->addr
, addr
) && mDNSSameIPPort((*p
)->port
, port
) && SameDomainName(&(*p
)->domain
, d
))
1245 if (!((*p
)->flags
& DNSServer_FlagDelete
)) LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr
, d
->c
);
1246 (*p
)->flags
&= ~DNSServer_FlagDelete
;
1252 // allocate, add to list
1253 *p
= mDNSPlatformMemAllocate(sizeof(**p
));
1254 if (!*p
) LogMsg("Error: mDNS_AddDNSServer - malloc");
1257 (*p
)->interface
= interface
;
1260 (*p
)->flags
= DNSServer_FlagNew
;
1261 (*p
)->teststate
= DNSServer_Untested
;
1262 (*p
)->lasttest
= m
->timenow
- INIT_UCAST_POLL_INTERVAL
;
1263 AssignDomainName(&(*p
)->domain
, d
);
1264 (*p
)->next
= mDNSNULL
;
1269 // ***************************************************************************
1270 #if COMPILER_LIKES_PRAGMA_MARK
1271 #pragma mark - authorization management
1274 mDNSlocal DomainAuthInfo
*GetAuthInfoForName_direct(mDNS
*m
, const domainname
*const name
)
1276 const domainname
*n
= name
;
1279 DomainAuthInfo
*ptr
;
1280 for (ptr
= m
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
1281 if (SameDomainName(&ptr
->domain
, n
))
1283 debugf("GetAuthInfoForName %##s Matched %##s Key name %##s", name
->c
, ptr
->domain
.c
, ptr
->keyname
.c
);
1286 n
= (const domainname
*)(n
->c
+ 1 + n
->c
[0]);
1288 //LogOperation("GetAuthInfoForName none found for %##s", name->c);
1292 // MUST be called with lock held
1293 mDNSexport DomainAuthInfo
*GetAuthInfoForName_internal(mDNS
*m
, const domainname
*const name
)
1295 DomainAuthInfo
**p
= &m
->AuthInfoList
;
1297 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
1298 LogMsg("GetAuthInfoForName_internal: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
1300 // First purge any dead keys from the list
1303 if ((*p
)->deltime
&& m
->timenow
- (*p
)->deltime
>= 0 && AutoTunnelUnregistered(*p
))
1306 DomainAuthInfo
*info
= *p
;
1307 LogOperation("GetAuthInfoForName_internal deleting expired key %##s %##s", info
->domain
.c
, info
->keyname
.c
);
1308 *p
= info
->next
; // Cut DomainAuthInfo from list *before* scanning our question list updating AuthInfo pointers
1309 for (q
= m
->Questions
; q
; q
=q
->next
)
1310 if (q
->AuthInfo
== info
)
1312 q
->AuthInfo
= GetAuthInfoForName_direct(m
, &q
->qname
);
1313 debugf("GetAuthInfoForName_internal updated q->AuthInfo from %##s to %##s for %##s (%s)",
1314 info
->domain
.c
, q
->AuthInfo
? q
->AuthInfo
->domain
.c
: mDNSNULL
, q
->qname
.c
, DNSTypeName(q
->qtype
));
1317 // Probably not essential, but just to be safe, zero out the secret key data
1318 // so we don't leave it hanging around in memory
1319 // (where it could potentially get exposed via some other bug)
1320 mDNSPlatformMemZero(info
, sizeof(*info
));
1321 mDNSPlatformMemFree(info
);
1327 return(GetAuthInfoForName_direct(m
, name
));
1330 mDNSexport DomainAuthInfo
*GetAuthInfoForName(mDNS
*m
, const domainname
*const name
)
1334 d
= GetAuthInfoForName_internal(m
, name
);
1339 // MUST be called with the lock held
1340 mDNSexport mStatus
mDNS_SetSecretForDomain(mDNS
*m
, DomainAuthInfo
*info
,
1341 const domainname
*domain
, const domainname
*keyname
, const char *b64keydata
, mDNSBool AutoTunnel
)
1344 DomainAuthInfo
**p
= &m
->AuthInfoList
;
1345 if (!info
|| !b64keydata
) { LogMsg("mDNS_SetSecretForDomain: ERROR: info %p b64keydata %p", info
, b64keydata
); return(mStatus_BadParamErr
); }
1347 LogOperation("mDNS_SetSecretForDomain: domain %##s key %##s%s", domain
->c
, keyname
->c
, AutoTunnel
? " AutoTunnel" : "");
1349 info
->AutoTunnel
= AutoTunnel
;
1350 AssignDomainName(&info
->domain
, domain
);
1351 AssignDomainName(&info
->keyname
, keyname
);
1352 mDNS_snprintf(info
->b64keydata
, sizeof(info
->b64keydata
), "%s", b64keydata
);
1354 if (DNSDigest_ConstructHMACKeyfromBase64(info
, b64keydata
) < 0)
1356 LogMsg("mDNS_SetSecretForDomain: ERROR: Could not convert shared secret from base64: domain %##s key %##s %s",
1357 domain
->c
, keyname
->c
, LogAllOperations
? b64keydata
: "");
1358 return(mStatus_BadParamErr
);
1361 // Don't clear deltime until after we've ascertained that b64keydata is valid
1364 while (*p
&& (*p
) != info
) p
=&(*p
)->next
;
1365 if (*p
) return(mStatus_AlreadyRegistered
);
1367 // Caution: Only zero AutoTunnelHostRecord.namestorage and AutoTunnelNAT.clientContext AFTER we've determined that this is a NEW DomainAuthInfo
1368 // being added to the list. Otherwise we risk smashing our AutoTunnel host records and NATOperation that are already active and in use.
1369 info
->AutoTunnelHostRecord
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
1370 info
->AutoTunnelHostRecord
.namestorage
.c
[0] = 0;
1371 info
->AutoTunnelTarget
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
1372 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
1373 info
->AutoTunnelService
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
1374 info
->AutoTunnelNAT
.clientContext
= mDNSNULL
;
1375 info
->next
= mDNSNULL
;
1378 // Check to see if adding this new DomainAuthInfo has changed the credentials for any of our questions
1379 for (q
= m
->Questions
; q
; q
=q
->next
)
1381 DomainAuthInfo
*newinfo
= GetAuthInfoForQuestion(m
, q
);
1382 if (q
->AuthInfo
!= newinfo
)
1384 debugf("mDNS_SetSecretForDomain updating q->AuthInfo from %##s to %##s for %##s (%s)",
1385 q
->AuthInfo
? q
->AuthInfo
->domain
.c
: mDNSNULL
,
1386 newinfo
? newinfo
->domain
.c
: mDNSNULL
, q
->qname
.c
, DNSTypeName(q
->qtype
));
1387 q
->AuthInfo
= newinfo
;
1391 return(mStatus_NoError
);
1394 // ***************************************************************************
1395 #if COMPILER_LIKES_PRAGMA_MARK
1397 #pragma mark - NAT Traversal
1400 mDNSlocal mStatus
uDNS_SendNATMsg(mDNS
*m
, NATTraversalInfo
*info
)
1402 mStatus err
= mStatus_NoError
;
1404 // send msg if we have a router and it is a private address
1405 if (!mDNSIPv4AddressIsZero(m
->Router
.ip
.v4
) && mDNSv4AddrIsRFC1918(&m
->Router
.ip
.v4
))
1407 union { NATAddrRequest NATAddrReq
; NATPortMapRequest NATPortReq
; } u
= { { NATMAP_VERS
, NATOp_AddrRequest
} } ;
1408 const mDNSu8
*end
= (mDNSu8
*)&u
+ sizeof(NATAddrRequest
);
1410 if (info
) // For NATOp_MapUDP and NATOp_MapTCP, fill in additional fields
1412 mDNSu8
*p
= (mDNSu8
*)&u
.NATPortReq
.NATReq_lease
;
1413 u
.NATPortReq
.opcode
= info
->Protocol
;
1414 u
.NATPortReq
.unused
= zeroID
;
1415 u
.NATPortReq
.intport
= info
->IntPort
;
1416 u
.NATPortReq
.extport
= info
->RequestedPort
;
1417 p
[0] = (mDNSu8
)((info
->NATLease
>> 24) & 0xFF);
1418 p
[1] = (mDNSu8
)((info
->NATLease
>> 16) & 0xFF);
1419 p
[2] = (mDNSu8
)((info
->NATLease
>> 8) & 0xFF);
1420 p
[3] = (mDNSu8
)( info
->NATLease
& 0xFF);
1421 end
= (mDNSu8
*)&u
+ sizeof(NATPortMapRequest
);
1424 err
= mDNSPlatformSendUDP(m
, (mDNSu8
*)&u
, end
, 0, &m
->Router
, NATPMPPort
);
1426 #ifdef _LEGACY_NAT_TRAVERSAL_
1427 if (mDNSIPPortIsZero(m
->UPnPSOAPPort
)) LNT_SendDiscoveryMsg(m
);
1428 else if (info
) err
= LNT_MapPort(m
, info
);
1429 else err
= LNT_GetExternalAddress(m
);
1430 #endif // _LEGACY_NAT_TRAVERSAL_
1435 mDNSlocal
void RecreateNATMappings(mDNS
*const m
)
1437 NATTraversalInfo
*n
;
1438 for (n
= m
->NATTraversals
; n
; n
=n
->next
)
1440 n
->ExpiryTime
= 0; // Mark this mapping as expired
1441 n
->retryInterval
= NATMAP_INIT_RETRY
;
1442 n
->retryPortMap
= m
->timenow
;
1443 #ifdef _LEGACY_NAT_TRAVERSAL_
1444 if (n
->tcpInfo
.sock
) { mDNSPlatformTCPCloseConnection(n
->tcpInfo
.sock
); n
->tcpInfo
.sock
= mDNSNULL
; }
1445 #endif // _LEGACY_NAT_TRAVERSAL_
1448 m
->NextScheduledNATOp
= m
->timenow
; // Need to send packets immediately
1451 #ifdef _LEGACY_NAT_TRAVERSAL_
1452 mDNSlocal
void ClearUPnPState(mDNS
*const m
)
1454 if (m
->tcpAddrInfo
.sock
) { mDNSPlatformTCPCloseConnection(m
->tcpAddrInfo
.sock
); m
->tcpAddrInfo
.sock
= mDNSNULL
; }
1455 if (m
->tcpDeviceInfo
.sock
) { mDNSPlatformTCPCloseConnection(m
->tcpDeviceInfo
.sock
); m
->tcpDeviceInfo
.sock
= mDNSNULL
; }
1456 m
->UPnPSOAPPort
= m
->UPnPRouterPort
= zeroIPPort
; // Reset UPnP ports
1459 #define ClearUPnPState(X)
1460 #endif // _LEGACY_NAT_TRAVERSAL_
1462 mDNSexport
void natTraversalHandleAddressReply(mDNS
*const m
, mDNSu16 err
, mDNSv4Addr ExtAddr
)
1464 if (err
) LogMsg("Error getting external address %d", err
);
1465 else if (!mDNSSameIPv4Address(m
->ExternalAddress
, ExtAddr
))
1467 LogOperation("Received external IP address %.4a from NAT", &ExtAddr
);
1468 if (mDNSv4AddrIsRFC1918(&ExtAddr
))
1469 LogMsg("Double NAT (external NAT gateway address %.4a is also a private RFC 1918 address)", &ExtAddr
);
1470 m
->ExternalAddress
= ExtAddr
;
1471 RecreateNATMappings(m
); // Also sets NextScheduledNATOp for us
1474 if (err
|| mDNSIPv4AddressIsZero(ExtAddr
)) m
->retryIntervalGetAddr
= NATMAP_INIT_RETRY
* 32; // 8 seconds
1475 else m
->retryIntervalGetAddr
= NATMAP_MAX_RETRY_INTERVAL
;
1477 m
->retryGetAddr
= m
->timenow
+ m
->retryIntervalGetAddr
;
1478 if (m
->NextScheduledNATOp
- m
->retryIntervalGetAddr
> 0)
1479 m
->NextScheduledNATOp
= m
->retryIntervalGetAddr
;
1482 // Both places that call NATSetNextRenewalTime() update m->NextScheduledNATOp correctly afterwards
1483 mDNSlocal
void NATSetNextRenewalTime(mDNS
*const m
, NATTraversalInfo
*n
)
1485 n
->retryInterval
= (n
->ExpiryTime
- m
->timenow
)/2;
1486 if (n
->retryInterval
< NATMAP_MIN_RETRY_INTERVAL
) // Min retry interval is 2 seconds
1487 n
->retryInterval
= NATMAP_MIN_RETRY_INTERVAL
;
1488 n
->retryPortMap
= m
->timenow
+ n
->retryInterval
;
1491 // Note: When called from handleLNTPortMappingResponse() only pkt->err, pkt->extport and pkt->NATRep_lease fields are filled in
1492 mDNSexport
void natTraversalHandlePortMapReply(mDNS
*const m
, NATTraversalInfo
*n
, const mDNSInterfaceID InterfaceID
, mDNSu16 err
, mDNSIPPort extport
, mDNSu32 lease
)
1495 if (err
|| lease
== 0 || mDNSIPPortIsZero(extport
))
1497 LogOperation("natTraversalHandlePortMapReply: received error making port mapping error %d port %d", err
, mDNSVal16(extport
));
1498 n
->retryInterval
= NATMAP_MAX_RETRY_INTERVAL
;
1499 n
->retryPortMap
= m
->timenow
+ NATMAP_MAX_RETRY_INTERVAL
;
1500 // No need to set m->NextScheduledNATOp here, since we're only ever extending the m->retryPortMap time
1501 if (err
== NATErr_Refused
) n
->NewResult
= mStatus_NATPortMappingDisabled
;
1502 else if (err
> NATErr_None
&& err
<= NATErr_Opcode
) n
->NewResult
= mStatus_NATPortMappingUnsupported
;
1506 if (lease
> 999999999UL / mDNSPlatformOneSecond
)
1507 lease
= 999999999UL / mDNSPlatformOneSecond
;
1508 n
->ExpiryTime
= NonZeroTime(m
->timenow
+ lease
* mDNSPlatformOneSecond
);
1510 if (!mDNSSameIPPort(n
->RequestedPort
, extport
))
1511 LogOperation("natTraversalHandlePortMapReply: public port changed from %d to %d", mDNSVal16(n
->RequestedPort
), mDNSVal16(extport
));
1513 n
->InterfaceID
= InterfaceID
;
1514 n
->RequestedPort
= extport
;
1516 LogOperation("natTraversalHandlePortMapReply %p %s Internal Port %d External Port %d", n
,
1517 n
->Protocol
== NATOp_MapUDP
? "UDP Response" :
1518 n
->Protocol
== NATOp_MapTCP
? "TCP Response" : "?", mDNSVal16(n
->IntPort
), mDNSVal16(n
->RequestedPort
));
1520 NATSetNextRenewalTime(m
, n
); // Got our port mapping; now set timer to renew it at halfway point
1521 m
->NextScheduledNATOp
= m
->timenow
; // May need to invoke client callback immediately
1525 // Must be called with the mDNS_Lock held
1526 mDNSexport mStatus
mDNS_StartNATOperation_internal(mDNS
*const m
, NATTraversalInfo
*traversal
)
1528 NATTraversalInfo
**n
;
1530 LogOperation("mDNS_StartNATOperation_internal %d %d %d %d",
1531 traversal
->Protocol
, mDNSVal16(traversal
->IntPort
), mDNSVal16(traversal
->RequestedPort
), traversal
->NATLease
);
1533 // Note: It important that new traversal requests are appended at the *end* of the list, not prepended at the start
1534 n
= &m
->NATTraversals
;
1535 while (*n
&& *n
!= traversal
) n
=&(*n
)->next
;
1536 if (*n
) { LogMsg("Error! Tried to add a NAT traversal that's already in the active list"); return(mStatus_AlreadyRegistered
); }
1538 // Initialize necessary fields
1539 traversal
->next
= mDNSNULL
;
1540 traversal
->ExpiryTime
= 0;
1541 traversal
->retryInterval
= NATMAP_INIT_RETRY
;
1542 traversal
->retryPortMap
= m
->timenow
;
1543 traversal
->NewResult
= mStatus_NoError
;
1544 traversal
->ExternalAddress
= onesIPv4Addr
;
1545 traversal
->ExternalPort
= zeroIPPort
;
1546 traversal
->Lifetime
= 0;
1547 traversal
->Result
= mStatus_NoError
;
1549 // set default lease if necessary
1550 if (!traversal
->NATLease
) traversal
->NATLease
= NATMAP_DEFAULT_LEASE
;
1552 #ifdef _LEGACY_NAT_TRAVERSAL_
1553 mDNSPlatformMemZero(&traversal
->tcpInfo
, sizeof(traversal
->tcpInfo
));
1554 #endif _LEGACY_NAT_TRAVERSAL_
1556 if (!m
->NATTraversals
) // If this is our first NAT request, kick off an address request too
1558 m
->retryGetAddr
= m
->timenow
;
1559 m
->retryIntervalGetAddr
= NATMAP_INIT_RETRY
;
1562 m
->NextScheduledNATOp
= m
->timenow
; // This will always trigger sending the packet ASAP, and generate client callback if necessary
1564 *n
= traversal
; // Append new NATTraversalInfo to the end of our list
1566 return(mStatus_NoError
);
1569 // Must be called with the mDNS_Lock held
1570 mDNSexport mStatus
mDNS_StopNATOperation_internal(mDNS
*m
, NATTraversalInfo
*traversal
)
1572 NATTraversalInfo
**ptr
= &m
->NATTraversals
;
1574 while (*ptr
&& *ptr
!= traversal
) ptr
=&(*ptr
)->next
;
1575 if (*ptr
) *ptr
= (*ptr
)->next
; // If we found it, cut this NATTraversalInfo struct from our list
1578 LogMsg("mDNS_StopNATOperation: NATTraversalInfo %p not found in list", traversal
);
1579 return(mStatus_BadReferenceErr
);
1582 LogOperation("mDNS_StopNATOperation_internal %d %d %d %d",
1583 traversal
->Protocol
, mDNSVal16(traversal
->IntPort
), mDNSVal16(traversal
->RequestedPort
), traversal
->NATLease
);
1585 if (m
->CurrentNATTraversal
== traversal
)
1586 m
->CurrentNATTraversal
= m
->CurrentNATTraversal
->next
;
1588 if (traversal
->ExpiryTime
)
1590 traversal
->NATLease
= 0;
1591 traversal
->retryInterval
= 0;
1592 uDNS_SendNATMsg(m
, traversal
);
1594 // 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
1595 #ifdef _LEGACY_NAT_TRAVERSAL_
1597 mStatus err
= LNT_UnmapPort(m
, traversal
);
1598 if (err
) LogMsg("Legacy NAT Traversal - unmap request failed with error %ld", err
);
1600 #endif // _LEGACY_NAT_TRAVERSAL_
1601 return(mStatus_NoError
);
1604 mDNSexport mStatus
mDNS_StartNATOperation(mDNS
*m
, NATTraversalInfo
*traversal
)
1608 status
= mDNS_StartNATOperation_internal(m
, traversal
);
1613 mDNSexport mStatus
mDNS_StopNATOperation(mDNS
*m
, NATTraversalInfo
*traversal
)
1617 status
= mDNS_StopNATOperation_internal(m
, traversal
);
1622 // ***************************************************************************
1623 #if COMPILER_LIKES_PRAGMA_MARK
1625 #pragma mark - Long-Lived Queries
1628 // Lock must be held -- otherwise m->timenow is undefined
1629 mDNSlocal
void StartLLQPolling(mDNS
*const m
, DNSQuestion
*q
)
1631 LogOperation("StartLLQPolling: %##s", q
->qname
.c
);
1632 q
->state
= LLQ_Poll
;
1633 q
->ThisQInterval
= INIT_UCAST_POLL_INTERVAL
;
1634 // We want to send our poll query ASAP, but the "+ 1" is because if we set the time to now,
1635 // we risk causing spurious "SendQueries didn't send all its queries" log messages
1636 q
->LastQTime
= m
->timenow
- q
->ThisQInterval
+ 1;
1637 SetNextQueryTime(m
, q
);
1640 mDNSlocal mDNSu8
*putLLQ(DNSMessage
*const msg
, mDNSu8
*ptr
, const DNSQuestion
*const question
, const LLQOptData
*const data
, mDNSBool includeQuestion
)
1643 ResourceRecord
*opt
= &rr
.resrec
;
1646 //!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section
1647 if (includeQuestion
)
1649 ptr
= putQuestion(msg
, ptr
, msg
->data
+ AbsoluteMaxDNSMessageData
, &question
->qname
, question
->qtype
, question
->qclass
);
1650 if (!ptr
) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL
; }
1652 // locate OptRR if it exists, set pointer to end
1653 // !!!KRS implement me
1655 // format opt rr (fields not specified are zero-valued)
1656 mDNS_SetupResourceRecord(&rr
, mDNSNULL
, mDNSInterface_Any
, kDNSType_OPT
, kStandardTTL
, kDNSRecordTypeKnownUnique
, mDNSNULL
, mDNSNULL
);
1657 opt
->rdlength
= LLQ_OPT_RDLEN
;
1658 opt
->rdestimate
= LLQ_OPT_RDLEN
;
1660 optRD
= &rr
.resrec
.rdata
->u
.opt
;
1661 optRD
->opt
= kDNSOpt_LLQ
;
1662 optRD
->optlen
= LLQ_OPTLEN
;
1663 optRD
->OptData
.llq
= *data
;
1664 ptr
= PutResourceRecordTTLJumbo(msg
, ptr
, &msg
->h
.numAdditionals
, opt
, 0);
1665 if (!ptr
) { LogMsg("ERROR: putLLQ - PutResourceRecordTTLJumbo"); return mDNSNULL
; }
1670 // Normally we'd just request event packets be sent directly to m->LLQNAT.ExternalPort, except...
1671 // with LLQs over TLS/TCP we're doing a weird thing where instead of requesting packets be sent to ExternalAddress:ExternalPort
1672 // we're requesting that packets be sent to ExternalPort, but at the source address of our outgoing TCP connection.
1673 // Normally, after going through the NAT gateway, the source address of our outgoing TCP connection is the same as ExternalAddress,
1674 // so this is fine, except when the TCP connection ends up going over a VPN tunnel instead.
1675 // 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
1676 // LLQ server to send events to us directly at port 5353 on that address, instead of at our mapped external NAT port.
1678 mDNSlocal mDNSu16
GetLLQEventPort(const mDNS
*const m
, const mDNSAddr
*const dst
)
1681 mDNSPlatformSourceAddrForDest(&src
, dst
);
1682 //LogMsg("GetLLQEventPort: src %#a for dst %#a (%d)", &src, dst, mDNSv4AddrIsRFC1918(&src.ip.v4) ? mDNSVal16(m->LLQNAT.ExternalPort) : 0);
1683 return(mDNSv4AddrIsRFC1918(&src
.ip
.v4
) ? mDNSVal16(m
->LLQNAT
.ExternalPort
) : mDNSVal16(MulticastDNSPort
));
1686 // Normally called with llq set.
1687 // May be called with llq NULL, when retransmitting a lost Challenge Response
1688 mDNSlocal
void sendChallengeResponse(mDNS
*const m
, DNSQuestion
*const q
, const LLQOptData
*llq
)
1690 mDNSu8
*responsePtr
= m
->omsg
.data
;
1693 if (q
->ntries
++ == kLLQ_MAX_TRIES
)
1695 LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s", kLLQ_MAX_TRIES
, q
->qname
.c
);
1696 StartLLQPolling(m
,q
);
1700 if (!llq
) // Retransmission: need to make a new LLQOptData
1702 llqBuf
.vers
= kLLQ_Vers
;
1703 llqBuf
.llqOp
= kLLQOp_Setup
;
1704 llqBuf
.err
= LLQErr_NoError
; // Don't need to tell server UDP notification port when sending over UDP
1706 llqBuf
.llqlease
= q
->ReqLease
;
1710 q
->LastQTime
= m
->timenow
;
1711 q
->ThisQInterval
= q
->tcp
? 0 : (kLLQ_INIT_RESEND
* q
->ntries
* mDNSPlatformOneSecond
); // If using TCP, don't need to retransmit
1712 SetNextQueryTime(m
, q
);
1714 // To simulate loss of challenge response packet, uncomment line below
1715 //if (q->ntries == 1) return;
1717 InitializeDNSMessage(&m
->omsg
.h
, q
->TargetQID
, uQueryFlags
);
1718 responsePtr
= putQuestion(&m
->omsg
, responsePtr
, m
->omsg
.data
+ AbsoluteMaxDNSMessageData
, &q
->qname
, q
->qtype
, q
->qclass
);
1719 if (responsePtr
) responsePtr
= putLLQ(&m
->omsg
, responsePtr
, q
, llq
, mDNSfalse
);
1722 mStatus err
= mDNSSendDNSMessage(m
, &m
->omsg
, responsePtr
, mDNSInterface_Any
, &q
->servAddr
, q
->servPort
, q
->tcp
? q
->tcp
->sock
: mDNSNULL
, q
->AuthInfo
);
1725 LogMsg("sendChallengeResponse: mDNSSendDNSMessage%s failed: %d", q
->tcp
? " (TCP)" : "", err
);
1726 if (q
->tcp
) { DisposeTCPConn(q
->tcp
); q
->tcp
= mDNSNULL
; }
1729 else StartLLQPolling(m
,q
);
1732 mDNSlocal
void SetLLQTimer(mDNS
*const m
, DNSQuestion
*const q
, const LLQOptData
*const llq
)
1734 mDNSs32 lease
= (mDNSs32
)llq
->llqlease
* mDNSPlatformOneSecond
;
1735 q
->ReqLease
= llq
->llqlease
;
1736 q
->LastQTime
= m
->timenow
;
1737 q
->expire
= m
->timenow
+ lease
;
1738 q
->ThisQInterval
= lease
/2 + mDNSRandom(lease
/10);
1739 SetNextQueryTime(m
, q
);
1742 mDNSlocal
void recvSetupResponse(mDNS
*const m
, mDNSu8 rcode
, DNSQuestion
*const q
, const LLQOptData
*const llq
)
1744 if (rcode
&& rcode
!= kDNSFlag1_RC_NXDomain
)
1745 { LogMsg("ERROR: recvSetupResponse %##s - rcode && rcode != kDNSFlag1_RC_NXDomain", q
->qname
.c
); return; }
1747 if (llq
->llqOp
!= kLLQOp_Setup
)
1748 { LogMsg("ERROR: recvSetupResponse %##s - bad op %d", q
->qname
.c
, llq
->llqOp
); return; }
1750 if (llq
->vers
!= kLLQ_Vers
)
1751 { LogMsg("ERROR: recvSetupResponse %##s - bad vers %d", q
->qname
.c
, llq
->vers
); return; }
1753 if (q
->state
== LLQ_InitialRequest
)
1755 //LogOperation("Got LLQ_InitialRequest");
1757 if (llq
->err
) { LogMsg("recvSetupResponse - received llq->err %d from server", llq
->err
); StartLLQPolling(m
,q
); return; }
1759 if (q
->ReqLease
!= llq
->llqlease
)
1760 debugf("recvSetupResponse: requested lease %lu, granted lease %lu", q
->ReqLease
, llq
->llqlease
);
1762 // cache expiration in case we go to sleep before finishing setup
1763 q
->ReqLease
= llq
->llqlease
;
1764 q
->expire
= m
->timenow
+ ((mDNSs32
)llq
->llqlease
* mDNSPlatformOneSecond
);
1767 q
->state
= LLQ_SecondaryRequest
;
1769 q
->ntries
= 0; // first attempt to send response
1770 sendChallengeResponse(m
, q
, llq
);
1772 else if (q
->state
== LLQ_SecondaryRequest
)
1774 //LogOperation("Got LLQ_SecondaryRequest");
1776 // Fix this immediately if not sooner. Copy the id from the LLQOptData into our DNSQuestion struct. This is only
1777 // an issue for private LLQs, because we skip parts 2 and 3 of the handshake. This is related to a bigger
1778 // problem of the current implementation of TCP LLQ setup: we're not handling state transitions correctly
1779 // if the server sends back SERVFULL or STATIC.
1782 LogOperation("Private LLQ_SecondaryRequest; copying id %08X%08X", llq
->id
.l
[0], llq
->id
.l
[1]);
1786 if (llq
->err
) { LogMsg("ERROR: recvSetupResponse %##s code %d from server", q
->qname
.c
, llq
->err
); StartLLQPolling(m
,q
); return; }
1787 if (!mDNSSameOpaque64(&q
->id
, &llq
->id
))
1788 { LogMsg("recvSetupResponse - ID changed. discarding"); return; } // this can happen rarely (on packet loss + reordering)
1789 q
->state
= LLQ_Established
;
1791 SetLLQTimer(m
, q
, llq
);
1795 mDNSexport uDNS_LLQType
uDNS_recvLLQResponse(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
, const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
)
1797 DNSQuestion pktQ
, *q
;
1798 if (msg
->h
.numQuestions
&& getQuestion(msg
, msg
->data
, end
, 0, &pktQ
))
1800 const rdataOPT
*opt
= GetLLQOptData(m
, msg
, end
);
1802 for (q
= m
->Questions
; q
; q
= q
->next
)
1804 if (!mDNSOpaque16IsZero(q
->TargetQID
) && q
->LongLived
&& q
->qtype
== pktQ
.qtype
&& q
->qnamehash
== pktQ
.qnamehash
&& SameDomainName(&q
->qname
, &pktQ
.qname
))
1806 debugf("uDNS_recvLLQResponse found %##s (%s) %d %#a %#a %X %X %X %X %d",
1807 q
->qname
.c
, DNSTypeName(q
->qtype
), q
->state
, srcaddr
, &q
->servAddr
,
1808 opt
->OptData
.llq
.id
.l
[0], opt
->OptData
.llq
.id
.l
[1], q
->id
.l
[0], q
->id
.l
[1], opt
->OptData
.llq
.llqOp
);
1809 if (q
->state
== LLQ_Poll
)
1811 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
1812 LogOperation("uDNS_recvLLQResponse got poll response; moving to LLQ_InitialRequest for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
1813 q
->state
= LLQ_InitialRequest
;
1814 q
->servPort
= zeroIPPort
; // Clear servPort so that startLLQHandshake will retry the GetZoneData processing
1815 q
->ThisQInterval
= LLQ_POLL_INTERVAL
+ mDNSRandom(LLQ_POLL_INTERVAL
/10); // Retry LLQ setup in approx 15 minutes
1816 q
->LastQTime
= m
->timenow
;
1817 SetNextQueryTime(m
, q
);
1818 return uDNS_LLQ_Entire
; // uDNS_LLQ_Entire means flush stale records; assume a large effective TTL
1820 else if (opt
&& q
->state
== LLQ_Established
&& opt
->OptData
.llq
.llqOp
== kLLQOp_Event
&& mDNSSameOpaque64(&opt
->OptData
.llq
.id
, &q
->id
))
1823 if (q
->ThisQInterval
< MAX_UCAST_POLL_INTERVAL
) q
->ThisQInterval
= MAX_UCAST_POLL_INTERVAL
;
1824 //debugf("Sending LLQ ack for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
1825 InitializeDNSMessage(&m
->omsg
.h
, msg
->h
.id
, ResponseFlags
);
1826 ackEnd
= putLLQ(&m
->omsg
, m
->omsg
.data
, mDNSNULL
, &opt
->OptData
.llq
, mDNSfalse
);
1827 if (ackEnd
) mDNSSendDNSMessage(m
, &m
->omsg
, ackEnd
, mDNSInterface_Any
, srcaddr
, srcport
, mDNSNULL
, mDNSNULL
);
1828 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
1829 return uDNS_LLQ_Events
;
1831 if (opt
&& mDNSSameOpaque16(msg
->h
.id
, q
->TargetQID
))
1833 if (q
->state
== LLQ_Established
&& opt
->OptData
.llq
.llqOp
== kLLQOp_Refresh
&& mDNSSameOpaque64(&opt
->OptData
.llq
.id
, &q
->id
) && msg
->h
.numAdditionals
&& !msg
->h
.numAnswers
)
1835 if (opt
->OptData
.llq
.err
!= LLQErr_NoError
) LogMsg("recvRefreshReply: received error %d from server", opt
->OptData
.llq
.err
);
1838 //LogOperation("Received refresh confirmation ntries %d for %##s (%s)", q->ntries, q->qname.c, DNSTypeName(q->qtype));
1839 GrantCacheExtensions(m
, q
, opt
->OptData
.llq
.llqlease
);
1840 SetLLQTimer(m
, q
, &opt
->OptData
.llq
);
1843 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
1844 return uDNS_LLQ_Ignore
;
1846 if (q
->state
< LLQ_Established
&& mDNSSameAddress(srcaddr
, &q
->servAddr
))
1848 LLQ_State oldstate
= q
->state
;
1849 recvSetupResponse(m
, msg
->h
.flags
.b
[1] & kDNSFlag1_RC_Mask
, q
, &opt
->OptData
.llq
);
1850 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
1851 // We have a protocol anomaly here in the LLQ definition.
1852 // Both the challenge packet from the server and the ack+answers packet have opt->OptData.llq.llqOp == kLLQOp_Setup.
1853 // However, we need to treat them differently:
1854 // The challenge packet has no answers in it, and tells us nothing about whether our cache entries
1855 // are still valid, so this packet should not cause us to do anything that messes with our cache.
1856 // The ack+answers packet gives us the whole truth, so we should handle it by updating our cache
1857 // to match the answers in the packet, and only the answers in the packet.
1858 return (oldstate
== LLQ_SecondaryRequest
? uDNS_LLQ_Entire
: uDNS_LLQ_Ignore
);
1863 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
1865 return uDNS_LLQ_Not
;
1868 // Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
1869 struct TCPSocket_struct
{ TCPSocketFlags flags
; /* ... */ };
1871 // tcpCallback is called to handle events (e.g. connection opening and data reception) on TCP connections for
1872 // Private DNS operations -- private queries, private LLQs, private record updates and private service updates
1873 mDNSlocal
void tcpCallback(TCPSocket
*sock
, void *context
, mDNSBool ConnectionEstablished
, mStatus err
)
1875 tcpInfo_t
*tcpInfo
= (tcpInfo_t
*)context
;
1876 mDNSBool closed
= mDNSfalse
;
1877 mDNS
*m
= tcpInfo
->m
;
1878 DNSQuestion
*const q
= tcpInfo
->question
;
1879 tcpInfo_t
**backpointer
=
1881 tcpInfo
->srs
? &tcpInfo
->srs
->tcp
:
1882 tcpInfo
->rr
? &tcpInfo
->rr
->tcp
: mDNSNULL
;
1883 if (backpointer
&& *backpointer
!= tcpInfo
)
1884 LogMsg("tcpCallback: %d backpointer %p incorrect tcpInfo %p question %p srs %p rr %p",
1885 mDNSPlatformTCPGetFD(tcpInfo
->sock
), *backpointer
, tcpInfo
, q
, tcpInfo
->srs
, tcpInfo
->rr
);
1889 if (ConnectionEstablished
)
1891 mDNSu8
*end
= ((mDNSu8
*) &tcpInfo
->request
) + tcpInfo
->requestLen
;
1892 DomainAuthInfo
*AuthInfo
;
1894 // Defensive coding for <rdar://problem/5546824> Crash in mDNSResponder at GetAuthInfoForName_internal + 366
1895 // 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
1896 if (tcpInfo
->srs
&& tcpInfo
->srs
->RR_SRV
.resrec
.name
!= &tcpInfo
->srs
->RR_SRV
.namestorage
)
1897 LogMsg("tcpCallback: ERROR: tcpInfo->srs->RR_SRV.resrec.name %p != &tcpInfo->srs->RR_SRV.namestorage %p",
1898 tcpInfo
->srs
->RR_SRV
.resrec
.name
, &tcpInfo
->srs
->RR_SRV
.namestorage
);
1899 if (tcpInfo
->rr
&& tcpInfo
->rr
->resrec
.name
!= &tcpInfo
->rr
->namestorage
)
1900 LogMsg("tcpCallback: ERROR: tcpInfo->rr->resrec.name %p != &tcpInfo->rr->namestorage %p",
1901 tcpInfo
->rr
->resrec
.name
, &tcpInfo
->rr
->namestorage
);
1902 if (tcpInfo
->srs
&& tcpInfo
->srs
->RR_SRV
.resrec
.name
!= &tcpInfo
->srs
->RR_SRV
.namestorage
) return;
1903 if (tcpInfo
->rr
&& tcpInfo
->rr
-> resrec
.name
!= &tcpInfo
->rr
-> namestorage
) return;
1905 AuthInfo
= tcpInfo
->srs
? GetAuthInfoForName(m
, tcpInfo
->srs
->RR_SRV
.resrec
.name
) :
1906 tcpInfo
->rr
? GetAuthInfoForName(m
, tcpInfo
->rr
->resrec
.name
) : mDNSNULL
;
1908 // connection is established - send the message
1909 if (q
&& q
->LongLived
&& q
->state
== LLQ_Established
)
1911 end
= ((mDNSu8
*) &tcpInfo
->request
) + tcpInfo
->requestLen
;
1913 else if (q
&& q
->LongLived
&& q
->state
!= LLQ_Poll
&& !mDNSIPPortIsZero(m
->LLQNAT
.ExternalPort
))
1916 // If we have a NAT port mapping, ExternalPort is the external port
1917 // If we have a routable address so we don't need a port mapping, ExternalPort is the same as our own internal port
1918 // If we need a NAT port mapping but can't get one, then ExternalPort is zero
1919 LLQOptData llqData
; // set llq rdata
1920 llqData
.vers
= kLLQ_Vers
;
1921 llqData
.llqOp
= kLLQOp_Setup
;
1922 llqData
.err
= GetLLQEventPort(m
, &tcpInfo
->Addr
); // We're using TCP; tell server what UDP port to send notifications to
1923 LogOperation("tcpCallback: eventPort %d", llqData
.err
);
1924 llqData
.id
= zeroOpaque64
;
1925 llqData
.llqlease
= kLLQ_DefLease
;
1926 InitializeDNSMessage(&tcpInfo
->request
.h
, q
->TargetQID
, uQueryFlags
);
1927 end
= putLLQ(&tcpInfo
->request
, tcpInfo
->request
.data
, q
, &llqData
, mDNStrue
);
1928 if (!end
) { LogMsg("ERROR: tcpCallback - putLLQ"); err
= mStatus_UnknownErr
; goto exit
; }
1929 AuthInfo
= q
->AuthInfo
; // Need to add TSIG to this message
1933 InitializeDNSMessage(&tcpInfo
->request
.h
, q
->TargetQID
, uQueryFlags
);
1934 end
= putQuestion(&tcpInfo
->request
, tcpInfo
->request
.data
, tcpInfo
->request
.data
+ AbsoluteMaxDNSMessageData
, &q
->qname
, q
->qtype
, q
->qclass
);
1935 AuthInfo
= q
->AuthInfo
; // Need to add TSIG to this message
1938 err
= mDNSSendDNSMessage(m
, &tcpInfo
->request
, end
, mDNSInterface_Any
, &tcpInfo
->Addr
, tcpInfo
->Port
, sock
, AuthInfo
);
1939 if (err
) { debugf("ERROR: tcpCallback: mDNSSendDNSMessage - %ld", err
); err
= mStatus_UnknownErr
; goto exit
; }
1941 // Record time we sent this question
1945 q
->LastQTime
= m
->timenow
;
1946 q
->ThisQInterval
= MAX_UCAST_POLL_INTERVAL
;
1947 SetNextQueryTime(m
, q
);
1954 if (tcpInfo
->nread
< 2) // First read the two-byte length preceeding the DNS message
1956 mDNSu8
*lenptr
= (mDNSu8
*)&tcpInfo
->replylen
;
1957 n
= mDNSPlatformReadTCP(sock
, lenptr
+ tcpInfo
->nread
, 2 - tcpInfo
->nread
, &closed
);
1958 if (n
< 0) { LogMsg("ERROR:tcpCallback - attempt to read message length failed (%d)", n
); err
= mStatus_ConnFailed
; goto exit
; }
1961 // It's perfectly fine for this socket to close after the first reply. The server might
1962 // be sending gratuitous replies using UDP and doesn't have a need to leave the TCP socket open.
1963 // We'll only log this event if we've never received a reply before.
1964 // BIND 9 appears to close an idle connection after 30 seconds.
1965 if (tcpInfo
->numReplies
== 0) LogMsg("ERROR: socket closed prematurely tcpInfo->nread = %d", tcpInfo
->nread
);
1966 err
= mStatus_ConnFailed
;
1970 tcpInfo
->nread
+= n
;
1971 if (tcpInfo
->nread
< 2) goto exit
;
1973 tcpInfo
->replylen
= (mDNSu16
)((mDNSu16
)lenptr
[0] << 8 | lenptr
[1]);
1974 if (tcpInfo
->replylen
< sizeof(DNSMessageHeader
))
1975 { LogMsg("ERROR: tcpCallback - length too short (%d bytes)", tcpInfo
->replylen
); err
= mStatus_UnknownErr
; goto exit
; }
1977 tcpInfo
->reply
= mDNSPlatformMemAllocate(tcpInfo
->replylen
);
1978 if (!tcpInfo
->reply
) { LogMsg("ERROR: tcpCallback - malloc failed"); err
= mStatus_NoMemoryErr
; goto exit
; }
1981 n
= mDNSPlatformReadTCP(sock
, ((char *)tcpInfo
->reply
) + (tcpInfo
->nread
- 2), tcpInfo
->replylen
- (tcpInfo
->nread
- 2), &closed
);
1983 if (n
< 0) { LogMsg("ERROR: tcpCallback - read returned %d", n
); err
= mStatus_ConnFailed
; goto exit
; }
1984 else if (closed
) { LogMsg("ERROR: socket closed prematurely %d", tcpInfo
->nread
); err
= mStatus_ConnFailed
; goto exit
; }
1986 tcpInfo
->nread
+= n
;
1988 if ((tcpInfo
->nread
- 2) == tcpInfo
->replylen
)
1990 AuthRecord
*rr
= tcpInfo
->rr
;
1991 DNSMessage
*reply
= tcpInfo
->reply
;
1992 mDNSu8
*end
= (mDNSu8
*)tcpInfo
->reply
+ tcpInfo
->replylen
;
1993 mDNSAddr Addr
= tcpInfo
->Addr
;
1994 mDNSIPPort Port
= tcpInfo
->Port
;
1995 tcpInfo
->numReplies
++;
1996 tcpInfo
->reply
= mDNSNULL
; // Detach reply buffer from tcpInfo_t, to make sure client callback can't cause it to be disposed
1998 tcpInfo
->replylen
= 0;
2000 // If we're going to dispose this connection, do it FIRST, before calling client callback
2001 // Note: Sleep code depends on us clearing *backpointer here -- it uses the clearing of rr->tcp and srs->tcp
2002 // as the signal that the DNS deregistration operation with the server has completed, and the machine may now sleep
2004 if (!q
|| !q
->LongLived
|| m
->SleepState
)
2005 { *backpointer
= mDNSNULL
; DisposeTCPConn(tcpInfo
); }
2007 if (rr
&& rr
->resrec
.RecordType
== kDNSRecordTypeDeregistering
)
2010 LogOperation("tcpCallback: CompleteDeregistration %s", ARDisplayString(m
, rr
));
2011 CompleteDeregistration(m
, rr
); // Don't touch rr after this
2015 mDNSCoreReceive(m
, reply
, end
, &Addr
, Port
, (sock
->flags
& kTCPSocketFlags_UseTLS
) ? (mDNSAddr
*)1 : mDNSNULL
, zeroIPPort
, 0);
2016 // USE CAUTION HERE: Invoking mDNSCoreReceive may have caused the environment to change, including canceling this operation itself
2018 mDNSPlatformMemFree(reply
);
2027 // Clear client backpointer FIRST -- that way if one of the callbacks cancels its operation
2028 // we won't end up double-disposing our tcpInfo_t
2029 if (backpointer
) *backpointer
= mDNSNULL
;
2031 mDNS_Lock(m
); // Need to grab the lock to get m->timenow
2035 if (q
->ThisQInterval
== 0 || q
->LastQTime
+ q
->ThisQInterval
- m
->timenow
> MAX_UCAST_POLL_INTERVAL
)
2037 q
->LastQTime
= m
->timenow
;
2038 q
->ThisQInterval
= MAX_UCAST_POLL_INTERVAL
;
2039 SetNextQueryTime(m
, q
);
2041 // ConnFailed is actually okay. It just means that the server closed the connection but the LLQ is still okay.
2042 // If the error isn't ConnFailed, then the LLQ is in bad shape.
2043 if (err
!= mStatus_ConnFailed
)
2045 if (q
->LongLived
&& q
->state
!= LLQ_Poll
) StartLLQPolling(m
, q
);
2049 if (tcpInfo
->rr
) SetRecordRetry(m
, tcpInfo
->rr
, mStatus_NoError
);
2051 if (tcpInfo
->srs
) SetRecordRetry(m
, &tcpInfo
->srs
->RR_SRV
, mStatus_NoError
);
2055 DisposeTCPConn(tcpInfo
);
2059 mDNSlocal tcpInfo_t
*MakeTCPConn(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
,
2060 TCPSocketFlags flags
, const mDNSAddr
*const Addr
, const mDNSIPPort Port
,
2061 DNSQuestion
*const question
, ServiceRecordSet
*const srs
, AuthRecord
*const rr
)
2064 mDNSIPPort srcport
= zeroIPPort
;
2065 tcpInfo_t
*info
= (tcpInfo_t
*)mDNSPlatformMemAllocate(sizeof(tcpInfo_t
));
2066 if (!info
) { LogMsg("ERROR: MakeTCP - memallocate failed"); return(mDNSNULL
); }
2067 mDNSPlatformMemZero(info
, sizeof(tcpInfo_t
));
2070 info
->sock
= mDNSPlatformTCPSocket(m
, flags
, &srcport
);
2071 info
->requestLen
= 0;
2072 info
->question
= question
;
2077 info
->reply
= mDNSNULL
;
2080 info
->numReplies
= 0;
2084 info
->requestLen
= (int) (end
- ((mDNSu8
*)msg
));
2085 mDNSPlatformMemCopy(&info
->request
, msg
, info
->requestLen
);
2088 if (!info
->sock
) { LogMsg("SendServiceRegistration: uanble to create TCP socket"); mDNSPlatformMemFree(info
); return(mDNSNULL
); }
2089 err
= mDNSPlatformTCPConnect(info
->sock
, Addr
, Port
, 0, tcpCallback
, info
);
2091 // Probably suboptimal here.
2092 // Instead of returning mDNSNULL here on failure, we should probably invoke the callback with an error code.
2093 // That way clients can put all the error handling and retry/recovery code in one place,
2094 // instead of having to handle immediate errors in one place and async errors in another.
2095 // Also: "err == mStatus_ConnEstablished" probably never happens.
2097 // Don't need to log "connection failed" in customer builds -- it happens quite often during sleep, wake, configuration changes, etc.
2098 if (err
== mStatus_ConnEstablished
) { tcpCallback(info
->sock
, info
, mDNStrue
, mStatus_NoError
); }
2099 else if (err
!= mStatus_ConnPending
) { LogOperation("MakeTCPConnection: connection failed"); DisposeTCPConn(info
); return(mDNSNULL
); }
2103 mDNSexport
void DisposeTCPConn(struct tcpInfo_t
*tcp
)
2105 mDNSPlatformTCPCloseConnection(tcp
->sock
);
2106 if (tcp
->reply
) mDNSPlatformMemFree(tcp
->reply
);
2107 mDNSPlatformMemFree(tcp
);
2110 // Lock must be held
2111 mDNSexport
void startLLQHandshake(mDNS
*m
, DNSQuestion
*q
)
2113 if (mDNSIPv4AddressIsOnes(m
->LLQNAT
.ExternalAddress
))
2115 LogOperation("startLLQHandshake: waiting for NAT status for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
2116 q
->ThisQInterval
= LLQ_POLL_INTERVAL
+ mDNSRandom(LLQ_POLL_INTERVAL
/10); // Retry in approx 15 minutes
2117 q
->LastQTime
= m
->timenow
;
2118 SetNextQueryTime(m
, q
);
2122 if (mDNSIPPortIsZero(m
->LLQNAT
.ExternalPort
))
2124 LogOperation("startLLQHandshake: Cannot receive inbound packets; will poll for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
2125 StartLLQPolling(m
, q
);
2129 if (mDNSIPPortIsZero(q
->servPort
))
2131 LogOperation("startLLQHandshake: StartGetZoneData for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
2132 q
->ThisQInterval
= LLQ_POLL_INTERVAL
+ mDNSRandom(LLQ_POLL_INTERVAL
/10); // Retry in approx 15 minutes
2133 q
->LastQTime
= m
->timenow
;
2134 SetNextQueryTime(m
, q
);
2135 q
->servAddr
= zeroAddr
;
2136 q
->servPort
= zeroIPPort
;
2137 if (q
->nta
) CancelGetZoneData(m
, q
->nta
);
2138 q
->nta
= StartGetZoneData(m
, &q
->qname
, ZoneServiceLLQ
, LLQGotZoneData
, q
);
2144 if (q
->tcp
) LogOperation("startLLQHandshake: Disposing existing TCP connection for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
2145 if (q
->tcp
) DisposeTCPConn(q
->tcp
);
2146 q
->tcp
= MakeTCPConn(m
, mDNSNULL
, mDNSNULL
, kTCPSocketFlags_UseTLS
, &q
->servAddr
, q
->servPort
, q
, mDNSNULL
, mDNSNULL
);
2148 q
->ThisQInterval
= mDNSPlatformOneSecond
* 5; // If TCP failed (transient networking glitch) try again in five seconds
2151 q
->state
= LLQ_SecondaryRequest
; // Right now, for private DNS, we skip the four-way LLQ handshake
2152 q
->ReqLease
= kLLQ_DefLease
;
2153 q
->ThisQInterval
= 0;
2155 q
->LastQTime
= m
->timenow
;
2156 SetNextQueryTime(m
, q
);
2160 LogOperation("startLLQHandshake m->AdvertisedV4 %#a%s Server %#a:%d%s %##s (%s)",
2161 &m
->AdvertisedV4
, mDNSv4AddrIsRFC1918(&m
->AdvertisedV4
.ip
.v4
) ? " (RFC 1918)" : "",
2162 &q
->servAddr
, mDNSVal16(q
->servPort
), mDNSAddrIsRFC1918(&q
->servAddr
) ? " (RFC 1918)" : "",
2163 q
->qname
.c
, DNSTypeName(q
->qtype
));
2165 if (q
->ntries
++ >= kLLQ_MAX_TRIES
)
2167 LogMsg("startLLQHandshake: %d failed attempts for LLQ %##s Polling.", kLLQ_MAX_TRIES
, q
->qname
.c
);
2168 StartLLQPolling(m
, q
);
2176 llqData
.vers
= kLLQ_Vers
;
2177 llqData
.llqOp
= kLLQOp_Setup
;
2178 llqData
.err
= LLQErr_NoError
; // Don't need to tell server UDP notification port when sending over UDP
2179 llqData
.id
= zeroOpaque64
;
2180 llqData
.llqlease
= kLLQ_DefLease
;
2182 InitializeDNSMessage(&m
->omsg
.h
, q
->TargetQID
, uQueryFlags
);
2183 end
= putLLQ(&m
->omsg
, m
->omsg
.data
, q
, &llqData
, mDNStrue
);
2184 if (!end
) { LogMsg("ERROR: startLLQHandshake - putLLQ"); StartLLQPolling(m
,q
); return; }
2186 mDNSSendDNSMessage(m
, &m
->omsg
, end
, mDNSInterface_Any
, &q
->servAddr
, q
->servPort
, mDNSNULL
, mDNSNULL
);
2188 // update question state
2189 q
->state
= LLQ_InitialRequest
;
2190 q
->ReqLease
= kLLQ_DefLease
;
2191 q
->ThisQInterval
= (kLLQ_INIT_RESEND
* mDNSPlatformOneSecond
);
2192 q
->LastQTime
= m
->timenow
;
2193 SetNextQueryTime(m
, q
);
2198 mDNSexport
const domainname
*GetServiceTarget(mDNS
*m
, ServiceRecordSet
*srs
)
2200 LogOperation("GetServiceTarget %##s", srs
->RR_SRV
.resrec
.name
->c
);
2202 if (!srs
->RR_SRV
.AutoTarget
) // If not automatically tracking this host's current name, just return the existing target
2203 return(&srs
->RR_SRV
.resrec
.rdata
->u
.srv
.target
);
2206 #if APPLE_OSX_mDNSResponder
2207 DomainAuthInfo
*AuthInfo
= GetAuthInfoForName_internal(m
, srs
->RR_SRV
.resrec
.name
);
2208 if (AuthInfo
&& AuthInfo
->AutoTunnel
)
2210 // If this AutoTunnel is not yet active, start it now (which entails activating its NAT Traversal request,
2211 // which will subsequently advertise the appropriate records when the NAT Traversal returns a result)
2212 if (!AuthInfo
->AutoTunnelNAT
.clientContext
&& m
->AutoTunnelHostAddr
.b
[0])
2213 SetupLocalAutoTunnelInterface_internal(m
);
2214 if (AuthInfo
->AutoTunnelHostRecord
.namestorage
.c
[0] == 0) return(mDNSNULL
);
2215 return(&AuthInfo
->AutoTunnelHostRecord
.namestorage
);
2218 #endif APPLE_OSX_mDNSResponder
2220 const int srvcount
= CountLabels(srs
->RR_SRV
.resrec
.name
);
2221 HostnameInfo
*besthi
= mDNSNULL
, *hi
;
2223 for (hi
= m
->Hostnames
; hi
; hi
= hi
->next
)
2224 if (hi
->arv4
.state
== regState_Registered
|| hi
->arv4
.state
== regState_Refresh
||
2225 hi
->arv6
.state
== regState_Registered
|| hi
->arv6
.state
== regState_Refresh
)
2227 int x
, hostcount
= CountLabels(&hi
->fqdn
);
2228 for (x
= hostcount
< srvcount
? hostcount
: srvcount
; x
> 0 && x
> best
; x
--)
2229 if (SameDomainName(SkipLeadingLabels(srs
->RR_SRV
.resrec
.name
, srvcount
- x
), SkipLeadingLabels(&hi
->fqdn
, hostcount
- x
)))
2230 { best
= x
; besthi
= hi
; }
2233 if (besthi
) return(&besthi
->fqdn
);
2235 if (m
->StaticHostname
.c
[0]) return(&m
->StaticHostname
);
2240 // Called with lock held
2241 mDNSlocal
void SendServiceRegistration(mDNS
*m
, ServiceRecordSet
*srs
)
2243 mDNSu8
*ptr
= m
->omsg
.data
;
2244 mDNSu8
*end
= (mDNSu8
*)&m
->omsg
+ sizeof(DNSMessage
);
2246 mStatus err
= mStatus_NoError
;
2247 const domainname
*target
;
2250 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
2251 LogMsg("SendServiceRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
2253 if (mDNSIPv4AddressIsZero(srs
->SRSUpdateServer
.ip
.v4
)) // Don't know our UpdateServer yet
2255 srs
->RR_SRV
.LastAPTime
= m
->timenow
;
2256 if (srs
->RR_SRV
.ThisAPInterval
< mDNSPlatformOneSecond
* 5)
2257 srs
->RR_SRV
.ThisAPInterval
= mDNSPlatformOneSecond
* 5;
2261 if (srs
->state
== regState_Registered
) srs
->state
= regState_Refresh
;
2263 id
= mDNS_NewMessageID(m
);
2264 InitializeDNSMessage(&m
->omsg
.h
, id
, UpdateReqFlags
);
2266 // setup resource records
2267 SetNewRData(&srs
->RR_PTR
.resrec
, mDNSNULL
, 0); // Update rdlength, rdestimate, rdatahash
2268 SetNewRData(&srs
->RR_TXT
.resrec
, mDNSNULL
, 0); // Update rdlength, rdestimate, rdatahash
2270 // replace port w/ NAT mapping if necessary
2271 if (srs
->RR_SRV
.AutoTarget
== Target_AutoHostAndNATMAP
&& !mDNSIPPortIsZero(srs
->NATinfo
.ExternalPort
))
2272 srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
= srs
->NATinfo
.ExternalPort
;
2274 // construct update packet
2276 ptr
= putZone(&m
->omsg
, ptr
, end
, &srs
->zone
, mDNSOpaque16fromIntVal(srs
->RR_SRV
.resrec
.rrclass
));
2277 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
2279 if (srs
->TestForSelfConflict
)
2281 // update w/ prereq that SRV already exist to make sure previous registration was ours, and delete any stale TXT records
2282 if (!(ptr
= PutResourceRecordTTLJumbo(&m
->omsg
, ptr
, &m
->omsg
.h
.mDNS_numPrereqs
, &srs
->RR_SRV
.resrec
, 0))) { err
= mStatus_UnknownErr
; goto exit
; }
2283 if (!(ptr
= putDeleteRRSet(&m
->omsg
, ptr
, srs
->RR_TXT
.resrec
.name
, srs
->RR_TXT
.resrec
.rrtype
))) { err
= mStatus_UnknownErr
; goto exit
; }
2286 else if (srs
->state
!= regState_Refresh
&& srs
->state
!= regState_UpdatePending
)
2288 // use SRV name for prereq
2289 //ptr = putPrereqNameNotInUse(srs->RR_SRV.resrec.name, &m->omsg, ptr, end);
2291 // For now, until we implement RFC 4701 (DHCID RR) to detect whether an existing record is someone else using the name, or just a
2292 // stale echo of our own previous registration before we changed our host name, we just overwrite whatever may have already been there
2293 ptr
= putDeleteRRSet(&m
->omsg
, ptr
, srs
->RR_SRV
.resrec
.name
, kDNSQType_ANY
);
2294 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
2297 //!!!KRS Need to do bounds checking and use TCP if it won't fit!!!
2298 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
; }
2300 for (i
= 0; i
< srs
->NumSubTypes
; i
++)
2301 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
; }
2303 if (srs
->state
== regState_UpdatePending
) // we're updating the txt record
2305 AuthRecord
*txt
= &srs
->RR_TXT
;
2307 SetNewRData(&txt
->resrec
, txt
->OrigRData
, txt
->OrigRDLen
);
2308 if (!(ptr
= putDeletionRecord(&m
->omsg
, ptr
, &srs
->RR_TXT
.resrec
))) { err
= mStatus_UnknownErr
; goto exit
; } // delete old rdata
2311 SetNewRData(&txt
->resrec
, txt
->InFlightRData
, txt
->InFlightRDLen
);
2312 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
; }
2315 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
; }
2317 target
= GetServiceTarget(m
, srs
);
2318 if (!target
|| target
->c
[0] == 0)
2320 LogOperation("SendServiceRegistration - no target for %##s", srs
->RR_SRV
.resrec
.name
->c
);
2321 srs
->state
= regState_NoTarget
;
2325 if (!SameDomainName(target
, &srs
->RR_SRV
.resrec
.rdata
->u
.srv
.target
))
2327 AssignDomainName(&srs
->RR_SRV
.resrec
.rdata
->u
.srv
.target
, target
);
2328 SetNewRData(&srs
->RR_SRV
.resrec
, mDNSNULL
, 0); // Update rdlength, rdestimate, rdatahash
2331 ptr
= PutResourceRecordTTLJumbo(&m
->omsg
, ptr
, &m
->omsg
.h
.mDNS_numUpdates
, &srs
->RR_SRV
.resrec
, srs
->RR_SRV
.resrec
.rroriginalttl
);
2332 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
2334 if (srs
->srs_uselease
)
2335 { ptr
= putUpdateLease(&m
->omsg
, ptr
, DEFAULT_UPDATE_LEASE
); if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; } }
2337 if (srs
->state
!= regState_Refresh
&& srs
->state
!= regState_DeregDeferred
&& srs
->state
!= regState_UpdatePending
)
2338 srs
->state
= regState_Pending
;
2344 if (srs
->tcp
) LogOperation("SendServiceRegistration: Disposing existing TCP connection for %s", ARDisplayString(m
, &srs
->RR_SRV
));
2345 if (srs
->tcp
) DisposeTCPConn(srs
->tcp
);
2346 srs
->tcp
= MakeTCPConn(m
, &m
->omsg
, ptr
, kTCPSocketFlags_UseTLS
, &srs
->SRSUpdateServer
, srs
->SRSUpdatePort
, mDNSNULL
, srs
, mDNSNULL
);
2347 if (!srs
->tcp
) srs
->RR_SRV
.ThisAPInterval
= mDNSPlatformOneSecond
* 5; // If failed to make TCP connection, try again in ten seconds (5*2)
2348 else if (srs
->RR_SRV
.ThisAPInterval
< mDNSPlatformOneSecond
* 30) srs
->RR_SRV
.ThisAPInterval
= mDNSPlatformOneSecond
* 30;
2352 err
= mDNSSendDNSMessage(m
, &m
->omsg
, ptr
, mDNSInterface_Any
, &srs
->SRSUpdateServer
, srs
->SRSUpdatePort
, mDNSNULL
, GetAuthInfoForName_internal(m
, srs
->RR_SRV
.resrec
.name
));
2353 if (err
) debugf("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %ld", err
);
2356 SetRecordRetry(m
, &srs
->RR_SRV
, err
);
2362 LogMsg("SendServiceRegistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
2364 srs
->state
= regState_Unregistered
;
2366 mDNS_DropLockBeforeCallback();
2367 srs
->ServiceCallback(m
, srs
, err
);
2368 mDNS_ReclaimLockAfterCallback();
2369 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
2370 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
2374 mDNSlocal
const domainname
*PUBLIC_UPDATE_SERVICE_TYPE
= (const domainname
*)"\x0B_dns-update" "\x04_udp";
2375 mDNSlocal
const domainname
*PUBLIC_LLQ_SERVICE_TYPE
= (const domainname
*)"\x08_dns-llq" "\x04_udp";
2377 mDNSlocal
const domainname
*PRIVATE_UPDATE_SERVICE_TYPE
= (const domainname
*)"\x0F_dns-update-tls" "\x04_tcp";
2378 mDNSlocal
const domainname
*PRIVATE_QUERY_SERVICE_TYPE
= (const domainname
*)"\x0E_dns-query-tls" "\x04_tcp";
2379 mDNSlocal
const domainname
*PRIVATE_LLQ_SERVICE_TYPE
= (const domainname
*)"\x0C_dns-llq-tls" "\x04_tcp";
2381 #define ZoneDataSRV(X) (\
2382 (X)->ZoneService == ZoneServiceUpdate ? ((X)->ZonePrivate ? PRIVATE_UPDATE_SERVICE_TYPE : PUBLIC_UPDATE_SERVICE_TYPE) : \
2383 (X)->ZoneService == ZoneServiceQuery ? ((X)->ZonePrivate ? PRIVATE_QUERY_SERVICE_TYPE : (const domainname*)"" ) : \
2384 (X)->ZoneService == ZoneServiceLLQ ? ((X)->ZonePrivate ? PRIVATE_LLQ_SERVICE_TYPE : PUBLIC_LLQ_SERVICE_TYPE ) : (const domainname*)"")
2386 // Forward reference: GetZoneData_StartQuery references GetZoneData_QuestionCallback, and
2387 // GetZoneData_QuestionCallback calls GetZoneData_StartQuery
2388 mDNSlocal mStatus
GetZoneData_StartQuery(mDNS
*const m
, ZoneData
*zd
, mDNSu16 qtype
);
2390 // GetZoneData_QuestionCallback is called from normal client callback context (core API calls allowed)
2391 mDNSlocal
void GetZoneData_QuestionCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
2393 ZoneData
*zd
= (ZoneData
*)question
->QuestionContext
;
2395 debugf("GetZoneData_QuestionCallback: %s %s", AddRecord
? "Add" : "Rmv", RRDisplayString(m
, answer
));
2397 if (!AddRecord
) return; // Don't care about REMOVE events
2398 if (AddRecord
== QC_addnocache
&& answer
->rdlength
== 0) return; // Don't care about transient failure indications
2399 if (answer
->rrtype
!= question
->qtype
) return; // Don't care about CNAMEs
2401 if (answer
->rrtype
== kDNSType_SOA
)
2403 debugf("GetZoneData GOT SOA %s", RRDisplayString(m
, answer
));
2404 mDNS_StopQuery(m
, question
);
2405 if (answer
->rdlength
)
2407 AssignDomainName(&zd
->ZoneName
, answer
->name
);
2408 zd
->ZoneClass
= answer
->rrclass
;
2409 AssignDomainName(&zd
->question
.qname
, &zd
->ZoneName
);
2410 GetZoneData_StartQuery(m
, zd
, kDNSType_SRV
);
2412 else if (zd
->CurrentSOA
->c
[0])
2414 zd
->CurrentSOA
= (domainname
*)(zd
->CurrentSOA
->c
+ zd
->CurrentSOA
->c
[0]+1);
2415 AssignDomainName(&zd
->question
.qname
, zd
->CurrentSOA
);
2416 GetZoneData_StartQuery(m
, zd
, kDNSType_SOA
);
2420 LogOperation("GetZoneData recursed to root label of %##s without finding SOA", zd
->ChildName
.c
);
2421 zd
->ZoneDataCallback(m
, mStatus_NoSuchNameErr
, zd
);
2422 mDNSPlatformMemFree(zd
);
2425 else if (answer
->rrtype
== kDNSType_SRV
)
2427 debugf("GetZoneData GOT SRV %s", RRDisplayString(m
, answer
));
2428 mDNS_StopQuery(m
, question
);
2429 if (!answer
->rdlength
&& zd
->ZonePrivate
&& zd
->ZoneService
!= ZoneServiceQuery
)
2431 zd
->ZonePrivate
= mDNSfalse
; // Causes ZoneDataSRV() to yield a different SRV name when building the query
2432 GetZoneData_StartQuery(m
, zd
, kDNSType_SRV
); // Try again, non-private this time
2436 if (answer
->rdlength
)
2438 AssignDomainName(&zd
->Host
, &answer
->rdata
->u
.srv
.target
);
2439 zd
->Port
= answer
->rdata
->u
.srv
.port
;
2440 AssignDomainName(&zd
->question
.qname
, &zd
->Host
);
2441 GetZoneData_StartQuery(m
, zd
, kDNSType_A
);
2445 zd
->ZonePrivate
= mDNSfalse
;
2447 zd
->Port
= zeroIPPort
;
2448 zd
->Addr
= zeroAddr
;
2449 zd
->ZoneDataCallback(m
, mStatus_NoError
, zd
);
2450 mDNSPlatformMemFree(zd
);
2454 else if (answer
->rrtype
== kDNSType_A
)
2456 debugf("GetZoneData GOT A %s", RRDisplayString(m
, answer
));
2457 mDNS_StopQuery(m
, question
);
2458 zd
->Addr
.type
= mDNSAddrType_IPv4
;
2459 zd
->Addr
.ip
.v4
= (answer
->rdlength
== 4) ? answer
->rdata
->u
.ipv4
: zerov4Addr
;
2460 // In order to simulate firewalls blocking our outgoing TCP connections, returning immediate ICMP errors or TCP resets,
2461 // the code below will make us try to connect to loopback, resulting in an immediate "port unreachable" failure.
2462 // This helps us test to make sure we handle this case gracefully
2463 // <rdar://problem/5607082> BTMM: mDNSResponder taking 100 percent CPU after upgrading to 10.5.1
2465 zd
->Addr
.ip
.v4
.b
[0] = 127;
2466 zd
->Addr
.ip
.v4
.b
[1] = 0;
2467 zd
->Addr
.ip
.v4
.b
[2] = 0;
2468 zd
->Addr
.ip
.v4
.b
[3] = 1;
2470 zd
->ZoneDataCallback(m
, mStatus_NoError
, zd
);
2471 mDNSPlatformMemFree(zd
);
2475 // GetZoneData_StartQuery is called from normal client context (lock not held, or client callback)
2476 mDNSlocal mStatus
GetZoneData_StartQuery(mDNS
*const m
, ZoneData
*zd
, mDNSu16 qtype
)
2478 if (qtype
== kDNSType_SRV
)
2480 AssignDomainName(&zd
->question
.qname
, ZoneDataSRV(zd
));
2481 AppendDomainName(&zd
->question
.qname
, &zd
->ZoneName
);
2482 LogOperation("lookupDNSPort %##s", zd
->question
.qname
.c
);
2485 zd
->question
.ThisQInterval
= -1; // So that GetZoneData_QuestionCallback() knows whether to cancel this question (Is this necessary?)
2486 zd
->question
.InterfaceID
= mDNSInterface_Any
;
2487 zd
->question
.Target
= zeroAddr
;
2488 //zd->question.qname.c[0] = 0; // Already set
2489 zd
->question
.qtype
= qtype
;
2490 zd
->question
.qclass
= kDNSClass_IN
;
2491 zd
->question
.LongLived
= mDNSfalse
;
2492 zd
->question
.ExpectUnique
= mDNStrue
;
2493 zd
->question
.ForceMCast
= mDNSfalse
;
2494 zd
->question
.ReturnIntermed
= mDNStrue
;
2495 zd
->question
.QuestionCallback
= GetZoneData_QuestionCallback
;
2496 zd
->question
.QuestionContext
= zd
;
2498 //LogMsg("GetZoneData_StartQuery %##s (%s) %p", zd->question.qname.c, DNSTypeName(zd->question.qtype), zd->question.Private);
2499 return(mDNS_StartQuery(m
, &zd
->question
));
2502 // StartGetZoneData is an internal routine (i.e. must be called with the lock already held)
2503 mDNSexport ZoneData
*StartGetZoneData(mDNS
*const m
, const domainname
*const name
, const ZoneService target
, ZoneDataCallback callback
, void *ZoneDataContext
)
2505 DomainAuthInfo
*AuthInfo
= GetAuthInfoForName_internal(m
, name
);
2506 int initialskip
= (AuthInfo
&& AuthInfo
->AutoTunnel
) ? DomainNameLength(name
) - DomainNameLength(&AuthInfo
->domain
) : 0;
2507 ZoneData
*zd
= (ZoneData
*)mDNSPlatformMemAllocate(sizeof(ZoneData
));
2508 if (!zd
) { LogMsg("ERROR: StartGetZoneData - mDNSPlatformMemAllocate failed"); return mDNSNULL
; }
2509 mDNSPlatformMemZero(zd
, sizeof(ZoneData
));
2510 AssignDomainName(&zd
->ChildName
, name
);
2511 zd
->ZoneService
= target
;
2512 zd
->CurrentSOA
= (domainname
*)(&zd
->ChildName
.c
[initialskip
]);
2513 zd
->ZoneName
.c
[0] = 0;
2516 zd
->Port
= zeroIPPort
;
2517 zd
->Addr
= zeroAddr
;
2518 zd
->ZonePrivate
= AuthInfo
? mDNStrue
: mDNSfalse
;
2519 zd
->ZoneDataCallback
= callback
;
2520 zd
->ZoneDataContext
= ZoneDataContext
;
2522 zd
->question
.QuestionContext
= zd
;
2523 AssignDomainName(&zd
->question
.qname
, zd
->CurrentSOA
);
2525 mDNS_DropLockBeforeCallback(); // GetZoneData_StartQuery expects to be called from a normal callback, so we emulate that here
2526 GetZoneData_StartQuery(m
, zd
, kDNSType_SOA
);
2527 mDNS_ReclaimLockAfterCallback();
2532 // GetZoneData queries are a special case -- even if we have a key for them, we don't do them privately,
2533 // because that would result in an infinite loop (i.e. to do a private query we first need to get
2534 // the _dns-query-tls SRV record for the zone, and we can't do *that* privately because to do so
2535 // we'd need to already know the _dns-query-tls SRV record.
2536 // Also, as a general rule, we never do SOA queries privately
2537 mDNSexport DomainAuthInfo
*GetAuthInfoForQuestion(mDNS
*m
, const DNSQuestion
*const q
) // Must be called with lock held
2539 if (q
->QuestionCallback
== GetZoneData_QuestionCallback
) return(mDNSNULL
);
2540 if (q
->qtype
== kDNSType_SOA
) return(mDNSNULL
);
2541 return(GetAuthInfoForName_internal(m
, &q
->qname
));
2544 // ***************************************************************************
2545 #if COMPILER_LIKES_PRAGMA_MARK
2546 #pragma mark - host name and interface management
2549 // Called in normal client context (lock not held)
2550 mDNSlocal
void CompleteSRVNatMap(mDNS
*m
, NATTraversalInfo
*n
)
2552 ServiceRecordSet
*srs
= (ServiceRecordSet
*)n
->clientContext
;
2553 LogOperation("SRVNatMap complete %.4a %u %u TTL %u", &n
->ExternalAddress
, mDNSVal16(n
->IntPort
), mDNSVal16(n
->ExternalPort
), n
->NATLease
);
2555 if (!srs
) { LogMsg("CompleteSRVNatMap called with unknown ServiceRecordSet object"); return; }
2556 if (!n
->NATLease
) return;
2559 if (!mDNSIPv4AddressIsZero(srs
->SRSUpdateServer
.ip
.v4
))
2560 SendServiceRegistration(m
, srs
); // non-zero server address means we already have necessary zone data to send update
2563 // SHOULD NEVER HAPPEN!
2564 LogOperation("ERROR: CompleteSRVNatMap called but srs->SRSUpdateServer.ip.v4 is zero!");
2565 srs
->state
= regState_FetchingZoneData
;
2566 if (srs
->nta
) CancelGetZoneData(m
, srs
->nta
); // Make sure we cancel old one before we start a new one
2567 srs
->nta
= StartGetZoneData(m
, srs
->RR_SRV
.resrec
.name
, ZoneServiceUpdate
, ServiceRegistrationGotZoneData
, srs
);
2572 mDNSlocal
void StartSRVNatMap(mDNS
*m
, ServiceRecordSet
*srs
)
2574 const mDNSu8
*p
= srs
->RR_PTR
.resrec
.name
->c
;
2575 if (p
[0]) p
+= 1 + p
[0];
2576 if (SameDomainLabel(p
, (mDNSu8
*)"\x4" "_tcp")) srs
->NATinfo
.Protocol
= NATOp_MapTCP
;
2577 else if (SameDomainLabel(p
, (mDNSu8
*)"\x4" "_udp")) srs
->NATinfo
.Protocol
= NATOp_MapUDP
;
2578 else { LogMsg("StartSRVNatMap: could not determine transport protocol of service %##s", srs
->RR_SRV
.resrec
.name
->c
); return; }
2580 if (srs
->NATinfo
.clientContext
) mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
2581 srs
->NATinfo
.IntPort
= srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
;
2582 srs
->NATinfo
.RequestedPort
= srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
;
2583 srs
->NATinfo
.NATLease
= 0; // Request default lease
2584 srs
->NATinfo
.clientCallback
= CompleteSRVNatMap
;
2585 srs
->NATinfo
.clientContext
= srs
;
2586 mDNS_StartNATOperation_internal(m
, &srs
->NATinfo
);
2589 // Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
2590 mDNSexport
void ServiceRegistrationGotZoneData(mDNS
*const m
, mStatus err
, const ZoneData
*zoneData
)
2592 ServiceRecordSet
*srs
= (ServiceRecordSet
*)zoneData
->ZoneDataContext
;
2594 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
)
2595 LogMsg("ServiceRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
2597 srs
->nta
= mDNSNULL
;
2599 // Start off assuming we're going to use a lease
2600 // If we get an error from the server, and the update port as given in the SRV record is 53, then we'll retry without the lease option
2601 srs
->srs_uselease
= mDNStrue
;
2603 if (err
|| !zoneData
) return;
2605 if (mDNSIPPortIsZero(zoneData
->Port
) || mDNSAddressIsZero(&zoneData
->Addr
)) return;
2608 AssignDomainName(&srs
->zone
, &zoneData
->ZoneName
);
2609 srs
->SRSUpdateServer
.type
= mDNSAddrType_IPv4
;
2610 srs
->SRSUpdateServer
= zoneData
->Addr
;
2611 srs
->SRSUpdatePort
= zoneData
->Port
;
2612 srs
->Private
= zoneData
->ZonePrivate
;
2614 srs
->RR_SRV
.LastAPTime
= m
->timenow
;
2615 srs
->RR_SRV
.ThisAPInterval
= 0;
2617 LogOperation("ServiceRegistrationGotZoneData My IPv4 %#a%s Server %#a:%d%s for %##s",
2618 &m
->AdvertisedV4
, mDNSv4AddrIsRFC1918(&m
->AdvertisedV4
.ip
.v4
) ? " (RFC1918)" : "",
2619 &srs
->SRSUpdateServer
, mDNSVal16(srs
->SRSUpdatePort
), mDNSAddrIsRFC1918(&srs
->SRSUpdateServer
) ? " (RFC1918)" : "",
2620 srs
->RR_SRV
.resrec
.name
->c
);
2622 if (!mDNSIPPortIsZero(srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
) &&
2623 mDNSv4AddrIsRFC1918(&m
->AdvertisedV4
.ip
.v4
) && !mDNSAddrIsRFC1918(&srs
->SRSUpdateServer
) &&
2624 srs
->RR_SRV
.AutoTarget
== Target_AutoHostAndNATMAP
)
2626 srs
->state
= regState_NATMap
;
2627 LogOperation("ServiceRegistrationGotZoneData StartSRVNatMap");
2628 StartSRVNatMap(m
, srs
);
2633 SendServiceRegistration(m
, srs
);
2638 mDNSlocal
void SendServiceDeregistration(mDNS
*m
, ServiceRecordSet
*srs
)
2641 mDNSu8
*ptr
= m
->omsg
.data
;
2642 mDNSu8
*end
= (mDNSu8
*)&m
->omsg
+ sizeof(DNSMessage
);
2643 mStatus err
= mStatus_UnknownErr
;
2646 if (mDNSIPv4AddressIsZero(srs
->SRSUpdateServer
.ip
.v4
)) // Don't know our UpdateServer yet
2648 srs
->RR_SRV
.LastAPTime
= m
->timenow
;
2649 if (srs
->RR_SRV
.ThisAPInterval
< mDNSPlatformOneSecond
* 5)
2650 srs
->RR_SRV
.ThisAPInterval
= mDNSPlatformOneSecond
* 5;
2654 id
= mDNS_NewMessageID(m
);
2655 InitializeDNSMessage(&m
->omsg
.h
, id
, UpdateReqFlags
);
2658 ptr
= putZone(&m
->omsg
, ptr
, end
, &srs
->zone
, mDNSOpaque16fromIntVal(srs
->RR_SRV
.resrec
.rrclass
));
2659 if (!ptr
) { LogMsg("ERROR: SendServiceDeregistration - putZone"); err
= mStatus_UnknownErr
; goto exit
; }
2661 if (!(ptr
= putDeleteAllRRSets(&m
->omsg
, ptr
, srs
->RR_SRV
.resrec
.name
))) { err
= mStatus_UnknownErr
; goto exit
; } // this deletes SRV, TXT, and Extras
2662 if (!(ptr
= putDeletionRecord(&m
->omsg
, ptr
, &srs
->RR_PTR
.resrec
))) { err
= mStatus_UnknownErr
; goto exit
; }
2663 for (i
= 0; i
< srs
->NumSubTypes
; i
++)
2664 if (!(ptr
= putDeletionRecord(&m
->omsg
, ptr
, &srs
->SubTypes
[i
].resrec
))) { err
= mStatus_UnknownErr
; goto exit
; }
2667 srs
->state
= regState_DeregPending
;
2668 srs
->RR_SRV
.expire
= 0; // Indicate that we have no active registration any more
2672 LogOperation("SendServiceDeregistration TCP %p %s", srs
->tcp
, ARDisplayString(m
, &srs
->RR_SRV
));
2673 if (srs
->tcp
) LogOperation("SendServiceDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m
, &srs
->RR_SRV
));
2674 if (srs
->tcp
) DisposeTCPConn(srs
->tcp
);
2675 srs
->tcp
= MakeTCPConn(m
, &m
->omsg
, ptr
, kTCPSocketFlags_UseTLS
, &srs
->SRSUpdateServer
, srs
->SRSUpdatePort
, mDNSNULL
, srs
, mDNSNULL
);
2676 if (!srs
->tcp
) srs
->RR_SRV
.ThisAPInterval
= mDNSPlatformOneSecond
* 5; // If failed to make TCP connection, try again in ten seconds (5*2)
2677 else if (srs
->RR_SRV
.ThisAPInterval
< mDNSPlatformOneSecond
* 30) srs
->RR_SRV
.ThisAPInterval
= mDNSPlatformOneSecond
* 30;
2681 err
= mDNSSendDNSMessage(m
, &m
->omsg
, ptr
, mDNSInterface_Any
, &srs
->SRSUpdateServer
, srs
->SRSUpdatePort
, mDNSNULL
, GetAuthInfoForName_internal(m
, srs
->RR_SRV
.resrec
.name
));
2682 if (err
&& err
!= mStatus_TransientErr
) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %ld", err
); goto exit
; }
2685 SetRecordRetry(m
, &srs
->RR_SRV
, err
);
2691 LogMsg("SendServiceDeregistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
2693 srs
->state
= regState_Unregistered
;
2697 // Called with lock held
2698 mDNSlocal
void UpdateSRV(mDNS
*m
, ServiceRecordSet
*srs
)
2700 ExtraResourceRecord
*e
;
2702 // Target change if:
2703 // We have a target and were previously waiting for one, or
2704 // We had a target and no longer do, or
2705 // The target has changed
2707 domainname
*curtarget
= &srs
->RR_SRV
.resrec
.rdata
->u
.srv
.target
;
2708 const domainname
*const nt
= GetServiceTarget(m
, srs
);
2709 const domainname
*const newtarget
= nt
? nt
: (domainname
*)"";
2710 mDNSBool TargetChanged
= (newtarget
->c
[0] && srs
->state
== regState_NoTarget
) || !SameDomainName(curtarget
, newtarget
);
2711 mDNSBool HaveZoneData
= !mDNSIPv4AddressIsZero(srs
->SRSUpdateServer
.ip
.v4
);
2713 // Nat state change if:
2714 // We were behind a NAT, and now we are behind a new NAT, or
2715 // We're not behind a NAT but our port was previously mapped to a different public port
2716 // We were not behind a NAT and now we are
2718 mDNSIPPort port
= srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
;
2719 mDNSBool NowNeedNATMAP
= (srs
->RR_SRV
.AutoTarget
== Target_AutoHostAndNATMAP
&& !mDNSIPPortIsZero(port
) && mDNSv4AddrIsRFC1918(&m
->AdvertisedV4
.ip
.v4
) && !mDNSAddrIsRFC1918(&srs
->SRSUpdateServer
));
2720 mDNSBool WereBehindNAT
= (srs
->NATinfo
.clientContext
!= mDNSNULL
);
2721 mDNSBool PortWasMapped
= (srs
->NATinfo
.clientContext
&& !mDNSSameIPPort(srs
->NATinfo
.RequestedPort
, port
)); // I think this is always false -- SC Sept 07
2722 mDNSBool NATChanged
= (!WereBehindNAT
&& NowNeedNATMAP
) || (!NowNeedNATMAP
&& PortWasMapped
);
2724 LogOperation("UpdateSRV %##s newtarget %##s TargetChanged %d HaveZoneData %d port %d NowNeedNATMAP %d WereBehindNAT %d PortWasMapped %d NATChanged %d",
2725 srs
->RR_SRV
.resrec
.name
->c
, newtarget
,
2726 TargetChanged
, HaveZoneData
, mDNSVal16(port
), NowNeedNATMAP
, WereBehindNAT
, PortWasMapped
, NATChanged
);
2728 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
2729 LogMsg("UpdateSRV: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
2731 if (!TargetChanged
&& !NATChanged
) return;
2735 case regState_FetchingZoneData
:
2736 case regState_DeregPending
:
2737 case regState_DeregDeferred
:
2738 case regState_Unregistered
:
2739 case regState_NATMap
:
2740 case regState_ExtraQueued
:
2741 // In these states, the SRV has either not yet been registered (it will get up-to-date information when it is)
2742 // or is in the process of, or has already been, deregistered
2745 case regState_Pending
:
2746 case regState_Refresh
:
2747 case regState_UpdatePending
:
2748 // let the in-flight operation complete before updating
2749 srs
->SRVUpdateDeferred
= mDNStrue
;
2752 case regState_NATError
:
2753 if (!NATChanged
) return;
2754 // if nat changed, register if we have a target (below)
2756 case regState_NoTarget
:
2757 if (newtarget
->c
[0])
2759 debugf("UpdateSRV: %s service %##s", HaveZoneData
? (NATChanged
&& NowNeedNATMAP
? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs
->RR_SRV
.resrec
.name
->c
);
2762 srs
->state
= regState_FetchingZoneData
;
2763 if (srs
->nta
) CancelGetZoneData(m
, srs
->nta
); // Make sure we cancel old one before we start a new one
2764 srs
->nta
= StartGetZoneData(m
, srs
->RR_SRV
.resrec
.name
, ZoneServiceUpdate
, ServiceRegistrationGotZoneData
, srs
);
2768 if (srs
->NATinfo
.clientContext
&& (NATChanged
|| !NowNeedNATMAP
))
2770 mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
2771 srs
->NATinfo
.clientContext
= mDNSNULL
;
2773 if (NATChanged
&& NowNeedNATMAP
&& srs
->RR_SRV
.AutoTarget
== Target_AutoHostAndNATMAP
)
2774 { srs
->state
= regState_NATMap
; StartSRVNatMap(m
, srs
); }
2775 else SendServiceRegistration(m
, srs
);
2780 case regState_Registered
:
2781 // target or nat changed. deregister service. upon completion, we'll look for a new target
2782 debugf("UpdateSRV: SRV record changed for service %##s - deregistering (will re-register with new SRV)", srs
->RR_SRV
.resrec
.name
->c
);
2783 for (e
= srs
->Extras
; e
; e
= e
->next
) e
->r
.state
= regState_ExtraQueued
; // extra will be re-registed if the service is re-registered
2784 srs
->SRVChanged
= mDNStrue
;
2785 SendServiceDeregistration(m
, srs
);
2788 default: LogMsg("UpdateSRV: Unknown state %d for %##s", srs
->state
, srs
->RR_SRV
.resrec
.name
->c
);
2792 // Called with lock held
2793 mDNSlocal
void UpdateSRVRecords(mDNS
*m
)
2795 LogOperation("UpdateSRVRecords%s", m
->SleepState
? " (ignored due to SleepState)" : "");
2796 if (m
->SleepState
) return;
2798 if (CurrentServiceRecordSet
)
2799 LogMsg("UpdateSRVRecords ERROR CurrentServiceRecordSet already set");
2800 CurrentServiceRecordSet
= m
->ServiceRegistrations
;
2802 while (CurrentServiceRecordSet
)
2804 ServiceRecordSet
*s
= CurrentServiceRecordSet
;
2805 CurrentServiceRecordSet
= CurrentServiceRecordSet
->uDNS_next
;
2810 // Forward reference: AdvertiseHostname references HostnameCallback, and HostnameCallback calls AdvertiseHostname
2811 mDNSlocal
void HostnameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
);
2813 // Called in normal client context (lock not held)
2814 mDNSlocal
void hostnameGetPublicAddressCallback(mDNS
*m
, NATTraversalInfo
*n
)
2816 HostnameInfo
*h
= (HostnameInfo
*)n
->clientContext
;
2818 if (!h
) { LogMsg("RegisterHostnameRecord: registration cancelled"); return; }
2822 if (mDNSIPv4AddressIsZero(n
->ExternalAddress
) || mDNSv4AddrIsRFC1918(&n
->ExternalAddress
)) return;
2824 if (h
->arv4
.resrec
.RecordType
)
2826 if (mDNSSameIPv4Address(h
->arv4
.resrec
.rdata
->u
.ipv4
, n
->ExternalAddress
)) return; // If address unchanged, do nothing
2827 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
);
2828 mDNS_Deregister(m
, &h
->arv4
); // mStatus_MemFree callback will re-register with new address
2832 LogOperation("Advertising hostname %##s IPv4 %.4a (NAT gateway's external address)", h
->arv4
.resrec
.name
->c
, &n
->ExternalAddress
);
2833 h
->arv4
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
2834 h
->arv4
.resrec
.rdata
->u
.ipv4
= n
->ExternalAddress
;
2835 mDNS_Register(m
, &h
->arv4
);
2840 // register record or begin NAT traversal
2841 mDNSlocal
void AdvertiseHostname(mDNS
*m
, HostnameInfo
*h
)
2843 if (!mDNSIPv4AddressIsZero(m
->AdvertisedV4
.ip
.v4
) && h
->arv4
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
2845 mDNS_SetupResourceRecord(&h
->arv4
, mDNSNULL
, mDNSInterface_Any
, kDNSType_A
, kHostNameTTL
, kDNSRecordTypeUnregistered
, HostnameCallback
, h
);
2846 AssignDomainName(&h
->arv4
.namestorage
, &h
->fqdn
);
2847 h
->arv4
.resrec
.rdata
->u
.ipv4
= m
->AdvertisedV4
.ip
.v4
;
2848 h
->arv4
.state
= regState_Unregistered
;
2849 if (mDNSv4AddrIsRFC1918(&m
->AdvertisedV4
.ip
.v4
))
2851 // If we already have a NAT query active, stop it and restart it to make sure we get another callback
2852 if (h
->natinfo
.clientContext
) mDNS_StopNATOperation_internal(m
, &h
->natinfo
);
2853 h
->natinfo
.Protocol
= 0;
2854 h
->natinfo
.IntPort
= zeroIPPort
;
2855 h
->natinfo
.RequestedPort
= zeroIPPort
;
2856 h
->natinfo
.NATLease
= 0;
2857 h
->natinfo
.clientCallback
= hostnameGetPublicAddressCallback
;
2858 h
->natinfo
.clientContext
= h
;
2859 mDNS_StartNATOperation_internal(m
, &h
->natinfo
);
2863 LogOperation("Advertising hostname %##s IPv4 %.4a", h
->arv4
.resrec
.name
->c
, &m
->AdvertisedV4
.ip
.v4
);
2864 h
->arv4
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
2865 mDNS_Register_internal(m
, &h
->arv4
);
2869 if (!mDNSIPv6AddressIsZero(m
->AdvertisedV6
.ip
.v6
) && h
->arv6
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
2871 mDNS_SetupResourceRecord(&h
->arv6
, mDNSNULL
, mDNSInterface_Any
, kDNSType_AAAA
, kHostNameTTL
, kDNSRecordTypeKnownUnique
, HostnameCallback
, h
);
2872 AssignDomainName(&h
->arv6
.namestorage
, &h
->fqdn
);
2873 h
->arv6
.resrec
.rdata
->u
.ipv6
= m
->AdvertisedV6
.ip
.v6
;
2874 h
->arv6
.state
= regState_Unregistered
;
2875 LogOperation("Advertising hostname %##s IPv6 %.16a", h
->arv6
.resrec
.name
->c
, &m
->AdvertisedV6
.ip
.v6
);
2876 mDNS_Register_internal(m
, &h
->arv6
);
2880 mDNSlocal
void HostnameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
2882 HostnameInfo
*hi
= (HostnameInfo
*)rr
->RecordContext
;
2884 if (result
== mStatus_MemFree
)
2888 // If we're still in the Hostnames list, update to new address
2890 LogOperation("HostnameCallback: Got mStatus_MemFree for %p %p %s", hi
, rr
, ARDisplayString(m
, rr
));
2891 for (i
= m
->Hostnames
; i
; i
= i
->next
)
2892 if (rr
== &i
->arv4
|| rr
== &i
->arv6
)
2893 { mDNS_Lock(m
); AdvertiseHostname(m
, i
); mDNS_Unlock(m
); return; }
2895 // Else, we're not still in the Hostnames list, so free the memory
2896 if (hi
->arv4
.resrec
.RecordType
== kDNSRecordTypeUnregistered
&&
2897 hi
->arv6
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
2899 if (hi
->natinfo
.clientContext
) mDNS_StopNATOperation_internal(m
, &hi
->natinfo
);
2900 hi
->natinfo
.clientContext
= mDNSNULL
;
2901 mDNSPlatformMemFree(hi
); // free hi when both v4 and v6 AuthRecs deallocated
2909 // don't unlink or free - we can retry when we get a new address/router
2910 if (rr
->resrec
.rrtype
== kDNSType_A
)
2911 LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.4a", result
, rr
->resrec
.name
->c
, &rr
->resrec
.rdata
->u
.ipv4
);
2913 LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.16a", result
, rr
->resrec
.name
->c
, &rr
->resrec
.rdata
->u
.ipv6
);
2914 if (!hi
) { mDNSPlatformMemFree(rr
); return; }
2915 if (rr
->state
!= regState_Unregistered
) LogMsg("Error: HostnameCallback invoked with error code for record not in regState_Unregistered!");
2917 if (hi
->arv4
.state
== regState_Unregistered
&&
2918 hi
->arv6
.state
== regState_Unregistered
)
2920 // only deliver status if both v4 and v6 fail
2921 rr
->RecordContext
= (void *)hi
->StatusContext
;
2922 if (hi
->StatusCallback
)
2923 hi
->StatusCallback(m
, rr
, result
); // client may NOT make API calls here
2924 rr
->RecordContext
= (void *)hi
;
2929 // register any pending services that require a target
2931 UpdateSRVRecords(m
);
2934 // Deliver success to client
2935 if (!hi
) { LogMsg("HostnameCallback invoked with orphaned address record"); return; }
2936 if (rr
->resrec
.rrtype
== kDNSType_A
)
2937 LogOperation("Registered hostname %##s IP %.4a", rr
->resrec
.name
->c
, &rr
->resrec
.rdata
->u
.ipv4
);
2939 LogOperation("Registered hostname %##s IP %.16a", rr
->resrec
.name
->c
, &rr
->resrec
.rdata
->u
.ipv6
);
2941 rr
->RecordContext
= (void *)hi
->StatusContext
;
2942 if (hi
->StatusCallback
)
2943 hi
->StatusCallback(m
, rr
, result
); // client may NOT make API calls here
2944 rr
->RecordContext
= (void *)hi
;
2947 mDNSlocal
void FoundStaticHostname(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
2949 const domainname
*pktname
= &answer
->rdata
->u
.name
;
2950 domainname
*storedname
= &m
->StaticHostname
;
2951 HostnameInfo
*h
= m
->Hostnames
;
2955 debugf("FoundStaticHostname: %##s -> %##s (%s)", question
->qname
.c
, answer
->rdata
->u
.name
.c
, AddRecord
? "added" : "removed");
2956 if (AddRecord
&& !SameDomainName(pktname
, storedname
))
2958 AssignDomainName(storedname
, pktname
);
2961 if (h
->arv4
.state
== regState_FetchingZoneData
|| h
->arv4
.state
== regState_Pending
|| h
->arv4
.state
== regState_NATMap
||
2962 h
->arv6
.state
== regState_FetchingZoneData
|| h
->arv6
.state
== regState_Pending
)
2964 // 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
2965 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
+ 5 * mDNSPlatformOneSecond
);
2971 UpdateSRVRecords(m
);
2974 else if (!AddRecord
&& SameDomainName(pktname
, storedname
))
2977 storedname
->c
[0] = 0;
2978 UpdateSRVRecords(m
);
2983 // Called with lock held
2984 mDNSlocal
void GetStaticHostname(mDNS
*m
)
2986 char buf
[MAX_REVERSE_MAPPING_NAME_V4
];
2987 DNSQuestion
*q
= &m
->ReverseMap
;
2988 mDNSu8
*ip
= m
->AdvertisedV4
.ip
.v4
.b
;
2991 if (m
->ReverseMap
.ThisQInterval
!= -1) mDNS_StopQuery_internal(m
, q
);
2993 m
->StaticHostname
.c
[0] = 0;
2994 if (mDNSIPv4AddressIsZero(m
->AdvertisedV4
.ip
.v4
)) return;
2995 mDNSPlatformMemZero(q
, sizeof(*q
));
2996 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
2997 mDNS_snprintf(buf
, sizeof(buf
), "%d.%d.%d.%d.in-addr.arpa.", ip
[3], ip
[2], ip
[1], ip
[0]);
2998 if (!MakeDomainNameFromDNSNameString(&q
->qname
, buf
)) { LogMsg("Error: GetStaticHostname - bad name %s", buf
); return; }
3000 q
->InterfaceID
= mDNSInterface_Any
;
3001 q
->Target
= zeroAddr
;
3002 q
->qtype
= kDNSType_PTR
;
3003 q
->qclass
= kDNSClass_IN
;
3004 q
->LongLived
= mDNSfalse
;
3005 q
->ExpectUnique
= mDNSfalse
;
3006 q
->ForceMCast
= mDNSfalse
;
3007 q
->ReturnIntermed
= mDNStrue
;
3008 q
->QuestionCallback
= FoundStaticHostname
;
3009 q
->QuestionContext
= mDNSNULL
;
3011 err
= mDNS_StartQuery_internal(m
, q
);
3012 if (err
) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err
);
3015 mDNSexport
void mDNS_AddDynDNSHostName(mDNS
*m
, const domainname
*fqdn
, mDNSRecordCallback
*StatusCallback
, const void *StatusContext
)
3017 HostnameInfo
**ptr
= &m
->Hostnames
;
3019 LogOperation("mDNS_AddDynDNSHostName %##s", fqdn
);
3021 while (*ptr
&& !SameDomainName(fqdn
, &(*ptr
)->fqdn
)) ptr
= &(*ptr
)->next
;
3022 if (*ptr
) { LogMsg("DynDNSHostName %##s already in list", fqdn
->c
); return; }
3024 // allocate and format new address record
3025 *ptr
= mDNSPlatformMemAllocate(sizeof(**ptr
));
3026 if (!*ptr
) { LogMsg("ERROR: mDNS_AddDynDNSHostName - malloc"); return; }
3028 mDNSPlatformMemZero(*ptr
, sizeof(**ptr
));
3029 AssignDomainName(&(*ptr
)->fqdn
, fqdn
);
3030 (*ptr
)->arv4
.state
= regState_Unregistered
;
3031 (*ptr
)->arv6
.state
= regState_Unregistered
;
3032 (*ptr
)->StatusCallback
= StatusCallback
;
3033 (*ptr
)->StatusContext
= StatusContext
;
3035 AdvertiseHostname(m
, *ptr
);
3038 mDNSexport
void mDNS_RemoveDynDNSHostName(mDNS
*m
, const domainname
*fqdn
)
3040 HostnameInfo
**ptr
= &m
->Hostnames
;
3042 LogOperation("mDNS_RemoveDynDNSHostName %##s", fqdn
);
3044 while (*ptr
&& !SameDomainName(fqdn
, &(*ptr
)->fqdn
)) ptr
= &(*ptr
)->next
;
3045 if (!*ptr
) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn
->c
);
3048 HostnameInfo
*hi
= *ptr
;
3049 // We do it this way because, if we have no active v6 record, the "mDNS_Deregister_internal(m, &hi->arv4);"
3050 // below could free the memory, and we have to make sure we don't touch hi fields after that.
3051 mDNSBool f4
= hi
->arv4
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
&& hi
->arv4
.state
!= regState_Unregistered
;
3052 mDNSBool f6
= hi
->arv6
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
&& hi
->arv6
.state
!= regState_Unregistered
;
3053 if (f4
) LogOperation("mDNS_RemoveDynDNSHostName removing v4 %##s", fqdn
);
3054 if (f6
) LogOperation("mDNS_RemoveDynDNSHostName removing v6 %##s", fqdn
);
3055 *ptr
= (*ptr
)->next
; // unlink
3056 if (f4
) mDNS_Deregister_internal(m
, &hi
->arv4
, mDNS_Dereg_normal
);
3057 if (f6
) mDNS_Deregister_internal(m
, &hi
->arv6
, mDNS_Dereg_normal
);
3058 // When both deregistrations complete we'll free the memory in the mStatus_MemFree callback
3060 UpdateSRVRecords(m
);
3063 // Currently called without holding the lock
3064 // Maybe we should change that?
3065 mDNSexport
void mDNS_SetPrimaryInterfaceInfo(mDNS
*m
, const mDNSAddr
*v4addr
, const mDNSAddr
*v6addr
, const mDNSAddr
*router
)
3067 mDNSBool v4Changed
, v6Changed
, RouterChanged
;
3069 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
)
3070 LogMsg("mDNS_SetPrimaryInterfaceInfo: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
3072 if (v4addr
&& v4addr
->type
!= mDNSAddrType_IPv4
) { LogMsg("mDNS_SetPrimaryInterfaceInfo v4 address - incorrect type. Discarding. %#a", v4addr
); return; }
3073 if (v6addr
&& v6addr
->type
!= mDNSAddrType_IPv6
) { LogMsg("mDNS_SetPrimaryInterfaceInfo v6 address - incorrect type. Discarding. %#a", v6addr
); return; }
3074 if (router
&& router
->type
!= mDNSAddrType_IPv4
) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-v4 router. Discarding. %#a", router
); return; }
3078 if (v4addr
&& !mDNSv4AddressIsLinkLocal(&v4addr
->ip
.v4
)) v6addr
= mDNSNULL
;
3080 v4Changed
= !mDNSSameIPv4Address(m
->AdvertisedV4
.ip
.v4
, v4addr
? v4addr
->ip
.v4
: zerov4Addr
);
3081 v6Changed
= !mDNSSameIPv6Address(m
->AdvertisedV6
.ip
.v6
, v6addr
? v6addr
->ip
.v6
: zerov6Addr
);
3082 RouterChanged
= !mDNSSameIPv4Address(m
->Router
.ip
.v4
, router
? router
->ip
.v4
: zerov4Addr
);
3084 if (v4addr
&& (v4Changed
|| RouterChanged
))
3085 debugf("mDNS_SetPrimaryInterfaceInfo: address changed from %#a to %#a", &m
->AdvertisedV4
, v4addr
);
3087 if (v4addr
) m
->AdvertisedV4
= *v4addr
; else m
->AdvertisedV4
.ip
.v4
= zerov4Addr
;
3088 if (v6addr
) m
->AdvertisedV6
= *v6addr
; else m
->AdvertisedV6
.ip
.v6
= zerov6Addr
;
3089 if (router
) m
->Router
= *router
; else m
->Router
.ip
.v4
= zerov4Addr
;
3090 // setting router to zero indicates that nat mappings must be reestablished when router is reset
3092 if (v4Changed
|| RouterChanged
|| v6Changed
)
3095 LogOperation("mDNS_SetPrimaryInterfaceInfo: %s%s%s%#a %#a %#a",
3096 v4Changed
? "v4Changed " : "",
3097 RouterChanged
? "RouterChanged " : "",
3098 v6Changed
? "v6Changed " : "", v4addr
, v6addr
, router
);
3100 for (i
= m
->Hostnames
; i
; i
= i
->next
)
3102 LogOperation("mDNS_SetPrimaryInterfaceInfo updating host name registrations for %##s", i
->fqdn
.c
);
3104 if (i
->arv4
.resrec
.RecordType
> kDNSRecordTypeDeregistering
&&
3105 !mDNSSameIPv4Address(i
->arv4
.resrec
.rdata
->u
.ipv4
, m
->AdvertisedV4
.ip
.v4
))
3107 LogOperation("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m
, &i
->arv4
));
3108 mDNS_Deregister_internal(m
, &i
->arv4
, mDNS_Dereg_normal
);
3111 if (i
->arv6
.resrec
.RecordType
> kDNSRecordTypeDeregistering
&&
3112 !mDNSSameIPv6Address(i
->arv6
.resrec
.rdata
->u
.ipv6
, m
->AdvertisedV6
.ip
.v6
))
3114 LogOperation("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m
, &i
->arv6
));
3115 mDNS_Deregister_internal(m
, &i
->arv6
, mDNS_Dereg_normal
);
3118 // AdvertiseHostname will only register new address records.
3119 // For records still in the process of deregistering it will ignore them, and let the mStatus_MemFree callback handle them.
3120 AdvertiseHostname(m
, i
);
3123 if (v4Changed
|| RouterChanged
)
3125 m
->ExternalAddress
= zerov4Addr
;
3126 m
->retryIntervalGetAddr
= NATMAP_INIT_RETRY
;
3127 m
->retryGetAddr
= m
->timenow
;
3128 m
->NextScheduledNATOp
= m
->timenow
;
3132 UpdateSRVRecords(m
);
3133 GetStaticHostname(m
); // look up reverse map record to find any static hostnames for our IP address
3139 // ***************************************************************************
3140 #if COMPILER_LIKES_PRAGMA_MARK
3141 #pragma mark - Incoming Message Processing
3144 mDNSlocal mStatus
ParseTSIGError(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
, const domainname
*const displayname
)
3147 mStatus err
= mStatus_NoError
;
3150 ptr
= LocateAdditionals(msg
, end
);
3151 if (!ptr
) goto finish
;
3153 for (i
= 0; i
< msg
->h
.numAdditionals
; i
++)
3155 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &m
->rec
);
3156 if (!ptr
) goto finish
;
3157 if (m
->rec
.r
.resrec
.rrtype
== kDNSType_TSIG
)
3160 mDNSu8
*rd
= m
->rec
.r
.resrec
.rdata
->u
.data
;
3161 mDNSu8
*rdend
= rd
+ m
->rec
.r
.resrec
.rdlength
;
3162 int alglen
= DomainNameLengthLimit(&m
->rec
.r
.resrec
.rdata
->u
.name
, rdend
);
3163 if (alglen
> MAX_DOMAIN_NAME
) goto finish
;
3164 rd
+= alglen
; // algorithm name
3165 if (rd
+ 6 > rdend
) goto finish
;
3166 rd
+= 6; // 48-bit timestamp
3167 if (rd
+ sizeof(mDNSOpaque16
) > rdend
) goto finish
;
3168 rd
+= sizeof(mDNSOpaque16
); // fudge
3169 if (rd
+ sizeof(mDNSOpaque16
) > rdend
) goto finish
;
3170 macsize
= mDNSVal16(*(mDNSOpaque16
*)rd
);
3171 rd
+= sizeof(mDNSOpaque16
); // MAC size
3172 if (rd
+ macsize
> rdend
) goto finish
;
3174 if (rd
+ sizeof(mDNSOpaque16
) > rdend
) goto finish
;
3175 rd
+= sizeof(mDNSOpaque16
); // orig id
3176 if (rd
+ sizeof(mDNSOpaque16
) > rdend
) goto finish
;
3177 err
= mDNSVal16(*(mDNSOpaque16
*)rd
); // error code
3179 if (err
== TSIG_ErrBadSig
) { LogMsg("%##s: bad signature", displayname
->c
); err
= mStatus_BadSig
; }
3180 else if (err
== TSIG_ErrBadKey
) { LogMsg("%##s: bad key", displayname
->c
); err
= mStatus_BadKey
; }
3181 else if (err
== TSIG_ErrBadTime
) { LogMsg("%##s: bad time", displayname
->c
); err
= mStatus_BadTime
; }
3182 else if (err
) { LogMsg("%##s: unknown tsig error %d", displayname
->c
, err
); err
= mStatus_UnknownErr
; }
3185 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
3189 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
3193 mDNSlocal mStatus
checkUpdateResult(mDNS
*const m
, const domainname
*const displayname
, const mDNSu8 rcode
, const DNSMessage
*const msg
, const mDNSu8
*const end
)
3195 (void)msg
; // currently unused, needed for TSIG errors
3196 if (!rcode
) return mStatus_NoError
;
3197 else if (rcode
== kDNSFlag1_RC_YXDomain
)
3199 debugf("name in use: %##s", displayname
->c
);
3200 return mStatus_NameConflict
;
3202 else if (rcode
== kDNSFlag1_RC_Refused
)
3204 LogMsg("Update %##s refused", displayname
->c
);
3205 return mStatus_Refused
;
3207 else if (rcode
== kDNSFlag1_RC_NXRRSet
)
3209 LogMsg("Reregister refused (NXRRSET): %##s", displayname
->c
);
3210 return mStatus_NoSuchRecord
;
3212 else if (rcode
== kDNSFlag1_RC_NotAuth
)
3214 // TSIG errors should come with FmtErr as per RFC 2845, but BIND 9 sends them with NotAuth so we look here too
3215 mStatus tsigerr
= ParseTSIGError(m
, msg
, end
, displayname
);
3218 LogMsg("Permission denied (NOAUTH): %##s", displayname
->c
);
3219 return mStatus_UnknownErr
;
3221 else return tsigerr
;
3223 else if (rcode
== kDNSFlag1_RC_FmtErr
)
3225 mStatus tsigerr
= ParseTSIGError(m
, msg
, end
, displayname
);
3228 LogMsg("Format Error: %##s", displayname
->c
);
3229 return mStatus_UnknownErr
;
3231 else return tsigerr
;
3235 LogMsg("Update %##s failed with rcode %d", displayname
->c
, rcode
);
3236 return mStatus_UnknownErr
;
3240 // Called with lock held
3241 mDNSlocal
void SendRecordRegistration(mDNS
*const m
, AuthRecord
*rr
)
3243 mDNSu8
*ptr
= m
->omsg
.data
;
3244 mDNSu8
*end
= (mDNSu8
*)&m
->omsg
+ sizeof(DNSMessage
);
3245 mStatus err
= mStatus_UnknownErr
;
3247 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
3248 LogMsg("SendRecordRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
3250 if (mDNSIPv4AddressIsZero(rr
->UpdateServer
.ip
.v4
)) // Don't know our UpdateServer yet
3252 rr
->LastAPTime
= m
->timenow
;
3253 if (rr
->ThisAPInterval
< mDNSPlatformOneSecond
* 5)
3254 rr
->ThisAPInterval
= mDNSPlatformOneSecond
* 5;
3258 rr
->RequireGoodbye
= mDNStrue
;
3259 rr
->id
= mDNS_NewMessageID(m
);
3260 InitializeDNSMessage(&m
->omsg
.h
, rr
->id
, UpdateReqFlags
);
3263 ptr
= putZone(&m
->omsg
, ptr
, end
, &rr
->zone
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
3264 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
3266 if (rr
->state
== regState_UpdatePending
)
3269 SetNewRData(&rr
->resrec
, rr
->OrigRData
, rr
->OrigRDLen
);
3270 if (!(ptr
= putDeletionRecord(&m
->omsg
, ptr
, &rr
->resrec
))) { err
= mStatus_UnknownErr
; goto exit
; } // delete old rdata
3273 SetNewRData(&rr
->resrec
, rr
->InFlightRData
, rr
->InFlightRDLen
);
3274 if (!(ptr
= PutResourceRecordTTLJumbo(&m
->omsg
, ptr
, &m
->omsg
.h
.mDNS_numUpdates
, &rr
->resrec
, rr
->resrec
.rroriginalttl
))) { err
= mStatus_UnknownErr
; goto exit
; }
3279 if (rr
->resrec
.RecordType
== kDNSRecordTypeKnownUnique
)
3281 // KnownUnique: Delete any previous value
3282 ptr
= putDeleteRRSet(&m
->omsg
, ptr
, rr
->resrec
.name
, rr
->resrec
.rrtype
);
3283 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
3286 else if (rr
->resrec
.RecordType
!= kDNSRecordTypeShared
)
3288 ptr
= putPrereqNameNotInUse(rr
->resrec
.name
, &m
->omsg
, ptr
, end
);
3289 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
3292 ptr
= PutResourceRecordTTLJumbo(&m
->omsg
, ptr
, &m
->omsg
.h
.mDNS_numUpdates
, &rr
->resrec
, rr
->resrec
.rroriginalttl
);
3293 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
3298 ptr
= putUpdateLease(&m
->omsg
, ptr
, DEFAULT_UPDATE_LEASE
); if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
3303 LogOperation("SendRecordRegistration TCP %p %s", rr
->tcp
, ARDisplayString(m
, rr
));
3304 if (rr
->tcp
) LogOperation("SendRecordRegistration: Disposing existing TCP connection for %s", ARDisplayString(m
, rr
));
3305 if (rr
->tcp
) DisposeTCPConn(rr
->tcp
);
3306 rr
->tcp
= MakeTCPConn(m
, &m
->omsg
, ptr
, kTCPSocketFlags_UseTLS
, &rr
->UpdateServer
, rr
->UpdatePort
, mDNSNULL
, mDNSNULL
, rr
);
3307 if (!rr
->tcp
) rr
->ThisAPInterval
= mDNSPlatformOneSecond
* 5; // If failed to make TCP connection, try again in ten seconds (5*2)
3308 else if (rr
->ThisAPInterval
< mDNSPlatformOneSecond
* 30) rr
->ThisAPInterval
= mDNSPlatformOneSecond
* 30;
3312 err
= mDNSSendDNSMessage(m
, &m
->omsg
, ptr
, mDNSInterface_Any
, &rr
->UpdateServer
, rr
->UpdatePort
, mDNSNULL
, GetAuthInfoForName_internal(m
, rr
->resrec
.name
));
3313 if (err
) debugf("ERROR: SendRecordRegistration - mDNSSendDNSMessage - %ld", err
);
3316 SetRecordRetry(m
, rr
, err
);
3318 if (rr
->state
!= regState_Refresh
&& rr
->state
!= regState_DeregDeferred
&& rr
->state
!= regState_UpdatePending
)
3319 rr
->state
= regState_Pending
;
3324 LogMsg("SendRecordRegistration: Error formatting message for %s", ARDisplayString(m
, rr
));
3327 // Called with lock held
3328 mDNSlocal
void hndlServiceUpdateReply(mDNS
*const m
, ServiceRecordSet
*srs
, mStatus err
)
3330 mDNSBool InvokeCallback
= mDNSfalse
;
3331 ExtraResourceRecord
**e
= &srs
->Extras
;
3332 AuthRecord
*txt
= &srs
->RR_TXT
;
3334 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
3335 LogMsg("hndlServiceUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
3337 LogOperation("hndlServiceUpdateReply: err %d state %d %##s", err
, srs
->state
, srs
->RR_SRV
.resrec
.name
->c
);
3339 SetRecordRetry(m
, &srs
->RR_SRV
, mStatus_NoError
);
3343 case regState_Pending
:
3344 if (err
== mStatus_NameConflict
&& !srs
->TestForSelfConflict
)
3346 srs
->TestForSelfConflict
= mDNStrue
;
3347 debugf("checking for self-conflict of service %##s", srs
->RR_SRV
.resrec
.name
->c
);
3348 SendServiceRegistration(m
, srs
);
3351 else if (srs
->TestForSelfConflict
)
3353 srs
->TestForSelfConflict
= mDNSfalse
;
3354 if (err
== mStatus_NoSuchRecord
) err
= mStatus_NameConflict
; // NoSuchRecord implies that our prereq was not met, so we actually have a name conflict
3355 if (!err
) srs
->state
= regState_Registered
;
3356 InvokeCallback
= mDNStrue
;
3359 else if (srs
->srs_uselease
&& err
== mStatus_UnknownErr
&& mDNSSameIPPort(srs
->SRSUpdatePort
, UnicastDNSPort
))
3361 LogMsg("Re-trying update of service %##s without lease option", srs
->RR_SRV
.resrec
.name
->c
);
3362 srs
->srs_uselease
= mDNSfalse
;
3363 SendServiceRegistration(m
, srs
);
3368 //!!!KRS make sure all structs will still get cleaned up when client calls DeregisterService with this state
3369 if (err
) LogMsg("Error %ld for registration of service %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
3370 else srs
->state
= regState_Registered
;
3371 InvokeCallback
= mDNStrue
;
3374 case regState_Refresh
:
3377 LogMsg("Error %ld for refresh of service %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
3378 InvokeCallback
= mDNStrue
;
3380 else srs
->state
= regState_Registered
;
3382 case regState_DeregPending
:
3383 if (err
) LogMsg("Error %ld for deregistration of service %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
3384 if (srs
->SRVChanged
)
3386 srs
->state
= regState_NoTarget
; // NoTarget will allow us to pick up new target OR nat traversal state
3389 err
= mStatus_MemFree
;
3390 InvokeCallback
= mDNStrue
;
3391 if (srs
->NATinfo
.clientContext
)
3393 // deletion completed
3394 mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
3395 srs
->NATinfo
.clientContext
= mDNSNULL
;
3397 srs
->state
= regState_Unregistered
;
3399 case regState_DeregDeferred
:
3402 debugf("Error %ld received prior to deferred derigstration of %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
3403 err
= mStatus_MemFree
;
3404 InvokeCallback
= mDNStrue
;
3405 srs
->state
= regState_Unregistered
;
3410 debugf("Performing deferred deregistration of %##s", srs
->RR_SRV
.resrec
.name
->c
);
3411 srs
->state
= regState_Registered
;
3412 SendServiceDeregistration(m
, srs
);
3415 case regState_UpdatePending
:
3418 LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs
->RR_SRV
.resrec
.name
->c
);
3419 InvokeCallback
= mDNStrue
;
3423 srs
->state
= regState_Registered
;
3424 // deallocate old RData
3425 if (txt
->UpdateCallback
) txt
->UpdateCallback(m
, txt
, txt
->OrigRData
);
3426 SetNewRData(&txt
->resrec
, txt
->InFlightRData
, txt
->InFlightRDLen
);
3427 txt
->OrigRData
= mDNSNULL
;
3428 txt
->InFlightRData
= mDNSNULL
;
3431 case regState_NoTarget
:
3432 // This state is used when using SendServiceDeregistration() when going to sleep -- no further action required
3434 case regState_FetchingZoneData
:
3435 case regState_Registered
:
3436 case regState_Unregistered
:
3437 case regState_NATMap
:
3438 case regState_ExtraQueued
:
3439 case regState_NATError
:
3440 LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %ld. Unlinking.",
3441 srs
->RR_SRV
.resrec
.name
->c
, srs
->state
, err
);
3442 err
= mStatus_UnknownErr
;
3443 default: LogMsg("hndlServiceUpdateReply: Unknown state %d for %##s", srs
->state
, srs
->RR_SRV
.resrec
.name
->c
);
3446 if ((srs
->SRVChanged
|| srs
->SRVUpdateDeferred
) && (srs
->state
== regState_NoTarget
|| srs
->state
== regState_Registered
))
3448 LogOperation("hndlServiceUpdateReply: SRVChanged %d SRVUpdateDeferred %d state %d", srs
->SRVChanged
, srs
->SRVUpdateDeferred
, srs
->state
);
3451 srs
->ClientCallbackDeferred
= mDNStrue
;
3452 srs
->DeferredStatus
= err
;
3454 srs
->SRVChanged
= srs
->SRVUpdateDeferred
= mDNSfalse
;
3461 if ((*e
)->r
.state
== regState_ExtraQueued
)
3463 if (srs
->state
== regState_Registered
&& !err
)
3465 // extra resource record queued for this service - copy zone srs and register
3466 AssignDomainName(&(*e
)->r
.zone
, &srs
->zone
);
3467 (*e
)->r
.UpdateServer
= srs
->SRSUpdateServer
;
3468 (*e
)->r
.UpdatePort
= srs
->SRSUpdatePort
;
3469 (*e
)->r
.uselease
= srs
->srs_uselease
;
3470 SendRecordRegistration(m
, &(*e
)->r
);
3473 else if (err
&& (*e
)->r
.state
!= regState_Unregistered
)
3475 // unlink extra from list
3476 (*e
)->r
.state
= regState_Unregistered
;
3479 else e
= &(*e
)->next
;
3481 else e
= &(*e
)->next
;
3484 if (srs
->state
== regState_Unregistered
)
3486 if (err
!= mStatus_MemFree
)
3487 LogMsg("hndlServiceUpdateReply ERROR! state == regState_Unregistered but err != mStatus_MemFree. Permanently abandoning service registration %##s",
3488 srs
->RR_SRV
.resrec
.name
->c
);
3491 else if (txt
->QueuedRData
&& srs
->state
== regState_Registered
)
3495 // if we were supposed to give a client callback, we'll do it after we update the primary txt record
3496 srs
->ClientCallbackDeferred
= mDNStrue
;
3497 srs
->DeferredStatus
= err
;
3499 srs
->state
= regState_UpdatePending
;
3500 txt
->InFlightRData
= txt
->QueuedRData
;
3501 txt
->InFlightRDLen
= txt
->QueuedRDLen
;
3502 txt
->OrigRData
= txt
->resrec
.rdata
;
3503 txt
->OrigRDLen
= txt
->resrec
.rdlength
;
3504 txt
->QueuedRData
= mDNSNULL
;
3505 SendServiceRegistration(m
, srs
);
3509 mDNS_DropLockBeforeCallback();
3511 srs
->ServiceCallback(m
, srs
, err
);
3512 else if (srs
->ClientCallbackDeferred
)
3514 srs
->ClientCallbackDeferred
= mDNSfalse
;
3515 srs
->ServiceCallback(m
, srs
, srs
->DeferredStatus
);
3517 mDNS_ReclaimLockAfterCallback();
3518 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
3519 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
3522 // Called with lock held
3523 mDNSlocal
void hndlRecordUpdateReply(mDNS
*m
, AuthRecord
*rr
, mStatus err
)
3525 mDNSBool InvokeCallback
= mDNStrue
;
3527 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
3528 LogMsg("hndlRecordUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
3530 LogOperation("hndlRecordUpdateReply: err %d state %d %s", err
, rr
->state
, ARDisplayString(m
, rr
));
3532 if (m
->SleepState
) return; // If we just sent a deregister on going to sleep, no further action required
3534 SetRecordRetry(m
, rr
, mStatus_NoError
);
3536 if (rr
->state
== regState_UpdatePending
)
3538 if (err
) LogMsg("Update record failed for %##s (err %d)", rr
->resrec
.name
->c
, err
);
3539 rr
->state
= regState_Registered
;
3540 // deallocate old RData
3541 if (rr
->UpdateCallback
) rr
->UpdateCallback(m
, rr
, rr
->OrigRData
);
3542 SetNewRData(&rr
->resrec
, rr
->InFlightRData
, rr
->InFlightRDLen
);
3543 rr
->OrigRData
= mDNSNULL
;
3544 rr
->InFlightRData
= mDNSNULL
;
3547 if (rr
->state
== regState_DeregPending
)
3549 debugf("Received reply for deregister record %##s type %d", rr
->resrec
.name
->c
, rr
->resrec
.rrtype
);
3550 if (err
) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %ld",
3551 rr
->resrec
.name
->c
, rr
->resrec
.rrtype
, err
);
3552 err
= mStatus_MemFree
;
3553 rr
->state
= regState_Unregistered
;
3556 if (rr
->state
== regState_DeregDeferred
)
3560 LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %ld",
3561 rr
->resrec
.name
->c
, rr
->resrec
.rrtype
, err
);
3562 rr
->state
= regState_Unregistered
;
3564 debugf("Calling deferred deregistration of record %##s type %d", rr
->resrec
.name
->c
, rr
->resrec
.rrtype
);
3565 rr
->state
= regState_Registered
;
3566 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
3570 if (rr
->state
== regState_Pending
|| rr
->state
== regState_Refresh
)
3574 if (rr
->state
== regState_Refresh
) InvokeCallback
= mDNSfalse
;
3575 rr
->state
= regState_Registered
;
3579 if (rr
->uselease
&& err
== mStatus_UnknownErr
&& mDNSSameIPPort(rr
->UpdatePort
, UnicastDNSPort
))
3581 LogMsg("Re-trying update of record %##s without lease option", rr
->resrec
.name
->c
);
3582 rr
->uselease
= mDNSfalse
;
3583 SendRecordRegistration(m
, rr
);
3586 LogMsg("hndlRecordUpdateReply: Registration of record %##s type %d failed with error %ld", rr
->resrec
.name
->c
, rr
->resrec
.rrtype
, err
);
3591 if (rr
->state
== regState_Unregistered
) // Should never happen
3593 LogMsg("hndlRecordUpdateReply rr->state == regState_Unregistered %s", ARDisplayString(m
, rr
));
3597 if (rr
->QueuedRData
&& rr
->state
== regState_Registered
)
3599 rr
->state
= regState_UpdatePending
;
3600 rr
->InFlightRData
= rr
->QueuedRData
;
3601 rr
->InFlightRDLen
= rr
->QueuedRDLen
;
3602 rr
->OrigRData
= rr
->resrec
.rdata
;
3603 rr
->OrigRDLen
= rr
->resrec
.rdlength
;
3604 rr
->QueuedRData
= mDNSNULL
;
3605 SendRecordRegistration(m
, rr
);
3609 if (InvokeCallback
&& rr
->RecordCallback
)
3611 mDNS_DropLockBeforeCallback();
3612 rr
->RecordCallback(m
, rr
, err
);
3613 mDNS_ReclaimLockAfterCallback();
3615 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
3616 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
3619 mDNSexport
void uDNS_ReceiveNATPMPPacket(mDNS
*m
, const mDNSInterfaceID InterfaceID
, mDNSu8
*pkt
, mDNSu16 len
)
3621 NATTraversalInfo
*ptr
;
3622 NATAddrReply
*AddrReply
= (NATAddrReply
*)pkt
;
3623 NATPortMapReply
*PortMapReply
= (NATPortMapReply
*)pkt
;
3624 mDNSu32 nat_elapsed
, our_elapsed
;
3626 // Minimum packet is vers (1) opcode (1) err (2) upseconds (4) = 8 bytes
3627 if (!AddrReply
->err
&& len
< 8) { LogMsg("NAT Traversal message too short (%d bytes)", len
); return; }
3628 if (AddrReply
->vers
!= NATMAP_VERS
) { LogMsg("Received NAT Traversal response with version %d (expected %d)", pkt
[0], NATMAP_VERS
); return; }
3630 // Read multi-byte numeric values (fields are identical in a NATPortMapReply)
3631 AddrReply
->err
= (mDNSu16
) ( (mDNSu16
)pkt
[2] << 8 | pkt
[3]);
3632 AddrReply
->upseconds
= (mDNSs32
) ((mDNSs32
)pkt
[4] << 24 | (mDNSs32
)pkt
[5] << 16 | (mDNSs32
)pkt
[6] << 8 | pkt
[7]);
3634 nat_elapsed
= AddrReply
->upseconds
- m
->LastNATupseconds
;
3635 our_elapsed
= (m
->timenow
- m
->LastNATReplyLocalTime
) / mDNSPlatformOneSecond
;
3636 LogOperation("uDNS_ReceiveNATPMPPacket %X upseconds %u nat_elapsed %d our_elapsed %d", AddrReply
->opcode
, AddrReply
->upseconds
, nat_elapsed
, our_elapsed
);
3638 // We compute a conservative estimate of how much the NAT gateways's clock should have advanced
3639 // 1. We subtract 12.5% from our own measured elapsed time, to allow for NAT gateways that have an inacurate clock that runs slowly
3640 // 2. We add a two-second safety margin to allow for rounding errors:
3641 // -- e.g. if NAT gateway sends a packet at t=2.00 seconds, then one at t=7.99, that's virtually 6 seconds,
3642 // but based on the values in the packet (2,7) the apparent difference is only 5 seconds
3643 // -- similarly, if we're slow handling packets and/or we have coarse clock granularity, we could over-estimate the true interval
3644 // (e.g. t=1.99 seconds rounded to 1, and t=8.01 rounded to 8, gives an apparent difference of 7 seconds)
3645 if (AddrReply
->upseconds
< m
->LastNATupseconds
|| nat_elapsed
+ 2 < our_elapsed
- our_elapsed
/8)
3646 { LogMsg("NAT gateway %#a rebooted", &m
->Router
); RecreateNATMappings(m
); }
3648 m
->LastNATupseconds
= AddrReply
->upseconds
;
3649 m
->LastNATReplyLocalTime
= m
->timenow
;
3650 ClearUPnPState(m
); // We know this is a NAT-PMP base station, so discard any prior UPnP state
3652 if (AddrReply
->opcode
== NATOp_AddrResponse
)
3654 if (!AddrReply
->err
&& len
< sizeof(NATAddrReply
)) { LogMsg("NAT Traversal AddrResponse message too short (%d bytes)", len
); return; }
3655 natTraversalHandleAddressReply(m
, AddrReply
->err
, AddrReply
->ExtAddr
);
3657 else if (AddrReply
->opcode
== NATOp_MapUDPResponse
|| AddrReply
->opcode
== NATOp_MapTCPResponse
)
3659 mDNSu8 Protocol
= AddrReply
->opcode
& 0x7F;
3660 if (!PortMapReply
->err
)
3662 if (len
< sizeof(NATPortMapReply
)) { LogMsg("NAT Traversal PortMapReply message too short (%d bytes)", len
); return; }
3663 PortMapReply
->NATRep_lease
= (mDNSu32
) ((mDNSu32
)pkt
[12] << 24 | (mDNSu32
)pkt
[13] << 16 | (mDNSu32
)pkt
[14] << 8 | pkt
[15]);
3666 for (ptr
= m
->NATTraversals
; ptr
; ptr
=ptr
->next
)
3667 if (ptr
->Protocol
== Protocol
&& mDNSSameIPPort(ptr
->IntPort
, PortMapReply
->intport
))
3668 natTraversalHandlePortMapReply(m
, ptr
, InterfaceID
, PortMapReply
->err
, PortMapReply
->extport
, PortMapReply
->NATRep_lease
);
3670 else { LogMsg("Received NAT Traversal response with version unknown opcode 0x%X", AddrReply
->opcode
); return; }
3672 // Don't need an SSDP socket if we get a NAT-PMP packet
3673 if (m
->SSDPSocket
) { LogOperation("uDNS_ReceiveNATPMPPacket destroying SSDPSocket %p", &m
->SSDPSocket
); mDNSPlatformUDPClose(m
->SSDPSocket
); m
->SSDPSocket
= mDNSNULL
; }
3676 // <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
3677 // <rdar://problem/4288449> Add check to avoid crashing NAT gateways that have buggy DNS relay code
3679 // We know of bugs in home NAT gateways that cause them to crash if they receive certain DNS queries.
3680 // The DNS queries that make them crash are perfectly legal DNS queries, but even if they weren't,
3681 // the gateway shouldn't crash -- in today's world of viruses and network attacks, software has to
3682 // be written assuming that a malicious attacker could send them any packet, properly-formed or not.
3683 // Still, we don't want to be crashing people's home gateways, so we go out of our way to avoid
3684 // the queries that crash them.
3688 // 1. Any query where the name ends in ".in-addr.arpa." and the text before this is 32 or more bytes.
3689 // The query type does not need to be PTR -- the gateway will crash for any query type.
3690 // e.g. "ping long-name-crashes-the-buggy-router.in-addr.arpa" will crash one of these.
3692 // 2. Any query that results in a large response with the TC bit set.
3694 // 3. Any PTR query that doesn't begin with four decimal numbers.
3695 // These gateways appear to assume that the only possible PTR query is a reverse-mapping query
3696 // (e.g. "1.0.168.192.in-addr.arpa") and if they ever get a PTR query where the first four
3697 // labels are not all decimal numbers in the range 0-255, they handle that by crashing.
3698 // These gateways also ignore the remainder of the name following the four decimal numbers
3699 // -- whether or not it actually says in-addr.arpa, they just make up an answer anyway.
3701 // The challenge therefore is to craft a query that will discern whether the DNS server
3702 // is one of these buggy ones, without crashing it. Furthermore we don't want our test
3703 // queries making it all the way to the root name servers, putting extra load on those
3704 // name servers and giving Apple a bad reputation. To this end we send this query:
3705 // dig -t ptr 1.0.0.127.dnsbugtest.1.0.0.127.in-addr.arpa.
3707 // The text preceding the ".in-addr.arpa." is under 32 bytes, so it won't cause crash (1).
3708 // It will not yield a large response with the TC bit set, so it won't cause crash (2).
3709 // It starts with four decimal numbers, so it won't cause crash (3).
3710 // The name falls within the "1.0.0.127.in-addr.arpa." domain, the reverse-mapping name for the local
3711 // loopback address, and therefore the query will black-hole at the first properly-configured DNS server
3712 // it reaches, making it highly unlikely that this query will make it all the way to the root.
3714 // Finally, the correct response to this query is NXDOMAIN or a similar error, but the
3715 // gateways that ignore the remainder of the name following the four decimal numbers
3716 // give themselves away by actually returning a result for this nonsense query.
3718 mDNSlocal
const domainname
*DNSRelayTestQuestion
= (const domainname
*)
3719 "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\xa" "dnsbugtest"
3720 "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\x7" "in-addr" "\x4" "arpa";
3722 // Returns mDNStrue if response was handled
3723 mDNSlocal mDNSBool
uDNS_ReceiveTestQuestionResponse(mDNS
*const m
, DNSMessage
*const msg
, const mDNSu8
*const end
,
3724 const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
)
3726 const mDNSu8
*ptr
= msg
->data
;
3731 // 1. Find out if this is an answer to one of our test questions
3732 if (msg
->h
.numQuestions
!= 1) return(mDNSfalse
);
3733 ptr
= getQuestion(msg
, ptr
, end
, mDNSInterface_Any
, &pktq
);
3734 if (!ptr
) return(mDNSfalse
);
3735 if (pktq
.qtype
!= kDNSType_PTR
|| pktq
.qclass
!= kDNSClass_IN
) return(mDNSfalse
);
3736 if (!SameDomainName(&pktq
.qname
, DNSRelayTestQuestion
)) return(mDNSfalse
);
3738 // 2. If the DNS relay gave us a positive response, then it's got buggy firmware
3739 // else, if the DNS relay gave us an error or no-answer response, it passed our test
3740 if ((msg
->h
.flags
.b
[1] & kDNSFlag1_RC_Mask
) == kDNSFlag1_RC_NoErr
&& msg
->h
.numAnswers
> 0)
3741 result
= DNSServer_Failed
;
3743 result
= DNSServer_Passed
;
3745 // 3. Find occurrences of this server in our list, and mark them appropriately
3746 for (s
= m
->DNSServers
; s
; s
= s
->next
)
3747 if (mDNSSameAddress(srcaddr
, &s
->addr
) && mDNSSameIPPort(srcport
, s
->port
) && s
->teststate
!= result
)
3750 if (s
->teststate
!= result
)
3752 s
->teststate
= result
;
3753 if (result
== DNSServer_Passed
) LogOperation("DNS Server %#a:%d passed", srcaddr
, mDNSVal16(srcport
));
3754 else LogMsg("NOTE: Wide-Area Service Discovery disabled to avoid crashing defective DNS relay %#a:%d", srcaddr
, mDNSVal16(srcport
));
3756 if (result
== DNSServer_Passed
) // Unblock any questions that were waiting for this result
3757 for (q
= m
->Questions
; q
; q
=q
->next
)
3758 if (q
->qDNSServer
== s
)
3759 { q
->LastQTime
= m
->timenow
- q
->ThisQInterval
; m
->NextScheduledQuery
= m
->timenow
; }
3762 return(mDNStrue
); // Return mDNStrue to tell uDNS_ReceiveMsg it doesn't need to process this packet further
3765 // Called from mDNSCoreReceive with the lock held
3766 mDNSexport
void uDNS_ReceiveMsg(mDNS
*const m
, DNSMessage
*const msg
, const mDNSu8
*const end
, const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
)
3769 mStatus err
= mStatus_NoError
;
3771 mDNSu8 StdR
= kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
;
3772 mDNSu8 UpdateR
= kDNSFlag0_QR_Response
| kDNSFlag0_OP_Update
;
3773 mDNSu8 QR_OP
= (mDNSu8
)(msg
->h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
);
3774 mDNSu8 rcode
= (mDNSu8
)(msg
->h
.flags
.b
[1] & kDNSFlag1_RC_Mask
);
3776 (void)srcport
; // Unused
3778 debugf("uDNS_ReceiveMsg from %#-15a with "
3779 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
3781 msg
->h
.numQuestions
, msg
->h
.numQuestions
== 1 ? ", " : "s,",
3782 msg
->h
.numAnswers
, msg
->h
.numAnswers
== 1 ? ", " : "s,",
3783 msg
->h
.numAuthorities
, msg
->h
.numAuthorities
== 1 ? "y, " : "ies,",
3784 msg
->h
.numAdditionals
, msg
->h
.numAdditionals
== 1 ? "" : "s");
3788 //if (srcaddr && recvLLQResponse(m, msg, end, srcaddr, srcport)) return;
3789 if (uDNS_ReceiveTestQuestionResponse(m
, msg
, end
, srcaddr
, srcport
)) return;
3790 for (qptr
= m
->Questions
; qptr
; qptr
= qptr
->next
)
3791 if (msg
->h
.flags
.b
[0] & kDNSFlag0_TC
&& mDNSSameOpaque16(qptr
->TargetQID
, msg
->h
.id
) && m
->timenow
- qptr
->LastQTime
< RESPONSE_WINDOW
)
3793 if (!srcaddr
) LogMsg("uDNS_ReceiveMsg: TCP DNS response had TC bit set: ignoring");
3796 // There may be a race condition here, if the server decides to drop the connection just as we decide to reuse it
3797 // For now it should not be serious because our normal retry logic (as used to handle UDP packet loss)
3798 // should take care of it but later we may want to look at handling this case explicitly
3799 LogOperation("uDNS_ReceiveMsg: Using existing TCP connection for %##s (%s)", qptr
->qname
.c
, DNSTypeName(qptr
->qtype
));
3800 mDNS_DropLockBeforeCallback();
3801 tcpCallback(qptr
->tcp
->sock
, qptr
->tcp
, mDNStrue
, mStatus_NoError
);
3802 mDNS_ReclaimLockAfterCallback();
3804 else qptr
->tcp
= MakeTCPConn(m
, mDNSNULL
, mDNSNULL
, kTCPSocketFlags_Zero
, srcaddr
, srcport
, qptr
, mDNSNULL
, mDNSNULL
);
3808 if (QR_OP
== UpdateR
)
3810 mDNSu32 lease
= GetPktLease(m
, msg
, end
);
3811 mDNSs32 expire
= m
->timenow
+ (mDNSs32
)lease
* mDNSPlatformOneSecond
;
3813 //rcode = kDNSFlag1_RC_SrvErr; // Simulate server failure (rcode 2)
3815 if (CurrentServiceRecordSet
)
3816 LogMsg("uDNS_ReceiveMsg ERROR CurrentServiceRecordSet already set");
3817 CurrentServiceRecordSet
= m
->ServiceRegistrations
;
3819 while (CurrentServiceRecordSet
)
3821 ServiceRecordSet
*sptr
= CurrentServiceRecordSet
;
3822 CurrentServiceRecordSet
= CurrentServiceRecordSet
->uDNS_next
;
3824 if (mDNSSameOpaque16(sptr
->id
, msg
->h
.id
))
3826 err
= checkUpdateResult(m
, sptr
->RR_SRV
.resrec
.name
, rcode
, msg
, end
);
3827 if (!err
&& sptr
->srs_uselease
&& lease
)
3828 if (sptr
->RR_SRV
.expire
- expire
>= 0 || sptr
->state
!= regState_UpdatePending
)
3829 sptr
->RR_SRV
.expire
= expire
;
3830 hndlServiceUpdateReply(m
, sptr
, err
);
3831 CurrentServiceRecordSet
= mDNSNULL
;
3836 if (m
->CurrentRecord
)
3837 LogMsg("uDNS_ReceiveMsg ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
3838 m
->CurrentRecord
= m
->ResourceRecords
;
3839 while (m
->CurrentRecord
)
3841 AuthRecord
*rptr
= m
->CurrentRecord
;
3842 m
->CurrentRecord
= m
->CurrentRecord
->next
;
3843 if (mDNSSameOpaque16(rptr
->id
, msg
->h
.id
))
3845 err
= checkUpdateResult(m
, rptr
->resrec
.name
, rcode
, msg
, end
);
3846 if (!err
&& rptr
->uselease
&& lease
)
3847 if (rptr
->expire
- expire
>= 0 || rptr
->state
!= regState_UpdatePending
)
3848 rptr
->expire
= expire
;
3849 hndlRecordUpdateReply(m
, rptr
, err
);
3850 m
->CurrentRecord
= mDNSNULL
;
3855 debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg
->h
.id
));
3858 // ***************************************************************************
3859 #if COMPILER_LIKES_PRAGMA_MARK
3860 #pragma mark - Query Routines
3863 mDNSexport
void sendLLQRefresh(mDNS
*m
, DNSQuestion
*q
)
3869 if ((q
->state
== LLQ_Established
&& q
->ntries
>= kLLQ_MAX_TRIES
) || q
->expire
- m
->timenow
< 0)
3871 LogMsg("Unable to refresh LLQ %##s (%s) - will retry in %d minutes", q
->qname
.c
, DNSTypeName(q
->qtype
), LLQ_POLL_INTERVAL
/3600);
3872 StartLLQPolling(m
,q
);
3876 llq
.vers
= kLLQ_Vers
;
3877 llq
.llqOp
= kLLQOp_Refresh
;
3878 llq
.err
= q
->tcp
? GetLLQEventPort(m
, &q
->servAddr
) : LLQErr_NoError
; // If using TCP tell server what UDP port to send notifications to
3880 llq
.llqlease
= q
->ReqLease
;
3882 InitializeDNSMessage(&m
->omsg
.h
, q
->TargetQID
, uQueryFlags
);
3883 end
= putLLQ(&m
->omsg
, m
->omsg
.data
, q
, &llq
, mDNStrue
);
3884 if (!end
) { LogMsg("sendLLQRefresh: putLLQ failed %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
)); return; }
3887 DNSDigest_SignMessageHostByteOrder(&m
->omsg
, &end
, q
->AuthInfo
);
3888 if (!end
) { LogMsg("sendLLQRefresh: DNSDigest_SignMessage failed %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
)); return; }
3891 if (q
->AuthInfo
&& !q
->tcp
)
3893 LogOperation("sendLLQRefresh setting up new TLS session %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
3894 q
->tcp
= MakeTCPConn(m
, &m
->omsg
, end
, kTCPSocketFlags_UseTLS
, &q
->servAddr
, q
->servPort
, q
, mDNSNULL
, mDNSNULL
);
3898 mStatus err
= mDNSSendDNSMessage(m
, &m
->omsg
, end
, mDNSInterface_Any
, &q
->servAddr
, q
->servPort
, q
->tcp
? q
->tcp
->sock
: mDNSNULL
, mDNSNULL
);
3901 LogMsg("sendLLQRefresh: mDNSSendDNSMessage%s failed: %d", q
->tcp
? " (TCP)" : "", err
);
3902 if (q
->tcp
) { DisposeTCPConn(q
->tcp
); q
->tcp
= mDNSNULL
; }
3908 debugf("sendLLQRefresh ntries %d %##s (%s)", q
->ntries
, q
->qname
.c
, DNSTypeName(q
->qtype
));
3910 q
->LastQTime
= m
->timenow
;
3911 SetNextQueryTime(m
, q
);
3914 mDNSexport
void LLQGotZoneData(mDNS
*const m
, mStatus err
, const ZoneData
*zoneInfo
)
3916 DNSQuestion
*q
= (DNSQuestion
*)zoneInfo
->ZoneDataContext
;
3920 // If we get here it means that the GetZoneData operation has completed, and is is about to cancel
3921 // its question and free the ZoneData memory. We no longer need to hold onto our pointer (which
3922 // we use for cleaning up if our LLQ is cancelled *before* the GetZoneData operation has completes).
3924 q
->servAddr
= zeroAddr
;
3925 q
->servPort
= zeroIPPort
;
3927 if (!err
&& zoneInfo
&& !mDNSIPPortIsZero(zoneInfo
->Port
) && !mDNSAddressIsZero(&zoneInfo
->Addr
))
3929 q
->servAddr
= zoneInfo
->Addr
;
3930 q
->servPort
= zoneInfo
->Port
;
3931 q
->AuthInfo
= zoneInfo
->ZonePrivate
? GetAuthInfoForName_internal(m
, &q
->qname
) : mDNSNULL
;
3933 LogOperation("LLQGotZoneData %#a:%d", &q
->servAddr
, mDNSVal16(q
->servPort
));
3934 startLLQHandshake(m
, q
);
3937 StartLLQPolling(m
,q
);
3942 // Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
3943 mDNSlocal
void PrivateQueryGotZoneData(mDNS
*const m
, mStatus err
, const ZoneData
*zoneInfo
)
3945 DNSQuestion
*q
= (DNSQuestion
*) zoneInfo
->ZoneDataContext
;
3947 LogOperation("PrivateQueryGotZoneData %##s (%s) err %d Zone %##s Private %d", q
->qname
.c
, DNSTypeName(q
->qtype
), err
, zoneInfo
->ZoneName
.c
, zoneInfo
->ZonePrivate
);
3949 // If we get here it means that the GetZoneData operation has completed, and is is about to cancel
3950 // its question and free the ZoneData memory. We no longer need to hold onto our pointer (which
3951 // we use for cleaning up if our LLQ is cancelled *before* the GetZoneData operation has completes).
3956 LogMsg("ERROR: PrivateQueryGotZoneData %##s (%s) invoked with error code %ld", q
->qname
.c
, DNSTypeName(q
->qtype
), err
);
3960 if (!zoneInfo
->ZonePrivate
)
3962 debugf("Private port lookup failed -- retrying without TLS -- %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
3963 q
->AuthInfo
= mDNSNULL
; // Clear AuthInfo so we try again non-private
3964 q
->ThisQInterval
= InitialQuestionInterval
;
3965 q
->LastQTime
= m
->timenow
- q
->ThisQInterval
;
3967 SetNextQueryTime(m
, q
);
3970 // Next call to uDNS_CheckCurrentQuestion() will do this as a non-private query
3975 LogMsg("ERROR: PrivateQueryGotZoneData: cannot find credentials for q %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
3979 q
->TargetQID
= mDNS_NewMessageID(m
);
3980 if (q
->tcp
) DisposeTCPConn(q
->tcp
);
3981 q
->tcp
= MakeTCPConn(m
, mDNSNULL
, mDNSNULL
, kTCPSocketFlags_UseTLS
, &zoneInfo
->Addr
, zoneInfo
->Port
, q
, mDNSNULL
, mDNSNULL
);
3984 // ***************************************************************************
3985 #if COMPILER_LIKES_PRAGMA_MARK
3986 #pragma mark - Dynamic Updates
3989 // Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
3990 mDNSexport
void RecordRegistrationGotZoneData(mDNS
*const m
, mStatus err
, const ZoneData
*zoneData
)
3992 AuthRecord
*newRR
= (AuthRecord
*)zoneData
->ZoneDataContext
;
3995 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
)
3996 LogMsg("RecordRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
3998 newRR
->nta
= mDNSNULL
;
4000 // Start off assuming we're going to use a lease
4001 // If we get an error from the server, and the update port as given in the SRV record is 53, then we'll retry without the lease option
4002 newRR
->uselease
= mDNStrue
;
4004 // make sure record is still in list (!!!)
4005 for (ptr
= m
->ResourceRecords
; ptr
; ptr
= ptr
->next
) if (ptr
== newRR
) break;
4006 if (!ptr
) { LogMsg("RecordRegistrationGotZoneData - RR no longer in list. Discarding."); return; }
4008 // check error/result
4011 if (err
!= mStatus_NoSuchNameErr
) LogMsg("RecordRegistrationGotZoneData: error %ld", err
);
4015 if (!zoneData
) { LogMsg("ERROR: RecordRegistrationGotZoneData invoked with NULL result and no error"); return; }
4017 if (newRR
->resrec
.rrclass
!= zoneData
->ZoneClass
)
4019 LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)", newRR
->resrec
.rrclass
, zoneData
->ZoneClass
);
4023 // Don't try to do updates to the root name server.
4024 // We might be tempted also to block updates to any single-label name server (e.g. com, edu, net, etc.) but some
4025 // organizations use their own private pseudo-TLD, like ".home", etc, and we don't want to block that.
4026 if (zoneData
->ZoneName
.c
[0] == 0)
4028 LogOperation("RecordRegistrationGotZoneData: No name server found claiming responsibility for \"%##s\"!", newRR
->resrec
.name
->c
);
4032 // Store discovered zone data
4033 AssignDomainName(&newRR
->zone
, &zoneData
->ZoneName
);
4034 newRR
->UpdateServer
= zoneData
->Addr
;
4035 newRR
->UpdatePort
= zoneData
->Port
;
4036 newRR
->Private
= zoneData
->ZonePrivate
;
4037 debugf("RecordRegistrationGotZoneData: Set newRR->UpdateServer %##s %##s to %#a:%d",
4038 newRR
->resrec
.name
->c
, zoneData
->ZoneName
.c
, &newRR
->UpdateServer
, mDNSVal16(newRR
->UpdatePort
));
4040 if (mDNSIPPortIsZero(zoneData
->Port
) || mDNSAddressIsZero(&zoneData
->Addr
))
4042 LogOperation("RecordRegistrationGotZoneData: No _dns-update._udp service found for \"%##s\"!", newRR
->resrec
.name
->c
);
4046 newRR
->ThisAPInterval
= 5 * mDNSPlatformOneSecond
; // After doubling, first retry will happen after ten seconds
4048 mDNS_Lock(m
); // SendRecordRegistration expects to be called with the lock held
4049 SendRecordRegistration(m
, newRR
);
4053 mDNSlocal
void SendRecordDeregistration(mDNS
*m
, AuthRecord
*rr
)
4055 mDNSu8
*ptr
= m
->omsg
.data
;
4056 mDNSu8
*end
= (mDNSu8
*)&m
->omsg
+ sizeof(DNSMessage
);
4058 if (mDNSIPv4AddressIsZero(rr
->UpdateServer
.ip
.v4
)) // Don't know our UpdateServer yet
4060 rr
->LastAPTime
= m
->timenow
;
4061 if (rr
->ThisAPInterval
< mDNSPlatformOneSecond
* 5)
4062 rr
->ThisAPInterval
= mDNSPlatformOneSecond
* 5;
4066 InitializeDNSMessage(&m
->omsg
.h
, rr
->id
, UpdateReqFlags
);
4068 ptr
= putZone(&m
->omsg
, ptr
, end
, &rr
->zone
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
4069 if (ptr
) ptr
= putDeletionRecord(&m
->omsg
, ptr
, &rr
->resrec
);
4072 LogMsg("SendRecordDeregistration Error: could not contruct deregistration packet for %s", ARDisplayString(m
, rr
));
4073 if (rr
->state
== regState_DeregPending
) CompleteDeregistration(m
, rr
);
4077 rr
->expire
= 0; // Indicate that we have no active registration any more
4080 LogOperation("SendRecordDeregistration TCP %p %s", rr
->tcp
, ARDisplayString(m
, rr
));
4081 if (rr
->tcp
) LogOperation("SendRecordDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m
, rr
));
4082 if (rr
->tcp
) DisposeTCPConn(rr
->tcp
);
4083 rr
->tcp
= MakeTCPConn(m
, &m
->omsg
, ptr
, kTCPSocketFlags_UseTLS
, &rr
->UpdateServer
, rr
->UpdatePort
, mDNSNULL
, mDNSNULL
, rr
);
4084 if (!rr
->tcp
) rr
->ThisAPInterval
= mDNSPlatformOneSecond
* 5; // If failed to make TCP connection, try again in ten seconds (5*2)
4085 else if (rr
->ThisAPInterval
< mDNSPlatformOneSecond
* 30) rr
->ThisAPInterval
= mDNSPlatformOneSecond
* 30;
4086 SetRecordRetry(m
, rr
, mStatus_NoError
);
4090 mStatus err
= mDNSSendDNSMessage(m
, &m
->omsg
, ptr
, mDNSInterface_Any
, &rr
->UpdateServer
, rr
->UpdatePort
, mDNSNULL
, GetAuthInfoForName_internal(m
, rr
->resrec
.name
));
4091 if (err
) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %ld", err
);
4092 if (rr
->state
== regState_DeregPending
) CompleteDeregistration(m
, rr
); // Don't touch rr after this
4097 mDNSexport mStatus
uDNS_DeregisterRecord(mDNS
*const m
, AuthRecord
*const rr
)
4101 case regState_NATMap
: LogMsg("regState_NATMap %##s type %s", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
)); return mStatus_NoError
;
4102 case regState_ExtraQueued
: rr
->state
= regState_Unregistered
; break;
4103 case regState_Refresh
:
4104 case regState_Pending
:
4105 case regState_UpdatePending
:
4106 case regState_FetchingZoneData
:
4107 case regState_Registered
: break;
4108 case regState_DeregPending
: break;
4109 case regState_DeregDeferred
: LogMsg("regState_DeregDeferred %##s type %s", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
)); return mStatus_NoError
;
4110 case regState_Unregistered
: LogMsg("regState_Unregistered %##s type %s", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
)); return mStatus_NoError
;
4111 case regState_NATError
: LogMsg("regState_NATError %##s type %s", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
)); return mStatus_NoError
;
4112 case regState_NoTarget
: LogMsg("regState_NoTarget %##s type %s", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
)); return mStatus_NoError
;
4113 default: LogMsg("uDNS_DeregisterRecord: State %d for %##s type %s", rr
->state
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
)); return mStatus_NoError
;
4116 if (rr
->state
!= regState_Unregistered
) { rr
->state
= regState_DeregPending
; SendRecordDeregistration(m
, rr
); }
4117 return mStatus_NoError
;
4120 // Called with lock held
4121 mDNSexport mStatus
uDNS_DeregisterService(mDNS
*const m
, ServiceRecordSet
*srs
)
4123 char *errmsg
= "Unknown State";
4125 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
4126 LogMsg("uDNS_DeregisterService: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
4128 // don't re-register with a new target following deregistration
4129 srs
->SRVChanged
= srs
->SRVUpdateDeferred
= mDNSfalse
;
4131 if (srs
->nta
) { CancelGetZoneData(m
, srs
->nta
); srs
->nta
= mDNSNULL
; }
4133 if (srs
->NATinfo
.clientContext
)
4135 mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
4136 srs
->NATinfo
.clientContext
= mDNSNULL
;
4141 case regState_Unregistered
:
4142 debugf("uDNS_DeregisterService - service %##s not registered", srs
->RR_SRV
.resrec
.name
->c
);
4143 return mStatus_BadReferenceErr
;
4144 case regState_DeregPending
:
4145 case regState_DeregDeferred
:
4146 debugf("Double deregistration of service %##s", srs
->RR_SRV
.resrec
.name
->c
);
4147 return mStatus_NoError
;
4148 case regState_NATError
: // not registered
4149 case regState_NATMap
: // not registered
4150 case regState_NoTarget
: // not registered
4152 srs
->state
= regState_Unregistered
;
4153 mDNS_DropLockBeforeCallback();
4154 srs
->ServiceCallback(m
, srs
, mStatus_MemFree
);
4155 mDNS_ReclaimLockAfterCallback();
4156 return mStatus_NoError
;
4157 case regState_Pending
:
4158 case regState_Refresh
:
4159 case regState_UpdatePending
:
4160 case regState_FetchingZoneData
:
4161 case regState_Registered
:
4162 srs
->state
= regState_DeregPending
;
4163 SendServiceDeregistration(m
, srs
);
4164 return mStatus_NoError
;
4165 case regState_ExtraQueued
: // only for record registrations
4166 errmsg
= "bad state (regState_ExtraQueued)";
4168 default: LogMsg("uDNS_DeregisterService: Unknown state %d for %##s", srs
->state
, srs
->RR_SRV
.resrec
.name
->c
);
4172 LogMsg("Error, uDNS_DeregisterService: %s", errmsg
);
4173 return mStatus_BadReferenceErr
;
4176 mDNSexport mStatus
uDNS_UpdateRecord(mDNS
*m
, AuthRecord
*rr
)
4178 ServiceRecordSet
*parent
= mDNSNULL
;
4180 regState_t
*stateptr
= mDNSNULL
;
4182 // find the record in registered service list
4183 for (parent
= m
->ServiceRegistrations
; parent
; parent
= parent
->uDNS_next
)
4184 if (&parent
->RR_TXT
== rr
) { stateptr
= &parent
->state
; break; }
4188 // record not part of a service - check individual record registrations
4189 for (rptr
= m
->ResourceRecords
; rptr
; rptr
= rptr
->next
)
4190 if (rptr
== rr
) { stateptr
= &rr
->state
; break; }
4191 if (!rptr
) goto unreg_error
;
4196 case regState_DeregPending
:
4197 case regState_DeregDeferred
:
4198 case regState_Unregistered
:
4199 // not actively registered
4202 case regState_FetchingZoneData
:
4203 case regState_NATMap
:
4204 case regState_ExtraQueued
:
4205 case regState_NoTarget
:
4206 // change rdata directly since it hasn't been sent yet
4207 if (rr
->UpdateCallback
) rr
->UpdateCallback(m
, rr
, rr
->resrec
.rdata
);
4208 SetNewRData(&rr
->resrec
, rr
->NewRData
, rr
->newrdlength
);
4209 rr
->NewRData
= mDNSNULL
;
4210 return mStatus_NoError
;
4212 case regState_Pending
:
4213 case regState_Refresh
:
4214 case regState_UpdatePending
:
4215 // registration in-flight. queue rdata and return
4216 if (rr
->QueuedRData
&& rr
->UpdateCallback
)
4217 // if unsent rdata is already queued, free it before we replace it
4218 rr
->UpdateCallback(m
, rr
, rr
->QueuedRData
);
4219 rr
->QueuedRData
= rr
->NewRData
;
4220 rr
->QueuedRDLen
= rr
->newrdlength
;
4221 rr
->NewRData
= mDNSNULL
;
4222 return mStatus_NoError
;
4224 case regState_Registered
:
4225 rr
->OrigRData
= rr
->resrec
.rdata
;
4226 rr
->OrigRDLen
= rr
->resrec
.rdlength
;
4227 rr
->InFlightRData
= rr
->NewRData
;
4228 rr
->InFlightRDLen
= rr
->newrdlength
;
4229 rr
->NewRData
= mDNSNULL
;
4230 *stateptr
= regState_UpdatePending
;
4231 if (parent
) SendServiceRegistration(m
, parent
);
4232 else SendRecordRegistration(m
, rr
);
4233 return mStatus_NoError
;
4235 case regState_NATError
:
4236 LogMsg("ERROR: uDNS_UpdateRecord called for record %##s with bad state regState_NATError", rr
->resrec
.name
->c
);
4237 return mStatus_UnknownErr
; // states for service records only
4239 default: LogMsg("uDNS_UpdateRecord: Unknown state %d for %##s", *stateptr
, rr
->resrec
.name
->c
);
4243 LogMsg("Requested update of record %##s type %d, part of service not currently registered",
4244 rr
->resrec
.name
->c
, rr
->resrec
.rrtype
);
4245 return mStatus_Invalid
;
4248 // ***************************************************************************
4249 #if COMPILER_LIKES_PRAGMA_MARK
4250 #pragma mark - Periodic Execution Routines
4253 // See comments above for DNSRelayTestQuestion
4254 // If this is the kind of query that has the risk of crashing buggy DNS servers, we do a test question first
4255 mDNSlocal mDNSBool
NoTestQuery(DNSQuestion
*q
)
4258 mDNSu8
*p
= q
->qname
.c
;
4259 if (q
->AuthInfo
) return(mDNStrue
); // Don't need a test query for private queries sent directly to authoritative server over TLS/TCP
4260 if (q
->qtype
!= kDNSType_PTR
) return(mDNStrue
); // Don't need a test query for any non-PTR queries
4261 for (i
=0; i
<4; i
++) // If qname does not begin with num.num.num.num, can't skip the test query
4263 if (p
[0] < 1 || p
[0] > 3) return(mDNSfalse
);
4264 if ( p
[1] < '0' || p
[1] > '9' ) return(mDNSfalse
);
4265 if (p
[0] >= 2 && (p
[2] < '0' || p
[2] > '9')) return(mDNSfalse
);
4266 if (p
[0] >= 3 && (p
[3] < '0' || p
[3] > '9')) return(mDNSfalse
);
4269 // If remainder of qname is ".in-addr.arpa.", this is a vanilla reverse-mapping query and
4270 // we can safely do it without needing a test query first, otherwise we need the test query.
4271 return(SameDomainName((domainname
*)p
, (const domainname
*)"\x7" "in-addr" "\x4" "arpa"));
4274 // The question to be checked is not passed in as an explicit parameter;
4275 // instead it is implicit that the question to be checked is m->CurrentQuestion.
4276 mDNSexport
void uDNS_CheckCurrentQuestion(mDNS
*const m
)
4278 DNSQuestion
*q
= m
->CurrentQuestion
;
4279 mDNSs32 sendtime
= q
->LastQTime
+ q
->ThisQInterval
;
4280 // Don't allow sendtime to be earlier than SuppressStdPort53Queries
4281 if (!q
->LongLived
&& m
->SuppressStdPort53Queries
&& sendtime
- m
->SuppressStdPort53Queries
< 0)
4282 sendtime
= m
->SuppressStdPort53Queries
;
4283 if (m
->timenow
- sendtime
< 0) return;
4289 case LLQ_InitialRequest
: startLLQHandshake(m
, q
); break;
4290 case LLQ_SecondaryRequest
: sendChallengeResponse(m
, q
, mDNSNULL
); break;
4291 case LLQ_Established
: sendLLQRefresh(m
, q
); break;
4292 case LLQ_Poll
: break; // Do nothing (handled below)
4296 // We repeat the check above (rather than just making this the "else" case) because startLLQHandshake can change q->state to LLQ_Poll
4297 if (!(q
->LongLived
&& q
->state
!= LLQ_Poll
))
4299 if (q
->qDNSServer
&& q
->qDNSServer
->teststate
!= DNSServer_Disabled
)
4301 mDNSu8
*end
= m
->omsg
.data
;
4302 mStatus err
= mStatus_NoError
;
4303 DomainAuthInfo
*private = mDNSNULL
;
4305 if (q
->qDNSServer
->teststate
!= DNSServer_Untested
|| NoTestQuery(q
))
4307 InitializeDNSMessage(&m
->omsg
.h
, q
->TargetQID
, uQueryFlags
);
4308 end
= putQuestion(&m
->omsg
, m
->omsg
.data
, m
->omsg
.data
+ AbsoluteMaxDNSMessageData
, &q
->qname
, q
->qtype
, q
->qclass
);
4309 private = q
->AuthInfo
;
4311 else if (m
->timenow
- q
->qDNSServer
->lasttest
>= INIT_UCAST_POLL_INTERVAL
) // Make sure at least three seconds has elapsed since last test query
4313 LogOperation("Sending DNS test query to %#a:%d", &q
->qDNSServer
->addr
, mDNSVal16(q
->qDNSServer
->port
));
4314 q
->ThisQInterval
= INIT_UCAST_POLL_INTERVAL
/ QuestionIntervalStep
;
4315 q
->qDNSServer
->lasttest
= m
->timenow
;
4316 InitializeDNSMessage(&m
->omsg
.h
, mDNS_NewMessageID(m
), uQueryFlags
);
4317 end
= putQuestion(&m
->omsg
, m
->omsg
.data
, m
->omsg
.data
+ AbsoluteMaxDNSMessageData
, DNSRelayTestQuestion
, kDNSType_PTR
, kDNSClass_IN
);
4320 if (end
> m
->omsg
.data
&& (q
->qDNSServer
->teststate
!= DNSServer_Failed
|| NoTestQuery(q
)))
4322 //LogMsg("uDNS_CheckCurrentQuestion %d %p %##s (%s)", sendtime - m->timenow, private, q->qname.c, DNSTypeName(q->qtype));
4325 if (q
->nta
) CancelGetZoneData(m
, q
->nta
);
4326 q
->nta
= StartGetZoneData(m
, &q
->qname
, q
->LongLived
? ZoneServiceLLQ
: ZoneServiceQuery
, PrivateQueryGotZoneData
, q
);
4327 q
->ThisQInterval
= (LLQ_POLL_INTERVAL
+ mDNSRandom(LLQ_POLL_INTERVAL
/10)) / QuestionIntervalStep
;
4331 err
= mDNSSendDNSMessage(m
, &m
->omsg
, end
, q
->qDNSServer
->interface
, &q
->qDNSServer
->addr
, q
->qDNSServer
->port
, mDNSNULL
, mDNSNULL
);
4332 m
->SuppressStdPort53Queries
= NonZeroTime(m
->timenow
+ (mDNSPlatformOneSecond
+99)/100);
4336 if (err
) debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %ld", err
); // surpress syslog messages if we have no network
4339 q
->ThisQInterval
= q
->ThisQInterval
* QuestionIntervalStep
; // Only increase interval if send succeeded
4340 if (q
->ThisQInterval
> MAX_UCAST_POLL_INTERVAL
)
4341 q
->ThisQInterval
= MAX_UCAST_POLL_INTERVAL
;
4342 LogOperation("Increased ThisQInterval to %d for %##s (%s)", q
->ThisQInterval
, q
->qname
.c
, DNSTypeName(q
->qtype
));
4344 q
->LastQTime
= m
->timenow
;
4345 SetNextQueryTime(m
, q
);
4349 // If we have no server for this query, or the only server is a disabled one, then we deliver
4350 // a transient failure indication to the client. This is important for things like iPhone
4351 // where we want to return timely feedback to the user when no network is available.
4352 // After calling MakeNegativeCacheRecord() we store the resulting record in the
4353 // cache so that it will be visible to other clients asking the same question.
4354 // (When we have a group of identical questions, only the active representative of the group gets
4355 // passed to uDNS_CheckCurrentQuestion -- we only want one set of query packets hitting the wire --
4356 // but we want *all* of the questions to get answer callbacks.)
4359 const mDNSu32 slot
= HashSlot(&q
->qname
);
4360 CacheGroup
*const cg
= CacheGroupForName(m
, slot
, q
->qnamehash
, &q
->qname
);
4362 for (rr
= cg
->members
; rr
; rr
=rr
->next
)
4363 if (SameNameRecordAnswersQuestion(&rr
->resrec
, q
)) mDNS_PurgeCacheResourceRecord(m
, rr
);
4365 if (!q
->qDNSServer
) LogOperation("uDNS_CheckCurrentQuestion no DNS server for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4366 else LogMsg("uDNS_CheckCurrentQuestion DNS server %#a:%d for %##s is disabled", &q
->qDNSServer
->addr
, mDNSVal16(q
->qDNSServer
->port
), q
->qname
.c
);
4368 MakeNegativeCacheRecord(m
, &q
->qname
, q
->qnamehash
, q
->qtype
, q
->qclass
, 60);
4369 // Inactivate this question until the next change of DNS servers (do this before AnswerCurrentQuestionWithResourceRecord)
4370 q
->ThisQInterval
= 0;
4371 CreateNewCacheEntry(m
, slot
, cg
);
4372 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
4373 // MUST NOT touch m->CurrentQuestion (or q) after this -- client callback could have deleted it
4378 mDNSlocal
void CheckNATMappings(mDNS
*m
)
4380 mStatus err
= mStatus_NoError
;
4381 mDNSBool rfc1918
= mDNSv4AddrIsRFC1918(&m
->AdvertisedV4
.ip
.v4
);
4382 mDNSBool HaveRoutable
= !rfc1918
&& !mDNSIPv4AddressIsZero(m
->AdvertisedV4
.ip
.v4
);
4383 m
->NextScheduledNATOp
= m
->timenow
+ 0x3FFFFFFF;
4385 if (HaveRoutable
) m
->ExternalAddress
= m
->AdvertisedV4
.ip
.v4
;
4387 if (m
->NATTraversals
&& rfc1918
) // Do we need to open NAT-PMP socket to receive multicast announcements from router?
4389 if (m
->NATMcastRecvskt
== mDNSNULL
) // If we are behind a NAT and the socket hasn't been opened yet, open it
4391 m
->NATMcastRecvskt
= mDNSPlatformUDPSocket(m
, NATPMPAnnouncementPort
);
4392 m
->NATMcastRecvsk2
= mDNSPlatformUDPSocket(m
, NATPMPPort
); // For backwards compatibility with older base stations that announce on 5351
4393 if (!m
->NATMcastRecvskt
) LogMsg("CheckNATMappings: Failed to allocate port 5350 UDP multicast socket for NAT-PMP announcements");
4394 if (!m
->NATMcastRecvsk2
) LogOperation("CheckNATMappings: Failed to allocate port 5351 UDP multicast socket for NAT-PMP announcements");
4397 else // else, we don't want to listen for announcements, so close them if they're open
4399 if (m
->NATMcastRecvskt
) { mDNSPlatformUDPClose(m
->NATMcastRecvskt
); m
->NATMcastRecvskt
= mDNSNULL
; }
4400 if (m
->NATMcastRecvsk2
) { mDNSPlatformUDPClose(m
->NATMcastRecvsk2
); m
->NATMcastRecvsk2
= mDNSNULL
; }
4401 if (m
->SSDPSocket
) { LogOperation("CheckNATMappings destroying SSDPSocket %p", &m
->SSDPSocket
); mDNSPlatformUDPClose(m
->SSDPSocket
); m
->SSDPSocket
= mDNSNULL
; }
4404 if (m
->NATTraversals
)
4406 if (m
->timenow
- m
->retryGetAddr
>= 0)
4408 err
= uDNS_SendNATMsg(m
, mDNSNULL
); // Will also do UPnP discovery for us, if necessary
4411 if (m
->retryIntervalGetAddr
< NATMAP_INIT_RETRY
) m
->retryIntervalGetAddr
= NATMAP_INIT_RETRY
;
4412 else if (m
->retryIntervalGetAddr
< NATMAP_MAX_RETRY_INTERVAL
/ 2) m
->retryIntervalGetAddr
*= 2;
4413 else m
->retryIntervalGetAddr
= NATMAP_MAX_RETRY_INTERVAL
;
4415 // Always update m->retryGetAddr, even if we fail to send the packet. Otherwise in cases where we can't send the packet
4416 // (like when we have no active interfaces) we'll spin in an infinite loop repeatedly failing to send the packet
4417 m
->retryGetAddr
= m
->timenow
+ m
->retryIntervalGetAddr
;
4419 // Even when we didn't send the GetAddr packet, still need to make sure NextScheduledNATOp is set correctly
4420 if (m
->NextScheduledNATOp
- m
->retryGetAddr
> 0)
4421 m
->NextScheduledNATOp
= m
->retryGetAddr
;
4424 if (m
->CurrentNATTraversal
) LogMsg("WARNING m->CurrentNATTraversal already in use");
4425 m
->CurrentNATTraversal
= m
->NATTraversals
;
4427 while (m
->CurrentNATTraversal
)
4429 NATTraversalInfo
*cur
= m
->CurrentNATTraversal
;
4430 m
->CurrentNATTraversal
= m
->CurrentNATTraversal
->next
;
4432 if (HaveRoutable
) // If not RFC 1918 address, our own address and port are effectively our external address and port
4434 cur
->ExpiryTime
= 0;
4435 cur
->NewResult
= mStatus_NoError
;
4437 else if (cur
->Protocol
) // Check if it's time to send port mapping packets
4439 if (m
->timenow
- cur
->retryPortMap
>= 0) // Time to do something with this mapping
4441 if (cur
->ExpiryTime
&& cur
->ExpiryTime
- m
->timenow
< 0) // Mapping has expired
4443 cur
->ExpiryTime
= 0;
4444 cur
->retryInterval
= NATMAP_INIT_RETRY
;
4447 //LogMsg("uDNS_SendNATMsg");
4448 err
= uDNS_SendNATMsg(m
, cur
);
4450 if (cur
->ExpiryTime
) // If have active mapping then set next renewal time halfway to expiry
4451 NATSetNextRenewalTime(m
, cur
);
4452 else // else no mapping; use exponential backoff sequence
4454 if (cur
->retryInterval
< NATMAP_INIT_RETRY
) cur
->retryInterval
= NATMAP_INIT_RETRY
;
4455 else if (cur
->retryInterval
< NATMAP_MAX_RETRY_INTERVAL
/ 2) cur
->retryInterval
*= 2;
4456 else cur
->retryInterval
= NATMAP_MAX_RETRY_INTERVAL
;
4457 cur
->retryPortMap
= m
->timenow
+ cur
->retryInterval
;
4461 if (m
->NextScheduledNATOp
- cur
->retryPortMap
> 0)
4462 m
->NextScheduledNATOp
= cur
->retryPortMap
;
4465 // Notify the client if necessary. We invoke the callback if:
4466 // (1) we have an ExternalAddress, or we've tried and failed a couple of times to discover it
4467 // 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
4468 // and (3) we have new data to give the client that's changed since the last callback
4469 if (!mDNSIPv4AddressIsZero(m
->ExternalAddress
) || m
->retryIntervalGetAddr
> NATMAP_INIT_RETRY
* 8)
4471 const mDNSIPPort ExternalPort
= HaveRoutable
? cur
->IntPort
:
4472 !mDNSIPv4AddressIsZero(m
->ExternalAddress
) && cur
->ExpiryTime
? cur
->RequestedPort
: zeroIPPort
;
4473 if (!cur
->Protocol
|| HaveRoutable
|| cur
->ExpiryTime
|| cur
->retryInterval
> NATMAP_INIT_RETRY
* 8)
4474 if (!mDNSSameIPv4Address(cur
->ExternalAddress
, m
->ExternalAddress
) ||
4475 !mDNSSameIPPort (cur
->ExternalPort
, ExternalPort
) ||
4476 cur
->Result
!= cur
->NewResult
)
4478 //LogMsg("NAT callback %d %d %d", cur->Protocol, cur->ExpiryTime, cur->retryInterval);
4479 if (cur
->Protocol
&& mDNSIPPortIsZero(ExternalPort
) && !mDNSIPv4AddressIsZero(m
->Router
.ip
.v4
))
4480 LogMsg("Failed to obtain NAT port mapping from router %#a external address %.4a internal port %d",
4481 &m
->Router
, &m
->ExternalAddress
, mDNSVal16(cur
->IntPort
));
4482 cur
->ExternalAddress
= m
->ExternalAddress
;
4483 cur
->ExternalPort
= ExternalPort
;
4484 cur
->Lifetime
= cur
->ExpiryTime
&& !mDNSIPPortIsZero(ExternalPort
) ?
4485 (cur
->ExpiryTime
- m
->timenow
+ mDNSPlatformOneSecond
/2) / mDNSPlatformOneSecond
: 0;
4486 cur
->Result
= cur
->NewResult
;
4487 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
4488 if (cur
->clientCallback
)
4489 cur
->clientCallback(m
, cur
);
4490 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
4491 // MUST NOT touch cur after invoking the callback
4497 mDNSlocal mDNSs32
CheckRecordRegistrations(mDNS
*m
)
4500 mDNSs32 nextevent
= m
->timenow
+ 0x3FFFFFFF;
4502 for (rr
= m
->ResourceRecords
; rr
; rr
= rr
->next
)
4504 if (rr
->state
== regState_FetchingZoneData
||
4505 rr
->state
== regState_Pending
|| rr
->state
== regState_DeregPending
|| rr
->state
== regState_UpdatePending
||
4506 rr
->state
== regState_DeregDeferred
|| rr
->state
== regState_Refresh
|| rr
->state
== regState_Registered
)
4508 if (rr
->LastAPTime
+ rr
->ThisAPInterval
- m
->timenow
< 0)
4510 if (rr
->tcp
) { DisposeTCPConn(rr
->tcp
); rr
->tcp
= mDNSNULL
; }
4511 if (rr
->state
== regState_FetchingZoneData
)
4513 if (rr
->nta
) CancelGetZoneData(m
, rr
->nta
);
4514 rr
->nta
= StartGetZoneData(m
, rr
->resrec
.name
, ZoneServiceUpdate
, RecordRegistrationGotZoneData
, rr
);
4515 SetRecordRetry(m
, rr
, mStatus_NoError
);
4517 else if (rr
->state
== regState_DeregPending
) SendRecordDeregistration(m
, rr
);
4518 else SendRecordRegistration(m
, rr
);
4520 if (nextevent
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) > 0)
4521 nextevent
= (rr
->LastAPTime
+ rr
->ThisAPInterval
);
4527 mDNSlocal mDNSs32
CheckServiceRegistrations(mDNS
*m
)
4529 mDNSs32 nextevent
= m
->timenow
+ 0x3FFFFFFF;
4531 if (CurrentServiceRecordSet
)
4532 LogMsg("CheckServiceRegistrations ERROR CurrentServiceRecordSet already set");
4533 CurrentServiceRecordSet
= m
->ServiceRegistrations
;
4535 // Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery
4536 while (CurrentServiceRecordSet
)
4538 ServiceRecordSet
*srs
= CurrentServiceRecordSet
;
4539 CurrentServiceRecordSet
= CurrentServiceRecordSet
->uDNS_next
;
4540 if (srs
->state
== regState_FetchingZoneData
||
4541 srs
->state
== regState_Pending
|| srs
->state
== regState_DeregPending
|| srs
->state
== regState_DeregDeferred
||
4542 srs
->state
== regState_Refresh
|| srs
->state
== regState_UpdatePending
|| srs
->state
== regState_Registered
)
4544 if (srs
->RR_SRV
.LastAPTime
+ srs
->RR_SRV
.ThisAPInterval
- m
->timenow
<= 0)
4546 if (srs
->tcp
) { DisposeTCPConn(srs
->tcp
); srs
->tcp
= mDNSNULL
; }
4547 if (srs
->state
== regState_FetchingZoneData
)
4549 if (srs
->nta
) CancelGetZoneData(m
, srs
->nta
);
4550 srs
->nta
= StartGetZoneData(m
, srs
->RR_SRV
.resrec
.name
, ZoneServiceUpdate
, ServiceRegistrationGotZoneData
, srs
);
4551 SetRecordRetry(m
, &srs
->RR_SRV
, mStatus_NoError
);
4553 else if (srs
->state
== regState_DeregPending
) SendServiceDeregistration(m
, srs
);
4554 else SendServiceRegistration(m
, srs
);
4556 if (nextevent
- (srs
->RR_SRV
.LastAPTime
+ srs
->RR_SRV
.ThisAPInterval
) > 0)
4557 nextevent
= (srs
->RR_SRV
.LastAPTime
+ srs
->RR_SRV
.ThisAPInterval
);
4563 mDNSexport
void uDNS_Execute(mDNS
*const m
)
4567 m
->NextuDNSEvent
= m
->timenow
+ 0x3FFFFFFF;
4569 if (m
->NextSRVUpdate
&& m
->NextSRVUpdate
- m
->timenow
< 0)
4570 { m
->NextSRVUpdate
= 0; UpdateSRVRecords(m
); }
4572 CheckNATMappings(m
);
4574 if (m
->SuppressStdPort53Queries
&& m
->timenow
- m
->SuppressStdPort53Queries
>= 0)
4575 m
->SuppressStdPort53Queries
= 0; // If suppression time has passed, clear it
4577 nexte
= CheckRecordRegistrations(m
);
4578 if (nexte
- m
->NextuDNSEvent
< 0) m
->NextuDNSEvent
= nexte
;
4580 nexte
= CheckServiceRegistrations(m
);
4581 if (nexte
- m
->NextuDNSEvent
< 0) m
->NextuDNSEvent
= nexte
;
4584 // ***************************************************************************
4585 #if COMPILER_LIKES_PRAGMA_MARK
4586 #pragma mark - Startup, Shutdown, and Sleep
4589 // simplest sleep logic - rather than having sleep states that must be dealt with explicitly in all parts of
4590 // the code, we simply send a deregistration, and put the service in Refresh state, with a timeout far enough
4591 // in the future that we'll sleep (or the sleep will be cancelled) before it is retransmitted. Then to wake,
4592 // we just move up the timers.
4594 mDNSexport
void SleepRecordRegistrations(mDNS
*m
)
4597 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
4598 if (AuthRecord_uDNS(rr
))
4599 if (rr
->state
== regState_Registered
||
4600 rr
->state
== regState_Refresh
)
4602 SendRecordDeregistration(m
, rr
);
4603 rr
->state
= regState_Refresh
;
4604 rr
->LastAPTime
= m
->timenow
;
4605 rr
->ThisAPInterval
= 300 * mDNSPlatformOneSecond
;
4609 mDNSexport
void SleepServiceRegistrations(mDNS
*m
)
4611 ServiceRecordSet
*srs
= m
->ServiceRegistrations
;
4614 LogOperation("SleepServiceRegistrations: state %d %s", srs
->state
, ARDisplayString(m
, &srs
->RR_SRV
));
4615 if (srs
->nta
) { CancelGetZoneData(m
, srs
->nta
); srs
->nta
= mDNSNULL
; }
4617 if (srs
->NATinfo
.clientContext
)
4619 mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
4620 srs
->NATinfo
.clientContext
= mDNSNULL
;
4623 if (srs
->state
== regState_UpdatePending
)
4625 // act as if the update succeeded, since we're about to delete the name anyway
4626 AuthRecord
*txt
= &srs
->RR_TXT
;
4627 srs
->state
= regState_Registered
;
4628 // deallocate old RData
4629 if (txt
->UpdateCallback
) txt
->UpdateCallback(m
, txt
, txt
->OrigRData
);
4630 SetNewRData(&txt
->resrec
, txt
->InFlightRData
, txt
->InFlightRDLen
);
4631 txt
->OrigRData
= mDNSNULL
;
4632 txt
->InFlightRData
= mDNSNULL
;
4635 if (srs
->state
== regState_Registered
|| srs
->state
== regState_Refresh
)
4636 SendServiceDeregistration(m
, srs
);
4638 srs
->state
= regState_NoTarget
; // when we wake, we'll re-register (and optionally nat-map) once our address record completes
4639 srs
->RR_SRV
.resrec
.rdata
->u
.srv
.target
.c
[0] = 0;
4640 srs
->SRSUpdateServer
= zeroAddr
; // This will cause UpdateSRV to do a new StartGetZoneData
4641 srs
->RR_SRV
.ThisAPInterval
= 5 * mDNSPlatformOneSecond
; // After doubling, first retry will happen after ten seconds
4643 srs
= srs
->uDNS_next
;
4647 mDNSexport
void mDNS_AddSearchDomain(const domainname
*const domain
)
4651 // Check to see if we already have this domain in our list
4652 for (p
= &SearchList
; *p
; p
= &(*p
)->next
)
4653 if (SameDomainName(&(*p
)->domain
, domain
))
4655 // If domain is already in list, and marked for deletion, change it to "leave alone"
4656 if ((*p
)->flag
== -1) (*p
)->flag
= 0;
4657 LogOperation("mDNS_AddSearchDomain already in list %##s", domain
->c
);
4661 // if domain not in list, add to list, mark as add (1)
4662 *p
= mDNSPlatformMemAllocate(sizeof(SearchListElem
));
4663 if (!*p
) { LogMsg("ERROR: mDNS_AddSearchDomain - malloc"); return; }
4664 mDNSPlatformMemZero(*p
, sizeof(SearchListElem
));
4665 AssignDomainName(&(*p
)->domain
, domain
);
4666 (*p
)->flag
= 1; // add
4667 (*p
)->next
= mDNSNULL
;
4668 LogOperation("mDNS_AddSearchDomain created new %##s", domain
->c
);
4671 mDNSlocal
void FreeARElemCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
4674 if (result
== mStatus_MemFree
) mDNSPlatformMemFree(rr
->RecordContext
);
4677 mDNSlocal
void FoundDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
4679 SearchListElem
*slElem
= question
->QuestionContext
;
4682 if (answer
->rrtype
!= kDNSType_PTR
) return;
4683 if (answer
->RecordType
== kDNSRecordTypePacketNegative
) return;
4688 ARListElem
*arElem
= mDNSPlatformMemAllocate(sizeof(ARListElem
));
4689 if (!arElem
) { LogMsg("ERROR: malloc"); return; }
4690 mDNS_SetupResourceRecord(&arElem
->ar
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, FreeARElemCallback
, arElem
);
4691 if (question
== &slElem
->BrowseQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeBrowse
];
4692 else if (question
== &slElem
->DefBrowseQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeBrowseDefault
];
4693 else if (question
== &slElem
->AutomaticBrowseQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeBrowseAutomatic
];
4694 else if (question
== &slElem
->RegisterQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeRegistration
];
4695 else if (question
== &slElem
->DefRegisterQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeRegistrationDefault
];
4696 else { LogMsg("FoundDomain - unknown question"); mDNSPlatformMemFree(arElem
); return; }
4698 MakeDomainNameFromDNSNameString(&arElem
->ar
.namestorage
, name
);
4699 AppendDNSNameString (&arElem
->ar
.namestorage
, "local");
4700 AssignDomainName(&arElem
->ar
.resrec
.rdata
->u
.name
, &answer
->rdata
->u
.name
);
4701 err
= mDNS_Register(m
, &arElem
->ar
);
4702 if (err
) { LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err
); mDNSPlatformMemFree(arElem
); return; }
4703 arElem
->next
= slElem
->AuthRecs
;
4704 slElem
->AuthRecs
= arElem
;
4708 ARListElem
**ptr
= &slElem
->AuthRecs
;
4711 if (SameDomainName(&(*ptr
)->ar
.resrec
.rdata
->u
.name
, &answer
->rdata
->u
.name
))
4713 ARListElem
*dereg
= *ptr
;
4714 *ptr
= (*ptr
)->next
;
4715 debugf("Deregistering PTR %##s -> %##s", dereg
->ar
.resrec
.name
->c
, dereg
->ar
.resrec
.rdata
->u
.name
.c
);
4716 err
= mDNS_Deregister(m
, &dereg
->ar
);
4717 if (err
) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err
);
4718 // Memory will be freed in the FreeARElemCallback
4721 ptr
= &(*ptr
)->next
;
4726 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
4727 mDNSexport
void udns_validatelists(void *const v
)
4731 ServiceRecordSet
*s
;
4732 for (s
= m
->ServiceRegistrations
; s
; s
=s
->uDNS_next
)
4733 if (s
->uDNS_next
== (ServiceRecordSet
*)~0)
4734 LogMemCorruption("m->ServiceRegistrations: %p is garbage (%lX)", s
, s
->uDNS_next
);
4736 NATTraversalInfo
*n
;
4737 for (n
= m
->NATTraversals
; n
; n
=n
->next
)
4738 if (n
->next
== (NATTraversalInfo
*)~0 || n
->clientCallback
== (NATTraversalClientCallback
)~0)
4739 LogMemCorruption("m->NATTraversals: %p is garbage", n
);
4742 for (d
= m
->DNSServers
; d
; d
=d
->next
)
4743 if (d
->next
== (DNSServer
*)~0 || d
->teststate
> DNSServer_Disabled
)
4744 LogMemCorruption("m->DNSServers: %p is garbage (%d)", d
, d
->teststate
);
4746 DomainAuthInfo
*info
;
4747 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
4748 if (info
->next
== (DomainAuthInfo
*)~0 || info
->AutoTunnel
== (mDNSBool
)~0)
4749 LogMemCorruption("m->AuthInfoList: %p is garbage (%X)", info
, info
->AutoTunnel
);
4752 for (hi
= m
->Hostnames
; hi
; hi
= hi
->next
)
4753 if (hi
->next
== (HostnameInfo
*)~0 || hi
->StatusCallback
== (mDNSRecordCallback
*)~0)
4754 LogMemCorruption("m->Hostnames: %p is garbage", n
);
4756 SearchListElem
*ptr
;
4757 for (ptr
= SearchList
; ptr
; ptr
= ptr
->next
)
4758 if (ptr
->next
== (SearchListElem
*)~0 || ptr
->AuthRecs
== (void*)~0)
4759 LogMemCorruption("SearchList: %p is garbage (%X)", ptr
, ptr
->AuthRecs
);
4763 // This should probably move to the UDS daemon -- the concept of legacy clients and automatic registration / automatic browsing
4764 // is really a UDS API issue, not something intrinsic to uDNS
4766 mDNSexport mStatus
uDNS_RegisterSearchDomains(mDNS
*const m
)
4768 SearchListElem
**p
= &SearchList
, *ptr
;
4771 // step 1: mark each element for removal (-1)
4772 for (ptr
= SearchList
; ptr
; ptr
= ptr
->next
) ptr
->flag
= -1;
4774 // Client has requested domain enumeration or automatic browse -- time to make sure we have the search domains from the platform layer
4776 m
->RegisterSearchDomains
= mDNStrue
;
4777 mDNSPlatformSetDNSConfig(m
, mDNSfalse
, m
->RegisterSearchDomains
, mDNSNULL
, mDNSNULL
, mDNSNULL
);
4780 // delete elems marked for removal, do queries for elems marked add
4784 debugf("RegisterSearchDomains %d %p %##s", ptr
->flag
, ptr
->AuthRecs
, ptr
->domain
.c
);
4785 if (ptr
->flag
== -1) // remove
4787 ARListElem
*arList
= ptr
->AuthRecs
;
4788 ptr
->AuthRecs
= mDNSNULL
;
4791 mDNS_StopGetDomains(m
, &ptr
->BrowseQ
);
4792 mDNS_StopGetDomains(m
, &ptr
->RegisterQ
);
4793 mDNS_StopGetDomains(m
, &ptr
->DefBrowseQ
);
4794 mDNS_StopGetDomains(m
, &ptr
->DefRegisterQ
);
4795 mDNS_StopGetDomains(m
, &ptr
->AutomaticBrowseQ
);
4796 mDNSPlatformMemFree(ptr
);
4798 // deregister records generated from answers to the query
4801 ARListElem
*dereg
= arList
;
4802 arList
= arList
->next
;
4803 debugf("Deregistering PTR %##s -> %##s", dereg
->ar
.resrec
.name
->c
, dereg
->ar
.resrec
.rdata
->u
.name
.c
);
4804 err
= mDNS_Deregister(m
, &dereg
->ar
);
4805 if (err
) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err
);
4806 // Memory will be freed in the FreeARElemCallback
4811 if (ptr
->flag
== 1) // add
4813 mStatus err1
, err2
, err3
, err4
, err5
;
4814 err1
= mDNS_GetDomains(m
, &ptr
->BrowseQ
, mDNS_DomainTypeBrowse
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
4815 err2
= mDNS_GetDomains(m
, &ptr
->DefBrowseQ
, mDNS_DomainTypeBrowseDefault
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
4816 err3
= mDNS_GetDomains(m
, &ptr
->RegisterQ
, mDNS_DomainTypeRegistration
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
4817 err4
= mDNS_GetDomains(m
, &ptr
->DefRegisterQ
, mDNS_DomainTypeRegistrationDefault
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
4818 err5
= mDNS_GetDomains(m
, &ptr
->AutomaticBrowseQ
, mDNS_DomainTypeBrowseAutomatic
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
4819 if (err1
|| err2
|| err3
|| err4
|| err5
)
4820 LogMsg("GetDomains for domain %##s returned error(s):\n"
4821 "%d (mDNS_DomainTypeBrowse)\n"
4822 "%d (mDNS_DomainTypeBrowseDefault)\n"
4823 "%d (mDNS_DomainTypeRegistration)\n"
4824 "%d (mDNS_DomainTypeRegistrationDefault)"
4825 "%d (mDNS_DomainTypeBrowseAutomatic)\n",
4826 ptr
->domain
.c
, err1
, err2
, err3
, err4
, err5
);
4830 if (ptr
->flag
) { LogMsg("RegisterSearchDomains - unknown flag %d. Skipping.", ptr
->flag
); }
4835 return mStatus_NoError
;
4838 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
4839 // 1) query for b._dns-sd._udp.local on LocalOnly interface
4840 // (.local manually generated via explicit callback)
4841 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
4842 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
4843 // 4) result above should generate a callback from question in (1). result added to global list
4844 // 5) global list delivered to client via GetSearchDomainList()
4845 // 6) client calls to enumerate domains now go over LocalOnly interface
4846 // (!!!KRS may add outgoing interface in addition)
4848 struct CompileTimeAssertionChecks_uDNS
4850 // Check our structures are reasonable sizes. Including overly-large buffers, or embedding
4851 // other overly-large structures instead of having a pointer to them, can inadvertently
4852 // cause structure sizes (and therefore memory usage) to balloon unreasonably.
4853 char sizecheck_tcpInfo_t
[(sizeof(tcpInfo_t
) <= 9100) ? 1 : -1];
4854 char sizecheck_SearchListElem
[(sizeof(SearchListElem
) <= 3800) ? 1 : -1];