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.617 2009/06/30 20:51:02 cheshire
26 Improved "Error! Tried to add a NAT traversal that's already in the active list" debugging message
28 Revision 1.616 2009/05/27 20:29:36 cheshire
29 <rdar://problem/6926465> Sleep is delayed by 10 seconds if BTMM is on
30 After receiving confirmation of LLQ deletion, need to schedule another evaluation of whether we're ready to sleep yet
32 Revision 1.615 2009/05/05 01:32:50 jessic2
33 <rdar://problem/6830541> regservice_callback: instance->request is NULL 0 -- Clean up spurious logs resulting from fixing this bug.
35 Revision 1.614 2009/04/24 02:17:57 mcguire
36 <rdar://problem/5264124> uDNS: Not always respecting preference order of DNS servers
38 Revision 1.613 2009/04/23 22:06:29 cheshire
39 Added CacheRecord and InterfaceID parameters to MakeNegativeCacheRecord, in preparation for:
40 <rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
42 Revision 1.612 2009/04/22 01:19:57 jessic2
43 <rdar://problem/6814585> Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32
45 Revision 1.611 2009/04/15 20:42:51 mcguire
46 <rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures
48 Revision 1.610 2009/04/15 01:10:39 jessic2
49 <rdar://problem/6466541> BTMM: Add support for setting kDNSServiceErr_NoSuchRecord in DynamicStore
51 Revision 1.609 2009/04/11 00:19:45 jessic2
52 <rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
54 Revision 1.608 2009/04/06 23:44:59 cheshire
55 <rdar://problem/6757838> mDNSResponder thrashing kernel lock in the UDP close path, hurting SPECweb performance
57 Revision 1.607 2009/04/02 22:36:34 jessic2
58 Fix crash when calling debugf with null opt
60 Revision 1.606 2009/03/26 03:59:00 jessic2
61 Changes for <rdar://problem/6492552&6492593&6492609&6492613&6492628&6492640&6492699>
63 Revision 1.605 2009/03/04 00:40:14 cheshire
64 Updated DNS server error codes to be more consistent with definitions at
65 <http://www.iana.org/assignments/dns-parameters>
67 Revision 1.604 2009/02/27 03:08:47 cheshire
68 <rdar://problem/6547720> Crash while shutting down when "local" is in the user's DNS searchlist
70 Revision 1.603 2009/02/27 02:56:57 cheshire
71 Moved struct SearchListElem definition from uDNS.c into mDNSEmbeddedAPI.h
73 Revision 1.602 2009/02/13 06:29:54 cheshire
74 Converted LogOperation messages to LogInfo
76 Revision 1.601 2009/02/12 20:57:25 cheshire
77 Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch
79 Revision 1.600 2009/01/31 21:05:12 cheshire
80 Improved "Failed to obtain NAT port mapping" debugging log message
82 Revision 1.599 2009/01/23 00:38:36 mcguire
83 <rdar://problem/5570906> BTMM: Doesn't work with Linksys WRT54GS firmware 4.71.1
85 Revision 1.598 2009/01/21 03:43:57 mcguire
86 <rdar://problem/6511765> BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore
88 Revision 1.597 2009/01/10 01:55:49 cheshire
89 Added LogOperation message showing when domains are added and removed in FoundDomain
91 Revision 1.596 2008/12/19 20:23:33 mcguire
92 <rdar://problem/6459269> Lots of duplicate log messages about failure to bind to NAT-PMP Announcement port
94 Revision 1.595 2008/12/18 23:32:19 mcguire
95 <rdar://problem/6019470> BTMM: Include the question in the LLQ notification acknowledgment
97 Revision 1.594 2008/12/10 02:25:31 cheshire
98 Minor fixes to use of LogClientOperations symbol
100 Revision 1.593 2008/12/10 02:11:42 cheshire
101 ARMv5 compiler doesn't like uncommented stuff after #endif
103 Revision 1.592 2008/12/06 01:42:55 mcguire
104 <rdar://problem/6418958> Need to exponentially back-off after failure to get public address
106 Revision 1.591 2008/12/06 00:17:11 cheshire
107 <rdar://problem/6380477> mDNS_StopNATOperation doesn't handle duplicate NAT mapping requests properly
108 Refinement: For duplicate ssh mappings we want to suppress the syslog warning message, but not the "unmap = mDNSfalse"
110 Revision 1.590 2008/12/04 20:57:36 mcguire
113 Revision 1.589 2008/12/04 02:24:09 cheshire
114 Improved NAT-PMP debugging messages
116 Revision 1.588 2008/11/26 20:38:08 cheshire
117 Changed some "LogOperation" debugging messages to "debugf"
119 Revision 1.587 2008/11/26 19:53:26 cheshire
120 Don't overwrite srs->NATinfo.IntPort in StartSRVNatMap()
122 Revision 1.586 2008/11/25 23:43:07 cheshire
123 <rdar://problem/5745355> Crashes at ServiceRegistrationGotZoneData + 397
124 Made code more defensive to guard against ServiceRegistrationGotZoneData being called with invalid ServiceRecordSet object
126 Revision 1.585 2008/11/25 22:46:30 cheshire
127 For ease of code searching, renamed ZoneData field of ServiceRecordSet_struct from "nta" to "srs_nta"
129 Revision 1.584 2008/11/24 19:46:40 cheshire
130 When sending query over TCP, don't include LLQ option when we're talking to a conventional DNS server or cache
132 Revision 1.583 2008/11/21 00:34:58 cheshire
133 <rdar://problem/6380477> mDNS_StopNATOperation doesn't handle duplicate NAT mapping requests properly
135 Revision 1.582 2008/11/20 02:23:37 mcguire
136 <rdar://problem/6041208> need to handle URLBase
138 Revision 1.581 2008/11/20 01:51:19 cheshire
139 Exported RecreateNATMappings so it's callable from other files
141 Revision 1.580 2008/11/13 19:08:45 cheshire
142 Fixed code to handle rdataOPT properly
144 Revision 1.579 2008/11/07 00:18:01 mcguire
145 <rdar://problem/6351068> uDNS: Supress reverse DNS query until required
147 Revision 1.578 2008/11/04 22:21:46 cheshire
148 Changed zone field of AuthRecord_struct from domainname to pointer, saving 252 bytes per AuthRecord
150 Revision 1.577 2008/10/29 21:37:01 cheshire
151 Removed some old debugging messages
153 Revision 1.576 2008/10/23 22:25:57 cheshire
154 Renamed field "id" to more descriptive "updateid"
156 Revision 1.575 2008/10/20 02:07:49 mkrochma
157 <rdar://problem/6296804> Remove Note: DNS Server <ip> for domain <d> registered more than once
159 Revision 1.574 2008/10/14 19:06:45 cheshire
160 In uDNS_ReceiveMsg(), only do checkUpdateResult() for uDNS records
162 Revision 1.573 2008/09/25 20:43:44 cheshire
163 <rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
164 In UpdateSRVRecords, call mDNS_SetFQDN(m) to update AutoTarget SRV records on the main m->ResourceRecords list
166 Revision 1.572 2008/09/24 23:48:05 cheshire
167 Don't need to pass whole ServiceRecordSet reference to GetServiceTarget;
168 it only needs to access the embedded SRV member of the set
170 Revision 1.571 2008/09/23 22:56:53 cheshire
171 <rdar://problem/5298845> Remove dnsbugtest query
173 Revision 1.570 2008/09/23 01:30:18 cheshire
174 The putLLQ() routine was not setting the OPT record's rrclass to NormalMaxDNSMessageData
176 Revision 1.569 2008/07/25 22:34:11 mcguire
177 fix sizecheck issues for 64bit
179 Revision 1.568 2008/07/24 20:23:03 cheshire
180 <rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
182 Revision 1.567 2008/07/01 01:40:00 mcguire
183 <rdar://problem/5823010> 64-bit fixes
185 Revision 1.566 2008/06/26 17:24:11 mkrochma
186 <rdar://problem/5450912> BTMM: Stop listening on UDP 5351 for NAT Status Announcements
188 Revision 1.565 2008/06/21 19:06:58 mcguire
189 <rdar://problem/4206534> Use all configured DNS servers
191 Revision 1.564 2008/06/19 23:42:03 mcguire
192 <rdar://problem/4206534> Use all configured DNS servers
194 Revision 1.563 2008/06/19 17:46:14 mcguire
195 <rdar://problem/4206534> Use all configured DNS servers
196 Don't do extra work for log messages if we're not going to log
198 Revision 1.562 2008/06/19 17:35:19 mcguire
199 <rdar://problem/4206534> Use all configured DNS servers
201 check for null pointers
203 Revision 1.561 2008/06/19 01:20:49 mcguire
204 <rdar://problem/4206534> Use all configured DNS servers
206 Revision 1.560 2008/05/31 01:51:09 mcguire
207 fixed typo in log message
209 Revision 1.559 2008/04/15 22:37:58 mkrochma
210 Change LogMsg to LogOperation
212 Revision 1.558 2008/03/17 18:02:35 mkrochma
213 Add space to log message for consistency
215 Revision 1.557 2008/03/14 19:58:38 mcguire
216 <rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client
217 Make sure we add the record when sending LLQ refreshes
219 Revision 1.556 2008/03/07 23:55:05 cheshire
220 <rdar://problem/5787898> LLQ refresh randomization not working properly
222 Revision 1.555 2008/03/07 23:25:56 cheshire
223 Improved debugging messages
225 Revision 1.554 2008/03/07 18:56:03 cheshire
226 <rdar://problem/5777647> dnsbugtest query every three seconds when source IP address of response doesn't match
228 Revision 1.553 2008/03/06 02:48:34 mcguire
229 <rdar://problem/5321824> write status to the DS
231 Revision 1.552 2008/03/05 01:56:42 cheshire
232 <rdar://problem/5687667> BTMM: Don't fallback to unencrypted operations when SRV lookup fails
234 Revision 1.551 2008/03/01 01:43:04 cheshire
235 <rdar://problem/5631565> BTMM: Lots of "Error getting external address 3" when double-NATed prevents sleep
236 Added code to suppress logging of multiple identical error results
238 Revision 1.550 2008/03/01 01:34:47 cheshire
239 <rdar://problem/5736313> BTMM: Double-NAT'd machines register all but AutoTunnel v4 address records
242 Revision 1.549 2008/02/29 01:35:37 mcguire
243 <rdar://problem/5736313> BTMM: Double-NAT'd machines register all but AutoTunnel v4 address records
245 Revision 1.548 2008/02/20 23:54:18 cheshire
246 <rdar://problem/5661518> "Failed to obtain NAT port mapping" syslog messages
247 Improved log message so it tells us more about what's going on
249 Revision 1.547 2008/02/20 00:41:09 cheshire
250 Change "PrivateQueryGotZoneData ... invoked with error code" from LogMsg to LogOperation
252 Revision 1.546 2008/02/19 23:26:50 cheshire
253 <rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
255 Revision 1.545 2007/12/22 02:25:29 cheshire
256 <rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep
258 Revision 1.544 2007/12/18 00:40:11 cheshire
259 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
260 Reordered code to avoid double-TSIGs in some cases
262 Revision 1.543 2007/12/17 23:57:43 cheshire
263 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
264 Need to include TSIG signature when sending LLQ cancellations over TLS
266 Revision 1.542 2007/12/15 01:12:27 cheshire
267 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
269 Revision 1.541 2007/12/15 00:18:51 cheshire
270 Renamed question->origLease to question->ReqLease
272 Revision 1.540 2007/12/14 23:55:28 cheshire
273 Moved "struct tcpInfo_t" definition from uDNS.c to mDNSEmbeddedAPI.h
275 Revision 1.539 2007/12/14 20:44:24 cheshire
276 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
277 SleepRecordRegistrations/WakeRecordRegistrations should only operate on uDNS records
279 Revision 1.538 2007/12/14 01:13:40 cheshire
280 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
281 Additional fixes (existing code to deregister private records and services didn't work at all)
283 Revision 1.537 2007/12/11 00:18:25 cheshire
284 <rdar://problem/5569316> BTMM: My iMac has a "ghost" ID associated with it
285 There were cases where the code was incorrectly clearing the "uselease" flag, and never resetting it.
287 Revision 1.536 2007/12/10 23:07:00 cheshire
288 Removed some unnecessary log messages
290 Revision 1.535 2007/12/06 00:22:27 mcguire
291 <rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
293 Revision 1.534 2007/12/04 00:49:37 cheshire
294 <rdar://problem/5607082> BTMM: mDNSResponder taking 100 percent CPU after upgrading to 10.5.1
296 Revision 1.533 2007/12/01 01:21:27 jgraessley
297 <rdar://problem/5623140> mDNSResponder unicast DNS improvements
299 Revision 1.532 2007/11/30 20:16:44 cheshire
300 Fixed compile warning: declaration of 'end' shadows a previous local
302 Revision 1.531 2007/11/28 22:00:09 cheshire
303 In StartSRVNatMap, change "mDNSu8 *p" to "const mDNSu8 *p"
305 Revision 1.530 2007/11/16 22:19:40 cheshire
306 <rdar://problem/5547474> mDNSResponder leaks on network changes
307 The "connection failed" code path in MakeTCPConn was not disposing of the TCPSocket it had created
309 Revision 1.529 2007/11/15 22:52:29 cheshire
310 <rdar://problem/5589039> ERROR: mDNSPlatformWriteTCP - send Broken pipe
312 Revision 1.528 2007/11/02 21:32:30 cheshire
313 <rdar://problem/5575593> BTMM: Deferring deregistration of record log messages on sleep/wake
315 Revision 1.527 2007/11/01 16:08:51 cheshire
316 Tidy up alignment of "SetRecordRetry refresh" log messages
318 Revision 1.526 2007/10/31 19:26:55 cheshire
319 Don't need to log "Permanently abandoning service registration" message when we're intentionally deleting a service
321 Revision 1.525 2007/10/30 23:58:59 cheshire
322 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
323 After failure, double retry interval up to maximum of 30 minutes
325 Revision 1.524 2007/10/30 20:10:47 cheshire
326 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
328 Revision 1.523 2007/10/30 00:54:31 cheshire
329 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
330 Fixed timing logic to double retry interval properly
332 Revision 1.522 2007/10/30 00:04:43 cheshire
333 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
334 Made the code not give up and abandon the record when it gets an error in regState_UpdatePending state
336 Revision 1.521 2007/10/29 23:58:52 cheshire
337 <rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
338 Use standard "if (mDNSIPv4AddressIsOnes(....ExternalAddress))" mechanism to determine whether callback has been invoked yet
340 Revision 1.520 2007/10/29 21:48:36 cheshire
341 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
342 Added 10% random variation on LLQ renewal time, to reduce unintended timing correlation between multiple machines
344 Revision 1.519 2007/10/29 21:37:00 cheshire
345 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
346 Added 10% random variation on record refresh time, to reduce accidental timing correlation between multiple machines
348 Revision 1.518 2007/10/26 23:41:29 cheshire
349 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
351 Revision 1.517 2007/10/25 23:30:12 cheshire
352 Private DNS registered records now deregistered on sleep and re-registered on wake
354 Revision 1.516 2007/10/25 22:53:52 cheshire
355 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
356 Don't unlinkSRS and permanently give up at the first sign of trouble
358 Revision 1.515 2007/10/25 21:08:07 cheshire
359 Don't try to send record registrations/deletions before we have our server address
361 Revision 1.514 2007/10/25 20:48:47 cheshire
362 For naming consistency (with AuthRecord's UpdateServer) renamed 'ns' to 'SRSUpdateServer'
364 Revision 1.513 2007/10/25 20:06:13 cheshire
365 Don't try to do SOA queries using private DNS (TLS over TCP) queries
367 Revision 1.512 2007/10/25 18:25:15 cheshire
368 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
369 Don't need a NAT mapping for autotunnel services
371 Revision 1.511 2007/10/25 00:16:23 cheshire
372 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
373 Fixed retry timing logic; when DNS server returns an error code, we should retry later,
374 instead of just deleting our record ("UnlinkAuthRecord") and completely giving up
376 Revision 1.510 2007/10/24 22:40:06 cheshire
377 Renamed: RecordRegistrationCallback -> RecordRegistrationGotZoneData
378 Renamed: ServiceRegistrationZoneDataComplete -> ServiceRegistrationGotZoneData
380 Revision 1.509 2007/10/24 00:54:07 cheshire
381 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
383 Revision 1.508 2007/10/24 00:05:03 cheshire
384 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
385 When sending TLS/TCP LLQ setup request over VPN, need to set EventPort to 5353, not zero
387 Revision 1.507 2007/10/23 00:33:36 cheshire
388 Improved debugging messages
390 Revision 1.506 2007/10/22 19:54:13 cheshire
391 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
392 Only put EventPort in LLQ request when sending from an RFC 1918 source address, not when sending over VPN
394 Revision 1.505 2007/10/19 22:08:49 cheshire
395 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
396 Additional fixes and refinements
398 Revision 1.504 2007/10/18 23:06:43 cheshire
399 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
400 Additional fixes and refinements
402 Revision 1.503 2007/10/18 20:23:17 cheshire
403 Moved SuspendLLQs into mDNS.c, since it's only called from one place
405 Revision 1.502 2007/10/17 22:49:54 cheshire
406 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
408 Revision 1.501 2007/10/17 22:37:23 cheshire
409 <rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
411 Revision 1.500 2007/10/17 21:53:51 cheshire
412 Improved debugging messages; renamed startLLQHandshakeCallback to LLQGotZoneData
414 Revision 1.499 2007/10/16 21:16:50 cheshire
415 Get rid of unused uDNS_Sleep() routine
417 Revision 1.498 2007/10/16 20:59:41 cheshire
418 Export SuspendLLQs/SleepServiceRegistrations/SleepRecordRegistrations so they're callable from other files
420 Revision 1.497 2007/10/05 18:09:44 cheshire
421 <rdar://problem/5524841> Services advertised with wrong target host
423 Revision 1.496 2007/10/04 22:38:59 cheshire
424 Added LogOperation message showing new q->ThisQInterval after sending uDNS query packet
426 Revision 1.495 2007/10/03 00:16:19 cheshire
427 In PrivateQueryGotZoneData, need to grab lock before calling SetNextQueryTime
429 Revision 1.494 2007/10/02 21:11:08 cheshire
430 <rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing
432 Revision 1.493 2007/10/02 19:50:23 cheshire
433 Improved debugging message
435 Revision 1.492 2007/09/29 03:15:43 cheshire
436 <rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
437 Use AutoTunnelUnregistered macro instead of checking record state directly
439 Revision 1.491 2007/09/29 01:33:45 cheshire
440 <rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
442 Revision 1.490 2007/09/29 01:06:17 mcguire
443 <rdar://problem/5507862> 9A564: mDNSResponder crash in mDNS_Execute
445 Revision 1.489 2007/09/27 22:02:33 cheshire
446 <rdar://problem/5464941> BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord
448 Revision 1.488 2007/09/27 21:20:17 cheshire
449 Improved debugging syslog messages
451 Revision 1.487 2007/09/27 18:55:11 cheshire
452 <rdar://problem/5477165> BTMM: Multiple SRV records get registered after changing Computer Name
454 Revision 1.486 2007/09/27 17:42:49 cheshire
455 Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask"
457 Revision 1.485 2007/09/27 02:16:30 cheshire
458 <rdar://problem/5500111> BTMM: LLQ refreshes being sent in the clear to the wrong port
460 Revision 1.484 2007/09/27 00:25:39 cheshire
461 Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
462 <rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
464 Revision 1.483 2007/09/26 23:16:58 cheshire
465 <rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac
467 Revision 1.482 2007/09/26 22:06:02 cheshire
468 <rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
470 Revision 1.481 2007/09/26 00:49:46 cheshire
471 Improve packet logging to show sent and received packets,
472 transport protocol (UDP/TCP/TLS) and source/destination address:port
474 Revision 1.480 2007/09/21 21:08:52 cheshire
475 Get rid of unnecessary DumpPacket() calls -- it makes more sense
476 to do this in mDNSSendDNSMessage and mDNSCoreReceive instead
478 Revision 1.479 2007/09/21 20:01:17 cheshire
479 <rdar://problem/5496750> BTMM: Skip directly to member name in SOA queries to avoid sending names in the clear
481 Revision 1.478 2007/09/21 19:29:14 cheshire
482 Added dump of uDNS questions when in MDNS_LOG_VERBOSE_DEBUG mode
484 Revision 1.477 2007/09/20 02:29:37 cheshire
485 <rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
487 Revision 1.476 2007/09/20 01:19:49 cheshire
488 Improve debugging messages: report startLLQHandshake errors; show state in uDNS_StopLongLivedQuery message
490 Revision 1.475 2007/09/19 23:51:26 cheshire
491 <rdar://problem/5480517> BTMM: Need to log a message when NAT port mapping fails
493 Revision 1.474 2007/09/19 20:32:09 cheshire
494 Export GetAuthInfoForName so it's callable from other files
496 Revision 1.473 2007/09/18 21:42:29 cheshire
497 To reduce programming mistakes, renamed ExtPort to RequestedPort
499 Revision 1.472 2007/09/14 21:26:08 cheshire
500 <rdar://problem/5482627> BTMM: Need to manually avoid port conflicts when using UPnP gateways
502 Revision 1.471 2007/09/14 01:07:10 cheshire
503 If UPnP NAT gateway returns 0.0.0.0 as external address (e.g. because it hasn't
504 got a DHCP address yet) then retry periodically until it gives us a real address.
506 Revision 1.470 2007/09/13 00:36:26 cheshire
507 <rdar://problem/5477360> NAT Reboot detection logic incorrect
509 Revision 1.469 2007/09/13 00:28:50 cheshire
510 <rdar://problem/5477354> Host records not updated on NAT address change
512 Revision 1.468 2007/09/13 00:16:41 cheshire
513 <rdar://problem/5468706> Miscellaneous NAT Traversal improvements
515 Revision 1.467 2007/09/12 23:03:08 cheshire
516 <rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
518 Revision 1.466 2007/09/12 22:19:29 cheshire
519 <rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
521 Revision 1.465 2007/09/12 19:22:19 cheshire
522 Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
523 Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
525 Revision 1.464 2007/09/12 01:22:13 cheshire
526 Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
528 Revision 1.463 2007/09/11 20:23:28 vazquez
529 <rdar://problem/5466719> CrashTracer: 3 crashes in mDNSResponder at mDNSResponder: natTraversalHandlePortMapReply + 107
530 Make sure we clean up NATTraversals before free'ing HostnameInfo
532 Revision 1.462 2007/09/11 19:19:16 cheshire
533 Correct capitalization of "uPNP" to "UPnP"
535 Revision 1.461 2007/09/10 22:08:17 cheshire
536 Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
538 Revision 1.460 2007/09/07 21:47:43 vazquez
539 <rdar://problem/5460210> BTMM: SetupSocket 5351 failed; Can't allocate UDP multicast socket spew on wake from sleep with internet sharing on
540 Try to allocate using port 5350 if we get a failure, and only log message if that fails too.
542 Revision 1.459 2007/09/07 01:01:05 cheshire
543 <rdar://problem/5464844> BTMM: Services being registered and deregistered in a loop
544 In hndlServiceUpdateReply, need to clear SRVUpdateDeferred
546 Revision 1.458 2007/09/06 19:14:33 cheshire
547 Fixed minor error introduced in 1.379 (an "if" statement was deleted but the "else" following it was left there)
549 Revision 1.457 2007/09/05 21:48:01 cheshire
550 <rdar://problem/5385864> BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone.
551 Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance code needs
552 to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
553 otherwise those records will expire and vanish from the cache.
555 Revision 1.456 2007/09/05 21:00:17 cheshire
556 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
557 Additional refinement: ThisQInterval needs to be restored in tcpCallback, not in PrivateQueryGotZoneData
559 Revision 1.455 2007/09/05 20:53:06 cheshire
560 Tidied up alignment of code layout; code was clearing m->tcpAddrInfo.sock instead of m->tcpDeviceInfo.sock
562 Revision 1.454 2007/09/05 02:32:55 cheshire
563 Fixed posix build error (mixed declarations and code)
565 Revision 1.453 2007/09/05 02:26:57 cheshire
566 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
567 In PrivateQueryGotZoneData, restore q->ThisQInterval to non-zero value after GetZoneData completes
569 Revision 1.452 2007/08/31 22:58:22 cheshire
570 If we have an existing TCP connection we should re-use it instead of just bailing out
571 After receiving dnsbugtest response, need to set m->NextScheduledQuery to cause queries to be re-issued
573 Revision 1.451 2007/08/31 18:49:49 vazquez
574 <rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
576 Revision 1.450 2007/08/30 22:50:04 mcguire
577 <rdar://problem/5430628> BTMM: Tunneled services are registered when autotunnel can't be setup
579 Revision 1.449 2007/08/30 00:43:17 cheshire
580 Need to clear m->rec.r.resrec.RecordType before returning from uDNS_recvLLQResponse
582 Revision 1.448 2007/08/30 00:18:46 cheshire
583 <rdar://problem/5448804> Error messages: "SendServiceRegistration: Already have TCP connection..."
585 Revision 1.447 2007/08/29 01:18:33 cheshire
586 <rdar://problem/5400181> BTMM: Tunneled services do not need NAT port mappings
587 Only create NAT mappings for SRV records with AutoTarget set to Target_AutoHostAndNATMAP
589 Revision 1.446 2007/08/28 23:58:42 cheshire
590 Rename HostTarget -> AutoTarget
592 Revision 1.445 2007/08/28 23:53:21 cheshire
593 Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
595 Revision 1.444 2007/08/27 20:29:20 cheshire
596 Additional debugging messages
598 Revision 1.443 2007/08/24 23:18:28 cheshire
599 mDNS_SetSecretForDomain is called with lock held; needs to use
600 GetAuthInfoForName_internal() instead of external version GetAuthInfoForName()
602 Revision 1.442 2007/08/24 22:43:06 cheshire
603 Tidied up coded layout
605 Revision 1.441 2007/08/24 01:20:55 cheshire
606 <rdar://problem/5434381> BTMM: Memory corruption in KeychainChanged event handling
608 Revision 1.440 2007/08/24 00:15:20 cheshire
609 Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
611 Revision 1.439 2007/08/23 21:47:09 vazquez
612 <rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
613 make sure we clean up port mappings on base stations by sending a lease value of 0,
614 and only send NAT-PMP packets on private networks; also save some memory by
615 not using packet structs in NATTraversals.
617 Revision 1.438 2007/08/22 17:50:08 vazquez
618 <rdar://problem/5399276> Need to handle errors returned by NAT-PMP routers properly
619 Propagate router errors to clients, and stop logging spurious "message too short" logs.
621 Revision 1.437 2007/08/18 00:54:15 mcguire
622 <rdar://problem/5413147> BTMM: Should not register private addresses or zeros
624 Revision 1.436 2007/08/08 21:07:48 vazquez
625 <rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
627 Revision 1.435 2007/08/03 02:04:09 vazquez
628 <rdar://problem/5371843> BTMM: Private LLQs never fall back to polling
629 Fix case where NAT-PMP returns an external address but does not support
630 port mappings. Undo previous change and now, if the router returns an
631 error in the reply packet we respect it.
633 Revision 1.434 2007/08/02 21:03:05 vazquez
634 Change NAT logic to fix case where base station with port mapping turned off
635 returns an external address but does not make port mappings.
637 Revision 1.433 2007/08/02 03:30:11 vazquez
638 <rdar://problem/5371843> BTMM: Private LLQs never fall back to polling
640 Revision 1.432 2007/08/01 18:15:19 cheshire
641 Fixed crash in tcpCallback; fixed some problems with LLQ setup behind NAT
643 Revision 1.431 2007/08/01 16:11:06 cheshire
644 Fixed "mixed declarations and code" compiler error in Posix build
646 Revision 1.430 2007/08/01 16:09:13 cheshire
647 Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
649 Revision 1.429 2007/08/01 03:09:22 cheshire
650 <rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
652 Revision 1.428 2007/08/01 01:43:36 cheshire
653 Need to do mDNS_DropLockBeforeCallback/ReclaimLock around invokation of NAT client callback
655 Revision 1.427 2007/08/01 01:31:13 cheshire
656 Need to initialize traversal->tcpInfo fields or code may crash
658 Revision 1.426 2007/08/01 01:15:57 cheshire
659 <rdar://problem/5375791> Need to invoke NAT client callback when not on RFC1918 private network
661 Revision 1.425 2007/08/01 00:04:14 cheshire
662 <rdar://problem/5261696> Crash in tcpKQSocketCallback
663 Half-open TCP connections were not being cancelled properly
665 Revision 1.424 2007/07/31 02:28:35 vazquez
666 <rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
668 Revision 1.423 2007/07/30 23:31:26 cheshire
669 Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
671 Revision 1.422 2007/07/28 01:25:57 cheshire
672 <rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
674 Revision 1.421 2007/07/28 00:04:14 cheshire
675 Various fixes for comments and debugging messages
677 Revision 1.420 2007/07/27 23:59:18 cheshire
678 Added compile-time structure size checks
680 Revision 1.419 2007/07/27 20:52:29 cheshire
681 Made uDNS_recvLLQResponse() return tri-state result: LLQ_Not, LLQ_First, or LLQ_Events
683 Revision 1.418 2007/07/27 20:32:05 vazquez
684 Flag a UPnP NAT traversal before starting a UPnP port mapping, and make sure all
685 calls to mDNS_StopNATOperation() go through the UPnP code
687 Revision 1.417 2007/07/27 20:19:42 cheshire
688 Use MDNS_LOG_VERBOSE_DEBUG for dumping out packets instead of MDNS_LOG_DEBUG
690 Revision 1.416 2007/07/27 19:59:28 cheshire
691 MUST NOT touch m->CurrentQuestion (or q) after calling AnswerCurrentQuestionWithResourceRecord()
693 Revision 1.415 2007/07/27 19:51:01 cheshire
694 Use symbol QC_addnocache instead of literal constant "2"
696 Revision 1.414 2007/07/27 19:30:39 cheshire
697 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
698 to properly reflect tri-state nature of the possible responses
700 Revision 1.413 2007/07/27 18:44:01 cheshire
701 Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
703 Revision 1.412 2007/07/27 18:38:56 cheshire
704 Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
706 Revision 1.411 2007/07/27 00:57:13 cheshire
707 Create hostname address records using standard kHostNameTTL (2 minutes) instead of 1 second
709 Revision 1.410 2007/07/25 21:41:00 vazquez
710 Make sure we clean up opened sockets when there are network transitions and when changing
713 Revision 1.409 2007/07/25 03:05:02 vazquez
715 <rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
716 <rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
717 and a myriad of other security problems
719 Revision 1.408 2007/07/24 21:47:51 cheshire
720 Don't do mDNS_StopNATOperation() for operations we never started
722 Revision 1.407 2007/07/24 17:23:33 cheshire
723 <rdar://problem/5357133> Add list validation checks for debugging
725 Revision 1.406 2007/07/24 04:14:30 cheshire
726 <rdar://problem/5356281> LLQs not working in with NAT Traversal
728 Revision 1.405 2007/07/24 01:29:03 cheshire
729 <rdar://problem/5356026> DNSServiceNATPortMappingCreate() returns stale external address information
731 Revision 1.404 2007/07/20 23:10:51 cheshire
734 Revision 1.403 2007/07/20 20:12:37 cheshire
735 Rename "mDNS_DomainTypeBrowseLegacy" as "mDNS_DomainTypeBrowseAutomatic"
737 Revision 1.402 2007/07/20 00:54:20 cheshire
738 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
740 Revision 1.401 2007/07/18 03:23:33 cheshire
741 In GetServiceTarget, need to call SetupLocalAutoTunnelInterface_internal to bring up tunnel on demand, if necessary
743 Revision 1.400 2007/07/18 02:30:25 cheshire
744 Defer AutoTunnel server record advertising until we have at least one service to advertise
745 Do AutoTunnel target host selection in GetServiceTarget (instead of uDNS_RegisterService)
747 Revision 1.399 2007/07/18 01:02:28 cheshire
748 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
749 Declare records as kDNSRecordTypeKnownUnique so we don't get name conflicts with ourselves
751 Revision 1.398 2007/07/16 23:54:48 cheshire
752 <rdar://problem/5338850> Crash when removing or changing DNS keys
754 Revision 1.397 2007/07/16 20:13:31 vazquez
755 <rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
757 Revision 1.396 2007/07/14 00:33:04 cheshire
758 Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working
760 Revision 1.395 2007/07/12 23:56:23 cheshire
761 Change "GetZoneData GOT SRV" message to debugf to reduce verbosity in syslog
763 Revision 1.394 2007/07/12 23:36:08 cheshire
764 Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog
766 Revision 1.393 2007/07/12 22:15:10 cheshire
767 Modified mDNS_SetSecretForDomain() so it can be called to update an existing entry
769 Revision 1.392 2007/07/12 02:51:27 cheshire
770 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
772 Revision 1.391 2007/07/11 23:16:31 cheshire
773 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
774 Need to prepend _autotunnel._udp to start of AutoTunnel SRV record name
776 Revision 1.390 2007/07/11 22:47:55 cheshire
777 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
778 In mDNS_SetSecretForDomain(), don't register records until after we've validated the parameters
780 Revision 1.389 2007/07/11 21:33:10 cheshire
781 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
782 Set up and register AutoTunnelTarget and AutoTunnelService DNS records
784 Revision 1.388 2007/07/11 19:27:10 cheshire
785 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
786 For temporary testing fake up an IPv4LL address instead of IPv6 ULA
788 Revision 1.387 2007/07/11 03:04:08 cheshire
789 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
790 Add AutoTunnel parameter to mDNS_SetSecretForDomain; Set up AutoTunnel information for domains that require it
792 Revision 1.386 2007/07/10 01:57:28 cheshire
793 <rdar://problem/5196524> uDNS: mDNSresponder is leaking TCP connections to DNS server
794 Turned vast chunks of replicated code into a subroutine MakeTCPConn(...);
795 Made routines hold on to the reference it returns instead of leaking it
797 Revision 1.385 2007/07/09 23:50:18 cheshire
798 unlinkSRS needs to call mDNS_StopNATOperation_internal(), not mDNS_StopNATOperation()
800 Revision 1.384 2007/07/06 21:20:21 cheshire
801 Fix scheduling error (was causing "Task Scheduling Error: Continuously busy for more than a second")
803 Revision 1.383 2007/07/06 18:59:59 cheshire
804 Avoid spinning in an infinite loop when uDNS_SendNATMsg() returns an error
806 Revision 1.382 2007/07/04 00:49:43 vazquez
807 Clean up extraneous comments
809 Revision 1.381 2007/07/03 00:41:14 vazquez
810 More changes for <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
811 Safely deal with packet replies and client callbacks
813 Revision 1.380 2007/07/02 22:08:47 cheshire
814 Fixed crash in "Received public IP address" message
816 Revision 1.379 2007/06/29 00:08:49 vazquez
817 <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
819 Revision 1.378 2007/06/27 20:25:10 cheshire
820 Expanded dnsbugtest comment, explaining requirement that we also need these
821 test queries to black-hole before they get to the root name servers.
823 Revision 1.377 2007/06/22 21:27:21 cheshire
824 Modified "could not convert shared secret from base64" log message
826 Revision 1.376 2007/06/20 01:10:12 cheshire
827 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
829 Revision 1.375 2007/06/15 21:54:51 cheshire
830 <rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
832 Revision 1.374 2007/06/12 02:15:26 cheshire
833 Fix incorrect "DNS Server passed" LogOperation message
835 Revision 1.373 2007/05/31 00:25:43 cheshire
836 <rdar://problem/5238688> Only send dnsbugtest query for questions where it's warranted
838 Revision 1.372 2007/05/25 17:03:45 cheshire
839 lenptr needs to be declared unsigned, otherwise sign extension can mess up the shifting and ORing operations
841 Revision 1.371 2007/05/24 00:11:44 cheshire
842 Remove unnecessary lenbuf field from tcpInfo_t
844 Revision 1.370 2007/05/23 00:30:59 cheshire
845 Don't change question->TargetQID when repeating query over TCP
847 Revision 1.369 2007/05/21 18:04:40 cheshire
848 Updated comments -- port_mapping_create_reply renamed to port_mapping_reply
850 Revision 1.368 2007/05/17 19:12:16 cheshire
851 Updated comment about finding matching pair of sockets
853 Revision 1.367 2007/05/15 23:38:00 cheshire
854 Need to grab lock before calling SendRecordRegistration();
856 Revision 1.366 2007/05/15 00:43:05 cheshire
857 <rdar://problem/4983538> uDNS serviceRegistrationCallback locking failures
859 Revision 1.365 2007/05/10 21:19:18 cheshire
860 Rate-limit DNS test queries to at most one per three seconds
861 (useful when we have a dozen active WAB queries, and then we join a new network)
863 Revision 1.364 2007/05/07 20:43:45 cheshire
864 <rdar://problem/4241419> Reduce the number of queries and announcements
866 Revision 1.363 2007/05/04 22:12:48 cheshire
867 Work towards solving <rdar://problem/5176892> "uDNS_CheckQuery: LastQTime" log messages
868 When code gets in this invalid state, double ThisQInterval each time, to avoid excessive logging
870 Revision 1.362 2007/05/04 21:23:05 cheshire
871 <rdar://problem/5167263> Private DNS always returns no answers in the initial LLQ setup response
872 Preparatory work to enable us to do a four-way LLQ handshake over TCP, if we decide that's what we want
874 Revision 1.361 2007/05/03 23:50:48 cheshire
875 <rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
876 In the case of negative answers for the address record, set the server address to zerov4Addr
878 Revision 1.360 2007/05/03 22:40:38 cheshire
879 <rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
881 Revision 1.359 2007/05/02 22:21:33 cheshire
882 <rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
884 Revision 1.358 2007/05/01 21:46:31 cheshire
885 Move GetLLQOptData/GetPktLease from uDNS.c into DNSCommon.c so that dnsextd can use them
887 Revision 1.357 2007/05/01 01:33:49 cheshire
888 Removed "#define LLQ_Info DNSQuestion" and manually reconciled code that was still referring to "LLQ_Info"
890 Revision 1.356 2007/04/30 21:51:06 cheshire
893 Revision 1.355 2007/04/30 21:33:38 cheshire
894 Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
895 is iterating through the m->ServiceRegistrations list
897 Revision 1.354 2007/04/30 01:30:04 cheshire
898 GetZoneData_QuestionCallback needs to call client callback function on error, so client knows operation is finished
899 RecordRegistrationCallback and serviceRegistrationCallback need to clear nta reference when they're invoked
901 Revision 1.353 2007/04/28 01:28:25 cheshire
902 Fixed memory leak on error path in FoundDomain
904 Revision 1.352 2007/04/27 19:49:53 cheshire
905 In uDNS_ReceiveTestQuestionResponse, also check that srcport matches
907 Revision 1.351 2007/04/27 19:28:02 cheshire
908 Any code that calls StartGetZoneData needs to keep a handle to the structure, so
909 it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
910 -- it would start a query and then quickly cancel it, and then when
911 StartGetZoneData completed, it had a dangling pointer and crashed.)
913 Revision 1.350 2007/04/26 22:47:14 cheshire
914 Defensive coding: tcpCallback only needs to check "if (closed)", not "if (!n && closed)"
916 Revision 1.349 2007/04/26 16:04:06 cheshire
917 In mDNS_AddDNSServer, check whether port matches
918 In uDNS_CheckQuery, handle case where startLLQHandshake changes q->llq->state to LLQ_Poll
920 Revision 1.348 2007/04/26 04:01:59 cheshire
921 Copy-and-paste error: Test should be "if (result == DNSServer_Passed)" not "if (result == DNSServer_Failed)"
923 Revision 1.347 2007/04/26 00:35:15 cheshire
924 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
925 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
926 inside the firewall may give answers where a public one gives none, and vice versa.)
928 Revision 1.346 2007/04/25 19:16:59 cheshire
929 Don't set SuppressStdPort53Queries unless we do actually send a DNS packet
931 Revision 1.345 2007/04/25 18:05:11 cheshire
932 Don't try to restart inactive (duplicate) queries
934 Revision 1.344 2007/04/25 17:54:07 cheshire
935 Don't cancel Private LLQs using a clear-text UDP packet
937 Revision 1.343 2007/04/25 16:40:08 cheshire
938 Add comment explaining uDNS_recvLLQResponse logic
940 Revision 1.342 2007/04/25 02:14:38 cheshire
941 <rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
942 Additional fixes to make LLQs work properly
944 Revision 1.341 2007/04/24 02:07:42 cheshire
945 <rdar://problem/4246187> Identical client queries should reference a single shared core query
946 Deleted some more redundant code
948 Revision 1.340 2007/04/23 22:01:23 cheshire
949 <rdar://problem/5094009> IPv6 filtering in AirPort base station breaks Wide-Area Bonjour
950 As of March 2007, AirPort base stations now block incoming IPv6 connections by default, so there's no point
951 advertising IPv6 addresses in DNS any more -- we have to assume that most of the time a host's IPv6 address
952 probably won't work for incoming connections (but its IPv4 address probably will, using NAT-PMP).
954 Revision 1.339 2007/04/22 06:02:03 cheshire
955 <rdar://problem/4615977> Query should immediately return failure when no server
957 Revision 1.338 2007/04/21 19:44:11 cheshire
958 Improve uDNS_HandleNATPortMapReply log message
960 Revision 1.337 2007/04/21 02:03:00 cheshire
961 Also need to set AddressRec->resrec.RecordType in the NAT case too
963 Revision 1.336 2007/04/20 21:16:12 cheshire
964 Fixed bogus double-registration of host name -- was causing these warning messages in syslog:
965 Error! Tried to register AuthRecord 0181FB0C host.example.com. (Addr) that's already in the list
967 Revision 1.335 2007/04/19 23:57:20 cheshire
968 Temporary workaround for some AirPort base stations that don't seem to like us requesting public port zero
970 Revision 1.334 2007/04/19 23:21:51 cheshire
971 Fixed a couple of places where the StartGetZoneData check was backwards
973 Revision 1.333 2007/04/19 22:50:53 cheshire
974 <rdar://problem/4246187> Identical client queries should reference a single shared core query
976 Revision 1.332 2007/04/19 20:34:32 cheshire
977 Add debugging log message in uDNS_CheckQuery()
979 Revision 1.331 2007/04/19 20:06:41 cheshire
980 Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
982 Revision 1.330 2007/04/19 19:51:54 cheshire
983 Get rid of unnecessary initializeQuery() routine
985 Revision 1.329 2007/04/19 18:03:52 cheshire
986 Improved "mDNS_AddSearchDomain" log message
988 Revision 1.328 2007/04/18 20:57:20 cheshire
989 Commented out "GetAuthInfoForName none found" debugging message
991 Revision 1.327 2007/04/17 19:21:29 cheshire
992 <rdar://problem/5140339> Domain discovery not working over VPN
994 Revision 1.326 2007/04/16 20:49:39 cheshire
995 Fix compile errors for mDNSPosix build
997 Revision 1.325 2007/04/05 22:55:35 cheshire
998 <rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
1000 Revision 1.324 2007/04/05 20:43:30 cheshire
1001 Collapse sprawling code onto one line -- this is part of a bigger block of identical
1002 code that has been copied-and-pasted into six different places in the same file.
1003 This really needs to be turned into a subroutine.
1005 Revision 1.323 2007/04/04 21:48:52 cheshire
1006 <rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
1008 Revision 1.322 2007/04/03 19:53:06 cheshire
1009 Use mDNSSameIPPort (and similar) instead of accessing internal fields directly
1011 Revision 1.321 2007/04/02 23:44:09 cheshire
1014 Revision 1.320 2007/03/31 01:26:13 cheshire
1015 Take out GetAuthInfoForName syslog message
1017 Revision 1.319 2007/03/31 01:10:53 cheshire
1020 Revision 1.318 2007/03/31 00:17:11 cheshire
1023 Revision 1.317 2007/03/29 00:09:31 cheshire
1024 Improve "uDNS_InitLongLivedQuery" log message
1026 Revision 1.316 2007/03/28 21:16:27 cheshire
1027 Remove DumpPacket() call now that OPT pseudo-RR rrclass bug is fixed
1029 Revision 1.315 2007/03/28 21:02:18 cheshire
1030 <rdar://problem/3810563> Wide-Area Bonjour should work on multi-subnet private network
1032 Revision 1.314 2007/03/28 15:56:37 cheshire
1033 <rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
1035 Revision 1.313 2007/03/28 01:27:32 cheshire
1036 <rdar://problem/4996439> Unicast DNS polling server every three seconds
1037 StartLLQPolling was using INIT_UCAST_POLL_INTERVAL instead of LLQ_POLL_INTERVAL for the retry interval
1039 Revision 1.312 2007/03/27 23:48:21 cheshire
1040 Use mDNS_StopGetDomains(), not mDNS_StopQuery()
1042 Revision 1.311 2007/03/27 22:47:51 cheshire
1043 Remove unnecessary "*(long*)0 = 0;" to generate crash and stack trace
1045 Revision 1.310 2007/03/24 01:24:13 cheshire
1046 Add validator for uDNS data structures; fixed crash in RegisterSearchDomains()
1048 Revision 1.309 2007/03/24 00:47:53 cheshire
1049 <rdar://problem/4983538> serviceRegistrationCallback: Locking Failure! mDNS_busy (1) != mDNS_reentrancy (2)
1050 Locking in this file is all messed up. For now we'll just work around the issue.
1052 Revision 1.308 2007/03/24 00:41:33 cheshire
1053 Minor code cleanup (move variable declarations to minimum enclosing scope)
1055 Revision 1.307 2007/03/21 23:06:00 cheshire
1056 Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
1058 Revision 1.306 2007/03/21 00:30:03 cheshire
1059 <rdar://problem/4789455> Multiple errors in DNameList-related code
1061 Revision 1.305 2007/03/20 17:07:15 cheshire
1062 Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
1064 Revision 1.304 2007/03/17 00:02:11 cheshire
1065 <rdar://problem/5067013> NAT-PMP: Lease TTL is being ignored
1067 Revision 1.303 2007/03/10 03:26:44 cheshire
1068 <rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
1070 Revision 1.302 2007/03/10 02:29:58 cheshire
1071 Added comments about NAT-PMP response functions
1073 Revision 1.301 2007/03/10 02:02:58 cheshire
1074 <rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
1075 Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
1077 Revision 1.300 2007/03/08 18:56:00 cheshire
1078 Fixed typo: "&v4.ip.v4.b[0]" is always non-zero (ampersand should not be there)
1080 Revision 1.299 2007/02/28 01:45:47 cheshire
1081 <rdar://problem/4683261> NAT-PMP: Port mapping refreshes should contain actual public port
1082 <rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
1084 Revision 1.298 2007/02/14 03:16:39 cheshire
1085 <rdar://problem/4789477> Eliminate unnecessary malloc/free in mDNSCore code
1087 Revision 1.297 2007/02/08 21:12:28 cheshire
1088 <rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
1090 Revision 1.296 2007/01/29 16:03:22 cheshire
1091 Fix unused parameter warning
1093 Revision 1.295 2007/01/27 03:34:27 cheshire
1094 Made GetZoneData use standard queries (and cached results);
1095 eliminated GetZoneData_Callback() packet response handler
1097 Revision 1.294 2007/01/25 00:40:16 cheshire
1098 Unified CNAME-following functionality into cache management code (which means CNAME-following
1099 should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine.
1101 Revision 1.293 2007/01/23 02:56:11 cheshire
1102 Store negative results in the cache, instead of generating them out of pktResponseHndlr()
1104 Revision 1.292 2007/01/20 01:32:40 cheshire
1105 Update comments and debugging messages
1107 Revision 1.291 2007/01/20 00:07:02 cheshire
1108 When we have credentials in the keychain for a domain, we attempt private queries, but
1109 if the authoritative server is not set up for private queries (i.e. no _dns-query-tls
1110 or _dns-llq-tls record) then we need to fall back to conventional non-private queries.
1112 Revision 1.290 2007/01/19 23:41:45 cheshire
1113 Need to clear m->rec.r.resrec.RecordType after calling GetLLQOptData()
1115 Revision 1.289 2007/01/19 23:32:07 cheshire
1116 Eliminate pointless timenow variable
1118 Revision 1.288 2007/01/19 23:26:08 cheshire
1119 Right now tcpCallback does not run holding the lock, so no need to drop the lock before invoking callbacks
1121 Revision 1.287 2007/01/19 22:55:41 cheshire
1122 Eliminate redundant identical parameters to GetZoneData_StartQuery()
1124 Revision 1.286 2007/01/19 21:17:33 cheshire
1125 StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
1127 Revision 1.285 2007/01/19 18:39:11 cheshire
1128 Fix a bunch of parameters that should have been declared "const"
1130 Revision 1.284 2007/01/19 18:28:28 cheshire
1131 Improved debugging messages
1133 Revision 1.283 2007/01/19 18:09:33 cheshire
1134 Fixed getLLQAtIndex (now called GetLLQOptData):
1135 1. It incorrectly assumed all EDNS0 OPT records are the same size (it ignored optlen)
1136 2. It used inefficient memory copying instead of just returning a pointer
1138 Revision 1.282 2007/01/17 22:06:01 cheshire
1139 Replace duplicated literal constant "{ { 0 } }" with symbol "zeroIPPort"
1141 Revision 1.281 2007/01/17 21:58:13 cheshire
1142 For clarity, rename ntaContext field "isPrivate" to "ntaPrivate"
1144 Revision 1.280 2007/01/17 21:46:02 cheshire
1145 Remove redundant duplicated "isPrivate" field from LLQ_Info
1147 Revision 1.279 2007/01/17 21:35:31 cheshire
1148 For clarity, rename zoneData_t field "isPrivate" to "zonePrivate"
1150 Revision 1.278 2007/01/16 03:04:16 cheshire
1151 <rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
1152 Don't cache result of ntaContextSRV(context) in a local variable --
1153 the macro evaluates to a different result after we clear "context->isPrivate"
1155 Revision 1.277 2007/01/10 22:51:58 cheshire
1156 <rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
1158 Revision 1.276 2007/01/10 02:09:30 cheshire
1159 Better LogOperation record of keys read from System Keychain
1161 Revision 1.275 2007/01/09 22:37:18 cheshire
1162 Provide ten-second grace period for deleted keys, to give mDNSResponder
1163 time to delete host name before it gives up access to the required key.
1165 Revision 1.274 2007/01/09 01:16:32 cheshire
1166 Improve "ERROR m->CurrentQuestion already set" debugging messages
1168 Revision 1.273 2007/01/08 23:58:00 cheshire
1169 Don't request regDomain and browseDomains in uDNS_SetupDNSConfig() -- it just ignores those results
1171 Revision 1.272 2007/01/05 08:30:42 cheshire
1172 Trim excessive "Log" checkin history from before 2006
1173 (checkin history still available via "cvs log ..." of course)
1175 Revision 1.271 2007/01/05 06:34:03 cheshire
1176 Improve "ERROR m->CurrentQuestion already set" debugging messages
1178 Revision 1.270 2007/01/05 05:44:33 cheshire
1179 Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c,
1180 so that mDNSPosix embedded clients will compile again
1182 Revision 1.269 2007/01/04 23:11:13 cheshire
1183 <rdar://problem/4720673> uDNS: Need to start caching unicast records
1184 When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
1186 Revision 1.268 2007/01/04 22:06:38 cheshire
1187 Fixed crash in LLQNatMapComplete()
1189 Revision 1.267 2007/01/04 21:45:20 cheshire
1190 Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
1191 to do additional lock sanity checking around callback invocations
1193 Revision 1.266 2007/01/04 21:01:20 cheshire
1194 <rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
1195 Only return NXDOMAIN results to clients that request them using kDNSServiceFlagsReturnIntermediates
1197 Revision 1.265 2007/01/04 20:47:17 cheshire
1198 Fixed crash in CheckForUnreferencedLLQMapping()
1200 Revision 1.264 2007/01/04 20:39:27 cheshire
1201 Fix locking mismatch
1203 Revision 1.263 2007/01/04 02:39:53 cheshire
1204 <rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
1206 Revision 1.262 2007/01/04 00:29:25 cheshire
1207 Covert LogMsg() in GetAuthInfoForName to LogOperation()
1209 Revision 1.261 2006/12/22 20:59:49 cheshire
1210 <rdar://problem/4742742> Read *all* DNS keys from keychain,
1211 not just key for the system-wide default registration domain
1213 Revision 1.260 2006/12/21 00:06:07 cheshire
1214 Don't need to do mDNSPlatformMemZero() -- mDNS_SetupResourceRecord() does it for us
1216 Revision 1.259 2006/12/20 04:07:36 cheshire
1217 Remove uDNS_info substructure from AuthRecord_struct
1219 Revision 1.258 2006/12/19 22:49:24 cheshire
1220 Remove uDNS_info substructure from ServiceRecordSet_struct
1222 Revision 1.257 2006/12/19 02:38:20 cheshire
1223 Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
1225 Revision 1.256 2006/12/19 02:18:48 cheshire
1226 Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
1228 Revision 1.255 2006/12/16 01:58:31 cheshire
1229 <rdar://problem/4720673> uDNS: Need to start caching unicast records
1231 Revision 1.254 2006/12/15 19:23:39 cheshire
1232 Use new DomainNameLengthLimit() function, to be more defensive against malformed
1233 data received from the network.
1235 Revision 1.253 2006/12/01 07:43:34 herscher
1236 Fix byte ordering problem for one-shot TCP queries.
1237 Iterate more intelligently over duplicates in uDNS_ReceiveMsg to avoid spin loops.
1239 Revision 1.252 2006/11/30 23:07:57 herscher
1240 <rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
1242 Revision 1.251 2006/11/28 21:42:11 mkrochma
1243 Work around a crashing bug that was introduced by uDNS and mDNS code unification
1245 Revision 1.250 2006/11/18 05:01:30 cheshire
1246 Preliminary support for unifying the uDNS and mDNS code,
1247 including caching of uDNS answers
1249 Revision 1.249 2006/11/10 07:44:04 herscher
1250 <rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
1252 Revision 1.248 2006/11/08 04:26:53 cheshire
1253 Fix typo in debugging message
1255 Revision 1.247 2006/10/20 05:35:04 herscher
1256 <rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
1258 Revision 1.246 2006/10/11 19:29:41 herscher
1259 <rdar://problem/4744553> uDNS: mDNSResponder-111 using 100% CPU
1261 Revision 1.245 2006/10/04 22:21:15 herscher
1262 Tidy up references to mDNS_struct introduced when the embedded uDNS_info struct was removed.
1264 Revision 1.244 2006/10/04 21:51:27 herscher
1265 Replace calls to mDNSPlatformTimeNow(m) with m->timenow
1267 Revision 1.243 2006/10/04 21:38:59 herscher
1268 Remove uDNS_info substructure from DNSQuestion_struct
1270 Revision 1.242 2006/09/27 00:51:46 herscher
1271 Fix compile error when _LEGACY_NAT_TRAVERSAL_ is not defined
1273 Revision 1.241 2006/09/26 01:54:47 herscher
1274 <rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
1276 Revision 1.240 2006/09/15 21:20:15 cheshire
1277 Remove uDNS_info substructure from mDNS_struct
1279 Revision 1.239 2006/08/16 02:52:56 mkrochma
1280 <rdar://problem/4104154> Actually fix it this time
1282 Revision 1.238 2006/08/16 00:31:50 mkrochma
1283 <rdar://problem/4386944> Get rid of NotAnInteger references
1285 Revision 1.237 2006/08/15 23:38:17 mkrochma
1286 <rdar://problem/4104154> Requested Public Port field should be set to zero on mapping deletion
1288 Revision 1.236 2006/08/14 23:24:23 cheshire
1289 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
1291 Revision 1.235 2006/07/30 05:45:36 cheshire
1292 <rdar://problem/4304215> Eliminate MIN_UCAST_PERIODIC_EXEC
1294 Revision 1.234 2006/07/22 02:58:36 cheshire
1295 Code was clearing namehash twice instead of namehash and rdatahash
1297 Revision 1.233 2006/07/20 19:46:51 mkrochma
1298 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1301 Revision 1.232 2006/07/15 02:01:29 cheshire
1302 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1303 Fix broken "empty string" browsing
1305 Revision 1.231 2006/07/05 23:28:22 cheshire
1306 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1308 Revision 1.230 2006/06/29 03:02:44 cheshire
1309 <rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
1311 Revision 1.229 2006/03/02 22:03:41 cheshire
1312 <rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
1313 Refinement: m->rec.r.resrec.RecordType needs to be cleared *every* time around for loop, not just once at the end
1315 Revision 1.228 2006/02/26 00:54:42 cheshire
1316 Fixes to avoid code generation warning/error on FreeBSD 7
1318 Revision 1.227 2006/01/09 20:47:05 cheshire
1319 <rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
1325 #if(defined(_MSC_VER))
1326 // Disable "assignment within conditional expression".
1327 // Other compilers understand the convention that if you place the assignment expression within an extra pair
1328 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
1329 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
1330 // to the compiler that the assignment is intentional, we have to just turn this warning off completely.
1331 #pragma warning(disable:4706)
1334 // For domain enumeration and automatic browsing
1335 // This is the user's DNS search list.
1336 // In each of these domains we search for our special pointer records (lb._dns-sd._udp.<domain>, etc.)
1337 // to discover recommended domains for domain enumeration (browse, default browse, registration,
1338 // default registration) and possibly one or more recommended automatic browsing domains.
1339 mDNSexport SearchListElem
*SearchList
= mDNSNULL
;
1341 // Temporary workaround to make ServiceRecordSet list management safe.
1342 // Ideally a ServiceRecordSet shouldn't be a special entity that's given special treatment by the uDNS code
1343 // -- it should just be a grouping of records that are treated the same as any other registered records.
1344 // In that case it may no longer be necessary to keep an explicit list of ServiceRecordSets, which in turn
1345 // would avoid the perils of modifying that list cleanly while some other piece of code is iterating through it.
1346 ServiceRecordSet
*CurrentServiceRecordSet
= mDNSNULL
;
1348 // ***************************************************************************
1349 #if COMPILER_LIKES_PRAGMA_MARK
1350 #pragma mark - General Utility Functions
1353 // Unlink an AuthRecord from the m->ResourceRecords list.
1354 // This seems risky. Probably some (or maybe all) of the places calling UnlinkAuthRecord to directly
1355 // remove a record from the list should actually be using mDNS_Deregister/mDNS_Deregister_internal.
1356 mDNSlocal mStatus
UnlinkAuthRecord(mDNS
*const m
, AuthRecord
*const rr
)
1358 AuthRecord
**list
= &m
->ResourceRecords
;
1359 if (m
->NewLocalRecords
== rr
) m
->NewLocalRecords
= rr
->next
;
1360 if (m
->CurrentRecord
== rr
) m
->CurrentRecord
= rr
->next
;
1361 while (*list
&& *list
!= rr
) list
= &(*list
)->next
;
1364 list
= &m
->DuplicateRecords
;
1365 while (*list
&& *list
!= rr
) list
= &(*list
)->next
;
1367 if (*list
) { *list
= rr
->next
; rr
->next
= mDNSNULL
; return(mStatus_NoError
); }
1368 LogMsg("ERROR: UnlinkAuthRecord - no such active record %##s", rr
->resrec
.name
->c
);
1369 return(mStatus_NoSuchRecord
);
1372 // unlinkSRS is an internal routine (i.e. must be called with the lock already held)
1373 mDNSlocal
void unlinkSRS(mDNS
*const m
, ServiceRecordSet
*srs
)
1375 ServiceRecordSet
**p
;
1377 if (srs
->NATinfo
.clientContext
)
1379 mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
1380 srs
->NATinfo
.clientContext
= mDNSNULL
;
1383 for (p
= &m
->ServiceRegistrations
; *p
; p
= &(*p
)->uDNS_next
)
1386 ExtraResourceRecord
*e
;
1387 *p
= srs
->uDNS_next
;
1388 if (CurrentServiceRecordSet
== srs
)
1389 CurrentServiceRecordSet
= srs
->uDNS_next
;
1390 srs
->uDNS_next
= mDNSNULL
;
1391 for (e
=srs
->Extras
; e
; e
=e
->next
)
1392 if (UnlinkAuthRecord(m
, &e
->r
))
1393 LogMsg("unlinkSRS: extra record %##s not found", e
->r
.resrec
.name
->c
);
1396 LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list %##s", srs
->RR_SRV
.resrec
.name
->c
);
1399 // set retry timestamp for record with exponential backoff
1400 // (for service record sets, use RR_SRV as representative for time checks
1401 mDNSlocal
void SetRecordRetry(mDNS
*const m
, AuthRecord
*rr
, mStatus SendErr
)
1403 mDNSs32 elapsed
= m
->timenow
- rr
->LastAPTime
;
1404 rr
->LastAPTime
= m
->timenow
;
1407 // Code for stress-testing registration renewal code
1408 if (rr
->expire
&& rr
->expire
- m
->timenow
> mDNSPlatformOneSecond
* 120)
1410 LogInfo("Adjusting expiry from %d to 120 seconds for %s",
1411 (rr
->expire
- m
->timenow
) / mDNSPlatformOneSecond
, ARDisplayString(m
, rr
));
1412 rr
->expire
= m
->timenow
+ mDNSPlatformOneSecond
* 120;
1416 if (rr
->expire
&& rr
->expire
- m
->timenow
> mDNSPlatformOneSecond
)
1418 mDNSs32 remaining
= rr
->expire
- m
->timenow
;
1419 rr
->ThisAPInterval
= remaining
/2 + mDNSRandom(remaining
/10);
1420 debugf("SetRecordRetry refresh in %4d of %4d for %s",
1421 rr
->ThisAPInterval
/ mDNSPlatformOneSecond
, (rr
->expire
- m
->timenow
) / mDNSPlatformOneSecond
, ARDisplayString(m
, rr
));
1427 // If at least half our our time interval has elapsed, it's time to double rr->ThisAPInterval
1428 // If resulting interval is too small, set to at least INIT_UCAST_POLL_INTERVAL (3 seconds)
1429 // If resulting interval is too large, set to at most 30 minutes
1430 if (rr
->ThisAPInterval
/ 2 <= elapsed
) rr
->ThisAPInterval
*= 2;
1431 if (rr
->ThisAPInterval
< INIT_UCAST_POLL_INTERVAL
|| SendErr
== mStatus_TransientErr
)
1432 rr
->ThisAPInterval
= INIT_UCAST_POLL_INTERVAL
;
1433 rr
->ThisAPInterval
+= mDNSRandom(rr
->ThisAPInterval
/20);
1434 if (rr
->ThisAPInterval
> 30 * 60 * mDNSPlatformOneSecond
)
1435 rr
->ThisAPInterval
= 30 * 60 * mDNSPlatformOneSecond
;
1437 LogInfo("SetRecordRetry retry in %4d for %s", rr
->ThisAPInterval
/ mDNSPlatformOneSecond
, ARDisplayString(m
, rr
));
1440 // ***************************************************************************
1441 #if COMPILER_LIKES_PRAGMA_MARK
1442 #pragma mark - Name Server List Management
1445 mDNSexport DNSServer
*mDNS_AddDNSServer(mDNS
*const m
, const domainname
*d
, const mDNSInterfaceID interface
, const mDNSAddr
*addr
, const mDNSIPPort port
)
1447 DNSServer
**p
= &m
->DNSServers
;
1448 DNSServer
*tmp
= mDNSNULL
;
1450 if (!d
) d
= (const domainname
*)"";
1452 LogInfo("mDNS_AddDNSServer: Adding %#a for %##s", addr
, d
->c
);
1453 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
1454 LogMsg("mDNS_AddDNSServer: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
1456 while (*p
) // Check if we already have this {interface,address,port,domain} tuple registered
1458 if ((*p
)->interface
== interface
&& (*p
)->teststate
!= DNSServer_Disabled
&&
1459 mDNSSameAddress(&(*p
)->addr
, addr
) && mDNSSameIPPort((*p
)->port
, port
) && SameDomainName(&(*p
)->domain
, d
))
1461 if (!((*p
)->flags
& DNSServer_FlagDelete
)) debugf("Note: DNS Server %#a:%d for domain %##s (%p) registered more than once", addr
, mDNSVal16(port
), d
->c
, interface
);
1462 (*p
)->flags
&= ~DNSServer_FlagDelete
;
1465 tmp
->next
= mDNSNULL
;
1471 if (tmp
) *p
= tmp
; // move to end of list, to ensure ordering from platform layer
1474 // allocate, add to list
1475 *p
= mDNSPlatformMemAllocate(sizeof(**p
));
1476 if (!*p
) LogMsg("Error: mDNS_AddDNSServer - malloc");
1479 (*p
)->interface
= interface
;
1482 (*p
)->flags
= DNSServer_FlagNew
;
1483 (*p
)->teststate
= /* DNSServer_Untested */ DNSServer_Passed
;
1484 (*p
)->lasttest
= m
->timenow
- INIT_UCAST_POLL_INTERVAL
;
1485 AssignDomainName(&(*p
)->domain
, d
);
1486 (*p
)->next
= mDNSNULL
;
1492 mDNSexport
void PushDNSServerToEnd(mDNS
*const m
, DNSQuestion
*q
)
1494 DNSServer
*orig
= q
->qDNSServer
;
1495 DNSServer
**p
= &m
->DNSServers
;
1497 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
1498 LogMsg("PushDNSServerToEnd: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
1502 LogMsg("PushDNSServerToEnd: Null DNS server for %##s (%s) %d", q
->qname
.c
, DNSTypeName(q
->qtype
), q
->unansweredQueries
);
1506 LogInfo("PushDNSServerToEnd: Pushing DNS server %#a:%d (%##s) due to %d unanswered queries for %##s (%s)",
1507 &q
->qDNSServer
->addr
, mDNSVal16(q
->qDNSServer
->port
), q
->qDNSServer
->domain
.c
, q
->unansweredQueries
, q
->qname
.c
, DNSTypeName(q
->qtype
));
1511 if (*p
== q
->qDNSServer
) *p
= q
->qDNSServer
->next
;
1516 q
->qDNSServer
->next
= mDNSNULL
;
1519 q
->qDNSServer
= GetServerForName(m
, &q
->qname
);
1521 if (q
->qDNSServer
!= orig
)
1523 if (q
->qDNSServer
) LogInfo("PushDNSServerToEnd: Server for %##s (%s) changed to %#a:%d (%##s)", q
->qname
.c
, DNSTypeName(q
->qtype
), &q
->qDNSServer
->addr
, mDNSVal16(q
->qDNSServer
->port
), q
->qDNSServer
->domain
.c
);
1524 else LogInfo("PushDNSServerToEnd: Server for %##s (%s) changed to <null>", q
->qname
.c
, DNSTypeName(q
->qtype
));
1525 q
->ThisQInterval
= q
->ThisQInterval
/ QuestionIntervalStep
; // Decrease interval one step so we don't quickly bounce between servers for queries that will not be answered.
1529 // ***************************************************************************
1530 #if COMPILER_LIKES_PRAGMA_MARK
1531 #pragma mark - authorization management
1534 mDNSlocal DomainAuthInfo
*GetAuthInfoForName_direct(mDNS
*m
, const domainname
*const name
)
1536 const domainname
*n
= name
;
1539 DomainAuthInfo
*ptr
;
1540 for (ptr
= m
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
1541 if (SameDomainName(&ptr
->domain
, n
))
1543 debugf("GetAuthInfoForName %##s Matched %##s Key name %##s", name
->c
, ptr
->domain
.c
, ptr
->keyname
.c
);
1546 n
= (const domainname
*)(n
->c
+ 1 + n
->c
[0]);
1548 //LogInfo("GetAuthInfoForName none found for %##s", name->c);
1552 // MUST be called with lock held
1553 mDNSexport DomainAuthInfo
*GetAuthInfoForName_internal(mDNS
*m
, const domainname
*const name
)
1555 DomainAuthInfo
**p
= &m
->AuthInfoList
;
1557 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
1558 LogMsg("GetAuthInfoForName_internal: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
1560 // First purge any dead keys from the list
1563 if ((*p
)->deltime
&& m
->timenow
- (*p
)->deltime
>= 0 && AutoTunnelUnregistered(*p
))
1566 DomainAuthInfo
*info
= *p
;
1567 LogInfo("GetAuthInfoForName_internal deleting expired key %##s %##s", info
->domain
.c
, info
->keyname
.c
);
1568 *p
= info
->next
; // Cut DomainAuthInfo from list *before* scanning our question list updating AuthInfo pointers
1569 for (q
= m
->Questions
; q
; q
=q
->next
)
1570 if (q
->AuthInfo
== info
)
1572 q
->AuthInfo
= GetAuthInfoForName_direct(m
, &q
->qname
);
1573 debugf("GetAuthInfoForName_internal updated q->AuthInfo from %##s to %##s for %##s (%s)",
1574 info
->domain
.c
, q
->AuthInfo
? q
->AuthInfo
->domain
.c
: mDNSNULL
, q
->qname
.c
, DNSTypeName(q
->qtype
));
1577 // Probably not essential, but just to be safe, zero out the secret key data
1578 // so we don't leave it hanging around in memory
1579 // (where it could potentially get exposed via some other bug)
1580 mDNSPlatformMemZero(info
, sizeof(*info
));
1581 mDNSPlatformMemFree(info
);
1587 return(GetAuthInfoForName_direct(m
, name
));
1590 mDNSexport DomainAuthInfo
*GetAuthInfoForName(mDNS
*m
, const domainname
*const name
)
1594 d
= GetAuthInfoForName_internal(m
, name
);
1599 // MUST be called with the lock held
1600 mDNSexport mStatus
mDNS_SetSecretForDomain(mDNS
*m
, DomainAuthInfo
*info
,
1601 const domainname
*domain
, const domainname
*keyname
, const char *b64keydata
, mDNSBool AutoTunnel
)
1604 DomainAuthInfo
**p
= &m
->AuthInfoList
;
1605 if (!info
|| !b64keydata
) { LogMsg("mDNS_SetSecretForDomain: ERROR: info %p b64keydata %p", info
, b64keydata
); return(mStatus_BadParamErr
); }
1607 LogInfo("mDNS_SetSecretForDomain: domain %##s key %##s%s", domain
->c
, keyname
->c
, AutoTunnel
? " AutoTunnel" : "");
1609 info
->AutoTunnel
= AutoTunnel
;
1610 AssignDomainName(&info
->domain
, domain
);
1611 AssignDomainName(&info
->keyname
, keyname
);
1612 mDNS_snprintf(info
->b64keydata
, sizeof(info
->b64keydata
), "%s", b64keydata
);
1614 if (DNSDigest_ConstructHMACKeyfromBase64(info
, b64keydata
) < 0)
1616 LogMsg("mDNS_SetSecretForDomain: ERROR: Could not convert shared secret from base64: domain %##s key %##s %s", domain
->c
, keyname
->c
, mDNS_LoggingEnabled
? b64keydata
: "");
1617 return(mStatus_BadParamErr
);
1620 // Don't clear deltime until after we've ascertained that b64keydata is valid
1623 while (*p
&& (*p
) != info
) p
=&(*p
)->next
;
1624 if (*p
) return(mStatus_AlreadyRegistered
);
1626 // Caution: Only zero AutoTunnelHostRecord.namestorage and AutoTunnelNAT.clientContext AFTER we've determined that this is a NEW DomainAuthInfo
1627 // being added to the list. Otherwise we risk smashing our AutoTunnel host records and NATOperation that are already active and in use.
1628 info
->AutoTunnelHostRecord
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
1629 info
->AutoTunnelHostRecord
.namestorage
.c
[0] = 0;
1630 info
->AutoTunnelTarget
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
1631 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
1632 info
->AutoTunnelService
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
1633 info
->AutoTunnelNAT
.clientContext
= mDNSNULL
;
1634 info
->next
= mDNSNULL
;
1637 // Check to see if adding this new DomainAuthInfo has changed the credentials for any of our questions
1638 for (q
= m
->Questions
; q
; q
=q
->next
)
1640 DomainAuthInfo
*newinfo
= GetAuthInfoForQuestion(m
, q
);
1641 if (q
->AuthInfo
!= newinfo
)
1643 debugf("mDNS_SetSecretForDomain updating q->AuthInfo from %##s to %##s for %##s (%s)",
1644 q
->AuthInfo
? q
->AuthInfo
->domain
.c
: mDNSNULL
,
1645 newinfo
? newinfo
->domain
.c
: mDNSNULL
, q
->qname
.c
, DNSTypeName(q
->qtype
));
1646 q
->AuthInfo
= newinfo
;
1650 return(mStatus_NoError
);
1653 // ***************************************************************************
1654 #if COMPILER_LIKES_PRAGMA_MARK
1656 #pragma mark - NAT Traversal
1659 mDNSlocal mStatus
uDNS_SendNATMsg(mDNS
*m
, NATTraversalInfo
*info
)
1661 mStatus err
= mStatus_NoError
;
1663 // send msg if we have a router and it is a private address
1664 if (!mDNSIPv4AddressIsZero(m
->Router
.ip
.v4
) && mDNSv4AddrIsRFC1918(&m
->Router
.ip
.v4
))
1666 union { NATAddrRequest NATAddrReq
; NATPortMapRequest NATPortReq
; } u
= { { NATMAP_VERS
, NATOp_AddrRequest
} } ;
1667 const mDNSu8
*end
= (mDNSu8
*)&u
+ sizeof(NATAddrRequest
);
1669 if (info
) // For NATOp_MapUDP and NATOp_MapTCP, fill in additional fields
1671 mDNSu8
*p
= (mDNSu8
*)&u
.NATPortReq
.NATReq_lease
;
1672 u
.NATPortReq
.opcode
= info
->Protocol
;
1673 u
.NATPortReq
.unused
= zeroID
;
1674 u
.NATPortReq
.intport
= info
->IntPort
;
1675 u
.NATPortReq
.extport
= info
->RequestedPort
;
1676 p
[0] = (mDNSu8
)((info
->NATLease
>> 24) & 0xFF);
1677 p
[1] = (mDNSu8
)((info
->NATLease
>> 16) & 0xFF);
1678 p
[2] = (mDNSu8
)((info
->NATLease
>> 8) & 0xFF);
1679 p
[3] = (mDNSu8
)( info
->NATLease
& 0xFF);
1680 end
= (mDNSu8
*)&u
+ sizeof(NATPortMapRequest
);
1683 err
= mDNSPlatformSendUDP(m
, (mDNSu8
*)&u
, end
, 0, mDNSNULL
, &m
->Router
, NATPMPPort
);
1685 #ifdef _LEGACY_NAT_TRAVERSAL_
1686 if (mDNSIPPortIsZero(m
->UPnPRouterPort
) || mDNSIPPortIsZero(m
->UPnPSOAPPort
)) LNT_SendDiscoveryMsg(m
);
1687 else if (info
) err
= LNT_MapPort(m
, info
);
1688 else err
= LNT_GetExternalAddress(m
);
1689 #endif // _LEGACY_NAT_TRAVERSAL_
1694 mDNSexport
void RecreateNATMappings(mDNS
*const m
)
1696 NATTraversalInfo
*n
;
1697 for (n
= m
->NATTraversals
; n
; n
=n
->next
)
1699 n
->ExpiryTime
= 0; // Mark this mapping as expired
1700 n
->retryInterval
= NATMAP_INIT_RETRY
;
1701 n
->retryPortMap
= m
->timenow
;
1702 #ifdef _LEGACY_NAT_TRAVERSAL_
1703 if (n
->tcpInfo
.sock
) { mDNSPlatformTCPCloseConnection(n
->tcpInfo
.sock
); n
->tcpInfo
.sock
= mDNSNULL
; }
1704 #endif // _LEGACY_NAT_TRAVERSAL_
1707 m
->NextScheduledNATOp
= m
->timenow
; // Need to send packets immediately
1710 mDNSexport
void natTraversalHandleAddressReply(mDNS
*const m
, mDNSu16 err
, mDNSv4Addr ExtAddr
)
1712 static mDNSu16 last_err
= 0;
1716 if (err
!= last_err
) LogMsg("Error getting external address %d", err
);
1717 ExtAddr
= zerov4Addr
;
1721 LogInfo("Received external IP address %.4a from NAT", &ExtAddr
);
1722 if (mDNSv4AddrIsRFC1918(&ExtAddr
))
1723 LogMsg("Double NAT (external NAT gateway address %.4a is also a private RFC 1918 address)", &ExtAddr
);
1724 if (mDNSIPv4AddressIsZero(ExtAddr
))
1725 err
= NATErr_NetFail
; // fake error to handle routers that pathologically report success with the zero address
1728 if (!mDNSSameIPv4Address(m
->ExternalAddress
, ExtAddr
))
1730 m
->ExternalAddress
= ExtAddr
;
1731 RecreateNATMappings(m
); // Also sets NextScheduledNATOp for us
1734 if (!err
) // Success, back-off to maximum interval
1735 m
->retryIntervalGetAddr
= NATMAP_MAX_RETRY_INTERVAL
;
1736 else if (!last_err
) // Failure after success, retry quickly (then back-off exponentially)
1737 m
->retryIntervalGetAddr
= NATMAP_INIT_RETRY
;
1738 // else back-off normally in case of pathological failures
1740 m
->retryGetAddr
= m
->timenow
+ m
->retryIntervalGetAddr
;
1741 if (m
->NextScheduledNATOp
- m
->retryIntervalGetAddr
> 0)
1742 m
->NextScheduledNATOp
= m
->retryIntervalGetAddr
;
1747 // Both places that call NATSetNextRenewalTime() update m->NextScheduledNATOp correctly afterwards
1748 mDNSlocal
void NATSetNextRenewalTime(mDNS
*const m
, NATTraversalInfo
*n
)
1750 n
->retryInterval
= (n
->ExpiryTime
- m
->timenow
)/2;
1751 if (n
->retryInterval
< NATMAP_MIN_RETRY_INTERVAL
) // Min retry interval is 2 seconds
1752 n
->retryInterval
= NATMAP_MIN_RETRY_INTERVAL
;
1753 n
->retryPortMap
= m
->timenow
+ n
->retryInterval
;
1756 // Note: When called from handleLNTPortMappingResponse() only pkt->err, pkt->extport and pkt->NATRep_lease fields are filled in
1757 mDNSexport
void natTraversalHandlePortMapReply(mDNS
*const m
, NATTraversalInfo
*n
, const mDNSInterfaceID InterfaceID
, mDNSu16 err
, mDNSIPPort extport
, mDNSu32 lease
)
1759 const char *prot
= n
->Protocol
== NATOp_MapUDP
? "UDP" : n
->Protocol
== NATOp_MapTCP
? "TCP" : "?";
1762 if (err
|| lease
== 0 || mDNSIPPortIsZero(extport
))
1764 LogInfo("natTraversalHandlePortMapReply: %p Response %s Port %5d External Port %5d lease %d error %d",
1765 n
, prot
, mDNSVal16(n
->IntPort
), mDNSVal16(extport
), lease
, err
);
1766 n
->retryInterval
= NATMAP_MAX_RETRY_INTERVAL
;
1767 n
->retryPortMap
= m
->timenow
+ NATMAP_MAX_RETRY_INTERVAL
;
1768 // No need to set m->NextScheduledNATOp here, since we're only ever extending the m->retryPortMap time
1769 if (err
== NATErr_Refused
) n
->NewResult
= mStatus_NATPortMappingDisabled
;
1770 else if (err
> NATErr_None
&& err
<= NATErr_Opcode
) n
->NewResult
= mStatus_NATPortMappingUnsupported
;
1774 if (lease
> 999999999UL / mDNSPlatformOneSecond
)
1775 lease
= 999999999UL / mDNSPlatformOneSecond
;
1776 n
->ExpiryTime
= NonZeroTime(m
->timenow
+ lease
* mDNSPlatformOneSecond
);
1778 if (!mDNSSameIPPort(n
->RequestedPort
, extport
))
1779 LogInfo("natTraversalHandlePortMapReply: %p Response %s Port %5d External Port %5d changed to %5d",
1780 n
, prot
, mDNSVal16(n
->IntPort
), mDNSVal16(n
->RequestedPort
), mDNSVal16(extport
));
1782 n
->InterfaceID
= InterfaceID
;
1783 n
->RequestedPort
= extport
;
1785 LogInfo("natTraversalHandlePortMapReply: %p Response %s Port %5d External Port %5d lease %d",
1786 n
, prot
, mDNSVal16(n
->IntPort
), mDNSVal16(extport
), lease
);
1788 NATSetNextRenewalTime(m
, n
); // Got our port mapping; now set timer to renew it at halfway point
1789 m
->NextScheduledNATOp
= m
->timenow
; // May need to invoke client callback immediately
1793 // Must be called with the mDNS_Lock held
1794 mDNSexport mStatus
mDNS_StartNATOperation_internal(mDNS
*const m
, NATTraversalInfo
*traversal
)
1796 NATTraversalInfo
**n
;
1798 LogInfo("mDNS_StartNATOperation_internal Protocol %d IntPort %d RequestedPort %d NATLease %d",
1799 traversal
->Protocol
, mDNSVal16(traversal
->IntPort
), mDNSVal16(traversal
->RequestedPort
), traversal
->NATLease
);
1801 // Note: It important that new traversal requests are appended at the *end* of the list, not prepended at the start
1802 for (n
= &m
->NATTraversals
; *n
; n
=&(*n
)->next
)
1804 if (traversal
== *n
)
1806 LogMsg("Error! Tried to add a NAT traversal that's already in the active list: request %p Prot %d Int %d TTL %d",
1807 traversal
, traversal
->Protocol
, mDNSVal16(traversal
->IntPort
), traversal
->NATLease
);
1808 return(mStatus_AlreadyRegistered
);
1810 if (traversal
->Protocol
&& traversal
->Protocol
== (*n
)->Protocol
&& mDNSSameIPPort(traversal
->IntPort
, (*n
)->IntPort
) &&
1811 !mDNSSameIPPort(traversal
->IntPort
, SSHPort
))
1812 LogMsg("Warning: Created port mapping request %p Prot %d Int %d TTL %d "
1813 "duplicates existing port mapping request %p Prot %d Int %d TTL %d",
1814 traversal
, traversal
->Protocol
, mDNSVal16(traversal
->IntPort
), traversal
->NATLease
,
1815 *n
, (*n
) ->Protocol
, mDNSVal16((*n
) ->IntPort
), (*n
) ->NATLease
);
1818 // Initialize necessary fields
1819 traversal
->next
= mDNSNULL
;
1820 traversal
->ExpiryTime
= 0;
1821 traversal
->retryInterval
= NATMAP_INIT_RETRY
;
1822 traversal
->retryPortMap
= m
->timenow
;
1823 traversal
->NewResult
= mStatus_NoError
;
1824 traversal
->ExternalAddress
= onesIPv4Addr
;
1825 traversal
->ExternalPort
= zeroIPPort
;
1826 traversal
->Lifetime
= 0;
1827 traversal
->Result
= mStatus_NoError
;
1829 // set default lease if necessary
1830 if (!traversal
->NATLease
) traversal
->NATLease
= NATMAP_DEFAULT_LEASE
;
1832 #ifdef _LEGACY_NAT_TRAVERSAL_
1833 mDNSPlatformMemZero(&traversal
->tcpInfo
, sizeof(traversal
->tcpInfo
));
1834 #endif // _LEGACY_NAT_TRAVERSAL_
1836 if (!m
->NATTraversals
) // If this is our first NAT request, kick off an address request too
1838 m
->retryGetAddr
= m
->timenow
;
1839 m
->retryIntervalGetAddr
= NATMAP_INIT_RETRY
;
1842 m
->NextScheduledNATOp
= m
->timenow
; // This will always trigger sending the packet ASAP, and generate client callback if necessary
1844 *n
= traversal
; // Append new NATTraversalInfo to the end of our list
1846 return(mStatus_NoError
);
1849 // Must be called with the mDNS_Lock held
1850 mDNSexport mStatus
mDNS_StopNATOperation_internal(mDNS
*m
, NATTraversalInfo
*traversal
)
1852 mDNSBool unmap
= mDNStrue
;
1853 NATTraversalInfo
*p
;
1854 NATTraversalInfo
**ptr
= &m
->NATTraversals
;
1856 while (*ptr
&& *ptr
!= traversal
) ptr
=&(*ptr
)->next
;
1857 if (*ptr
) *ptr
= (*ptr
)->next
; // If we found it, cut this NATTraversalInfo struct from our list
1860 LogMsg("mDNS_StopNATOperation: NATTraversalInfo %p not found in list", traversal
);
1861 return(mStatus_BadReferenceErr
);
1864 LogInfo("mDNS_StopNATOperation_internal %d %d %d %d",
1865 traversal
->Protocol
, mDNSVal16(traversal
->IntPort
), mDNSVal16(traversal
->RequestedPort
), traversal
->NATLease
);
1867 if (m
->CurrentNATTraversal
== traversal
)
1868 m
->CurrentNATTraversal
= m
->CurrentNATTraversal
->next
;
1870 if (traversal
->Protocol
)
1871 for (p
= m
->NATTraversals
; p
; p
=p
->next
)
1872 if (traversal
->Protocol
== p
->Protocol
&& mDNSSameIPPort(traversal
->IntPort
, p
->IntPort
))
1874 if (!mDNSSameIPPort(traversal
->IntPort
, SSHPort
))
1875 LogMsg("Warning: Removed port mapping request %p Prot %d Int %d TTL %d "
1876 "duplicates existing port mapping request %p Prot %d Int %d TTL %d",
1877 traversal
, traversal
->Protocol
, mDNSVal16(traversal
->IntPort
), traversal
->NATLease
,
1878 p
, p
->Protocol
, mDNSVal16(p
->IntPort
), p
->NATLease
);
1882 if (traversal
->ExpiryTime
&& unmap
)
1884 traversal
->NATLease
= 0;
1885 traversal
->retryInterval
= 0;
1886 uDNS_SendNATMsg(m
, traversal
);
1889 // 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
1890 #ifdef _LEGACY_NAT_TRAVERSAL_
1892 mStatus err
= LNT_UnmapPort(m
, traversal
);
1893 if (err
) LogMsg("Legacy NAT Traversal - unmap request failed with error %d", err
);
1895 #endif // _LEGACY_NAT_TRAVERSAL_
1897 return(mStatus_NoError
);
1900 mDNSexport mStatus
mDNS_StartNATOperation(mDNS
*m
, NATTraversalInfo
*traversal
)
1904 status
= mDNS_StartNATOperation_internal(m
, traversal
);
1909 mDNSexport mStatus
mDNS_StopNATOperation(mDNS
*m
, NATTraversalInfo
*traversal
)
1913 status
= mDNS_StopNATOperation_internal(m
, traversal
);
1918 // ***************************************************************************
1919 #if COMPILER_LIKES_PRAGMA_MARK
1921 #pragma mark - Long-Lived Queries
1924 // Lock must be held -- otherwise m->timenow is undefined
1925 mDNSlocal
void StartLLQPolling(mDNS
*const m
, DNSQuestion
*q
)
1927 debugf("StartLLQPolling: %##s", q
->qname
.c
);
1928 q
->state
= LLQ_Poll
;
1929 q
->ThisQInterval
= INIT_UCAST_POLL_INTERVAL
;
1930 // We want to send our poll query ASAP, but the "+ 1" is because if we set the time to now,
1931 // we risk causing spurious "SendQueries didn't send all its queries" log messages
1932 q
->LastQTime
= m
->timenow
- q
->ThisQInterval
+ 1;
1933 SetNextQueryTime(m
, q
);
1934 #if APPLE_OSX_mDNSResponder
1935 UpdateAutoTunnelDomainStatuses(m
);
1939 mDNSlocal mDNSu8
*putLLQ(DNSMessage
*const msg
, mDNSu8
*ptr
, const DNSQuestion
*const question
, const LLQOptData
*const data
)
1942 ResourceRecord
*opt
= &rr
.resrec
;
1945 //!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section
1946 ptr
= putQuestion(msg
, ptr
, msg
->data
+ AbsoluteMaxDNSMessageData
, &question
->qname
, question
->qtype
, question
->qclass
);
1947 if (!ptr
) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL
; }
1949 // locate OptRR if it exists, set pointer to end
1950 // !!!KRS implement me
1952 // format opt rr (fields not specified are zero-valued)
1953 mDNS_SetupResourceRecord(&rr
, mDNSNULL
, mDNSInterface_Any
, kDNSType_OPT
, kStandardTTL
, kDNSRecordTypeKnownUnique
, mDNSNULL
, mDNSNULL
);
1954 opt
->rrclass
= NormalMaxDNSMessageData
;
1955 opt
->rdlength
= sizeof(rdataOPT
); // One option in this OPT record
1956 opt
->rdestimate
= sizeof(rdataOPT
);
1958 optRD
= &rr
.resrec
.rdata
->u
.opt
[0];
1959 optRD
->opt
= kDNSOpt_LLQ
;
1960 optRD
->u
.llq
= *data
;
1961 ptr
= PutResourceRecordTTLJumbo(msg
, ptr
, &msg
->h
.numAdditionals
, opt
, 0);
1962 if (!ptr
) { LogMsg("ERROR: putLLQ - PutResourceRecordTTLJumbo"); return mDNSNULL
; }
1967 // Normally we'd just request event packets be sent directly to m->LLQNAT.ExternalPort, except...
1968 // with LLQs over TLS/TCP we're doing a weird thing where instead of requesting packets be sent to ExternalAddress:ExternalPort
1969 // we're requesting that packets be sent to ExternalPort, but at the source address of our outgoing TCP connection.
1970 // Normally, after going through the NAT gateway, the source address of our outgoing TCP connection is the same as ExternalAddress,
1971 // so this is fine, except when the TCP connection ends up going over a VPN tunnel instead.
1972 // 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
1973 // LLQ server to send events to us directly at port 5353 on that address, instead of at our mapped external NAT port.
1975 mDNSlocal mDNSu16
GetLLQEventPort(const mDNS
*const m
, const mDNSAddr
*const dst
)
1978 mDNSPlatformSourceAddrForDest(&src
, dst
);
1979 //LogMsg("GetLLQEventPort: src %#a for dst %#a (%d)", &src, dst, mDNSv4AddrIsRFC1918(&src.ip.v4) ? mDNSVal16(m->LLQNAT.ExternalPort) : 0);
1980 return(mDNSv4AddrIsRFC1918(&src
.ip
.v4
) ? mDNSVal16(m
->LLQNAT
.ExternalPort
) : mDNSVal16(MulticastDNSPort
));
1983 // Normally called with llq set.
1984 // May be called with llq NULL, when retransmitting a lost Challenge Response
1985 mDNSlocal
void sendChallengeResponse(mDNS
*const m
, DNSQuestion
*const q
, const LLQOptData
*llq
)
1987 mDNSu8
*responsePtr
= m
->omsg
.data
;
1990 if (q
->ntries
++ == kLLQ_MAX_TRIES
)
1992 LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s", kLLQ_MAX_TRIES
, q
->qname
.c
);
1993 StartLLQPolling(m
,q
);
1997 if (!llq
) // Retransmission: need to make a new LLQOptData
1999 llqBuf
.vers
= kLLQ_Vers
;
2000 llqBuf
.llqOp
= kLLQOp_Setup
;
2001 llqBuf
.err
= LLQErr_NoError
; // Don't need to tell server UDP notification port when sending over UDP
2003 llqBuf
.llqlease
= q
->ReqLease
;
2007 q
->LastQTime
= m
->timenow
;
2008 q
->ThisQInterval
= q
->tcp
? 0 : (kLLQ_INIT_RESEND
* q
->ntries
* mDNSPlatformOneSecond
); // If using TCP, don't need to retransmit
2009 SetNextQueryTime(m
, q
);
2011 // To simulate loss of challenge response packet, uncomment line below
2012 //if (q->ntries == 1) return;
2014 InitializeDNSMessage(&m
->omsg
.h
, q
->TargetQID
, uQueryFlags
);
2015 responsePtr
= putLLQ(&m
->omsg
, responsePtr
, q
, llq
);
2018 mStatus err
= mDNSSendDNSMessage(m
, &m
->omsg
, responsePtr
, mDNSInterface_Any
, q
->LocalSocket
, &q
->servAddr
, q
->servPort
, q
->tcp
? q
->tcp
->sock
: mDNSNULL
, q
->AuthInfo
);
2021 LogMsg("sendChallengeResponse: mDNSSendDNSMessage%s failed: %d", q
->tcp
? " (TCP)" : "", err
);
2022 if (q
->tcp
) { DisposeTCPConn(q
->tcp
); q
->tcp
= mDNSNULL
; }
2025 else StartLLQPolling(m
,q
);
2028 mDNSlocal
void SetLLQTimer(mDNS
*const m
, DNSQuestion
*const q
, const LLQOptData
*const llq
)
2030 mDNSs32 lease
= (mDNSs32
)llq
->llqlease
* mDNSPlatformOneSecond
;
2031 q
->ReqLease
= llq
->llqlease
;
2032 q
->LastQTime
= m
->timenow
;
2033 q
->expire
= m
->timenow
+ lease
;
2034 q
->ThisQInterval
= lease
/2 + mDNSRandom(lease
/10);
2035 debugf("SetLLQTimer setting %##s (%s) to %d %d", q
->qname
.c
, DNSTypeName(q
->qtype
), lease
/mDNSPlatformOneSecond
, q
->ThisQInterval
/mDNSPlatformOneSecond
);
2036 SetNextQueryTime(m
, q
);
2039 mDNSlocal
void recvSetupResponse(mDNS
*const m
, mDNSu8 rcode
, DNSQuestion
*const q
, const LLQOptData
*const llq
)
2041 if (rcode
&& rcode
!= kDNSFlag1_RC_NXDomain
)
2042 { LogMsg("ERROR: recvSetupResponse %##s (%s) - rcode && rcode != kDNSFlag1_RC_NXDomain", q
->qname
.c
, DNSTypeName(q
->qtype
)); return; }
2044 if (llq
->llqOp
!= kLLQOp_Setup
)
2045 { LogMsg("ERROR: recvSetupResponse %##s (%s) - bad op %d", q
->qname
.c
, DNSTypeName(q
->qtype
), llq
->llqOp
); return; }
2047 if (llq
->vers
!= kLLQ_Vers
)
2048 { LogMsg("ERROR: recvSetupResponse %##s (%s) - bad vers %d", q
->qname
.c
, DNSTypeName(q
->qtype
), llq
->vers
); return; }
2050 if (q
->state
== LLQ_InitialRequest
)
2052 //LogInfo("Got LLQ_InitialRequest");
2054 if (llq
->err
) { LogMsg("recvSetupResponse - received llq->err %d from server", llq
->err
); StartLLQPolling(m
,q
); return; }
2056 if (q
->ReqLease
!= llq
->llqlease
)
2057 debugf("recvSetupResponse: requested lease %lu, granted lease %lu", q
->ReqLease
, llq
->llqlease
);
2059 // cache expiration in case we go to sleep before finishing setup
2060 q
->ReqLease
= llq
->llqlease
;
2061 q
->expire
= m
->timenow
+ ((mDNSs32
)llq
->llqlease
* mDNSPlatformOneSecond
);
2064 q
->state
= LLQ_SecondaryRequest
;
2066 q
->ntries
= 0; // first attempt to send response
2067 sendChallengeResponse(m
, q
, llq
);
2069 else if (q
->state
== LLQ_SecondaryRequest
)
2071 //LogInfo("Got LLQ_SecondaryRequest");
2073 // Fix this immediately if not sooner. Copy the id from the LLQOptData into our DNSQuestion struct. This is only
2074 // an issue for private LLQs, because we skip parts 2 and 3 of the handshake. This is related to a bigger
2075 // problem of the current implementation of TCP LLQ setup: we're not handling state transitions correctly
2076 // if the server sends back SERVFULL or STATIC.
2079 LogInfo("Private LLQ_SecondaryRequest; copying id %08X%08X", llq
->id
.l
[0], llq
->id
.l
[1]);
2083 if (llq
->err
) { LogMsg("ERROR: recvSetupResponse %##s (%s) code %d from server", q
->qname
.c
, DNSTypeName(q
->qtype
), llq
->err
); StartLLQPolling(m
,q
); return; }
2084 if (!mDNSSameOpaque64(&q
->id
, &llq
->id
))
2085 { LogMsg("recvSetupResponse - ID changed. discarding"); return; } // this can happen rarely (on packet loss + reordering)
2086 q
->state
= LLQ_Established
;
2088 SetLLQTimer(m
, q
, llq
);
2089 #if APPLE_OSX_mDNSResponder
2090 UpdateAutoTunnelDomainStatuses(m
);
2095 mDNSexport uDNS_LLQType
uDNS_recvLLQResponse(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
, const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
)
2097 DNSQuestion pktQ
, *q
;
2098 if (msg
->h
.numQuestions
&& getQuestion(msg
, msg
->data
, end
, 0, &pktQ
))
2100 const rdataOPT
*opt
= GetLLQOptData(m
, msg
, end
);
2102 for (q
= m
->Questions
; q
; q
= q
->next
)
2104 if (!mDNSOpaque16IsZero(q
->TargetQID
) && q
->LongLived
&& q
->qtype
== pktQ
.qtype
&& q
->qnamehash
== pktQ
.qnamehash
&& SameDomainName(&q
->qname
, &pktQ
.qname
))
2106 debugf("uDNS_recvLLQResponse found %##s (%s) %d %#a %#a %X %X %X %X %d",
2107 q
->qname
.c
, DNSTypeName(q
->qtype
), q
->state
, srcaddr
, &q
->servAddr
,
2108 opt
? opt
->u
.llq
.id
.l
[0] : 0, opt
? opt
->u
.llq
.id
.l
[1] : 0, q
->id
.l
[0], q
->id
.l
[1], opt
? opt
->u
.llq
.llqOp
: 0);
2109 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
));
2110 if (q
->state
== LLQ_Poll
&& mDNSSameOpaque16(msg
->h
.id
, q
->TargetQID
))
2112 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
2113 debugf("uDNS_recvLLQResponse got poll response; moving to LLQ_InitialRequest for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
2114 q
->state
= LLQ_InitialRequest
;
2115 q
->servPort
= zeroIPPort
; // Clear servPort so that startLLQHandshake will retry the GetZoneData processing
2116 q
->ThisQInterval
= LLQ_POLL_INTERVAL
+ mDNSRandom(LLQ_POLL_INTERVAL
/10); // Retry LLQ setup in approx 15 minutes
2117 q
->LastQTime
= m
->timenow
;
2118 SetNextQueryTime(m
, q
);
2119 return uDNS_LLQ_Entire
; // uDNS_LLQ_Entire means flush stale records; assume a large effective TTL
2121 // 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
2122 else if (opt
&& q
->state
== LLQ_Established
&& opt
->u
.llq
.llqOp
== kLLQOp_Event
&& mDNSSameOpaque64(&opt
->u
.llq
.id
, &q
->id
))
2125 //debugf("Sending LLQ ack for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
2126 InitializeDNSMessage(&m
->omsg
.h
, msg
->h
.id
, ResponseFlags
);
2127 ackEnd
= putLLQ(&m
->omsg
, m
->omsg
.data
, q
, &opt
->u
.llq
);
2128 if (ackEnd
) mDNSSendDNSMessage(m
, &m
->omsg
, ackEnd
, mDNSInterface_Any
, q
->LocalSocket
, srcaddr
, srcport
, mDNSNULL
, mDNSNULL
);
2129 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
2130 debugf("uDNS_LLQ_Events: q->state == LLQ_Established msg->h.id %d q->TargetQID %d", mDNSVal16(msg
->h
.id
), mDNSVal16(q
->TargetQID
));
2131 return uDNS_LLQ_Events
;
2133 if (opt
&& mDNSSameOpaque16(msg
->h
.id
, q
->TargetQID
))
2135 if (q
->state
== LLQ_Established
&& opt
->u
.llq
.llqOp
== kLLQOp_Refresh
&& mDNSSameOpaque64(&opt
->u
.llq
.id
, &q
->id
) && msg
->h
.numAdditionals
&& !msg
->h
.numAnswers
)
2137 if (opt
->u
.llq
.err
!= LLQErr_NoError
) LogMsg("recvRefreshReply: received error %d from server", opt
->u
.llq
.err
);
2140 //LogInfo("Received refresh confirmation ntries %d for %##s (%s)", q->ntries, q->qname.c, DNSTypeName(q->qtype));
2141 // If we're waiting to go to sleep, then this LLQ deletion may have been the thing
2142 // we were waiting for, so schedule another check to see if we can sleep now.
2143 if (opt
->u
.llq
.llqlease
== 0 && m
->SleepLimit
) m
->NextScheduledSPRetry
= m
->timenow
;
2144 GrantCacheExtensions(m
, q
, opt
->u
.llq
.llqlease
);
2145 SetLLQTimer(m
, q
, &opt
->u
.llq
);
2148 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
2149 return uDNS_LLQ_Ignore
;
2151 if (q
->state
< LLQ_Established
&& mDNSSameAddress(srcaddr
, &q
->servAddr
))
2153 LLQ_State oldstate
= q
->state
;
2154 recvSetupResponse(m
, msg
->h
.flags
.b
[1] & kDNSFlag1_RC_Mask
, q
, &opt
->u
.llq
);
2155 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
2156 // We have a protocol anomaly here in the LLQ definition.
2157 // Both the challenge packet from the server and the ack+answers packet have opt->u.llq.llqOp == kLLQOp_Setup.
2158 // However, we need to treat them differently:
2159 // The challenge packet has no answers in it, and tells us nothing about whether our cache entries
2160 // are still valid, so this packet should not cause us to do anything that messes with our cache.
2161 // The ack+answers packet gives us the whole truth, so we should handle it by updating our cache
2162 // to match the answers in the packet, and only the answers in the packet.
2163 return (oldstate
== LLQ_SecondaryRequest
? uDNS_LLQ_Entire
: uDNS_LLQ_Ignore
);
2168 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
2170 return uDNS_LLQ_Not
;
2173 // Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
2174 struct TCPSocket_struct
{ TCPSocketFlags flags
; /* ... */ };
2176 // tcpCallback is called to handle events (e.g. connection opening and data reception) on TCP connections for
2177 // Private DNS operations -- private queries, private LLQs, private record updates and private service updates
2178 mDNSlocal
void tcpCallback(TCPSocket
*sock
, void *context
, mDNSBool ConnectionEstablished
, mStatus err
)
2180 tcpInfo_t
*tcpInfo
= (tcpInfo_t
*)context
;
2181 mDNSBool closed
= mDNSfalse
;
2182 mDNS
*m
= tcpInfo
->m
;
2183 DNSQuestion
*const q
= tcpInfo
->question
;
2184 tcpInfo_t
**backpointer
=
2186 tcpInfo
->srs
? &tcpInfo
->srs
->tcp
:
2187 tcpInfo
->rr
? &tcpInfo
->rr
->tcp
: mDNSNULL
;
2188 if (backpointer
&& *backpointer
!= tcpInfo
)
2189 LogMsg("tcpCallback: %d backpointer %p incorrect tcpInfo %p question %p srs %p rr %p",
2190 mDNSPlatformTCPGetFD(tcpInfo
->sock
), *backpointer
, tcpInfo
, q
, tcpInfo
->srs
, tcpInfo
->rr
);
2194 if (ConnectionEstablished
)
2196 mDNSu8
*end
= ((mDNSu8
*) &tcpInfo
->request
) + tcpInfo
->requestLen
;
2197 DomainAuthInfo
*AuthInfo
;
2199 // Defensive coding for <rdar://problem/5546824> Crash in mDNSResponder at GetAuthInfoForName_internal + 366
2200 // 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
2201 if (tcpInfo
->srs
&& tcpInfo
->srs
->RR_SRV
.resrec
.name
!= &tcpInfo
->srs
->RR_SRV
.namestorage
)
2202 LogMsg("tcpCallback: ERROR: tcpInfo->srs->RR_SRV.resrec.name %p != &tcpInfo->srs->RR_SRV.namestorage %p",
2203 tcpInfo
->srs
->RR_SRV
.resrec
.name
, &tcpInfo
->srs
->RR_SRV
.namestorage
);
2204 if (tcpInfo
->rr
&& tcpInfo
->rr
->resrec
.name
!= &tcpInfo
->rr
->namestorage
)
2205 LogMsg("tcpCallback: ERROR: tcpInfo->rr->resrec.name %p != &tcpInfo->rr->namestorage %p",
2206 tcpInfo
->rr
->resrec
.name
, &tcpInfo
->rr
->namestorage
);
2207 if (tcpInfo
->srs
&& tcpInfo
->srs
->RR_SRV
.resrec
.name
!= &tcpInfo
->srs
->RR_SRV
.namestorage
) return;
2208 if (tcpInfo
->rr
&& tcpInfo
->rr
-> resrec
.name
!= &tcpInfo
->rr
-> namestorage
) return;
2210 AuthInfo
= tcpInfo
->srs
? GetAuthInfoForName(m
, tcpInfo
->srs
->RR_SRV
.resrec
.name
) :
2211 tcpInfo
->rr
? GetAuthInfoForName(m
, tcpInfo
->rr
->resrec
.name
) : mDNSNULL
;
2213 // connection is established - send the message
2214 if (q
&& q
->LongLived
&& q
->state
== LLQ_Established
)
2216 end
= ((mDNSu8
*) &tcpInfo
->request
) + tcpInfo
->requestLen
;
2218 else if (q
&& q
->LongLived
&& q
->state
!= LLQ_Poll
&& !mDNSIPPortIsZero(m
->LLQNAT
.ExternalPort
) && !mDNSIPPortIsZero(q
->servPort
))
2221 // If we have a NAT port mapping, ExternalPort is the external port
2222 // If we have a routable address so we don't need a port mapping, ExternalPort is the same as our own internal port
2223 // If we need a NAT port mapping but can't get one, then ExternalPort is zero
2224 LLQOptData llqData
; // set llq rdata
2225 llqData
.vers
= kLLQ_Vers
;
2226 llqData
.llqOp
= kLLQOp_Setup
;
2227 llqData
.err
= GetLLQEventPort(m
, &tcpInfo
->Addr
); // We're using TCP; tell server what UDP port to send notifications to
2228 LogInfo("tcpCallback: eventPort %d", llqData
.err
);
2229 llqData
.id
= zeroOpaque64
;
2230 llqData
.llqlease
= kLLQ_DefLease
;
2231 InitializeDNSMessage(&tcpInfo
->request
.h
, q
->TargetQID
, uQueryFlags
);
2232 end
= putLLQ(&tcpInfo
->request
, tcpInfo
->request
.data
, q
, &llqData
);
2233 if (!end
) { LogMsg("ERROR: tcpCallback - putLLQ"); err
= mStatus_UnknownErr
; goto exit
; }
2234 AuthInfo
= q
->AuthInfo
; // Need to add TSIG to this message
2238 InitializeDNSMessage(&tcpInfo
->request
.h
, q
->TargetQID
, uQueryFlags
);
2239 end
= putQuestion(&tcpInfo
->request
, tcpInfo
->request
.data
, tcpInfo
->request
.data
+ AbsoluteMaxDNSMessageData
, &q
->qname
, q
->qtype
, q
->qclass
);
2240 AuthInfo
= q
->AuthInfo
; // Need to add TSIG to this message
2243 err
= mDNSSendDNSMessage(m
, &tcpInfo
->request
, end
, mDNSInterface_Any
, mDNSNULL
, &tcpInfo
->Addr
, tcpInfo
->Port
, sock
, AuthInfo
);
2244 if (err
) { debugf("ERROR: tcpCallback: mDNSSendDNSMessage - %d", err
); err
= mStatus_UnknownErr
; goto exit
; }
2246 // Record time we sent this question
2250 q
->LastQTime
= m
->timenow
;
2251 if (q
->ThisQInterval
< (256 * mDNSPlatformOneSecond
)) // Now we have a TCP connection open, make sure we wait at least 256 seconds before retrying
2252 q
->ThisQInterval
= (256 * mDNSPlatformOneSecond
);
2253 SetNextQueryTime(m
, q
);
2260 if (tcpInfo
->nread
< 2) // First read the two-byte length preceeding the DNS message
2262 mDNSu8
*lenptr
= (mDNSu8
*)&tcpInfo
->replylen
;
2263 n
= mDNSPlatformReadTCP(sock
, lenptr
+ tcpInfo
->nread
, 2 - tcpInfo
->nread
, &closed
);
2264 if (n
< 0) { LogMsg("ERROR: tcpCallback - attempt to read message length failed (%d)", n
); err
= mStatus_ConnFailed
; goto exit
; }
2267 // It's perfectly fine for this socket to close after the first reply. The server might
2268 // be sending gratuitous replies using UDP and doesn't have a need to leave the TCP socket open.
2269 // We'll only log this event if we've never received a reply before.
2270 // BIND 9 appears to close an idle connection after 30 seconds.
2271 if (tcpInfo
->numReplies
== 0) LogMsg("ERROR: socket closed prematurely tcpInfo->nread = %d", tcpInfo
->nread
);
2272 err
= mStatus_ConnFailed
;
2276 tcpInfo
->nread
+= n
;
2277 if (tcpInfo
->nread
< 2) goto exit
;
2279 tcpInfo
->replylen
= (mDNSu16
)((mDNSu16
)lenptr
[0] << 8 | lenptr
[1]);
2280 if (tcpInfo
->replylen
< sizeof(DNSMessageHeader
))
2281 { LogMsg("ERROR: tcpCallback - length too short (%d bytes)", tcpInfo
->replylen
); err
= mStatus_UnknownErr
; goto exit
; }
2283 tcpInfo
->reply
= mDNSPlatformMemAllocate(tcpInfo
->replylen
);
2284 if (!tcpInfo
->reply
) { LogMsg("ERROR: tcpCallback - malloc failed"); err
= mStatus_NoMemoryErr
; goto exit
; }
2287 n
= mDNSPlatformReadTCP(sock
, ((char *)tcpInfo
->reply
) + (tcpInfo
->nread
- 2), tcpInfo
->replylen
- (tcpInfo
->nread
- 2), &closed
);
2289 if (n
< 0) { LogMsg("ERROR: tcpCallback - read returned %d", n
); err
= mStatus_ConnFailed
; goto exit
; }
2290 else if (closed
) { LogMsg("ERROR: socket closed prematurely %d", tcpInfo
->nread
); err
= mStatus_ConnFailed
; goto exit
; }
2292 tcpInfo
->nread
+= n
;
2294 if ((tcpInfo
->nread
- 2) == tcpInfo
->replylen
)
2296 AuthRecord
*rr
= tcpInfo
->rr
;
2297 DNSMessage
*reply
= tcpInfo
->reply
;
2298 mDNSu8
*end
= (mDNSu8
*)tcpInfo
->reply
+ tcpInfo
->replylen
;
2299 mDNSAddr Addr
= tcpInfo
->Addr
;
2300 mDNSIPPort Port
= tcpInfo
->Port
;
2301 tcpInfo
->numReplies
++;
2302 tcpInfo
->reply
= mDNSNULL
; // Detach reply buffer from tcpInfo_t, to make sure client callback can't cause it to be disposed
2304 tcpInfo
->replylen
= 0;
2306 // If we're going to dispose this connection, do it FIRST, before calling client callback
2307 // Note: Sleep code depends on us clearing *backpointer here -- it uses the clearing of rr->tcp and srs->tcp
2308 // as the signal that the DNS deregistration operation with the server has completed, and the machine may now sleep
2310 if (!q
|| !q
->LongLived
|| m
->SleepState
)
2311 { *backpointer
= mDNSNULL
; DisposeTCPConn(tcpInfo
); }
2313 if (rr
&& rr
->resrec
.RecordType
== kDNSRecordTypeDeregistering
)
2316 LogInfo("tcpCallback: CompleteDeregistration %s", ARDisplayString(m
, rr
));
2317 CompleteDeregistration(m
, rr
); // Don't touch rr after this
2321 mDNSCoreReceive(m
, reply
, end
, &Addr
, Port
, (sock
->flags
& kTCPSocketFlags_UseTLS
) ? (mDNSAddr
*)1 : mDNSNULL
, zeroIPPort
, 0);
2322 // USE CAUTION HERE: Invoking mDNSCoreReceive may have caused the environment to change, including canceling this operation itself
2324 mDNSPlatformMemFree(reply
);
2333 // Clear client backpointer FIRST -- that way if one of the callbacks cancels its operation
2334 // we won't end up double-disposing our tcpInfo_t
2335 if (backpointer
) *backpointer
= mDNSNULL
;
2337 mDNS_Lock(m
); // Need to grab the lock to get m->timenow
2341 if (q
->ThisQInterval
== 0 || q
->LastQTime
+ q
->ThisQInterval
- m
->timenow
> MAX_UCAST_POLL_INTERVAL
)
2343 q
->LastQTime
= m
->timenow
;
2344 q
->ThisQInterval
= MAX_UCAST_POLL_INTERVAL
;
2345 SetNextQueryTime(m
, q
);
2347 // ConnFailed may be actually okay. It just means that the server closed the connection but the LLQ may still be okay.
2348 // If the error isn't ConnFailed, then the LLQ is in bad shape.
2349 if (err
!= mStatus_ConnFailed
)
2351 if (q
->LongLived
&& q
->state
!= LLQ_Poll
) StartLLQPolling(m
, q
);
2355 if (tcpInfo
->rr
) SetRecordRetry(m
, tcpInfo
->rr
, mStatus_NoError
);
2357 if (tcpInfo
->srs
) SetRecordRetry(m
, &tcpInfo
->srs
->RR_SRV
, mStatus_NoError
);
2361 DisposeTCPConn(tcpInfo
);
2365 mDNSlocal tcpInfo_t
*MakeTCPConn(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
,
2366 TCPSocketFlags flags
, const mDNSAddr
*const Addr
, const mDNSIPPort Port
,
2367 DNSQuestion
*const question
, ServiceRecordSet
*const srs
, AuthRecord
*const rr
)
2370 mDNSIPPort srcport
= zeroIPPort
;
2371 tcpInfo_t
*info
= (tcpInfo_t
*)mDNSPlatformMemAllocate(sizeof(tcpInfo_t
));
2372 if (!info
) { LogMsg("ERROR: MakeTCP - memallocate failed"); return(mDNSNULL
); }
2373 mDNSPlatformMemZero(info
, sizeof(tcpInfo_t
));
2376 info
->sock
= mDNSPlatformTCPSocket(m
, flags
, &srcport
);
2377 info
->requestLen
= 0;
2378 info
->question
= question
;
2383 info
->reply
= mDNSNULL
;
2386 info
->numReplies
= 0;
2390 info
->requestLen
= (int) (end
- ((mDNSu8
*)msg
));
2391 mDNSPlatformMemCopy(&info
->request
, msg
, info
->requestLen
);
2394 if (!info
->sock
) { LogMsg("SendServiceRegistration: unable to create TCP socket"); mDNSPlatformMemFree(info
); return(mDNSNULL
); }
2395 err
= mDNSPlatformTCPConnect(info
->sock
, Addr
, Port
, 0, tcpCallback
, info
);
2397 // Probably suboptimal here.
2398 // Instead of returning mDNSNULL here on failure, we should probably invoke the callback with an error code.
2399 // That way clients can put all the error handling and retry/recovery code in one place,
2400 // instead of having to handle immediate errors in one place and async errors in another.
2401 // Also: "err == mStatus_ConnEstablished" probably never happens.
2403 // Don't need to log "connection failed" in customer builds -- it happens quite often during sleep, wake, configuration changes, etc.
2404 if (err
== mStatus_ConnEstablished
) { tcpCallback(info
->sock
, info
, mDNStrue
, mStatus_NoError
); }
2405 else if (err
!= mStatus_ConnPending
) { LogInfo("MakeTCPConnection: connection failed"); DisposeTCPConn(info
); return(mDNSNULL
); }
2409 mDNSexport
void DisposeTCPConn(struct tcpInfo_t
*tcp
)
2411 mDNSPlatformTCPCloseConnection(tcp
->sock
);
2412 if (tcp
->reply
) mDNSPlatformMemFree(tcp
->reply
);
2413 mDNSPlatformMemFree(tcp
);
2416 // Lock must be held
2417 mDNSexport
void startLLQHandshake(mDNS
*m
, DNSQuestion
*q
)
2419 if (mDNSIPv4AddressIsOnes(m
->LLQNAT
.ExternalAddress
))
2421 LogInfo("startLLQHandshake: waiting for NAT status for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
2422 q
->ThisQInterval
= LLQ_POLL_INTERVAL
+ mDNSRandom(LLQ_POLL_INTERVAL
/10); // Retry in approx 15 minutes
2423 q
->LastQTime
= m
->timenow
;
2424 SetNextQueryTime(m
, q
);
2428 if (mDNSIPPortIsZero(m
->LLQNAT
.ExternalPort
))
2430 LogInfo("startLLQHandshake: Cannot receive inbound packets; will poll for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
2431 StartLLQPolling(m
, q
);
2435 if (mDNSIPPortIsZero(q
->servPort
))
2437 debugf("startLLQHandshake: StartGetZoneData for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
2438 q
->ThisQInterval
= LLQ_POLL_INTERVAL
+ mDNSRandom(LLQ_POLL_INTERVAL
/10); // Retry in approx 15 minutes
2439 q
->LastQTime
= m
->timenow
;
2440 SetNextQueryTime(m
, q
);
2441 q
->servAddr
= zeroAddr
;
2442 // We know q->servPort is zero because of check above
2443 if (q
->nta
) CancelGetZoneData(m
, q
->nta
);
2444 q
->nta
= StartGetZoneData(m
, &q
->qname
, ZoneServiceLLQ
, LLQGotZoneData
, q
);
2450 if (q
->tcp
) LogInfo("startLLQHandshake: Disposing existing TCP connection for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
2451 if (q
->tcp
) DisposeTCPConn(q
->tcp
);
2452 q
->tcp
= MakeTCPConn(m
, mDNSNULL
, mDNSNULL
, kTCPSocketFlags_UseTLS
, &q
->servAddr
, q
->servPort
, q
, mDNSNULL
, mDNSNULL
);
2454 q
->ThisQInterval
= mDNSPlatformOneSecond
* 5; // If TCP failed (transient networking glitch) try again in five seconds
2457 q
->state
= LLQ_SecondaryRequest
; // Right now, for private DNS, we skip the four-way LLQ handshake
2458 q
->ReqLease
= kLLQ_DefLease
;
2459 q
->ThisQInterval
= 0;
2461 q
->LastQTime
= m
->timenow
;
2462 SetNextQueryTime(m
, q
);
2466 debugf("startLLQHandshake: m->AdvertisedV4 %#a%s Server %#a:%d%s %##s (%s)",
2467 &m
->AdvertisedV4
, mDNSv4AddrIsRFC1918(&m
->AdvertisedV4
.ip
.v4
) ? " (RFC 1918)" : "",
2468 &q
->servAddr
, mDNSVal16(q
->servPort
), mDNSAddrIsRFC1918(&q
->servAddr
) ? " (RFC 1918)" : "",
2469 q
->qname
.c
, DNSTypeName(q
->qtype
));
2471 if (q
->ntries
++ >= kLLQ_MAX_TRIES
)
2473 LogMsg("startLLQHandshake: %d failed attempts for LLQ %##s Polling.", kLLQ_MAX_TRIES
, q
->qname
.c
);
2474 StartLLQPolling(m
, q
);
2482 llqData
.vers
= kLLQ_Vers
;
2483 llqData
.llqOp
= kLLQOp_Setup
;
2484 llqData
.err
= LLQErr_NoError
; // Don't need to tell server UDP notification port when sending over UDP
2485 llqData
.id
= zeroOpaque64
;
2486 llqData
.llqlease
= kLLQ_DefLease
;
2488 InitializeDNSMessage(&m
->omsg
.h
, q
->TargetQID
, uQueryFlags
);
2489 end
= putLLQ(&m
->omsg
, m
->omsg
.data
, q
, &llqData
);
2490 if (!end
) { LogMsg("ERROR: startLLQHandshake - putLLQ"); StartLLQPolling(m
,q
); return; }
2492 mDNSSendDNSMessage(m
, &m
->omsg
, end
, mDNSInterface_Any
, q
->LocalSocket
, &q
->servAddr
, q
->servPort
, mDNSNULL
, mDNSNULL
);
2494 // update question state
2495 q
->state
= LLQ_InitialRequest
;
2496 q
->ReqLease
= kLLQ_DefLease
;
2497 q
->ThisQInterval
= (kLLQ_INIT_RESEND
* mDNSPlatformOneSecond
);
2498 q
->LastQTime
= m
->timenow
;
2499 SetNextQueryTime(m
, q
);
2504 // forward declaration so GetServiceTarget can do reverse lookup if needed
2505 mDNSlocal
void GetStaticHostname(mDNS
*m
);
2507 mDNSexport
const domainname
*GetServiceTarget(mDNS
*m
, AuthRecord
*const rr
)
2509 debugf("GetServiceTarget %##s", rr
->resrec
.name
->c
);
2511 if (!rr
->AutoTarget
) // If not automatically tracking this host's current name, just return the existing target
2512 return(&rr
->resrec
.rdata
->u
.srv
.target
);
2515 #if APPLE_OSX_mDNSResponder
2516 DomainAuthInfo
*AuthInfo
= GetAuthInfoForName_internal(m
, rr
->resrec
.name
);
2517 if (AuthInfo
&& AuthInfo
->AutoTunnel
)
2519 // If this AutoTunnel is not yet active, start it now (which entails activating its NAT Traversal request,
2520 // which will subsequently advertise the appropriate records when the NAT Traversal returns a result)
2521 if (!AuthInfo
->AutoTunnelNAT
.clientContext
&& m
->AutoTunnelHostAddr
.b
[0])
2522 SetupLocalAutoTunnelInterface_internal(m
);
2523 if (AuthInfo
->AutoTunnelHostRecord
.namestorage
.c
[0] == 0) return(mDNSNULL
);
2524 return(&AuthInfo
->AutoTunnelHostRecord
.namestorage
);
2527 #endif // APPLE_OSX_mDNSResponder
2529 const int srvcount
= CountLabels(rr
->resrec
.name
);
2530 HostnameInfo
*besthi
= mDNSNULL
, *hi
;
2532 for (hi
= m
->Hostnames
; hi
; hi
= hi
->next
)
2533 if (hi
->arv4
.state
== regState_Registered
|| hi
->arv4
.state
== regState_Refresh
||
2534 hi
->arv6
.state
== regState_Registered
|| hi
->arv6
.state
== regState_Refresh
)
2536 int x
, hostcount
= CountLabels(&hi
->fqdn
);
2537 for (x
= hostcount
< srvcount
? hostcount
: srvcount
; x
> 0 && x
> best
; x
--)
2538 if (SameDomainName(SkipLeadingLabels(rr
->resrec
.name
, srvcount
- x
), SkipLeadingLabels(&hi
->fqdn
, hostcount
- x
)))
2539 { best
= x
; besthi
= hi
; }
2542 if (besthi
) return(&besthi
->fqdn
);
2544 if (m
->StaticHostname
.c
[0]) return(&m
->StaticHostname
);
2545 else GetStaticHostname(m
); // asynchronously do reverse lookup for primary IPv4 address
2550 // Called with lock held
2551 mDNSlocal
void SendServiceRegistration(mDNS
*m
, ServiceRecordSet
*srs
)
2553 mDNSu8
*ptr
= m
->omsg
.data
;
2554 mDNSu8
*end
= (mDNSu8
*)&m
->omsg
+ sizeof(DNSMessage
);
2556 mStatus err
= mStatus_NoError
;
2557 const domainname
*target
;
2560 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
2561 LogMsg("SendServiceRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
2563 if (mDNSIPv4AddressIsZero(srs
->SRSUpdateServer
.ip
.v4
)) // Don't know our UpdateServer yet
2565 srs
->RR_SRV
.LastAPTime
= m
->timenow
;
2566 if (srs
->RR_SRV
.ThisAPInterval
< mDNSPlatformOneSecond
* 5)
2567 srs
->RR_SRV
.ThisAPInterval
= mDNSPlatformOneSecond
* 5;
2571 if (srs
->state
== regState_Registered
) srs
->state
= regState_Refresh
;
2573 id
= mDNS_NewMessageID(m
);
2574 InitializeDNSMessage(&m
->omsg
.h
, id
, UpdateReqFlags
);
2576 // setup resource records
2577 SetNewRData(&srs
->RR_PTR
.resrec
, mDNSNULL
, 0); // Update rdlength, rdestimate, rdatahash
2578 SetNewRData(&srs
->RR_TXT
.resrec
, mDNSNULL
, 0); // Update rdlength, rdestimate, rdatahash
2580 // replace port w/ NAT mapping if necessary
2581 if (srs
->RR_SRV
.AutoTarget
== Target_AutoHostAndNATMAP
&& !mDNSIPPortIsZero(srs
->NATinfo
.ExternalPort
))
2582 srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
= srs
->NATinfo
.ExternalPort
;
2584 // construct update packet
2586 ptr
= putZone(&m
->omsg
, ptr
, end
, &srs
->zone
, mDNSOpaque16fromIntVal(srs
->RR_SRV
.resrec
.rrclass
));
2587 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
2589 if (srs
->TestForSelfConflict
)
2591 // update w/ prereq that SRV already exist to make sure previous registration was ours, and delete any stale TXT records
2592 if (!(ptr
= PutResourceRecordTTLJumbo(&m
->omsg
, ptr
, &m
->omsg
.h
.mDNS_numPrereqs
, &srs
->RR_SRV
.resrec
, 0))) { err
= mStatus_UnknownErr
; goto exit
; }
2593 if (!(ptr
= putDeleteRRSet(&m
->omsg
, ptr
, srs
->RR_TXT
.resrec
.name
, srs
->RR_TXT
.resrec
.rrtype
))) { err
= mStatus_UnknownErr
; goto exit
; }
2596 else if (srs
->state
!= regState_Refresh
&& srs
->state
!= regState_UpdatePending
)
2598 // use SRV name for prereq
2599 //ptr = putPrereqNameNotInUse(srs->RR_SRV.resrec.name, &m->omsg, ptr, end);
2601 // For now, until we implement RFC 4701 (DHCID RR) to detect whether an existing record is someone else using the name, or just a
2602 // stale echo of our own previous registration before we changed our host name, we just overwrite whatever may have already been there
2603 ptr
= putDeleteRRSet(&m
->omsg
, ptr
, srs
->RR_SRV
.resrec
.name
, kDNSQType_ANY
);
2604 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
2607 //!!!KRS Need to do bounds checking and use TCP if it won't fit!!!
2608 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
; }
2610 for (i
= 0; i
< srs
->NumSubTypes
; i
++)
2611 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
; }
2613 if (srs
->state
== regState_UpdatePending
) // we're updating the txt record
2615 AuthRecord
*txt
= &srs
->RR_TXT
;
2617 SetNewRData(&txt
->resrec
, txt
->OrigRData
, txt
->OrigRDLen
);
2618 if (!(ptr
= putDeletionRecord(&m
->omsg
, ptr
, &srs
->RR_TXT
.resrec
))) { err
= mStatus_UnknownErr
; goto exit
; } // delete old rdata
2621 SetNewRData(&txt
->resrec
, txt
->InFlightRData
, txt
->InFlightRDLen
);
2622 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
; }
2625 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
; }
2627 target
= GetServiceTarget(m
, &srs
->RR_SRV
);
2628 if (!target
|| target
->c
[0] == 0)
2630 debugf("SendServiceRegistration - no target for %##s", srs
->RR_SRV
.resrec
.name
->c
);
2631 srs
->state
= regState_NoTarget
;
2635 if (!SameDomainName(target
, &srs
->RR_SRV
.resrec
.rdata
->u
.srv
.target
))
2637 AssignDomainName(&srs
->RR_SRV
.resrec
.rdata
->u
.srv
.target
, target
);
2638 SetNewRData(&srs
->RR_SRV
.resrec
, mDNSNULL
, 0); // Update rdlength, rdestimate, rdatahash
2641 ptr
= PutResourceRecordTTLJumbo(&m
->omsg
, ptr
, &m
->omsg
.h
.mDNS_numUpdates
, &srs
->RR_SRV
.resrec
, srs
->RR_SRV
.resrec
.rroriginalttl
);
2642 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
2644 if (srs
->srs_uselease
)
2645 { ptr
= putUpdateLease(&m
->omsg
, ptr
, DEFAULT_UPDATE_LEASE
); if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; } }
2647 if (srs
->state
!= regState_Refresh
&& srs
->state
!= regState_DeregDeferred
&& srs
->state
!= regState_UpdatePending
)
2648 srs
->state
= regState_Pending
;
2654 if (srs
->tcp
) LogInfo("SendServiceRegistration: Disposing existing TCP connection for %s", ARDisplayString(m
, &srs
->RR_SRV
));
2655 if (srs
->tcp
) DisposeTCPConn(srs
->tcp
);
2656 srs
->tcp
= MakeTCPConn(m
, &m
->omsg
, ptr
, kTCPSocketFlags_UseTLS
, &srs
->SRSUpdateServer
, srs
->SRSUpdatePort
, mDNSNULL
, srs
, mDNSNULL
);
2657 if (!srs
->tcp
) srs
->RR_SRV
.ThisAPInterval
= mDNSPlatformOneSecond
* 5; // If failed to make TCP connection, try again in ten seconds (5*2)
2658 else if (srs
->RR_SRV
.ThisAPInterval
< mDNSPlatformOneSecond
* 30) srs
->RR_SRV
.ThisAPInterval
= mDNSPlatformOneSecond
* 30;
2662 err
= mDNSSendDNSMessage(m
, &m
->omsg
, ptr
, mDNSInterface_Any
, mDNSNULL
, &srs
->SRSUpdateServer
, srs
->SRSUpdatePort
, mDNSNULL
, GetAuthInfoForName_internal(m
, srs
->RR_SRV
.resrec
.name
));
2663 if (err
) debugf("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %d", err
);
2666 SetRecordRetry(m
, &srs
->RR_SRV
, err
);
2672 LogMsg("SendServiceRegistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
2674 srs
->state
= regState_Unregistered
;
2676 mDNS_DropLockBeforeCallback();
2677 srs
->ServiceCallback(m
, srs
, err
);
2678 mDNS_ReclaimLockAfterCallback();
2679 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
2680 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
2684 mDNSlocal
const domainname
*PUBLIC_UPDATE_SERVICE_TYPE
= (const domainname
*)"\x0B_dns-update" "\x04_udp";
2685 mDNSlocal
const domainname
*PUBLIC_LLQ_SERVICE_TYPE
= (const domainname
*)"\x08_dns-llq" "\x04_udp";
2687 mDNSlocal
const domainname
*PRIVATE_UPDATE_SERVICE_TYPE
= (const domainname
*)"\x0F_dns-update-tls" "\x04_tcp";
2688 mDNSlocal
const domainname
*PRIVATE_QUERY_SERVICE_TYPE
= (const domainname
*)"\x0E_dns-query-tls" "\x04_tcp";
2689 mDNSlocal
const domainname
*PRIVATE_LLQ_SERVICE_TYPE
= (const domainname
*)"\x0C_dns-llq-tls" "\x04_tcp";
2691 #define ZoneDataSRV(X) (\
2692 (X)->ZoneService == ZoneServiceUpdate ? ((X)->ZonePrivate ? PRIVATE_UPDATE_SERVICE_TYPE : PUBLIC_UPDATE_SERVICE_TYPE) : \
2693 (X)->ZoneService == ZoneServiceQuery ? ((X)->ZonePrivate ? PRIVATE_QUERY_SERVICE_TYPE : (const domainname*)"" ) : \
2694 (X)->ZoneService == ZoneServiceLLQ ? ((X)->ZonePrivate ? PRIVATE_LLQ_SERVICE_TYPE : PUBLIC_LLQ_SERVICE_TYPE ) : (const domainname*)"")
2696 // Forward reference: GetZoneData_StartQuery references GetZoneData_QuestionCallback, and
2697 // GetZoneData_QuestionCallback calls GetZoneData_StartQuery
2698 mDNSlocal mStatus
GetZoneData_StartQuery(mDNS
*const m
, ZoneData
*zd
, mDNSu16 qtype
);
2700 // GetZoneData_QuestionCallback is called from normal client callback context (core API calls allowed)
2701 mDNSlocal
void GetZoneData_QuestionCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
2703 ZoneData
*zd
= (ZoneData
*)question
->QuestionContext
;
2705 debugf("GetZoneData_QuestionCallback: %s %s", AddRecord
? "Add" : "Rmv", RRDisplayString(m
, answer
));
2707 if (!AddRecord
) return; // Don't care about REMOVE events
2708 if (AddRecord
== QC_addnocache
&& answer
->rdlength
== 0) return; // Don't care about transient failure indications
2709 if (answer
->rrtype
!= question
->qtype
) return; // Don't care about CNAMEs
2711 if (answer
->rrtype
== kDNSType_SOA
)
2713 debugf("GetZoneData GOT SOA %s", RRDisplayString(m
, answer
));
2714 mDNS_StopQuery(m
, question
);
2715 if (answer
->rdlength
)
2717 AssignDomainName(&zd
->ZoneName
, answer
->name
);
2718 zd
->ZoneClass
= answer
->rrclass
;
2719 AssignDomainName(&zd
->question
.qname
, &zd
->ZoneName
);
2720 GetZoneData_StartQuery(m
, zd
, kDNSType_SRV
);
2722 else if (zd
->CurrentSOA
->c
[0])
2724 zd
->CurrentSOA
= (domainname
*)(zd
->CurrentSOA
->c
+ zd
->CurrentSOA
->c
[0]+1);
2725 AssignDomainName(&zd
->question
.qname
, zd
->CurrentSOA
);
2726 GetZoneData_StartQuery(m
, zd
, kDNSType_SOA
);
2730 LogInfo("GetZoneData recursed to root label of %##s without finding SOA", zd
->ChildName
.c
);
2731 zd
->ZoneDataCallback(m
, mStatus_NoSuchNameErr
, zd
);
2732 mDNSPlatformMemFree(zd
);
2735 else if (answer
->rrtype
== kDNSType_SRV
)
2737 debugf("GetZoneData GOT SRV %s", RRDisplayString(m
, answer
));
2738 mDNS_StopQuery(m
, question
);
2739 // Right now we don't want to fail back to non-encrypted operations
2740 // If the AuthInfo has the AutoTunnel field set, then we want private or nothing
2741 // <rdar://problem/5687667> BTMM: Don't fallback to unencrypted operations when SRV lookup fails
2743 if (!answer
->rdlength
&& zd
->ZonePrivate
&& zd
->ZoneService
!= ZoneServiceQuery
)
2745 zd
->ZonePrivate
= mDNSfalse
; // Causes ZoneDataSRV() to yield a different SRV name when building the query
2746 GetZoneData_StartQuery(m
, zd
, kDNSType_SRV
); // Try again, non-private this time
2751 if (answer
->rdlength
)
2753 AssignDomainName(&zd
->Host
, &answer
->rdata
->u
.srv
.target
);
2754 zd
->Port
= answer
->rdata
->u
.srv
.port
;
2755 AssignDomainName(&zd
->question
.qname
, &zd
->Host
);
2756 GetZoneData_StartQuery(m
, zd
, kDNSType_A
);
2760 zd
->ZonePrivate
= mDNSfalse
;
2762 zd
->Port
= zeroIPPort
;
2763 zd
->Addr
= zeroAddr
;
2764 zd
->ZoneDataCallback(m
, mStatus_NoError
, zd
);
2765 mDNSPlatformMemFree(zd
);
2769 else if (answer
->rrtype
== kDNSType_A
)
2771 debugf("GetZoneData GOT A %s", RRDisplayString(m
, answer
));
2772 mDNS_StopQuery(m
, question
);
2773 zd
->Addr
.type
= mDNSAddrType_IPv4
;
2774 zd
->Addr
.ip
.v4
= (answer
->rdlength
== 4) ? answer
->rdata
->u
.ipv4
: zerov4Addr
;
2775 // In order to simulate firewalls blocking our outgoing TCP connections, returning immediate ICMP errors or TCP resets,
2776 // the code below will make us try to connect to loopback, resulting in an immediate "port unreachable" failure.
2777 // This helps us test to make sure we handle this case gracefully
2778 // <rdar://problem/5607082> BTMM: mDNSResponder taking 100 percent CPU after upgrading to 10.5.1
2780 zd
->Addr
.ip
.v4
.b
[0] = 127;
2781 zd
->Addr
.ip
.v4
.b
[1] = 0;
2782 zd
->Addr
.ip
.v4
.b
[2] = 0;
2783 zd
->Addr
.ip
.v4
.b
[3] = 1;
2785 zd
->ZoneDataCallback(m
, mStatus_NoError
, zd
);
2786 mDNSPlatformMemFree(zd
);
2790 // GetZoneData_StartQuery is called from normal client context (lock not held, or client callback)
2791 mDNSlocal mStatus
GetZoneData_StartQuery(mDNS
*const m
, ZoneData
*zd
, mDNSu16 qtype
)
2793 if (qtype
== kDNSType_SRV
)
2795 AssignDomainName(&zd
->question
.qname
, ZoneDataSRV(zd
));
2796 AppendDomainName(&zd
->question
.qname
, &zd
->ZoneName
);
2797 debugf("lookupDNSPort %##s", zd
->question
.qname
.c
);
2800 zd
->question
.ThisQInterval
= -1; // So that GetZoneData_QuestionCallback() knows whether to cancel this question (Is this necessary?)
2801 zd
->question
.InterfaceID
= mDNSInterface_Any
;
2802 zd
->question
.Target
= zeroAddr
;
2803 //zd->question.qname.c[0] = 0; // Already set
2804 zd
->question
.qtype
= qtype
;
2805 zd
->question
.qclass
= kDNSClass_IN
;
2806 zd
->question
.LongLived
= mDNSfalse
;
2807 zd
->question
.ExpectUnique
= mDNStrue
;
2808 zd
->question
.ForceMCast
= mDNSfalse
;
2809 zd
->question
.ReturnIntermed
= mDNStrue
;
2810 zd
->question
.QuestionCallback
= GetZoneData_QuestionCallback
;
2811 zd
->question
.QuestionContext
= zd
;
2813 //LogMsg("GetZoneData_StartQuery %##s (%s) %p", zd->question.qname.c, DNSTypeName(zd->question.qtype), zd->question.Private);
2814 return(mDNS_StartQuery(m
, &zd
->question
));
2817 // StartGetZoneData is an internal routine (i.e. must be called with the lock already held)
2818 mDNSexport ZoneData
*StartGetZoneData(mDNS
*const m
, const domainname
*const name
, const ZoneService target
, ZoneDataCallback callback
, void *ZoneDataContext
)
2820 DomainAuthInfo
*AuthInfo
= GetAuthInfoForName_internal(m
, name
);
2821 int initialskip
= (AuthInfo
&& AuthInfo
->AutoTunnel
) ? DomainNameLength(name
) - DomainNameLength(&AuthInfo
->domain
) : 0;
2822 ZoneData
*zd
= (ZoneData
*)mDNSPlatformMemAllocate(sizeof(ZoneData
));
2823 if (!zd
) { LogMsg("ERROR: StartGetZoneData - mDNSPlatformMemAllocate failed"); return mDNSNULL
; }
2824 mDNSPlatformMemZero(zd
, sizeof(ZoneData
));
2825 AssignDomainName(&zd
->ChildName
, name
);
2826 zd
->ZoneService
= target
;
2827 zd
->CurrentSOA
= (domainname
*)(&zd
->ChildName
.c
[initialskip
]);
2828 zd
->ZoneName
.c
[0] = 0;
2831 zd
->Port
= zeroIPPort
;
2832 zd
->Addr
= zeroAddr
;
2833 zd
->ZonePrivate
= AuthInfo
&& AuthInfo
->AutoTunnel
? mDNStrue
: mDNSfalse
;
2834 zd
->ZoneDataCallback
= callback
;
2835 zd
->ZoneDataContext
= ZoneDataContext
;
2837 zd
->question
.QuestionContext
= zd
;
2838 AssignDomainName(&zd
->question
.qname
, zd
->CurrentSOA
);
2840 mDNS_DropLockBeforeCallback(); // GetZoneData_StartQuery expects to be called from a normal callback, so we emulate that here
2841 GetZoneData_StartQuery(m
, zd
, kDNSType_SOA
);
2842 mDNS_ReclaimLockAfterCallback();
2847 // GetZoneData queries are a special case -- even if we have a key for them, we don't do them privately,
2848 // because that would result in an infinite loop (i.e. to do a private query we first need to get
2849 // the _dns-query-tls SRV record for the zone, and we can't do *that* privately because to do so
2850 // we'd need to already know the _dns-query-tls SRV record.
2851 // Also, as a general rule, we never do SOA queries privately
2852 mDNSexport DomainAuthInfo
*GetAuthInfoForQuestion(mDNS
*m
, const DNSQuestion
*const q
) // Must be called with lock held
2854 if (q
->QuestionCallback
== GetZoneData_QuestionCallback
) return(mDNSNULL
);
2855 if (q
->qtype
== kDNSType_SOA
) return(mDNSNULL
);
2856 return(GetAuthInfoForName_internal(m
, &q
->qname
));
2859 // ***************************************************************************
2860 #if COMPILER_LIKES_PRAGMA_MARK
2861 #pragma mark - host name and interface management
2864 // Called in normal client context (lock not held)
2865 mDNSlocal
void CompleteSRVNatMap(mDNS
*m
, NATTraversalInfo
*n
)
2867 ServiceRecordSet
*srs
= (ServiceRecordSet
*)n
->clientContext
;
2868 debugf("SRVNatMap complete %.4a IntPort %u ExternalPort %u NATLease %u", &n
->ExternalAddress
, mDNSVal16(n
->IntPort
), mDNSVal16(n
->ExternalPort
), n
->NATLease
);
2870 if (!srs
) { LogMsg("CompleteSRVNatMap called with unknown ServiceRecordSet object"); return; }
2871 if (!n
->NATLease
) return;
2874 if (!mDNSIPv4AddressIsZero(srs
->SRSUpdateServer
.ip
.v4
))
2875 SendServiceRegistration(m
, srs
); // non-zero server address means we already have necessary zone data to send update
2878 // SHOULD NEVER HAPPEN!
2879 LogInfo("ERROR: CompleteSRVNatMap called but srs->SRSUpdateServer.ip.v4 is zero!");
2880 srs
->state
= regState_FetchingZoneData
;
2881 if (srs
->srs_nta
) CancelGetZoneData(m
, srs
->srs_nta
); // Make sure we cancel old one before we start a new one
2882 srs
->srs_nta
= StartGetZoneData(m
, srs
->RR_SRV
.resrec
.name
, ZoneServiceUpdate
, ServiceRegistrationGotZoneData
, srs
);
2887 mDNSlocal
void StartSRVNatMap(mDNS
*m
, ServiceRecordSet
*srs
)
2889 const mDNSu8
*p
= srs
->RR_PTR
.resrec
.name
->c
;
2890 if (p
[0]) p
+= 1 + p
[0];
2891 if (SameDomainLabel(p
, (mDNSu8
*)"\x4" "_tcp")) srs
->NATinfo
.Protocol
= NATOp_MapTCP
;
2892 else if (SameDomainLabel(p
, (mDNSu8
*)"\x4" "_udp")) srs
->NATinfo
.Protocol
= NATOp_MapUDP
;
2893 else { LogMsg("StartSRVNatMap: could not determine transport protocol of service %##s", srs
->RR_SRV
.resrec
.name
->c
); return; }
2895 if (srs
->NATinfo
.clientContext
) mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
2896 // Don't try to set IntPort here --
2897 // SendServiceRegistration overwrites srs->RR_SRV.resrec.rdata->u.srv.port with external (mapped) port number
2898 //srs->NATinfo.IntPort = srs->RR_SRV.resrec.rdata->u.srv.port;
2899 srs
->NATinfo
.RequestedPort
= srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
;
2900 srs
->NATinfo
.NATLease
= 0; // Request default lease
2901 srs
->NATinfo
.clientCallback
= CompleteSRVNatMap
;
2902 srs
->NATinfo
.clientContext
= srs
;
2903 mDNS_StartNATOperation_internal(m
, &srs
->NATinfo
);
2906 // Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
2907 mDNSexport
void ServiceRegistrationGotZoneData(mDNS
*const m
, mStatus err
, const ZoneData
*zoneData
)
2909 ServiceRecordSet
*srs
= (ServiceRecordSet
*)zoneData
->ZoneDataContext
;
2911 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
)
2912 LogMsg("ServiceRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
2914 if (!srs
->RR_SRV
.resrec
.rdata
)
2915 { LogMsg("ServiceRegistrationGotZoneData: ERROR: srs->RR_SRV.resrec.rdata is NULL"); return; }
2917 srs
->srs_nta
= mDNSNULL
;
2919 // Start off assuming we're going to use a lease
2920 // 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
2921 srs
->srs_uselease
= mDNStrue
;
2923 if (err
|| !zoneData
) return;
2925 if (mDNSIPPortIsZero(zoneData
->Port
) || mDNSAddressIsZero(&zoneData
->Addr
)) return;
2928 AssignDomainName(&srs
->zone
, &zoneData
->ZoneName
);
2929 srs
->SRSUpdateServer
.type
= mDNSAddrType_IPv4
;
2930 srs
->SRSUpdateServer
= zoneData
->Addr
;
2931 srs
->SRSUpdatePort
= zoneData
->Port
;
2932 srs
->Private
= zoneData
->ZonePrivate
;
2934 srs
->RR_SRV
.LastAPTime
= m
->timenow
;
2935 srs
->RR_SRV
.ThisAPInterval
= 0;
2937 debugf("ServiceRegistrationGotZoneData My IPv4 %#a%s Server %#a:%d%s for %##s",
2938 &m
->AdvertisedV4
, mDNSv4AddrIsRFC1918(&m
->AdvertisedV4
.ip
.v4
) ? " (RFC1918)" : "",
2939 &srs
->SRSUpdateServer
, mDNSVal16(srs
->SRSUpdatePort
), mDNSAddrIsRFC1918(&srs
->SRSUpdateServer
) ? " (RFC1918)" : "",
2940 srs
->RR_SRV
.resrec
.name
->c
);
2942 // If we have non-zero service port (always?)
2943 // and a private address, and update server is non-private
2944 // and this service is AutoTarget
2945 // then initiate a NAT mapping request. On completion it will do SendServiceRegistration() for us
2946 if (!mDNSIPPortIsZero(srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
) &&
2947 mDNSv4AddrIsRFC1918(&m
->AdvertisedV4
.ip
.v4
) && !mDNSAddrIsRFC1918(&srs
->SRSUpdateServer
) &&
2948 srs
->RR_SRV
.AutoTarget
== Target_AutoHostAndNATMAP
)
2950 srs
->state
= regState_NATMap
;
2951 debugf("ServiceRegistrationGotZoneData StartSRVNatMap");
2952 StartSRVNatMap(m
, srs
);
2957 SendServiceRegistration(m
, srs
);
2962 mDNSlocal
void SendServiceDeregistration(mDNS
*m
, ServiceRecordSet
*srs
)
2965 mDNSu8
*ptr
= m
->omsg
.data
;
2966 mDNSu8
*end
= (mDNSu8
*)&m
->omsg
+ sizeof(DNSMessage
);
2967 mStatus err
= mStatus_UnknownErr
;
2970 if (mDNSIPv4AddressIsZero(srs
->SRSUpdateServer
.ip
.v4
)) // Don't know our UpdateServer yet
2972 srs
->RR_SRV
.LastAPTime
= m
->timenow
;
2973 if (srs
->RR_SRV
.ThisAPInterval
< mDNSPlatformOneSecond
* 5)
2974 srs
->RR_SRV
.ThisAPInterval
= mDNSPlatformOneSecond
* 5;
2978 id
= mDNS_NewMessageID(m
);
2979 InitializeDNSMessage(&m
->omsg
.h
, id
, UpdateReqFlags
);
2982 ptr
= putZone(&m
->omsg
, ptr
, end
, &srs
->zone
, mDNSOpaque16fromIntVal(srs
->RR_SRV
.resrec
.rrclass
));
2983 if (!ptr
) { LogMsg("ERROR: SendServiceDeregistration - putZone"); err
= mStatus_UnknownErr
; goto exit
; }
2985 if (!(ptr
= putDeleteAllRRSets(&m
->omsg
, ptr
, srs
->RR_SRV
.resrec
.name
))) { err
= mStatus_UnknownErr
; goto exit
; } // this deletes SRV, TXT, and Extras
2986 if (!(ptr
= putDeletionRecord(&m
->omsg
, ptr
, &srs
->RR_PTR
.resrec
))) { err
= mStatus_UnknownErr
; goto exit
; }
2987 for (i
= 0; i
< srs
->NumSubTypes
; i
++)
2988 if (!(ptr
= putDeletionRecord(&m
->omsg
, ptr
, &srs
->SubTypes
[i
].resrec
))) { err
= mStatus_UnknownErr
; goto exit
; }
2991 srs
->state
= regState_DeregPending
;
2992 srs
->RR_SRV
.expire
= 0; // Indicate that we have no active registration any more
2996 LogInfo("SendServiceDeregistration TCP %p %s", srs
->tcp
, ARDisplayString(m
, &srs
->RR_SRV
));
2997 if (srs
->tcp
) LogInfo("SendServiceDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m
, &srs
->RR_SRV
));
2998 if (srs
->tcp
) DisposeTCPConn(srs
->tcp
);
2999 srs
->tcp
= MakeTCPConn(m
, &m
->omsg
, ptr
, kTCPSocketFlags_UseTLS
, &srs
->SRSUpdateServer
, srs
->SRSUpdatePort
, mDNSNULL
, srs
, mDNSNULL
);
3000 if (!srs
->tcp
) srs
->RR_SRV
.ThisAPInterval
= mDNSPlatformOneSecond
* 5; // If failed to make TCP connection, try again in ten seconds (5*2)
3001 else if (srs
->RR_SRV
.ThisAPInterval
< mDNSPlatformOneSecond
* 30) srs
->RR_SRV
.ThisAPInterval
= mDNSPlatformOneSecond
* 30;
3005 err
= mDNSSendDNSMessage(m
, &m
->omsg
, ptr
, mDNSInterface_Any
, mDNSNULL
, &srs
->SRSUpdateServer
, srs
->SRSUpdatePort
, mDNSNULL
, GetAuthInfoForName_internal(m
, srs
->RR_SRV
.resrec
.name
));
3006 if (err
&& err
!= mStatus_TransientErr
) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %d", err
); goto exit
; }
3009 SetRecordRetry(m
, &srs
->RR_SRV
, err
);
3015 LogMsg("SendServiceDeregistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
3017 srs
->state
= regState_Unregistered
;
3021 // Called with lock held
3022 mDNSlocal
void UpdateSRV(mDNS
*m
, ServiceRecordSet
*srs
)
3024 ExtraResourceRecord
*e
;
3026 // Target change if:
3027 // We have a target and were previously waiting for one, or
3028 // We had a target and no longer do, or
3029 // The target has changed
3031 domainname
*curtarget
= &srs
->RR_SRV
.resrec
.rdata
->u
.srv
.target
;
3032 const domainname
*const nt
= GetServiceTarget(m
, &srs
->RR_SRV
);
3033 const domainname
*const newtarget
= nt
? nt
: (domainname
*)"";
3034 mDNSBool TargetChanged
= (newtarget
->c
[0] && srs
->state
== regState_NoTarget
) || !SameDomainName(curtarget
, newtarget
);
3035 mDNSBool HaveZoneData
= !mDNSIPv4AddressIsZero(srs
->SRSUpdateServer
.ip
.v4
);
3037 // Nat state change if:
3038 // We were behind a NAT, and now we are behind a new NAT, or
3039 // We're not behind a NAT but our port was previously mapped to a different external port
3040 // We were not behind a NAT and now we are
3042 mDNSIPPort port
= srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
;
3043 mDNSBool NowNeedNATMAP
= (srs
->RR_SRV
.AutoTarget
== Target_AutoHostAndNATMAP
&& !mDNSIPPortIsZero(port
) && mDNSv4AddrIsRFC1918(&m
->AdvertisedV4
.ip
.v4
) && !mDNSAddrIsRFC1918(&srs
->SRSUpdateServer
));
3044 mDNSBool WereBehindNAT
= (srs
->NATinfo
.clientContext
!= mDNSNULL
);
3045 mDNSBool PortWasMapped
= (srs
->NATinfo
.clientContext
&& !mDNSSameIPPort(srs
->NATinfo
.RequestedPort
, port
)); // I think this is always false -- SC Sept 07
3046 mDNSBool NATChanged
= (!WereBehindNAT
&& NowNeedNATMAP
) || (!NowNeedNATMAP
&& PortWasMapped
);
3048 debugf("UpdateSRV %##s newtarget %##s TargetChanged %d HaveZoneData %d port %d NowNeedNATMAP %d WereBehindNAT %d PortWasMapped %d NATChanged %d",
3049 srs
->RR_SRV
.resrec
.name
->c
, newtarget
,
3050 TargetChanged
, HaveZoneData
, mDNSVal16(port
), NowNeedNATMAP
, WereBehindNAT
, PortWasMapped
, NATChanged
);
3052 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
3053 LogMsg("UpdateSRV: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
3055 if (!TargetChanged
&& !NATChanged
) return;
3059 case regState_FetchingZoneData
:
3060 case regState_DeregPending
:
3061 case regState_DeregDeferred
:
3062 case regState_Unregistered
:
3063 case regState_NATMap
:
3064 case regState_ExtraQueued
:
3065 // In these states, the SRV has either not yet been registered (it will get up-to-date information when it is)
3066 // or is in the process of, or has already been, deregistered
3069 case regState_Pending
:
3070 case regState_Refresh
:
3071 case regState_UpdatePending
:
3072 // let the in-flight operation complete before updating
3073 srs
->SRVUpdateDeferred
= mDNStrue
;
3076 case regState_NATError
:
3077 if (!NATChanged
) return;
3078 // if nat changed, register if we have a target (below)
3080 case regState_NoTarget
:
3081 if (newtarget
->c
[0])
3083 debugf("UpdateSRV: %s service %##s", HaveZoneData
? (NATChanged
&& NowNeedNATMAP
? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs
->RR_SRV
.resrec
.name
->c
);
3086 srs
->state
= regState_FetchingZoneData
;
3087 if (srs
->srs_nta
) CancelGetZoneData(m
, srs
->srs_nta
); // Make sure we cancel old one before we start a new one
3088 srs
->srs_nta
= StartGetZoneData(m
, srs
->RR_SRV
.resrec
.name
, ZoneServiceUpdate
, ServiceRegistrationGotZoneData
, srs
);
3092 if (srs
->NATinfo
.clientContext
&& (NATChanged
|| !NowNeedNATMAP
))
3094 mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
3095 srs
->NATinfo
.clientContext
= mDNSNULL
;
3097 if (NATChanged
&& NowNeedNATMAP
&& srs
->RR_SRV
.AutoTarget
== Target_AutoHostAndNATMAP
)
3098 { srs
->state
= regState_NATMap
; StartSRVNatMap(m
, srs
); }
3099 else SendServiceRegistration(m
, srs
);
3104 case regState_Registered
:
3105 // target or nat changed. deregister service. upon completion, we'll look for a new target
3106 debugf("UpdateSRV: SRV record changed for service %##s - deregistering (will re-register with new SRV)", srs
->RR_SRV
.resrec
.name
->c
);
3107 for (e
= srs
->Extras
; e
; e
= e
->next
) e
->r
.state
= regState_ExtraQueued
; // extra will be re-registed if the service is re-registered
3108 srs
->SRVChanged
= mDNStrue
;
3109 SendServiceDeregistration(m
, srs
);
3112 default: LogMsg("UpdateSRV: Unknown state %d for %##s", srs
->state
, srs
->RR_SRV
.resrec
.name
->c
);
3116 // Called with lock held
3117 mDNSlocal
void UpdateSRVRecords(mDNS
*m
)
3119 debugf("UpdateSRVRecords%s", m
->SleepState
? " (ignored due to SleepState)" : "");
3120 if (m
->SleepState
) return;
3122 if (CurrentServiceRecordSet
)
3123 LogMsg("UpdateSRVRecords ERROR CurrentServiceRecordSet already set");
3124 CurrentServiceRecordSet
= m
->ServiceRegistrations
;
3126 while (CurrentServiceRecordSet
)
3128 ServiceRecordSet
*s
= CurrentServiceRecordSet
;
3129 CurrentServiceRecordSet
= CurrentServiceRecordSet
->uDNS_next
;
3133 mDNS_DropLockBeforeCallback(); // mDNS_SetFQDN expects to be called without the lock held, so we emulate that here
3135 mDNS_ReclaimLockAfterCallback();
3138 // Forward reference: AdvertiseHostname references HostnameCallback, and HostnameCallback calls AdvertiseHostname
3139 mDNSlocal
void HostnameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
);
3141 // Called in normal client context (lock not held)
3142 mDNSlocal
void hostnameGetPublicAddressCallback(mDNS
*m
, NATTraversalInfo
*n
)
3144 HostnameInfo
*h
= (HostnameInfo
*)n
->clientContext
;
3146 if (!h
) { LogMsg("RegisterHostnameRecord: registration cancelled"); return; }
3150 if (mDNSIPv4AddressIsZero(n
->ExternalAddress
) || mDNSv4AddrIsRFC1918(&n
->ExternalAddress
)) return;
3152 if (h
->arv4
.resrec
.RecordType
)
3154 if (mDNSSameIPv4Address(h
->arv4
.resrec
.rdata
->u
.ipv4
, n
->ExternalAddress
)) return; // If address unchanged, do nothing
3155 LogInfo("Updating hostname %##s IPv4 from %.4a to %.4a (NAT gateway's external address)",
3156 h
->arv4
.resrec
.name
->c
, &h
->arv4
.resrec
.rdata
->u
.ipv4
, &n
->ExternalAddress
);
3157 mDNS_Deregister(m
, &h
->arv4
); // mStatus_MemFree callback will re-register with new address
3161 LogInfo("Advertising hostname %##s IPv4 %.4a (NAT gateway's external address)", h
->arv4
.resrec
.name
->c
, &n
->ExternalAddress
);
3162 h
->arv4
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
3163 h
->arv4
.resrec
.rdata
->u
.ipv4
= n
->ExternalAddress
;
3164 mDNS_Register(m
, &h
->arv4
);
3169 // register record or begin NAT traversal
3170 mDNSlocal
void AdvertiseHostname(mDNS
*m
, HostnameInfo
*h
)
3172 if (!mDNSIPv4AddressIsZero(m
->AdvertisedV4
.ip
.v4
) && h
->arv4
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
3174 mDNS_SetupResourceRecord(&h
->arv4
, mDNSNULL
, mDNSInterface_Any
, kDNSType_A
, kHostNameTTL
, kDNSRecordTypeUnregistered
, HostnameCallback
, h
);
3175 AssignDomainName(&h
->arv4
.namestorage
, &h
->fqdn
);
3176 h
->arv4
.resrec
.rdata
->u
.ipv4
= m
->AdvertisedV4
.ip
.v4
;
3177 h
->arv4
.state
= regState_Unregistered
;
3178 if (mDNSv4AddrIsRFC1918(&m
->AdvertisedV4
.ip
.v4
))
3180 // If we already have a NAT query active, stop it and restart it to make sure we get another callback
3181 if (h
->natinfo
.clientContext
) mDNS_StopNATOperation_internal(m
, &h
->natinfo
);
3182 h
->natinfo
.Protocol
= 0;
3183 h
->natinfo
.IntPort
= zeroIPPort
;
3184 h
->natinfo
.RequestedPort
= zeroIPPort
;
3185 h
->natinfo
.NATLease
= 0;
3186 h
->natinfo
.clientCallback
= hostnameGetPublicAddressCallback
;
3187 h
->natinfo
.clientContext
= h
;
3188 mDNS_StartNATOperation_internal(m
, &h
->natinfo
);
3192 LogInfo("Advertising hostname %##s IPv4 %.4a", h
->arv4
.resrec
.name
->c
, &m
->AdvertisedV4
.ip
.v4
);
3193 h
->arv4
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
3194 mDNS_Register_internal(m
, &h
->arv4
);
3198 if (!mDNSIPv6AddressIsZero(m
->AdvertisedV6
.ip
.v6
) && h
->arv6
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
3200 mDNS_SetupResourceRecord(&h
->arv6
, mDNSNULL
, mDNSInterface_Any
, kDNSType_AAAA
, kHostNameTTL
, kDNSRecordTypeKnownUnique
, HostnameCallback
, h
);
3201 AssignDomainName(&h
->arv6
.namestorage
, &h
->fqdn
);
3202 h
->arv6
.resrec
.rdata
->u
.ipv6
= m
->AdvertisedV6
.ip
.v6
;
3203 h
->arv6
.state
= regState_Unregistered
;
3204 LogInfo("Advertising hostname %##s IPv6 %.16a", h
->arv6
.resrec
.name
->c
, &m
->AdvertisedV6
.ip
.v6
);
3205 mDNS_Register_internal(m
, &h
->arv6
);
3209 mDNSlocal
void HostnameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
3211 HostnameInfo
*hi
= (HostnameInfo
*)rr
->RecordContext
;
3213 if (result
== mStatus_MemFree
)
3217 // If we're still in the Hostnames list, update to new address
3219 LogInfo("HostnameCallback: Got mStatus_MemFree for %p %p %s", hi
, rr
, ARDisplayString(m
, rr
));
3220 for (i
= m
->Hostnames
; i
; i
= i
->next
)
3221 if (rr
== &i
->arv4
|| rr
== &i
->arv6
)
3222 { mDNS_Lock(m
); AdvertiseHostname(m
, i
); mDNS_Unlock(m
); return; }
3224 // Else, we're not still in the Hostnames list, so free the memory
3225 if (hi
->arv4
.resrec
.RecordType
== kDNSRecordTypeUnregistered
&&
3226 hi
->arv6
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
3228 if (hi
->natinfo
.clientContext
) mDNS_StopNATOperation_internal(m
, &hi
->natinfo
);
3229 hi
->natinfo
.clientContext
= mDNSNULL
;
3230 mDNSPlatformMemFree(hi
); // free hi when both v4 and v6 AuthRecs deallocated
3238 // don't unlink or free - we can retry when we get a new address/router
3239 if (rr
->resrec
.rrtype
== kDNSType_A
)
3240 LogMsg("HostnameCallback: Error %d for registration of %##s IP %.4a", result
, rr
->resrec
.name
->c
, &rr
->resrec
.rdata
->u
.ipv4
);
3242 LogMsg("HostnameCallback: Error %d for registration of %##s IP %.16a", result
, rr
->resrec
.name
->c
, &rr
->resrec
.rdata
->u
.ipv6
);
3243 if (!hi
) { mDNSPlatformMemFree(rr
); return; }
3244 if (rr
->state
!= regState_Unregistered
) LogMsg("Error: HostnameCallback invoked with error code for record not in regState_Unregistered!");
3246 if (hi
->arv4
.state
== regState_Unregistered
&&
3247 hi
->arv6
.state
== regState_Unregistered
)
3249 // only deliver status if both v4 and v6 fail
3250 rr
->RecordContext
= (void *)hi
->StatusContext
;
3251 if (hi
->StatusCallback
)
3252 hi
->StatusCallback(m
, rr
, result
); // client may NOT make API calls here
3253 rr
->RecordContext
= (void *)hi
;
3258 // register any pending services that require a target
3260 UpdateSRVRecords(m
);
3263 // Deliver success to client
3264 if (!hi
) { LogMsg("HostnameCallback invoked with orphaned address record"); return; }
3265 if (rr
->resrec
.rrtype
== kDNSType_A
)
3266 LogInfo("Registered hostname %##s IP %.4a", rr
->resrec
.name
->c
, &rr
->resrec
.rdata
->u
.ipv4
);
3268 LogInfo("Registered hostname %##s IP %.16a", rr
->resrec
.name
->c
, &rr
->resrec
.rdata
->u
.ipv6
);
3270 rr
->RecordContext
= (void *)hi
->StatusContext
;
3271 if (hi
->StatusCallback
)
3272 hi
->StatusCallback(m
, rr
, result
); // client may NOT make API calls here
3273 rr
->RecordContext
= (void *)hi
;
3276 mDNSlocal
void FoundStaticHostname(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
3278 const domainname
*pktname
= &answer
->rdata
->u
.name
;
3279 domainname
*storedname
= &m
->StaticHostname
;
3280 HostnameInfo
*h
= m
->Hostnames
;
3284 debugf("FoundStaticHostname: %##s -> %##s (%s)", question
->qname
.c
, answer
->rdata
->u
.name
.c
, AddRecord
? "added" : "removed");
3285 if (AddRecord
&& !SameDomainName(pktname
, storedname
))
3287 AssignDomainName(storedname
, pktname
);
3290 if (h
->arv4
.state
== regState_FetchingZoneData
|| h
->arv4
.state
== regState_Pending
|| h
->arv4
.state
== regState_NATMap
||
3291 h
->arv6
.state
== regState_FetchingZoneData
|| h
->arv6
.state
== regState_Pending
)
3293 // 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
3294 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
+ 5 * mDNSPlatformOneSecond
);
3300 UpdateSRVRecords(m
);
3303 else if (!AddRecord
&& SameDomainName(pktname
, storedname
))
3306 storedname
->c
[0] = 0;
3307 UpdateSRVRecords(m
);
3312 // Called with lock held
3313 mDNSlocal
void GetStaticHostname(mDNS
*m
)
3315 char buf
[MAX_REVERSE_MAPPING_NAME_V4
];
3316 DNSQuestion
*q
= &m
->ReverseMap
;
3317 mDNSu8
*ip
= m
->AdvertisedV4
.ip
.v4
.b
;
3320 if (m
->ReverseMap
.ThisQInterval
!= -1) return; // already running
3321 if (mDNSIPv4AddressIsZero(m
->AdvertisedV4
.ip
.v4
)) return;
3323 mDNSPlatformMemZero(q
, sizeof(*q
));
3324 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
3325 mDNS_snprintf(buf
, sizeof(buf
), "%d.%d.%d.%d.in-addr.arpa.", ip
[3], ip
[2], ip
[1], ip
[0]);
3326 if (!MakeDomainNameFromDNSNameString(&q
->qname
, buf
)) { LogMsg("Error: GetStaticHostname - bad name %s", buf
); return; }
3328 q
->InterfaceID
= mDNSInterface_Any
;
3329 q
->Target
= zeroAddr
;
3330 q
->qtype
= kDNSType_PTR
;
3331 q
->qclass
= kDNSClass_IN
;
3332 q
->LongLived
= mDNSfalse
;
3333 q
->ExpectUnique
= mDNSfalse
;
3334 q
->ForceMCast
= mDNSfalse
;
3335 q
->ReturnIntermed
= mDNStrue
;
3336 q
->QuestionCallback
= FoundStaticHostname
;
3337 q
->QuestionContext
= mDNSNULL
;
3339 LogInfo("GetStaticHostname: %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
3340 err
= mDNS_StartQuery_internal(m
, q
);
3341 if (err
) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err
);
3344 mDNSexport
void mDNS_AddDynDNSHostName(mDNS
*m
, const domainname
*fqdn
, mDNSRecordCallback
*StatusCallback
, const void *StatusContext
)
3346 HostnameInfo
**ptr
= &m
->Hostnames
;
3348 LogInfo("mDNS_AddDynDNSHostName %##s", fqdn
);
3350 while (*ptr
&& !SameDomainName(fqdn
, &(*ptr
)->fqdn
)) ptr
= &(*ptr
)->next
;
3351 if (*ptr
) { LogMsg("DynDNSHostName %##s already in list", fqdn
->c
); return; }
3353 // allocate and format new address record
3354 *ptr
= mDNSPlatformMemAllocate(sizeof(**ptr
));
3355 if (!*ptr
) { LogMsg("ERROR: mDNS_AddDynDNSHostName - malloc"); return; }
3357 mDNSPlatformMemZero(*ptr
, sizeof(**ptr
));
3358 AssignDomainName(&(*ptr
)->fqdn
, fqdn
);
3359 (*ptr
)->arv4
.state
= regState_Unregistered
;
3360 (*ptr
)->arv6
.state
= regState_Unregistered
;
3361 (*ptr
)->StatusCallback
= StatusCallback
;
3362 (*ptr
)->StatusContext
= StatusContext
;
3364 AdvertiseHostname(m
, *ptr
);
3367 mDNSexport
void mDNS_RemoveDynDNSHostName(mDNS
*m
, const domainname
*fqdn
)
3369 HostnameInfo
**ptr
= &m
->Hostnames
;
3371 LogInfo("mDNS_RemoveDynDNSHostName %##s", fqdn
);
3373 while (*ptr
&& !SameDomainName(fqdn
, &(*ptr
)->fqdn
)) ptr
= &(*ptr
)->next
;
3374 if (!*ptr
) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn
->c
);
3377 HostnameInfo
*hi
= *ptr
;
3378 // We do it this way because, if we have no active v6 record, the "mDNS_Deregister_internal(m, &hi->arv4);"
3379 // below could free the memory, and we have to make sure we don't touch hi fields after that.
3380 mDNSBool f4
= hi
->arv4
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
&& hi
->arv4
.state
!= regState_Unregistered
;
3381 mDNSBool f6
= hi
->arv6
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
&& hi
->arv6
.state
!= regState_Unregistered
;
3382 if (f4
) LogInfo("mDNS_RemoveDynDNSHostName removing v4 %##s", fqdn
);
3383 if (f6
) LogInfo("mDNS_RemoveDynDNSHostName removing v6 %##s", fqdn
);
3384 *ptr
= (*ptr
)->next
; // unlink
3385 if (f4
) mDNS_Deregister_internal(m
, &hi
->arv4
, mDNS_Dereg_normal
);
3386 if (f6
) mDNS_Deregister_internal(m
, &hi
->arv6
, mDNS_Dereg_normal
);
3387 // When both deregistrations complete we'll free the memory in the mStatus_MemFree callback
3389 UpdateSRVRecords(m
);
3392 // Currently called without holding the lock
3393 // Maybe we should change that?
3394 mDNSexport
void mDNS_SetPrimaryInterfaceInfo(mDNS
*m
, const mDNSAddr
*v4addr
, const mDNSAddr
*v6addr
, const mDNSAddr
*router
)
3396 mDNSBool v4Changed
, v6Changed
, RouterChanged
;
3398 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
)
3399 LogMsg("mDNS_SetPrimaryInterfaceInfo: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
3401 if (v4addr
&& v4addr
->type
!= mDNSAddrType_IPv4
) { LogMsg("mDNS_SetPrimaryInterfaceInfo v4 address - incorrect type. Discarding. %#a", v4addr
); return; }
3402 if (v6addr
&& v6addr
->type
!= mDNSAddrType_IPv6
) { LogMsg("mDNS_SetPrimaryInterfaceInfo v6 address - incorrect type. Discarding. %#a", v6addr
); return; }
3403 if (router
&& router
->type
!= mDNSAddrType_IPv4
) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-v4 router. Discarding. %#a", router
); return; }
3407 if (v4addr
&& !mDNSv4AddressIsLinkLocal(&v4addr
->ip
.v4
)) v6addr
= mDNSNULL
;
3409 v4Changed
= !mDNSSameIPv4Address(m
->AdvertisedV4
.ip
.v4
, v4addr
? v4addr
->ip
.v4
: zerov4Addr
);
3410 v6Changed
= !mDNSSameIPv6Address(m
->AdvertisedV6
.ip
.v6
, v6addr
? v6addr
->ip
.v6
: zerov6Addr
);
3411 RouterChanged
= !mDNSSameIPv4Address(m
->Router
.ip
.v4
, router
? router
->ip
.v4
: zerov4Addr
);
3413 if (v4addr
&& (v4Changed
|| RouterChanged
))
3414 debugf("mDNS_SetPrimaryInterfaceInfo: address changed from %#a to %#a", &m
->AdvertisedV4
, v4addr
);
3416 if (v4addr
) m
->AdvertisedV4
= *v4addr
; else m
->AdvertisedV4
.ip
.v4
= zerov4Addr
;
3417 if (v6addr
) m
->AdvertisedV6
= *v6addr
; else m
->AdvertisedV6
.ip
.v6
= zerov6Addr
;
3418 if (router
) m
->Router
= *router
; else m
->Router
.ip
.v4
= zerov4Addr
;
3419 // setting router to zero indicates that nat mappings must be reestablished when router is reset
3421 if (v4Changed
|| RouterChanged
|| v6Changed
)
3424 LogInfo("mDNS_SetPrimaryInterfaceInfo: %s%s%s%#a %#a %#a",
3425 v4Changed
? "v4Changed " : "",
3426 RouterChanged
? "RouterChanged " : "",
3427 v6Changed
? "v6Changed " : "", v4addr
, v6addr
, router
);
3429 for (i
= m
->Hostnames
; i
; i
= i
->next
)
3431 LogInfo("mDNS_SetPrimaryInterfaceInfo updating host name registrations for %##s", i
->fqdn
.c
);
3433 if (i
->arv4
.resrec
.RecordType
> kDNSRecordTypeDeregistering
&&
3434 !mDNSSameIPv4Address(i
->arv4
.resrec
.rdata
->u
.ipv4
, m
->AdvertisedV4
.ip
.v4
))
3436 LogInfo("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m
, &i
->arv4
));
3437 mDNS_Deregister_internal(m
, &i
->arv4
, mDNS_Dereg_normal
);
3440 if (i
->arv6
.resrec
.RecordType
> kDNSRecordTypeDeregistering
&&
3441 !mDNSSameIPv6Address(i
->arv6
.resrec
.rdata
->u
.ipv6
, m
->AdvertisedV6
.ip
.v6
))
3443 LogInfo("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m
, &i
->arv6
));
3444 mDNS_Deregister_internal(m
, &i
->arv6
, mDNS_Dereg_normal
);
3447 // AdvertiseHostname will only register new address records.
3448 // For records still in the process of deregistering it will ignore them, and let the mStatus_MemFree callback handle them.
3449 AdvertiseHostname(m
, i
);
3452 if (v4Changed
|| RouterChanged
)
3454 m
->ExternalAddress
= zerov4Addr
;
3455 m
->retryIntervalGetAddr
= NATMAP_INIT_RETRY
;
3456 m
->retryGetAddr
= m
->timenow
;
3457 m
->NextScheduledNATOp
= m
->timenow
;
3458 m
->LastNATMapResultCode
= NATErr_None
;
3459 #ifdef _LEGACY_NAT_TRAVERSAL_
3461 #endif // _LEGACY_NAT_TRAVERSAL_
3464 if (m
->ReverseMap
.ThisQInterval
!= -1) mDNS_StopQuery_internal(m
, &m
->ReverseMap
);
3465 m
->StaticHostname
.c
[0] = 0;
3467 UpdateSRVRecords(m
); // Will call GetStaticHostname if needed
3469 #if APPLE_OSX_mDNSResponder
3470 if (RouterChanged
) uuid_generate(m
->asl_uuid
);
3471 UpdateAutoTunnelDomainStatuses(m
);
3478 // ***************************************************************************
3479 #if COMPILER_LIKES_PRAGMA_MARK
3480 #pragma mark - Incoming Message Processing
3483 mDNSlocal mStatus
ParseTSIGError(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
, const domainname
*const displayname
)
3486 mStatus err
= mStatus_NoError
;
3489 ptr
= LocateAdditionals(msg
, end
);
3490 if (!ptr
) goto finish
;
3492 for (i
= 0; i
< msg
->h
.numAdditionals
; i
++)
3494 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &m
->rec
);
3495 if (!ptr
) goto finish
;
3496 if (m
->rec
.r
.resrec
.rrtype
== kDNSType_TSIG
)
3499 mDNSu8
*rd
= m
->rec
.r
.resrec
.rdata
->u
.data
;
3500 mDNSu8
*rdend
= rd
+ m
->rec
.r
.resrec
.rdlength
;
3501 int alglen
= DomainNameLengthLimit(&m
->rec
.r
.resrec
.rdata
->u
.name
, rdend
);
3502 if (alglen
> MAX_DOMAIN_NAME
) goto finish
;
3503 rd
+= alglen
; // algorithm name
3504 if (rd
+ 6 > rdend
) goto finish
;
3505 rd
+= 6; // 48-bit timestamp
3506 if (rd
+ sizeof(mDNSOpaque16
) > rdend
) goto finish
;
3507 rd
+= sizeof(mDNSOpaque16
); // fudge
3508 if (rd
+ sizeof(mDNSOpaque16
) > rdend
) goto finish
;
3509 macsize
= mDNSVal16(*(mDNSOpaque16
*)rd
);
3510 rd
+= sizeof(mDNSOpaque16
); // MAC size
3511 if (rd
+ macsize
> rdend
) goto finish
;
3513 if (rd
+ sizeof(mDNSOpaque16
) > rdend
) goto finish
;
3514 rd
+= sizeof(mDNSOpaque16
); // orig id
3515 if (rd
+ sizeof(mDNSOpaque16
) > rdend
) goto finish
;
3516 err
= mDNSVal16(*(mDNSOpaque16
*)rd
); // error code
3518 if (err
== TSIG_ErrBadSig
) { LogMsg("%##s: bad signature", displayname
->c
); err
= mStatus_BadSig
; }
3519 else if (err
== TSIG_ErrBadKey
) { LogMsg("%##s: bad key", displayname
->c
); err
= mStatus_BadKey
; }
3520 else if (err
== TSIG_ErrBadTime
) { LogMsg("%##s: bad time", displayname
->c
); err
= mStatus_BadTime
; }
3521 else if (err
) { LogMsg("%##s: unknown tsig error %d", displayname
->c
, err
); err
= mStatus_UnknownErr
; }
3524 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
3528 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
3532 mDNSlocal mStatus
checkUpdateResult(mDNS
*const m
, const domainname
*const displayname
, const mDNSu8 rcode
, const DNSMessage
*const msg
, const mDNSu8
*const end
)
3534 (void)msg
; // currently unused, needed for TSIG errors
3535 if (!rcode
) return mStatus_NoError
;
3536 else if (rcode
== kDNSFlag1_RC_YXDomain
)
3538 debugf("name in use: %##s", displayname
->c
);
3539 return mStatus_NameConflict
;
3541 else if (rcode
== kDNSFlag1_RC_Refused
)
3543 LogMsg("Update %##s refused", displayname
->c
);
3544 return mStatus_Refused
;
3546 else if (rcode
== kDNSFlag1_RC_NXRRSet
)
3548 LogMsg("Reregister refused (NXRRSET): %##s", displayname
->c
);
3549 return mStatus_NoSuchRecord
;
3551 else if (rcode
== kDNSFlag1_RC_NotAuth
)
3553 // TSIG errors should come with FormErr as per RFC 2845, but BIND 9 sends them with NotAuth so we look here too
3554 mStatus tsigerr
= ParseTSIGError(m
, msg
, end
, displayname
);
3557 LogMsg("Permission denied (NOAUTH): %##s", displayname
->c
);
3558 return mStatus_UnknownErr
;
3560 else return tsigerr
;
3562 else if (rcode
== kDNSFlag1_RC_FormErr
)
3564 mStatus tsigerr
= ParseTSIGError(m
, msg
, end
, displayname
);
3567 LogMsg("Format Error: %##s", displayname
->c
);
3568 return mStatus_UnknownErr
;
3570 else return tsigerr
;
3574 LogMsg("Update %##s failed with rcode %d", displayname
->c
, rcode
);
3575 return mStatus_UnknownErr
;
3579 // Called with lock held
3580 mDNSlocal
void SendRecordRegistration(mDNS
*const m
, AuthRecord
*rr
)
3582 mDNSu8
*ptr
= m
->omsg
.data
;
3583 mDNSu8
*end
= (mDNSu8
*)&m
->omsg
+ sizeof(DNSMessage
);
3584 mStatus err
= mStatus_UnknownErr
;
3586 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
3587 LogMsg("SendRecordRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
3589 if (mDNSIPv4AddressIsZero(rr
->UpdateServer
.ip
.v4
)) // Don't know our UpdateServer yet
3591 rr
->LastAPTime
= m
->timenow
;
3592 if (rr
->ThisAPInterval
< mDNSPlatformOneSecond
* 5)
3593 rr
->ThisAPInterval
= mDNSPlatformOneSecond
* 5;
3597 rr
->RequireGoodbye
= mDNStrue
;
3598 rr
->updateid
= mDNS_NewMessageID(m
);
3599 InitializeDNSMessage(&m
->omsg
.h
, rr
->updateid
, UpdateReqFlags
);
3602 ptr
= putZone(&m
->omsg
, ptr
, end
, rr
->zone
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
3603 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
3605 if (rr
->state
== regState_UpdatePending
)
3608 SetNewRData(&rr
->resrec
, rr
->OrigRData
, rr
->OrigRDLen
);
3609 if (!(ptr
= putDeletionRecord(&m
->omsg
, ptr
, &rr
->resrec
))) { err
= mStatus_UnknownErr
; goto exit
; } // delete old rdata
3612 SetNewRData(&rr
->resrec
, rr
->InFlightRData
, rr
->InFlightRDLen
);
3613 if (!(ptr
= PutResourceRecordTTLJumbo(&m
->omsg
, ptr
, &m
->omsg
.h
.mDNS_numUpdates
, &rr
->resrec
, rr
->resrec
.rroriginalttl
))) { err
= mStatus_UnknownErr
; goto exit
; }
3618 if (rr
->resrec
.RecordType
== kDNSRecordTypeKnownUnique
)
3620 // KnownUnique: Delete any previous value
3621 ptr
= putDeleteRRSet(&m
->omsg
, ptr
, rr
->resrec
.name
, rr
->resrec
.rrtype
);
3622 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
3625 else if (rr
->resrec
.RecordType
!= kDNSRecordTypeShared
)
3627 // For now don't do this, until we have the logic for intelligent grouping of individual recors into logical service record sets
3628 //ptr = putPrereqNameNotInUse(rr->resrec.name, &m->omsg, ptr, end);
3629 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
3632 ptr
= PutResourceRecordTTLJumbo(&m
->omsg
, ptr
, &m
->omsg
.h
.mDNS_numUpdates
, &rr
->resrec
, rr
->resrec
.rroriginalttl
);
3633 if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
3638 ptr
= putUpdateLease(&m
->omsg
, ptr
, DEFAULT_UPDATE_LEASE
); if (!ptr
) { err
= mStatus_UnknownErr
; goto exit
; }
3643 LogInfo("SendRecordRegistration TCP %p %s", rr
->tcp
, ARDisplayString(m
, rr
));
3644 if (rr
->tcp
) LogInfo("SendRecordRegistration: Disposing existing TCP connection for %s", ARDisplayString(m
, rr
));
3645 if (rr
->tcp
) DisposeTCPConn(rr
->tcp
);
3646 rr
->tcp
= MakeTCPConn(m
, &m
->omsg
, ptr
, kTCPSocketFlags_UseTLS
, &rr
->UpdateServer
, rr
->UpdatePort
, mDNSNULL
, mDNSNULL
, rr
);
3647 if (!rr
->tcp
) rr
->ThisAPInterval
= mDNSPlatformOneSecond
* 5; // If failed to make TCP connection, try again in ten seconds (5*2)
3648 else if (rr
->ThisAPInterval
< mDNSPlatformOneSecond
* 30) rr
->ThisAPInterval
= mDNSPlatformOneSecond
* 30;
3652 err
= mDNSSendDNSMessage(m
, &m
->omsg
, ptr
, mDNSInterface_Any
, mDNSNULL
, &rr
->UpdateServer
, rr
->UpdatePort
, mDNSNULL
, GetAuthInfoForName_internal(m
, rr
->resrec
.name
));
3653 if (err
) debugf("ERROR: SendRecordRegistration - mDNSSendDNSMessage - %d", err
);
3656 SetRecordRetry(m
, rr
, err
);
3658 if (rr
->state
!= regState_Refresh
&& rr
->state
!= regState_DeregDeferred
&& rr
->state
!= regState_UpdatePending
)
3659 rr
->state
= regState_Pending
;
3664 LogMsg("SendRecordRegistration: Error formatting message for %s", ARDisplayString(m
, rr
));
3667 // Called with lock held
3668 mDNSlocal
void hndlServiceUpdateReply(mDNS
*const m
, ServiceRecordSet
*srs
, mStatus err
)
3670 mDNSBool InvokeCallback
= mDNSfalse
;
3671 ExtraResourceRecord
**e
= &srs
->Extras
;
3672 AuthRecord
*txt
= &srs
->RR_TXT
;
3674 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
3675 LogMsg("hndlServiceUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
3677 debugf("hndlServiceUpdateReply: err %d state %d %##s", err
, srs
->state
, srs
->RR_SRV
.resrec
.name
->c
);
3679 SetRecordRetry(m
, &srs
->RR_SRV
, mStatus_NoError
);
3683 case regState_Pending
:
3684 if (err
== mStatus_NameConflict
&& !srs
->TestForSelfConflict
)
3686 srs
->TestForSelfConflict
= mDNStrue
;
3687 debugf("checking for self-conflict of service %##s", srs
->RR_SRV
.resrec
.name
->c
);
3688 SendServiceRegistration(m
, srs
);
3691 else if (srs
->TestForSelfConflict
)
3693 srs
->TestForSelfConflict
= mDNSfalse
;
3694 if (err
== mStatus_NoSuchRecord
) err
= mStatus_NameConflict
; // NoSuchRecord implies that our prereq was not met, so we actually have a name conflict
3695 if (!err
) srs
->state
= regState_Registered
;
3696 InvokeCallback
= mDNStrue
;
3699 else if (srs
->srs_uselease
&& err
== mStatus_UnknownErr
&& mDNSSameIPPort(srs
->SRSUpdatePort
, UnicastDNSPort
))
3701 LogMsg("Re-trying update of service %##s without lease option", srs
->RR_SRV
.resrec
.name
->c
);
3702 srs
->srs_uselease
= mDNSfalse
;
3703 SendServiceRegistration(m
, srs
);
3708 //!!!KRS make sure all structs will still get cleaned up when client calls DeregisterService with this state
3709 if (err
) LogMsg("Error %d for registration of service %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
3710 else srs
->state
= regState_Registered
;
3711 InvokeCallback
= mDNStrue
;
3714 case regState_Refresh
:
3717 LogMsg("Error %d for refresh of service %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
3718 InvokeCallback
= mDNStrue
;
3720 else srs
->state
= regState_Registered
;
3722 case regState_DeregPending
:
3723 if (err
) LogMsg("Error %d for deregistration of service %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
3724 if (srs
->SRVChanged
)
3726 srs
->state
= regState_NoTarget
; // NoTarget will allow us to pick up new target OR nat traversal state
3729 err
= mStatus_MemFree
;
3730 InvokeCallback
= mDNStrue
;
3731 if (srs
->NATinfo
.clientContext
)
3733 // deletion completed
3734 mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
3735 srs
->NATinfo
.clientContext
= mDNSNULL
;
3737 srs
->state
= regState_Unregistered
;
3739 case regState_DeregDeferred
:
3742 debugf("Error %d received prior to deferred deregistration of %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
3743 err
= mStatus_MemFree
;
3744 InvokeCallback
= mDNStrue
;
3745 srs
->state
= regState_Unregistered
;
3750 debugf("Performing deferred deregistration of %##s", srs
->RR_SRV
.resrec
.name
->c
);
3751 srs
->state
= regState_Registered
;
3752 SendServiceDeregistration(m
, srs
);
3755 case regState_UpdatePending
:
3758 LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs
->RR_SRV
.resrec
.name
->c
);
3759 InvokeCallback
= mDNStrue
;
3763 srs
->state
= regState_Registered
;
3764 // deallocate old RData
3765 if (txt
->UpdateCallback
) txt
->UpdateCallback(m
, txt
, txt
->OrigRData
);
3766 SetNewRData(&txt
->resrec
, txt
->InFlightRData
, txt
->InFlightRDLen
);
3767 txt
->OrigRData
= mDNSNULL
;
3768 txt
->InFlightRData
= mDNSNULL
;
3771 case regState_NoTarget
:
3772 // This state is used when using SendServiceDeregistration() when going to sleep -- no further action required
3774 case regState_FetchingZoneData
:
3775 case regState_Registered
:
3776 case regState_Unregistered
:
3777 case regState_NATMap
:
3778 case regState_ExtraQueued
:
3779 case regState_NATError
:
3780 LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %d. Unlinking.",
3781 srs
->RR_SRV
.resrec
.name
->c
, srs
->state
, err
);
3782 err
= mStatus_UnknownErr
;
3783 default: LogMsg("hndlServiceUpdateReply: Unknown state %d for %##s", srs
->state
, srs
->RR_SRV
.resrec
.name
->c
);
3786 if ((srs
->SRVChanged
|| srs
->SRVUpdateDeferred
) && (srs
->state
== regState_NoTarget
|| srs
->state
== regState_Registered
))
3788 debugf("hndlServiceUpdateReply: SRVChanged %d SRVUpdateDeferred %d state %d", srs
->SRVChanged
, srs
->SRVUpdateDeferred
, srs
->state
);
3791 srs
->ClientCallbackDeferred
= mDNStrue
;
3792 srs
->DeferredStatus
= err
;
3794 srs
->SRVChanged
= srs
->SRVUpdateDeferred
= mDNSfalse
;
3801 if ((*e
)->r
.state
== regState_ExtraQueued
)
3803 if (srs
->state
== regState_Registered
&& !err
)
3805 // extra resource record queued for this service - copy zone srs and register
3806 (*e
)->r
.zone
= &srs
->zone
;
3807 (*e
)->r
.UpdateServer
= srs
->SRSUpdateServer
;
3808 (*e
)->r
.UpdatePort
= srs
->SRSUpdatePort
;
3809 (*e
)->r
.uselease
= srs
->srs_uselease
;
3810 SendRecordRegistration(m
, &(*e
)->r
);
3813 else if (err
&& (*e
)->r
.state
!= regState_Unregistered
)
3815 // unlink extra from list
3816 (*e
)->r
.state
= regState_Unregistered
;
3819 else e
= &(*e
)->next
;
3821 else e
= &(*e
)->next
;
3824 if (srs
->state
== regState_Unregistered
)
3826 if (err
!= mStatus_MemFree
)
3827 LogMsg("hndlServiceUpdateReply ERROR! state == regState_Unregistered but err != mStatus_MemFree. Permanently abandoning service registration %##s",
3828 srs
->RR_SRV
.resrec
.name
->c
);
3831 else if (txt
->QueuedRData
&& srs
->state
== regState_Registered
)
3835 // if we were supposed to give a client callback, we'll do it after we update the primary txt record
3836 srs
->ClientCallbackDeferred
= mDNStrue
;
3837 srs
->DeferredStatus
= err
;
3839 srs
->state
= regState_UpdatePending
;
3840 txt
->InFlightRData
= txt
->QueuedRData
;
3841 txt
->InFlightRDLen
= txt
->QueuedRDLen
;
3842 txt
->OrigRData
= txt
->resrec
.rdata
;
3843 txt
->OrigRDLen
= txt
->resrec
.rdlength
;
3844 txt
->QueuedRData
= mDNSNULL
;
3845 SendServiceRegistration(m
, srs
);
3849 mDNS_DropLockBeforeCallback();
3851 srs
->ServiceCallback(m
, srs
, err
);
3852 else if (srs
->ClientCallbackDeferred
)
3854 srs
->ClientCallbackDeferred
= mDNSfalse
;
3855 srs
->ServiceCallback(m
, srs
, srs
->DeferredStatus
);
3857 mDNS_ReclaimLockAfterCallback();
3858 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
3859 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
3862 // Called with lock held
3863 mDNSlocal
void hndlRecordUpdateReply(mDNS
*m
, AuthRecord
*rr
, mStatus err
)
3865 mDNSBool InvokeCallback
= mDNStrue
;
3867 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
3868 LogMsg("hndlRecordUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
3870 LogInfo("hndlRecordUpdateReply: err %d state %d %s", err
, rr
->state
, ARDisplayString(m
, rr
));
3872 if (m
->SleepState
) return; // If we just sent a deregister on going to sleep, no further action required
3874 SetRecordRetry(m
, rr
, mStatus_NoError
);
3876 if (rr
->state
== regState_UpdatePending
)
3878 if (err
) LogMsg("Update record failed for %##s (err %d)", rr
->resrec
.name
->c
, err
);
3879 rr
->state
= regState_Registered
;
3880 // deallocate old RData
3881 if (rr
->UpdateCallback
) rr
->UpdateCallback(m
, rr
, rr
->OrigRData
);
3882 SetNewRData(&rr
->resrec
, rr
->InFlightRData
, rr
->InFlightRDLen
);
3883 rr
->OrigRData
= mDNSNULL
;
3884 rr
->InFlightRData
= mDNSNULL
;
3887 if (rr
->state
== regState_DeregPending
)
3889 debugf("Received reply for deregister record %##s type %d", rr
->resrec
.name
->c
, rr
->resrec
.rrtype
);
3890 if (err
) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %d",
3891 rr
->resrec
.name
->c
, rr
->resrec
.rrtype
, err
);
3892 err
= mStatus_MemFree
;
3893 rr
->state
= regState_Unregistered
;
3896 if (rr
->state
== regState_DeregDeferred
)
3900 LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %d",
3901 rr
->resrec
.name
->c
, rr
->resrec
.rrtype
, err
);
3902 rr
->state
= regState_Unregistered
;
3904 debugf("Calling deferred deregistration of record %##s type %d", rr
->resrec
.name
->c
, rr
->resrec
.rrtype
);
3905 rr
->state
= regState_Registered
;
3906 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
3910 if (rr
->state
== regState_Pending
|| rr
->state
== regState_Refresh
)
3914 if (rr
->state
== regState_Refresh
) InvokeCallback
= mDNSfalse
;
3915 rr
->state
= regState_Registered
;
3919 if (rr
->uselease
&& err
== mStatus_UnknownErr
&& mDNSSameIPPort(rr
->UpdatePort
, UnicastDNSPort
))
3921 LogMsg("Re-trying update of record %##s without lease option", rr
->resrec
.name
->c
);
3922 rr
->uselease
= mDNSfalse
;
3923 SendRecordRegistration(m
, rr
);
3926 LogMsg("hndlRecordUpdateReply: Registration of record %##s type %d failed with error %d", rr
->resrec
.name
->c
, rr
->resrec
.rrtype
, err
);
3931 if (rr
->state
== regState_Unregistered
) // Should never happen
3933 LogMsg("hndlRecordUpdateReply rr->state == regState_Unregistered %s", ARDisplayString(m
, rr
));
3937 if (rr
->QueuedRData
&& rr
->state
== regState_Registered
)
3939 rr
->state
= regState_UpdatePending
;
3940 rr
->InFlightRData
= rr
->QueuedRData
;
3941 rr
->InFlightRDLen
= rr
->QueuedRDLen
;
3942 rr
->OrigRData
= rr
->resrec
.rdata
;
3943 rr
->OrigRDLen
= rr
->resrec
.rdlength
;
3944 rr
->QueuedRData
= mDNSNULL
;
3945 SendRecordRegistration(m
, rr
);
3949 if (InvokeCallback
&& rr
->RecordCallback
)
3951 mDNS_DropLockBeforeCallback();
3952 rr
->RecordCallback(m
, rr
, err
);
3953 mDNS_ReclaimLockAfterCallback();
3955 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
3956 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
3959 mDNSexport
void uDNS_ReceiveNATPMPPacket(mDNS
*m
, const mDNSInterfaceID InterfaceID
, mDNSu8
*pkt
, mDNSu16 len
)
3961 NATTraversalInfo
*ptr
;
3962 NATAddrReply
*AddrReply
= (NATAddrReply
*)pkt
;
3963 NATPortMapReply
*PortMapReply
= (NATPortMapReply
*)pkt
;
3964 mDNSu32 nat_elapsed
, our_elapsed
;
3966 // Minimum packet is vers (1) opcode (1) err (2) upseconds (4) = 8 bytes
3967 if (!AddrReply
->err
&& len
< 8) { LogMsg("NAT Traversal message too short (%d bytes)", len
); return; }
3968 if (AddrReply
->vers
!= NATMAP_VERS
) { LogMsg("Received NAT Traversal response with version %d (expected %d)", pkt
[0], NATMAP_VERS
); return; }
3970 // Read multi-byte numeric values (fields are identical in a NATPortMapReply)
3971 AddrReply
->err
= (mDNSu16
) ( (mDNSu16
)pkt
[2] << 8 | pkt
[3]);
3972 AddrReply
->upseconds
= (mDNSs32
) ((mDNSs32
)pkt
[4] << 24 | (mDNSs32
)pkt
[5] << 16 | (mDNSs32
)pkt
[6] << 8 | pkt
[7]);
3974 nat_elapsed
= AddrReply
->upseconds
- m
->LastNATupseconds
;
3975 our_elapsed
= (m
->timenow
- m
->LastNATReplyLocalTime
) / mDNSPlatformOneSecond
;
3976 debugf("uDNS_ReceiveNATPMPPacket %X upseconds %u nat_elapsed %d our_elapsed %d", AddrReply
->opcode
, AddrReply
->upseconds
, nat_elapsed
, our_elapsed
);
3978 // We compute a conservative estimate of how much the NAT gateways's clock should have advanced
3979 // 1. We subtract 12.5% from our own measured elapsed time, to allow for NAT gateways that have an inacurate clock that runs slowly
3980 // 2. We add a two-second safety margin to allow for rounding errors:
3981 // -- e.g. if NAT gateway sends a packet at t=2.00 seconds, then one at t=7.99, that's virtually 6 seconds,
3982 // but based on the values in the packet (2,7) the apparent difference is only 5 seconds
3983 // -- similarly, if we're slow handling packets and/or we have coarse clock granularity, we could over-estimate the true interval
3984 // (e.g. t=1.99 seconds rounded to 1, and t=8.01 rounded to 8, gives an apparent difference of 7 seconds)
3985 if (AddrReply
->upseconds
< m
->LastNATupseconds
|| nat_elapsed
+ 2 < our_elapsed
- our_elapsed
/8)
3986 { LogMsg("NAT gateway %#a rebooted", &m
->Router
); RecreateNATMappings(m
); }
3988 m
->LastNATupseconds
= AddrReply
->upseconds
;
3989 m
->LastNATReplyLocalTime
= m
->timenow
;
3990 #ifdef _LEGACY_NAT_TRAVERSAL_
3992 #endif // _LEGACY_NAT_TRAVERSAL_
3994 if (AddrReply
->opcode
== NATOp_AddrResponse
)
3996 #if APPLE_OSX_mDNSResponder
3997 static char msgbuf
[16];
3998 mDNS_snprintf(msgbuf
, sizeof(msgbuf
), "%d", AddrReply
->err
);
3999 mDNSASLLog((uuid_t
*)&m
->asl_uuid
, "natt.natpmp.AddressRequest", AddrReply
->err
? "failure" : "success", msgbuf
, "");
4001 if (!AddrReply
->err
&& len
< sizeof(NATAddrReply
)) { LogMsg("NAT Traversal AddrResponse message too short (%d bytes)", len
); return; }
4002 natTraversalHandleAddressReply(m
, AddrReply
->err
, AddrReply
->ExtAddr
);
4004 else if (AddrReply
->opcode
== NATOp_MapUDPResponse
|| AddrReply
->opcode
== NATOp_MapTCPResponse
)
4006 mDNSu8 Protocol
= AddrReply
->opcode
& 0x7F;
4007 #if APPLE_OSX_mDNSResponder
4008 static char msgbuf
[16];
4009 mDNS_snprintf(msgbuf
, sizeof(msgbuf
), "%s - %d", AddrReply
->opcode
== NATOp_MapUDPResponse
? "UDP" : "TCP", PortMapReply
->err
);
4010 mDNSASLLog((uuid_t
*)&m
->asl_uuid
, "natt.natpmp.PortMapRequest", PortMapReply
->err
? "failure" : "success", msgbuf
, "");
4012 if (!PortMapReply
->err
)
4014 if (len
< sizeof(NATPortMapReply
)) { LogMsg("NAT Traversal PortMapReply message too short (%d bytes)", len
); return; }
4015 PortMapReply
->NATRep_lease
= (mDNSu32
) ((mDNSu32
)pkt
[12] << 24 | (mDNSu32
)pkt
[13] << 16 | (mDNSu32
)pkt
[14] << 8 | pkt
[15]);
4018 // Since some NAT-PMP server implementations don't return the requested internal port in
4019 // the reply, we can't associate this reply with a particular NATTraversalInfo structure.
4020 // We globally keep track of the most recent error code for mappings.
4021 m
->LastNATMapResultCode
= PortMapReply
->err
;
4023 for (ptr
= m
->NATTraversals
; ptr
; ptr
=ptr
->next
)
4024 if (ptr
->Protocol
== Protocol
&& mDNSSameIPPort(ptr
->IntPort
, PortMapReply
->intport
))
4025 natTraversalHandlePortMapReply(m
, ptr
, InterfaceID
, PortMapReply
->err
, PortMapReply
->extport
, PortMapReply
->NATRep_lease
);
4027 else { LogMsg("Received NAT Traversal response with version unknown opcode 0x%X", AddrReply
->opcode
); return; }
4029 // Don't need an SSDP socket if we get a NAT-PMP packet
4030 if (m
->SSDPSocket
) { debugf("uDNS_ReceiveNATPMPPacket destroying SSDPSocket %p", &m
->SSDPSocket
); mDNSPlatformUDPClose(m
->SSDPSocket
); m
->SSDPSocket
= mDNSNULL
; }
4033 // <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
4034 // <rdar://problem/4288449> Add check to avoid crashing NAT gateways that have buggy DNS relay code
4036 // We know of bugs in home NAT gateways that cause them to crash if they receive certain DNS queries.
4037 // The DNS queries that make them crash are perfectly legal DNS queries, but even if they weren't,
4038 // the gateway shouldn't crash -- in today's world of viruses and network attacks, software has to
4039 // be written assuming that a malicious attacker could send them any packet, properly-formed or not.
4040 // Still, we don't want to be crashing people's home gateways, so we go out of our way to avoid
4041 // the queries that crash them.
4045 // 1. Any query where the name ends in ".in-addr.arpa." and the text before this is 32 or more bytes.
4046 // The query type does not need to be PTR -- the gateway will crash for any query type.
4047 // e.g. "ping long-name-crashes-the-buggy-router.in-addr.arpa" will crash one of these.
4049 // 2. Any query that results in a large response with the TC bit set.
4051 // 3. Any PTR query that doesn't begin with four decimal numbers.
4052 // These gateways appear to assume that the only possible PTR query is a reverse-mapping query
4053 // (e.g. "1.0.168.192.in-addr.arpa") and if they ever get a PTR query where the first four
4054 // labels are not all decimal numbers in the range 0-255, they handle that by crashing.
4055 // These gateways also ignore the remainder of the name following the four decimal numbers
4056 // -- whether or not it actually says in-addr.arpa, they just make up an answer anyway.
4058 // The challenge therefore is to craft a query that will discern whether the DNS server
4059 // is one of these buggy ones, without crashing it. Furthermore we don't want our test
4060 // queries making it all the way to the root name servers, putting extra load on those
4061 // name servers and giving Apple a bad reputation. To this end we send this query:
4062 // dig -t ptr 1.0.0.127.dnsbugtest.1.0.0.127.in-addr.arpa.
4064 // The text preceding the ".in-addr.arpa." is under 32 bytes, so it won't cause crash (1).
4065 // It will not yield a large response with the TC bit set, so it won't cause crash (2).
4066 // It starts with four decimal numbers, so it won't cause crash (3).
4067 // The name falls within the "1.0.0.127.in-addr.arpa." domain, the reverse-mapping name for the local
4068 // loopback address, and therefore the query will black-hole at the first properly-configured DNS server
4069 // it reaches, making it highly unlikely that this query will make it all the way to the root.
4071 // Finally, the correct response to this query is NXDOMAIN or a similar error, but the
4072 // gateways that ignore the remainder of the name following the four decimal numbers
4073 // give themselves away by actually returning a result for this nonsense query.
4075 mDNSlocal
const domainname
*DNSRelayTestQuestion
= (const domainname
*)
4076 "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\xa" "dnsbugtest"
4077 "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\x7" "in-addr" "\x4" "arpa";
4079 // See comments above for DNSRelayTestQuestion
4080 // If this is the kind of query that has the risk of crashing buggy DNS servers, we do a test question first
4081 mDNSlocal mDNSBool
NoTestQuery(DNSQuestion
*q
)
4084 mDNSu8
*p
= q
->qname
.c
;
4085 if (q
->AuthInfo
) return(mDNStrue
); // Don't need a test query for private queries sent directly to authoritative server over TLS/TCP
4086 if (q
->qtype
!= kDNSType_PTR
) return(mDNStrue
); // Don't need a test query for any non-PTR queries
4087 for (i
=0; i
<4; i
++) // If qname does not begin with num.num.num.num, can't skip the test query
4089 if (p
[0] < 1 || p
[0] > 3) return(mDNSfalse
);
4090 if ( p
[1] < '0' || p
[1] > '9' ) return(mDNSfalse
);
4091 if (p
[0] >= 2 && (p
[2] < '0' || p
[2] > '9')) return(mDNSfalse
);
4092 if (p
[0] >= 3 && (p
[3] < '0' || p
[3] > '9')) return(mDNSfalse
);
4095 // If remainder of qname is ".in-addr.arpa.", this is a vanilla reverse-mapping query and
4096 // we can safely do it without needing a test query first, otherwise we need the test query.
4097 return(SameDomainName((domainname
*)p
, (const domainname
*)"\x7" "in-addr" "\x4" "arpa"));
4100 // Returns mDNStrue if response was handled
4101 mDNSlocal mDNSBool
uDNS_ReceiveTestQuestionResponse(mDNS
*const m
, DNSMessage
*const msg
, const mDNSu8
*const end
,
4102 const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
)
4104 const mDNSu8
*ptr
= msg
->data
;
4109 // 1. Find out if this is an answer to one of our test questions
4110 if (msg
->h
.numQuestions
!= 1) return(mDNSfalse
);
4111 ptr
= getQuestion(msg
, ptr
, end
, mDNSInterface_Any
, &pktq
);
4112 if (!ptr
) return(mDNSfalse
);
4113 if (pktq
.qtype
!= kDNSType_PTR
|| pktq
.qclass
!= kDNSClass_IN
) return(mDNSfalse
);
4114 if (!SameDomainName(&pktq
.qname
, DNSRelayTestQuestion
)) return(mDNSfalse
);
4116 // 2. If the DNS relay gave us a positive response, then it's got buggy firmware
4117 // else, if the DNS relay gave us an error or no-answer response, it passed our test
4118 if ((msg
->h
.flags
.b
[1] & kDNSFlag1_RC_Mask
) == kDNSFlag1_RC_NoErr
&& msg
->h
.numAnswers
> 0)
4119 result
= DNSServer_Failed
;
4121 result
= DNSServer_Passed
;
4123 // 3. Find occurrences of this server in our list, and mark them appropriately
4124 for (s
= m
->DNSServers
; s
; s
= s
->next
)
4126 mDNSBool matchaddr
= (s
->teststate
!= result
&& mDNSSameAddress(srcaddr
, &s
->addr
) && mDNSSameIPPort(srcport
, s
->port
));
4127 mDNSBool matchid
= (s
->teststate
== DNSServer_Untested
&& mDNSSameOpaque16(msg
->h
.id
, s
->testid
));
4128 if (matchaddr
|| matchid
)
4131 s
->teststate
= result
;
4132 if (result
== DNSServer_Passed
)
4134 LogInfo("DNS Server %#a:%d (%#a:%d) %d passed%s",
4135 &s
->addr
, mDNSVal16(s
->port
), srcaddr
, mDNSVal16(srcport
), mDNSVal16(s
->testid
),
4136 matchaddr
? "" : " NOTE: Reply did not come from address to which query was sent");
4140 LogMsg("NOTE: Wide-Area Service Discovery disabled to avoid crashing defective DNS relay %#a:%d (%#a:%d) %d%s",
4141 &s
->addr
, mDNSVal16(s
->port
), srcaddr
, mDNSVal16(srcport
), mDNSVal16(s
->testid
),
4142 matchaddr
? "" : " NOTE: Reply did not come from address to which query was sent");
4145 // If this server has just changed state from DNSServer_Untested to DNSServer_Passed, then retrigger any waiting questions.
4146 // We use the NoTestQuery() test so that we only retrigger questions that were actually blocked waiting for this test to complete.
4147 if (result
== DNSServer_Passed
) // Unblock any questions that were waiting for this result
4148 for (q
= m
->Questions
; q
; q
=q
->next
)
4149 if (q
->qDNSServer
== s
&& !NoTestQuery(q
))
4151 q
->ThisQInterval
= INIT_UCAST_POLL_INTERVAL
/ QuestionIntervalStep
;
4152 q
->unansweredQueries
= 0;
4153 q
->LastQTime
= m
->timenow
- q
->ThisQInterval
;
4154 m
->NextScheduledQuery
= m
->timenow
;
4159 return(mDNStrue
); // Return mDNStrue to tell uDNS_ReceiveMsg it doesn't need to process this packet further
4162 // Called from mDNSCoreReceive with the lock held
4163 mDNSexport
void uDNS_ReceiveMsg(mDNS
*const m
, DNSMessage
*const msg
, const mDNSu8
*const end
, const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
)
4166 mStatus err
= mStatus_NoError
;
4168 mDNSu8 StdR
= kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
;
4169 mDNSu8 UpdateR
= kDNSFlag0_QR_Response
| kDNSFlag0_OP_Update
;
4170 mDNSu8 QR_OP
= (mDNSu8
)(msg
->h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
);
4171 mDNSu8 rcode
= (mDNSu8
)(msg
->h
.flags
.b
[1] & kDNSFlag1_RC_Mask
);
4173 (void)srcport
; // Unused
4175 debugf("uDNS_ReceiveMsg from %#-15a with "
4176 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
4178 msg
->h
.numQuestions
, msg
->h
.numQuestions
== 1 ? ", " : "s,",
4179 msg
->h
.numAnswers
, msg
->h
.numAnswers
== 1 ? ", " : "s,",
4180 msg
->h
.numAuthorities
, msg
->h
.numAuthorities
== 1 ? "y, " : "ies,",
4181 msg
->h
.numAdditionals
, msg
->h
.numAdditionals
== 1 ? "" : "s");
4185 //if (srcaddr && recvLLQResponse(m, msg, end, srcaddr, srcport)) return;
4186 if (uDNS_ReceiveTestQuestionResponse(m
, msg
, end
, srcaddr
, srcport
)) return;
4187 for (qptr
= m
->Questions
; qptr
; qptr
= qptr
->next
)
4188 if (msg
->h
.flags
.b
[0] & kDNSFlag0_TC
&& mDNSSameOpaque16(qptr
->TargetQID
, msg
->h
.id
) && m
->timenow
- qptr
->LastQTime
< RESPONSE_WINDOW
)
4190 if (!srcaddr
) LogMsg("uDNS_ReceiveMsg: TCP DNS response had TC bit set: ignoring");
4193 // There may be a race condition here, if the server decides to drop the connection just as we decide to reuse it
4194 // For now it should not be serious because our normal retry logic (as used to handle UDP packet loss)
4195 // should take care of it but later we may want to look at handling this case explicitly
4196 LogInfo("uDNS_ReceiveMsg: Using existing TCP connection for %##s (%s)", qptr
->qname
.c
, DNSTypeName(qptr
->qtype
));
4197 mDNS_DropLockBeforeCallback();
4198 tcpCallback(qptr
->tcp
->sock
, qptr
->tcp
, mDNStrue
, mStatus_NoError
);
4199 mDNS_ReclaimLockAfterCallback();
4201 else qptr
->tcp
= MakeTCPConn(m
, mDNSNULL
, mDNSNULL
, kTCPSocketFlags_Zero
, srcaddr
, srcport
, qptr
, mDNSNULL
, mDNSNULL
);
4205 if (QR_OP
== UpdateR
)
4207 mDNSu32 lease
= GetPktLease(m
, msg
, end
);
4208 mDNSs32 expire
= m
->timenow
+ (mDNSs32
)lease
* mDNSPlatformOneSecond
;
4210 //rcode = kDNSFlag1_RC_ServFail; // Simulate server failure (rcode 2)
4212 if (CurrentServiceRecordSet
)
4213 LogMsg("uDNS_ReceiveMsg ERROR CurrentServiceRecordSet already set");
4214 CurrentServiceRecordSet
= m
->ServiceRegistrations
;
4216 while (CurrentServiceRecordSet
)
4218 ServiceRecordSet
*sptr
= CurrentServiceRecordSet
;
4219 CurrentServiceRecordSet
= CurrentServiceRecordSet
->uDNS_next
;
4221 if (mDNSSameOpaque16(sptr
->id
, msg
->h
.id
))
4223 err
= checkUpdateResult(m
, sptr
->RR_SRV
.resrec
.name
, rcode
, msg
, end
);
4224 if (!err
&& sptr
->srs_uselease
&& lease
)
4225 if (sptr
->RR_SRV
.expire
- expire
>= 0 || sptr
->state
!= regState_UpdatePending
)
4226 sptr
->RR_SRV
.expire
= expire
;
4227 hndlServiceUpdateReply(m
, sptr
, err
);
4228 CurrentServiceRecordSet
= mDNSNULL
;
4233 if (m
->CurrentRecord
)
4234 LogMsg("uDNS_ReceiveMsg ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
4235 m
->CurrentRecord
= m
->ResourceRecords
;
4236 while (m
->CurrentRecord
)
4238 AuthRecord
*rptr
= m
->CurrentRecord
;
4239 m
->CurrentRecord
= m
->CurrentRecord
->next
;
4240 if (AuthRecord_uDNS(rptr
) && mDNSSameOpaque16(rptr
->updateid
, msg
->h
.id
))
4242 err
= checkUpdateResult(m
, rptr
->resrec
.name
, rcode
, msg
, end
);
4243 if (!err
&& rptr
->uselease
&& lease
)
4244 if (rptr
->expire
- expire
>= 0 || rptr
->state
!= regState_UpdatePending
)
4245 rptr
->expire
= expire
;
4246 hndlRecordUpdateReply(m
, rptr
, err
);
4247 m
->CurrentRecord
= mDNSNULL
;
4252 debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg
->h
.id
));
4255 // ***************************************************************************
4256 #if COMPILER_LIKES_PRAGMA_MARK
4257 #pragma mark - Query Routines
4260 mDNSexport
void sendLLQRefresh(mDNS
*m
, DNSQuestion
*q
)
4266 if ((q
->state
== LLQ_Established
&& q
->ntries
>= kLLQ_MAX_TRIES
) || q
->expire
- m
->timenow
< 0)
4268 LogMsg("Unable to refresh LLQ %##s (%s) - will retry in %d seconds", q
->qname
.c
, DNSTypeName(q
->qtype
), LLQ_POLL_INTERVAL
/ mDNSPlatformOneSecond
);
4269 StartLLQPolling(m
,q
);
4273 llq
.vers
= kLLQ_Vers
;
4274 llq
.llqOp
= kLLQOp_Refresh
;
4275 llq
.err
= q
->tcp
? GetLLQEventPort(m
, &q
->servAddr
) : LLQErr_NoError
; // If using TCP tell server what UDP port to send notifications to
4277 llq
.llqlease
= q
->ReqLease
;
4279 InitializeDNSMessage(&m
->omsg
.h
, q
->TargetQID
, uQueryFlags
);
4280 end
= putLLQ(&m
->omsg
, m
->omsg
.data
, q
, &llq
);
4281 if (!end
) { LogMsg("sendLLQRefresh: putLLQ failed %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
)); return; }
4283 // Note that we (conditionally) add HINFO and TSIG here, since the question might be going away,
4284 // so we may not be able to reference it (most importantly it's AuthInfo) when we actually send the message
4285 end
= putHINFO(m
, &m
->omsg
, end
, q
->AuthInfo
);
4286 if (!end
) { LogMsg("sendLLQRefresh: putHINFO failed %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
)); return; }
4290 DNSDigest_SignMessageHostByteOrder(&m
->omsg
, &end
, q
->AuthInfo
);
4291 if (!end
) { LogMsg("sendLLQRefresh: DNSDigest_SignMessage failed %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
)); return; }
4294 if (q
->AuthInfo
&& !q
->tcp
)
4296 LogInfo("sendLLQRefresh setting up new TLS session %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4297 q
->tcp
= MakeTCPConn(m
, &m
->omsg
, end
, kTCPSocketFlags_UseTLS
, &q
->servAddr
, q
->servPort
, q
, mDNSNULL
, mDNSNULL
);
4301 mStatus err
= mDNSSendDNSMessage(m
, &m
->omsg
, end
, mDNSInterface_Any
, q
->LocalSocket
, &q
->servAddr
, q
->servPort
, q
->tcp
? q
->tcp
->sock
: mDNSNULL
, mDNSNULL
);
4304 LogMsg("sendLLQRefresh: mDNSSendDNSMessage%s failed: %d", q
->tcp
? " (TCP)" : "", err
);
4305 if (q
->tcp
) { DisposeTCPConn(q
->tcp
); q
->tcp
= mDNSNULL
; }
4311 debugf("sendLLQRefresh ntries %d %##s (%s)", q
->ntries
, q
->qname
.c
, DNSTypeName(q
->qtype
));
4313 q
->LastQTime
= m
->timenow
;
4314 SetNextQueryTime(m
, q
);
4317 mDNSexport
void LLQGotZoneData(mDNS
*const m
, mStatus err
, const ZoneData
*zoneInfo
)
4319 DNSQuestion
*q
= (DNSQuestion
*)zoneInfo
->ZoneDataContext
;
4323 // If we get here it means that the GetZoneData operation has completed, and is is about to cancel
4324 // its question and free the ZoneData memory. We no longer need to hold onto our pointer (which
4325 // we use for cleaning up if our LLQ is cancelled *before* the GetZoneData operation has completes).
4327 q
->servAddr
= zeroAddr
;
4328 q
->servPort
= zeroIPPort
;
4330 if (!err
&& zoneInfo
&& !mDNSIPPortIsZero(zoneInfo
->Port
) && !mDNSAddressIsZero(&zoneInfo
->Addr
))
4332 q
->servAddr
= zoneInfo
->Addr
;
4333 q
->servPort
= zoneInfo
->Port
;
4334 q
->AuthInfo
= zoneInfo
->ZonePrivate
? GetAuthInfoForName_internal(m
, &q
->qname
) : mDNSNULL
;
4336 debugf("LLQGotZoneData %#a:%d", &q
->servAddr
, mDNSVal16(q
->servPort
));
4337 startLLQHandshake(m
, q
);
4341 StartLLQPolling(m
,q
);
4342 if (err
== mStatus_NoSuchNameErr
)
4344 // this actually failed, so mark it by setting address to all ones
4345 q
->servAddr
.type
= mDNSAddrType_IPv4
;
4346 q
->servAddr
.ip
.v4
= onesIPv4Addr
;
4353 // Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
4354 mDNSlocal
void PrivateQueryGotZoneData(mDNS
*const m
, mStatus err
, const ZoneData
*zoneInfo
)
4356 DNSQuestion
*q
= (DNSQuestion
*) zoneInfo
->ZoneDataContext
;
4358 LogInfo("PrivateQueryGotZoneData %##s (%s) err %d Zone %##s Private %d", q
->qname
.c
, DNSTypeName(q
->qtype
), err
, zoneInfo
->ZoneName
.c
, zoneInfo
->ZonePrivate
);
4360 // If we get here it means that the GetZoneData operation has completed, and is is about to cancel
4361 // its question and free the ZoneData memory. We no longer need to hold onto our pointer (which
4362 // we use for cleaning up if our LLQ is cancelled *before* the GetZoneData operation has completes).
4365 if (err
|| !zoneInfo
|| mDNSAddressIsZero(&zoneInfo
->Addr
) || mDNSIPPortIsZero(zoneInfo
->Port
))
4367 LogInfo("ERROR: PrivateQueryGotZoneData %##s (%s) invoked with error code %d %p %#a:%d",
4368 q
->qname
.c
, DNSTypeName(q
->qtype
), err
, zoneInfo
,
4369 zoneInfo
? &zoneInfo
->Addr
: mDNSNULL
,
4370 zoneInfo
? mDNSVal16(zoneInfo
->Port
) : 0);
4374 if (!zoneInfo
->ZonePrivate
)
4376 debugf("Private port lookup failed -- retrying without TLS -- %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4377 q
->AuthInfo
= mDNSNULL
; // Clear AuthInfo so we try again non-private
4378 q
->ThisQInterval
= InitialQuestionInterval
;
4379 q
->LastQTime
= m
->timenow
- q
->ThisQInterval
;
4381 SetNextQueryTime(m
, q
);
4384 // Next call to uDNS_CheckCurrentQuestion() will do this as a non-private query
4389 LogMsg("ERROR: PrivateQueryGotZoneData: cannot find credentials for q %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4393 q
->TargetQID
= mDNS_NewMessageID(m
);
4394 if (q
->tcp
) DisposeTCPConn(q
->tcp
);
4395 q
->tcp
= MakeTCPConn(m
, mDNSNULL
, mDNSNULL
, kTCPSocketFlags_UseTLS
, &zoneInfo
->Addr
, zoneInfo
->Port
, q
, mDNSNULL
, mDNSNULL
);
4398 // ***************************************************************************
4399 #if COMPILER_LIKES_PRAGMA_MARK
4400 #pragma mark - Dynamic Updates
4403 // Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
4404 mDNSexport
void RecordRegistrationGotZoneData(mDNS
*const m
, mStatus err
, const ZoneData
*zoneData
)
4406 AuthRecord
*newRR
= (AuthRecord
*)zoneData
->ZoneDataContext
;
4410 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
)
4411 LogMsg("RecordRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
4413 newRR
->nta
= mDNSNULL
;
4415 // Start off assuming we're going to use a lease
4416 // 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
4417 newRR
->uselease
= mDNStrue
;
4419 // make sure record is still in list (!!!)
4420 for (ptr
= m
->ResourceRecords
; ptr
; ptr
= ptr
->next
) if (ptr
== newRR
) break;
4421 if (!ptr
) { LogMsg("RecordRegistrationGotZoneData - RR no longer in list. Discarding."); return; }
4423 // check error/result
4426 if (err
!= mStatus_NoSuchNameErr
) LogMsg("RecordRegistrationGotZoneData: error %d", err
);
4430 if (!zoneData
) { LogMsg("ERROR: RecordRegistrationGotZoneData invoked with NULL result and no error"); return; }
4432 if (newRR
->resrec
.rrclass
!= zoneData
->ZoneClass
)
4434 LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)", newRR
->resrec
.rrclass
, zoneData
->ZoneClass
);
4438 // Don't try to do updates to the root name server.
4439 // We might be tempted also to block updates to any single-label name server (e.g. com, edu, net, etc.) but some
4440 // organizations use their own private pseudo-TLD, like ".home", etc, and we don't want to block that.
4441 if (zoneData
->ZoneName
.c
[0] == 0)
4443 LogInfo("RecordRegistrationGotZoneData: No name server found claiming responsibility for \"%##s\"!", newRR
->resrec
.name
->c
);
4447 // Store discovered zone data
4448 c1
= CountLabels(newRR
->resrec
.name
);
4449 c2
= CountLabels(&zoneData
->ZoneName
);
4452 LogMsg("RecordRegistrationGotZoneData: Zone \"%##s\" is longer than \"%##s\"", zoneData
->ZoneName
.c
, newRR
->resrec
.name
->c
);
4455 newRR
->zone
= SkipLeadingLabels(newRR
->resrec
.name
, c1
-c2
);
4456 if (!SameDomainName(newRR
->zone
, &zoneData
->ZoneName
))
4458 LogMsg("RecordRegistrationGotZoneData: Zone \"%##s\" does not match \"%##s\" for \"%##s\"", newRR
->zone
->c
, zoneData
->ZoneName
.c
, newRR
->resrec
.name
->c
);
4461 newRR
->UpdateServer
= zoneData
->Addr
;
4462 newRR
->UpdatePort
= zoneData
->Port
;
4463 newRR
->Private
= zoneData
->ZonePrivate
;
4464 debugf("RecordRegistrationGotZoneData: Set newRR->UpdateServer %##s %##s to %#a:%d",
4465 newRR
->resrec
.name
->c
, zoneData
->ZoneName
.c
, &newRR
->UpdateServer
, mDNSVal16(newRR
->UpdatePort
));
4467 if (mDNSIPPortIsZero(zoneData
->Port
) || mDNSAddressIsZero(&zoneData
->Addr
))
4469 LogInfo("RecordRegistrationGotZoneData: No _dns-update._udp service found for \"%##s\"!", newRR
->resrec
.name
->c
);
4473 newRR
->ThisAPInterval
= 5 * mDNSPlatformOneSecond
; // After doubling, first retry will happen after ten seconds
4475 mDNS_Lock(m
); // SendRecordRegistration expects to be called with the lock held
4476 SendRecordRegistration(m
, newRR
);
4480 mDNSlocal
void SendRecordDeregistration(mDNS
*m
, AuthRecord
*rr
)
4482 mDNSu8
*ptr
= m
->omsg
.data
;
4483 mDNSu8
*end
= (mDNSu8
*)&m
->omsg
+ sizeof(DNSMessage
);
4485 if (mDNSIPv4AddressIsZero(rr
->UpdateServer
.ip
.v4
)) // Don't know our UpdateServer yet
4487 rr
->LastAPTime
= m
->timenow
;
4488 if (rr
->ThisAPInterval
< mDNSPlatformOneSecond
* 5)
4489 rr
->ThisAPInterval
= mDNSPlatformOneSecond
* 5;
4493 InitializeDNSMessage(&m
->omsg
.h
, rr
->updateid
, UpdateReqFlags
);
4495 ptr
= putZone(&m
->omsg
, ptr
, end
, rr
->zone
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
4496 if (ptr
) ptr
= putDeletionRecord(&m
->omsg
, ptr
, &rr
->resrec
);
4499 LogMsg("SendRecordDeregistration Error: could not contruct deregistration packet for %s", ARDisplayString(m
, rr
));
4500 if (rr
->state
== regState_DeregPending
) CompleteDeregistration(m
, rr
);
4504 rr
->expire
= 0; // Indicate that we have no active registration any more
4507 LogInfo("SendRecordDeregistration TCP %p %s", rr
->tcp
, ARDisplayString(m
, rr
));
4508 if (rr
->tcp
) LogInfo("SendRecordDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m
, rr
));
4509 if (rr
->tcp
) DisposeTCPConn(rr
->tcp
);
4510 rr
->tcp
= MakeTCPConn(m
, &m
->omsg
, ptr
, kTCPSocketFlags_UseTLS
, &rr
->UpdateServer
, rr
->UpdatePort
, mDNSNULL
, mDNSNULL
, rr
);
4511 if (!rr
->tcp
) rr
->ThisAPInterval
= mDNSPlatformOneSecond
* 5; // If failed to make TCP connection, try again in ten seconds (5*2)
4512 else if (rr
->ThisAPInterval
< mDNSPlatformOneSecond
* 30) rr
->ThisAPInterval
= mDNSPlatformOneSecond
* 30;
4513 SetRecordRetry(m
, rr
, mStatus_NoError
);
4517 mStatus err
= mDNSSendDNSMessage(m
, &m
->omsg
, ptr
, mDNSInterface_Any
, mDNSNULL
, &rr
->UpdateServer
, rr
->UpdatePort
, mDNSNULL
, GetAuthInfoForName_internal(m
, rr
->resrec
.name
));
4518 if (err
) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %d", err
);
4519 if (rr
->state
== regState_DeregPending
) CompleteDeregistration(m
, rr
); // Don't touch rr after this
4524 mDNSexport mStatus
uDNS_DeregisterRecord(mDNS
*const m
, AuthRecord
*const rr
)
4528 case regState_NATMap
: LogMsg("regState_NATMap %##s type %s", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
)); return mStatus_NoError
;
4529 case regState_ExtraQueued
: rr
->state
= regState_Unregistered
; break;
4530 case regState_Refresh
:
4531 case regState_Pending
:
4532 case regState_UpdatePending
:
4533 case regState_FetchingZoneData
:
4534 case regState_Registered
: break;
4535 case regState_DeregPending
: break;
4536 case regState_DeregDeferred
: LogMsg("regState_DeregDeferred %##s type %s", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
)); return mStatus_NoError
;
4537 case regState_Unregistered
: LogMsg("regState_Unregistered %##s type %s", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
)); return mStatus_NoError
;
4538 case regState_NATError
: LogMsg("regState_NATError %##s type %s", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
)); return mStatus_NoError
;
4539 case regState_NoTarget
: LogMsg("regState_NoTarget %##s type %s", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
)); return mStatus_NoError
;
4540 default: LogMsg("uDNS_DeregisterRecord: State %d for %##s type %s", rr
->state
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
)); return mStatus_NoError
;
4543 if (rr
->state
!= regState_Unregistered
) { rr
->state
= regState_DeregPending
; SendRecordDeregistration(m
, rr
); }
4544 return mStatus_NoError
;
4547 // Called with lock held
4548 mDNSexport mStatus
uDNS_DeregisterService(mDNS
*const m
, ServiceRecordSet
*srs
)
4550 char *errmsg
= "Unknown State";
4552 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
4553 LogMsg("uDNS_DeregisterService: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
4555 // don't re-register with a new target following deregistration
4556 srs
->SRVChanged
= srs
->SRVUpdateDeferred
= mDNSfalse
;
4558 if (srs
->srs_nta
) { CancelGetZoneData(m
, srs
->srs_nta
); srs
->srs_nta
= mDNSNULL
; }
4560 if (srs
->NATinfo
.clientContext
)
4562 mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
4563 srs
->NATinfo
.clientContext
= mDNSNULL
;
4568 case regState_Unregistered
:
4569 debugf("uDNS_DeregisterService - service %##s not registered", srs
->RR_SRV
.resrec
.name
->c
);
4570 return mStatus_BadReferenceErr
;
4571 case regState_DeregPending
:
4572 case regState_DeregDeferred
:
4573 debugf("Double deregistration of service %##s", srs
->RR_SRV
.resrec
.name
->c
);
4574 return mStatus_NoError
;
4575 case regState_NATError
: // not registered
4576 case regState_NATMap
: // not registered
4577 case regState_NoTarget
: // not registered
4579 srs
->state
= regState_Unregistered
;
4580 mDNS_DropLockBeforeCallback();
4581 srs
->ServiceCallback(m
, srs
, mStatus_MemFree
);
4582 mDNS_ReclaimLockAfterCallback();
4583 return mStatus_NoError
;
4584 case regState_Pending
:
4585 case regState_Refresh
:
4586 case regState_UpdatePending
:
4587 case regState_FetchingZoneData
:
4588 case regState_Registered
:
4589 srs
->state
= regState_DeregPending
;
4590 SendServiceDeregistration(m
, srs
);
4591 return mStatus_NoError
;
4592 case regState_ExtraQueued
: // only for record registrations
4593 errmsg
= "bad state (regState_ExtraQueued)";
4595 default: LogMsg("uDNS_DeregisterService: Unknown state %d for %##s", srs
->state
, srs
->RR_SRV
.resrec
.name
->c
);
4599 LogMsg("Error, uDNS_DeregisterService: %s", errmsg
);
4600 return mStatus_BadReferenceErr
;
4603 mDNSexport mStatus
uDNS_UpdateRecord(mDNS
*m
, AuthRecord
*rr
)
4605 ServiceRecordSet
*parent
= mDNSNULL
;
4607 regState_t
*stateptr
= mDNSNULL
;
4609 // find the record in registered service list
4610 for (parent
= m
->ServiceRegistrations
; parent
; parent
= parent
->uDNS_next
)
4611 if (&parent
->RR_TXT
== rr
) { stateptr
= &parent
->state
; break; }
4615 // record not part of a service - check individual record registrations
4616 for (rptr
= m
->ResourceRecords
; rptr
; rptr
= rptr
->next
)
4617 if (rptr
== rr
) { stateptr
= &rr
->state
; break; }
4618 if (!rptr
) goto unreg_error
;
4623 case regState_DeregPending
:
4624 case regState_DeregDeferred
:
4625 case regState_Unregistered
:
4626 // not actively registered
4629 case regState_FetchingZoneData
:
4630 case regState_NATMap
:
4631 case regState_ExtraQueued
:
4632 case regState_NoTarget
:
4633 // change rdata directly since it hasn't been sent yet
4634 if (rr
->UpdateCallback
) rr
->UpdateCallback(m
, rr
, rr
->resrec
.rdata
);
4635 SetNewRData(&rr
->resrec
, rr
->NewRData
, rr
->newrdlength
);
4636 rr
->NewRData
= mDNSNULL
;
4637 return mStatus_NoError
;
4639 case regState_Pending
:
4640 case regState_Refresh
:
4641 case regState_UpdatePending
:
4642 // registration in-flight. queue rdata and return
4643 if (rr
->QueuedRData
&& rr
->UpdateCallback
)
4644 // if unsent rdata is already queued, free it before we replace it
4645 rr
->UpdateCallback(m
, rr
, rr
->QueuedRData
);
4646 rr
->QueuedRData
= rr
->NewRData
;
4647 rr
->QueuedRDLen
= rr
->newrdlength
;
4648 rr
->NewRData
= mDNSNULL
;
4649 return mStatus_NoError
;
4651 case regState_Registered
:
4652 rr
->OrigRData
= rr
->resrec
.rdata
;
4653 rr
->OrigRDLen
= rr
->resrec
.rdlength
;
4654 rr
->InFlightRData
= rr
->NewRData
;
4655 rr
->InFlightRDLen
= rr
->newrdlength
;
4656 rr
->NewRData
= mDNSNULL
;
4657 *stateptr
= regState_UpdatePending
;
4658 if (parent
) SendServiceRegistration(m
, parent
);
4659 else SendRecordRegistration(m
, rr
);
4660 return mStatus_NoError
;
4662 case regState_NATError
:
4663 LogMsg("ERROR: uDNS_UpdateRecord called for record %##s with bad state regState_NATError", rr
->resrec
.name
->c
);
4664 return mStatus_UnknownErr
; // states for service records only
4666 default: LogMsg("uDNS_UpdateRecord: Unknown state %d for %##s", *stateptr
, rr
->resrec
.name
->c
);
4670 LogMsg("Requested update of record %##s type %d, part of service not currently registered",
4671 rr
->resrec
.name
->c
, rr
->resrec
.rrtype
);
4672 return mStatus_Invalid
;
4675 // ***************************************************************************
4676 #if COMPILER_LIKES_PRAGMA_MARK
4677 #pragma mark - Periodic Execution Routines
4680 // The question to be checked is not passed in as an explicit parameter;
4681 // instead it is implicit that the question to be checked is m->CurrentQuestion.
4682 mDNSexport
void uDNS_CheckCurrentQuestion(mDNS
*const m
)
4684 DNSQuestion
*q
= m
->CurrentQuestion
;
4685 mDNSs32 sendtime
= q
->LastQTime
+ q
->ThisQInterval
;
4686 // Don't allow sendtime to be earlier than SuppressStdPort53Queries
4687 if (!q
->LongLived
&& m
->SuppressStdPort53Queries
&& sendtime
- m
->SuppressStdPort53Queries
< 0)
4688 sendtime
= m
->SuppressStdPort53Queries
;
4689 if (m
->timenow
- sendtime
< 0) return;
4695 case LLQ_InitialRequest
: startLLQHandshake(m
, q
); break;
4696 case LLQ_SecondaryRequest
: sendChallengeResponse(m
, q
, mDNSNULL
); break;
4697 case LLQ_Established
: sendLLQRefresh(m
, q
); break;
4698 case LLQ_Poll
: break; // Do nothing (handled below)
4702 // We repeat the check above (rather than just making this the "else" case) because startLLQHandshake can change q->state to LLQ_Poll
4703 if (!(q
->LongLived
&& q
->state
!= LLQ_Poll
))
4705 if (q
->unansweredQueries
>= MAX_UCAST_UNANSWERED_QUERIES
)
4707 DNSServer
*orig
= q
->qDNSServer
;
4708 if (orig
) LogInfo("Sent %d unanswered queries for %##s (%s) to %#a:%d (%##s)", q
->unansweredQueries
, q
->qname
.c
, DNSTypeName(q
->qtype
), &orig
->addr
, mDNSVal16(orig
->port
), orig
->domain
.c
);
4710 PushDNSServerToEnd(m
, q
);
4711 q
->unansweredQueries
= 0;
4714 if (q
->qDNSServer
&& q
->qDNSServer
->teststate
!= DNSServer_Disabled
)
4716 mDNSu8
*end
= m
->omsg
.data
;
4717 mStatus err
= mStatus_NoError
;
4718 mDNSBool
private = mDNSfalse
;
4720 InitializeDNSMessage(&m
->omsg
.h
, q
->TargetQID
, uQueryFlags
);
4722 if (q
->qDNSServer
->teststate
!= DNSServer_Untested
|| NoTestQuery(q
))
4724 end
= putQuestion(&m
->omsg
, m
->omsg
.data
, m
->omsg
.data
+ AbsoluteMaxDNSMessageData
, &q
->qname
, q
->qtype
, q
->qclass
);
4725 private = (q
->AuthInfo
&& q
->AuthInfo
->AutoTunnel
);
4727 else if (m
->timenow
- q
->qDNSServer
->lasttest
>= INIT_UCAST_POLL_INTERVAL
) // Make sure at least three seconds has elapsed since last test query
4729 LogInfo("Sending DNS test query to %#a:%d", &q
->qDNSServer
->addr
, mDNSVal16(q
->qDNSServer
->port
));
4730 q
->ThisQInterval
= INIT_UCAST_POLL_INTERVAL
/ QuestionIntervalStep
;
4731 q
->qDNSServer
->lasttest
= m
->timenow
;
4732 end
= putQuestion(&m
->omsg
, m
->omsg
.data
, m
->omsg
.data
+ AbsoluteMaxDNSMessageData
, DNSRelayTestQuestion
, kDNSType_PTR
, kDNSClass_IN
);
4733 q
->qDNSServer
->testid
= m
->omsg
.h
.id
;
4736 if (end
> m
->omsg
.data
&& (q
->qDNSServer
->teststate
!= DNSServer_Failed
|| NoTestQuery(q
)))
4738 //LogMsg("uDNS_CheckCurrentQuestion %p %d %p %##s (%s)", q, sendtime - m->timenow, private, q->qname.c, DNSTypeName(q->qtype));
4741 if (q
->nta
) CancelGetZoneData(m
, q
->nta
);
4742 q
->nta
= StartGetZoneData(m
, &q
->qname
, q
->LongLived
? ZoneServiceLLQ
: ZoneServiceQuery
, PrivateQueryGotZoneData
, q
);
4743 q
->ThisQInterval
= (LLQ_POLL_INTERVAL
+ mDNSRandom(LLQ_POLL_INTERVAL
/10)) / QuestionIntervalStep
;
4747 if (!q
->LocalSocket
) q
->LocalSocket
= mDNSPlatformUDPSocket(m
, zeroIPPort
);
4748 if (!q
->LocalSocket
) err
= mStatus_NoMemoryErr
; // If failed to make socket (should be very rare), we'll try again next time
4749 else err
= mDNSSendDNSMessage(m
, &m
->omsg
, end
, q
->qDNSServer
->interface
, q
->LocalSocket
, &q
->qDNSServer
->addr
, q
->qDNSServer
->port
, mDNSNULL
, mDNSNULL
);
4750 m
->SuppressStdPort53Queries
= NonZeroTime(m
->timenow
+ (mDNSPlatformOneSecond
+99)/100);
4754 if (err
) debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %d", err
); // surpress syslog messages if we have no network
4757 q
->ThisQInterval
= q
->ThisQInterval
* QuestionIntervalStep
; // Only increase interval if send succeeded
4758 q
->unansweredQueries
++;
4759 if (q
->ThisQInterval
> MAX_UCAST_POLL_INTERVAL
)
4760 q
->ThisQInterval
= MAX_UCAST_POLL_INTERVAL
;
4761 debugf("Increased ThisQInterval to %d for %##s (%s)", q
->ThisQInterval
, q
->qname
.c
, DNSTypeName(q
->qtype
));
4763 q
->LastQTime
= m
->timenow
;
4764 SetNextQueryTime(m
, q
);
4768 // If we have no server for this query, or the only server is a disabled one, then we deliver
4769 // a transient failure indication to the client. This is important for things like iPhone
4770 // where we want to return timely feedback to the user when no network is available.
4771 // After calling MakeNegativeCacheRecord() we store the resulting record in the
4772 // cache so that it will be visible to other clients asking the same question.
4773 // (When we have a group of identical questions, only the active representative of the group gets
4774 // passed to uDNS_CheckCurrentQuestion -- we only want one set of query packets hitting the wire --
4775 // but we want *all* of the questions to get answer callbacks.)
4778 const mDNSu32 slot
= HashSlot(&q
->qname
);
4779 CacheGroup
*const cg
= CacheGroupForName(m
, slot
, q
->qnamehash
, &q
->qname
);
4781 for (rr
= cg
->members
; rr
; rr
=rr
->next
)
4782 if (SameNameRecordAnswersQuestion(&rr
->resrec
, q
)) mDNS_PurgeCacheResourceRecord(m
, rr
);
4784 if (!q
->qDNSServer
) debugf("uDNS_CheckCurrentQuestion no DNS server for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4785 else LogMsg("uDNS_CheckCurrentQuestion DNS server %#a:%d for %##s is disabled", &q
->qDNSServer
->addr
, mDNSVal16(q
->qDNSServer
->port
), q
->qname
.c
);
4787 MakeNegativeCacheRecord(m
, &m
->rec
.r
, &q
->qname
, q
->qnamehash
, q
->qtype
, q
->qclass
, 60, mDNSInterface_Any
);
4788 // Inactivate this question until the next change of DNS servers (do this before AnswerCurrentQuestionWithResourceRecord)
4789 q
->ThisQInterval
= 0;
4790 q
->unansweredQueries
= 0;
4791 CreateNewCacheEntry(m
, slot
, cg
);
4792 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
4793 // MUST NOT touch m->CurrentQuestion (or q) after this -- client callback could have deleted it
4798 mDNSlocal
void CheckNATMappings(mDNS
*m
)
4800 mStatus err
= mStatus_NoError
;
4801 mDNSBool rfc1918
= mDNSv4AddrIsRFC1918(&m
->AdvertisedV4
.ip
.v4
);
4802 mDNSBool HaveRoutable
= !rfc1918
&& !mDNSIPv4AddressIsZero(m
->AdvertisedV4
.ip
.v4
);
4803 m
->NextScheduledNATOp
= m
->timenow
+ 0x3FFFFFFF;
4805 if (HaveRoutable
) m
->ExternalAddress
= m
->AdvertisedV4
.ip
.v4
;
4807 if (m
->NATTraversals
&& rfc1918
) // Do we need to open NAT-PMP socket to receive multicast announcements from router?
4809 if (m
->NATMcastRecvskt
== mDNSNULL
) // If we are behind a NAT and the socket hasn't been opened yet, open it
4811 // we need to log a message if we can't get our socket, but only the first time (after success)
4812 static mDNSBool needLog
= mDNStrue
;
4813 m
->NATMcastRecvskt
= mDNSPlatformUDPSocket(m
, NATPMPAnnouncementPort
);
4814 if (!m
->NATMcastRecvskt
)
4818 LogMsg("CheckNATMappings: Failed to allocate port 5350 UDP multicast socket for NAT-PMP announcements");
4819 needLog
= mDNSfalse
;
4826 else // else, we don't want to listen for announcements, so close them if they're open
4828 if (m
->NATMcastRecvskt
) { mDNSPlatformUDPClose(m
->NATMcastRecvskt
); m
->NATMcastRecvskt
= mDNSNULL
; }
4829 if (m
->SSDPSocket
) { debugf("CheckNATMappings destroying SSDPSocket %p", &m
->SSDPSocket
); mDNSPlatformUDPClose(m
->SSDPSocket
); m
->SSDPSocket
= mDNSNULL
; }
4832 if (m
->NATTraversals
)
4834 if (m
->timenow
- m
->retryGetAddr
>= 0)
4836 err
= uDNS_SendNATMsg(m
, mDNSNULL
); // Will also do UPnP discovery for us, if necessary
4839 if (m
->retryIntervalGetAddr
< NATMAP_INIT_RETRY
) m
->retryIntervalGetAddr
= NATMAP_INIT_RETRY
;
4840 else if (m
->retryIntervalGetAddr
< NATMAP_MAX_RETRY_INTERVAL
/ 2) m
->retryIntervalGetAddr
*= 2;
4841 else m
->retryIntervalGetAddr
= NATMAP_MAX_RETRY_INTERVAL
;
4843 // Always update m->retryGetAddr, even if we fail to send the packet. Otherwise in cases where we can't send the packet
4844 // (like when we have no active interfaces) we'll spin in an infinite loop repeatedly failing to send the packet
4845 m
->retryGetAddr
= m
->timenow
+ m
->retryIntervalGetAddr
;
4847 // Even when we didn't send the GetAddr packet, still need to make sure NextScheduledNATOp is set correctly
4848 if (m
->NextScheduledNATOp
- m
->retryGetAddr
> 0)
4849 m
->NextScheduledNATOp
= m
->retryGetAddr
;
4852 if (m
->CurrentNATTraversal
) LogMsg("WARNING m->CurrentNATTraversal already in use");
4853 m
->CurrentNATTraversal
= m
->NATTraversals
;
4855 while (m
->CurrentNATTraversal
)
4857 NATTraversalInfo
*cur
= m
->CurrentNATTraversal
;
4858 m
->CurrentNATTraversal
= m
->CurrentNATTraversal
->next
;
4860 if (HaveRoutable
) // If not RFC 1918 address, our own address and port are effectively our external address and port
4862 cur
->ExpiryTime
= 0;
4863 cur
->NewResult
= mStatus_NoError
;
4865 else if (cur
->Protocol
) // Check if it's time to send port mapping packets
4867 if (m
->timenow
- cur
->retryPortMap
>= 0) // Time to do something with this mapping
4869 if (cur
->ExpiryTime
&& cur
->ExpiryTime
- m
->timenow
< 0) // Mapping has expired
4871 cur
->ExpiryTime
= 0;
4872 cur
->retryInterval
= NATMAP_INIT_RETRY
;
4875 //LogMsg("uDNS_SendNATMsg");
4876 err
= uDNS_SendNATMsg(m
, cur
);
4878 if (cur
->ExpiryTime
) // If have active mapping then set next renewal time halfway to expiry
4879 NATSetNextRenewalTime(m
, cur
);
4880 else // else no mapping; use exponential backoff sequence
4882 if (cur
->retryInterval
< NATMAP_INIT_RETRY
) cur
->retryInterval
= NATMAP_INIT_RETRY
;
4883 else if (cur
->retryInterval
< NATMAP_MAX_RETRY_INTERVAL
/ 2) cur
->retryInterval
*= 2;
4884 else cur
->retryInterval
= NATMAP_MAX_RETRY_INTERVAL
;
4885 cur
->retryPortMap
= m
->timenow
+ cur
->retryInterval
;
4889 if (m
->NextScheduledNATOp
- cur
->retryPortMap
> 0)
4890 m
->NextScheduledNATOp
= cur
->retryPortMap
;
4893 // Notify the client if necessary. We invoke the callback if:
4894 // (1) we have an ExternalAddress, or we've tried and failed a couple of times to discover it
4895 // 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
4896 // and (3) we have new data to give the client that's changed since the last callback
4897 if (!mDNSIPv4AddressIsZero(m
->ExternalAddress
) || m
->retryIntervalGetAddr
> NATMAP_INIT_RETRY
* 8)
4899 const mStatus EffectiveResult
= cur
->NewResult
? cur
->NewResult
: mDNSv4AddrIsRFC1918(&m
->ExternalAddress
) ? mStatus_DoubleNAT
: mStatus_NoError
;
4900 const mDNSIPPort ExternalPort
= HaveRoutable
? cur
->IntPort
:
4901 !mDNSIPv4AddressIsZero(m
->ExternalAddress
) && cur
->ExpiryTime
? cur
->RequestedPort
: zeroIPPort
;
4902 if (!cur
->Protocol
|| HaveRoutable
|| cur
->ExpiryTime
|| cur
->retryInterval
> NATMAP_INIT_RETRY
* 8)
4903 if (!mDNSSameIPv4Address(cur
->ExternalAddress
, m
->ExternalAddress
) ||
4904 !mDNSSameIPPort (cur
->ExternalPort
, ExternalPort
) ||
4905 cur
->Result
!= EffectiveResult
)
4907 //LogMsg("NAT callback %d %d %d", cur->Protocol, cur->ExpiryTime, cur->retryInterval);
4908 if (cur
->Protocol
&& mDNSIPPortIsZero(ExternalPort
) && !mDNSIPv4AddressIsZero(m
->Router
.ip
.v4
))
4910 if (!EffectiveResult
)
4911 LogInfo("Failed to obtain NAT port mapping %p from router %#a external address %.4a internal port %5d interval %d error %d",
4912 cur
, &m
->Router
, &m
->ExternalAddress
, mDNSVal16(cur
->IntPort
), cur
->retryInterval
, EffectiveResult
);
4914 LogMsg("Failed to obtain NAT port mapping %p from router %#a external address %.4a internal port %5d interval %d error %d",
4915 cur
, &m
->Router
, &m
->ExternalAddress
, mDNSVal16(cur
->IntPort
), cur
->retryInterval
, EffectiveResult
);
4918 cur
->ExternalAddress
= m
->ExternalAddress
;
4919 cur
->ExternalPort
= ExternalPort
;
4920 cur
->Lifetime
= cur
->ExpiryTime
&& !mDNSIPPortIsZero(ExternalPort
) ?
4921 (cur
->ExpiryTime
- m
->timenow
+ mDNSPlatformOneSecond
/2) / mDNSPlatformOneSecond
: 0;
4922 cur
->Result
= EffectiveResult
;
4923 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
4924 if (cur
->clientCallback
)
4925 cur
->clientCallback(m
, cur
);
4926 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
4927 // MUST NOT touch cur after invoking the callback
4933 mDNSlocal mDNSs32
CheckRecordRegistrations(mDNS
*m
)
4936 mDNSs32 nextevent
= m
->timenow
+ 0x3FFFFFFF;
4938 for (rr
= m
->ResourceRecords
; rr
; rr
= rr
->next
)
4940 if (rr
->state
== regState_FetchingZoneData
||
4941 rr
->state
== regState_Pending
|| rr
->state
== regState_DeregPending
|| rr
->state
== regState_UpdatePending
||
4942 rr
->state
== regState_DeregDeferred
|| rr
->state
== regState_Refresh
|| rr
->state
== regState_Registered
)
4944 if (rr
->LastAPTime
+ rr
->ThisAPInterval
- m
->timenow
< 0)
4946 if (rr
->tcp
) { DisposeTCPConn(rr
->tcp
); rr
->tcp
= mDNSNULL
; }
4947 if (rr
->state
== regState_FetchingZoneData
)
4949 if (rr
->nta
) CancelGetZoneData(m
, rr
->nta
);
4950 rr
->nta
= StartGetZoneData(m
, rr
->resrec
.name
, ZoneServiceUpdate
, RecordRegistrationGotZoneData
, rr
);
4951 SetRecordRetry(m
, rr
, mStatus_NoError
);
4953 else if (rr
->state
== regState_DeregPending
) SendRecordDeregistration(m
, rr
);
4954 else SendRecordRegistration(m
, rr
);
4956 if (nextevent
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) > 0)
4957 nextevent
= (rr
->LastAPTime
+ rr
->ThisAPInterval
);
4963 mDNSlocal mDNSs32
CheckServiceRegistrations(mDNS
*m
)
4965 mDNSs32 nextevent
= m
->timenow
+ 0x3FFFFFFF;
4967 if (CurrentServiceRecordSet
)
4968 LogMsg("CheckServiceRegistrations ERROR CurrentServiceRecordSet already set");
4969 CurrentServiceRecordSet
= m
->ServiceRegistrations
;
4971 // Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery
4972 while (CurrentServiceRecordSet
)
4974 ServiceRecordSet
*srs
= CurrentServiceRecordSet
;
4975 CurrentServiceRecordSet
= CurrentServiceRecordSet
->uDNS_next
;
4976 if (srs
->state
== regState_FetchingZoneData
||
4977 srs
->state
== regState_Pending
|| srs
->state
== regState_DeregPending
|| srs
->state
== regState_DeregDeferred
||
4978 srs
->state
== regState_Refresh
|| srs
->state
== regState_UpdatePending
|| srs
->state
== regState_Registered
)
4980 if (srs
->RR_SRV
.LastAPTime
+ srs
->RR_SRV
.ThisAPInterval
- m
->timenow
<= 0)
4982 if (srs
->tcp
) { DisposeTCPConn(srs
->tcp
); srs
->tcp
= mDNSNULL
; }
4983 if (srs
->state
== regState_FetchingZoneData
)
4985 if (srs
->srs_nta
) CancelGetZoneData(m
, srs
->srs_nta
);
4986 srs
->srs_nta
= StartGetZoneData(m
, srs
->RR_SRV
.resrec
.name
, ZoneServiceUpdate
, ServiceRegistrationGotZoneData
, srs
);
4987 SetRecordRetry(m
, &srs
->RR_SRV
, mStatus_NoError
);
4989 else if (srs
->state
== regState_DeregPending
) SendServiceDeregistration(m
, srs
);
4990 else SendServiceRegistration(m
, srs
);
4992 if (nextevent
- (srs
->RR_SRV
.LastAPTime
+ srs
->RR_SRV
.ThisAPInterval
) > 0)
4993 nextevent
= (srs
->RR_SRV
.LastAPTime
+ srs
->RR_SRV
.ThisAPInterval
);
4999 mDNSexport
void uDNS_Execute(mDNS
*const m
)
5003 m
->NextuDNSEvent
= m
->timenow
+ 0x3FFFFFFF;
5005 if (m
->NextSRVUpdate
&& m
->NextSRVUpdate
- m
->timenow
< 0)
5006 { m
->NextSRVUpdate
= 0; UpdateSRVRecords(m
); }
5008 CheckNATMappings(m
);
5010 if (m
->SuppressStdPort53Queries
&& m
->timenow
- m
->SuppressStdPort53Queries
>= 0)
5011 m
->SuppressStdPort53Queries
= 0; // If suppression time has passed, clear it
5013 nexte
= CheckRecordRegistrations(m
);
5014 if (nexte
- m
->NextuDNSEvent
< 0) m
->NextuDNSEvent
= nexte
;
5016 nexte
= CheckServiceRegistrations(m
);
5017 if (nexte
- m
->NextuDNSEvent
< 0) m
->NextuDNSEvent
= nexte
;
5020 // ***************************************************************************
5021 #if COMPILER_LIKES_PRAGMA_MARK
5022 #pragma mark - Startup, Shutdown, and Sleep
5025 // simplest sleep logic - rather than having sleep states that must be dealt with explicitly in all parts of
5026 // the code, we simply send a deregistration, and put the service in Refresh state, with a timeout far enough
5027 // in the future that we'll sleep (or the sleep will be cancelled) before it is retransmitted. Then to wake,
5028 // we just move up the timers.
5030 mDNSexport
void SleepRecordRegistrations(mDNS
*m
)
5033 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
5034 if (AuthRecord_uDNS(rr
))
5035 if (rr
->state
== regState_Registered
||
5036 rr
->state
== regState_Refresh
)
5038 SendRecordDeregistration(m
, rr
);
5039 rr
->state
= regState_Refresh
;
5040 rr
->LastAPTime
= m
->timenow
;
5041 rr
->ThisAPInterval
= 300 * mDNSPlatformOneSecond
;
5045 mDNSexport
void SleepServiceRegistrations(mDNS
*m
)
5047 ServiceRecordSet
*srs
= m
->ServiceRegistrations
;
5050 LogInfo("SleepServiceRegistrations: state %d %s", srs
->state
, ARDisplayString(m
, &srs
->RR_SRV
));
5051 if (srs
->srs_nta
) { CancelGetZoneData(m
, srs
->srs_nta
); srs
->srs_nta
= mDNSNULL
; }
5053 if (srs
->NATinfo
.clientContext
)
5055 mDNS_StopNATOperation_internal(m
, &srs
->NATinfo
);
5056 srs
->NATinfo
.clientContext
= mDNSNULL
;
5059 if (srs
->state
== regState_UpdatePending
)
5061 // act as if the update succeeded, since we're about to delete the name anyway
5062 AuthRecord
*txt
= &srs
->RR_TXT
;
5063 srs
->state
= regState_Registered
;
5064 // deallocate old RData
5065 if (txt
->UpdateCallback
) txt
->UpdateCallback(m
, txt
, txt
->OrigRData
);
5066 SetNewRData(&txt
->resrec
, txt
->InFlightRData
, txt
->InFlightRDLen
);
5067 txt
->OrigRData
= mDNSNULL
;
5068 txt
->InFlightRData
= mDNSNULL
;
5071 if (srs
->state
== regState_Registered
|| srs
->state
== regState_Refresh
)
5072 SendServiceDeregistration(m
, srs
);
5074 srs
->state
= regState_NoTarget
; // when we wake, we'll re-register (and optionally nat-map) once our address record completes
5075 srs
->RR_SRV
.resrec
.rdata
->u
.srv
.target
.c
[0] = 0;
5076 srs
->SRSUpdateServer
= zeroAddr
; // This will cause UpdateSRV to do a new StartGetZoneData
5077 srs
->RR_SRV
.ThisAPInterval
= 5 * mDNSPlatformOneSecond
; // After doubling, first retry will happen after ten seconds
5079 srs
= srs
->uDNS_next
;
5083 mDNSexport
void mDNS_AddSearchDomain(const domainname
*const domain
)
5087 // Check to see if we already have this domain in our list
5088 for (p
= &SearchList
; *p
; p
= &(*p
)->next
)
5089 if (SameDomainName(&(*p
)->domain
, domain
))
5091 // If domain is already in list, and marked for deletion, change it to "leave alone"
5092 if ((*p
)->flag
== -1) (*p
)->flag
= 0;
5093 LogInfo("mDNS_AddSearchDomain already in list %##s", domain
->c
);
5097 // if domain not in list, add to list, mark as add (1)
5098 *p
= mDNSPlatformMemAllocate(sizeof(SearchListElem
));
5099 if (!*p
) { LogMsg("ERROR: mDNS_AddSearchDomain - malloc"); return; }
5100 mDNSPlatformMemZero(*p
, sizeof(SearchListElem
));
5101 AssignDomainName(&(*p
)->domain
, domain
);
5102 (*p
)->flag
= 1; // add
5103 (*p
)->next
= mDNSNULL
;
5104 LogInfo("mDNS_AddSearchDomain created new %##s", domain
->c
);
5107 mDNSlocal
void FreeARElemCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
5110 if (result
== mStatus_MemFree
) mDNSPlatformMemFree(rr
->RecordContext
);
5113 mDNSlocal
void FoundDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
5115 SearchListElem
*slElem
= question
->QuestionContext
;
5119 if (answer
->rrtype
!= kDNSType_PTR
) return;
5120 if (answer
->RecordType
== kDNSRecordTypePacketNegative
) return;
5121 if (answer
->InterfaceID
== mDNSInterface_LocalOnly
) return;
5123 if (question
== &slElem
->BrowseQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeBrowse
];
5124 else if (question
== &slElem
->DefBrowseQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeBrowseDefault
];
5125 else if (question
== &slElem
->AutomaticBrowseQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeBrowseAutomatic
];
5126 else if (question
== &slElem
->RegisterQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeRegistration
];
5127 else if (question
== &slElem
->DefRegisterQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeRegistrationDefault
];
5128 else { LogMsg("FoundDomain - unknown question"); return; }
5130 LogInfo("FoundDomain: %p %s %s Q %##s A %s", answer
->InterfaceID
, AddRecord
? "Add" : "Rmv", name
, question
->qname
.c
, RRDisplayString(m
, answer
));
5134 ARListElem
*arElem
= mDNSPlatformMemAllocate(sizeof(ARListElem
));
5135 if (!arElem
) { LogMsg("ERROR: FoundDomain out of memory"); return; }
5136 mDNS_SetupResourceRecord(&arElem
->ar
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, FreeARElemCallback
, arElem
);
5137 MakeDomainNameFromDNSNameString(&arElem
->ar
.namestorage
, name
);
5138 AppendDNSNameString (&arElem
->ar
.namestorage
, "local");
5139 AssignDomainName(&arElem
->ar
.resrec
.rdata
->u
.name
, &answer
->rdata
->u
.name
);
5140 LogInfo("FoundDomain: Registering %s", ARDisplayString(m
, &arElem
->ar
));
5141 err
= mDNS_Register(m
, &arElem
->ar
);
5142 if (err
) { LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err
); mDNSPlatformMemFree(arElem
); return; }
5143 arElem
->next
= slElem
->AuthRecs
;
5144 slElem
->AuthRecs
= arElem
;
5148 ARListElem
**ptr
= &slElem
->AuthRecs
;
5151 if (SameDomainName(&(*ptr
)->ar
.resrec
.rdata
->u
.name
, &answer
->rdata
->u
.name
))
5153 ARListElem
*dereg
= *ptr
;
5154 *ptr
= (*ptr
)->next
;
5155 LogInfo("FoundDomain: Deregistering %s", ARDisplayString(m
, &dereg
->ar
));
5156 err
= mDNS_Deregister(m
, &dereg
->ar
);
5157 if (err
) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err
);
5158 // Memory will be freed in the FreeARElemCallback
5161 ptr
= &(*ptr
)->next
;
5166 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
5167 mDNSexport
void udns_validatelists(void *const v
)
5171 ServiceRecordSet
*s
;
5172 for (s
= m
->ServiceRegistrations
; s
; s
=s
->uDNS_next
)
5173 if (s
->uDNS_next
== (ServiceRecordSet
*)~0)
5174 LogMemCorruption("m->ServiceRegistrations: %p is garbage (%lX)", s
, s
->uDNS_next
);
5176 NATTraversalInfo
*n
;
5177 for (n
= m
->NATTraversals
; n
; n
=n
->next
)
5178 if (n
->next
== (NATTraversalInfo
*)~0 || n
->clientCallback
== (NATTraversalClientCallback
)~0)
5179 LogMemCorruption("m->NATTraversals: %p is garbage", n
);
5182 for (d
= m
->DNSServers
; d
; d
=d
->next
)
5183 if (d
->next
== (DNSServer
*)~0 || d
->teststate
> DNSServer_Disabled
)
5184 LogMemCorruption("m->DNSServers: %p is garbage (%d)", d
, d
->teststate
);
5186 DomainAuthInfo
*info
;
5187 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
5188 if (info
->next
== (DomainAuthInfo
*)~0 || info
->AutoTunnel
== (mDNSBool
)~0)
5189 LogMemCorruption("m->AuthInfoList: %p is garbage (%X)", info
, info
->AutoTunnel
);
5192 for (hi
= m
->Hostnames
; hi
; hi
= hi
->next
)
5193 if (hi
->next
== (HostnameInfo
*)~0 || hi
->StatusCallback
== (mDNSRecordCallback
*)~0)
5194 LogMemCorruption("m->Hostnames: %p is garbage", n
);
5196 SearchListElem
*ptr
;
5197 for (ptr
= SearchList
; ptr
; ptr
= ptr
->next
)
5198 if (ptr
->next
== (SearchListElem
*)~0 || ptr
->AuthRecs
== (void*)~0)
5199 LogMemCorruption("SearchList: %p is garbage (%X)", ptr
, ptr
->AuthRecs
);
5203 // This should probably move to the UDS daemon -- the concept of legacy clients and automatic registration / automatic browsing
5204 // is really a UDS API issue, not something intrinsic to uDNS
5206 mDNSexport mStatus
uDNS_RegisterSearchDomains(mDNS
*const m
)
5208 SearchListElem
**p
= &SearchList
, *ptr
;
5211 // step 1: mark each element for removal (-1)
5212 for (ptr
= SearchList
; ptr
; ptr
= ptr
->next
) ptr
->flag
= -1;
5214 // Client has requested domain enumeration or automatic browse -- time to make sure we have the search domains from the platform layer
5216 m
->RegisterSearchDomains
= mDNStrue
;
5217 mDNSPlatformSetDNSConfig(m
, mDNSfalse
, m
->RegisterSearchDomains
, mDNSNULL
, mDNSNULL
, mDNSNULL
);
5220 // delete elems marked for removal, do queries for elems marked add
5224 LogInfo("RegisterSearchDomains %d %p %##s", ptr
->flag
, ptr
->AuthRecs
, ptr
->domain
.c
);
5225 if (ptr
->flag
== -1) // remove
5227 ARListElem
*arList
= ptr
->AuthRecs
;
5228 ptr
->AuthRecs
= mDNSNULL
;
5231 // If the user has "local" in their DNS searchlist, we ignore that for the purposes of domain enumeration queries
5232 if (!SameDomainName(&ptr
->domain
, &localdomain
))
5234 mDNS_StopGetDomains(m
, &ptr
->BrowseQ
);
5235 mDNS_StopGetDomains(m
, &ptr
->RegisterQ
);
5236 mDNS_StopGetDomains(m
, &ptr
->DefBrowseQ
);
5237 mDNS_StopGetDomains(m
, &ptr
->DefRegisterQ
);
5238 mDNS_StopGetDomains(m
, &ptr
->AutomaticBrowseQ
);
5240 mDNSPlatformMemFree(ptr
);
5242 // deregister records generated from answers to the query
5245 ARListElem
*dereg
= arList
;
5246 arList
= arList
->next
;
5247 debugf("Deregistering PTR %##s -> %##s", dereg
->ar
.resrec
.name
->c
, dereg
->ar
.resrec
.rdata
->u
.name
.c
);
5248 err
= mDNS_Deregister(m
, &dereg
->ar
);
5249 if (err
) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err
);
5250 // Memory will be freed in the FreeARElemCallback
5255 if (ptr
->flag
== 1) // add
5257 // If the user has "local" in their DNS searchlist, we ignore that for the purposes of domain enumeration queries
5258 if (!SameDomainName(&ptr
->domain
, &localdomain
))
5260 mStatus err1
, err2
, err3
, err4
, err5
;
5261 err1
= mDNS_GetDomains(m
, &ptr
->BrowseQ
, mDNS_DomainTypeBrowse
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
5262 err2
= mDNS_GetDomains(m
, &ptr
->DefBrowseQ
, mDNS_DomainTypeBrowseDefault
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
5263 err3
= mDNS_GetDomains(m
, &ptr
->RegisterQ
, mDNS_DomainTypeRegistration
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
5264 err4
= mDNS_GetDomains(m
, &ptr
->DefRegisterQ
, mDNS_DomainTypeRegistrationDefault
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
5265 err5
= mDNS_GetDomains(m
, &ptr
->AutomaticBrowseQ
, mDNS_DomainTypeBrowseAutomatic
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
5266 if (err1
|| err2
|| err3
|| err4
|| err5
)
5267 LogMsg("GetDomains for domain %##s returned error(s):\n"
5268 "%d (mDNS_DomainTypeBrowse)\n"
5269 "%d (mDNS_DomainTypeBrowseDefault)\n"
5270 "%d (mDNS_DomainTypeRegistration)\n"
5271 "%d (mDNS_DomainTypeRegistrationDefault)"
5272 "%d (mDNS_DomainTypeBrowseAutomatic)\n",
5273 ptr
->domain
.c
, err1
, err2
, err3
, err4
, err5
);
5278 if (ptr
->flag
) { LogMsg("RegisterSearchDomains - unknown flag %d. Skipping.", ptr
->flag
); }
5283 return mStatus_NoError
;
5286 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
5287 // 1) query for b._dns-sd._udp.local on LocalOnly interface
5288 // (.local manually generated via explicit callback)
5289 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
5290 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
5291 // 4) result above should generate a callback from question in (1). result added to global list
5292 // 5) global list delivered to client via GetSearchDomainList()
5293 // 6) client calls to enumerate domains now go over LocalOnly interface
5294 // (!!!KRS may add outgoing interface in addition)
5296 struct CompileTimeAssertionChecks_uDNS
5298 // Check our structures are reasonable sizes. Including overly-large buffers, or embedding
5299 // other overly-large structures instead of having a pointer to them, can inadvertently
5300 // cause structure sizes (and therefore memory usage) to balloon unreasonably.
5301 char sizecheck_tcpInfo_t
[(sizeof(tcpInfo_t
) <= 9056) ? 1 : -1];
5302 char sizecheck_SearchListElem
[(sizeof(SearchListElem
) <= 3920) ? 1 : -1];