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.553.2.4 2008/07/29 20:47:44 mcguire
26 <rdar://problem/6090007> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
27 merge r1.567 & r1.568 from <rdar://problem/3988320>
29 Revision 1.553.2.3 2008/07/29 19:09:21 mcguire
30 <rdar://problem/6090041> Use all configured DNS servers
31 merge r1.558-r1.565 from <rdar://problem/4206534>
33 Revision 1.553.2.2 2008/07/29 18:50:09 mcguire
34 <rdar://problem/6090002> LLQ refresh randomization not working properly
35 merge r1.555 & r1.556 from <rdar://problem/5787898>
37 Revision 1.553.2.1 2008/03/14 20:11:25 mcguire
38 <rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client
39 Make sure we add the record when sending LLQ refreshes
41 Revision 1.553 2008/03/06 02:48:34 mcguire
42 <rdar://problem/5321824> write status to the DS
44 Revision 1.552 2008/03/05 01:56:42 cheshire
45 <rdar://problem/5687667> BTMM: Don't fallback to unencrypted operations when SRV lookup fails
47 Revision 1.551 2008/03/01 01:43:04 cheshire
48 <rdar://problem/5631565> BTMM: Lots of "Error getting external address 3" when double-NATed prevents sleep
49 Added code to suppress logging of multiple identical error results
51 Revision 1.550 2008/03/01 01:34:47 cheshire
52 <rdar://problem/5736313> BTMM: Double-NAT'd machines register all but AutoTunnel v4 address records
55 Revision 1.549 2008/02/29 01:35:37 mcguire
56 <rdar://problem/5736313> BTMM: Double-NAT'd machines register all but AutoTunnel v4 address records
58 Revision 1.548 2008/02/20 23:54:18 cheshire
59 <rdar://problem/5661518> "Failed to obtain NAT port mapping" syslog messages
60 Improved log message so it tells us more about what's going on
62 Revision 1.547 2008/02/20 00:41:09 cheshire
63 Change "PrivateQueryGotZoneData ... invoked with error code" from LogMsg to LogOperation
65 Revision 1.546 2008/02/19 23:26:50 cheshire
66 <rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
68 Revision 1.545 2007/12/22 02:25:29 cheshire
69 <rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep
71 Revision 1.544 2007/12/18 00:40:11 cheshire
72 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
73 Reordered code to avoid double-TSIGs in some cases
75 Revision 1.543 2007/12/17 23:57:43 cheshire
76 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
77 Need to include TSIG signature when sending LLQ cancellations over TLS
79 Revision 1.542 2007/12/15 01:12:27 cheshire
80 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
82 Revision 1.541 2007/12/15 00:18:51 cheshire
83 Renamed question->origLease to question->ReqLease
85 Revision 1.540 2007/12/14 23:55:28 cheshire
86 Moved "struct tcpInfo_t" definition from uDNS.c to mDNSEmbeddedAPI.h
88 Revision 1.539 2007/12/14 20:44:24 cheshire
89 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
90 SleepRecordRegistrations/WakeRecordRegistrations should only operate on uDNS records
92 Revision 1.538 2007/12/14 01:13:40 cheshire
93 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
94 Additional fixes (existing code to deregister private records and services didn't work at all)
96 Revision 1.537 2007/12/11 00:18:25 cheshire
97 <rdar://problem/5569316> BTMM: My iMac has a "ghost" ID associated with it
98 There were cases where the code was incorrectly clearing the "uselease" flag, and never resetting it.
100 Revision 1.536 2007/12/10 23:07:00 cheshire
101 Removed some unnecessary log messages
103 Revision 1.535 2007/12/06 00:22:27 mcguire
104 <rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
106 Revision 1.534 2007/12/04 00:49:37 cheshire
107 <rdar://problem/5607082> BTMM: mDNSResponder taking 100 percent CPU after upgrading to 10.5.1
109 Revision 1.533 2007/12/01 01:21:27 jgraessley
110 <rdar://problem/5623140> mDNSResponder unicast DNS improvements
112 Revision 1.532 2007/11/30 20:16:44 cheshire
113 Fixed compile warning: declaration of 'end' shadows a previous local
115 Revision 1.531 2007/11/28 22:00:09 cheshire
116 In StartSRVNatMap, change "mDNSu8 *p" to "const mDNSu8 *p"
118 Revision 1.530 2007/11/16 22:19:40 cheshire
119 <rdar://problem/5547474> mDNSResponder leaks on network changes
120 The "connection failed" code path in MakeTCPConn was not disposing of the TCPSocket it had created
122 Revision 1.529 2007/11/15 22:52:29 cheshire
123 <rdar://problem/5589039> ERROR: mDNSPlatformWriteTCP - send Broken pipe
125 Revision 1.528 2007/11/02 21:32:30 cheshire
126 <rdar://problem/5575593> BTMM: Deferring deregistration of record log messages on sleep/wake
128 Revision 1.527 2007/11/01 16:08:51 cheshire
129 Tidy up alignment of "SetRecordRetry refresh" log messages
131 Revision 1.526 2007/10/31 19:26:55 cheshire
132 Don't need to log "Permanently abandoning service registration" message when we're intentionally deleting a service
134 Revision 1.525 2007/10/30 23:58:59 cheshire
135 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
136 After failure, double retry interval up to maximum of 30 minutes
138 Revision 1.524 2007/10/30 20:10:47 cheshire
139 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
141 Revision 1.523 2007/10/30 00:54:31 cheshire
142 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
143 Fixed timing logic to double retry interval properly
145 Revision 1.522 2007/10/30 00:04:43 cheshire
146 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
147 Made the code not give up and abandon the record when it gets an error in regState_UpdatePending state
149 Revision 1.521 2007/10/29 23:58:52 cheshire
150 <rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
151 Use standard "if (mDNSIPv4AddressIsOnes(....ExternalAddress))" mechanism to determine whether callback has been invoked yet
153 Revision 1.520 2007/10/29 21:48:36 cheshire
154 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
155 Added 10% random variation on LLQ renewal time, to reduce unintended timing correlation between multiple machines
157 Revision 1.519 2007/10/29 21:37:00 cheshire
158 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
159 Added 10% random variation on record refresh time, to reduce accidental timing correlation between multiple machines
161 Revision 1.518 2007/10/26 23:41:29 cheshire
162 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
164 Revision 1.517 2007/10/25 23:30:12 cheshire
165 Private DNS registered records now deregistered on sleep and re-registered on wake
167 Revision 1.516 2007/10/25 22:53:52 cheshire
168 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
169 Don't unlinkSRS and permanently give up at the first sign of trouble
171 Revision 1.515 2007/10/25 21:08:07 cheshire
172 Don't try to send record registrations/deletions before we have our server address
174 Revision 1.514 2007/10/25 20:48:47 cheshire
175 For naming consistency (with AuthRecord's UpdateServer) renamed 'ns' to 'SRSUpdateServer'
177 Revision 1.513 2007/10/25 20:06:13 cheshire
178 Don't try to do SOA queries using private DNS (TLS over TCP) queries
180 Revision 1.512 2007/10/25 18:25:15 cheshire
181 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
182 Don't need a NAT mapping for autotunnel services
184 Revision 1.511 2007/10/25 00:16:23 cheshire
185 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
186 Fixed retry timing logic; when DNS server returns an error code, we should retry later,
187 instead of just deleting our record ("UnlinkAuthRecord") and completely giving up
189 Revision 1.510 2007/10/24 22:40:06 cheshire
190 Renamed: RecordRegistrationCallback -> RecordRegistrationGotZoneData
191 Renamed: ServiceRegistrationZoneDataComplete -> ServiceRegistrationGotZoneData
193 Revision 1.509 2007/10/24 00:54:07 cheshire
194 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
196 Revision 1.508 2007/10/24 00:05:03 cheshire
197 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
198 When sending TLS/TCP LLQ setup request over VPN, need to set EventPort to 5353, not zero
200 Revision 1.507 2007/10/23 00:33:36 cheshire
201 Improved debugging messages
203 Revision 1.506 2007/10/22 19:54:13 cheshire
204 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
205 Only put EventPort in LLQ request when sending from an RFC 1918 source address, not when sending over VPN
207 Revision 1.505 2007/10/19 22:08:49 cheshire
208 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
209 Additional fixes and refinements
211 Revision 1.504 2007/10/18 23:06:43 cheshire
212 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
213 Additional fixes and refinements
215 Revision 1.503 2007/10/18 20:23:17 cheshire
216 Moved SuspendLLQs into mDNS.c, since it's only called from one place
218 Revision 1.502 2007/10/17 22:49:54 cheshire
219 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
221 Revision 1.501 2007/10/17 22:37:23 cheshire
222 <rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
224 Revision 1.500 2007/10/17 21:53:51 cheshire
225 Improved debugging messages; renamed startLLQHandshakeCallback to LLQGotZoneData
227 Revision 1.499 2007/10/16 21:16:50 cheshire
228 Get rid of unused uDNS_Sleep() routine
230 Revision 1.498 2007/10/16 20:59:41 cheshire
231 Export SuspendLLQs/SleepServiceRegistrations/SleepRecordRegistrations so they're callable from other files
233 Revision 1.497 2007/10/05 18:09:44 cheshire
234 <rdar://problem/5524841> Services advertised with wrong target host
236 Revision 1.496 2007/10/04 22:38:59 cheshire
237 Added LogOperation message showing new q->ThisQInterval after sending uDNS query packet
239 Revision 1.495 2007/10/03 00:16:19 cheshire
240 In PrivateQueryGotZoneData, need to grab lock before calling SetNextQueryTime
242 Revision 1.494 2007/10/02 21:11:08 cheshire
243 <rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing
245 Revision 1.493 2007/10/02 19:50:23 cheshire
246 Improved debugging message
248 Revision 1.492 2007/09/29 03:15:43 cheshire
249 <rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
250 Use AutoTunnelUnregistered macro instead of checking record state directly
252 Revision 1.491 2007/09/29 01:33:45 cheshire
253 <rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
255 Revision 1.490 2007/09/29 01:06:17 mcguire
256 <rdar://problem/5507862> 9A564: mDNSResponder crash in mDNS_Execute
258 Revision 1.489 2007/09/27 22:02:33 cheshire
259 <rdar://problem/5464941> BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord
261 Revision 1.488 2007/09/27 21:20:17 cheshire
262 Improved debugging syslog messages
264 Revision 1.487 2007/09/27 18:55:11 cheshire
265 <rdar://problem/5477165> BTMM: Multiple SRV records get registered after changing Computer Name
267 Revision 1.486 2007/09/27 17:42:49 cheshire
268 Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask"
270 Revision 1.485 2007/09/27 02:16:30 cheshire
271 <rdar://problem/5500111> BTMM: LLQ refreshes being sent in the clear to the wrong port
273 Revision 1.484 2007/09/27 00:25:39 cheshire
274 Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
275 <rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
277 Revision 1.483 2007/09/26 23:16:58 cheshire
278 <rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac
280 Revision 1.482 2007/09/26 22:06:02 cheshire
281 <rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
283 Revision 1.481 2007/09/26 00:49:46 cheshire
284 Improve packet logging to show sent and received packets,
285 transport protocol (UDP/TCP/TLS) and source/destination address:port
287 Revision 1.480 2007/09/21 21:08:52 cheshire
288 Get rid of unnecessary DumpPacket() calls -- it makes more sense
289 to do this in mDNSSendDNSMessage and mDNSCoreReceive instead
291 Revision 1.479 2007/09/21 20:01:17 cheshire
292 <rdar://problem/5496750> BTMM: Skip directly to member name in SOA queries to avoid sending names in the clear
294 Revision 1.478 2007/09/21 19:29:14 cheshire
295 Added dump of uDNS questions when in MDNS_LOG_VERBOSE_DEBUG mode
297 Revision 1.477 2007/09/20 02:29:37 cheshire
298 <rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
300 Revision 1.476 2007/09/20 01:19:49 cheshire
301 Improve debugging messages: report startLLQHandshake errors; show state in uDNS_StopLongLivedQuery message
303 Revision 1.475 2007/09/19 23:51:26 cheshire
304 <rdar://problem/5480517> BTMM: Need to log a message when NAT port mapping fails
306 Revision 1.474 2007/09/19 20:32:09 cheshire
307 Export GetAuthInfoForName so it's callable from other files
309 Revision 1.473 2007/09/18 21:42:29 cheshire
310 To reduce programming mistakes, renamed ExtPort to RequestedPort
312 Revision 1.472 2007/09/14 21:26:08 cheshire
313 <rdar://problem/5482627> BTMM: Need to manually avoid port conflicts when using UPnP gateways
315 Revision 1.471 2007/09/14 01:07:10 cheshire
316 If UPnP NAT gateway returns 0.0.0.0 as external address (e.g. because it hasn't
317 got a DHCP address yet) then retry periodically until it gives us a real address.
319 Revision 1.470 2007/09/13 00:36:26 cheshire
320 <rdar://problem/5477360> NAT Reboot detection logic incorrect
322 Revision 1.469 2007/09/13 00:28:50 cheshire
323 <rdar://problem/5477354> Host records not updated on NAT address change
325 Revision 1.468 2007/09/13 00:16:41 cheshire
326 <rdar://problem/5468706> Miscellaneous NAT Traversal improvements
328 Revision 1.467 2007/09/12 23:03:08 cheshire
329 <rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
331 Revision 1.466 2007/09/12 22:19:29 cheshire
332 <rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
334 Revision 1.465 2007/09/12 19:22:19 cheshire
335 Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
336 Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
338 Revision 1.464 2007/09/12 01:22:13 cheshire
339 Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
341 Revision 1.463 2007/09/11 20:23:28 vazquez
342 <rdar://problem/5466719> CrashTracer: 3 crashes in mDNSResponder at mDNSResponder: natTraversalHandlePortMapReply + 107
343 Make sure we clean up NATTraversals before free'ing HostnameInfo
345 Revision 1.462 2007/09/11 19:19:16 cheshire
346 Correct capitalization of "uPNP" to "UPnP"
348 Revision 1.461 2007/09/10 22:08:17 cheshire
349 Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
351 Revision 1.460 2007/09/07 21:47:43 vazquez
352 <rdar://problem/5460210> BTMM: SetupSocket 5351 failed; Can't allocate UDP multicast socket spew on wake from sleep with internet sharing on
353 Try to allocate using port 5350 if we get a failure, and only log message if that fails too.
355 Revision 1.459 2007/09/07 01:01:05 cheshire
356 <rdar://problem/5464844> BTMM: Services being registered and deregistered in a loop
357 In hndlServiceUpdateReply, need to clear SRVUpdateDeferred
359 Revision 1.458 2007/09/06 19:14:33 cheshire
360 Fixed minor error introduced in 1.379 (an "if" statement was deleted but the "else" following it was left there)
362 Revision 1.457 2007/09/05 21:48:01 cheshire
363 <rdar://problem/5385864> BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone.
364 Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance cod needs
365 to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
366 otherwise those records will expire and vanish from the cache.
368 Revision 1.456 2007/09/05 21:00:17 cheshire
369 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
370 Additional refinement: ThisQInterval needs to be restored in tcpCallback, not in PrivateQueryGotZoneData
372 Revision 1.455 2007/09/05 20:53:06 cheshire
373 Tidied up alignment of code layout; code was clearing m->tcpAddrInfo.sock instead of m->tcpDeviceInfo.sock
375 Revision 1.454 2007/09/05 02:32:55 cheshire
376 Fixed posix build error (mixed declarations and code)
378 Revision 1.453 2007/09/05 02:26:57 cheshire
379 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
380 In PrivateQueryGotZoneData, restore q->ThisQInterval to non-zero value after GetZoneData completes
382 Revision 1.452 2007/08/31 22:58:22 cheshire
383 If we have an existing TCP connection we should re-use it instead of just bailing out
384 After receiving dnsbugtest response, need to set m->NextScheduledQuery to cause queries to be re-issued
386 Revision 1.451 2007/08/31 18:49:49 vazquez
387 <rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
389 Revision 1.450 2007/08/30 22:50:04 mcguire
390 <rdar://problem/5430628> BTMM: Tunneled services are registered when autotunnel can't be setup
392 Revision 1.449 2007/08/30 00:43:17 cheshire
393 Need to clear m->rec.r.resrec.RecordType before returning from uDNS_recvLLQResponse
395 Revision 1.448 2007/08/30 00:18:46 cheshire
396 <rdar://problem/5448804> Error messages: "SendServiceRegistration: Already have TCP connection..."
398 Revision 1.447 2007/08/29 01:18:33 cheshire
399 <rdar://problem/5400181> BTMM: Tunneled services do not need NAT port mappings
400 Only create NAT mappings for SRV records with AutoTarget set to Target_AutoHostAndNATMAP
402 Revision 1.446 2007/08/28 23:58:42 cheshire
403 Rename HostTarget -> AutoTarget
405 Revision 1.445 2007/08/28 23:53:21 cheshire
406 Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
408 Revision 1.444 2007/08/27 20:29:20 cheshire
409 Additional debugging messages
411 Revision 1.443 2007/08/24 23:18:28 cheshire
412 mDNS_SetSecretForDomain is called with lock held; needs to use
413 GetAuthInfoForName_internal() instead of external version GetAuthInfoForName()
415 Revision 1.442 2007/08/24 22:43:06 cheshire
416 Tidied up coded layout
418 Revision 1.441 2007/08/24 01:20:55 cheshire
419 <rdar://problem/5434381> BTMM: Memory corruption in KeychainChanged event handling
421 Revision 1.440 2007/08/24 00:15:20 cheshire
422 Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
424 Revision 1.439 2007/08/23 21:47:09 vazquez
425 <rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
426 make sure we clean up port mappings on base stations by sending a lease value of 0,
427 and only send NAT-PMP packets on private networks; also save some memory by
428 not using packet structs in NATTraversals.
430 Revision 1.438 2007/08/22 17:50:08 vazquez
431 <rdar://problem/5399276> Need to handle errors returned by NAT-PMP routers properly
432 Propagate router errors to clients, and stop logging spurious "message too short" logs.
434 Revision 1.437 2007/08/18 00:54:15 mcguire
435 <rdar://problem/5413147> BTMM: Should not register private addresses or zeros
437 Revision 1.436 2007/08/08 21:07:48 vazquez
438 <rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
440 Revision 1.435 2007/08/03 02:04:09 vazquez
441 <rdar://problem/5371843> BTMM: Private LLQs never fall back to polling
442 Fix case where NAT-PMP returns an external address but does not support
443 port mappings. Undo previous change and now, if the router returns an
444 error in the reply packet we respect it.
446 Revision 1.434 2007/08/02 21:03:05 vazquez
447 Change NAT logic to fix case where base station with port mapping turned off
448 returns an external address but does not make port mappings.
450 Revision 1.433 2007/08/02 03:30:11 vazquez
451 <rdar://problem/5371843> BTMM: Private LLQs never fall back to polling
453 Revision 1.432 2007/08/01 18:15:19 cheshire
454 Fixed crash in tcpCallback; fixed some problems with LLQ setup behind NAT
456 Revision 1.431 2007/08/01 16:11:06 cheshire
457 Fixed "mixed declarations and code" compiler error in Posix build
459 Revision 1.430 2007/08/01 16:09:13 cheshire
460 Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
462 Revision 1.429 2007/08/01 03:09:22 cheshire
463 <rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
465 Revision 1.428 2007/08/01 01:43:36 cheshire
466 Need to do mDNS_DropLockBeforeCallback/ReclaimLock around invokation of NAT client callback
468 Revision 1.427 2007/08/01 01:31:13 cheshire
469 Need to initialize traversal->tcpInfo fields or code may crash
471 Revision 1.426 2007/08/01 01:15:57 cheshire
472 <rdar://problem/5375791> Need to invoke NAT client callback when not on RFC1918 private network
474 Revision 1.425 2007/08/01 00:04:14 cheshire
475 <rdar://problem/5261696> Crash in tcpKQSocketCallback
476 Half-open TCP connections were not being cancelled properly
478 Revision 1.424 2007/07/31 02:28:35 vazquez
479 <rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
481 Revision 1.423 2007/07/30 23:31:26 cheshire
482 Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
484 Revision 1.422 2007/07/28 01:25:57 cheshire
485 <rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
487 Revision 1.421 2007/07/28 00:04:14 cheshire
488 Various fixes for comments and debugging messages
490 Revision 1.420 2007/07/27 23:59:18 cheshire
491 Added compile-time structure size checks
493 Revision 1.419 2007/07/27 20:52:29 cheshire
494 Made uDNS_recvLLQResponse() return tri-state result: LLQ_Not, LLQ_First, or LLQ_Events
496 Revision 1.418 2007/07/27 20:32:05 vazquez
497 Flag a UPnP NAT traversal before starting a UPnP port mapping, and make sure all
498 calls to mDNS_StopNATOperation() go through the UPnP code
500 Revision 1.417 2007/07/27 20:19:42 cheshire
501 Use MDNS_LOG_VERBOSE_DEBUG for dumping out packets instead of MDNS_LOG_DEBUG
503 Revision 1.416 2007/07/27 19:59:28 cheshire
504 MUST NOT touch m->CurrentQuestion (or q) after calling AnswerCurrentQuestionWithResourceRecord()
506 Revision 1.415 2007/07/27 19:51:01 cheshire
507 Use symbol QC_addnocache instead of literal constant "2"
509 Revision 1.414 2007/07/27 19:30:39 cheshire
510 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
511 to properly reflect tri-state nature of the possible responses
513 Revision 1.413 2007/07/27 18:44:01 cheshire
514 Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
516 Revision 1.412 2007/07/27 18:38:56 cheshire
517 Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
519 Revision 1.411 2007/07/27 00:57:13 cheshire
520 Create hostname address records using standard kHostNameTTL (2 minutes) instead of 1 second
522 Revision 1.410 2007/07/25 21:41:00 vazquez
523 Make sure we clean up opened sockets when there are network transitions and when changing
526 Revision 1.409 2007/07/25 03:05:02 vazquez
528 <rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
529 <rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
530 and a myriad of other security problems
532 Revision 1.408 2007/07/24 21:47:51 cheshire
533 Don't do mDNS_StopNATOperation() for operations we never started
535 Revision 1.407 2007/07/24 17:23:33 cheshire
536 <rdar://problem/5357133> Add list validation checks for debugging
538 Revision 1.406 2007/07/24 04:14:30 cheshire
539 <rdar://problem/5356281> LLQs not working in with NAT Traversal
541 Revision 1.405 2007/07/24 01:29:03 cheshire
542 <rdar://problem/5356026> DNSServiceNATPortMappingCreate() returns stale external address information
544 Revision 1.404 2007/07/20 23:10:51 cheshire
547 Revision 1.403 2007/07/20 20:12:37 cheshire
548 Rename "mDNS_DomainTypeBrowseLegacy" as "mDNS_DomainTypeBrowseAutomatic"
550 Revision 1.402 2007/07/20 00:54:20 cheshire
551 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
553 Revision 1.401 2007/07/18 03:23:33 cheshire
554 In GetServiceTarget, need to call SetupLocalAutoTunnelInterface_internal to bring up tunnel on demand, if necessary
556 Revision 1.400 2007/07/18 02:30:25 cheshire
557 Defer AutoTunnel server record advertising until we have at least one service to advertise
558 Do AutoTunnel target host selection in GetServiceTarget (instead of uDNS_RegisterService)
560 Revision 1.399 2007/07/18 01:02:28 cheshire
561 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
562 Declare records as kDNSRecordTypeKnownUnique so we don't get name conflicts with ourselves
564 Revision 1.398 2007/07/16 23:54:48 cheshire
565 <rdar://problem/5338850> Crash when removing or changing DNS keys
567 Revision 1.397 2007/07/16 20:13:31 vazquez
568 <rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
570 Revision 1.396 2007/07/14 00:33:04 cheshire
571 Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working
573 Revision 1.395 2007/07/12 23:56:23 cheshire
574 Change "GetZoneData GOT SRV" message to debugf to reduce verbosity in syslog
576 Revision 1.394 2007/07/12 23:36:08 cheshire
577 Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog
579 Revision 1.393 2007/07/12 22:15:10 cheshire
580 Modified mDNS_SetSecretForDomain() so it can be called to update an existing entry
582 Revision 1.392 2007/07/12 02:51:27 cheshire
583 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
585 Revision 1.391 2007/07/11 23:16:31 cheshire
586 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
587 Need to prepend _autotunnel._udp to start of AutoTunnel SRV record name
589 Revision 1.390 2007/07/11 22:47:55 cheshire
590 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
591 In mDNS_SetSecretForDomain(), don't register records until after we've validated the parameters
593 Revision 1.389 2007/07/11 21:33:10 cheshire
594 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
595 Set up and register AutoTunnelTarget and AutoTunnelService DNS records
597 Revision 1.388 2007/07/11 19:27:10 cheshire
598 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
599 For temporary testing fake up an IPv4LL address instead of IPv6 ULA
601 Revision 1.387 2007/07/11 03:04:08 cheshire
602 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
603 Add AutoTunnel parameter to mDNS_SetSecretForDomain; Set up AutoTunnel information for domains that require it
605 Revision 1.386 2007/07/10 01:57:28 cheshire
606 <rdar://problem/5196524> uDNS: mDNSresponder is leaking TCP connections to DNS server
607 Turned vast chunks of replicated code into a subroutine MakeTCPConn(...);
608 Made routines hold on to the reference it returns instead of leaking it
610 Revision 1.385 2007/07/09 23:50:18 cheshire
611 unlinkSRS needs to call mDNS_StopNATOperation_internal(), not mDNS_StopNATOperation()
613 Revision 1.384 2007/07/06 21:20:21 cheshire
614 Fix scheduling error (was causing "Task Scheduling Error: Continuously busy for more than a second")
616 Revision 1.383 2007/07/06 18:59:59 cheshire
617 Avoid spinning in an infinite loop when uDNS_SendNATMsg() returns an error
619 Revision 1.382 2007/07/04 00:49:43 vazquez
620 Clean up extraneous comments
622 Revision 1.381 2007/07/03 00:41:14 vazquez
623 More changes for <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
624 Safely deal with packet replies and client callbacks
626 Revision 1.380 2007/07/02 22:08:47 cheshire
627 Fixed crash in "Received public IP address" message
629 Revision 1.379 2007/06/29 00:08:49 vazquez
630 <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
632 Revision 1.378 2007/06/27 20:25:10 cheshire
633 Expanded dnsbugtest comment, explaining requirement that we also need these
634 test queries to black-hole before they get to the root name servers.
636 Revision 1.377 2007/06/22 21:27:21 cheshire
637 Modified "could not convert shared secret from base64" log message
639 Revision 1.376 2007/06/20 01:10:12 cheshire
640 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
642 Revision 1.375 2007/06/15 21:54:51 cheshire
643 <rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
645 Revision 1.374 2007/06/12 02:15:26 cheshire
646 Fix incorrect "DNS Server passed" LogOperation message
648 Revision 1.373 2007/05/31 00:25:43 cheshire
649 <rdar://problem/5238688> Only send dnsbugtest query for questions where it's warranted
651 Revision 1.372 2007/05/25 17:03:45 cheshire
652 lenptr needs to be declared unsigned, otherwise sign extension can mess up the shifting and ORing operations
654 Revision 1.371 2007/05/24 00:11:44 cheshire
655 Remove unnecessary lenbuf field from tcpInfo_t
657 Revision 1.370 2007/05/23 00:30:59 cheshire
658 Don't change question->TargetQID when repeating query over TCP
660 Revision 1.369 2007/05/21 18:04:40 cheshire
661 Updated comments -- port_mapping_create_reply renamed to port_mapping_reply
663 Revision 1.368 2007/05/17 19:12:16 cheshire
664 Updated comment about finding matching pair of sockets
666 Revision 1.367 2007/05/15 23:38:00 cheshire
667 Need to grab lock before calling SendRecordRegistration();
669 Revision 1.366 2007/05/15 00:43:05 cheshire
670 <rdar://problem/4983538> uDNS serviceRegistrationCallback locking failures
672 Revision 1.365 2007/05/10 21:19:18 cheshire
673 Rate-limit DNS test queries to at most one per three seconds
674 (useful when we have a dozen active WAB queries, and then we join a new network)
676 Revision 1.364 2007/05/07 20:43:45 cheshire
677 <rdar://problem/4241419> Reduce the number of queries and announcements
679 Revision 1.363 2007/05/04 22:12:48 cheshire
680 Work towards solving <rdar://problem/5176892> "uDNS_CheckQuery: LastQTime" log messages
681 When code gets in this invalid state, double ThisQInterval each time, to avoid excessive logging
683 Revision 1.362 2007/05/04 21:23:05 cheshire
684 <rdar://problem/5167263> Private DNS always returns no answers in the initial LLQ setup response
685 Preparatory work to enable us to do a four-way LLQ handshake over TCP, if we decide that's what we want
687 Revision 1.361 2007/05/03 23:50:48 cheshire
688 <rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
689 In the case of negative answers for the address record, set the server address to zerov4Addr
691 Revision 1.360 2007/05/03 22:40:38 cheshire
692 <rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
694 Revision 1.359 2007/05/02 22:21:33 cheshire
695 <rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
697 Revision 1.358 2007/05/01 21:46:31 cheshire
698 Move GetLLQOptData/GetPktLease from uDNS.c into DNSCommon.c so that dnsextd can use them
700 Revision 1.357 2007/05/01 01:33:49 cheshire
701 Removed "#define LLQ_Info DNSQuestion" and manually reconciled code that was still referring to "LLQ_Info"
703 Revision 1.356 2007/04/30 21:51:06 cheshire
706 Revision 1.355 2007/04/30 21:33:38 cheshire
707 Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
708 is iterating through the m->ServiceRegistrations list
710 Revision 1.354 2007/04/30 01:30:04 cheshire
711 GetZoneData_QuestionCallback needs to call client callback function on error, so client knows operation is finished
712 RecordRegistrationCallback and serviceRegistrationCallback need to clear nta reference when they're invoked
714 Revision 1.353 2007/04/28 01:28:25 cheshire
715 Fixed memory leak on error path in FoundDomain
717 Revision 1.352 2007/04/27 19:49:53 cheshire
718 In uDNS_ReceiveTestQuestionResponse, also check that srcport matches
720 Revision 1.351 2007/04/27 19:28:02 cheshire
721 Any code that calls StartGetZoneData needs to keep a handle to the structure, so
722 it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
723 -- it would start a query and then quickly cancel it, and then when
724 StartGetZoneData completed, it had a dangling pointer and crashed.)
726 Revision 1.350 2007/04/26 22:47:14 cheshire
727 Defensive coding: tcpCallback only needs to check "if (closed)", not "if (!n && closed)"
729 Revision 1.349 2007/04/26 16:04:06 cheshire
730 In mDNS_AddDNSServer, check whether port matches
731 In uDNS_CheckQuery, handle case where startLLQHandshake changes q->llq->state to LLQ_Poll
733 Revision 1.348 2007/04/26 04:01:59 cheshire
734 Copy-and-paste error: Test should be "if (result == DNSServer_Passed)" not "if (result == DNSServer_Failed)"
736 Revision 1.347 2007/04/26 00:35:15 cheshire
737 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
738 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
739 inside the firewall may give answers where a public one gives none, and vice versa.)
741 Revision 1.346 2007/04/25 19:16:59 cheshire
742 Don't set SuppressStdPort53Queries unless we do actually send a DNS packet
744 Revision 1.345 2007/04/25 18:05:11 cheshire
745 Don't try to restart inactive (duplicate) queries
747 Revision 1.344 2007/04/25 17:54:07 cheshire
748 Don't cancel Private LLQs using a clear-text UDP packet
750 Revision 1.343 2007/04/25 16:40:08 cheshire
751 Add comment explaining uDNS_recvLLQResponse logic
753 Revision 1.342 2007/04/25 02:14:38 cheshire
754 <rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
755 Additional fixes to make LLQs work properly
757 Revision 1.341 2007/04/24 02:07:42 cheshire
758 <rdar://problem/4246187> Identical client queries should reference a single shared core query
759 Deleted some more redundant code
761 Revision 1.340 2007/04/23 22:01:23 cheshire
762 <rdar://problem/5094009> IPv6 filtering in AirPort base station breaks Wide-Area Bonjour
763 As of March 2007, AirPort base stations now block incoming IPv6 connections by default, so there's no point
764 advertising IPv6 addresses in DNS any more -- we have to assume that most of the time a host's IPv6 address
765 probably won't work for incoming connections (but its IPv4 address probably will, using NAT-PMP).
767 Revision 1.339 2007/04/22 06:02:03 cheshire
768 <rdar://problem/4615977> Query should immediately return failure when no server
770 Revision 1.338 2007/04/21 19:44:11 cheshire
771 Improve uDNS_HandleNATPortMapReply log message
773 Revision 1.337 2007/04/21 02:03:00 cheshire
774 Also need to set AddressRec->resrec.RecordType in the NAT case too
776 Revision 1.336 2007/04/20 21:16:12 cheshire
777 Fixed bogus double-registration of host name -- was causing these warning messages in syslog:
778 Error! Tried to register AuthRecord 0181FB0C host.example.com. (Addr) that's already in the list
780 Revision 1.335 2007/04/19 23:57:20 cheshire
781 Temporary workaround for some AirPort base stations that don't seem to like us requesting public port zero
783 Revision 1.334 2007/04/19 23:21:51 cheshire
784 Fixed a couple of places where the StartGetZoneData check was backwards
786 Revision 1.333 2007/04/19 22:50:53 cheshire
787 <rdar://problem/4246187> Identical client queries should reference a single shared core query
789 Revision 1.332 2007/04/19 20:34:32 cheshire
790 Add debugging log message in uDNS_CheckQuery()
792 Revision 1.331 2007/04/19 20:06:41 cheshire
793 Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
795 Revision 1.330 2007/04/19 19:51:54 cheshire
796 Get rid of unnecessary initializeQuery() routine
798 Revision 1.329 2007/04/19 18:03:52 cheshire
799 Improved "mDNS_AddSearchDomain" log message
801 Revision 1.328 2007/04/18 20:57:20 cheshire
802 Commented out "GetAuthInfoForName none found" debugging message
804 Revision 1.327 2007/04/17 19:21:29 cheshire
805 <rdar://problem/5140339> Domain discovery not working over VPN
807 Revision 1.326 2007/04/16 20:49:39 cheshire
808 Fix compile errors for mDNSPosix build
810 Revision 1.325 2007/04/05 22:55:35 cheshire
811 <rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
813 Revision 1.324 2007/04/05 20:43:30 cheshire
814 Collapse sprawling code onto one line -- this is part of a bigger block of identical
815 code that has been copied-and-pasted into six different places in the same file.
816 This really needs to be turned into a subroutine.
818 Revision 1.323 2007/04/04 21:48:52 cheshire
819 <rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
821 Revision 1.322 2007/04/03 19:53:06 cheshire
822 Use mDNSSameIPPort (and similar) instead of accessing internal fields directly
824 Revision 1.321 2007/04/02 23:44:09 cheshire
827 Revision 1.320 2007/03/31 01:26:13 cheshire
828 Take out GetAuthInfoForName syslog message
830 Revision 1.319 2007/03/31 01:10:53 cheshire
833 Revision 1.318 2007/03/31 00:17:11 cheshire
836 Revision 1.317 2007/03/29 00:09:31 cheshire
837 Improve "uDNS_InitLongLivedQuery" log message
839 Revision 1.316 2007/03/28 21:16:27 cheshire
840 Remove DumpPacket() call now that OPT pseudo-RR rrclass bug is fixed
842 Revision 1.315 2007/03/28 21:02:18 cheshire
843 <rdar://problem/3810563> Wide-Area Bonjour should work on multi-subnet private network
845 Revision 1.314 2007/03/28 15:56:37 cheshire
846 <rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
848 Revision 1.313 2007/03/28 01:27:32 cheshire
849 <rdar://problem/4996439> Unicast DNS polling server every three seconds
850 StartLLQPolling was using INIT_UCAST_POLL_INTERVAL instead of LLQ_POLL_INTERVAL for the retry interval
852 Revision 1.312 2007/03/27 23:48:21 cheshire
853 Use mDNS_StopGetDomains(), not mDNS_StopQuery()
855 Revision 1.311 2007/03/27 22:47:51 cheshire
856 Remove unnecessary "*(long*)0 = 0;" to generate crash and stack trace
858 Revision 1.310 2007/03/24 01:24:13 cheshire
859 Add validator for uDNS data structures; fixed crash in RegisterSearchDomains()
861 Revision 1.309 2007/03/24 00:47:53 cheshire
862 <rdar://problem/4983538> serviceRegistrationCallback: Locking Failure! mDNS_busy (1) != mDNS_reentrancy (2)
863 Locking in this file is all messed up. For now we'll just work around the issue.
865 Revision 1.308 2007/03/24 00:41:33 cheshire
866 Minor code cleanup (move variable declarations to minimum enclosing scope)
868 Revision 1.307 2007/03/21 23:06:00 cheshire
869 Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
871 Revision 1.306 2007/03/21 00:30:03 cheshire
872 <rdar://problem/4789455> Multiple errors in DNameList-related code
874 Revision 1.305 2007/03/20 17:07:15 cheshire
875 Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
877 Revision 1.304 2007/03/17 00:02:11 cheshire
878 <rdar://problem/5067013> NAT-PMP: Lease TTL is being ignored
880 Revision 1.303 2007/03/10 03:26:44 cheshire
881 <rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
883 Revision 1.302 2007/03/10 02:29:58 cheshire
884 Added comments about NAT-PMP response functions
886 Revision 1.301 2007/03/10 02:02:58 cheshire
887 <rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
888 Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
890 Revision 1.300 2007/03/08 18:56:00 cheshire
891 Fixed typo: "&v4.ip.v4.b[0]" is always non-zero (ampersand should not be there)
893 Revision 1.299 2007/02/28 01:45:47 cheshire
894 <rdar://problem/4683261> NAT-PMP: Port mapping refreshes should contain actual public port
895 <rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
897 Revision 1.298 2007/02/14 03:16:39 cheshire
898 <rdar://problem/4789477> Eliminate unnecessary malloc/free in mDNSCore code
900 Revision 1.297 2007/02/08 21:12:28 cheshire
901 <rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
903 Revision 1.296 2007/01/29 16:03:22 cheshire
904 Fix unused parameter warning
906 Revision 1.295 2007/01/27 03:34:27 cheshire
907 Made GetZoneData use standard queries (and cached results);
908 eliminated GetZoneData_Callback() packet response handler
910 Revision 1.294 2007/01/25 00:40:16 cheshire
911 Unified CNAME-following functionality into cache management code (which means CNAME-following
912 should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine.
914 Revision 1.293 2007/01/23 02:56:11 cheshire
915 Store negative results in the cache, instead of generating them out of pktResponseHndlr()
917 Revision 1.292 2007/01/20 01:32:40 cheshire
918 Update comments and debugging messages
920 Revision 1.291 2007/01/20 00:07:02 cheshire
921 When we have credentials in the keychain for a domain, we attempt private queries, but
922 if the authoritative server is not set up for private queries (i.e. no _dns-query-tls
923 or _dns-llq-tls record) then we need to fall back to conventional non-private queries.
925 Revision 1.290 2007/01/19 23:41:45 cheshire
926 Need to clear m->rec.r.resrec.RecordType after calling GetLLQOptData()
928 Revision 1.289 2007/01/19 23:32:07 cheshire
929 Eliminate pointless timenow variable
931 Revision 1.288 2007/01/19 23:26:08 cheshire
932 Right now tcpCallback does not run holding the lock, so no need to drop the lock before invoking callbacks
934 Revision 1.287 2007/01/19 22:55:41 cheshire
935 Eliminate redundant identical parameters to GetZoneData_StartQuery()
937 Revision 1.286 2007/01/19 21:17:33 cheshire
938 StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
940 Revision 1.285 2007/01/19 18:39:11 cheshire
941 Fix a bunch of parameters that should have been declared "const"
943 Revision 1.284 2007/01/19 18:28:28 cheshire
944 Improved debugging messages
946 Revision 1.283 2007/01/19 18:09:33 cheshire
947 Fixed getLLQAtIndex (now called GetLLQOptData):
948 1. It incorrectly assumed all EDNS0 OPT records are the same size (it ignored optlen)
949 2. It used inefficient memory copying instead of just returning a pointer
951 Revision 1.282 2007/01/17 22:06:01 cheshire
952 Replace duplicated literal constant "{ { 0 } }" with symbol "zeroIPPort"
954 Revision 1.281 2007/01/17 21:58:13 cheshire
955 For clarity, rename ntaContext field "isPrivate" to "ntaPrivate"
957 Revision 1.280 2007/01/17 21:46:02 cheshire
958 Remove redundant duplicated "isPrivate" field from LLQ_Info
960 Revision 1.279 2007/01/17 21:35:31 cheshire
961 For clarity, rename zoneData_t field "isPrivate" to "zonePrivate"
963 Revision 1.278 2007/01/16 03:04:16 cheshire
964 <rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
965 Don't cache result of ntaContextSRV(context) in a local variable --
966 the macro evaluates to a different result after we clear "context->isPrivate"
968 Revision 1.277 2007/01/10 22:51:58 cheshire
969 <rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
971 Revision 1.276 2007/01/10 02:09:30 cheshire
972 Better LogOperation record of keys read from System Keychain
974 Revision 1.275 2007/01/09 22:37:18 cheshire
975 Provide ten-second grace period for deleted keys, to give mDNSResponder
976 time to delete host name before it gives up access to the required key.
978 Revision 1.274 2007/01/09 01:16:32 cheshire
979 Improve "ERROR m->CurrentQuestion already set" debugging messages
981 Revision 1.273 2007/01/08 23:58:00 cheshire
982 Don't request regDomain and browseDomains in uDNS_SetupDNSConfig() -- it just ignores those results
984 Revision 1.272 2007/01/05 08:30:42 cheshire
985 Trim excessive "$Log" checkin history from before 2006
986 (checkin history still available via "cvs log ..." of course)
988 Revision 1.271 2007/01/05 06:34:03 cheshire
989 Improve "ERROR m->CurrentQuestion already set" debugging messages
991 Revision 1.270 2007/01/05 05:44:33 cheshire
992 Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c,
993 so that mDNSPosix embedded clients will compile again
995 Revision 1.269 2007/01/04 23:11:13 cheshire
996 <rdar://problem/4720673> uDNS: Need to start caching unicast records
997 When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
999 Revision 1.268 2007/01/04 22:06:38 cheshire
1000 Fixed crash in LLQNatMapComplete()
1002 Revision 1.267 2007/01/04 21:45:20 cheshire
1003 Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
1004 to do additional lock sanity checking around callback invocations
1006 Revision 1.266 2007/01/04 21:01:20 cheshire
1007 <rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
1008 Only return NXDOMAIN results to clients that request them using kDNSServiceFlagsReturnIntermediates
1010 Revision 1.265 2007/01/04 20:47:17 cheshire
1011 Fixed crash in CheckForUnreferencedLLQMapping()
1013 Revision 1.264 2007/01/04 20:39:27 cheshire
1014 Fix locking mismatch
1016 Revision 1.263 2007/01/04 02:39:53 cheshire
1017 <rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
1019 Revision 1.262 2007/01/04 00:29:25 cheshire
1020 Covert LogMsg() in GetAuthInfoForName to LogOperation()
1022 Revision 1.261 2006/12/22 20:59:49 cheshire
1023 <rdar://problem/4742742> Read *all* DNS keys from keychain,
1024 not just key for the system-wide default registration domain
1026 Revision 1.260 2006/12/21 00:06:07 cheshire
1027 Don't need to do mDNSPlatformMemZero() -- mDNS_SetupResourceRecord() does it for us
1029 Revision 1.259 2006/12/20 04:07:36 cheshire
1030 Remove uDNS_info substructure from AuthRecord_struct
1032 Revision 1.258 2006/12/19 22:49:24 cheshire
1033 Remove uDNS_info substructure from ServiceRecordSet_struct
1035 Revision 1.257 2006/12/19 02:38:20 cheshire
1036 Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
1038 Revision 1.256 2006/12/19 02:18:48 cheshire
1039 Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
1041 Revision 1.255 2006/12/16 01:58:31 cheshire
1042 <rdar://problem/4720673> uDNS: Need to start caching unicast records
1044 Revision 1.254 2006/12/15 19:23:39 cheshire
1045 Use new DomainNameLengthLimit() function, to be more defensive against malformed
1046 data received from the network.
1048 Revision 1.253 2006/12/01 07:43:34 herscher
1049 Fix byte ordering problem for one-shot TCP queries.
1050 Iterate more intelligently over duplicates in uDNS_ReceiveMsg to avoid spin loops.
1052 Revision 1.252 2006/11/30 23:07:57 herscher
1053 <rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
1055 Revision 1.251 2006/11/28 21:42:11 mkrochma
1056 Work around a crashing bug that was introduced by uDNS and mDNS code unification
1058 Revision 1.250 2006/11/18 05:01:30 cheshire
1059 Preliminary support for unifying the uDNS and mDNS code,
1060 including caching of uDNS answers
1062 Revision 1.249 2006/11/10 07:44:04 herscher
1063 <rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
1065 Revision 1.248 2006/11/08 04:26:53 cheshire
1066 Fix typo in debugging message
1068 Revision 1.247 2006/10/20 05:35:04 herscher
1069 <rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
1071 Revision 1.246 2006/10/11 19:29:41 herscher
1072 <rdar://problem/4744553> uDNS: mDNSResponder-111 using 100% CPU
1074 Revision 1.245 2006/10/04 22:21:15 herscher
1075 Tidy up references to mDNS_struct introduced when the embedded uDNS_info struct was removed.
1077 Revision 1.244 2006/10/04 21:51:27 herscher
1078 Replace calls to mDNSPlatformTimeNow(m) with m->timenow
1080 Revision 1.243 2006/10/04 21:38:59 herscher
1081 Remove uDNS_info substructure from DNSQuestion_struct
1083 Revision 1.242 2006/09/27 00:51:46 herscher
1084 Fix compile error when _LEGACY_NAT_TRAVERSAL_ is not defined
1086 Revision 1.241 2006/09/26 01:54:47 herscher
1087 <rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
1089 Revision 1.240 2006/09/15 21:20:15 cheshire
1090 Remove uDNS_info substructure from mDNS_struct
1092 Revision 1.239 2006/08/16 02:52:56 mkrochma
1093 <rdar://problem/4104154> Actually fix it this time
1095 Revision 1.238 2006/08/16 00:31:50 mkrochma
1096 <rdar://problem/4386944> Get rid of NotAnInteger references
1098 Revision 1.237 2006/08/15 23:38:17 mkrochma
1099 <rdar://problem/4104154> Requested Public Port field should be set to zero on mapping deletion
1101 Revision 1.236 2006/08/14 23:24:23 cheshire
1102 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
1104 Revision 1.235 2006/07/30 05:45:36 cheshire
1105 <rdar://problem/4304215> Eliminate MIN_UCAST_PERIODIC_EXEC
1107 Revision 1.234 2006/07/22 02:58:36 cheshire
1108 Code was clearing namehash twice instead of namehash and rdatahash
1110 Revision 1.233 2006/07/20 19:46:51 mkrochma
1111 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1114 Revision 1.232 2006/07/15 02:01:29 cheshire
1115 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1116 Fix broken "empty string" browsing
1118 Revision 1.231 2006/07/05 23:28:22 cheshire
1119 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1121 Revision 1.230 2006/06/29 03:02:44 cheshire
1122 <rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
1124 Revision 1.229 2006/03/02 22:03:41 cheshire
1125 <rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
1126 Refinement: m->rec.r.resrec.RecordType needs to be cleared *every* time around for loop, not just once at the end
1128 Revision 1.228 2006/02/26 00:54:42 cheshire
1129 Fixes to avoid code generation warning/error on FreeBSD 7
1131 Revision 1.227 2006/01/09 20:47:05 cheshire
1132 <rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
1138 #if(defined(_MSC_VER))
1139 // Disable "assignment within conditional expression".
1140 // Other compilers understand the convention that if you place the assignment expression within an extra pair
1141 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
1142 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
1143 // to the compiler that the assignment is intentional, we have to just turn this warning off completely.
1144 #pragma warning(disable:4706)
1147 typedef struct SearchListElem
1149 struct SearchListElem
*next
;
1151 int flag
; // -1 means delete, 0 means unchanged, +1 means newly added
1152 DNSQuestion BrowseQ
;
1153 DNSQuestion DefBrowseQ
;
1154 DNSQuestion AutomaticBrowseQ
;
1155 DNSQuestion RegisterQ
;
1156 DNSQuestion DefRegisterQ
;
1157 ARListElem
*AuthRecs
;
1160 // For domain enumeration and automatic browsing
1161 // This is the user's DNS search list.
1162 // In each of these domains we search for our special pointer records (lb._dns-sd._udp.<domain>, etc.)
1163 // to discover recommended domains for domain enumeration (browse, default browse, registration,
1164 // default registration) and possibly one or more recommended automatic browsing domains.
1165 static SearchListElem
*SearchList
= mDNSNULL
;
1167 // Temporary workaround to make ServiceRecordSet list management safe.
1168 // Ideally a ServiceRecordSet shouldn't be a special entity that's given special treatment by the uDNS code
1169 // -- it should just be a grouping of records that are treated the same as any other registered records.
1170 // In that case it may no longer be necessary to keep an explicit list of ServiceRecordSets, which in turn
1171 // would avoid the perils of modifying that list cleanly while some other piece of code is iterating through it.
1172 ServiceRecordSet
*CurrentServiceRecordSet
= mDNSNULL
;
1174 // ***************************************************************************
1175 #if COMPILER_LIKES_PRAGMA_MARK
1176 #pragma mark - General Utility Functions
1179 // Unlink an AuthRecord from the m->ResourceRecords list.
1180 // This seems risky. Probably some (or maybe all) of the places calling UnlinkAuthRecord to directly
1181 // remove a record from the list should actually be using mDNS_Deregister/mDNS_Deregister_internal.
1182 mDNSlocal mStatus
UnlinkAuthRecord(mDNS
*const m
, AuthRecord
*const rr
)
1184 AuthRecord
**list
= &m
->ResourceRecords
;
1185 if (m
->NewLocalRecords
== rr
) m
->NewLocalRecords
= rr
->next
;
1186 if (m
->CurrentRecord
== rr
) m
->CurrentRecord
= rr
->next
;
1187 while (*list
&& *list
!= rr
) list
= &(*list
)->next
;
1190 list
= &m
->DuplicateRecords
;
1191 while (*list
&& *list
!= rr
) list
= &(*list
)->next
;
1193 if (*list
) { *list
= rr
->next
; rr
->next
= mDNSNULL
; return(mStatus_NoError
); }
1194 LogMsg("ERROR: UnlinkAuthRecord - no such active record %##s", rr
->resrec
.name
->c
);
1195 return(mStatus_NoSuchRecord
);
1198 // unlinkSRS is an internal routine (i.e. must be called with the lock already held)
1199 mDNSlocal
void unlinkSRS(mDNS
*const m
, ServiceRecordSet
*srs
)
1201 ServiceRecordSet
**p
;
1203 if (srs
->NATinfo
.clientContext
)
1205 mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
1206 srs
->NATinfo
.clientContext
= mDNSNULL
;
1209 for (p
= &m
->ServiceRegistrations
; *p
; p
= &(*p
)->uDNS_next
)
1212 ExtraResourceRecord
*e
;
1213 *p
= srs
->uDNS_next
;
1214 if (CurrentServiceRecordSet
== srs
)
1215 CurrentServiceRecordSet
= srs
->uDNS_next
;
1216 srs
->uDNS_next
= mDNSNULL
;
1217 for (e
=srs
->Extras
; e
; e
=e
->next
)
1218 if (UnlinkAuthRecord(m
, &e
->r
))
1219 LogMsg("unlinkSRS: extra record %##s not found", e
->r
.resrec
.name
->c
);
1222 LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list %##s", srs
->RR_SRV
.resrec
.name
->c
);
1225 // set retry timestamp for record with exponential backoff
1226 // (for service record sets, use RR_SRV as representative for time checks
1227 mDNSlocal
void SetRecordRetry(mDNS
*const m
, AuthRecord
*rr
, mStatus SendErr
)
1229 mDNSs32 elapsed
= m
->timenow
- rr
->LastAPTime
;
1230 rr
->LastAPTime
= m
->timenow
;
1233 // Code for stress-testing registration renewal code
1234 if (rr
->expire
&& rr
->expire
- m
->timenow
> mDNSPlatformOneSecond
* 120)
1236 LogOperation("Adjusting expiry from %d to 120 seconds for %s",
1237 (rr
->expire
- m
->timenow
) / mDNSPlatformOneSecond
, ARDisplayString(m
, rr
));
1238 rr
->expire
= m
->timenow
+ mDNSPlatformOneSecond
* 120;
1242 if (rr
->expire
&& rr
->expire
- m
->timenow
> mDNSPlatformOneSecond
)
1244 mDNSs32 remaining
= rr
->expire
- m
->timenow
;
1245 rr
->ThisAPInterval
= remaining
/2 + mDNSRandom(remaining
/10);
1246 LogOperation("SetRecordRetry refresh in %4d of %4d for %s",
1247 rr
->ThisAPInterval
/ mDNSPlatformOneSecond
,
1248 (rr
->expire
- m
->timenow
) / mDNSPlatformOneSecond
,
1249 ARDisplayString(m
, rr
));
1255 // If at least half our our time interval has elapsed, it's time to double rr->ThisAPInterval
1256 // If resulting interval is too small, set to at least INIT_UCAST_POLL_INTERVAL (3 seconds)
1257 // If resulting interval is too large, set to at most 30 minutes
1258 if (rr
->ThisAPInterval
/ 2 <= elapsed
) rr
->ThisAPInterval
*= 2;
1259 if (rr
->ThisAPInterval
< INIT_UCAST_POLL_INTERVAL
|| SendErr
== mStatus_TransientErr
)
1260 rr
->ThisAPInterval
= INIT_UCAST_POLL_INTERVAL
;
1261 rr
->ThisAPInterval
+= mDNSRandom(rr
->ThisAPInterval
/20);
1262 if (rr
->ThisAPInterval
> 30 * 60 * mDNSPlatformOneSecond
)
1263 rr
->ThisAPInterval
= 30 * 60 * mDNSPlatformOneSecond
;
1265 LogOperation("SetRecordRetry retry in %4d for %s", rr
->ThisAPInterval
/ mDNSPlatformOneSecond
, ARDisplayString(m
, rr
));
1268 // ***************************************************************************
1269 #if COMPILER_LIKES_PRAGMA_MARK
1270 #pragma mark - Name Server List Management
1273 mDNSexport DNSServer
*mDNS_AddDNSServer(mDNS
*const m
, const domainname
*d
, const mDNSInterfaceID interface
, const mDNSAddr
*addr
, const mDNSIPPort port
)
1275 DNSServer
**p
= &m
->DNSServers
;
1277 if (!d
) d
= (const domainname
*)"";
1279 LogOperation("mDNS_AddDNSServer: Adding %#a for %##s", addr
, d
->c
);
1280 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
1281 LogMsg("mDNS_AddDNSServer: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
1283 while (*p
) // Check if we already have this {server,domain} pair registered
1285 if ((*p
)->interface
== interface
&& (*p
)->teststate
!= DNSServer_Disabled
&&
1286 mDNSSameAddress(&(*p
)->addr
, addr
) && mDNSSameIPPort((*p
)->port
, port
) && SameDomainName(&(*p
)->domain
, d
))
1288 if (!((*p
)->flags
& DNSServer_FlagDelete
)) LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr
, d
->c
);
1289 (*p
)->flags
&= ~DNSServer_FlagDelete
;
1295 // allocate, add to list
1296 *p
= mDNSPlatformMemAllocate(sizeof(**p
));
1297 if (!*p
) LogMsg("Error: mDNS_AddDNSServer - malloc");
1300 (*p
)->interface
= interface
;
1303 (*p
)->flags
= DNSServer_FlagNew
;
1304 (*p
)->teststate
= DNSServer_Untested
;
1305 (*p
)->lasttest
= m
->timenow
- INIT_UCAST_POLL_INTERVAL
;
1306 AssignDomainName(&(*p
)->domain
, d
);
1307 (*p
)->next
= mDNSNULL
;
1312 mDNSlocal
void PushDNSServerToEnd(mDNS
*const m
, DNSQuestion
*q
)
1314 DNSServer
**p
= &m
->DNSServers
;
1316 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
1317 LogMsg("PushDNSServerToEnd: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
1321 LogMsg("PushDNSServerToEnd: Null DNS server for %##s (%s) %d", q
->qname
.c
, DNSTypeName(q
->qtype
), q
->unansweredQueries
);
1325 LogOperation("PushDNSServerToEnd: Pushing DNS server %#a:%d (%##s) due to %d unanswered queries for %##s (%s)", &q
->qDNSServer
->addr
, mDNSVal16(q
->qDNSServer
->port
), q
->qDNSServer
->domain
.c
, q
->unansweredQueries
, q
->qname
.c
, DNSTypeName(q
->qtype
));
1329 if (*p
== q
->qDNSServer
) *p
= q
->qDNSServer
->next
;
1334 q
->qDNSServer
->next
= mDNSNULL
;
1337 // ***************************************************************************
1338 #if COMPILER_LIKES_PRAGMA_MARK
1339 #pragma mark - authorization management
1342 mDNSlocal DomainAuthInfo
*GetAuthInfoForName_direct(mDNS
*m
, const domainname
*const name
)
1344 const domainname
*n
= name
;
1347 DomainAuthInfo
*ptr
;
1348 for (ptr
= m
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
1349 if (SameDomainName(&ptr
->domain
, n
))
1351 debugf("GetAuthInfoForName %##s Matched %##s Key name %##s", name
->c
, ptr
->domain
.c
, ptr
->keyname
.c
);
1354 n
= (const domainname
*)(n
->c
+ 1 + n
->c
[0]);
1356 //LogOperation("GetAuthInfoForName none found for %##s", name->c);
1360 // MUST be called with lock held
1361 mDNSexport DomainAuthInfo
*GetAuthInfoForName_internal(mDNS
*m
, const domainname
*const name
)
1363 DomainAuthInfo
**p
= &m
->AuthInfoList
;
1365 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
1366 LogMsg("GetAuthInfoForName_internal: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
1368 // First purge any dead keys from the list
1371 if ((*p
)->deltime
&& m
->timenow
- (*p
)->deltime
>= 0 && AutoTunnelUnregistered(*p
))
1374 DomainAuthInfo
*info
= *p
;
1375 LogOperation("GetAuthInfoForName_internal deleting expired key %##s %##s", info
->domain
.c
, info
->keyname
.c
);
1376 *p
= info
->next
; // Cut DomainAuthInfo from list *before* scanning our question list updating AuthInfo pointers
1377 for (q
= m
->Questions
; q
; q
=q
->next
)
1378 if (q
->AuthInfo
== info
)
1380 q
->AuthInfo
= GetAuthInfoForName_direct(m
, &q
->qname
);
1381 debugf("GetAuthInfoForName_internal updated q->AuthInfo from %##s to %##s for %##s (%s)",
1382 info
->domain
.c
, q
->AuthInfo
? q
->AuthInfo
->domain
.c
: mDNSNULL
, q
->qname
.c
, DNSTypeName(q
->qtype
));
1385 // Probably not essential, but just to be safe, zero out the secret key data
1386 // so we don't leave it hanging around in memory
1387 // (where it could potentially get exposed via some other bug)
1388 mDNSPlatformMemZero(info
, sizeof(*info
));
1389 mDNSPlatformMemFree(info
);
1395 return(GetAuthInfoForName_direct(m
, name
));
1398 mDNSexport DomainAuthInfo
*GetAuthInfoForName(mDNS
*m
, const domainname
*const name
)
1402 d
= GetAuthInfoForName_internal(m
, name
);
1407 // MUST be called with the lock held
1408 mDNSexport mStatus
mDNS_SetSecretForDomain(mDNS
*m
, DomainAuthInfo
*info
,
1409 const domainname
*domain
, const domainname
*keyname
, const char *b64keydata
, mDNSBool AutoTunnel
)
1412 DomainAuthInfo
**p
= &m
->AuthInfoList
;
1413 if (!info
|| !b64keydata
) { LogMsg("mDNS_SetSecretForDomain: ERROR: info %p b64keydata %p", info
, b64keydata
); return(mStatus_BadParamErr
); }
1415 LogOperation("mDNS_SetSecretForDomain: domain %##s key %##s%s", domain
->c
, keyname
->c
, AutoTunnel
? " AutoTunnel" : "");
1417 info
->AutoTunnel
= AutoTunnel
;
1418 AssignDomainName(&info
->domain
, domain
);
1419 AssignDomainName(&info
->keyname
, keyname
);
1420 mDNS_snprintf(info
->b64keydata
, sizeof(info
->b64keydata
), "%s", b64keydata
);
1422 if (DNSDigest_ConstructHMACKeyfromBase64(info
, b64keydata
) < 0)
1424 LogMsg("mDNS_SetSecretForDomain: ERROR: Could not convert shared secret from base64: domain %##s key %##s %s",
1425 domain
->c
, keyname
->c
, LogAllOperations
? b64keydata
: "");
1426 return(mStatus_BadParamErr
);
1429 // Don't clear deltime until after we've ascertained that b64keydata is valid
1432 while (*p
&& (*p
) != info
) p
=&(*p
)->next
;
1433 if (*p
) return(mStatus_AlreadyRegistered
);
1435 // Caution: Only zero AutoTunnelHostRecord.namestorage and AutoTunnelNAT.clientContext AFTER we've determined that this is a NEW DomainAuthInfo
1436 // being added to the list. Otherwise we risk smashing our AutoTunnel host records and NATOperation that are already active and in use.
1437 info
->AutoTunnelHostRecord
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
1438 info
->AutoTunnelHostRecord
.namestorage
.c
[0] = 0;
1439 info
->AutoTunnelTarget
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
1440 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
1441 info
->AutoTunnelService
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
1442 info
->AutoTunnelNAT
.clientContext
= mDNSNULL
;
1443 info
->next
= mDNSNULL
;
1446 // Check to see if adding this new DomainAuthInfo has changed the credentials for any of our questions
1447 for (q
= m
->Questions
; q
; q
=q
->next
)
1449 DomainAuthInfo
*newinfo
= GetAuthInfoForQuestion(m
, q
);
1450 if (q
->AuthInfo
!= newinfo
)
1452 debugf("mDNS_SetSecretForDomain updating q->AuthInfo from %##s to %##s for %##s (%s)",
1453 q
->AuthInfo
? q
->AuthInfo
->domain
.c
: mDNSNULL
,
1454 newinfo
? newinfo
->domain
.c
: mDNSNULL
, q
->qname
.c
, DNSTypeName(q
->qtype
));
1455 q
->AuthInfo
= newinfo
;
1459 return(mStatus_NoError
);
1462 // ***************************************************************************
1463 #if COMPILER_LIKES_PRAGMA_MARK
1465 #pragma mark - NAT Traversal
1468 mDNSlocal mStatus
uDNS_SendNATMsg(mDNS
*m
, NATTraversalInfo
*info
)
1470 mStatus err
= mStatus_NoError
;
1472 // send msg if we have a router and it is a private address
1473 if (!mDNSIPv4AddressIsZero(m
->Router
.ip
.v4
) && mDNSv4AddrIsRFC1918(&m
->Router
.ip
.v4
))
1475 union { NATAddrRequest NATAddrReq
; NATPortMapRequest NATPortReq
; } u
= { { NATMAP_VERS
, NATOp_AddrRequest
} } ;
1476 const mDNSu8
*end
= (mDNSu8
*)&u
+ sizeof(NATAddrRequest
);
1478 if (info
) // For NATOp_MapUDP and NATOp_MapTCP, fill in additional fields
1480 mDNSu8
*p
= (mDNSu8
*)&u
.NATPortReq
.NATReq_lease
;
1481 u
.NATPortReq
.opcode
= info
->Protocol
;
1482 u
.NATPortReq
.unused
= zeroID
;
1483 u
.NATPortReq
.intport
= info
->IntPort
;
1484 u
.NATPortReq
.extport
= info
->RequestedPort
;
1485 p
[0] = (mDNSu8
)((info
->NATLease
>> 24) & 0xFF);
1486 p
[1] = (mDNSu8
)((info
->NATLease
>> 16) & 0xFF);
1487 p
[2] = (mDNSu8
)((info
->NATLease
>> 8) & 0xFF);
1488 p
[3] = (mDNSu8
)( info
->NATLease
& 0xFF);
1489 end
= (mDNSu8
*)&u
+ sizeof(NATPortMapRequest
);
1492 err
= mDNSPlatformSendUDP(m
, (mDNSu8
*)&u
, end
, 0, mDNSNULL
, &m
->Router
, NATPMPPort
);
1494 #ifdef _LEGACY_NAT_TRAVERSAL_
1495 if (mDNSIPPortIsZero(m
->UPnPSOAPPort
)) LNT_SendDiscoveryMsg(m
);
1496 else if (info
) err
= LNT_MapPort(m
, info
);
1497 else err
= LNT_GetExternalAddress(m
);
1498 #endif // _LEGACY_NAT_TRAVERSAL_
1503 mDNSlocal
void RecreateNATMappings(mDNS
*const m
)
1505 NATTraversalInfo
*n
;
1506 for (n
= m
->NATTraversals
; n
; n
=n
->next
)
1508 n
->ExpiryTime
= 0; // Mark this mapping as expired
1509 n
->retryInterval
= NATMAP_INIT_RETRY
;
1510 n
->retryPortMap
= m
->timenow
;
1511 #ifdef _LEGACY_NAT_TRAVERSAL_
1512 if (n
->tcpInfo
.sock
) { mDNSPlatformTCPCloseConnection(n
->tcpInfo
.sock
); n
->tcpInfo
.sock
= mDNSNULL
; }
1513 #endif // _LEGACY_NAT_TRAVERSAL_
1516 m
->NextScheduledNATOp
= m
->timenow
; // Need to send packets immediately
1519 #ifdef _LEGACY_NAT_TRAVERSAL_
1520 mDNSlocal
void ClearUPnPState(mDNS
*const m
)
1522 if (m
->tcpAddrInfo
.sock
) { mDNSPlatformTCPCloseConnection(m
->tcpAddrInfo
.sock
); m
->tcpAddrInfo
.sock
= mDNSNULL
; }
1523 if (m
->tcpDeviceInfo
.sock
) { mDNSPlatformTCPCloseConnection(m
->tcpDeviceInfo
.sock
); m
->tcpDeviceInfo
.sock
= mDNSNULL
; }
1524 m
->UPnPSOAPPort
= m
->UPnPRouterPort
= zeroIPPort
; // Reset UPnP ports
1527 #define ClearUPnPState(X)
1528 #endif // _LEGACY_NAT_TRAVERSAL_
1530 mDNSexport
void natTraversalHandleAddressReply(mDNS
*const m
, mDNSu16 err
, mDNSv4Addr ExtAddr
)
1532 static mDNSu16 last_err
;
1535 if (err
!= last_err
) LogMsg("Error getting external address %d", err
);
1537 else if (!mDNSSameIPv4Address(m
->ExternalAddress
, ExtAddr
))
1539 LogOperation("Received external IP address %.4a from NAT", &ExtAddr
);
1540 if (mDNSv4AddrIsRFC1918(&ExtAddr
))
1541 LogMsg("Double NAT (external NAT gateway address %.4a is also a private RFC 1918 address)", &ExtAddr
);
1542 m
->ExternalAddress
= ExtAddr
;
1543 RecreateNATMappings(m
); // Also sets NextScheduledNATOp for us
1546 if (err
|| mDNSIPv4AddressIsZero(ExtAddr
)) m
->retryIntervalGetAddr
= NATMAP_INIT_RETRY
* 32; // 8 seconds
1547 else m
->retryIntervalGetAddr
= NATMAP_MAX_RETRY_INTERVAL
;
1549 m
->retryGetAddr
= m
->timenow
+ m
->retryIntervalGetAddr
;
1550 if (m
->NextScheduledNATOp
- m
->retryIntervalGetAddr
> 0)
1551 m
->NextScheduledNATOp
= m
->retryIntervalGetAddr
;
1556 // Both places that call NATSetNextRenewalTime() update m->NextScheduledNATOp correctly afterwards
1557 mDNSlocal
void NATSetNextRenewalTime(mDNS
*const m
, NATTraversalInfo
*n
)
1559 n
->retryInterval
= (n
->ExpiryTime
- m
->timenow
)/2;
1560 if (n
->retryInterval
< NATMAP_MIN_RETRY_INTERVAL
) // Min retry interval is 2 seconds
1561 n
->retryInterval
= NATMAP_MIN_RETRY_INTERVAL
;
1562 n
->retryPortMap
= m
->timenow
+ n
->retryInterval
;
1565 // Note: When called from handleLNTPortMappingResponse() only pkt->err, pkt->extport and pkt->NATRep_lease fields are filled in
1566 mDNSexport
void natTraversalHandlePortMapReply(mDNS
*const m
, NATTraversalInfo
*n
, const mDNSInterfaceID InterfaceID
, mDNSu16 err
, mDNSIPPort extport
, mDNSu32 lease
)
1569 if (err
|| lease
== 0 || mDNSIPPortIsZero(extport
))
1571 LogOperation("natTraversalHandlePortMapReply: received error making port mapping error %d port %d", err
, mDNSVal16(extport
));
1572 n
->retryInterval
= NATMAP_MAX_RETRY_INTERVAL
;
1573 n
->retryPortMap
= m
->timenow
+ NATMAP_MAX_RETRY_INTERVAL
;
1574 // No need to set m->NextScheduledNATOp here, since we're only ever extending the m->retryPortMap time
1575 if (err
== NATErr_Refused
) n
->NewResult
= mStatus_NATPortMappingDisabled
;
1576 else if (err
> NATErr_None
&& err
<= NATErr_Opcode
) n
->NewResult
= mStatus_NATPortMappingUnsupported
;
1580 if (lease
> 999999999UL / mDNSPlatformOneSecond
)
1581 lease
= 999999999UL / mDNSPlatformOneSecond
;
1582 n
->ExpiryTime
= NonZeroTime(m
->timenow
+ lease
* mDNSPlatformOneSecond
);
1584 if (!mDNSSameIPPort(n
->RequestedPort
, extport
))
1585 LogOperation("natTraversalHandlePortMapReply: public port changed from %d to %d", mDNSVal16(n
->RequestedPort
), mDNSVal16(extport
));
1587 n
->InterfaceID
= InterfaceID
;
1588 n
->RequestedPort
= extport
;
1590 LogOperation("natTraversalHandlePortMapReply %p %s Internal Port %d External Port %d", n
,
1591 n
->Protocol
== NATOp_MapUDP
? "UDP Response" :
1592 n
->Protocol
== NATOp_MapTCP
? "TCP Response" : "?", mDNSVal16(n
->IntPort
), mDNSVal16(n
->RequestedPort
));
1594 NATSetNextRenewalTime(m
, n
); // Got our port mapping; now set timer to renew it at halfway point
1595 m
->NextScheduledNATOp
= m
->timenow
; // May need to invoke client callback immediately
1599 // Must be called with the mDNS_Lock held
1600 mDNSexport mStatus
mDNS_StartNATOperation_internal(mDNS
*const m
, NATTraversalInfo
*traversal
)
1602 NATTraversalInfo
**n
;
1604 LogOperation("mDNS_StartNATOperation_internal %d %d %d %d",
1605 traversal
->Protocol
, mDNSVal16(traversal
->IntPort
), mDNSVal16(traversal
->RequestedPort
), traversal
->NATLease
);
1607 // Note: It important that new traversal requests are appended at the *end* of the list, not prepended at the start
1608 n
= &m
->NATTraversals
;
1609 while (*n
&& *n
!= traversal
) n
=&(*n
)->next
;
1610 if (*n
) { LogMsg("Error! Tried to add a NAT traversal that's already in the active list"); return(mStatus_AlreadyRegistered
); }
1612 // Initialize necessary fields
1613 traversal
->next
= mDNSNULL
;
1614 traversal
->ExpiryTime
= 0;
1615 traversal
->retryInterval
= NATMAP_INIT_RETRY
;
1616 traversal
->retryPortMap
= m
->timenow
;
1617 traversal
->NewResult
= mStatus_NoError
;
1618 traversal
->ExternalAddress
= onesIPv4Addr
;
1619 traversal
->ExternalPort
= zeroIPPort
;
1620 traversal
->Lifetime
= 0;
1621 traversal
->Result
= mStatus_NoError
;
1623 // set default lease if necessary
1624 if (!traversal
->NATLease
) traversal
->NATLease
= NATMAP_DEFAULT_LEASE
;
1626 #ifdef _LEGACY_NAT_TRAVERSAL_
1627 mDNSPlatformMemZero(&traversal
->tcpInfo
, sizeof(traversal
->tcpInfo
));
1628 #endif _LEGACY_NAT_TRAVERSAL_
1630 if (!m
->NATTraversals
) // If this is our first NAT request, kick off an address request too
1632 m
->retryGetAddr
= m
->timenow
;
1633 m
->retryIntervalGetAddr
= NATMAP_INIT_RETRY
;
1636 m
->NextScheduledNATOp
= m
->timenow
; // This will always trigger sending the packet ASAP, and generate client callback if necessary
1638 *n
= traversal
; // Append new NATTraversalInfo to the end of our list
1640 return(mStatus_NoError
);
1643 // Must be called with the mDNS_Lock held
1644 mDNSexport mStatus
mDNS_StopNATOperation_internal(mDNS
*m
, NATTraversalInfo
*traversal
)
1646 NATTraversalInfo
**ptr
= &m
->NATTraversals
;
1648 while (*ptr
&& *ptr
!= traversal
) ptr
=&(*ptr
)->next
;
1649 if (*ptr
) *ptr
= (*ptr
)->next
; // If we found it, cut this NATTraversalInfo struct from our list
1652 LogMsg("mDNS_StopNATOperation: NATTraversalInfo %p not found in list", traversal
);
1653 return(mStatus_BadReferenceErr
);
1656 LogOperation("mDNS_StopNATOperation_internal %d %d %d %d",
1657 traversal
->Protocol
, mDNSVal16(traversal
->IntPort
), mDNSVal16(traversal
->RequestedPort
), traversal
->NATLease
);
1659 if (m
->CurrentNATTraversal
== traversal
)
1660 m
->CurrentNATTraversal
= m
->CurrentNATTraversal
->next
;
1662 if (traversal
->ExpiryTime
)
1664 traversal
->NATLease
= 0;
1665 traversal
->retryInterval
= 0;
1666 uDNS_SendNATMsg(m
, traversal
);
1668 // 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
1669 #ifdef _LEGACY_NAT_TRAVERSAL_
1671 mStatus err
= LNT_UnmapPort(m
, traversal
);
1672 if (err
) LogMsg("Legacy NAT Traversal - unmap request failed with error %ld", err
);
1674 #endif // _LEGACY_NAT_TRAVERSAL_
1675 return(mStatus_NoError
);
1678 mDNSexport mStatus
mDNS_StartNATOperation(mDNS
*m
, NATTraversalInfo
*traversal
)
1682 status
= mDNS_StartNATOperation_internal(m
, traversal
);
1687 mDNSexport mStatus
mDNS_StopNATOperation(mDNS
*m
, NATTraversalInfo
*traversal
)
1691 status
= mDNS_StopNATOperation_internal(m
, traversal
);
1696 // ***************************************************************************
1697 #if COMPILER_LIKES_PRAGMA_MARK
1699 #pragma mark - Long-Lived Queries
1702 // Lock must be held -- otherwise m->timenow is undefined
1703 mDNSlocal
void StartLLQPolling(mDNS
*const m
, DNSQuestion
*q
)
1705 LogOperation("StartLLQPolling: %##s", q
->qname
.c
);
1706 q
->state
= LLQ_Poll
;
1707 q
->ThisQInterval
= INIT_UCAST_POLL_INTERVAL
;
1708 // We want to send our poll query ASAP, but the "+ 1" is because if we set the time to now,
1709 // we risk causing spurious "SendQueries didn't send all its queries" log messages
1710 q
->LastQTime
= m
->timenow
- q
->ThisQInterval
+ 1;
1711 SetNextQueryTime(m
, q
);
1712 #if APPLE_OSX_mDNSResponder
1713 UpdateAutoTunnelDomainStatuses(m
);
1717 mDNSlocal mDNSu8
*putLLQ(DNSMessage
*const msg
, mDNSu8
*ptr
, const DNSQuestion
*const question
, const LLQOptData
*const data
, mDNSBool includeQuestion
)
1720 ResourceRecord
*opt
= &rr
.resrec
;
1723 //!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section
1724 if (includeQuestion
)
1726 ptr
= putQuestion(msg
, ptr
, msg
->data
+ AbsoluteMaxDNSMessageData
, &question
->qname
, question
->qtype
, question
->qclass
);
1727 if (!ptr
) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL
; }
1729 // locate OptRR if it exists, set pointer to end
1730 // !!!KRS implement me
1732 // format opt rr (fields not specified are zero-valued)
1733 mDNS_SetupResourceRecord(&rr
, mDNSNULL
, mDNSInterface_Any
, kDNSType_OPT
, kStandardTTL
, kDNSRecordTypeKnownUnique
, mDNSNULL
, mDNSNULL
);
1734 opt
->rdlength
= LLQ_OPT_RDLEN
;
1735 opt
->rdestimate
= LLQ_OPT_RDLEN
;
1737 optRD
= &rr
.resrec
.rdata
->u
.opt
;
1738 optRD
->opt
= kDNSOpt_LLQ
;
1739 optRD
->optlen
= LLQ_OPTLEN
;
1740 optRD
->OptData
.llq
= *data
;
1741 ptr
= PutResourceRecordTTLJumbo(msg
, ptr
, &msg
->h
.numAdditionals
, opt
, 0);
1742 if (!ptr
) { LogMsg("ERROR: putLLQ - PutResourceRecordTTLJumbo"); return mDNSNULL
; }
1747 // Normally we'd just request event packets be sent directly to m->LLQNAT.ExternalPort, except...
1748 // with LLQs over TLS/TCP we're doing a weird thing where instead of requesting packets be sent to ExternalAddress:ExternalPort
1749 // we're requesting that packets be sent to ExternalPort, but at the source address of our outgoing TCP connection.
1750 // Normally, after going through the NAT gateway, the source address of our outgoing TCP connection is the same as ExternalAddress,
1751 // so this is fine, except when the TCP connection ends up going over a VPN tunnel instead.
1752 // 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
1753 // LLQ server to send events to us directly at port 5353 on that address, instead of at our mapped external NAT port.
1755 mDNSlocal mDNSu16
GetLLQEventPort(const mDNS
*const m
, const mDNSAddr
*const dst
)
1758 mDNSPlatformSourceAddrForDest(&src
, dst
);
1759 //LogMsg("GetLLQEventPort: src %#a for dst %#a (%d)", &src, dst, mDNSv4AddrIsRFC1918(&src.ip.v4) ? mDNSVal16(m->LLQNAT.ExternalPort) : 0);
1760 return(mDNSv4AddrIsRFC1918(&src
.ip
.v4
) ? mDNSVal16(m
->LLQNAT
.ExternalPort
) : mDNSVal16(MulticastDNSPort
));
1763 // Normally called with llq set.
1764 // May be called with llq NULL, when retransmitting a lost Challenge Response
1765 mDNSlocal
void sendChallengeResponse(mDNS
*const m
, DNSQuestion
*const q
, const LLQOptData
*llq
)
1767 mDNSu8
*responsePtr
= m
->omsg
.data
;
1770 if (q
->ntries
++ == kLLQ_MAX_TRIES
)
1772 LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s", kLLQ_MAX_TRIES
, q
->qname
.c
);
1773 StartLLQPolling(m
,q
);
1777 if (!llq
) // Retransmission: need to make a new LLQOptData
1779 llqBuf
.vers
= kLLQ_Vers
;
1780 llqBuf
.llqOp
= kLLQOp_Setup
;
1781 llqBuf
.err
= LLQErr_NoError
; // Don't need to tell server UDP notification port when sending over UDP
1783 llqBuf
.llqlease
= q
->ReqLease
;
1787 q
->LastQTime
= m
->timenow
;
1788 q
->ThisQInterval
= q
->tcp
? 0 : (kLLQ_INIT_RESEND
* q
->ntries
* mDNSPlatformOneSecond
); // If using TCP, don't need to retransmit
1789 SetNextQueryTime(m
, q
);
1791 // To simulate loss of challenge response packet, uncomment line below
1792 //if (q->ntries == 1) return;
1794 InitializeDNSMessage(&m
->omsg
.h
, q
->TargetQID
, uQueryFlags
);
1795 responsePtr
= putQuestion(&m
->omsg
, responsePtr
, m
->omsg
.data
+ AbsoluteMaxDNSMessageData
, &q
->qname
, q
->qtype
, q
->qclass
);
1796 if (responsePtr
) responsePtr
= putLLQ(&m
->omsg
, responsePtr
, q
, llq
, mDNSfalse
);
1799 mStatus err
= mDNSSendDNSMessage(m
, &m
->omsg
, responsePtr
, mDNSInterface_Any
, q
->LocalSocket
, &q
->servAddr
, q
->servPort
, q
->tcp
? q
->tcp
->sock
: mDNSNULL
, q
->AuthInfo
);
1802 LogMsg("sendChallengeResponse: mDNSSendDNSMessage%s failed: %d", q
->tcp
? " (TCP)" : "", err
);
1803 if (q
->tcp
) { DisposeTCPConn(q
->tcp
); q
->tcp
= mDNSNULL
; }
1806 else StartLLQPolling(m
,q
);
1809 mDNSlocal
void SetLLQTimer(mDNS
*const m
, DNSQuestion
*const q
, const LLQOptData
*const llq
)
1811 mDNSs32 lease
= (mDNSs32
)llq
->llqlease
* mDNSPlatformOneSecond
;
1812 q
->ReqLease
= llq
->llqlease
;
1813 q
->LastQTime
= m
->timenow
;
1814 q
->expire
= m
->timenow
+ lease
;
1815 q
->ThisQInterval
= lease
/2 + mDNSRandom(lease
/10);
1816 debugf("SetLLQTimer setting %##s (%s) to %d %d", q
->qname
.c
, DNSTypeName(q
->qtype
), lease
/mDNSPlatformOneSecond
, q
->ThisQInterval
/mDNSPlatformOneSecond
);
1817 SetNextQueryTime(m
, q
);
1820 mDNSlocal
void recvSetupResponse(mDNS
*const m
, mDNSu8 rcode
, DNSQuestion
*const q
, const LLQOptData
*const llq
)
1822 if (rcode
&& rcode
!= kDNSFlag1_RC_NXDomain
)
1823 { LogMsg("ERROR: recvSetupResponse %##s (%s) - rcode && rcode != kDNSFlag1_RC_NXDomain", q
->qname
.c
, DNSTypeName(q
->qtype
)); return; }
1825 if (llq
->llqOp
!= kLLQOp_Setup
)
1826 { LogMsg("ERROR: recvSetupResponse %##s (%s) - bad op %d", q
->qname
.c
, DNSTypeName(q
->qtype
), llq
->llqOp
); return; }
1828 if (llq
->vers
!= kLLQ_Vers
)
1829 { LogMsg("ERROR: recvSetupResponse %##s (%s) - bad vers %d", q
->qname
.c
, DNSTypeName(q
->qtype
), llq
->vers
); return; }
1831 if (q
->state
== LLQ_InitialRequest
)
1833 //LogOperation("Got LLQ_InitialRequest");
1835 if (llq
->err
) { LogMsg("recvSetupResponse - received llq->err %d from server", llq
->err
); StartLLQPolling(m
,q
); return; }
1837 if (q
->ReqLease
!= llq
->llqlease
)
1838 debugf("recvSetupResponse: requested lease %lu, granted lease %lu", q
->ReqLease
, llq
->llqlease
);
1840 // cache expiration in case we go to sleep before finishing setup
1841 q
->ReqLease
= llq
->llqlease
;
1842 q
->expire
= m
->timenow
+ ((mDNSs32
)llq
->llqlease
* mDNSPlatformOneSecond
);
1845 q
->state
= LLQ_SecondaryRequest
;
1847 q
->ntries
= 0; // first attempt to send response
1848 sendChallengeResponse(m
, q
, llq
);
1850 else if (q
->state
== LLQ_SecondaryRequest
)
1852 //LogOperation("Got LLQ_SecondaryRequest");
1854 // Fix this immediately if not sooner. Copy the id from the LLQOptData into our DNSQuestion struct. This is only
1855 // an issue for private LLQs, because we skip parts 2 and 3 of the handshake. This is related to a bigger
1856 // problem of the current implementation of TCP LLQ setup: we're not handling state transitions correctly
1857 // if the server sends back SERVFULL or STATIC.
1860 LogOperation("Private LLQ_SecondaryRequest; copying id %08X%08X", llq
->id
.l
[0], llq
->id
.l
[1]);
1864 if (llq
->err
) { LogMsg("ERROR: recvSetupResponse %##s (%s) code %d from server", q
->qname
.c
, DNSTypeName(q
->qtype
), llq
->err
); StartLLQPolling(m
,q
); return; }
1865 if (!mDNSSameOpaque64(&q
->id
, &llq
->id
))
1866 { LogMsg("recvSetupResponse - ID changed. discarding"); return; } // this can happen rarely (on packet loss + reordering)
1867 q
->state
= LLQ_Established
;
1869 SetLLQTimer(m
, q
, llq
);
1870 #if APPLE_OSX_mDNSResponder
1871 UpdateAutoTunnelDomainStatuses(m
);
1876 mDNSexport uDNS_LLQType
uDNS_recvLLQResponse(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
, const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
)
1878 DNSQuestion pktQ
, *q
;
1879 if (msg
->h
.numQuestions
&& getQuestion(msg
, msg
->data
, end
, 0, &pktQ
))
1881 const rdataOPT
*opt
= GetLLQOptData(m
, msg
, end
);
1883 for (q
= m
->Questions
; q
; q
= q
->next
)
1885 if (!mDNSOpaque16IsZero(q
->TargetQID
) && q
->LongLived
&& q
->qtype
== pktQ
.qtype
&& q
->qnamehash
== pktQ
.qnamehash
&& SameDomainName(&q
->qname
, &pktQ
.qname
))
1887 debugf("uDNS_recvLLQResponse found %##s (%s) %d %#a %#a %X %X %X %X %d",
1888 q
->qname
.c
, DNSTypeName(q
->qtype
), q
->state
, srcaddr
, &q
->servAddr
,
1889 opt
->OptData
.llq
.id
.l
[0], opt
->OptData
.llq
.id
.l
[1], q
->id
.l
[0], q
->id
.l
[1], opt
->OptData
.llq
.llqOp
);
1890 if (q
->state
== LLQ_Poll
) debugf("uDNS_LLQ_Events: q->state == LLQ_Poll msg->h.id %d q->TargetQID %d", mDNSVal16(msg
->h
.id
), mDNSVal16(q
->TargetQID
));
1891 if (q
->state
== LLQ_Poll
&& mDNSSameOpaque16(msg
->h
.id
, q
->TargetQID
))
1893 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
1894 LogOperation("uDNS_recvLLQResponse got poll response; moving to LLQ_InitialRequest for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
1895 q
->state
= LLQ_InitialRequest
;
1896 q
->servPort
= zeroIPPort
; // Clear servPort so that startLLQHandshake will retry the GetZoneData processing
1897 q
->ThisQInterval
= LLQ_POLL_INTERVAL
+ mDNSRandom(LLQ_POLL_INTERVAL
/10); // Retry LLQ setup in approx 15 minutes
1898 q
->LastQTime
= m
->timenow
;
1899 SetNextQueryTime(m
, q
);
1900 return uDNS_LLQ_Entire
; // uDNS_LLQ_Entire means flush stale records; assume a large effective TTL
1902 // Note: In LLQ Event packets, the msg->h.id does not match our q->TargetQID, because in that case the msg->h.id nonce is selected by the server
1903 else if (opt
&& q
->state
== LLQ_Established
&& opt
->OptData
.llq
.llqOp
== kLLQOp_Event
&& mDNSSameOpaque64(&opt
->OptData
.llq
.id
, &q
->id
))
1906 //debugf("Sending LLQ ack for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
1907 InitializeDNSMessage(&m
->omsg
.h
, msg
->h
.id
, ResponseFlags
);
1908 ackEnd
= putLLQ(&m
->omsg
, m
->omsg
.data
, mDNSNULL
, &opt
->OptData
.llq
, mDNSfalse
);
1909 if (ackEnd
) mDNSSendDNSMessage(m
, &m
->omsg
, ackEnd
, mDNSInterface_Any
, q
->LocalSocket
, srcaddr
, srcport
, mDNSNULL
, mDNSNULL
);
1910 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
1911 debugf("uDNS_LLQ_Events: q->state == LLQ_Established msg->h.id %d q->TargetQID %d", mDNSVal16(msg
->h
.id
), mDNSVal16(q
->TargetQID
));
1912 return uDNS_LLQ_Events
;
1914 if (opt
&& mDNSSameOpaque16(msg
->h
.id
, q
->TargetQID
))
1916 if (q
->state
== LLQ_Established
&& opt
->OptData
.llq
.llqOp
== kLLQOp_Refresh
&& mDNSSameOpaque64(&opt
->OptData
.llq
.id
, &q
->id
) && msg
->h
.numAdditionals
&& !msg
->h
.numAnswers
)
1918 if (opt
->OptData
.llq
.err
!= LLQErr_NoError
) LogMsg("recvRefreshReply: received error %d from server", opt
->OptData
.llq
.err
);
1921 //LogOperation("Received refresh confirmation ntries %d for %##s (%s)", q->ntries, q->qname.c, DNSTypeName(q->qtype));
1922 GrantCacheExtensions(m
, q
, opt
->OptData
.llq
.llqlease
);
1923 SetLLQTimer(m
, q
, &opt
->OptData
.llq
);
1926 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
1927 return uDNS_LLQ_Ignore
;
1929 if (q
->state
< LLQ_Established
&& mDNSSameAddress(srcaddr
, &q
->servAddr
))
1931 LLQ_State oldstate
= q
->state
;
1932 recvSetupResponse(m
, msg
->h
.flags
.b
[1] & kDNSFlag1_RC_Mask
, q
, &opt
->OptData
.llq
);
1933 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
1934 // We have a protocol anomaly here in the LLQ definition.
1935 // Both the challenge packet from the server and the ack+answers packet have opt->OptData.llq.llqOp == kLLQOp_Setup.
1936 // However, we need to treat them differently:
1937 // The challenge packet has no answers in it, and tells us nothing about whether our cache entries
1938 // are still valid, so this packet should not cause us to do anything that messes with our cache.
1939 // The ack+answers packet gives us the whole truth, so we should handle it by updating our cache
1940 // to match the answers in the packet, and only the answers in the packet.
1941 return (oldstate
== LLQ_SecondaryRequest
? uDNS_LLQ_Entire
: uDNS_LLQ_Ignore
);
1946 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
1948 return uDNS_LLQ_Not
;
1951 // Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
1952 struct TCPSocket_struct
{ TCPSocketFlags flags
; /* ... */ };
1954 // tcpCallback is called to handle events (e.g. connection opening and data reception) on TCP connections for
1955 // Private DNS operations -- private queries, private LLQs, private record updates and private service updates
1956 mDNSlocal
void tcpCallback(TCPSocket
*sock
, void *context
, mDNSBool ConnectionEstablished
, mStatus err
)
1958 tcpInfo_t
*tcpInfo
= (tcpInfo_t
*)context
;
1959 mDNSBool closed
= mDNSfalse
;
1960 mDNS
*m
= tcpInfo
->m
;
1961 DNSQuestion
*const q
= tcpInfo
->question
;
1962 tcpInfo_t
**backpointer
=
1964 tcpInfo
->srs
? &tcpInfo
->srs
->tcp
:
1965 tcpInfo
->rr
? &tcpInfo
->rr
->tcp
: mDNSNULL
;
1966 if (backpointer
&& *backpointer
!= tcpInfo
)
1967 LogMsg("tcpCallback: %d backpointer %p incorrect tcpInfo %p question %p srs %p rr %p",
1968 mDNSPlatformTCPGetFD(tcpInfo
->sock
), *backpointer
, tcpInfo
, q
, tcpInfo
->srs
, tcpInfo
->rr
);
1972 if (ConnectionEstablished
)
1974 mDNSu8
*end
= ((mDNSu8
*) &tcpInfo
->request
) + tcpInfo
->requestLen
;
1975 DomainAuthInfo
*AuthInfo
;
1977 // Defensive coding for <rdar://problem/5546824> Crash in mDNSResponder at GetAuthInfoForName_internal + 366
1978 // 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
1979 if (tcpInfo
->srs
&& tcpInfo
->srs
->RR_SRV
.resrec
.name
!= &tcpInfo
->srs
->RR_SRV
.namestorage
)
1980 LogMsg("tcpCallback: ERROR: tcpInfo->srs->RR_SRV.resrec.name %p != &tcpInfo->srs->RR_SRV.namestorage %p",
1981 tcpInfo
->srs
->RR_SRV
.resrec
.name
, &tcpInfo
->srs
->RR_SRV
.namestorage
);
1982 if (tcpInfo
->rr
&& tcpInfo
->rr
->resrec
.name
!= &tcpInfo
->rr
->namestorage
)
1983 LogMsg("tcpCallback: ERROR: tcpInfo->rr->resrec.name %p != &tcpInfo->rr->namestorage %p",
1984 tcpInfo
->rr
->resrec
.name
, &tcpInfo
->rr
->namestorage
);
1985 if (tcpInfo
->srs
&& tcpInfo
->srs
->RR_SRV
.resrec
.name
!= &tcpInfo
->srs
->RR_SRV
.namestorage
) return;
1986 if (tcpInfo
->rr
&& tcpInfo
->rr
-> resrec
.name
!= &tcpInfo
->rr
-> namestorage
) return;
1988 AuthInfo
= tcpInfo
->srs
? GetAuthInfoForName(m
, tcpInfo
->srs
->RR_SRV
.resrec
.name
) :
1989 tcpInfo
->rr
? GetAuthInfoForName(m
, tcpInfo
->rr
->resrec
.name
) : mDNSNULL
;
1991 // connection is established - send the message
1992 if (q
&& q
->LongLived
&& q
->state
== LLQ_Established
)
1994 end
= ((mDNSu8
*) &tcpInfo
->request
) + tcpInfo
->requestLen
;
1996 else if (q
&& q
->LongLived
&& q
->state
!= LLQ_Poll
&& !mDNSIPPortIsZero(m
->LLQNAT
.ExternalPort
))
1999 // If we have a NAT port mapping, ExternalPort is the external port
2000 // If we have a routable address so we don't need a port mapping, ExternalPort is the same as our own internal port
2001 // If we need a NAT port mapping but can't get one, then ExternalPort is zero
2002 LLQOptData llqData
; // set llq rdata
2003 llqData
.vers
= kLLQ_Vers
;
2004 llqData
.llqOp
= kLLQOp_Setup
;
2005 llqData
.err
= GetLLQEventPort(m
, &tcpInfo
->Addr
); // We're using TCP; tell server what UDP port to send notifications to
2006 LogOperation("tcpCallback: eventPort %d", llqData
.err
);
2007 llqData
.id
= zeroOpaque64
;
2008 llqData
.llqlease
= kLLQ_DefLease
;
2009 InitializeDNSMessage(&tcpInfo
->request
.h
, q
->TargetQID
, uQueryFlags
);
2010 end
= putLLQ(&tcpInfo
->request
, tcpInfo
->request
.data
, q
, &llqData
, mDNStrue
);
2011 if (!end
) { LogMsg("ERROR: tcpCallback - putLLQ"); err
= mStatus_UnknownErr
; goto exit
; }
2012 AuthInfo
= q
->AuthInfo
; // Need to add TSIG to this message
2016 InitializeDNSMessage(&tcpInfo
->request
.h
, q
->TargetQID
, uQueryFlags
);
2017 end
= putQuestion(&tcpInfo
->request
, tcpInfo
->request
.data
, tcpInfo
->request
.data
+ AbsoluteMaxDNSMessageData
, &q
->qname
, q
->qtype
, q
->qclass
);
2018 AuthInfo
= q
->AuthInfo
; // Need to add TSIG to this message
2021 err
= mDNSSendDNSMessage(m
, &tcpInfo
->request
, end
, mDNSInterface_Any
, mDNSNULL
, &tcpInfo
->Addr
, tcpInfo
->Port
, sock
, AuthInfo
);
2022 if (err
) { debugf("ERROR: tcpCallback: mDNSSendDNSMessage - %ld", err
); err
= mStatus_UnknownErr
; goto exit
; }
2024 // Record time we sent this question
2028 q
->LastQTime
= m
->timenow
;
2029 if (q
->ThisQInterval
< (256 * mDNSPlatformOneSecond
)) // Now we have a TCP connection open, make sure we wait at least 256 seconds before retrying
2030 q
->ThisQInterval
= (256 * mDNSPlatformOneSecond
);
2031 SetNextQueryTime(m
, q
);
2038 if (tcpInfo
->nread
< 2) // First read the two-byte length preceeding the DNS message
2040 mDNSu8
*lenptr
= (mDNSu8
*)&tcpInfo
->replylen
;
2041 n
= mDNSPlatformReadTCP(sock
, lenptr
+ tcpInfo
->nread
, 2 - tcpInfo
->nread
, &closed
);
2042 if (n
< 0) { LogMsg("ERROR: tcpCallback - attempt to read message length failed (%d)", n
); err
= mStatus_ConnFailed
; goto exit
; }
2045 // It's perfectly fine for this socket to close after the first reply. The server might
2046 // be sending gratuitous replies using UDP and doesn't have a need to leave the TCP socket open.
2047 // We'll only log this event if we've never received a reply before.
2048 // BIND 9 appears to close an idle connection after 30 seconds.
2049 if (tcpInfo
->numReplies
== 0) LogMsg("ERROR: socket closed prematurely tcpInfo->nread = %d", tcpInfo
->nread
);
2050 err
= mStatus_ConnFailed
;
2054 tcpInfo
->nread
+= n
;
2055 if (tcpInfo
->nread
< 2) goto exit
;
2057 tcpInfo
->replylen
= (mDNSu16
)((mDNSu16
)lenptr
[0] << 8 | lenptr
[1]);
2058 if (tcpInfo
->replylen
< sizeof(DNSMessageHeader
))
2059 { LogMsg("ERROR: tcpCallback - length too short (%d bytes)", tcpInfo
->replylen
); err
= mStatus_UnknownErr
; goto exit
; }
2061 tcpInfo
->reply
= mDNSPlatformMemAllocate(tcpInfo
->replylen
);
2062 if (!tcpInfo
->reply
) { LogMsg("ERROR: tcpCallback - malloc failed"); err
= mStatus_NoMemoryErr
; goto exit
; }
2065 n
= mDNSPlatformReadTCP(sock
, ((char *)tcpInfo
->reply
) + (tcpInfo
->nread
- 2), tcpInfo
->replylen
- (tcpInfo
->nread
- 2), &closed
);
2067 if (n
< 0) { LogMsg("ERROR: tcpCallback - read returned %d", n
); err
= mStatus_ConnFailed
; goto exit
; }
2068 else if (closed
) { LogMsg("ERROR: socket closed prematurely %d", tcpInfo
->nread
); err
= mStatus_ConnFailed
; goto exit
; }
2070 tcpInfo
->nread
+= n
;
2072 if ((tcpInfo
->nread
- 2) == tcpInfo
->replylen
)
2074 AuthRecord
*rr
= tcpInfo
->rr
;
2075 DNSMessage
*reply
= tcpInfo
->reply
;
2076 mDNSu8
*end
= (mDNSu8
*)tcpInfo
->reply
+ tcpInfo
->replylen
;
2077 mDNSAddr Addr
= tcpInfo
->Addr
;
2078 mDNSIPPort Port
= tcpInfo
->Port
;
2079 tcpInfo
->numReplies
++;
2080 tcpInfo
->reply
= mDNSNULL
; // Detach reply buffer from tcpInfo_t, to make sure client callback can't cause it to be disposed
2082 tcpInfo
->replylen
= 0;
2084 // If we're going to dispose this connection, do it FIRST, before calling client callback
2085 // Note: Sleep code depends on us clearing *backpointer here -- it uses the clearing of rr->tcp and srs->tcp
2086 // as the signal that the DNS deregistration operation with the server has completed, and the machine may now sleep
2088 if (!q
|| !q
->LongLived
|| m
->SleepState
)
2089 { *backpointer
= mDNSNULL
; DisposeTCPConn(tcpInfo
); }
2091 if (rr
&& rr
->resrec
.RecordType
== kDNSRecordTypeDeregistering
)
2094 LogOperation("tcpCallback: CompleteDeregistration %s", ARDisplayString(m
, rr
));
2095 CompleteDeregistration(m
, rr
); // Don't touch rr after this
2099 mDNSCoreReceive(m
, reply
, end
, &Addr
, Port
, (sock
->flags
& kTCPSocketFlags_UseTLS
) ? (mDNSAddr
*)1 : mDNSNULL
, zeroIPPort
, 0);
2100 // USE CAUTION HERE: Invoking mDNSCoreReceive may have caused the environment to change, including canceling this operation itself
2102 mDNSPlatformMemFree(reply
);
2111 // Clear client backpointer FIRST -- that way if one of the callbacks cancels its operation
2112 // we won't end up double-disposing our tcpInfo_t
2113 if (backpointer
) *backpointer
= mDNSNULL
;
2115 mDNS_Lock(m
); // Need to grab the lock to get m->timenow
2119 if (q
->ThisQInterval
== 0 || q
->LastQTime
+ q
->ThisQInterval
- m
->timenow
> MAX_UCAST_POLL_INTERVAL
)
2121 q
->LastQTime
= m
->timenow
;
2122 q
->ThisQInterval
= MAX_UCAST_POLL_INTERVAL
;
2123 SetNextQueryTime(m
, q
);
2125 // ConnFailed may be actually okay. It just means that the server closed the connection but the LLQ may still be okay.
2126 // If the error isn't ConnFailed, then the LLQ is in bad shape.
2127 if (err
!= mStatus_ConnFailed
)
2129 if (q
->LongLived
&& q
->state
!= LLQ_Poll
) StartLLQPolling(m
, q
);
2133 if (tcpInfo
->rr
) SetRecordRetry(m
, tcpInfo
->rr
, mStatus_NoError
);
2135 if (tcpInfo
->srs
) SetRecordRetry(m
, &tcpInfo
->srs
->RR_SRV
, mStatus_NoError
);
2139 DisposeTCPConn(tcpInfo
);
2143 mDNSlocal tcpInfo_t
*MakeTCPConn(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
,
2144 TCPSocketFlags flags
, const mDNSAddr
*const Addr
, const mDNSIPPort Port
,
2145 DNSQuestion
*const question
, ServiceRecordSet
*const srs
, AuthRecord
*const rr
)
2148 mDNSIPPort srcport
= zeroIPPort
;
2149 tcpInfo_t
*info
= (tcpInfo_t
*)mDNSPlatformMemAllocate(sizeof(tcpInfo_t
));
2150 if (!info
) { LogMsg("ERROR: MakeTCP - memallocate failed"); return(mDNSNULL
); }
2151 mDNSPlatformMemZero(info
, sizeof(tcpInfo_t
));
2154 info
->sock
= mDNSPlatformTCPSocket(m
, flags
, &srcport
);
2155 info
->requestLen
= 0;
2156 info
->question
= question
;
2161 info
->reply
= mDNSNULL
;
2164 info
->numReplies
= 0;
2168 info
->requestLen
= (int) (end
- ((mDNSu8
*)msg
));
2169 mDNSPlatformMemCopy(&info
->request
, msg
, info
->requestLen
);
2172 if (!info
->sock
) { LogMsg("SendServiceRegistration: unable to create TCP socket"); mDNSPlatformMemFree(info
); return(mDNSNULL
); }
2173 err
= mDNSPlatformTCPConnect(info
->sock
, Addr
, Port
, 0, tcpCallback
, info
);
2175 // Probably suboptimal here.
2176 // Instead of returning mDNSNULL here on failure, we should probably invoke the callback with an error code.
2177 // That way clients can put all the error handling and retry/recovery code in one place,
2178 // instead of having to handle immediate errors in one place and async errors in another.
2179 // Also: "err == mStatus_ConnEstablished" probably never happens.
2181 // Don't need to log "connection failed" in customer builds -- it happens quite often during sleep, wake, configuration changes, etc.
2182 if (err
== mStatus_ConnEstablished
) { tcpCallback(info
->sock
, info
, mDNStrue
, mStatus_NoError
); }
2183 else if (err
!= mStatus_ConnPending
) { LogOperation("MakeTCPConnection: connection failed"); DisposeTCPConn(info
); return(mDNSNULL
); }
2187 mDNSexport
void DisposeTCPConn(struct tcpInfo_t
*tcp
)
2189 mDNSPlatformTCPCloseConnection(tcp
->sock
);
2190 if (tcp
->reply
) mDNSPlatformMemFree(tcp
->reply
);
2191 mDNSPlatformMemFree(tcp
);
2194 // Lock must be held
2195 mDNSexport
void startLLQHandshake(mDNS
*m
, DNSQuestion
*q
)
2197 if (mDNSIPv4AddressIsOnes(m
->LLQNAT
.ExternalAddress
))
2199 LogOperation("startLLQHandshake: waiting for NAT status for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
2200 q
->ThisQInterval
= LLQ_POLL_INTERVAL
+ mDNSRandom(LLQ_POLL_INTERVAL
/10); // Retry in approx 15 minutes
2201 q
->LastQTime
= m
->timenow
;
2202 SetNextQueryTime(m
, q
);
2206 if (mDNSIPPortIsZero(m
->LLQNAT
.ExternalPort
))
2208 LogOperation("startLLQHandshake: Cannot receive inbound packets; will poll for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
2209 StartLLQPolling(m
, q
);
2213 if (mDNSIPPortIsZero(q
->servPort
))
2215 LogOperation("startLLQHandshake: StartGetZoneData for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
2216 q
->ThisQInterval
= LLQ_POLL_INTERVAL
+ mDNSRandom(LLQ_POLL_INTERVAL
/10); // Retry in approx 15 minutes
2217 q
->LastQTime
= m
->timenow
;
2218 SetNextQueryTime(m
, q
);
2219 q
->servAddr
= zeroAddr
;
2220 q
->servPort
= zeroIPPort
;
2221 if (q
->nta
) CancelGetZoneData(m
, q
->nta
);
2222 q
->nta
= StartGetZoneData(m
, &q
->qname
, ZoneServiceLLQ
, LLQGotZoneData
, q
);
2228 if (q
->tcp
) LogOperation("startLLQHandshake: Disposing existing TCP connection for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
2229 if (q
->tcp
) DisposeTCPConn(q
->tcp
);
2230 q
->tcp
= MakeTCPConn(m
, mDNSNULL
, mDNSNULL
, kTCPSocketFlags_UseTLS
, &q
->servAddr
, q
->servPort
, q
, mDNSNULL
, mDNSNULL
);
2232 q
->ThisQInterval
= mDNSPlatformOneSecond
* 5; // If TCP failed (transient networking glitch) try again in five seconds
2235 q
->state
= LLQ_SecondaryRequest
; // Right now, for private DNS, we skip the four-way LLQ handshake
2236 q
->ReqLease
= kLLQ_DefLease
;
2237 q
->ThisQInterval
= 0;
2239 q
->LastQTime
= m
->timenow
;
2240 SetNextQueryTime(m
, q
);
2244 LogOperation("startLLQHandshake m->AdvertisedV4 %#a%s Server %#a:%d%s %##s (%s)",
2245 &m
->AdvertisedV4
, mDNSv4AddrIsRFC1918(&m
->AdvertisedV4
.ip
.v4
) ? " (RFC 1918)" : "",
2246 &q
->servAddr
, mDNSVal16(q
->servPort
), mDNSAddrIsRFC1918(&q
->servAddr
) ? " (RFC 1918)" : "",
2247 q
->qname
.c
, DNSTypeName(q
->qtype
));
2249 if (q
->ntries
++ >= kLLQ_MAX_TRIES
)
2251 LogMsg("startLLQHandshake: %d failed attempts for LLQ %##s Polling.", kLLQ_MAX_TRIES
, q
->qname
.c
);
2252 StartLLQPolling(m
, q
);
2260 llqData
.vers
= kLLQ_Vers
;
2261 llqData
.llqOp
= kLLQOp_Setup
;
2262 llqData
.err
= LLQErr_NoError
; // Don't need to tell server UDP notification port when sending over UDP
2263 llqData
.id
= zeroOpaque64
;
2264 llqData
.llqlease
= kLLQ_DefLease
;
2266 InitializeDNSMessage(&m
->omsg
.h
, q
->TargetQID
, uQueryFlags
);
2267 end
= putLLQ(&m
->omsg
, m
->omsg
.data
, q
, &llqData
, mDNStrue
);
2268 if (!end
) { LogMsg("ERROR: startLLQHandshake - putLLQ"); StartLLQPolling(m
,q
); return; }
2270 mDNSSendDNSMessage(m
, &m
->omsg
, end
, mDNSInterface_Any
, q
->LocalSocket
, &q
->servAddr
, q
->servPort
, mDNSNULL
, mDNSNULL
);
2272 // update question state
2273 q
->state
= LLQ_InitialRequest
;
2274 q
->ReqLease
= kLLQ_DefLease
;
2275 q
->ThisQInterval
= (kLLQ_INIT_RESEND
* mDNSPlatformOneSecond
);
2276 q
->LastQTime
= m
->timenow
;
2277 SetNextQueryTime(m
, q
);
2282 mDNSexport
const domainname
*GetServiceTarget(mDNS
*m
, ServiceRecordSet
*srs
)
2284 LogOperation("GetServiceTarget %##s", srs
->RR_SRV
.resrec
.name
->c
);
2286 if (!srs
->RR_SRV
.AutoTarget
) // If not automatically tracking this host's current name, just return the existing target
2287 return(&srs
->RR_SRV
.resrec
.rdata
->u
.srv
.target
);
2290 #if APPLE_OSX_mDNSResponder
2291 DomainAuthInfo
*AuthInfo
= GetAuthInfoForName_internal(m
, srs
->RR_SRV
.resrec
.name
);
2292 if (AuthInfo
&& AuthInfo
->AutoTunnel
)
2294 // If this AutoTunnel is not yet active, start it now (which entails activating its NAT Traversal request,
2295 // which will subsequently advertise the appropriate records when the NAT Traversal returns a result)
2296 if (!AuthInfo
->AutoTunnelNAT
.clientContext
&& m
->AutoTunnelHostAddr
.b
[0])
2297 SetupLocalAutoTunnelInterface_internal(m
);
2298 if (AuthInfo
->AutoTunnelHostRecord
.namestorage
.c
[0] == 0) return(mDNSNULL
);
2299 return(&AuthInfo
->AutoTunnelHostRecord
.namestorage
);
2302 #endif APPLE_OSX_mDNSResponder
2304 const int srvcount
= CountLabels(srs
->RR_SRV
.resrec
.name
);
2305 HostnameInfo
*besthi
= mDNSNULL
, *hi
;
2307 for (hi
= m
->Hostnames
; hi
; hi
= hi
->next
)
2308 if (hi
->arv4
.state
== regState_Registered
|| hi
->arv4
.state
== regState_Refresh
||
2309 hi
->arv6
.state
== regState_Registered
|| hi
->arv6
.state
== regState_Refresh
)
2311 int x
, hostcount
= CountLabels(&hi
->fqdn
);
2312 for (x
= hostcount
< srvcount
? hostcount
: srvcount
; x
> 0 && x
> best
; x
--)
2313 if (SameDomainName(SkipLeadingLabels(srs
->RR_SRV
.resrec
.name
, srvcount
- x
), SkipLeadingLabels(&hi
->fqdn
, hostcount
- x
)))
2314 { best
= x
; besthi
= hi
; }
2317 if (besthi
) return(&besthi
->fqdn
);
2319 if (m
->StaticHostname
.c
[0]) return(&m
->StaticHostname
);
2324 // Called with lock held
2325 mDNSlocal
void SendServiceRegistration(mDNS
*m
, ServiceRecordSet
*srs
)
2327 mDNSu8
*ptr
= m
->omsg
.data
;
2328 mDNSu8
*end
= (mDNSu8
*)&m
->omsg
+ sizeof(DNSMessage
);
2330 mStatus err
= mStatus_NoError
;
2331 const domainname
*target
;
2334 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
2335 LogMsg("SendServiceRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
2337 if (mDNSIPv4AddressIsZero(srs
->SRSUpdateServer
.ip
.v4
)) // Don't know our UpdateServer yet
2339 srs
->RR_SRV
.LastAPTime
= m
->timenow
;
2340 if (srs
->RR_SRV
.ThisAPInterval
< mDNSPlatformOneSecond
* 5)
2341 srs
->RR_SRV
.ThisAPInterval
= mDNSPlatformOneSecond
* 5;
2345 if (srs
->state
== regState_Registered
) srs
->state
= regState_Refresh
;
2347 id
= mDNS_NewMessageID(m
);
2348 InitializeDNSMessage(&m
->omsg
.h
, id
, UpdateReqFlags
);
2350 // setup resource records
2351 SetNewRData(&srs
->RR_PTR
.resrec
, mDNSNULL
, 0); // Update rdlength, rdestimate, rdatahash
2352 SetNewRData(&srs
->RR_TXT
.resrec
, mDNSNULL
, 0); // Update rdlength, rdestimate, rdatahash
2354 // replace port w/ NAT mapping if necessary
2355 if (srs
->RR_SRV
.AutoTarget
== Target_AutoHostAndNATMAP
&& !mDNSIPPortIsZero(srs
->NATinfo
.ExternalPort
))
2356 srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
= srs
->NATinfo
.ExternalPort
;
2358 // construct update packet
2360 ptr
= putZone(&m
->omsg
, ptr
, end
, &srs
->zone
, mDNSOpaque16fromIntVal(srs
->RR_SRV
.resrec
.rrclass
));
2361 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
2363 if (srs
->TestForSelfConflict
)
2365 // update w/ prereq that SRV already exist to make sure previous registration was ours, and delete any stale TXT records
2366 if (!(ptr
= PutResourceRecordTTLJumbo(&m
->omsg
, ptr
, &m
->omsg
.h
.mDNS_numPrereqs
, &srs
->RR_SRV
.resrec
, 0))) { err
= mStatus_UnknownErr
; goto exit
; }
2367 if (!(ptr
= putDeleteRRSet(&m
->omsg
, ptr
, srs
->RR_TXT
.resrec
.name
, srs
->RR_TXT
.resrec
.rrtype
))) { err
= mStatus_UnknownErr
; goto exit
; }
2370 else if (srs
->state
!= regState_Refresh
&& srs
->state
!= regState_UpdatePending
)
2372 // use SRV name for prereq
2373 //ptr = putPrereqNameNotInUse(srs->RR_SRV.resrec.name, &m->omsg, ptr, end);
2375 // For now, until we implement RFC 4701 (DHCID RR) to detect whether an existing record is someone else using the name, or just a
2376 // stale echo of our own previous registration before we changed our host name, we just overwrite whatever may have already been there
2377 ptr
= putDeleteRRSet(&m
->omsg
, ptr
, srs
->RR_SRV
.resrec
.name
, kDNSQType_ANY
);
2378 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
2381 //!!!KRS Need to do bounds checking and use TCP if it won't fit!!!
2382 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
; }
2384 for (i
= 0; i
< srs
->NumSubTypes
; i
++)
2385 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
; }
2387 if (srs
->state
== regState_UpdatePending
) // we're updating the txt record
2389 AuthRecord
*txt
= &srs
->RR_TXT
;
2391 SetNewRData(&txt
->resrec
, txt
->OrigRData
, txt
->OrigRDLen
);
2392 if (!(ptr
= putDeletionRecord(&m
->omsg
, ptr
, &srs
->RR_TXT
.resrec
))) { err
= mStatus_UnknownErr
; goto exit
; } // delete old rdata
2395 SetNewRData(&txt
->resrec
, txt
->InFlightRData
, txt
->InFlightRDLen
);
2396 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
; }
2399 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
; }
2401 target
= GetServiceTarget(m
, srs
);
2402 if (!target
|| target
->c
[0] == 0)
2404 LogOperation("SendServiceRegistration - no target for %##s", srs
->RR_SRV
.resrec
.name
->c
);
2405 srs
->state
= regState_NoTarget
;
2409 if (!SameDomainName(target
, &srs
->RR_SRV
.resrec
.rdata
->u
.srv
.target
))
2411 AssignDomainName(&srs
->RR_SRV
.resrec
.rdata
->u
.srv
.target
, target
);
2412 SetNewRData(&srs
->RR_SRV
.resrec
, mDNSNULL
, 0); // Update rdlength, rdestimate, rdatahash
2415 ptr
= PutResourceRecordTTLJumbo(&m
->omsg
, ptr
, &m
->omsg
.h
.mDNS_numUpdates
, &srs
->RR_SRV
.resrec
, srs
->RR_SRV
.resrec
.rroriginalttl
);
2416 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
2418 if (srs
->srs_uselease
)
2419 { ptr
= putUpdateLease(&m
->omsg
, ptr
, DEFAULT_UPDATE_LEASE
); if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; } }
2421 if (srs
->state
!= regState_Refresh
&& srs
->state
!= regState_DeregDeferred
&& srs
->state
!= regState_UpdatePending
)
2422 srs
->state
= regState_Pending
;
2428 if (srs
->tcp
) LogOperation("SendServiceRegistration: Disposing existing TCP connection for %s", ARDisplayString(m
, &srs
->RR_SRV
));
2429 if (srs
->tcp
) DisposeTCPConn(srs
->tcp
);
2430 srs
->tcp
= MakeTCPConn(m
, &m
->omsg
, ptr
, kTCPSocketFlags_UseTLS
, &srs
->SRSUpdateServer
, srs
->SRSUpdatePort
, mDNSNULL
, srs
, mDNSNULL
);
2431 if (!srs
->tcp
) srs
->RR_SRV
.ThisAPInterval
= mDNSPlatformOneSecond
* 5; // If failed to make TCP connection, try again in ten seconds (5*2)
2432 else if (srs
->RR_SRV
.ThisAPInterval
< mDNSPlatformOneSecond
* 30) srs
->RR_SRV
.ThisAPInterval
= mDNSPlatformOneSecond
* 30;
2436 err
= mDNSSendDNSMessage(m
, &m
->omsg
, ptr
, mDNSInterface_Any
, mDNSNULL
, &srs
->SRSUpdateServer
, srs
->SRSUpdatePort
, mDNSNULL
, GetAuthInfoForName_internal(m
, srs
->RR_SRV
.resrec
.name
));
2437 if (err
) debugf("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %ld", err
);
2440 SetRecordRetry(m
, &srs
->RR_SRV
, err
);
2446 LogMsg("SendServiceRegistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
2448 srs
->state
= regState_Unregistered
;
2450 mDNS_DropLockBeforeCallback();
2451 srs
->ServiceCallback(m
, srs
, err
);
2452 mDNS_ReclaimLockAfterCallback();
2453 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
2454 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
2458 mDNSlocal
const domainname
*PUBLIC_UPDATE_SERVICE_TYPE
= (const domainname
*)"\x0B_dns-update" "\x04_udp";
2459 mDNSlocal
const domainname
*PUBLIC_LLQ_SERVICE_TYPE
= (const domainname
*)"\x08_dns-llq" "\x04_udp";
2461 mDNSlocal
const domainname
*PRIVATE_UPDATE_SERVICE_TYPE
= (const domainname
*)"\x0F_dns-update-tls" "\x04_tcp";
2462 mDNSlocal
const domainname
*PRIVATE_QUERY_SERVICE_TYPE
= (const domainname
*)"\x0E_dns-query-tls" "\x04_tcp";
2463 mDNSlocal
const domainname
*PRIVATE_LLQ_SERVICE_TYPE
= (const domainname
*)"\x0C_dns-llq-tls" "\x04_tcp";
2465 #define ZoneDataSRV(X) (\
2466 (X)->ZoneService == ZoneServiceUpdate ? ((X)->ZonePrivate ? PRIVATE_UPDATE_SERVICE_TYPE : PUBLIC_UPDATE_SERVICE_TYPE) : \
2467 (X)->ZoneService == ZoneServiceQuery ? ((X)->ZonePrivate ? PRIVATE_QUERY_SERVICE_TYPE : (const domainname*)"" ) : \
2468 (X)->ZoneService == ZoneServiceLLQ ? ((X)->ZonePrivate ? PRIVATE_LLQ_SERVICE_TYPE : PUBLIC_LLQ_SERVICE_TYPE ) : (const domainname*)"")
2470 // Forward reference: GetZoneData_StartQuery references GetZoneData_QuestionCallback, and
2471 // GetZoneData_QuestionCallback calls GetZoneData_StartQuery
2472 mDNSlocal mStatus
GetZoneData_StartQuery(mDNS
*const m
, ZoneData
*zd
, mDNSu16 qtype
);
2474 // GetZoneData_QuestionCallback is called from normal client callback context (core API calls allowed)
2475 mDNSlocal
void GetZoneData_QuestionCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
2477 ZoneData
*zd
= (ZoneData
*)question
->QuestionContext
;
2479 debugf("GetZoneData_QuestionCallback: %s %s", AddRecord
? "Add" : "Rmv", RRDisplayString(m
, answer
));
2481 if (!AddRecord
) return; // Don't care about REMOVE events
2482 if (AddRecord
== QC_addnocache
&& answer
->rdlength
== 0) return; // Don't care about transient failure indications
2483 if (answer
->rrtype
!= question
->qtype
) return; // Don't care about CNAMEs
2485 if (answer
->rrtype
== kDNSType_SOA
)
2487 debugf("GetZoneData GOT SOA %s", RRDisplayString(m
, answer
));
2488 mDNS_StopQuery(m
, question
);
2489 if (answer
->rdlength
)
2491 AssignDomainName(&zd
->ZoneName
, answer
->name
);
2492 zd
->ZoneClass
= answer
->rrclass
;
2493 AssignDomainName(&zd
->question
.qname
, &zd
->ZoneName
);
2494 GetZoneData_StartQuery(m
, zd
, kDNSType_SRV
);
2496 else if (zd
->CurrentSOA
->c
[0])
2498 zd
->CurrentSOA
= (domainname
*)(zd
->CurrentSOA
->c
+ zd
->CurrentSOA
->c
[0]+1);
2499 AssignDomainName(&zd
->question
.qname
, zd
->CurrentSOA
);
2500 GetZoneData_StartQuery(m
, zd
, kDNSType_SOA
);
2504 LogOperation("GetZoneData recursed to root label of %##s without finding SOA", zd
->ChildName
.c
);
2505 zd
->ZoneDataCallback(m
, mStatus_NoSuchNameErr
, zd
);
2506 mDNSPlatformMemFree(zd
);
2509 else if (answer
->rrtype
== kDNSType_SRV
)
2511 debugf("GetZoneData GOT SRV %s", RRDisplayString(m
, answer
));
2512 mDNS_StopQuery(m
, question
);
2513 // Right now we don't want to fail back to non-encrypted operations
2514 // If the AuthInfo has the AutoTunnel field set, then we want private or nothing
2515 // <rdar://problem/5687667> BTMM: Don't fallback to unencrypted operations when SRV lookup fails
2517 if (!answer
->rdlength
&& zd
->ZonePrivate
&& zd
->ZoneService
!= ZoneServiceQuery
)
2519 zd
->ZonePrivate
= mDNSfalse
; // Causes ZoneDataSRV() to yield a different SRV name when building the query
2520 GetZoneData_StartQuery(m
, zd
, kDNSType_SRV
); // Try again, non-private this time
2525 if (answer
->rdlength
)
2527 AssignDomainName(&zd
->Host
, &answer
->rdata
->u
.srv
.target
);
2528 zd
->Port
= answer
->rdata
->u
.srv
.port
;
2529 AssignDomainName(&zd
->question
.qname
, &zd
->Host
);
2530 GetZoneData_StartQuery(m
, zd
, kDNSType_A
);
2534 zd
->ZonePrivate
= mDNSfalse
;
2536 zd
->Port
= zeroIPPort
;
2537 zd
->Addr
= zeroAddr
;
2538 zd
->ZoneDataCallback(m
, mStatus_NoError
, zd
);
2539 mDNSPlatformMemFree(zd
);
2543 else if (answer
->rrtype
== kDNSType_A
)
2545 debugf("GetZoneData GOT A %s", RRDisplayString(m
, answer
));
2546 mDNS_StopQuery(m
, question
);
2547 zd
->Addr
.type
= mDNSAddrType_IPv4
;
2548 zd
->Addr
.ip
.v4
= (answer
->rdlength
== 4) ? answer
->rdata
->u
.ipv4
: zerov4Addr
;
2549 // In order to simulate firewalls blocking our outgoing TCP connections, returning immediate ICMP errors or TCP resets,
2550 // the code below will make us try to connect to loopback, resulting in an immediate "port unreachable" failure.
2551 // This helps us test to make sure we handle this case gracefully
2552 // <rdar://problem/5607082> BTMM: mDNSResponder taking 100 percent CPU after upgrading to 10.5.1
2554 zd
->Addr
.ip
.v4
.b
[0] = 127;
2555 zd
->Addr
.ip
.v4
.b
[1] = 0;
2556 zd
->Addr
.ip
.v4
.b
[2] = 0;
2557 zd
->Addr
.ip
.v4
.b
[3] = 1;
2559 zd
->ZoneDataCallback(m
, mStatus_NoError
, zd
);
2560 mDNSPlatformMemFree(zd
);
2564 // GetZoneData_StartQuery is called from normal client context (lock not held, or client callback)
2565 mDNSlocal mStatus
GetZoneData_StartQuery(mDNS
*const m
, ZoneData
*zd
, mDNSu16 qtype
)
2567 if (qtype
== kDNSType_SRV
)
2569 AssignDomainName(&zd
->question
.qname
, ZoneDataSRV(zd
));
2570 AppendDomainName(&zd
->question
.qname
, &zd
->ZoneName
);
2571 LogOperation("lookupDNSPort %##s", zd
->question
.qname
.c
);
2574 zd
->question
.ThisQInterval
= -1; // So that GetZoneData_QuestionCallback() knows whether to cancel this question (Is this necessary?)
2575 zd
->question
.InterfaceID
= mDNSInterface_Any
;
2576 zd
->question
.Target
= zeroAddr
;
2577 //zd->question.qname.c[0] = 0; // Already set
2578 zd
->question
.qtype
= qtype
;
2579 zd
->question
.qclass
= kDNSClass_IN
;
2580 zd
->question
.LongLived
= mDNSfalse
;
2581 zd
->question
.ExpectUnique
= mDNStrue
;
2582 zd
->question
.ForceMCast
= mDNSfalse
;
2583 zd
->question
.ReturnIntermed
= mDNStrue
;
2584 zd
->question
.QuestionCallback
= GetZoneData_QuestionCallback
;
2585 zd
->question
.QuestionContext
= zd
;
2587 //LogMsg("GetZoneData_StartQuery %##s (%s) %p", zd->question.qname.c, DNSTypeName(zd->question.qtype), zd->question.Private);
2588 return(mDNS_StartQuery(m
, &zd
->question
));
2591 // StartGetZoneData is an internal routine (i.e. must be called with the lock already held)
2592 mDNSexport ZoneData
*StartGetZoneData(mDNS
*const m
, const domainname
*const name
, const ZoneService target
, ZoneDataCallback callback
, void *ZoneDataContext
)
2594 DomainAuthInfo
*AuthInfo
= GetAuthInfoForName_internal(m
, name
);
2595 int initialskip
= (AuthInfo
&& AuthInfo
->AutoTunnel
) ? DomainNameLength(name
) - DomainNameLength(&AuthInfo
->domain
) : 0;
2596 ZoneData
*zd
= (ZoneData
*)mDNSPlatformMemAllocate(sizeof(ZoneData
));
2597 if (!zd
) { LogMsg("ERROR: StartGetZoneData - mDNSPlatformMemAllocate failed"); return mDNSNULL
; }
2598 mDNSPlatformMemZero(zd
, sizeof(ZoneData
));
2599 AssignDomainName(&zd
->ChildName
, name
);
2600 zd
->ZoneService
= target
;
2601 zd
->CurrentSOA
= (domainname
*)(&zd
->ChildName
.c
[initialskip
]);
2602 zd
->ZoneName
.c
[0] = 0;
2605 zd
->Port
= zeroIPPort
;
2606 zd
->Addr
= zeroAddr
;
2607 zd
->ZonePrivate
= AuthInfo
&& AuthInfo
->AutoTunnel
? mDNStrue
: mDNSfalse
;
2608 zd
->ZoneDataCallback
= callback
;
2609 zd
->ZoneDataContext
= ZoneDataContext
;
2611 zd
->question
.QuestionContext
= zd
;
2612 AssignDomainName(&zd
->question
.qname
, zd
->CurrentSOA
);
2614 mDNS_DropLockBeforeCallback(); // GetZoneData_StartQuery expects to be called from a normal callback, so we emulate that here
2615 GetZoneData_StartQuery(m
, zd
, kDNSType_SOA
);
2616 mDNS_ReclaimLockAfterCallback();
2621 // GetZoneData queries are a special case -- even if we have a key for them, we don't do them privately,
2622 // because that would result in an infinite loop (i.e. to do a private query we first need to get
2623 // the _dns-query-tls SRV record for the zone, and we can't do *that* privately because to do so
2624 // we'd need to already know the _dns-query-tls SRV record.
2625 // Also, as a general rule, we never do SOA queries privately
2626 mDNSexport DomainAuthInfo
*GetAuthInfoForQuestion(mDNS
*m
, const DNSQuestion
*const q
) // Must be called with lock held
2628 if (q
->QuestionCallback
== GetZoneData_QuestionCallback
) return(mDNSNULL
);
2629 if (q
->qtype
== kDNSType_SOA
) return(mDNSNULL
);
2630 return(GetAuthInfoForName_internal(m
, &q
->qname
));
2633 // ***************************************************************************
2634 #if COMPILER_LIKES_PRAGMA_MARK
2635 #pragma mark - host name and interface management
2638 // Called in normal client context (lock not held)
2639 mDNSlocal
void CompleteSRVNatMap(mDNS
*m
, NATTraversalInfo
*n
)
2641 ServiceRecordSet
*srs
= (ServiceRecordSet
*)n
->clientContext
;
2642 LogOperation("SRVNatMap complete %.4a %u %u TTL %u", &n
->ExternalAddress
, mDNSVal16(n
->IntPort
), mDNSVal16(n
->ExternalPort
), n
->NATLease
);
2644 if (!srs
) { LogMsg("CompleteSRVNatMap called with unknown ServiceRecordSet object"); return; }
2645 if (!n
->NATLease
) return;
2648 if (!mDNSIPv4AddressIsZero(srs
->SRSUpdateServer
.ip
.v4
))
2649 SendServiceRegistration(m
, srs
); // non-zero server address means we already have necessary zone data to send update
2652 // SHOULD NEVER HAPPEN!
2653 LogOperation("ERROR: CompleteSRVNatMap called but srs->SRSUpdateServer.ip.v4 is zero!");
2654 srs
->state
= regState_FetchingZoneData
;
2655 if (srs
->nta
) CancelGetZoneData(m
, srs
->nta
); // Make sure we cancel old one before we start a new one
2656 srs
->nta
= StartGetZoneData(m
, srs
->RR_SRV
.resrec
.name
, ZoneServiceUpdate
, ServiceRegistrationGotZoneData
, srs
);
2661 mDNSlocal
void StartSRVNatMap(mDNS
*m
, ServiceRecordSet
*srs
)
2663 const mDNSu8
*p
= srs
->RR_PTR
.resrec
.name
->c
;
2664 if (p
[0]) p
+= 1 + p
[0];
2665 if (SameDomainLabel(p
, (mDNSu8
*)"\x4" "_tcp")) srs
->NATinfo
.Protocol
= NATOp_MapTCP
;
2666 else if (SameDomainLabel(p
, (mDNSu8
*)"\x4" "_udp")) srs
->NATinfo
.Protocol
= NATOp_MapUDP
;
2667 else { LogMsg("StartSRVNatMap: could not determine transport protocol of service %##s", srs
->RR_SRV
.resrec
.name
->c
); return; }
2669 if (srs
->NATinfo
.clientContext
) mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
2670 srs
->NATinfo
.IntPort
= srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
;
2671 srs
->NATinfo
.RequestedPort
= srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
;
2672 srs
->NATinfo
.NATLease
= 0; // Request default lease
2673 srs
->NATinfo
.clientCallback
= CompleteSRVNatMap
;
2674 srs
->NATinfo
.clientContext
= srs
;
2675 mDNS_StartNATOperation_internal(m
, &srs
->NATinfo
);
2678 // Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
2679 mDNSexport
void ServiceRegistrationGotZoneData(mDNS
*const m
, mStatus err
, const ZoneData
*zoneData
)
2681 ServiceRecordSet
*srs
= (ServiceRecordSet
*)zoneData
->ZoneDataContext
;
2683 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
)
2684 LogMsg("ServiceRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
2686 srs
->nta
= mDNSNULL
;
2688 // Start off assuming we're going to use a lease
2689 // 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
2690 srs
->srs_uselease
= mDNStrue
;
2692 if (err
|| !zoneData
) return;
2694 if (mDNSIPPortIsZero(zoneData
->Port
) || mDNSAddressIsZero(&zoneData
->Addr
)) return;
2697 AssignDomainName(&srs
->zone
, &zoneData
->ZoneName
);
2698 srs
->SRSUpdateServer
.type
= mDNSAddrType_IPv4
;
2699 srs
->SRSUpdateServer
= zoneData
->Addr
;
2700 srs
->SRSUpdatePort
= zoneData
->Port
;
2701 srs
->Private
= zoneData
->ZonePrivate
;
2703 srs
->RR_SRV
.LastAPTime
= m
->timenow
;
2704 srs
->RR_SRV
.ThisAPInterval
= 0;
2706 LogOperation("ServiceRegistrationGotZoneData My IPv4 %#a%s Server %#a:%d%s for %##s",
2707 &m
->AdvertisedV4
, mDNSv4AddrIsRFC1918(&m
->AdvertisedV4
.ip
.v4
) ? " (RFC1918)" : "",
2708 &srs
->SRSUpdateServer
, mDNSVal16(srs
->SRSUpdatePort
), mDNSAddrIsRFC1918(&srs
->SRSUpdateServer
) ? " (RFC1918)" : "",
2709 srs
->RR_SRV
.resrec
.name
->c
);
2711 if (!mDNSIPPortIsZero(srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
) &&
2712 mDNSv4AddrIsRFC1918(&m
->AdvertisedV4
.ip
.v4
) && !mDNSAddrIsRFC1918(&srs
->SRSUpdateServer
) &&
2713 srs
->RR_SRV
.AutoTarget
== Target_AutoHostAndNATMAP
)
2715 srs
->state
= regState_NATMap
;
2716 LogOperation("ServiceRegistrationGotZoneData StartSRVNatMap");
2717 StartSRVNatMap(m
, srs
);
2722 SendServiceRegistration(m
, srs
);
2727 mDNSlocal
void SendServiceDeregistration(mDNS
*m
, ServiceRecordSet
*srs
)
2730 mDNSu8
*ptr
= m
->omsg
.data
;
2731 mDNSu8
*end
= (mDNSu8
*)&m
->omsg
+ sizeof(DNSMessage
);
2732 mStatus err
= mStatus_UnknownErr
;
2735 if (mDNSIPv4AddressIsZero(srs
->SRSUpdateServer
.ip
.v4
)) // Don't know our UpdateServer yet
2737 srs
->RR_SRV
.LastAPTime
= m
->timenow
;
2738 if (srs
->RR_SRV
.ThisAPInterval
< mDNSPlatformOneSecond
* 5)
2739 srs
->RR_SRV
.ThisAPInterval
= mDNSPlatformOneSecond
* 5;
2743 id
= mDNS_NewMessageID(m
);
2744 InitializeDNSMessage(&m
->omsg
.h
, id
, UpdateReqFlags
);
2747 ptr
= putZone(&m
->omsg
, ptr
, end
, &srs
->zone
, mDNSOpaque16fromIntVal(srs
->RR_SRV
.resrec
.rrclass
));
2748 if (!ptr
) { LogMsg("ERROR: SendServiceDeregistration - putZone"); err
= mStatus_UnknownErr
; goto exit
; }
2750 if (!(ptr
= putDeleteAllRRSets(&m
->omsg
, ptr
, srs
->RR_SRV
.resrec
.name
))) { err
= mStatus_UnknownErr
; goto exit
; } // this deletes SRV, TXT, and Extras
2751 if (!(ptr
= putDeletionRecord(&m
->omsg
, ptr
, &srs
->RR_PTR
.resrec
))) { err
= mStatus_UnknownErr
; goto exit
; }
2752 for (i
= 0; i
< srs
->NumSubTypes
; i
++)
2753 if (!(ptr
= putDeletionRecord(&m
->omsg
, ptr
, &srs
->SubTypes
[i
].resrec
))) { err
= mStatus_UnknownErr
; goto exit
; }
2756 srs
->state
= regState_DeregPending
;
2757 srs
->RR_SRV
.expire
= 0; // Indicate that we have no active registration any more
2761 LogOperation("SendServiceDeregistration TCP %p %s", srs
->tcp
, ARDisplayString(m
, &srs
->RR_SRV
));
2762 if (srs
->tcp
) LogOperation("SendServiceDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m
, &srs
->RR_SRV
));
2763 if (srs
->tcp
) DisposeTCPConn(srs
->tcp
);
2764 srs
->tcp
= MakeTCPConn(m
, &m
->omsg
, ptr
, kTCPSocketFlags_UseTLS
, &srs
->SRSUpdateServer
, srs
->SRSUpdatePort
, mDNSNULL
, srs
, mDNSNULL
);
2765 if (!srs
->tcp
) srs
->RR_SRV
.ThisAPInterval
= mDNSPlatformOneSecond
* 5; // If failed to make TCP connection, try again in ten seconds (5*2)
2766 else if (srs
->RR_SRV
.ThisAPInterval
< mDNSPlatformOneSecond
* 30) srs
->RR_SRV
.ThisAPInterval
= mDNSPlatformOneSecond
* 30;
2770 err
= mDNSSendDNSMessage(m
, &m
->omsg
, ptr
, mDNSInterface_Any
, mDNSNULL
, &srs
->SRSUpdateServer
, srs
->SRSUpdatePort
, mDNSNULL
, GetAuthInfoForName_internal(m
, srs
->RR_SRV
.resrec
.name
));
2771 if (err
&& err
!= mStatus_TransientErr
) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %ld", err
); goto exit
; }
2774 SetRecordRetry(m
, &srs
->RR_SRV
, err
);
2780 LogMsg("SendServiceDeregistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
2782 srs
->state
= regState_Unregistered
;
2786 // Called with lock held
2787 mDNSlocal
void UpdateSRV(mDNS
*m
, ServiceRecordSet
*srs
)
2789 ExtraResourceRecord
*e
;
2791 // Target change if:
2792 // We have a target and were previously waiting for one, or
2793 // We had a target and no longer do, or
2794 // The target has changed
2796 domainname
*curtarget
= &srs
->RR_SRV
.resrec
.rdata
->u
.srv
.target
;
2797 const domainname
*const nt
= GetServiceTarget(m
, srs
);
2798 const domainname
*const newtarget
= nt
? nt
: (domainname
*)"";
2799 mDNSBool TargetChanged
= (newtarget
->c
[0] && srs
->state
== regState_NoTarget
) || !SameDomainName(curtarget
, newtarget
);
2800 mDNSBool HaveZoneData
= !mDNSIPv4AddressIsZero(srs
->SRSUpdateServer
.ip
.v4
);
2802 // Nat state change if:
2803 // We were behind a NAT, and now we are behind a new NAT, or
2804 // We're not behind a NAT but our port was previously mapped to a different public port
2805 // We were not behind a NAT and now we are
2807 mDNSIPPort port
= srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
;
2808 mDNSBool NowNeedNATMAP
= (srs
->RR_SRV
.AutoTarget
== Target_AutoHostAndNATMAP
&& !mDNSIPPortIsZero(port
) && mDNSv4AddrIsRFC1918(&m
->AdvertisedV4
.ip
.v4
) && !mDNSAddrIsRFC1918(&srs
->SRSUpdateServer
));
2809 mDNSBool WereBehindNAT
= (srs
->NATinfo
.clientContext
!= mDNSNULL
);
2810 mDNSBool PortWasMapped
= (srs
->NATinfo
.clientContext
&& !mDNSSameIPPort(srs
->NATinfo
.RequestedPort
, port
)); // I think this is always false -- SC Sept 07
2811 mDNSBool NATChanged
= (!WereBehindNAT
&& NowNeedNATMAP
) || (!NowNeedNATMAP
&& PortWasMapped
);
2813 LogOperation("UpdateSRV %##s newtarget %##s TargetChanged %d HaveZoneData %d port %d NowNeedNATMAP %d WereBehindNAT %d PortWasMapped %d NATChanged %d",
2814 srs
->RR_SRV
.resrec
.name
->c
, newtarget
,
2815 TargetChanged
, HaveZoneData
, mDNSVal16(port
), NowNeedNATMAP
, WereBehindNAT
, PortWasMapped
, NATChanged
);
2817 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
2818 LogMsg("UpdateSRV: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
2820 if (!TargetChanged
&& !NATChanged
) return;
2824 case regState_FetchingZoneData
:
2825 case regState_DeregPending
:
2826 case regState_DeregDeferred
:
2827 case regState_Unregistered
:
2828 case regState_NATMap
:
2829 case regState_ExtraQueued
:
2830 // In these states, the SRV has either not yet been registered (it will get up-to-date information when it is)
2831 // or is in the process of, or has already been, deregistered
2834 case regState_Pending
:
2835 case regState_Refresh
:
2836 case regState_UpdatePending
:
2837 // let the in-flight operation complete before updating
2838 srs
->SRVUpdateDeferred
= mDNStrue
;
2841 case regState_NATError
:
2842 if (!NATChanged
) return;
2843 // if nat changed, register if we have a target (below)
2845 case regState_NoTarget
:
2846 if (newtarget
->c
[0])
2848 debugf("UpdateSRV: %s service %##s", HaveZoneData
? (NATChanged
&& NowNeedNATMAP
? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs
->RR_SRV
.resrec
.name
->c
);
2851 srs
->state
= regState_FetchingZoneData
;
2852 if (srs
->nta
) CancelGetZoneData(m
, srs
->nta
); // Make sure we cancel old one before we start a new one
2853 srs
->nta
= StartGetZoneData(m
, srs
->RR_SRV
.resrec
.name
, ZoneServiceUpdate
, ServiceRegistrationGotZoneData
, srs
);
2857 if (srs
->NATinfo
.clientContext
&& (NATChanged
|| !NowNeedNATMAP
))
2859 mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
2860 srs
->NATinfo
.clientContext
= mDNSNULL
;
2862 if (NATChanged
&& NowNeedNATMAP
&& srs
->RR_SRV
.AutoTarget
== Target_AutoHostAndNATMAP
)
2863 { srs
->state
= regState_NATMap
; StartSRVNatMap(m
, srs
); }
2864 else SendServiceRegistration(m
, srs
);
2869 case regState_Registered
:
2870 // target or nat changed. deregister service. upon completion, we'll look for a new target
2871 debugf("UpdateSRV: SRV record changed for service %##s - deregistering (will re-register with new SRV)", srs
->RR_SRV
.resrec
.name
->c
);
2872 for (e
= srs
->Extras
; e
; e
= e
->next
) e
->r
.state
= regState_ExtraQueued
; // extra will be re-registed if the service is re-registered
2873 srs
->SRVChanged
= mDNStrue
;
2874 SendServiceDeregistration(m
, srs
);
2877 default: LogMsg("UpdateSRV: Unknown state %d for %##s", srs
->state
, srs
->RR_SRV
.resrec
.name
->c
);
2881 // Called with lock held
2882 mDNSlocal
void UpdateSRVRecords(mDNS
*m
)
2884 LogOperation("UpdateSRVRecords%s", m
->SleepState
? " (ignored due to SleepState)" : "");
2885 if (m
->SleepState
) return;
2887 if (CurrentServiceRecordSet
)
2888 LogMsg("UpdateSRVRecords ERROR CurrentServiceRecordSet already set");
2889 CurrentServiceRecordSet
= m
->ServiceRegistrations
;
2891 while (CurrentServiceRecordSet
)
2893 ServiceRecordSet
*s
= CurrentServiceRecordSet
;
2894 CurrentServiceRecordSet
= CurrentServiceRecordSet
->uDNS_next
;
2899 // Forward reference: AdvertiseHostname references HostnameCallback, and HostnameCallback calls AdvertiseHostname
2900 mDNSlocal
void HostnameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
);
2902 // Called in normal client context (lock not held)
2903 mDNSlocal
void hostnameGetPublicAddressCallback(mDNS
*m
, NATTraversalInfo
*n
)
2905 HostnameInfo
*h
= (HostnameInfo
*)n
->clientContext
;
2907 if (!h
) { LogMsg("RegisterHostnameRecord: registration cancelled"); return; }
2911 if (mDNSIPv4AddressIsZero(n
->ExternalAddress
) || mDNSv4AddrIsRFC1918(&n
->ExternalAddress
)) return;
2913 if (h
->arv4
.resrec
.RecordType
)
2915 if (mDNSSameIPv4Address(h
->arv4
.resrec
.rdata
->u
.ipv4
, n
->ExternalAddress
)) return; // If address unchanged, do nothing
2916 LogOperation("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
);
2917 mDNS_Deregister(m
, &h
->arv4
); // mStatus_MemFree callback will re-register with new address
2921 LogOperation("Advertising hostname %##s IPv4 %.4a (NAT gateway's external address)", h
->arv4
.resrec
.name
->c
, &n
->ExternalAddress
);
2922 h
->arv4
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
2923 h
->arv4
.resrec
.rdata
->u
.ipv4
= n
->ExternalAddress
;
2924 mDNS_Register(m
, &h
->arv4
);
2929 // register record or begin NAT traversal
2930 mDNSlocal
void AdvertiseHostname(mDNS
*m
, HostnameInfo
*h
)
2932 if (!mDNSIPv4AddressIsZero(m
->AdvertisedV4
.ip
.v4
) && h
->arv4
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
2934 mDNS_SetupResourceRecord(&h
->arv4
, mDNSNULL
, mDNSInterface_Any
, kDNSType_A
, kHostNameTTL
, kDNSRecordTypeUnregistered
, HostnameCallback
, h
);
2935 AssignDomainName(&h
->arv4
.namestorage
, &h
->fqdn
);
2936 h
->arv4
.resrec
.rdata
->u
.ipv4
= m
->AdvertisedV4
.ip
.v4
;
2937 h
->arv4
.state
= regState_Unregistered
;
2938 if (mDNSv4AddrIsRFC1918(&m
->AdvertisedV4
.ip
.v4
))
2940 // If we already have a NAT query active, stop it and restart it to make sure we get another callback
2941 if (h
->natinfo
.clientContext
) mDNS_StopNATOperation_internal(m
, &h
->natinfo
);
2942 h
->natinfo
.Protocol
= 0;
2943 h
->natinfo
.IntPort
= zeroIPPort
;
2944 h
->natinfo
.RequestedPort
= zeroIPPort
;
2945 h
->natinfo
.NATLease
= 0;
2946 h
->natinfo
.clientCallback
= hostnameGetPublicAddressCallback
;
2947 h
->natinfo
.clientContext
= h
;
2948 mDNS_StartNATOperation_internal(m
, &h
->natinfo
);
2952 LogOperation("Advertising hostname %##s IPv4 %.4a", h
->arv4
.resrec
.name
->c
, &m
->AdvertisedV4
.ip
.v4
);
2953 h
->arv4
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
2954 mDNS_Register_internal(m
, &h
->arv4
);
2958 if (!mDNSIPv6AddressIsZero(m
->AdvertisedV6
.ip
.v6
) && h
->arv6
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
2960 mDNS_SetupResourceRecord(&h
->arv6
, mDNSNULL
, mDNSInterface_Any
, kDNSType_AAAA
, kHostNameTTL
, kDNSRecordTypeKnownUnique
, HostnameCallback
, h
);
2961 AssignDomainName(&h
->arv6
.namestorage
, &h
->fqdn
);
2962 h
->arv6
.resrec
.rdata
->u
.ipv6
= m
->AdvertisedV6
.ip
.v6
;
2963 h
->arv6
.state
= regState_Unregistered
;
2964 LogOperation("Advertising hostname %##s IPv6 %.16a", h
->arv6
.resrec
.name
->c
, &m
->AdvertisedV6
.ip
.v6
);
2965 mDNS_Register_internal(m
, &h
->arv6
);
2969 mDNSlocal
void HostnameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
2971 HostnameInfo
*hi
= (HostnameInfo
*)rr
->RecordContext
;
2973 if (result
== mStatus_MemFree
)
2977 // If we're still in the Hostnames list, update to new address
2979 LogOperation("HostnameCallback: Got mStatus_MemFree for %p %p %s", hi
, rr
, ARDisplayString(m
, rr
));
2980 for (i
= m
->Hostnames
; i
; i
= i
->next
)
2981 if (rr
== &i
->arv4
|| rr
== &i
->arv6
)
2982 { mDNS_Lock(m
); AdvertiseHostname(m
, i
); mDNS_Unlock(m
); return; }
2984 // Else, we're not still in the Hostnames list, so free the memory
2985 if (hi
->arv4
.resrec
.RecordType
== kDNSRecordTypeUnregistered
&&
2986 hi
->arv6
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
2988 if (hi
->natinfo
.clientContext
) mDNS_StopNATOperation_internal(m
, &hi
->natinfo
);
2989 hi
->natinfo
.clientContext
= mDNSNULL
;
2990 mDNSPlatformMemFree(hi
); // free hi when both v4 and v6 AuthRecs deallocated
2998 // don't unlink or free - we can retry when we get a new address/router
2999 if (rr
->resrec
.rrtype
== kDNSType_A
)
3000 LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.4a", result
, rr
->resrec
.name
->c
, &rr
->resrec
.rdata
->u
.ipv4
);
3002 LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.16a", result
, rr
->resrec
.name
->c
, &rr
->resrec
.rdata
->u
.ipv6
);
3003 if (!hi
) { mDNSPlatformMemFree(rr
); return; }
3004 if (rr
->state
!= regState_Unregistered
) LogMsg("Error: HostnameCallback invoked with error code for record not in regState_Unregistered!");
3006 if (hi
->arv4
.state
== regState_Unregistered
&&
3007 hi
->arv6
.state
== regState_Unregistered
)
3009 // only deliver status if both v4 and v6 fail
3010 rr
->RecordContext
= (void *)hi
->StatusContext
;
3011 if (hi
->StatusCallback
)
3012 hi
->StatusCallback(m
, rr
, result
); // client may NOT make API calls here
3013 rr
->RecordContext
= (void *)hi
;
3018 // register any pending services that require a target
3020 UpdateSRVRecords(m
);
3023 // Deliver success to client
3024 if (!hi
) { LogMsg("HostnameCallback invoked with orphaned address record"); return; }
3025 if (rr
->resrec
.rrtype
== kDNSType_A
)
3026 LogOperation("Registered hostname %##s IP %.4a", rr
->resrec
.name
->c
, &rr
->resrec
.rdata
->u
.ipv4
);
3028 LogOperation("Registered hostname %##s IP %.16a", rr
->resrec
.name
->c
, &rr
->resrec
.rdata
->u
.ipv6
);
3030 rr
->RecordContext
= (void *)hi
->StatusContext
;
3031 if (hi
->StatusCallback
)
3032 hi
->StatusCallback(m
, rr
, result
); // client may NOT make API calls here
3033 rr
->RecordContext
= (void *)hi
;
3036 mDNSlocal
void FoundStaticHostname(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
3038 const domainname
*pktname
= &answer
->rdata
->u
.name
;
3039 domainname
*storedname
= &m
->StaticHostname
;
3040 HostnameInfo
*h
= m
->Hostnames
;
3044 debugf("FoundStaticHostname: %##s -> %##s (%s)", question
->qname
.c
, answer
->rdata
->u
.name
.c
, AddRecord
? "added" : "removed");
3045 if (AddRecord
&& !SameDomainName(pktname
, storedname
))
3047 AssignDomainName(storedname
, pktname
);
3050 if (h
->arv4
.state
== regState_FetchingZoneData
|| h
->arv4
.state
== regState_Pending
|| h
->arv4
.state
== regState_NATMap
||
3051 h
->arv6
.state
== regState_FetchingZoneData
|| h
->arv6
.state
== regState_Pending
)
3053 // 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
3054 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
+ 5 * mDNSPlatformOneSecond
);
3060 UpdateSRVRecords(m
);
3063 else if (!AddRecord
&& SameDomainName(pktname
, storedname
))
3066 storedname
->c
[0] = 0;
3067 UpdateSRVRecords(m
);
3072 // Called with lock held
3073 mDNSlocal
void GetStaticHostname(mDNS
*m
)
3075 char buf
[MAX_REVERSE_MAPPING_NAME_V4
];
3076 DNSQuestion
*q
= &m
->ReverseMap
;
3077 mDNSu8
*ip
= m
->AdvertisedV4
.ip
.v4
.b
;
3080 if (m
->ReverseMap
.ThisQInterval
!= -1) mDNS_StopQuery_internal(m
, q
);
3082 m
->StaticHostname
.c
[0] = 0;
3083 if (mDNSIPv4AddressIsZero(m
->AdvertisedV4
.ip
.v4
)) return;
3084 mDNSPlatformMemZero(q
, sizeof(*q
));
3085 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
3086 mDNS_snprintf(buf
, sizeof(buf
), "%d.%d.%d.%d.in-addr.arpa.", ip
[3], ip
[2], ip
[1], ip
[0]);
3087 if (!MakeDomainNameFromDNSNameString(&q
->qname
, buf
)) { LogMsg("Error: GetStaticHostname - bad name %s", buf
); return; }
3089 q
->InterfaceID
= mDNSInterface_Any
;
3090 q
->Target
= zeroAddr
;
3091 q
->qtype
= kDNSType_PTR
;
3092 q
->qclass
= kDNSClass_IN
;
3093 q
->LongLived
= mDNSfalse
;
3094 q
->ExpectUnique
= mDNSfalse
;
3095 q
->ForceMCast
= mDNSfalse
;
3096 q
->ReturnIntermed
= mDNStrue
;
3097 q
->QuestionCallback
= FoundStaticHostname
;
3098 q
->QuestionContext
= mDNSNULL
;
3100 err
= mDNS_StartQuery_internal(m
, q
);
3101 if (err
) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err
);
3104 mDNSexport
void mDNS_AddDynDNSHostName(mDNS
*m
, const domainname
*fqdn
, mDNSRecordCallback
*StatusCallback
, const void *StatusContext
)
3106 HostnameInfo
**ptr
= &m
->Hostnames
;
3108 LogOperation("mDNS_AddDynDNSHostName %##s", fqdn
);
3110 while (*ptr
&& !SameDomainName(fqdn
, &(*ptr
)->fqdn
)) ptr
= &(*ptr
)->next
;
3111 if (*ptr
) { LogMsg("DynDNSHostName %##s already in list", fqdn
->c
); return; }
3113 // allocate and format new address record
3114 *ptr
= mDNSPlatformMemAllocate(sizeof(**ptr
));
3115 if (!*ptr
) { LogMsg("ERROR: mDNS_AddDynDNSHostName - malloc"); return; }
3117 mDNSPlatformMemZero(*ptr
, sizeof(**ptr
));
3118 AssignDomainName(&(*ptr
)->fqdn
, fqdn
);
3119 (*ptr
)->arv4
.state
= regState_Unregistered
;
3120 (*ptr
)->arv6
.state
= regState_Unregistered
;
3121 (*ptr
)->StatusCallback
= StatusCallback
;
3122 (*ptr
)->StatusContext
= StatusContext
;
3124 AdvertiseHostname(m
, *ptr
);
3127 mDNSexport
void mDNS_RemoveDynDNSHostName(mDNS
*m
, const domainname
*fqdn
)
3129 HostnameInfo
**ptr
= &m
->Hostnames
;
3131 LogOperation("mDNS_RemoveDynDNSHostName %##s", fqdn
);
3133 while (*ptr
&& !SameDomainName(fqdn
, &(*ptr
)->fqdn
)) ptr
= &(*ptr
)->next
;
3134 if (!*ptr
) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn
->c
);
3137 HostnameInfo
*hi
= *ptr
;
3138 // We do it this way because, if we have no active v6 record, the "mDNS_Deregister_internal(m, &hi->arv4);"
3139 // below could free the memory, and we have to make sure we don't touch hi fields after that.
3140 mDNSBool f4
= hi
->arv4
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
&& hi
->arv4
.state
!= regState_Unregistered
;
3141 mDNSBool f6
= hi
->arv6
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
&& hi
->arv6
.state
!= regState_Unregistered
;
3142 if (f4
) LogOperation("mDNS_RemoveDynDNSHostName removing v4 %##s", fqdn
);
3143 if (f6
) LogOperation("mDNS_RemoveDynDNSHostName removing v6 %##s", fqdn
);
3144 *ptr
= (*ptr
)->next
; // unlink
3145 if (f4
) mDNS_Deregister_internal(m
, &hi
->arv4
, mDNS_Dereg_normal
);
3146 if (f6
) mDNS_Deregister_internal(m
, &hi
->arv6
, mDNS_Dereg_normal
);
3147 // When both deregistrations complete we'll free the memory in the mStatus_MemFree callback
3149 UpdateSRVRecords(m
);
3152 // Currently called without holding the lock
3153 // Maybe we should change that?
3154 mDNSexport
void mDNS_SetPrimaryInterfaceInfo(mDNS
*m
, const mDNSAddr
*v4addr
, const mDNSAddr
*v6addr
, const mDNSAddr
*router
)
3156 mDNSBool v4Changed
, v6Changed
, RouterChanged
;
3158 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
)
3159 LogMsg("mDNS_SetPrimaryInterfaceInfo: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
3161 if (v4addr
&& v4addr
->type
!= mDNSAddrType_IPv4
) { LogMsg("mDNS_SetPrimaryInterfaceInfo v4 address - incorrect type. Discarding. %#a", v4addr
); return; }
3162 if (v6addr
&& v6addr
->type
!= mDNSAddrType_IPv6
) { LogMsg("mDNS_SetPrimaryInterfaceInfo v6 address - incorrect type. Discarding. %#a", v6addr
); return; }
3163 if (router
&& router
->type
!= mDNSAddrType_IPv4
) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-v4 router. Discarding. %#a", router
); return; }
3167 if (v4addr
&& !mDNSv4AddressIsLinkLocal(&v4addr
->ip
.v4
)) v6addr
= mDNSNULL
;
3169 v4Changed
= !mDNSSameIPv4Address(m
->AdvertisedV4
.ip
.v4
, v4addr
? v4addr
->ip
.v4
: zerov4Addr
);
3170 v6Changed
= !mDNSSameIPv6Address(m
->AdvertisedV6
.ip
.v6
, v6addr
? v6addr
->ip
.v6
: zerov6Addr
);
3171 RouterChanged
= !mDNSSameIPv4Address(m
->Router
.ip
.v4
, router
? router
->ip
.v4
: zerov4Addr
);
3173 if (v4addr
&& (v4Changed
|| RouterChanged
))
3174 debugf("mDNS_SetPrimaryInterfaceInfo: address changed from %#a to %#a", &m
->AdvertisedV4
, v4addr
);
3176 if (v4addr
) m
->AdvertisedV4
= *v4addr
; else m
->AdvertisedV4
.ip
.v4
= zerov4Addr
;
3177 if (v6addr
) m
->AdvertisedV6
= *v6addr
; else m
->AdvertisedV6
.ip
.v6
= zerov6Addr
;
3178 if (router
) m
->Router
= *router
; else m
->Router
.ip
.v4
= zerov4Addr
;
3179 // setting router to zero indicates that nat mappings must be reestablished when router is reset
3181 if (v4Changed
|| RouterChanged
|| v6Changed
)
3184 LogOperation("mDNS_SetPrimaryInterfaceInfo: %s%s%s%#a %#a %#a",
3185 v4Changed
? "v4Changed " : "",
3186 RouterChanged
? "RouterChanged " : "",
3187 v6Changed
? "v6Changed " : "", v4addr
, v6addr
, router
);
3189 for (i
= m
->Hostnames
; i
; i
= i
->next
)
3191 LogOperation("mDNS_SetPrimaryInterfaceInfo updating host name registrations for %##s", i
->fqdn
.c
);
3193 if (i
->arv4
.resrec
.RecordType
> kDNSRecordTypeDeregistering
&&
3194 !mDNSSameIPv4Address(i
->arv4
.resrec
.rdata
->u
.ipv4
, m
->AdvertisedV4
.ip
.v4
))
3196 LogOperation("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m
, &i
->arv4
));
3197 mDNS_Deregister_internal(m
, &i
->arv4
, mDNS_Dereg_normal
);
3200 if (i
->arv6
.resrec
.RecordType
> kDNSRecordTypeDeregistering
&&
3201 !mDNSSameIPv6Address(i
->arv6
.resrec
.rdata
->u
.ipv6
, m
->AdvertisedV6
.ip
.v6
))
3203 LogOperation("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m
, &i
->arv6
));
3204 mDNS_Deregister_internal(m
, &i
->arv6
, mDNS_Dereg_normal
);
3207 // AdvertiseHostname will only register new address records.
3208 // For records still in the process of deregistering it will ignore them, and let the mStatus_MemFree callback handle them.
3209 AdvertiseHostname(m
, i
);
3212 if (v4Changed
|| RouterChanged
)
3214 m
->ExternalAddress
= zerov4Addr
;
3215 m
->retryIntervalGetAddr
= NATMAP_INIT_RETRY
;
3216 m
->retryGetAddr
= m
->timenow
;
3217 m
->NextScheduledNATOp
= m
->timenow
;
3221 UpdateSRVRecords(m
);
3222 GetStaticHostname(m
); // look up reverse map record to find any static hostnames for our IP address
3223 #if APPLE_OSX_mDNSResponder
3224 UpdateAutoTunnelDomainStatuses(m
);
3231 // ***************************************************************************
3232 #if COMPILER_LIKES_PRAGMA_MARK
3233 #pragma mark - Incoming Message Processing
3236 mDNSlocal mStatus
ParseTSIGError(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
, const domainname
*const displayname
)
3239 mStatus err
= mStatus_NoError
;
3242 ptr
= LocateAdditionals(msg
, end
);
3243 if (!ptr
) goto finish
;
3245 for (i
= 0; i
< msg
->h
.numAdditionals
; i
++)
3247 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &m
->rec
);
3248 if (!ptr
) goto finish
;
3249 if (m
->rec
.r
.resrec
.rrtype
== kDNSType_TSIG
)
3252 mDNSu8
*rd
= m
->rec
.r
.resrec
.rdata
->u
.data
;
3253 mDNSu8
*rdend
= rd
+ m
->rec
.r
.resrec
.rdlength
;
3254 int alglen
= DomainNameLengthLimit(&m
->rec
.r
.resrec
.rdata
->u
.name
, rdend
);
3255 if (alglen
> MAX_DOMAIN_NAME
) goto finish
;
3256 rd
+= alglen
; // algorithm name
3257 if (rd
+ 6 > rdend
) goto finish
;
3258 rd
+= 6; // 48-bit timestamp
3259 if (rd
+ sizeof(mDNSOpaque16
) > rdend
) goto finish
;
3260 rd
+= sizeof(mDNSOpaque16
); // fudge
3261 if (rd
+ sizeof(mDNSOpaque16
) > rdend
) goto finish
;
3262 macsize
= mDNSVal16(*(mDNSOpaque16
*)rd
);
3263 rd
+= sizeof(mDNSOpaque16
); // MAC size
3264 if (rd
+ macsize
> rdend
) goto finish
;
3266 if (rd
+ sizeof(mDNSOpaque16
) > rdend
) goto finish
;
3267 rd
+= sizeof(mDNSOpaque16
); // orig id
3268 if (rd
+ sizeof(mDNSOpaque16
) > rdend
) goto finish
;
3269 err
= mDNSVal16(*(mDNSOpaque16
*)rd
); // error code
3271 if (err
== TSIG_ErrBadSig
) { LogMsg("%##s: bad signature", displayname
->c
); err
= mStatus_BadSig
; }
3272 else if (err
== TSIG_ErrBadKey
) { LogMsg("%##s: bad key", displayname
->c
); err
= mStatus_BadKey
; }
3273 else if (err
== TSIG_ErrBadTime
) { LogMsg("%##s: bad time", displayname
->c
); err
= mStatus_BadTime
; }
3274 else if (err
) { LogMsg("%##s: unknown tsig error %d", displayname
->c
, err
); err
= mStatus_UnknownErr
; }
3277 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
3281 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
3285 mDNSlocal mStatus
checkUpdateResult(mDNS
*const m
, const domainname
*const displayname
, const mDNSu8 rcode
, const DNSMessage
*const msg
, const mDNSu8
*const end
)
3287 (void)msg
; // currently unused, needed for TSIG errors
3288 if (!rcode
) return mStatus_NoError
;
3289 else if (rcode
== kDNSFlag1_RC_YXDomain
)
3291 debugf("name in use: %##s", displayname
->c
);
3292 return mStatus_NameConflict
;
3294 else if (rcode
== kDNSFlag1_RC_Refused
)
3296 LogMsg("Update %##s refused", displayname
->c
);
3297 return mStatus_Refused
;
3299 else if (rcode
== kDNSFlag1_RC_NXRRSet
)
3301 LogMsg("Reregister refused (NXRRSET): %##s", displayname
->c
);
3302 return mStatus_NoSuchRecord
;
3304 else if (rcode
== kDNSFlag1_RC_NotAuth
)
3306 // TSIG errors should come with FmtErr as per RFC 2845, but BIND 9 sends them with NotAuth so we look here too
3307 mStatus tsigerr
= ParseTSIGError(m
, msg
, end
, displayname
);
3310 LogMsg("Permission denied (NOAUTH): %##s", displayname
->c
);
3311 return mStatus_UnknownErr
;
3313 else return tsigerr
;
3315 else if (rcode
== kDNSFlag1_RC_FmtErr
)
3317 mStatus tsigerr
= ParseTSIGError(m
, msg
, end
, displayname
);
3320 LogMsg("Format Error: %##s", displayname
->c
);
3321 return mStatus_UnknownErr
;
3323 else return tsigerr
;
3327 LogMsg("Update %##s failed with rcode %d", displayname
->c
, rcode
);
3328 return mStatus_UnknownErr
;
3332 // Called with lock held
3333 mDNSlocal
void SendRecordRegistration(mDNS
*const m
, AuthRecord
*rr
)
3335 mDNSu8
*ptr
= m
->omsg
.data
;
3336 mDNSu8
*end
= (mDNSu8
*)&m
->omsg
+ sizeof(DNSMessage
);
3337 mStatus err
= mStatus_UnknownErr
;
3339 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
3340 LogMsg("SendRecordRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
3342 if (mDNSIPv4AddressIsZero(rr
->UpdateServer
.ip
.v4
)) // Don't know our UpdateServer yet
3344 rr
->LastAPTime
= m
->timenow
;
3345 if (rr
->ThisAPInterval
< mDNSPlatformOneSecond
* 5)
3346 rr
->ThisAPInterval
= mDNSPlatformOneSecond
* 5;
3350 rr
->RequireGoodbye
= mDNStrue
;
3351 rr
->id
= mDNS_NewMessageID(m
);
3352 InitializeDNSMessage(&m
->omsg
.h
, rr
->id
, UpdateReqFlags
);
3355 ptr
= putZone(&m
->omsg
, ptr
, end
, &rr
->zone
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
3356 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
3358 if (rr
->state
== regState_UpdatePending
)
3361 SetNewRData(&rr
->resrec
, rr
->OrigRData
, rr
->OrigRDLen
);
3362 if (!(ptr
= putDeletionRecord(&m
->omsg
, ptr
, &rr
->resrec
))) { err
= mStatus_UnknownErr
; goto exit
; } // delete old rdata
3365 SetNewRData(&rr
->resrec
, rr
->InFlightRData
, rr
->InFlightRDLen
);
3366 if (!(ptr
= PutResourceRecordTTLJumbo(&m
->omsg
, ptr
, &m
->omsg
.h
.mDNS_numUpdates
, &rr
->resrec
, rr
->resrec
.rroriginalttl
))) { err
= mStatus_UnknownErr
; goto exit
; }
3371 if (rr
->resrec
.RecordType
== kDNSRecordTypeKnownUnique
)
3373 // KnownUnique: Delete any previous value
3374 ptr
= putDeleteRRSet(&m
->omsg
, ptr
, rr
->resrec
.name
, rr
->resrec
.rrtype
);
3375 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
3378 else if (rr
->resrec
.RecordType
!= kDNSRecordTypeShared
)
3380 ptr
= putPrereqNameNotInUse(rr
->resrec
.name
, &m
->omsg
, ptr
, end
);
3381 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
3384 ptr
= PutResourceRecordTTLJumbo(&m
->omsg
, ptr
, &m
->omsg
.h
.mDNS_numUpdates
, &rr
->resrec
, rr
->resrec
.rroriginalttl
);
3385 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
3390 ptr
= putUpdateLease(&m
->omsg
, ptr
, DEFAULT_UPDATE_LEASE
); if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
3395 LogOperation("SendRecordRegistration TCP %p %s", rr
->tcp
, ARDisplayString(m
, rr
));
3396 if (rr
->tcp
) LogOperation("SendRecordRegistration: Disposing existing TCP connection for %s", ARDisplayString(m
, rr
));
3397 if (rr
->tcp
) DisposeTCPConn(rr
->tcp
);
3398 rr
->tcp
= MakeTCPConn(m
, &m
->omsg
, ptr
, kTCPSocketFlags_UseTLS
, &rr
->UpdateServer
, rr
->UpdatePort
, mDNSNULL
, mDNSNULL
, rr
);
3399 if (!rr
->tcp
) rr
->ThisAPInterval
= mDNSPlatformOneSecond
* 5; // If failed to make TCP connection, try again in ten seconds (5*2)
3400 else if (rr
->ThisAPInterval
< mDNSPlatformOneSecond
* 30) rr
->ThisAPInterval
= mDNSPlatformOneSecond
* 30;
3404 err
= mDNSSendDNSMessage(m
, &m
->omsg
, ptr
, mDNSInterface_Any
, mDNSNULL
, &rr
->UpdateServer
, rr
->UpdatePort
, mDNSNULL
, GetAuthInfoForName_internal(m
, rr
->resrec
.name
));
3405 if (err
) debugf("ERROR: SendRecordRegistration - mDNSSendDNSMessage - %ld", err
);
3408 SetRecordRetry(m
, rr
, err
);
3410 if (rr
->state
!= regState_Refresh
&& rr
->state
!= regState_DeregDeferred
&& rr
->state
!= regState_UpdatePending
)
3411 rr
->state
= regState_Pending
;
3416 LogMsg("SendRecordRegistration: Error formatting message for %s", ARDisplayString(m
, rr
));
3419 // Called with lock held
3420 mDNSlocal
void hndlServiceUpdateReply(mDNS
*const m
, ServiceRecordSet
*srs
, mStatus err
)
3422 mDNSBool InvokeCallback
= mDNSfalse
;
3423 ExtraResourceRecord
**e
= &srs
->Extras
;
3424 AuthRecord
*txt
= &srs
->RR_TXT
;
3426 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
3427 LogMsg("hndlServiceUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
3429 LogOperation("hndlServiceUpdateReply: err %d state %d %##s", err
, srs
->state
, srs
->RR_SRV
.resrec
.name
->c
);
3431 SetRecordRetry(m
, &srs
->RR_SRV
, mStatus_NoError
);
3435 case regState_Pending
:
3436 if (err
== mStatus_NameConflict
&& !srs
->TestForSelfConflict
)
3438 srs
->TestForSelfConflict
= mDNStrue
;
3439 debugf("checking for self-conflict of service %##s", srs
->RR_SRV
.resrec
.name
->c
);
3440 SendServiceRegistration(m
, srs
);
3443 else if (srs
->TestForSelfConflict
)
3445 srs
->TestForSelfConflict
= mDNSfalse
;
3446 if (err
== mStatus_NoSuchRecord
) err
= mStatus_NameConflict
; // NoSuchRecord implies that our prereq was not met, so we actually have a name conflict
3447 if (!err
) srs
->state
= regState_Registered
;
3448 InvokeCallback
= mDNStrue
;
3451 else if (srs
->srs_uselease
&& err
== mStatus_UnknownErr
&& mDNSSameIPPort(srs
->SRSUpdatePort
, UnicastDNSPort
))
3453 LogMsg("Re-trying update of service %##s without lease option", srs
->RR_SRV
.resrec
.name
->c
);
3454 srs
->srs_uselease
= mDNSfalse
;
3455 SendServiceRegistration(m
, srs
);
3460 //!!!KRS make sure all structs will still get cleaned up when client calls DeregisterService with this state
3461 if (err
) LogMsg("Error %ld for registration of service %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
3462 else srs
->state
= regState_Registered
;
3463 InvokeCallback
= mDNStrue
;
3466 case regState_Refresh
:
3469 LogMsg("Error %ld for refresh of service %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
3470 InvokeCallback
= mDNStrue
;
3472 else srs
->state
= regState_Registered
;
3474 case regState_DeregPending
:
3475 if (err
) LogMsg("Error %ld for deregistration of service %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
3476 if (srs
->SRVChanged
)
3478 srs
->state
= regState_NoTarget
; // NoTarget will allow us to pick up new target OR nat traversal state
3481 err
= mStatus_MemFree
;
3482 InvokeCallback
= mDNStrue
;
3483 if (srs
->NATinfo
.clientContext
)
3485 // deletion completed
3486 mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
3487 srs
->NATinfo
.clientContext
= mDNSNULL
;
3489 srs
->state
= regState_Unregistered
;
3491 case regState_DeregDeferred
:
3494 debugf("Error %ld received prior to deferred derigstration of %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
3495 err
= mStatus_MemFree
;
3496 InvokeCallback
= mDNStrue
;
3497 srs
->state
= regState_Unregistered
;
3502 debugf("Performing deferred deregistration of %##s", srs
->RR_SRV
.resrec
.name
->c
);
3503 srs
->state
= regState_Registered
;
3504 SendServiceDeregistration(m
, srs
);
3507 case regState_UpdatePending
:
3510 LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs
->RR_SRV
.resrec
.name
->c
);
3511 InvokeCallback
= mDNStrue
;
3515 srs
->state
= regState_Registered
;
3516 // deallocate old RData
3517 if (txt
->UpdateCallback
) txt
->UpdateCallback(m
, txt
, txt
->OrigRData
);
3518 SetNewRData(&txt
->resrec
, txt
->InFlightRData
, txt
->InFlightRDLen
);
3519 txt
->OrigRData
= mDNSNULL
;
3520 txt
->InFlightRData
= mDNSNULL
;
3523 case regState_NoTarget
:
3524 // This state is used when using SendServiceDeregistration() when going to sleep -- no further action required
3526 case regState_FetchingZoneData
:
3527 case regState_Registered
:
3528 case regState_Unregistered
:
3529 case regState_NATMap
:
3530 case regState_ExtraQueued
:
3531 case regState_NATError
:
3532 LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %ld. Unlinking.",
3533 srs
->RR_SRV
.resrec
.name
->c
, srs
->state
, err
);
3534 err
= mStatus_UnknownErr
;
3535 default: LogMsg("hndlServiceUpdateReply: Unknown state %d for %##s", srs
->state
, srs
->RR_SRV
.resrec
.name
->c
);
3538 if ((srs
->SRVChanged
|| srs
->SRVUpdateDeferred
) && (srs
->state
== regState_NoTarget
|| srs
->state
== regState_Registered
))
3540 LogOperation("hndlServiceUpdateReply: SRVChanged %d SRVUpdateDeferred %d state %d", srs
->SRVChanged
, srs
->SRVUpdateDeferred
, srs
->state
);
3543 srs
->ClientCallbackDeferred
= mDNStrue
;
3544 srs
->DeferredStatus
= err
;
3546 srs
->SRVChanged
= srs
->SRVUpdateDeferred
= mDNSfalse
;
3553 if ((*e
)->r
.state
== regState_ExtraQueued
)
3555 if (srs
->state
== regState_Registered
&& !err
)
3557 // extra resource record queued for this service - copy zone srs and register
3558 AssignDomainName(&(*e
)->r
.zone
, &srs
->zone
);
3559 (*e
)->r
.UpdateServer
= srs
->SRSUpdateServer
;
3560 (*e
)->r
.UpdatePort
= srs
->SRSUpdatePort
;
3561 (*e
)->r
.uselease
= srs
->srs_uselease
;
3562 SendRecordRegistration(m
, &(*e
)->r
);
3565 else if (err
&& (*e
)->r
.state
!= regState_Unregistered
)
3567 // unlink extra from list
3568 (*e
)->r
.state
= regState_Unregistered
;
3571 else e
= &(*e
)->next
;
3573 else e
= &(*e
)->next
;
3576 if (srs
->state
== regState_Unregistered
)
3578 if (err
!= mStatus_MemFree
)
3579 LogMsg("hndlServiceUpdateReply ERROR! state == regState_Unregistered but err != mStatus_MemFree. Permanently abandoning service registration %##s",
3580 srs
->RR_SRV
.resrec
.name
->c
);
3583 else if (txt
->QueuedRData
&& srs
->state
== regState_Registered
)
3587 // if we were supposed to give a client callback, we'll do it after we update the primary txt record
3588 srs
->ClientCallbackDeferred
= mDNStrue
;
3589 srs
->DeferredStatus
= err
;
3591 srs
->state
= regState_UpdatePending
;
3592 txt
->InFlightRData
= txt
->QueuedRData
;
3593 txt
->InFlightRDLen
= txt
->QueuedRDLen
;
3594 txt
->OrigRData
= txt
->resrec
.rdata
;
3595 txt
->OrigRDLen
= txt
->resrec
.rdlength
;
3596 txt
->QueuedRData
= mDNSNULL
;
3597 SendServiceRegistration(m
, srs
);
3601 mDNS_DropLockBeforeCallback();
3603 srs
->ServiceCallback(m
, srs
, err
);
3604 else if (srs
->ClientCallbackDeferred
)
3606 srs
->ClientCallbackDeferred
= mDNSfalse
;
3607 srs
->ServiceCallback(m
, srs
, srs
->DeferredStatus
);
3609 mDNS_ReclaimLockAfterCallback();
3610 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
3611 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
3614 // Called with lock held
3615 mDNSlocal
void hndlRecordUpdateReply(mDNS
*m
, AuthRecord
*rr
, mStatus err
)
3617 mDNSBool InvokeCallback
= mDNStrue
;
3619 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
3620 LogMsg("hndlRecordUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
3622 LogOperation("hndlRecordUpdateReply: err %d state %d %s", err
, rr
->state
, ARDisplayString(m
, rr
));
3624 if (m
->SleepState
) return; // If we just sent a deregister on going to sleep, no further action required
3626 SetRecordRetry(m
, rr
, mStatus_NoError
);
3628 if (rr
->state
== regState_UpdatePending
)
3630 if (err
) LogMsg("Update record failed for %##s (err %d)", rr
->resrec
.name
->c
, err
);
3631 rr
->state
= regState_Registered
;
3632 // deallocate old RData
3633 if (rr
->UpdateCallback
) rr
->UpdateCallback(m
, rr
, rr
->OrigRData
);
3634 SetNewRData(&rr
->resrec
, rr
->InFlightRData
, rr
->InFlightRDLen
);
3635 rr
->OrigRData
= mDNSNULL
;
3636 rr
->InFlightRData
= mDNSNULL
;
3639 if (rr
->state
== regState_DeregPending
)
3641 debugf("Received reply for deregister record %##s type %d", rr
->resrec
.name
->c
, rr
->resrec
.rrtype
);
3642 if (err
) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %ld",
3643 rr
->resrec
.name
->c
, rr
->resrec
.rrtype
, err
);
3644 err
= mStatus_MemFree
;
3645 rr
->state
= regState_Unregistered
;
3648 if (rr
->state
== regState_DeregDeferred
)
3652 LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %ld",
3653 rr
->resrec
.name
->c
, rr
->resrec
.rrtype
, err
);
3654 rr
->state
= regState_Unregistered
;
3656 debugf("Calling deferred deregistration of record %##s type %d", rr
->resrec
.name
->c
, rr
->resrec
.rrtype
);
3657 rr
->state
= regState_Registered
;
3658 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
3662 if (rr
->state
== regState_Pending
|| rr
->state
== regState_Refresh
)
3666 if (rr
->state
== regState_Refresh
) InvokeCallback
= mDNSfalse
;
3667 rr
->state
= regState_Registered
;
3671 if (rr
->uselease
&& err
== mStatus_UnknownErr
&& mDNSSameIPPort(rr
->UpdatePort
, UnicastDNSPort
))
3673 LogMsg("Re-trying update of record %##s without lease option", rr
->resrec
.name
->c
);
3674 rr
->uselease
= mDNSfalse
;
3675 SendRecordRegistration(m
, rr
);
3678 LogMsg("hndlRecordUpdateReply: Registration of record %##s type %d failed with error %ld", rr
->resrec
.name
->c
, rr
->resrec
.rrtype
, err
);
3683 if (rr
->state
== regState_Unregistered
) // Should never happen
3685 LogMsg("hndlRecordUpdateReply rr->state == regState_Unregistered %s", ARDisplayString(m
, rr
));
3689 if (rr
->QueuedRData
&& rr
->state
== regState_Registered
)
3691 rr
->state
= regState_UpdatePending
;
3692 rr
->InFlightRData
= rr
->QueuedRData
;
3693 rr
->InFlightRDLen
= rr
->QueuedRDLen
;
3694 rr
->OrigRData
= rr
->resrec
.rdata
;
3695 rr
->OrigRDLen
= rr
->resrec
.rdlength
;
3696 rr
->QueuedRData
= mDNSNULL
;
3697 SendRecordRegistration(m
, rr
);
3701 if (InvokeCallback
&& rr
->RecordCallback
)
3703 mDNS_DropLockBeforeCallback();
3704 rr
->RecordCallback(m
, rr
, err
);
3705 mDNS_ReclaimLockAfterCallback();
3707 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
3708 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
3711 mDNSexport
void uDNS_ReceiveNATPMPPacket(mDNS
*m
, const mDNSInterfaceID InterfaceID
, mDNSu8
*pkt
, mDNSu16 len
)
3713 NATTraversalInfo
*ptr
;
3714 NATAddrReply
*AddrReply
= (NATAddrReply
*)pkt
;
3715 NATPortMapReply
*PortMapReply
= (NATPortMapReply
*)pkt
;
3716 mDNSu32 nat_elapsed
, our_elapsed
;
3718 // Minimum packet is vers (1) opcode (1) err (2) upseconds (4) = 8 bytes
3719 if (!AddrReply
->err
&& len
< 8) { LogMsg("NAT Traversal message too short (%d bytes)", len
); return; }
3720 if (AddrReply
->vers
!= NATMAP_VERS
) { LogMsg("Received NAT Traversal response with version %d (expected %d)", pkt
[0], NATMAP_VERS
); return; }
3722 // Read multi-byte numeric values (fields are identical in a NATPortMapReply)
3723 AddrReply
->err
= (mDNSu16
) ( (mDNSu16
)pkt
[2] << 8 | pkt
[3]);
3724 AddrReply
->upseconds
= (mDNSs32
) ((mDNSs32
)pkt
[4] << 24 | (mDNSs32
)pkt
[5] << 16 | (mDNSs32
)pkt
[6] << 8 | pkt
[7]);
3726 nat_elapsed
= AddrReply
->upseconds
- m
->LastNATupseconds
;
3727 our_elapsed
= (m
->timenow
- m
->LastNATReplyLocalTime
) / mDNSPlatformOneSecond
;
3728 LogOperation("uDNS_ReceiveNATPMPPacket %X upseconds %u nat_elapsed %d our_elapsed %d", AddrReply
->opcode
, AddrReply
->upseconds
, nat_elapsed
, our_elapsed
);
3730 // We compute a conservative estimate of how much the NAT gateways's clock should have advanced
3731 // 1. We subtract 12.5% from our own measured elapsed time, to allow for NAT gateways that have an inacurate clock that runs slowly
3732 // 2. We add a two-second safety margin to allow for rounding errors:
3733 // -- e.g. if NAT gateway sends a packet at t=2.00 seconds, then one at t=7.99, that's virtually 6 seconds,
3734 // but based on the values in the packet (2,7) the apparent difference is only 5 seconds
3735 // -- similarly, if we're slow handling packets and/or we have coarse clock granularity, we could over-estimate the true interval
3736 // (e.g. t=1.99 seconds rounded to 1, and t=8.01 rounded to 8, gives an apparent difference of 7 seconds)
3737 if (AddrReply
->upseconds
< m
->LastNATupseconds
|| nat_elapsed
+ 2 < our_elapsed
- our_elapsed
/8)
3738 { LogMsg("NAT gateway %#a rebooted", &m
->Router
); RecreateNATMappings(m
); }
3740 m
->LastNATupseconds
= AddrReply
->upseconds
;
3741 m
->LastNATReplyLocalTime
= m
->timenow
;
3742 ClearUPnPState(m
); // We know this is a NAT-PMP base station, so discard any prior UPnP state
3744 if (AddrReply
->opcode
== NATOp_AddrResponse
)
3746 if (!AddrReply
->err
&& len
< sizeof(NATAddrReply
)) { LogMsg("NAT Traversal AddrResponse message too short (%d bytes)", len
); return; }
3747 natTraversalHandleAddressReply(m
, AddrReply
->err
, AddrReply
->ExtAddr
);
3749 else if (AddrReply
->opcode
== NATOp_MapUDPResponse
|| AddrReply
->opcode
== NATOp_MapTCPResponse
)
3751 mDNSu8 Protocol
= AddrReply
->opcode
& 0x7F;
3752 if (!PortMapReply
->err
)
3754 if (len
< sizeof(NATPortMapReply
)) { LogMsg("NAT Traversal PortMapReply message too short (%d bytes)", len
); return; }
3755 PortMapReply
->NATRep_lease
= (mDNSu32
) ((mDNSu32
)pkt
[12] << 24 | (mDNSu32
)pkt
[13] << 16 | (mDNSu32
)pkt
[14] << 8 | pkt
[15]);
3758 for (ptr
= m
->NATTraversals
; ptr
; ptr
=ptr
->next
)
3759 if (ptr
->Protocol
== Protocol
&& mDNSSameIPPort(ptr
->IntPort
, PortMapReply
->intport
))
3760 natTraversalHandlePortMapReply(m
, ptr
, InterfaceID
, PortMapReply
->err
, PortMapReply
->extport
, PortMapReply
->NATRep_lease
);
3762 else { LogMsg("Received NAT Traversal response with version unknown opcode 0x%X", AddrReply
->opcode
); return; }
3764 // Don't need an SSDP socket if we get a NAT-PMP packet
3765 if (m
->SSDPSocket
) { LogOperation("uDNS_ReceiveNATPMPPacket destroying SSDPSocket %p", &m
->SSDPSocket
); mDNSPlatformUDPClose(m
->SSDPSocket
); m
->SSDPSocket
= mDNSNULL
; }
3768 // <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
3769 // <rdar://problem/4288449> Add check to avoid crashing NAT gateways that have buggy DNS relay code
3771 // We know of bugs in home NAT gateways that cause them to crash if they receive certain DNS queries.
3772 // The DNS queries that make them crash are perfectly legal DNS queries, but even if they weren't,
3773 // the gateway shouldn't crash -- in today's world of viruses and network attacks, software has to
3774 // be written assuming that a malicious attacker could send them any packet, properly-formed or not.
3775 // Still, we don't want to be crashing people's home gateways, so we go out of our way to avoid
3776 // the queries that crash them.
3780 // 1. Any query where the name ends in ".in-addr.arpa." and the text before this is 32 or more bytes.
3781 // The query type does not need to be PTR -- the gateway will crash for any query type.
3782 // e.g. "ping long-name-crashes-the-buggy-router.in-addr.arpa" will crash one of these.
3784 // 2. Any query that results in a large response with the TC bit set.
3786 // 3. Any PTR query that doesn't begin with four decimal numbers.
3787 // These gateways appear to assume that the only possible PTR query is a reverse-mapping query
3788 // (e.g. "1.0.168.192.in-addr.arpa") and if they ever get a PTR query where the first four
3789 // labels are not all decimal numbers in the range 0-255, they handle that by crashing.
3790 // These gateways also ignore the remainder of the name following the four decimal numbers
3791 // -- whether or not it actually says in-addr.arpa, they just make up an answer anyway.
3793 // The challenge therefore is to craft a query that will discern whether the DNS server
3794 // is one of these buggy ones, without crashing it. Furthermore we don't want our test
3795 // queries making it all the way to the root name servers, putting extra load on those
3796 // name servers and giving Apple a bad reputation. To this end we send this query:
3797 // dig -t ptr 1.0.0.127.dnsbugtest.1.0.0.127.in-addr.arpa.
3799 // The text preceding the ".in-addr.arpa." is under 32 bytes, so it won't cause crash (1).
3800 // It will not yield a large response with the TC bit set, so it won't cause crash (2).
3801 // It starts with four decimal numbers, so it won't cause crash (3).
3802 // The name falls within the "1.0.0.127.in-addr.arpa." domain, the reverse-mapping name for the local
3803 // loopback address, and therefore the query will black-hole at the first properly-configured DNS server
3804 // it reaches, making it highly unlikely that this query will make it all the way to the root.
3806 // Finally, the correct response to this query is NXDOMAIN or a similar error, but the
3807 // gateways that ignore the remainder of the name following the four decimal numbers
3808 // give themselves away by actually returning a result for this nonsense query.
3810 mDNSlocal
const domainname
*DNSRelayTestQuestion
= (const domainname
*)
3811 "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\xa" "dnsbugtest"
3812 "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\x7" "in-addr" "\x4" "arpa";
3814 // See comments above for DNSRelayTestQuestion
3815 // If this is the kind of query that has the risk of crashing buggy DNS servers, we do a test question first
3816 mDNSlocal mDNSBool
NoTestQuery(DNSQuestion
*q
)
3819 mDNSu8
*p
= q
->qname
.c
;
3820 if (q
->AuthInfo
) return(mDNStrue
); // Don't need a test query for private queries sent directly to authoritative server over TLS/TCP
3821 if (q
->qtype
!= kDNSType_PTR
) return(mDNStrue
); // Don't need a test query for any non-PTR queries
3822 for (i
=0; i
<4; i
++) // If qname does not begin with num.num.num.num, can't skip the test query
3824 if (p
[0] < 1 || p
[0] > 3) return(mDNSfalse
);
3825 if ( p
[1] < '0' || p
[1] > '9' ) return(mDNSfalse
);
3826 if (p
[0] >= 2 && (p
[2] < '0' || p
[2] > '9')) return(mDNSfalse
);
3827 if (p
[0] >= 3 && (p
[3] < '0' || p
[3] > '9')) return(mDNSfalse
);
3830 // If remainder of qname is ".in-addr.arpa.", this is a vanilla reverse-mapping query and
3831 // we can safely do it without needing a test query first, otherwise we need the test query.
3832 return(SameDomainName((domainname
*)p
, (const domainname
*)"\x7" "in-addr" "\x4" "arpa"));
3835 // Returns mDNStrue if response was handled
3836 mDNSlocal mDNSBool
uDNS_ReceiveTestQuestionResponse(mDNS
*const m
, DNSMessage
*const msg
, const mDNSu8
*const end
,
3837 const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
)
3839 const mDNSu8
*ptr
= msg
->data
;
3844 // 1. Find out if this is an answer to one of our test questions
3845 if (msg
->h
.numQuestions
!= 1) return(mDNSfalse
);
3846 ptr
= getQuestion(msg
, ptr
, end
, mDNSInterface_Any
, &pktq
);
3847 if (!ptr
) return(mDNSfalse
);
3848 if (pktq
.qtype
!= kDNSType_PTR
|| pktq
.qclass
!= kDNSClass_IN
) return(mDNSfalse
);
3849 if (!SameDomainName(&pktq
.qname
, DNSRelayTestQuestion
)) return(mDNSfalse
);
3851 // 2. If the DNS relay gave us a positive response, then it's got buggy firmware
3852 // else, if the DNS relay gave us an error or no-answer response, it passed our test
3853 if ((msg
->h
.flags
.b
[1] & kDNSFlag1_RC_Mask
) == kDNSFlag1_RC_NoErr
&& msg
->h
.numAnswers
> 0)
3854 result
= DNSServer_Failed
;
3856 result
= DNSServer_Passed
;
3858 // 3. Find occurrences of this server in our list, and mark them appropriately
3859 for (s
= m
->DNSServers
; s
; s
= s
->next
)
3860 if (mDNSSameAddress(srcaddr
, &s
->addr
) && mDNSSameIPPort(srcport
, s
->port
) && s
->teststate
!= result
)
3863 s
->teststate
= result
;
3864 if (result
== DNSServer_Passed
) LogOperation("DNS Server %#a:%d passed", srcaddr
, mDNSVal16(srcport
));
3865 else LogMsg("NOTE: Wide-Area Service Discovery disabled to avoid crashing defective DNS relay %#a:%d", srcaddr
, mDNSVal16(srcport
));
3867 // If this server has just changed state from DNSServer_Untested to DNSServer_Passed, then retrigger any waiting questions.
3868 // We use the NoTestQuery() test so that we only retrigger questions that were actually blocked waiting for this test to complete.
3869 if (result
== DNSServer_Passed
) // Unblock any questions that were waiting for this result
3870 for (q
= m
->Questions
; q
; q
=q
->next
)
3871 if (q
->qDNSServer
== s
&& !NoTestQuery(q
))
3873 q
->ThisQInterval
= INIT_UCAST_POLL_INTERVAL
/ QuestionIntervalStep
;
3874 q
->unansweredQueries
= 0;
3875 q
->LastQTime
= m
->timenow
- q
->ThisQInterval
;
3876 m
->NextScheduledQuery
= m
->timenow
;
3880 return(mDNStrue
); // Return mDNStrue to tell uDNS_ReceiveMsg it doesn't need to process this packet further
3883 // Called from mDNSCoreReceive with the lock held
3884 mDNSexport
void uDNS_ReceiveMsg(mDNS
*const m
, DNSMessage
*const msg
, const mDNSu8
*const end
, const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
)
3887 mStatus err
= mStatus_NoError
;
3889 mDNSu8 StdR
= kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
;
3890 mDNSu8 UpdateR
= kDNSFlag0_QR_Response
| kDNSFlag0_OP_Update
;
3891 mDNSu8 QR_OP
= (mDNSu8
)(msg
->h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
);
3892 mDNSu8 rcode
= (mDNSu8
)(msg
->h
.flags
.b
[1] & kDNSFlag1_RC_Mask
);
3894 (void)srcport
; // Unused
3896 debugf("uDNS_ReceiveMsg from %#-15a with "
3897 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
3899 msg
->h
.numQuestions
, msg
->h
.numQuestions
== 1 ? ", " : "s,",
3900 msg
->h
.numAnswers
, msg
->h
.numAnswers
== 1 ? ", " : "s,",
3901 msg
->h
.numAuthorities
, msg
->h
.numAuthorities
== 1 ? "y, " : "ies,",
3902 msg
->h
.numAdditionals
, msg
->h
.numAdditionals
== 1 ? "" : "s");
3906 //if (srcaddr && recvLLQResponse(m, msg, end, srcaddr, srcport)) return;
3907 if (uDNS_ReceiveTestQuestionResponse(m
, msg
, end
, srcaddr
, srcport
)) return;
3908 for (qptr
= m
->Questions
; qptr
; qptr
= qptr
->next
)
3909 if (msg
->h
.flags
.b
[0] & kDNSFlag0_TC
&& mDNSSameOpaque16(qptr
->TargetQID
, msg
->h
.id
) && m
->timenow
- qptr
->LastQTime
< RESPONSE_WINDOW
)
3911 if (!srcaddr
) LogMsg("uDNS_ReceiveMsg: TCP DNS response had TC bit set: ignoring");
3914 // There may be a race condition here, if the server decides to drop the connection just as we decide to reuse it
3915 // For now it should not be serious because our normal retry logic (as used to handle UDP packet loss)
3916 // should take care of it but later we may want to look at handling this case explicitly
3917 LogOperation("uDNS_ReceiveMsg: Using existing TCP connection for %##s (%s)", qptr
->qname
.c
, DNSTypeName(qptr
->qtype
));
3918 mDNS_DropLockBeforeCallback();
3919 tcpCallback(qptr
->tcp
->sock
, qptr
->tcp
, mDNStrue
, mStatus_NoError
);
3920 mDNS_ReclaimLockAfterCallback();
3922 else qptr
->tcp
= MakeTCPConn(m
, mDNSNULL
, mDNSNULL
, kTCPSocketFlags_Zero
, srcaddr
, srcport
, qptr
, mDNSNULL
, mDNSNULL
);
3926 if (QR_OP
== UpdateR
)
3928 mDNSu32 lease
= GetPktLease(m
, msg
, end
);
3929 mDNSs32 expire
= m
->timenow
+ (mDNSs32
)lease
* mDNSPlatformOneSecond
;
3931 //rcode = kDNSFlag1_RC_SrvErr; // Simulate server failure (rcode 2)
3933 if (CurrentServiceRecordSet
)
3934 LogMsg("uDNS_ReceiveMsg ERROR CurrentServiceRecordSet already set");
3935 CurrentServiceRecordSet
= m
->ServiceRegistrations
;
3937 while (CurrentServiceRecordSet
)
3939 ServiceRecordSet
*sptr
= CurrentServiceRecordSet
;
3940 CurrentServiceRecordSet
= CurrentServiceRecordSet
->uDNS_next
;
3942 if (mDNSSameOpaque16(sptr
->id
, msg
->h
.id
))
3944 err
= checkUpdateResult(m
, sptr
->RR_SRV
.resrec
.name
, rcode
, msg
, end
);
3945 if (!err
&& sptr
->srs_uselease
&& lease
)
3946 if (sptr
->RR_SRV
.expire
- expire
>= 0 || sptr
->state
!= regState_UpdatePending
)
3947 sptr
->RR_SRV
.expire
= expire
;
3948 hndlServiceUpdateReply(m
, sptr
, err
);
3949 CurrentServiceRecordSet
= mDNSNULL
;
3954 if (m
->CurrentRecord
)
3955 LogMsg("uDNS_ReceiveMsg ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
3956 m
->CurrentRecord
= m
->ResourceRecords
;
3957 while (m
->CurrentRecord
)
3959 AuthRecord
*rptr
= m
->CurrentRecord
;
3960 m
->CurrentRecord
= m
->CurrentRecord
->next
;
3961 if (mDNSSameOpaque16(rptr
->id
, msg
->h
.id
))
3963 err
= checkUpdateResult(m
, rptr
->resrec
.name
, rcode
, msg
, end
);
3964 if (!err
&& rptr
->uselease
&& lease
)
3965 if (rptr
->expire
- expire
>= 0 || rptr
->state
!= regState_UpdatePending
)
3966 rptr
->expire
= expire
;
3967 hndlRecordUpdateReply(m
, rptr
, err
);
3968 m
->CurrentRecord
= mDNSNULL
;
3973 debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg
->h
.id
));
3976 // ***************************************************************************
3977 #if COMPILER_LIKES_PRAGMA_MARK
3978 #pragma mark - Query Routines
3981 mDNSexport
void sendLLQRefresh(mDNS
*m
, DNSQuestion
*q
)
3987 if ((q
->state
== LLQ_Established
&& q
->ntries
>= kLLQ_MAX_TRIES
) || q
->expire
- m
->timenow
< 0)
3989 LogMsg("Unable to refresh LLQ %##s (%s) - will retry in %d seconds", q
->qname
.c
, DNSTypeName(q
->qtype
), LLQ_POLL_INTERVAL
/ mDNSPlatformOneSecond
);
3990 StartLLQPolling(m
,q
);
3994 llq
.vers
= kLLQ_Vers
;
3995 llq
.llqOp
= kLLQOp_Refresh
;
3996 llq
.err
= q
->tcp
? GetLLQEventPort(m
, &q
->servAddr
) : LLQErr_NoError
; // If using TCP tell server what UDP port to send notifications to
3998 llq
.llqlease
= q
->ReqLease
;
4000 InitializeDNSMessage(&m
->omsg
.h
, q
->TargetQID
, uQueryFlags
);
4001 end
= putLLQ(&m
->omsg
, m
->omsg
.data
, q
, &llq
, mDNStrue
);
4002 if (!end
) { LogMsg("sendLLQRefresh: putLLQ failed %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
)); return; }
4004 // Note that we (conditionally) add HINFO and TSIG here, since the question might be going away,
4005 // so we may not be able to reference it (most importantly it's AuthInfo) when we actually send the message
4006 end
= putHINFO(m
, &m
->omsg
, end
, q
->AuthInfo
);
4007 if (!end
) { LogMsg("sendLLQRefresh: putHINFO failed %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
)); return; }
4011 DNSDigest_SignMessageHostByteOrder(&m
->omsg
, &end
, q
->AuthInfo
);
4012 if (!end
) { LogMsg("sendLLQRefresh: DNSDigest_SignMessage failed %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
)); return; }
4015 if (q
->AuthInfo
&& !q
->tcp
)
4017 LogOperation("sendLLQRefresh setting up new TLS session %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4018 q
->tcp
= MakeTCPConn(m
, &m
->omsg
, end
, kTCPSocketFlags_UseTLS
, &q
->servAddr
, q
->servPort
, q
, mDNSNULL
, mDNSNULL
);
4022 mStatus err
= mDNSSendDNSMessage(m
, &m
->omsg
, end
, mDNSInterface_Any
, q
->LocalSocket
, &q
->servAddr
, q
->servPort
, q
->tcp
? q
->tcp
->sock
: mDNSNULL
, mDNSNULL
);
4025 LogMsg("sendLLQRefresh: mDNSSendDNSMessage%s failed: %d", q
->tcp
? " (TCP)" : "", err
);
4026 if (q
->tcp
) { DisposeTCPConn(q
->tcp
); q
->tcp
= mDNSNULL
; }
4032 debugf("sendLLQRefresh ntries %d %##s (%s)", q
->ntries
, q
->qname
.c
, DNSTypeName(q
->qtype
));
4034 q
->LastQTime
= m
->timenow
;
4035 SetNextQueryTime(m
, q
);
4038 mDNSexport
void LLQGotZoneData(mDNS
*const m
, mStatus err
, const ZoneData
*zoneInfo
)
4040 DNSQuestion
*q
= (DNSQuestion
*)zoneInfo
->ZoneDataContext
;
4044 // If we get here it means that the GetZoneData operation has completed, and is is about to cancel
4045 // its question and free the ZoneData memory. We no longer need to hold onto our pointer (which
4046 // we use for cleaning up if our LLQ is cancelled *before* the GetZoneData operation has completes).
4048 q
->servAddr
= zeroAddr
;
4049 q
->servPort
= zeroIPPort
;
4051 if (!err
&& zoneInfo
&& !mDNSIPPortIsZero(zoneInfo
->Port
) && !mDNSAddressIsZero(&zoneInfo
->Addr
))
4053 q
->servAddr
= zoneInfo
->Addr
;
4054 q
->servPort
= zoneInfo
->Port
;
4055 q
->AuthInfo
= zoneInfo
->ZonePrivate
? GetAuthInfoForName_internal(m
, &q
->qname
) : mDNSNULL
;
4057 LogOperation("LLQGotZoneData %#a:%d", &q
->servAddr
, mDNSVal16(q
->servPort
));
4058 startLLQHandshake(m
, q
);
4061 StartLLQPolling(m
,q
);
4066 // Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
4067 mDNSlocal
void PrivateQueryGotZoneData(mDNS
*const m
, mStatus err
, const ZoneData
*zoneInfo
)
4069 DNSQuestion
*q
= (DNSQuestion
*) zoneInfo
->ZoneDataContext
;
4071 LogOperation("PrivateQueryGotZoneData %##s (%s) err %d Zone %##s Private %d", q
->qname
.c
, DNSTypeName(q
->qtype
), err
, zoneInfo
->ZoneName
.c
, zoneInfo
->ZonePrivate
);
4073 // If we get here it means that the GetZoneData operation has completed, and is is about to cancel
4074 // its question and free the ZoneData memory. We no longer need to hold onto our pointer (which
4075 // we use for cleaning up if our LLQ is cancelled *before* the GetZoneData operation has completes).
4078 if (err
|| !zoneInfo
|| mDNSAddressIsZero(&zoneInfo
->Addr
) || mDNSIPPortIsZero(zoneInfo
->Port
))
4080 LogOperation("ERROR: PrivateQueryGotZoneData %##s (%s) invoked with error code %ld %p %#a:%d",
4081 q
->qname
.c
, DNSTypeName(q
->qtype
), err
, zoneInfo
,
4082 zoneInfo
? &zoneInfo
->Addr
: mDNSNULL
,
4083 zoneInfo
? mDNSVal16(zoneInfo
->Port
) : 0);
4087 if (!zoneInfo
->ZonePrivate
)
4089 debugf("Private port lookup failed -- retrying without TLS -- %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4090 q
->AuthInfo
= mDNSNULL
; // Clear AuthInfo so we try again non-private
4091 q
->ThisQInterval
= InitialQuestionInterval
;
4092 q
->LastQTime
= m
->timenow
- q
->ThisQInterval
;
4094 SetNextQueryTime(m
, q
);
4097 // Next call to uDNS_CheckCurrentQuestion() will do this as a non-private query
4102 LogMsg("ERROR: PrivateQueryGotZoneData: cannot find credentials for q %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4106 q
->TargetQID
= mDNS_NewMessageID(m
);
4107 if (q
->tcp
) DisposeTCPConn(q
->tcp
);
4108 q
->tcp
= MakeTCPConn(m
, mDNSNULL
, mDNSNULL
, kTCPSocketFlags_UseTLS
, &zoneInfo
->Addr
, zoneInfo
->Port
, q
, mDNSNULL
, mDNSNULL
);
4111 // ***************************************************************************
4112 #if COMPILER_LIKES_PRAGMA_MARK
4113 #pragma mark - Dynamic Updates
4116 // Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
4117 mDNSexport
void RecordRegistrationGotZoneData(mDNS
*const m
, mStatus err
, const ZoneData
*zoneData
)
4119 AuthRecord
*newRR
= (AuthRecord
*)zoneData
->ZoneDataContext
;
4122 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
)
4123 LogMsg("RecordRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
4125 newRR
->nta
= mDNSNULL
;
4127 // Start off assuming we're going to use a lease
4128 // 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
4129 newRR
->uselease
= mDNStrue
;
4131 // make sure record is still in list (!!!)
4132 for (ptr
= m
->ResourceRecords
; ptr
; ptr
= ptr
->next
) if (ptr
== newRR
) break;
4133 if (!ptr
) { LogMsg("RecordRegistrationGotZoneData - RR no longer in list. Discarding."); return; }
4135 // check error/result
4138 if (err
!= mStatus_NoSuchNameErr
) LogMsg("RecordRegistrationGotZoneData: error %ld", err
);
4142 if (!zoneData
) { LogMsg("ERROR: RecordRegistrationGotZoneData invoked with NULL result and no error"); return; }
4144 if (newRR
->resrec
.rrclass
!= zoneData
->ZoneClass
)
4146 LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)", newRR
->resrec
.rrclass
, zoneData
->ZoneClass
);
4150 // Don't try to do updates to the root name server.
4151 // We might be tempted also to block updates to any single-label name server (e.g. com, edu, net, etc.) but some
4152 // organizations use their own private pseudo-TLD, like ".home", etc, and we don't want to block that.
4153 if (zoneData
->ZoneName
.c
[0] == 0)
4155 LogOperation("RecordRegistrationGotZoneData: No name server found claiming responsibility for \"%##s\"!", newRR
->resrec
.name
->c
);
4159 // Store discovered zone data
4160 AssignDomainName(&newRR
->zone
, &zoneData
->ZoneName
);
4161 newRR
->UpdateServer
= zoneData
->Addr
;
4162 newRR
->UpdatePort
= zoneData
->Port
;
4163 newRR
->Private
= zoneData
->ZonePrivate
;
4164 debugf("RecordRegistrationGotZoneData: Set newRR->UpdateServer %##s %##s to %#a:%d",
4165 newRR
->resrec
.name
->c
, zoneData
->ZoneName
.c
, &newRR
->UpdateServer
, mDNSVal16(newRR
->UpdatePort
));
4167 if (mDNSIPPortIsZero(zoneData
->Port
) || mDNSAddressIsZero(&zoneData
->Addr
))
4169 LogOperation("RecordRegistrationGotZoneData: No _dns-update._udp service found for \"%##s\"!", newRR
->resrec
.name
->c
);
4173 newRR
->ThisAPInterval
= 5 * mDNSPlatformOneSecond
; // After doubling, first retry will happen after ten seconds
4175 mDNS_Lock(m
); // SendRecordRegistration expects to be called with the lock held
4176 SendRecordRegistration(m
, newRR
);
4180 mDNSlocal
void SendRecordDeregistration(mDNS
*m
, AuthRecord
*rr
)
4182 mDNSu8
*ptr
= m
->omsg
.data
;
4183 mDNSu8
*end
= (mDNSu8
*)&m
->omsg
+ sizeof(DNSMessage
);
4185 if (mDNSIPv4AddressIsZero(rr
->UpdateServer
.ip
.v4
)) // Don't know our UpdateServer yet
4187 rr
->LastAPTime
= m
->timenow
;
4188 if (rr
->ThisAPInterval
< mDNSPlatformOneSecond
* 5)
4189 rr
->ThisAPInterval
= mDNSPlatformOneSecond
* 5;
4193 InitializeDNSMessage(&m
->omsg
.h
, rr
->id
, UpdateReqFlags
);
4195 ptr
= putZone(&m
->omsg
, ptr
, end
, &rr
->zone
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
4196 if (ptr
) ptr
= putDeletionRecord(&m
->omsg
, ptr
, &rr
->resrec
);
4199 LogMsg("SendRecordDeregistration Error: could not contruct deregistration packet for %s", ARDisplayString(m
, rr
));
4200 if (rr
->state
== regState_DeregPending
) CompleteDeregistration(m
, rr
);
4204 rr
->expire
= 0; // Indicate that we have no active registration any more
4207 LogOperation("SendRecordDeregistration TCP %p %s", rr
->tcp
, ARDisplayString(m
, rr
));
4208 if (rr
->tcp
) LogOperation("SendRecordDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m
, rr
));
4209 if (rr
->tcp
) DisposeTCPConn(rr
->tcp
);
4210 rr
->tcp
= MakeTCPConn(m
, &m
->omsg
, ptr
, kTCPSocketFlags_UseTLS
, &rr
->UpdateServer
, rr
->UpdatePort
, mDNSNULL
, mDNSNULL
, rr
);
4211 if (!rr
->tcp
) rr
->ThisAPInterval
= mDNSPlatformOneSecond
* 5; // If failed to make TCP connection, try again in ten seconds (5*2)
4212 else if (rr
->ThisAPInterval
< mDNSPlatformOneSecond
* 30) rr
->ThisAPInterval
= mDNSPlatformOneSecond
* 30;
4213 SetRecordRetry(m
, rr
, mStatus_NoError
);
4217 mStatus err
= mDNSSendDNSMessage(m
, &m
->omsg
, ptr
, mDNSInterface_Any
, mDNSNULL
, &rr
->UpdateServer
, rr
->UpdatePort
, mDNSNULL
, GetAuthInfoForName_internal(m
, rr
->resrec
.name
));
4218 if (err
) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %ld", err
);
4219 if (rr
->state
== regState_DeregPending
) CompleteDeregistration(m
, rr
); // Don't touch rr after this
4224 mDNSexport mStatus
uDNS_DeregisterRecord(mDNS
*const m
, AuthRecord
*const rr
)
4228 case regState_NATMap
: LogMsg("regState_NATMap %##s type %s", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
)); return mStatus_NoError
;
4229 case regState_ExtraQueued
: rr
->state
= regState_Unregistered
; break;
4230 case regState_Refresh
:
4231 case regState_Pending
:
4232 case regState_UpdatePending
:
4233 case regState_FetchingZoneData
:
4234 case regState_Registered
: break;
4235 case regState_DeregPending
: break;
4236 case regState_DeregDeferred
: LogMsg("regState_DeregDeferred %##s type %s", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
)); return mStatus_NoError
;
4237 case regState_Unregistered
: LogMsg("regState_Unregistered %##s type %s", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
)); return mStatus_NoError
;
4238 case regState_NATError
: LogMsg("regState_NATError %##s type %s", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
)); return mStatus_NoError
;
4239 case regState_NoTarget
: LogMsg("regState_NoTarget %##s type %s", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
)); return mStatus_NoError
;
4240 default: LogMsg("uDNS_DeregisterRecord: State %d for %##s type %s", rr
->state
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
)); return mStatus_NoError
;
4243 if (rr
->state
!= regState_Unregistered
) { rr
->state
= regState_DeregPending
; SendRecordDeregistration(m
, rr
); }
4244 return mStatus_NoError
;
4247 // Called with lock held
4248 mDNSexport mStatus
uDNS_DeregisterService(mDNS
*const m
, ServiceRecordSet
*srs
)
4250 char *errmsg
= "Unknown State";
4252 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
4253 LogMsg("uDNS_DeregisterService: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
4255 // don't re-register with a new target following deregistration
4256 srs
->SRVChanged
= srs
->SRVUpdateDeferred
= mDNSfalse
;
4258 if (srs
->nta
) { CancelGetZoneData(m
, srs
->nta
); srs
->nta
= mDNSNULL
; }
4260 if (srs
->NATinfo
.clientContext
)
4262 mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
4263 srs
->NATinfo
.clientContext
= mDNSNULL
;
4268 case regState_Unregistered
:
4269 debugf("uDNS_DeregisterService - service %##s not registered", srs
->RR_SRV
.resrec
.name
->c
);
4270 return mStatus_BadReferenceErr
;
4271 case regState_DeregPending
:
4272 case regState_DeregDeferred
:
4273 debugf("Double deregistration of service %##s", srs
->RR_SRV
.resrec
.name
->c
);
4274 return mStatus_NoError
;
4275 case regState_NATError
: // not registered
4276 case regState_NATMap
: // not registered
4277 case regState_NoTarget
: // not registered
4279 srs
->state
= regState_Unregistered
;
4280 mDNS_DropLockBeforeCallback();
4281 srs
->ServiceCallback(m
, srs
, mStatus_MemFree
);
4282 mDNS_ReclaimLockAfterCallback();
4283 return mStatus_NoError
;
4284 case regState_Pending
:
4285 case regState_Refresh
:
4286 case regState_UpdatePending
:
4287 case regState_FetchingZoneData
:
4288 case regState_Registered
:
4289 srs
->state
= regState_DeregPending
;
4290 SendServiceDeregistration(m
, srs
);
4291 return mStatus_NoError
;
4292 case regState_ExtraQueued
: // only for record registrations
4293 errmsg
= "bad state (regState_ExtraQueued)";
4295 default: LogMsg("uDNS_DeregisterService: Unknown state %d for %##s", srs
->state
, srs
->RR_SRV
.resrec
.name
->c
);
4299 LogMsg("Error, uDNS_DeregisterService: %s", errmsg
);
4300 return mStatus_BadReferenceErr
;
4303 mDNSexport mStatus
uDNS_UpdateRecord(mDNS
*m
, AuthRecord
*rr
)
4305 ServiceRecordSet
*parent
= mDNSNULL
;
4307 regState_t
*stateptr
= mDNSNULL
;
4309 // find the record in registered service list
4310 for (parent
= m
->ServiceRegistrations
; parent
; parent
= parent
->uDNS_next
)
4311 if (&parent
->RR_TXT
== rr
) { stateptr
= &parent
->state
; break; }
4315 // record not part of a service - check individual record registrations
4316 for (rptr
= m
->ResourceRecords
; rptr
; rptr
= rptr
->next
)
4317 if (rptr
== rr
) { stateptr
= &rr
->state
; break; }
4318 if (!rptr
) goto unreg_error
;
4323 case regState_DeregPending
:
4324 case regState_DeregDeferred
:
4325 case regState_Unregistered
:
4326 // not actively registered
4329 case regState_FetchingZoneData
:
4330 case regState_NATMap
:
4331 case regState_ExtraQueued
:
4332 case regState_NoTarget
:
4333 // change rdata directly since it hasn't been sent yet
4334 if (rr
->UpdateCallback
) rr
->UpdateCallback(m
, rr
, rr
->resrec
.rdata
);
4335 SetNewRData(&rr
->resrec
, rr
->NewRData
, rr
->newrdlength
);
4336 rr
->NewRData
= mDNSNULL
;
4337 return mStatus_NoError
;
4339 case regState_Pending
:
4340 case regState_Refresh
:
4341 case regState_UpdatePending
:
4342 // registration in-flight. queue rdata and return
4343 if (rr
->QueuedRData
&& rr
->UpdateCallback
)
4344 // if unsent rdata is already queued, free it before we replace it
4345 rr
->UpdateCallback(m
, rr
, rr
->QueuedRData
);
4346 rr
->QueuedRData
= rr
->NewRData
;
4347 rr
->QueuedRDLen
= rr
->newrdlength
;
4348 rr
->NewRData
= mDNSNULL
;
4349 return mStatus_NoError
;
4351 case regState_Registered
:
4352 rr
->OrigRData
= rr
->resrec
.rdata
;
4353 rr
->OrigRDLen
= rr
->resrec
.rdlength
;
4354 rr
->InFlightRData
= rr
->NewRData
;
4355 rr
->InFlightRDLen
= rr
->newrdlength
;
4356 rr
->NewRData
= mDNSNULL
;
4357 *stateptr
= regState_UpdatePending
;
4358 if (parent
) SendServiceRegistration(m
, parent
);
4359 else SendRecordRegistration(m
, rr
);
4360 return mStatus_NoError
;
4362 case regState_NATError
:
4363 LogMsg("ERROR: uDNS_UpdateRecord called for record %##s with bad state regState_NATError", rr
->resrec
.name
->c
);
4364 return mStatus_UnknownErr
; // states for service records only
4366 default: LogMsg("uDNS_UpdateRecord: Unknown state %d for %##s", *stateptr
, rr
->resrec
.name
->c
);
4370 LogMsg("Requested update of record %##s type %d, part of service not currently registered",
4371 rr
->resrec
.name
->c
, rr
->resrec
.rrtype
);
4372 return mStatus_Invalid
;
4375 // ***************************************************************************
4376 #if COMPILER_LIKES_PRAGMA_MARK
4377 #pragma mark - Periodic Execution Routines
4380 // The question to be checked is not passed in as an explicit parameter;
4381 // instead it is implicit that the question to be checked is m->CurrentQuestion.
4382 mDNSexport
void uDNS_CheckCurrentQuestion(mDNS
*const m
)
4384 DNSQuestion
*q
= m
->CurrentQuestion
;
4385 mDNSs32 sendtime
= q
->LastQTime
+ q
->ThisQInterval
;
4386 // Don't allow sendtime to be earlier than SuppressStdPort53Queries
4387 if (!q
->LongLived
&& m
->SuppressStdPort53Queries
&& sendtime
- m
->SuppressStdPort53Queries
< 0)
4388 sendtime
= m
->SuppressStdPort53Queries
;
4389 if (m
->timenow
- sendtime
< 0) return;
4395 case LLQ_InitialRequest
: startLLQHandshake(m
, q
); break;
4396 case LLQ_SecondaryRequest
: sendChallengeResponse(m
, q
, mDNSNULL
); break;
4397 case LLQ_Established
: sendLLQRefresh(m
, q
); break;
4398 case LLQ_Poll
: break; // Do nothing (handled below)
4402 // We repeat the check above (rather than just making this the "else" case) because startLLQHandshake can change q->state to LLQ_Poll
4403 if (!(q
->LongLived
&& q
->state
!= LLQ_Poll
))
4405 if (q
->unansweredQueries
>= MAX_UCAST_UNANSWERED_QUERIES
)
4407 DNSServer
*orig
= q
->qDNSServer
;
4409 #if LogAllOperations || MDNS_DEBUGMSGS
4412 mDNS_snprintf(buffer
, sizeof(buffer
), orig
? "%#a:%d (%##s)" : "null", &orig
->addr
, mDNSVal16(orig
->port
), orig
->domain
.c
);
4413 LogOperation("Sent %d unanswered queries for %##s (%s) to %s", q
->unansweredQueries
, q
->qname
.c
, DNSTypeName(q
->qtype
), buffer
);
4416 PushDNSServerToEnd(m
, q
);
4417 q
->qDNSServer
= GetServerForName(m
, &q
->qname
);
4419 if (q
->qDNSServer
!= orig
)
4421 #if LogAllOperations || MDNS_DEBUGMSGS
4422 mDNS_snprintf(buffer
, sizeof(buffer
), q
->qDNSServer
? "%#a:%d (%##s)" : "null", &q
->qDNSServer
->addr
, mDNSVal16(q
->qDNSServer
->port
), q
->qDNSServer
->domain
.c
);
4423 LogOperation("Server for %##s (%s) changed to %s", q
->qname
.c
, DNSTypeName(q
->qtype
), buffer
);
4425 q
->ThisQInterval
= q
->ThisQInterval
/ QuestionIntervalStep
; // Decrease interval one step so we don't quickly bounce between servers for queries that will not be answered.
4428 q
->unansweredQueries
= 0;
4431 if (q
->qDNSServer
&& q
->qDNSServer
->teststate
!= DNSServer_Disabled
)
4433 mDNSu8
*end
= m
->omsg
.data
;
4434 mStatus err
= mStatus_NoError
;
4435 mDNSBool
private = mDNSfalse
;
4437 InitializeDNSMessage(&m
->omsg
.h
, q
->TargetQID
, uQueryFlags
);
4439 if (q
->qDNSServer
->teststate
!= DNSServer_Untested
|| NoTestQuery(q
))
4441 end
= putQuestion(&m
->omsg
, m
->omsg
.data
, m
->omsg
.data
+ AbsoluteMaxDNSMessageData
, &q
->qname
, q
->qtype
, q
->qclass
);
4442 private = (q
->AuthInfo
&& q
->AuthInfo
->AutoTunnel
);
4444 else if (m
->timenow
- q
->qDNSServer
->lasttest
>= INIT_UCAST_POLL_INTERVAL
) // Make sure at least three seconds has elapsed since last test query
4446 LogOperation("Sending DNS test query to %#a:%d", &q
->qDNSServer
->addr
, mDNSVal16(q
->qDNSServer
->port
));
4447 q
->ThisQInterval
= INIT_UCAST_POLL_INTERVAL
/ QuestionIntervalStep
;
4448 q
->qDNSServer
->lasttest
= m
->timenow
;
4449 end
= putQuestion(&m
->omsg
, m
->omsg
.data
, m
->omsg
.data
+ AbsoluteMaxDNSMessageData
, DNSRelayTestQuestion
, kDNSType_PTR
, kDNSClass_IN
);
4452 if (end
> m
->omsg
.data
&& (q
->qDNSServer
->teststate
!= DNSServer_Failed
|| NoTestQuery(q
)))
4454 //LogMsg("uDNS_CheckCurrentQuestion %p %d %p %##s (%s)", q, sendtime - m->timenow, private, q->qname.c, DNSTypeName(q->qtype));
4457 if (q
->nta
) CancelGetZoneData(m
, q
->nta
);
4458 q
->nta
= StartGetZoneData(m
, &q
->qname
, q
->LongLived
? ZoneServiceLLQ
: ZoneServiceQuery
, PrivateQueryGotZoneData
, q
);
4459 q
->ThisQInterval
= (LLQ_POLL_INTERVAL
+ mDNSRandom(LLQ_POLL_INTERVAL
/10)) / QuestionIntervalStep
;
4463 err
= mDNSSendDNSMessage(m
, &m
->omsg
, end
, q
->qDNSServer
->interface
, q
->LocalSocket
, &q
->qDNSServer
->addr
, q
->qDNSServer
->port
, mDNSNULL
, mDNSNULL
);
4464 m
->SuppressStdPort53Queries
= NonZeroTime(m
->timenow
+ (mDNSPlatformOneSecond
+99)/100);
4468 if (err
) debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %ld", err
); // surpress syslog messages if we have no network
4471 q
->ThisQInterval
= q
->ThisQInterval
* QuestionIntervalStep
; // Only increase interval if send succeeded
4472 q
->unansweredQueries
++;
4473 if (q
->ThisQInterval
> MAX_UCAST_POLL_INTERVAL
)
4474 q
->ThisQInterval
= MAX_UCAST_POLL_INTERVAL
;
4475 LogOperation("Increased ThisQInterval to %d for %##s (%s)", q
->ThisQInterval
, q
->qname
.c
, DNSTypeName(q
->qtype
));
4477 q
->LastQTime
= m
->timenow
;
4478 SetNextQueryTime(m
, q
);
4482 // If we have no server for this query, or the only server is a disabled one, then we deliver
4483 // a transient failure indication to the client. This is important for things like iPhone
4484 // where we want to return timely feedback to the user when no network is available.
4485 // After calling MakeNegativeCacheRecord() we store the resulting record in the
4486 // cache so that it will be visible to other clients asking the same question.
4487 // (When we have a group of identical questions, only the active representative of the group gets
4488 // passed to uDNS_CheckCurrentQuestion -- we only want one set of query packets hitting the wire --
4489 // but we want *all* of the questions to get answer callbacks.)
4492 const mDNSu32 slot
= HashSlot(&q
->qname
);
4493 CacheGroup
*const cg
= CacheGroupForName(m
, slot
, q
->qnamehash
, &q
->qname
);
4495 for (rr
= cg
->members
; rr
; rr
=rr
->next
)
4496 if (SameNameRecordAnswersQuestion(&rr
->resrec
, q
)) mDNS_PurgeCacheResourceRecord(m
, rr
);
4498 if (!q
->qDNSServer
) LogOperation("uDNS_CheckCurrentQuestion no DNS server for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4499 else LogMsg("uDNS_CheckCurrentQuestion DNS server %#a:%d for %##s is disabled", &q
->qDNSServer
->addr
, mDNSVal16(q
->qDNSServer
->port
), q
->qname
.c
);
4501 MakeNegativeCacheRecord(m
, &q
->qname
, q
->qnamehash
, q
->qtype
, q
->qclass
, 60);
4502 // Inactivate this question until the next change of DNS servers (do this before AnswerCurrentQuestionWithResourceRecord)
4503 q
->ThisQInterval
= 0;
4504 q
->unansweredQueries
= 0;
4505 CreateNewCacheEntry(m
, slot
, cg
);
4506 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
4507 // MUST NOT touch m->CurrentQuestion (or q) after this -- client callback could have deleted it
4512 mDNSlocal
void CheckNATMappings(mDNS
*m
)
4514 mStatus err
= mStatus_NoError
;
4515 mDNSBool rfc1918
= mDNSv4AddrIsRFC1918(&m
->AdvertisedV4
.ip
.v4
);
4516 mDNSBool HaveRoutable
= !rfc1918
&& !mDNSIPv4AddressIsZero(m
->AdvertisedV4
.ip
.v4
);
4517 m
->NextScheduledNATOp
= m
->timenow
+ 0x3FFFFFFF;
4519 if (HaveRoutable
) m
->ExternalAddress
= m
->AdvertisedV4
.ip
.v4
;
4521 if (m
->NATTraversals
&& rfc1918
) // Do we need to open NAT-PMP socket to receive multicast announcements from router?
4523 if (m
->NATMcastRecvskt
== mDNSNULL
) // If we are behind a NAT and the socket hasn't been opened yet, open it
4525 m
->NATMcastRecvskt
= mDNSPlatformUDPSocket(m
, NATPMPAnnouncementPort
);
4526 m
->NATMcastRecvsk2
= mDNSPlatformUDPSocket(m
, NATPMPPort
); // For backwards compatibility with older base stations that announce on 5351
4527 if (!m
->NATMcastRecvskt
) LogMsg("CheckNATMappings: Failed to allocate port 5350 UDP multicast socket for NAT-PMP announcements");
4528 if (!m
->NATMcastRecvsk2
) LogOperation("CheckNATMappings: Failed to allocate port 5351 UDP multicast socket for NAT-PMP announcements");
4531 else // else, we don't want to listen for announcements, so close them if they're open
4533 if (m
->NATMcastRecvskt
) { mDNSPlatformUDPClose(m
->NATMcastRecvskt
); m
->NATMcastRecvskt
= mDNSNULL
; }
4534 if (m
->NATMcastRecvsk2
) { mDNSPlatformUDPClose(m
->NATMcastRecvsk2
); m
->NATMcastRecvsk2
= mDNSNULL
; }
4535 if (m
->SSDPSocket
) { LogOperation("CheckNATMappings destroying SSDPSocket %p", &m
->SSDPSocket
); mDNSPlatformUDPClose(m
->SSDPSocket
); m
->SSDPSocket
= mDNSNULL
; }
4538 if (m
->NATTraversals
)
4540 if (m
->timenow
- m
->retryGetAddr
>= 0)
4542 err
= uDNS_SendNATMsg(m
, mDNSNULL
); // Will also do UPnP discovery for us, if necessary
4545 if (m
->retryIntervalGetAddr
< NATMAP_INIT_RETRY
) m
->retryIntervalGetAddr
= NATMAP_INIT_RETRY
;
4546 else if (m
->retryIntervalGetAddr
< NATMAP_MAX_RETRY_INTERVAL
/ 2) m
->retryIntervalGetAddr
*= 2;
4547 else m
->retryIntervalGetAddr
= NATMAP_MAX_RETRY_INTERVAL
;
4549 // Always update m->retryGetAddr, even if we fail to send the packet. Otherwise in cases where we can't send the packet
4550 // (like when we have no active interfaces) we'll spin in an infinite loop repeatedly failing to send the packet
4551 m
->retryGetAddr
= m
->timenow
+ m
->retryIntervalGetAddr
;
4553 // Even when we didn't send the GetAddr packet, still need to make sure NextScheduledNATOp is set correctly
4554 if (m
->NextScheduledNATOp
- m
->retryGetAddr
> 0)
4555 m
->NextScheduledNATOp
= m
->retryGetAddr
;
4558 if (m
->CurrentNATTraversal
) LogMsg("WARNING m->CurrentNATTraversal already in use");
4559 m
->CurrentNATTraversal
= m
->NATTraversals
;
4561 while (m
->CurrentNATTraversal
)
4563 NATTraversalInfo
*cur
= m
->CurrentNATTraversal
;
4564 m
->CurrentNATTraversal
= m
->CurrentNATTraversal
->next
;
4566 if (HaveRoutable
) // If not RFC 1918 address, our own address and port are effectively our external address and port
4568 cur
->ExpiryTime
= 0;
4569 cur
->NewResult
= mStatus_NoError
;
4571 else if (cur
->Protocol
) // Check if it's time to send port mapping packets
4573 if (m
->timenow
- cur
->retryPortMap
>= 0) // Time to do something with this mapping
4575 if (cur
->ExpiryTime
&& cur
->ExpiryTime
- m
->timenow
< 0) // Mapping has expired
4577 cur
->ExpiryTime
= 0;
4578 cur
->retryInterval
= NATMAP_INIT_RETRY
;
4581 //LogMsg("uDNS_SendNATMsg");
4582 err
= uDNS_SendNATMsg(m
, cur
);
4584 if (cur
->ExpiryTime
) // If have active mapping then set next renewal time halfway to expiry
4585 NATSetNextRenewalTime(m
, cur
);
4586 else // else no mapping; use exponential backoff sequence
4588 if (cur
->retryInterval
< NATMAP_INIT_RETRY
) cur
->retryInterval
= NATMAP_INIT_RETRY
;
4589 else if (cur
->retryInterval
< NATMAP_MAX_RETRY_INTERVAL
/ 2) cur
->retryInterval
*= 2;
4590 else cur
->retryInterval
= NATMAP_MAX_RETRY_INTERVAL
;
4591 cur
->retryPortMap
= m
->timenow
+ cur
->retryInterval
;
4595 if (m
->NextScheduledNATOp
- cur
->retryPortMap
> 0)
4596 m
->NextScheduledNATOp
= cur
->retryPortMap
;
4599 // Notify the client if necessary. We invoke the callback if:
4600 // (1) we have an ExternalAddress, or we've tried and failed a couple of times to discover it
4601 // 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
4602 // and (3) we have new data to give the client that's changed since the last callback
4603 if (!mDNSIPv4AddressIsZero(m
->ExternalAddress
) || m
->retryIntervalGetAddr
> NATMAP_INIT_RETRY
* 8)
4605 const mStatus EffectiveResult
= cur
->NewResult
? cur
->NewResult
: mDNSv4AddrIsRFC1918(&m
->ExternalAddress
) ? mStatus_DoubleNAT
: mStatus_NoError
;
4606 const mDNSIPPort ExternalPort
= HaveRoutable
? cur
->IntPort
:
4607 !mDNSIPv4AddressIsZero(m
->ExternalAddress
) && cur
->ExpiryTime
? cur
->RequestedPort
: zeroIPPort
;
4608 if (!cur
->Protocol
|| HaveRoutable
|| cur
->ExpiryTime
|| cur
->retryInterval
> NATMAP_INIT_RETRY
* 8)
4609 if (!mDNSSameIPv4Address(cur
->ExternalAddress
, m
->ExternalAddress
) ||
4610 !mDNSSameIPPort (cur
->ExternalPort
, ExternalPort
) ||
4611 cur
->Result
!= EffectiveResult
)
4613 //LogMsg("NAT callback %d %d %d", cur->Protocol, cur->ExpiryTime, cur->retryInterval);
4614 if (cur
->Protocol
&& mDNSIPPortIsZero(ExternalPort
) && !mDNSIPv4AddressIsZero(m
->Router
.ip
.v4
))
4615 LogMsg("Failed to obtain NAT port mapping %p from router %#a external address %.4a internal port %d error %d",
4616 cur
, &m
->Router
, &m
->ExternalAddress
, mDNSVal16(cur
->IntPort
), EffectiveResult
);
4618 cur
->ExternalAddress
= m
->ExternalAddress
;
4619 cur
->ExternalPort
= ExternalPort
;
4620 cur
->Lifetime
= cur
->ExpiryTime
&& !mDNSIPPortIsZero(ExternalPort
) ?
4621 (cur
->ExpiryTime
- m
->timenow
+ mDNSPlatformOneSecond
/2) / mDNSPlatformOneSecond
: 0;
4622 cur
->Result
= EffectiveResult
;
4623 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
4624 if (cur
->clientCallback
)
4625 cur
->clientCallback(m
, cur
);
4626 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
4627 // MUST NOT touch cur after invoking the callback
4633 mDNSlocal mDNSs32
CheckRecordRegistrations(mDNS
*m
)
4636 mDNSs32 nextevent
= m
->timenow
+ 0x3FFFFFFF;
4638 for (rr
= m
->ResourceRecords
; rr
; rr
= rr
->next
)
4640 if (rr
->state
== regState_FetchingZoneData
||
4641 rr
->state
== regState_Pending
|| rr
->state
== regState_DeregPending
|| rr
->state
== regState_UpdatePending
||
4642 rr
->state
== regState_DeregDeferred
|| rr
->state
== regState_Refresh
|| rr
->state
== regState_Registered
)
4644 if (rr
->LastAPTime
+ rr
->ThisAPInterval
- m
->timenow
< 0)
4646 if (rr
->tcp
) { DisposeTCPConn(rr
->tcp
); rr
->tcp
= mDNSNULL
; }
4647 if (rr
->state
== regState_FetchingZoneData
)
4649 if (rr
->nta
) CancelGetZoneData(m
, rr
->nta
);
4650 rr
->nta
= StartGetZoneData(m
, rr
->resrec
.name
, ZoneServiceUpdate
, RecordRegistrationGotZoneData
, rr
);
4651 SetRecordRetry(m
, rr
, mStatus_NoError
);
4653 else if (rr
->state
== regState_DeregPending
) SendRecordDeregistration(m
, rr
);
4654 else SendRecordRegistration(m
, rr
);
4656 if (nextevent
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) > 0)
4657 nextevent
= (rr
->LastAPTime
+ rr
->ThisAPInterval
);
4663 mDNSlocal mDNSs32
CheckServiceRegistrations(mDNS
*m
)
4665 mDNSs32 nextevent
= m
->timenow
+ 0x3FFFFFFF;
4667 if (CurrentServiceRecordSet
)
4668 LogMsg("CheckServiceRegistrations ERROR CurrentServiceRecordSet already set");
4669 CurrentServiceRecordSet
= m
->ServiceRegistrations
;
4671 // Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery
4672 while (CurrentServiceRecordSet
)
4674 ServiceRecordSet
*srs
= CurrentServiceRecordSet
;
4675 CurrentServiceRecordSet
= CurrentServiceRecordSet
->uDNS_next
;
4676 if (srs
->state
== regState_FetchingZoneData
||
4677 srs
->state
== regState_Pending
|| srs
->state
== regState_DeregPending
|| srs
->state
== regState_DeregDeferred
||
4678 srs
->state
== regState_Refresh
|| srs
->state
== regState_UpdatePending
|| srs
->state
== regState_Registered
)
4680 if (srs
->RR_SRV
.LastAPTime
+ srs
->RR_SRV
.ThisAPInterval
- m
->timenow
<= 0)
4682 if (srs
->tcp
) { DisposeTCPConn(srs
->tcp
); srs
->tcp
= mDNSNULL
; }
4683 if (srs
->state
== regState_FetchingZoneData
)
4685 if (srs
->nta
) CancelGetZoneData(m
, srs
->nta
);
4686 srs
->nta
= StartGetZoneData(m
, srs
->RR_SRV
.resrec
.name
, ZoneServiceUpdate
, ServiceRegistrationGotZoneData
, srs
);
4687 SetRecordRetry(m
, &srs
->RR_SRV
, mStatus_NoError
);
4689 else if (srs
->state
== regState_DeregPending
) SendServiceDeregistration(m
, srs
);
4690 else SendServiceRegistration(m
, srs
);
4692 if (nextevent
- (srs
->RR_SRV
.LastAPTime
+ srs
->RR_SRV
.ThisAPInterval
) > 0)
4693 nextevent
= (srs
->RR_SRV
.LastAPTime
+ srs
->RR_SRV
.ThisAPInterval
);
4699 mDNSexport
void uDNS_Execute(mDNS
*const m
)
4703 m
->NextuDNSEvent
= m
->timenow
+ 0x3FFFFFFF;
4705 if (m
->NextSRVUpdate
&& m
->NextSRVUpdate
- m
->timenow
< 0)
4706 { m
->NextSRVUpdate
= 0; UpdateSRVRecords(m
); }
4708 CheckNATMappings(m
);
4710 if (m
->SuppressStdPort53Queries
&& m
->timenow
- m
->SuppressStdPort53Queries
>= 0)
4711 m
->SuppressStdPort53Queries
= 0; // If suppression time has passed, clear it
4713 nexte
= CheckRecordRegistrations(m
);
4714 if (nexte
- m
->NextuDNSEvent
< 0) m
->NextuDNSEvent
= nexte
;
4716 nexte
= CheckServiceRegistrations(m
);
4717 if (nexte
- m
->NextuDNSEvent
< 0) m
->NextuDNSEvent
= nexte
;
4720 // ***************************************************************************
4721 #if COMPILER_LIKES_PRAGMA_MARK
4722 #pragma mark - Startup, Shutdown, and Sleep
4725 // simplest sleep logic - rather than having sleep states that must be dealt with explicitly in all parts of
4726 // the code, we simply send a deregistration, and put the service in Refresh state, with a timeout far enough
4727 // in the future that we'll sleep (or the sleep will be cancelled) before it is retransmitted. Then to wake,
4728 // we just move up the timers.
4730 mDNSexport
void SleepRecordRegistrations(mDNS
*m
)
4733 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
4734 if (AuthRecord_uDNS(rr
))
4735 if (rr
->state
== regState_Registered
||
4736 rr
->state
== regState_Refresh
)
4738 SendRecordDeregistration(m
, rr
);
4739 rr
->state
= regState_Refresh
;
4740 rr
->LastAPTime
= m
->timenow
;
4741 rr
->ThisAPInterval
= 300 * mDNSPlatformOneSecond
;
4745 mDNSexport
void SleepServiceRegistrations(mDNS
*m
)
4747 ServiceRecordSet
*srs
= m
->ServiceRegistrations
;
4750 LogOperation("SleepServiceRegistrations: state %d %s", srs
->state
, ARDisplayString(m
, &srs
->RR_SRV
));
4751 if (srs
->nta
) { CancelGetZoneData(m
, srs
->nta
); srs
->nta
= mDNSNULL
; }
4753 if (srs
->NATinfo
.clientContext
)
4755 mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
4756 srs
->NATinfo
.clientContext
= mDNSNULL
;
4759 if (srs
->state
== regState_UpdatePending
)
4761 // act as if the update succeeded, since we're about to delete the name anyway
4762 AuthRecord
*txt
= &srs
->RR_TXT
;
4763 srs
->state
= regState_Registered
;
4764 // deallocate old RData
4765 if (txt
->UpdateCallback
) txt
->UpdateCallback(m
, txt
, txt
->OrigRData
);
4766 SetNewRData(&txt
->resrec
, txt
->InFlightRData
, txt
->InFlightRDLen
);
4767 txt
->OrigRData
= mDNSNULL
;
4768 txt
->InFlightRData
= mDNSNULL
;
4771 if (srs
->state
== regState_Registered
|| srs
->state
== regState_Refresh
)
4772 SendServiceDeregistration(m
, srs
);
4774 srs
->state
= regState_NoTarget
; // when we wake, we'll re-register (and optionally nat-map) once our address record completes
4775 srs
->RR_SRV
.resrec
.rdata
->u
.srv
.target
.c
[0] = 0;
4776 srs
->SRSUpdateServer
= zeroAddr
; // This will cause UpdateSRV to do a new StartGetZoneData
4777 srs
->RR_SRV
.ThisAPInterval
= 5 * mDNSPlatformOneSecond
; // After doubling, first retry will happen after ten seconds
4779 srs
= srs
->uDNS_next
;
4783 mDNSexport
void mDNS_AddSearchDomain(const domainname
*const domain
)
4787 // Check to see if we already have this domain in our list
4788 for (p
= &SearchList
; *p
; p
= &(*p
)->next
)
4789 if (SameDomainName(&(*p
)->domain
, domain
))
4791 // If domain is already in list, and marked for deletion, change it to "leave alone"
4792 if ((*p
)->flag
== -1) (*p
)->flag
= 0;
4793 LogOperation("mDNS_AddSearchDomain already in list %##s", domain
->c
);
4797 // if domain not in list, add to list, mark as add (1)
4798 *p
= mDNSPlatformMemAllocate(sizeof(SearchListElem
));
4799 if (!*p
) { LogMsg("ERROR: mDNS_AddSearchDomain - malloc"); return; }
4800 mDNSPlatformMemZero(*p
, sizeof(SearchListElem
));
4801 AssignDomainName(&(*p
)->domain
, domain
);
4802 (*p
)->flag
= 1; // add
4803 (*p
)->next
= mDNSNULL
;
4804 LogOperation("mDNS_AddSearchDomain created new %##s", domain
->c
);
4807 mDNSlocal
void FreeARElemCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
4810 if (result
== mStatus_MemFree
) mDNSPlatformMemFree(rr
->RecordContext
);
4813 mDNSlocal
void FoundDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
4815 SearchListElem
*slElem
= question
->QuestionContext
;
4818 if (answer
->rrtype
!= kDNSType_PTR
) return;
4819 if (answer
->RecordType
== kDNSRecordTypePacketNegative
) return;
4824 ARListElem
*arElem
= mDNSPlatformMemAllocate(sizeof(ARListElem
));
4825 if (!arElem
) { LogMsg("ERROR: malloc"); return; }
4826 mDNS_SetupResourceRecord(&arElem
->ar
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, FreeARElemCallback
, arElem
);
4827 if (question
== &slElem
->BrowseQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeBrowse
];
4828 else if (question
== &slElem
->DefBrowseQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeBrowseDefault
];
4829 else if (question
== &slElem
->AutomaticBrowseQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeBrowseAutomatic
];
4830 else if (question
== &slElem
->RegisterQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeRegistration
];
4831 else if (question
== &slElem
->DefRegisterQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeRegistrationDefault
];
4832 else { LogMsg("FoundDomain - unknown question"); mDNSPlatformMemFree(arElem
); return; }
4834 MakeDomainNameFromDNSNameString(&arElem
->ar
.namestorage
, name
);
4835 AppendDNSNameString (&arElem
->ar
.namestorage
, "local");
4836 AssignDomainName(&arElem
->ar
.resrec
.rdata
->u
.name
, &answer
->rdata
->u
.name
);
4837 err
= mDNS_Register(m
, &arElem
->ar
);
4838 if (err
) { LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err
); mDNSPlatformMemFree(arElem
); return; }
4839 arElem
->next
= slElem
->AuthRecs
;
4840 slElem
->AuthRecs
= arElem
;
4844 ARListElem
**ptr
= &slElem
->AuthRecs
;
4847 if (SameDomainName(&(*ptr
)->ar
.resrec
.rdata
->u
.name
, &answer
->rdata
->u
.name
))
4849 ARListElem
*dereg
= *ptr
;
4850 *ptr
= (*ptr
)->next
;
4851 debugf("Deregistering PTR %##s -> %##s", dereg
->ar
.resrec
.name
->c
, dereg
->ar
.resrec
.rdata
->u
.name
.c
);
4852 err
= mDNS_Deregister(m
, &dereg
->ar
);
4853 if (err
) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err
);
4854 // Memory will be freed in the FreeARElemCallback
4857 ptr
= &(*ptr
)->next
;
4862 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
4863 mDNSexport
void udns_validatelists(void *const v
)
4867 ServiceRecordSet
*s
;
4868 for (s
= m
->ServiceRegistrations
; s
; s
=s
->uDNS_next
)
4869 if (s
->uDNS_next
== (ServiceRecordSet
*)~0)
4870 LogMemCorruption("m->ServiceRegistrations: %p is garbage (%lX)", s
, s
->uDNS_next
);
4872 NATTraversalInfo
*n
;
4873 for (n
= m
->NATTraversals
; n
; n
=n
->next
)
4874 if (n
->next
== (NATTraversalInfo
*)~0 || n
->clientCallback
== (NATTraversalClientCallback
)~0)
4875 LogMemCorruption("m->NATTraversals: %p is garbage", n
);
4878 for (d
= m
->DNSServers
; d
; d
=d
->next
)
4879 if (d
->next
== (DNSServer
*)~0 || d
->teststate
> DNSServer_Disabled
)
4880 LogMemCorruption("m->DNSServers: %p is garbage (%d)", d
, d
->teststate
);
4882 DomainAuthInfo
*info
;
4883 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
4884 if (info
->next
== (DomainAuthInfo
*)~0 || info
->AutoTunnel
== (mDNSBool
)~0)
4885 LogMemCorruption("m->AuthInfoList: %p is garbage (%X)", info
, info
->AutoTunnel
);
4888 for (hi
= m
->Hostnames
; hi
; hi
= hi
->next
)
4889 if (hi
->next
== (HostnameInfo
*)~0 || hi
->StatusCallback
== (mDNSRecordCallback
*)~0)
4890 LogMemCorruption("m->Hostnames: %p is garbage", n
);
4892 SearchListElem
*ptr
;
4893 for (ptr
= SearchList
; ptr
; ptr
= ptr
->next
)
4894 if (ptr
->next
== (SearchListElem
*)~0 || ptr
->AuthRecs
== (void*)~0)
4895 LogMemCorruption("SearchList: %p is garbage (%X)", ptr
, ptr
->AuthRecs
);
4899 // This should probably move to the UDS daemon -- the concept of legacy clients and automatic registration / automatic browsing
4900 // is really a UDS API issue, not something intrinsic to uDNS
4902 mDNSexport mStatus
uDNS_RegisterSearchDomains(mDNS
*const m
)
4904 SearchListElem
**p
= &SearchList
, *ptr
;
4907 // step 1: mark each element for removal (-1)
4908 for (ptr
= SearchList
; ptr
; ptr
= ptr
->next
) ptr
->flag
= -1;
4910 // Client has requested domain enumeration or automatic browse -- time to make sure we have the search domains from the platform layer
4912 m
->RegisterSearchDomains
= mDNStrue
;
4913 mDNSPlatformSetDNSConfig(m
, mDNSfalse
, m
->RegisterSearchDomains
, mDNSNULL
, mDNSNULL
, mDNSNULL
);
4916 // delete elems marked for removal, do queries for elems marked add
4920 debugf("RegisterSearchDomains %d %p %##s", ptr
->flag
, ptr
->AuthRecs
, ptr
->domain
.c
);
4921 if (ptr
->flag
== -1) // remove
4923 ARListElem
*arList
= ptr
->AuthRecs
;
4924 ptr
->AuthRecs
= mDNSNULL
;
4927 mDNS_StopGetDomains(m
, &ptr
->BrowseQ
);
4928 mDNS_StopGetDomains(m
, &ptr
->RegisterQ
);
4929 mDNS_StopGetDomains(m
, &ptr
->DefBrowseQ
);
4930 mDNS_StopGetDomains(m
, &ptr
->DefRegisterQ
);
4931 mDNS_StopGetDomains(m
, &ptr
->AutomaticBrowseQ
);
4932 mDNSPlatformMemFree(ptr
);
4934 // deregister records generated from answers to the query
4937 ARListElem
*dereg
= arList
;
4938 arList
= arList
->next
;
4939 debugf("Deregistering PTR %##s -> %##s", dereg
->ar
.resrec
.name
->c
, dereg
->ar
.resrec
.rdata
->u
.name
.c
);
4940 err
= mDNS_Deregister(m
, &dereg
->ar
);
4941 if (err
) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err
);
4942 // Memory will be freed in the FreeARElemCallback
4947 if (ptr
->flag
== 1) // add
4949 mStatus err1
, err2
, err3
, err4
, err5
;
4950 err1
= mDNS_GetDomains(m
, &ptr
->BrowseQ
, mDNS_DomainTypeBrowse
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
4951 err2
= mDNS_GetDomains(m
, &ptr
->DefBrowseQ
, mDNS_DomainTypeBrowseDefault
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
4952 err3
= mDNS_GetDomains(m
, &ptr
->RegisterQ
, mDNS_DomainTypeRegistration
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
4953 err4
= mDNS_GetDomains(m
, &ptr
->DefRegisterQ
, mDNS_DomainTypeRegistrationDefault
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
4954 err5
= mDNS_GetDomains(m
, &ptr
->AutomaticBrowseQ
, mDNS_DomainTypeBrowseAutomatic
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
4955 if (err1
|| err2
|| err3
|| err4
|| err5
)
4956 LogMsg("GetDomains for domain %##s returned error(s):\n"
4957 "%d (mDNS_DomainTypeBrowse)\n"
4958 "%d (mDNS_DomainTypeBrowseDefault)\n"
4959 "%d (mDNS_DomainTypeRegistration)\n"
4960 "%d (mDNS_DomainTypeRegistrationDefault)"
4961 "%d (mDNS_DomainTypeBrowseAutomatic)\n",
4962 ptr
->domain
.c
, err1
, err2
, err3
, err4
, err5
);
4966 if (ptr
->flag
) { LogMsg("RegisterSearchDomains - unknown flag %d. Skipping.", ptr
->flag
); }
4971 return mStatus_NoError
;
4974 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
4975 // 1) query for b._dns-sd._udp.local on LocalOnly interface
4976 // (.local manually generated via explicit callback)
4977 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
4978 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
4979 // 4) result above should generate a callback from question in (1). result added to global list
4980 // 5) global list delivered to client via GetSearchDomainList()
4981 // 6) client calls to enumerate domains now go over LocalOnly interface
4982 // (!!!KRS may add outgoing interface in addition)
4984 struct CompileTimeAssertionChecks_uDNS
4986 // Check our structures are reasonable sizes. Including overly-large buffers, or embedding
4987 // other overly-large structures instead of having a pointer to them, can inadvertently
4988 // cause structure sizes (and therefore memory usage) to balloon unreasonably.
4989 char sizecheck_tcpInfo_t
[(sizeof(tcpInfo_t
) <= 9056) ? 1 : -1];
4990 char sizecheck_SearchListElem
[(sizeof(SearchListElem
) <= 3880) ? 1 : -1];