1 /* -*- Mode: C; tab-width: 4 -*-
2  *
3  * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16 
17  * To Do:
18  * Elimate all mDNSPlatformMemAllocate/mDNSPlatformMemFree from this code -- the core code
19  * is supposed to be malloc-free so that it runs in constant memory determined at compile-time.
20  * Any dynamic run-time requirements should be handled by the platform layer below or client layer above
21 
22 	Change History (most recent first):
23 
24 Log: uDNS.c,v $
25 Revision 1.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
27 
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
31 
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.
34 
35 Revision 1.614  2009/04/24 02:17:57  mcguire
36 <rdar://problem/5264124> uDNS: Not always respecting preference order of DNS servers
37 
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
41 
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
44 
45 Revision 1.611  2009/04/15 20:42:51  mcguire
46 <rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures
47 
48 Revision 1.610  2009/04/15 01:10:39  jessic2
49 <rdar://problem/6466541> BTMM: Add support for setting kDNSServiceErr_NoSuchRecord in DynamicStore
50 
51 Revision 1.609  2009/04/11 00:19:45  jessic2
52 <rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
53 
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
56 
57 Revision 1.607  2009/04/02 22:36:34  jessic2
58 Fix crash when calling debugf with null opt
59 
60 Revision 1.606  2009/03/26 03:59:00  jessic2
61 Changes for <rdar://problem/6492552&6492593&6492609&6492613&6492628&6492640&6492699>
62 
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>
66 
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
69 
70 Revision 1.603  2009/02/27 02:56:57  cheshire
71 Moved struct SearchListElem definition from uDNS.c into mDNSEmbeddedAPI.h
72 
73 Revision 1.602  2009/02/13 06:29:54  cheshire
74 Converted LogOperation messages to LogInfo
75 
76 Revision 1.601  2009/02/12 20:57:25  cheshire
77 Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch
78 
79 Revision 1.600  2009/01/31 21:05:12  cheshire
80 Improved "Failed to obtain NAT port mapping" debugging log message
81 
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
84 
85 Revision 1.598  2009/01/21 03:43:57  mcguire
86 <rdar://problem/6511765> BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore
87 
88 Revision 1.597  2009/01/10 01:55:49  cheshire
89 Added LogOperation message showing when domains are added and removed in FoundDomain
90 
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
93 
94 Revision 1.595  2008/12/18 23:32:19  mcguire
95 <rdar://problem/6019470> BTMM: Include the question in the LLQ notification acknowledgment
96 
97 Revision 1.594  2008/12/10 02:25:31  cheshire
98 Minor fixes to use of LogClientOperations symbol
99 
100 Revision 1.593  2008/12/10 02:11:42  cheshire
101 ARMv5 compiler doesn't like uncommented stuff after #endif
102 
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
105 
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"
109 
110 Revision 1.590  2008/12/04 20:57:36  mcguire
111 fix build
112 
113 Revision 1.589  2008/12/04 02:24:09  cheshire
114 Improved NAT-PMP debugging messages
115 
116 Revision 1.588  2008/11/26 20:38:08  cheshire
117 Changed some "LogOperation" debugging messages to "debugf"
118 
119 Revision 1.587  2008/11/26 19:53:26  cheshire
120 Don't overwrite srs->NATinfo.IntPort in StartSRVNatMap()
121 
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
125 
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"
128 
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
131 
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
134 
135 Revision 1.582  2008/11/20 02:23:37  mcguire
136 <rdar://problem/6041208> need to handle URLBase
137 
138 Revision 1.581  2008/11/20 01:51:19  cheshire
139 Exported RecreateNATMappings so it's callable from other files
140 
141 Revision 1.580  2008/11/13 19:08:45  cheshire
142 Fixed code to handle rdataOPT properly
143 
144 Revision 1.579  2008/11/07 00:18:01  mcguire
145 <rdar://problem/6351068> uDNS: Supress reverse DNS query until required
146 
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
149 
150 Revision 1.577  2008/10/29 21:37:01  cheshire
151 Removed some old debugging messages
152 
153 Revision 1.576  2008/10/23 22:25:57  cheshire
154 Renamed field "id" to more descriptive "updateid"
155 
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
158 
159 Revision 1.574  2008/10/14 19:06:45  cheshire
160 In uDNS_ReceiveMsg(), only do checkUpdateResult() for uDNS records
161 
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
165 
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
169 
170 Revision 1.571  2008/09/23 22:56:53  cheshire
171 <rdar://problem/5298845> Remove dnsbugtest query
172 
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
175 
176 Revision 1.569  2008/07/25 22:34:11  mcguire
177 fix sizecheck issues for 64bit
178 
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
181 
182 Revision 1.567  2008/07/01 01:40:00  mcguire
183 <rdar://problem/5823010> 64-bit fixes
184 
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
187 
188 Revision 1.565  2008/06/21 19:06:58  mcguire
189 <rdar://problem/4206534> Use all configured DNS servers
190 
191 Revision 1.564  2008/06/19 23:42:03  mcguire
192 <rdar://problem/4206534> Use all configured DNS servers
193 
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
197 
198 Revision 1.562  2008/06/19 17:35:19  mcguire
199 <rdar://problem/4206534> Use all configured DNS servers
200 cleanup log messages
201 check for null pointers
202 
203 Revision 1.561  2008/06/19 01:20:49  mcguire
204 <rdar://problem/4206534> Use all configured DNS servers
205 
206 Revision 1.560  2008/05/31 01:51:09  mcguire
207 fixed typo in log message
208 
209 Revision 1.559  2008/04/15 22:37:58  mkrochma
210 Change LogMsg to LogOperation
211 
212 Revision 1.558  2008/03/17 18:02:35  mkrochma
213 Add space to log message for consistency
214 
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
218 
219 Revision 1.556  2008/03/07 23:55:05  cheshire
220 <rdar://problem/5787898> LLQ refresh randomization not working properly
221 
222 Revision 1.555  2008/03/07 23:25:56  cheshire
223 Improved debugging messages
224 
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
227 
228 Revision 1.553  2008/03/06 02:48:34  mcguire
229 <rdar://problem/5321824> write status to the DS
230 
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
233 
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
237 
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
240 Further refinements
241 
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
244 
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
248 
249 Revision 1.547  2008/02/20 00:41:09  cheshire
250 Change "PrivateQueryGotZoneData ... invoked with error code" from LogMsg to LogOperation
251 
252 Revision 1.546  2008/02/19 23:26:50  cheshire
253 <rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
254 
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
257 
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
261 
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
265 
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
268 
269 Revision 1.541  2007/12/15 00:18:51  cheshire
270 Renamed question->origLease to question->ReqLease
271 
272 Revision 1.540  2007/12/14 23:55:28  cheshire
273 Moved "struct tcpInfo_t" definition from uDNS.c to mDNSEmbeddedAPI.h
274 
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
278 
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)
282 
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.
286 
287 Revision 1.536  2007/12/10 23:07:00  cheshire
288 Removed some unnecessary log messages
289 
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)
292 
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
295 
296 Revision 1.533  2007/12/01 01:21:27  jgraessley
297 <rdar://problem/5623140> mDNSResponder unicast DNS improvements
298 
299 Revision 1.532  2007/11/30 20:16:44  cheshire
300 Fixed compile warning: declaration of 'end' shadows a previous local
301 
302 Revision 1.531  2007/11/28 22:00:09  cheshire
303 In StartSRVNatMap, change "mDNSu8 *p" to "const mDNSu8 *p"
304 
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
308 
309 Revision 1.529  2007/11/15 22:52:29  cheshire
310 <rdar://problem/5589039> ERROR: mDNSPlatformWriteTCP - send Broken pipe
311 
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
314 
315 Revision 1.527  2007/11/01 16:08:51  cheshire
316 Tidy up alignment of "SetRecordRetry refresh" log messages
317 
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
320 
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
324 
325 Revision 1.524  2007/10/30 20:10:47  cheshire
326 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
327 
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
331 
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
335 
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
339 
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
343 
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
347 
348 Revision 1.518  2007/10/26 23:41:29  cheshire
349 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
350 
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
353 
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
357 
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
360 
361 Revision 1.514  2007/10/25 20:48:47  cheshire
362 For naming consistency (with AuthRecord's UpdateServer) renamed 'ns' to 'SRSUpdateServer'
363 
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
366 
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
370 
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
375 
376 Revision 1.510  2007/10/24 22:40:06  cheshire
377 Renamed: RecordRegistrationCallback          -> RecordRegistrationGotZoneData
378 Renamed: ServiceRegistrationZoneDataComplete -> ServiceRegistrationGotZoneData
379 
380 Revision 1.509  2007/10/24 00:54:07  cheshire
381 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
382 
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
386 
387 Revision 1.507  2007/10/23 00:33:36  cheshire
388 Improved debugging messages
389 
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
393 
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
397 
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
401 
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
404 
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
407 
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
410 
411 Revision 1.500  2007/10/17 21:53:51  cheshire
412 Improved debugging messages; renamed startLLQHandshakeCallback to LLQGotZoneData
413 
414 Revision 1.499  2007/10/16 21:16:50  cheshire
415 Get rid of unused uDNS_Sleep() routine
416 
417 Revision 1.498  2007/10/16 20:59:41  cheshire
418 Export SuspendLLQs/SleepServiceRegistrations/SleepRecordRegistrations so they're callable from other files
419 
420 Revision 1.497  2007/10/05 18:09:44  cheshire
421 <rdar://problem/5524841> Services advertised with wrong target host
422 
423 Revision 1.496  2007/10/04 22:38:59  cheshire
424 Added LogOperation message showing new q->ThisQInterval after sending uDNS query packet
425 
426 Revision 1.495  2007/10/03 00:16:19  cheshire
427 In PrivateQueryGotZoneData, need to grab lock before calling SetNextQueryTime
428 
429 Revision 1.494  2007/10/02 21:11:08  cheshire
430 <rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing
431 
432 Revision 1.493  2007/10/02 19:50:23  cheshire
433 Improved debugging message
434 
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
438 
439 Revision 1.491  2007/09/29 01:33:45  cheshire
440 <rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
441 
442 Revision 1.490  2007/09/29 01:06:17  mcguire
443 <rdar://problem/5507862> 9A564: mDNSResponder crash in mDNS_Execute
444 
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
447 
448 Revision 1.488  2007/09/27 21:20:17  cheshire
449 Improved debugging syslog messages
450 
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
453 
454 Revision 1.486  2007/09/27 17:42:49  cheshire
455 Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask"
456 
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
459 
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
463 
464 Revision 1.483  2007/09/26 23:16:58  cheshire
465 <rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac
466 
467 Revision 1.482  2007/09/26 22:06:02  cheshire
468 <rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
469 
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
473 
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
477 
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
480 
481 Revision 1.478  2007/09/21 19:29:14  cheshire
482 Added dump of uDNS questions when in MDNS_LOG_VERBOSE_DEBUG mode
483 
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
486 
487 Revision 1.476  2007/09/20 01:19:49  cheshire
488 Improve debugging messages: report startLLQHandshake errors; show state in uDNS_StopLongLivedQuery message
489 
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
492 
493 Revision 1.474  2007/09/19 20:32:09  cheshire
494 Export GetAuthInfoForName so it's callable from other files
495 
496 Revision 1.473  2007/09/18 21:42:29  cheshire
497 To reduce programming mistakes, renamed ExtPort to RequestedPort
498 
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
501 
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.
505 
506 Revision 1.470  2007/09/13 00:36:26  cheshire
507 <rdar://problem/5477360> NAT Reboot detection logic incorrect
508 
509 Revision 1.469  2007/09/13 00:28:50  cheshire
510 <rdar://problem/5477354> Host records not updated on NAT address change
511 
512 Revision 1.468  2007/09/13 00:16:41  cheshire
513 <rdar://problem/5468706> Miscellaneous NAT Traversal improvements
514 
515 Revision 1.467  2007/09/12 23:03:08  cheshire
516 <rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
517 
518 Revision 1.466  2007/09/12 22:19:29  cheshire
519 <rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
520 
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
524 
525 Revision 1.464  2007/09/12 01:22:13  cheshire
526 Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
527 
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
531 
532 Revision 1.462  2007/09/11 19:19:16  cheshire
533 Correct capitalization of "uPNP" to "UPnP"
534 
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
537 
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.
541 
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
545 
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)
548 
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.
554 
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
558 
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
561 
562 Revision 1.454  2007/09/05 02:32:55  cheshire
563 Fixed posix build error (mixed declarations and code)
564 
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
568 
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
572 
573 Revision 1.451  2007/08/31 18:49:49  vazquez
574 <rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
575 
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
578 
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
581 
582 Revision 1.448  2007/08/30 00:18:46  cheshire
583 <rdar://problem/5448804> Error messages: "SendServiceRegistration: Already have TCP connection..."
584 
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
588 
589 Revision 1.446  2007/08/28 23:58:42  cheshire
590 Rename HostTarget -> AutoTarget
591 
592 Revision 1.445  2007/08/28 23:53:21  cheshire
593 Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
594 
595 Revision 1.444  2007/08/27 20:29:20  cheshire
596 Additional debugging messages
597 
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()
601 
602 Revision 1.442  2007/08/24 22:43:06  cheshire
603 Tidied up coded layout
604 
605 Revision 1.441  2007/08/24 01:20:55  cheshire
606 <rdar://problem/5434381> BTMM: Memory corruption in KeychainChanged event handling
607 
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
610 
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.
616 
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.
620 
621 Revision 1.437  2007/08/18 00:54:15  mcguire
622 <rdar://problem/5413147> BTMM: Should not register private addresses or zeros
623 
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
626 
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.
632 
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.
636 
637 Revision 1.433  2007/08/02 03:30:11  vazquez
638 <rdar://problem/5371843> BTMM: Private LLQs never fall back to polling
639 
640 Revision 1.432  2007/08/01 18:15:19  cheshire
641 Fixed crash in tcpCallback; fixed some problems with LLQ setup behind NAT
642 
643 Revision 1.431  2007/08/01 16:11:06  cheshire
644 Fixed "mixed declarations and code" compiler error in Posix build
645 
646 Revision 1.430  2007/08/01 16:09:13  cheshire
647 Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
648 
649 Revision 1.429  2007/08/01 03:09:22  cheshire
650 <rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
651 
652 Revision 1.428  2007/08/01 01:43:36  cheshire
653 Need to do mDNS_DropLockBeforeCallback/ReclaimLock around invokation of NAT client callback
654 
655 Revision 1.427  2007/08/01 01:31:13  cheshire
656 Need to initialize traversal->tcpInfo fields or code may crash
657 
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
660 
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
664 
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
667 
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
670 
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
673 
674 Revision 1.421  2007/07/28 00:04:14  cheshire
675 Various fixes for comments and debugging messages
676 
677 Revision 1.420  2007/07/27 23:59:18  cheshire
678 Added compile-time structure size checks
679 
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
682 
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
686 
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
689 
690 Revision 1.416  2007/07/27 19:59:28  cheshire
691 MUST NOT touch m->CurrentQuestion (or q) after calling AnswerCurrentQuestionWithResourceRecord()
692 
693 Revision 1.415  2007/07/27 19:51:01  cheshire
694 Use symbol QC_addnocache instead of literal constant "2"
695 
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
699 
700 Revision 1.413  2007/07/27 18:44:01  cheshire
701 Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
702 
703 Revision 1.412  2007/07/27 18:38:56  cheshire
704 Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
705 
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
708 
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
711 port mappings
712 
713 Revision 1.409  2007/07/25 03:05:02  vazquez
714 Fixes for:
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
718 
719 Revision 1.408  2007/07/24 21:47:51  cheshire
720 Don't do mDNS_StopNATOperation() for operations we never started
721 
722 Revision 1.407  2007/07/24 17:23:33  cheshire
723 <rdar://problem/5357133> Add list validation checks for debugging
724 
725 Revision 1.406  2007/07/24 04:14:30  cheshire
726 <rdar://problem/5356281> LLQs not working in with NAT Traversal
727 
728 Revision 1.405  2007/07/24 01:29:03  cheshire
729 <rdar://problem/5356026> DNSServiceNATPortMappingCreate() returns stale external address information
730 
731 Revision 1.404  2007/07/20 23:10:51  cheshire
732 Fix code layout
733 
734 Revision 1.403  2007/07/20 20:12:37  cheshire
735 Rename "mDNS_DomainTypeBrowseLegacy" as "mDNS_DomainTypeBrowseAutomatic"
736 
737 Revision 1.402  2007/07/20 00:54:20  cheshire
738 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
739 
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
742 
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)
746 
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
750 
751 Revision 1.398  2007/07/16 23:54:48  cheshire
752 <rdar://problem/5338850> Crash when removing or changing DNS keys
753 
754 Revision 1.397  2007/07/16 20:13:31  vazquez
755 <rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
756 
757 Revision 1.396  2007/07/14 00:33:04  cheshire
758 Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working
759 
760 Revision 1.395  2007/07/12 23:56:23  cheshire
761 Change "GetZoneData GOT SRV" message to debugf to reduce verbosity in syslog
762 
763 Revision 1.394  2007/07/12 23:36:08  cheshire
764 Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog
765 
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
768 
769 Revision 1.392  2007/07/12 02:51:27  cheshire
770 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
771 
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
775 
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
779 
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
783 
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
787 
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
791 
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
796 
797 Revision 1.385  2007/07/09 23:50:18  cheshire
798 unlinkSRS needs to call mDNS_StopNATOperation_internal(), not mDNS_StopNATOperation()
799 
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")
802 
803 Revision 1.383  2007/07/06 18:59:59  cheshire
804 Avoid spinning in an infinite loop when uDNS_SendNATMsg() returns an error
805 
806 Revision 1.382  2007/07/04 00:49:43  vazquez
807 Clean up extraneous comments
808 
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
812 
813 Revision 1.380  2007/07/02 22:08:47  cheshire
814 Fixed crash in "Received public IP address" message
815 
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)
818 
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.
822 
823 Revision 1.377  2007/06/22 21:27:21  cheshire
824 Modified "could not convert shared secret from base64" log message
825 
826 Revision 1.376  2007/06/20 01:10:12  cheshire
827 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
828 
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
831 
832 Revision 1.374  2007/06/12 02:15:26  cheshire
833 Fix incorrect "DNS Server passed" LogOperation message
834 
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
837 
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
840 
841 Revision 1.371  2007/05/24 00:11:44  cheshire
842 Remove unnecessary lenbuf field from tcpInfo_t
843 
844 Revision 1.370  2007/05/23 00:30:59  cheshire
845 Don't change question->TargetQID when repeating query over TCP
846 
847 Revision 1.369  2007/05/21 18:04:40  cheshire
848 Updated comments -- port_mapping_create_reply renamed to port_mapping_reply
849 
850 Revision 1.368  2007/05/17 19:12:16  cheshire
851 Updated comment about finding matching pair of sockets
852 
853 Revision 1.367  2007/05/15 23:38:00  cheshire
854 Need to grab lock before calling SendRecordRegistration();
855 
856 Revision 1.366  2007/05/15 00:43:05  cheshire
857 <rdar://problem/4983538> uDNS serviceRegistrationCallback locking failures
858 
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)
862 
863 Revision 1.364  2007/05/07 20:43:45  cheshire
864 <rdar://problem/4241419> Reduce the number of queries and announcements
865 
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
869 
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
873 
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
877 
878 Revision 1.360  2007/05/03 22:40:38  cheshire
879 <rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
880 
881 Revision 1.359  2007/05/02 22:21:33  cheshire
882 <rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
883 
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
886 
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"
889 
890 Revision 1.356  2007/04/30 21:51:06  cheshire
891 Updated comments
892 
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
896 
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
900 
901 Revision 1.353  2007/04/28 01:28:25  cheshire
902 Fixed memory leak on error path in FoundDomain
903 
904 Revision 1.352  2007/04/27 19:49:53  cheshire
905 In uDNS_ReceiveTestQuestionResponse, also check that srcport matches
906 
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.)
912 
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)"
915 
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
919 
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)"
922 
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.)
927 
928 Revision 1.346  2007/04/25 19:16:59  cheshire
929 Don't set SuppressStdPort53Queries unless we do actually send a DNS packet
930 
931 Revision 1.345  2007/04/25 18:05:11  cheshire
932 Don't try to restart inactive (duplicate) queries
933 
934 Revision 1.344  2007/04/25 17:54:07  cheshire
935 Don't cancel Private LLQs using a clear-text UDP packet
936 
937 Revision 1.343  2007/04/25 16:40:08  cheshire
938 Add comment explaining uDNS_recvLLQResponse logic
939 
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
943 
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
947 
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).
953 
954 Revision 1.339  2007/04/22 06:02:03  cheshire
955 <rdar://problem/4615977> Query should immediately return failure when no server
956 
957 Revision 1.338  2007/04/21 19:44:11  cheshire
958 Improve uDNS_HandleNATPortMapReply log message
959 
960 Revision 1.337  2007/04/21 02:03:00  cheshire
961 Also need to set AddressRec->resrec.RecordType in the NAT case too
962 
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
966 
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
969 
970 Revision 1.334  2007/04/19 23:21:51  cheshire
971 Fixed a couple of places where the StartGetZoneData check was backwards
972 
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
975 
976 Revision 1.332  2007/04/19 20:34:32  cheshire
977 Add debugging log message in uDNS_CheckQuery()
978 
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)
981 
982 Revision 1.330  2007/04/19 19:51:54  cheshire
983 Get rid of unnecessary initializeQuery() routine
984 
985 Revision 1.329  2007/04/19 18:03:52  cheshire
986 Improved "mDNS_AddSearchDomain" log message
987 
988 Revision 1.328  2007/04/18 20:57:20  cheshire
989 Commented out "GetAuthInfoForName none found" debugging message
990 
991 Revision 1.327  2007/04/17 19:21:29  cheshire
992 <rdar://problem/5140339> Domain discovery not working over VPN
993 
994 Revision 1.326  2007/04/16 20:49:39  cheshire
995 Fix compile errors for mDNSPosix build
996 
997 Revision 1.325  2007/04/05 22:55:35  cheshire
998 <rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
999 
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.
1004 
1005 Revision 1.323  2007/04/04 21:48:52  cheshire
1006 <rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
1007 
1008 Revision 1.322  2007/04/03 19:53:06  cheshire
1009 Use mDNSSameIPPort (and similar) instead of accessing internal fields directly
1010 
1011 Revision 1.321  2007/04/02 23:44:09  cheshire
1012 Minor code tidying
1013 
1014 Revision 1.320  2007/03/31 01:26:13  cheshire
1015 Take out GetAuthInfoForName syslog message
1016 
1017 Revision 1.319  2007/03/31 01:10:53  cheshire
1018 Add debugging
1019 
1020 Revision 1.318  2007/03/31 00:17:11  cheshire
1021 Remove some LogMsgs
1022 
1023 Revision 1.317  2007/03/29 00:09:31  cheshire
1024 Improve "uDNS_InitLongLivedQuery" log message
1025 
1026 Revision 1.316  2007/03/28 21:16:27  cheshire
1027 Remove DumpPacket() call now that OPT pseudo-RR rrclass bug is fixed
1028 
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
1031 
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
1034 
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
1038 
1039 Revision 1.312  2007/03/27 23:48:21  cheshire
1040 Use mDNS_StopGetDomains(), not mDNS_StopQuery()
1041 
1042 Revision 1.311  2007/03/27 22:47:51  cheshire
1043 Remove unnecessary "*(long*)0 = 0;" to generate crash and stack trace
1044 
1045 Revision 1.310  2007/03/24 01:24:13  cheshire
1046 Add validator for uDNS data structures; fixed crash in RegisterSearchDomains()
1047 
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.
1051 
1052 Revision 1.308  2007/03/24 00:41:33  cheshire
1053 Minor code cleanup (move variable declarations to minimum enclosing scope)
1054 
1055 Revision 1.307  2007/03/21 23:06:00  cheshire
1056 Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
1057 
1058 Revision 1.306  2007/03/21 00:30:03  cheshire
1059 <rdar://problem/4789455> Multiple errors in DNameList-related code
1060 
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"
1063 
1064 Revision 1.304  2007/03/17 00:02:11  cheshire
1065 <rdar://problem/5067013> NAT-PMP: Lease TTL is being ignored
1066 
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
1069 
1070 Revision 1.302  2007/03/10 02:29:58  cheshire
1071 Added comments about NAT-PMP response functions
1072 
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
1076 
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)
1079 
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
1083 
1084 Revision 1.298  2007/02/14 03:16:39  cheshire
1085 <rdar://problem/4789477> Eliminate unnecessary malloc/free in mDNSCore code
1086 
1087 Revision 1.297  2007/02/08 21:12:28  cheshire
1088 <rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
1089 
1090 Revision 1.296  2007/01/29 16:03:22  cheshire
1091 Fix unused parameter warning
1092 
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
1096 
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.
1100 
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()
1103 
1104 Revision 1.292  2007/01/20 01:32:40  cheshire
1105 Update comments and debugging messages
1106 
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.
1111 
1112 Revision 1.290  2007/01/19 23:41:45  cheshire
1113 Need to clear m->rec.r.resrec.RecordType after calling GetLLQOptData()
1114 
1115 Revision 1.289  2007/01/19 23:32:07  cheshire
1116 Eliminate pointless timenow variable
1117 
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
1120 
1121 Revision 1.287  2007/01/19 22:55:41  cheshire
1122 Eliminate redundant identical parameters to GetZoneData_StartQuery()
1123 
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
1126 
1127 Revision 1.285  2007/01/19 18:39:11  cheshire
1128 Fix a bunch of parameters that should have been declared "const"
1129 
1130 Revision 1.284  2007/01/19 18:28:28  cheshire
1131 Improved debugging messages
1132 
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
1137 
1138 Revision 1.282  2007/01/17 22:06:01  cheshire
1139 Replace duplicated literal constant "{ { 0 } }" with symbol "zeroIPPort"
1140 
1141 Revision 1.281  2007/01/17 21:58:13  cheshire
1142 For clarity, rename ntaContext field "isPrivate" to "ntaPrivate"
1143 
1144 Revision 1.280  2007/01/17 21:46:02  cheshire
1145 Remove redundant duplicated "isPrivate" field from LLQ_Info
1146 
1147 Revision 1.279  2007/01/17 21:35:31  cheshire
1148 For clarity, rename zoneData_t field "isPrivate" to "zonePrivate"
1149 
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"
1154 
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
1157 
1158 Revision 1.276  2007/01/10 02:09:30  cheshire
1159 Better LogOperation record of keys read from System Keychain
1160 
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.
1164 
1165 Revision 1.274  2007/01/09 01:16:32  cheshire
1166 Improve "ERROR m->CurrentQuestion already set" debugging messages
1167 
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
1170 
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)
1174 
1175 Revision 1.271  2007/01/05 06:34:03  cheshire
1176 Improve "ERROR m->CurrentQuestion already set" debugging messages
1177 
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
1181 
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
1185 
1186 Revision 1.268  2007/01/04 22:06:38  cheshire
1187 Fixed crash in LLQNatMapComplete()
1188 
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
1192 
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
1196 
1197 Revision 1.265  2007/01/04 20:47:17  cheshire
1198 Fixed crash in CheckForUnreferencedLLQMapping()
1199 
1200 Revision 1.264  2007/01/04 20:39:27  cheshire
1201 Fix locking mismatch
1202 
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
1205 
1206 Revision 1.262  2007/01/04 00:29:25  cheshire
1207 Covert LogMsg() in GetAuthInfoForName to LogOperation()
1208 
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
1212 
1213 Revision 1.260  2006/12/21 00:06:07  cheshire
1214 Don't need to do mDNSPlatformMemZero() -- mDNS_SetupResourceRecord() does it for us
1215 
1216 Revision 1.259  2006/12/20 04:07:36  cheshire
1217 Remove uDNS_info substructure from AuthRecord_struct
1218 
1219 Revision 1.258  2006/12/19 22:49:24  cheshire
1220 Remove uDNS_info substructure from ServiceRecordSet_struct
1221 
1222 Revision 1.257  2006/12/19 02:38:20  cheshire
1223 Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
1224 
1225 Revision 1.256  2006/12/19 02:18:48  cheshire
1226 Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
1227 
1228 Revision 1.255  2006/12/16 01:58:31  cheshire
1229 <rdar://problem/4720673> uDNS: Need to start caching unicast records
1230 
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.
1234 
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.
1238 
1239 Revision 1.252  2006/11/30 23:07:57  herscher
1240 <rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
1241 
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
1244 
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
1248 
1249 Revision 1.249  2006/11/10 07:44:04  herscher
1250 <rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
1251 
1252 Revision 1.248  2006/11/08 04:26:53  cheshire
1253 Fix typo in debugging message
1254 
1255 Revision 1.247  2006/10/20 05:35:04  herscher
1256 <rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
1257 
1258 Revision 1.246  2006/10/11 19:29:41  herscher
1259 <rdar://problem/4744553> uDNS: mDNSResponder-111 using 100% CPU
1260 
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.
1263 
1264 Revision 1.244  2006/10/04 21:51:27  herscher
1265 Replace calls to mDNSPlatformTimeNow(m) with m->timenow
1266 
1267 Revision 1.243  2006/10/04 21:38:59  herscher
1268 Remove uDNS_info substructure from DNSQuestion_struct
1269 
1270 Revision 1.242  2006/09/27 00:51:46  herscher
1271 Fix compile error when _LEGACY_NAT_TRAVERSAL_ is not defined
1272 
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)
1275 
1276 Revision 1.240  2006/09/15 21:20:15  cheshire
1277 Remove uDNS_info substructure from mDNS_struct
1278 
1279 Revision 1.239  2006/08/16 02:52:56  mkrochma
1280 <rdar://problem/4104154> Actually fix it this time
1281 
1282 Revision 1.238  2006/08/16 00:31:50  mkrochma
1283 <rdar://problem/4386944> Get rid of NotAnInteger references
1284 
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
1287 
1288 Revision 1.236  2006/08/14 23:24:23  cheshire
1289 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
1290 
1291 Revision 1.235  2006/07/30 05:45:36  cheshire
1292 <rdar://problem/4304215> Eliminate MIN_UCAST_PERIODIC_EXEC
1293 
1294 Revision 1.234  2006/07/22 02:58:36  cheshire
1295 Code was clearing namehash twice instead of namehash and rdatahash
1296 
1297 Revision 1.233  2006/07/20 19:46:51  mkrochma
1298 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1299 Fix Private DNS
1300 
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
1304 
1305 Revision 1.231  2006/07/05 23:28:22  cheshire
1306 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1307 
1308 Revision 1.230  2006/06/29 03:02:44  cheshire
1309 <rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
1310 
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
1314 
1315 Revision 1.228  2006/02/26 00:54:42  cheshire
1316 Fixes to avoid code generation warning/error on FreeBSD 7
1317 
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"
1320 
1321 */
1322 
1323 #include "uDNS.h"
1324 
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)
1332 #endif
1333 
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;
1340 
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;
1347 
1348 // ***************************************************************************
1349 #if COMPILER_LIKES_PRAGMA_MARK
1350 #pragma mark - General Utility Functions
1351 #endif
1352 
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)
1357 	{
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;
1362 	if (!*list)
1363 		{
1364 		list = &m->DuplicateRecords;
1365 		while (*list && *list != rr) list = &(*list)->next;
1366 		}
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);
1370 	}
1371 
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)
1374 	{
1375 	ServiceRecordSet **p;
1376 
1377 	if (srs->NATinfo.clientContext)
1378 		{
1379 		mDNS_StopNATOperation_internal(m, &srs->NATinfo);
1380 		srs->NATinfo.clientContext = mDNSNULL;
1381 		}
1382 
1383 	for (p = &m->ServiceRegistrations; *p; p = &(*p)->uDNS_next)
1384 		if (*p == srs)
1385 			{
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);
1394 			return;
1395 			}
1396 	LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list %##s", srs->RR_SRV.resrec.name->c);
1397 	}
1398 
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)
1402 	{
1403 	mDNSs32 elapsed = m->timenow - rr->LastAPTime;
1404 	rr->LastAPTime = m->timenow;
1405 
1406 #if 0
1407 	// Code for stress-testing registration renewal code
1408 	if (rr->expire && rr->expire - m->timenow > mDNSPlatformOneSecond * 120)
1409 		{
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;
1413 		}
1414 #endif
1415 
1416 	if (rr->expire && rr->expire - m->timenow > mDNSPlatformOneSecond)
1417 		{
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));
1422 		return;
1423 		}
1424 
1425 	rr->expire = 0;
1426 
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;
1436 
1437 	LogInfo("SetRecordRetry retry   in %4d for %s", rr->ThisAPInterval / mDNSPlatformOneSecond, ARDisplayString(m, rr));
1438 	}
1439 
1440 // ***************************************************************************
1441 #if COMPILER_LIKES_PRAGMA_MARK
1442 #pragma mark - Name Server List Management
1443 #endif
1444 
1445 mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port)
1446 	{
1447 	DNSServer **p = &m->DNSServers;
1448 	DNSServer *tmp = mDNSNULL;
1449 
1450 	if (!d) d = (const domainname *)"";
1451 
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);
1455 
1456 	while (*p)	// Check if we already have this {interface,address,port,domain} tuple registered
1457 		{
1458 		if ((*p)->interface == interface && (*p)->teststate != DNSServer_Disabled &&
1459 			mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d))
1460 			{
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;
1463 			tmp = *p;
1464 			*p = tmp->next;
1465 			tmp->next = mDNSNULL;
1466 			}
1467 		else
1468 			p=&(*p)->next;
1469 		}
1470 
1471 	if (tmp) *p = tmp; // move to end of list, to ensure ordering from platform layer
1472 	else
1473 		{
1474 		// allocate, add to list
1475 		*p = mDNSPlatformMemAllocate(sizeof(**p));
1476 		if (!*p) LogMsg("Error: mDNS_AddDNSServer - malloc");
1477 		else
1478 			{
1479 			(*p)->interface = interface;
1480 			(*p)->addr      = *addr;
1481 			(*p)->port      = port;
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;
1487 			}
1488 		}
1489 	return(*p);
1490 	}
1491 
1492 mDNSexport void PushDNSServerToEnd(mDNS *const m, DNSQuestion *q)
1493 	{
1494 	DNSServer *orig = q->qDNSServer;
1495 	DNSServer **p = &m->DNSServers;
1496 
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);
1499 
1500 	if (!q->qDNSServer)
1501 		{
1502 		LogMsg("PushDNSServerToEnd: Null DNS server for %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), q->unansweredQueries);
1503 		goto end;
1504 		}
1505 
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));
1508 
1509 	while (*p)
1510 		{
1511 		if (*p == q->qDNSServer) *p = q->qDNSServer->next;
1512 		else p=&(*p)->next;
1513 		}
1514 
1515 	*p = q->qDNSServer;
1516 	q->qDNSServer->next = mDNSNULL;
1517 
1518 end:
1519 	q->qDNSServer = GetServerForName(m, &q->qname);
1520 
1521 	if (q->qDNSServer != orig)
1522 		{
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.
1526 		}
1527 	}
1528 
1529 // ***************************************************************************
1530 #if COMPILER_LIKES_PRAGMA_MARK
1531 #pragma mark - authorization management
1532 #endif
1533 
1534 mDNSlocal DomainAuthInfo *GetAuthInfoForName_direct(mDNS *m, const domainname *const name)
1535 	{
1536 	const domainname *n = name;
1537 	while (n->c[0])
1538 		{
1539 		DomainAuthInfo *ptr;
1540 		for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
1541 			if (SameDomainName(&ptr->domain, n))
1542 				{
1543 				debugf("GetAuthInfoForName %##s Matched %##s Key name %##s", name->c, ptr->domain.c, ptr->keyname.c);
1544 				return(ptr);
1545 				}
1546 		n = (const domainname *)(n->c + 1 + n->c[0]);
1547 		}
1548 	//LogInfo("GetAuthInfoForName none found for %##s", name->c);
1549 	return mDNSNULL;
1550 	}
1551 
1552 // MUST be called with lock held
1553 mDNSexport DomainAuthInfo *GetAuthInfoForName_internal(mDNS *m, const domainname *const name)
1554 	{
1555 	DomainAuthInfo **p = &m->AuthInfoList;
1556 
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);
1559 
1560 	// First purge any dead keys from the list
1561 	while (*p)
1562 		{
1563 		if ((*p)->deltime && m->timenow - (*p)->deltime >= 0 && AutoTunnelUnregistered(*p))
1564 			{
1565 			DNSQuestion *q;
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)
1571 					{
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));
1575 					}
1576 
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);
1582 			}
1583 		else
1584 			p = &(*p)->next;
1585 		}
1586 
1587 	return(GetAuthInfoForName_direct(m, name));
1588 	}
1589 
1590 mDNSexport DomainAuthInfo *GetAuthInfoForName(mDNS *m, const domainname *const name)
1591 	{
1592 	DomainAuthInfo *d;
1593 	mDNS_Lock(m);
1594 	d = GetAuthInfoForName_internal(m, name);
1595 	mDNS_Unlock(m);
1596 	return(d);
1597 	}
1598 
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)
1602 	{
1603 	DNSQuestion *q;
1604 	DomainAuthInfo **p = &m->AuthInfoList;
1605 	if (!info || !b64keydata) { LogMsg("mDNS_SetSecretForDomain: ERROR: info %p b64keydata %p", info, b64keydata); return(mStatus_BadParamErr); }
1606 
1607 	LogInfo("mDNS_SetSecretForDomain: domain %##s key %##s%s", domain->c, keyname->c, AutoTunnel ? " AutoTunnel" : "");
1608 
1609 	info->AutoTunnel = AutoTunnel;
1610 	AssignDomainName(&info->domain,  domain);
1611 	AssignDomainName(&info->keyname, keyname);
1612 	mDNS_snprintf(info->b64keydata, sizeof(info->b64keydata), "%s", b64keydata);
1613 
1614 	if (DNSDigest_ConstructHMACKeyfromBase64(info, b64keydata) < 0)
1615 		{
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);
1618 		}
1619 
1620 	// Don't clear deltime until after we've ascertained that b64keydata is valid
1621 	info->deltime = 0;
1622 
1623 	while (*p && (*p) != info) p=&(*p)->next;
1624 	if (*p) return(mStatus_AlreadyRegistered);
1625 
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;
1635 	*p = info;
1636 
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)
1639 		{
1640 		DomainAuthInfo *newinfo = GetAuthInfoForQuestion(m, q);
1641 		if (q->AuthInfo != newinfo)
1642 			{
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;
1647 			}
1648 		}
1649 
1650 	return(mStatus_NoError);
1651 	}
1652 
1653 // ***************************************************************************
1654 #if COMPILER_LIKES_PRAGMA_MARK
1655 #pragma mark -
1656 #pragma mark - NAT Traversal
1657 #endif
1658 
1659 mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info)
1660 	{
1661 	mStatus err = mStatus_NoError;
1662 
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))
1665 		{
1666 		union { NATAddrRequest NATAddrReq; NATPortMapRequest NATPortReq; } u = { { NATMAP_VERS, NATOp_AddrRequest } } ;
1667 		const mDNSu8 *end = (mDNSu8 *)&u + sizeof(NATAddrRequest);
1668 
1669 		if (info)			// For NATOp_MapUDP and NATOp_MapTCP, fill in additional fields
1670 			{
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);
1681 			}
1682 
1683 		err = mDNSPlatformSendUDP(m, (mDNSu8 *)&u, end, 0, mDNSNULL, &m->Router, NATPMPPort);
1684 
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_
1690 		}
1691 	return(err);
1692 	}
1693 
1694 mDNSexport void RecreateNATMappings(mDNS *const m)
1695 	{
1696 	NATTraversalInfo *n;
1697 	for (n = m->NATTraversals; n; n=n->next)
1698 		{
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_
1705 		}
1706 
1707 	m->NextScheduledNATOp = m->timenow;		// Need to send packets immediately
1708 	}
1709 
1710 mDNSexport void natTraversalHandleAddressReply(mDNS *const m, mDNSu16 err, mDNSv4Addr ExtAddr)
1711 	{
1712 	static mDNSu16 last_err = 0;
1713 
1714 	if (err)
1715 		{
1716 		if (err != last_err) LogMsg("Error getting external address %d", err);
1717 		ExtAddr = zerov4Addr;
1718 		}
1719 	else
1720 		{
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
1726 		}
1727 
1728 	if (!mDNSSameIPv4Address(m->ExternalAddress, ExtAddr))
1729 		{
1730 		m->ExternalAddress = ExtAddr;
1731 		RecreateNATMappings(m);		// Also sets NextScheduledNATOp for us
1732 		}
1733 
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
1739 
1740 	m->retryGetAddr = m->timenow + m->retryIntervalGetAddr;
1741 	if (m->NextScheduledNATOp - m->retryIntervalGetAddr > 0)
1742 		m->NextScheduledNATOp = m->retryIntervalGetAddr;
1743 
1744 	last_err = err;
1745 	}
1746 
1747 // Both places that call NATSetNextRenewalTime() update m->NextScheduledNATOp correctly afterwards
1748 mDNSlocal void NATSetNextRenewalTime(mDNS *const m, NATTraversalInfo *n)
1749 	{
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;
1754 	}
1755 
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)
1758 	{
1759 	const char *prot = n->Protocol == NATOp_MapUDP ? "UDP" : n->Protocol == NATOp_MapTCP ? "TCP" : "?";
1760 	(void)prot;
1761 	n->NewResult = err;
1762 	if (err || lease == 0 || mDNSIPPortIsZero(extport))
1763 		{
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;
1771 		}
1772 	else
1773 		{
1774 		if (lease > 999999999UL / mDNSPlatformOneSecond)
1775 			lease = 999999999UL / mDNSPlatformOneSecond;
1776 		n->ExpiryTime = NonZeroTime(m->timenow + lease * mDNSPlatformOneSecond);
1777 
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));
1781 
1782 		n->InterfaceID   = InterfaceID;
1783 		n->RequestedPort = extport;
1784 
1785 		LogInfo("natTraversalHandlePortMapReply: %p Response %s Port %5d External Port %5d lease %d",
1786 			n, prot, mDNSVal16(n->IntPort), mDNSVal16(extport), lease);
1787 
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
1790 		}
1791 	}
1792 
1793 // Must be called with the mDNS_Lock held
1794 mDNSexport mStatus mDNS_StartNATOperation_internal(mDNS *const m, NATTraversalInfo *traversal)
1795 	{
1796 	NATTraversalInfo **n;
1797 
1798 	LogInfo("mDNS_StartNATOperation_internal Protocol %d IntPort %d RequestedPort %d NATLease %d",
1799 		traversal->Protocol, mDNSVal16(traversal->IntPort), mDNSVal16(traversal->RequestedPort), traversal->NATLease);
1800 
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)
1803 		{
1804 		if (traversal == *n)
1805 			{
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);
1809 			}
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);
1816 		}
1817 
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;
1828 
1829 	// set default lease if necessary
1830 	if (!traversal->NATLease) traversal->NATLease = NATMAP_DEFAULT_LEASE;
1831 
1832 #ifdef _LEGACY_NAT_TRAVERSAL_
1833 	mDNSPlatformMemZero(&traversal->tcpInfo, sizeof(traversal->tcpInfo));
1834 #endif // _LEGACY_NAT_TRAVERSAL_
1835 
1836 	if (!m->NATTraversals)		// If this is our first NAT request, kick off an address request too
1837 		{
1838 		m->retryGetAddr         = m->timenow;
1839 		m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
1840 		}
1841 
1842 	m->NextScheduledNATOp = m->timenow;	// This will always trigger sending the packet ASAP, and generate client callback if necessary
1843 
1844 	*n = traversal;		// Append new NATTraversalInfo to the end of our list
1845 
1846 	return(mStatus_NoError);
1847 	}
1848 
1849 // Must be called with the mDNS_Lock held
1850 mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *traversal)
1851 	{
1852 	mDNSBool unmap = mDNStrue;
1853 	NATTraversalInfo *p;
1854 	NATTraversalInfo **ptr = &m->NATTraversals;
1855 
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
1858 	else
1859 		{
1860 		LogMsg("mDNS_StopNATOperation: NATTraversalInfo %p not found in list", traversal);
1861 		return(mStatus_BadReferenceErr);
1862 		}
1863 
1864 	LogInfo("mDNS_StopNATOperation_internal %d %d %d %d",
1865 		traversal->Protocol, mDNSVal16(traversal->IntPort), mDNSVal16(traversal->RequestedPort), traversal->NATLease);
1866 
1867 	if (m->CurrentNATTraversal == traversal)
1868 		m->CurrentNATTraversal = m->CurrentNATTraversal->next;
1869 
1870 	if (traversal->Protocol)
1871 		for (p = m->NATTraversals; p; p=p->next)
1872 			if (traversal->Protocol == p->Protocol && mDNSSameIPPort(traversal->IntPort, p->IntPort))
1873 				{
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);
1879 				unmap = mDNSfalse;
1880 				}
1881 
1882 	if (traversal->ExpiryTime && unmap)
1883 		{
1884 		traversal->NATLease = 0;
1885 		traversal->retryInterval = 0;
1886 		uDNS_SendNATMsg(m, traversal);
1887 		}
1888 
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_
1891 		{
1892 		mStatus err = LNT_UnmapPort(m, traversal);
1893 		if (err) LogMsg("Legacy NAT Traversal - unmap request failed with error %d", err);
1894 		}
1895 	#endif // _LEGACY_NAT_TRAVERSAL_
1896 
1897 	return(mStatus_NoError);
1898 	}
1899 
1900 mDNSexport mStatus mDNS_StartNATOperation(mDNS *m, NATTraversalInfo *traversal)
1901 	{
1902 	mStatus status;
1903 	mDNS_Lock(m);
1904 	status = mDNS_StartNATOperation_internal(m, traversal);
1905 	mDNS_Unlock(m);
1906 	return(status);
1907 	}
1908 
1909 mDNSexport mStatus mDNS_StopNATOperation(mDNS *m, NATTraversalInfo *traversal)
1910 	{
1911 	mStatus status;
1912 	mDNS_Lock(m);
1913 	status = mDNS_StopNATOperation_internal(m, traversal);
1914 	mDNS_Unlock(m);
1915 	return(status);
1916 	}
1917 
1918 // ***************************************************************************
1919 #if COMPILER_LIKES_PRAGMA_MARK
1920 #pragma mark -
1921 #pragma mark - Long-Lived Queries
1922 #endif
1923 
1924 // Lock must be held -- otherwise m->timenow is undefined
1925 mDNSlocal void StartLLQPolling(mDNS *const m, DNSQuestion *q)
1926 	{
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);
1936 #endif
1937 	}
1938 
1939 mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, const DNSQuestion *const question, const LLQOptData *const data)
1940 	{
1941 	AuthRecord rr;
1942 	ResourceRecord *opt = &rr.resrec;
1943 	rdataOPT *optRD;
1944 
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; }
1948 
1949 	// locate OptRR if it exists, set pointer to end
1950 	// !!!KRS implement me
1951 
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);
1957 
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; }
1963 
1964 	return ptr;
1965 	}
1966 
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.
1974 
1975 mDNSlocal mDNSu16 GetLLQEventPort(const mDNS *const m, const mDNSAddr *const dst)
1976 	{
1977 	mDNSAddr src;
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));
1981 	}
1982 
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)
1986 	{
1987 	mDNSu8 *responsePtr = m->omsg.data;
1988 	LLQOptData llqBuf;
1989 
1990 	if (q->ntries++ == kLLQ_MAX_TRIES)
1991 		{
1992 		LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s", kLLQ_MAX_TRIES, q->qname.c);
1993 		StartLLQPolling(m,q);
1994 		return;
1995 		}
1996 
1997 	if (!llq)		// Retransmission: need to make a new LLQOptData
1998 		{
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
2002 		llqBuf.id       = q->id;
2003 		llqBuf.llqlease = q->ReqLease;
2004 		llq = &llqBuf;
2005 		}
2006 
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);
2010 
2011 	// To simulate loss of challenge response packet, uncomment line below
2012 	//if (q->ntries == 1) return;
2013 
2014 	InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
2015 	responsePtr = putLLQ(&m->omsg, responsePtr, q, llq);
2016 	if (responsePtr)
2017 		{
2018 		mStatus err = mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, q->AuthInfo);
2019 		if (err)
2020 			{
2021 			LogMsg("sendChallengeResponse: mDNSSendDNSMessage%s failed: %d", q->tcp ? " (TCP)" : "", err);
2022 			if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; }
2023 			}
2024 		}
2025 	else StartLLQPolling(m,q);
2026 	}
2027 
2028 mDNSlocal void SetLLQTimer(mDNS *const m, DNSQuestion *const q, const LLQOptData *const llq)
2029 	{
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);
2037 	}
2038 
2039 mDNSlocal void recvSetupResponse(mDNS *const m, mDNSu8 rcode, DNSQuestion *const q, const LLQOptData *const llq)
2040 	{
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; }
2043 
2044 	if (llq->llqOp != kLLQOp_Setup)
2045 		{ LogMsg("ERROR: recvSetupResponse %##s (%s) - bad op %d", q->qname.c, DNSTypeName(q->qtype), llq->llqOp); return; }
2046 
2047 	if (llq->vers != kLLQ_Vers)
2048 		{ LogMsg("ERROR: recvSetupResponse %##s (%s) - bad vers %d", q->qname.c, DNSTypeName(q->qtype), llq->vers); return; }
2049 
2050 	if (q->state == LLQ_InitialRequest)
2051 		{
2052 		//LogInfo("Got LLQ_InitialRequest");
2053 
2054 		if (llq->err) { LogMsg("recvSetupResponse - received llq->err %d from server", llq->err); StartLLQPolling(m,q); return; }
2055 
2056 		if (q->ReqLease != llq->llqlease)
2057 			debugf("recvSetupResponse: requested lease %lu, granted lease %lu", q->ReqLease, llq->llqlease);
2058 
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);
2062 
2063 		// update state
2064 		q->state  = LLQ_SecondaryRequest;
2065 		q->id     = llq->id;
2066 		q->ntries = 0; // first attempt to send response
2067 		sendChallengeResponse(m, q, llq);
2068 		}
2069 	else if (q->state == LLQ_SecondaryRequest)
2070 		{
2071 		//LogInfo("Got LLQ_SecondaryRequest");
2072 
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.
2077 		if (q->AuthInfo)
2078 			{
2079 			LogInfo("Private LLQ_SecondaryRequest; copying id %08X%08X", llq->id.l[0], llq->id.l[1]);
2080 			q->id = llq->id;
2081 			}
2082 
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;
2087 		q->ntries        = 0;
2088 		SetLLQTimer(m, q, llq);
2089 #if APPLE_OSX_mDNSResponder
2090 		UpdateAutoTunnelDomainStatuses(m);
2091 #endif
2092 		}
2093 	}
2094 
2095 mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport)
2096 	{
2097 	DNSQuestion pktQ, *q;
2098 	if (msg->h.numQuestions && getQuestion(msg, msg->data, end, 0, &pktQ))
2099 		{
2100 		const rdataOPT *opt = GetLLQOptData(m, msg, end);
2101 
2102 		for (q = m->Questions; q; q = q->next)
2103 			{
2104 			if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->qtype == pktQ.qtype && q->qnamehash == pktQ.qnamehash && SameDomainName(&q->qname, &pktQ.qname))
2105 				{
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))
2111 					{
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
2120 					}
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))
2123 					{
2124 					mDNSu8 *ackEnd;
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;
2132 					}
2133 				if (opt && mDNSSameOpaque16(msg->h.id, q->TargetQID))
2134 					{
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)
2136 						{
2137 						if (opt->u.llq.err != LLQErr_NoError) LogMsg("recvRefreshReply: received error %d from server", opt->u.llq.err);
2138 						else
2139 							{
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);
2146 							q->ntries = 0;
2147 							}
2148 						m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
2149 						return uDNS_LLQ_Ignore;
2150 						}
2151 					if (q->state < LLQ_Established && mDNSSameAddress(srcaddr, &q->servAddr))
2152 						{
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);
2164 						}
2165 					}
2166 				}
2167 			}
2168 		m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
2169 		}
2170 	return uDNS_LLQ_Not;
2171 	}
2172 
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; /* ... */ };
2175 
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)
2179 	{
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 =
2185 		q                 ? &q           ->tcp :
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);
2191 
2192 	if (err) goto exit;
2193 
2194 	if (ConnectionEstablished)
2195 		{
2196 		mDNSu8    *end = ((mDNSu8*) &tcpInfo->request) + tcpInfo->requestLen;
2197 		DomainAuthInfo *AuthInfo;
2198 
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;
2209 
2210 		AuthInfo =  tcpInfo->srs ? GetAuthInfoForName(m, tcpInfo->srs->RR_SRV.resrec.name) :
2211 					tcpInfo->rr  ? GetAuthInfoForName(m, tcpInfo->rr->resrec.name)         : mDNSNULL;
2212 
2213 		// connection is established - send the message
2214 		if (q && q->LongLived && q->state == LLQ_Established)
2215 			{
2216 			end = ((mDNSu8*) &tcpInfo->request) + tcpInfo->requestLen;
2217 			}
2218 		else if (q && q->LongLived && q->state != LLQ_Poll && !mDNSIPPortIsZero(m->LLQNAT.ExternalPort) && !mDNSIPPortIsZero(q->servPort))
2219 			{
2220 			// Notes:
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
2235 			}
2236 		else if (q)
2237 			{
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
2241 			}
2242 
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; }
2245 
2246 		// Record time we sent this question
2247 		if (q)
2248 			{
2249 			mDNS_Lock(m);
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);
2254 			mDNS_Unlock(m);
2255 			}
2256 		}
2257 	else
2258 		{
2259 		long n;
2260 		if (tcpInfo->nread < 2)			// First read the two-byte length preceeding the DNS message
2261 			{
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; }
2265 			else if (closed)
2266 				{
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;
2273 				goto exit;
2274 				}
2275 
2276 			tcpInfo->nread += n;
2277 			if (tcpInfo->nread < 2) goto exit;
2278 
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; }
2282 
2283 			tcpInfo->reply = mDNSPlatformMemAllocate(tcpInfo->replylen);
2284 			if (!tcpInfo->reply) { LogMsg("ERROR: tcpCallback - malloc failed"); err = mStatus_NoMemoryErr; goto exit; }
2285 			}
2286 
2287 		n = mDNSPlatformReadTCP(sock, ((char *)tcpInfo->reply) + (tcpInfo->nread - 2), tcpInfo->replylen - (tcpInfo->nread - 2), &closed);
2288 
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; }
2291 
2292 		tcpInfo->nread += n;
2293 
2294 		if ((tcpInfo->nread - 2) == tcpInfo->replylen)
2295 			{
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
2303 			tcpInfo->nread    = 0;
2304 			tcpInfo->replylen = 0;
2305 
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
2309 			if (backpointer)
2310 				if (!q || !q->LongLived || m->SleepState)
2311 					{ *backpointer = mDNSNULL; DisposeTCPConn(tcpInfo); }
2312 
2313 			if (rr && rr->resrec.RecordType == kDNSRecordTypeDeregistering)
2314 				{
2315 				mDNS_Lock(m);
2316 				LogInfo("tcpCallback: CompleteDeregistration %s", ARDisplayString(m, rr));
2317 				CompleteDeregistration(m, rr);		// Don't touch rr after this
2318 				mDNS_Unlock(m);
2319 				}
2320 			else
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
2323 
2324 			mDNSPlatformMemFree(reply);
2325 			return;
2326 			}
2327 		}
2328 
2329 exit:
2330 
2331 	if (err)
2332 		{
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;
2336 
2337 		mDNS_Lock(m);		// Need to grab the lock to get m->timenow
2338 
2339 		if (q)
2340 			{
2341 			if (q->ThisQInterval == 0 || q->LastQTime + q->ThisQInterval - m->timenow > MAX_UCAST_POLL_INTERVAL)
2342 				{
2343 				q->LastQTime     = m->timenow;
2344 				q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
2345 				SetNextQueryTime(m, q);
2346 				}
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)
2350 				{
2351 				if (q->LongLived && q->state != LLQ_Poll) StartLLQPolling(m, q);
2352 				}
2353 			}
2354 
2355 		if (tcpInfo->rr) SetRecordRetry(m, tcpInfo->rr, mStatus_NoError);
2356 
2357 		if (tcpInfo->srs) SetRecordRetry(m, &tcpInfo->srs->RR_SRV, mStatus_NoError);
2358 
2359 		mDNS_Unlock(m);
2360 
2361 		DisposeTCPConn(tcpInfo);
2362 		}
2363 	}
2364 
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)
2368 	{
2369 	mStatus err;
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));
2374 
2375 	info->m          = m;
2376 	info->sock       = mDNSPlatformTCPSocket(m, flags, &srcport);
2377 	info->requestLen = 0;
2378 	info->question   = question;
2379 	info->srs        = srs;
2380 	info->rr         = rr;
2381 	info->Addr       = *Addr;
2382 	info->Port       = Port;
2383 	info->reply      = mDNSNULL;
2384 	info->replylen   = 0;
2385 	info->nread      = 0;
2386 	info->numReplies = 0;
2387 
2388 	if (msg)
2389 		{
2390 		info->requestLen = (int) (end - ((mDNSu8*)msg));
2391 		mDNSPlatformMemCopy(&info->request, msg, info->requestLen);
2392 		}
2393 
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);
2396 
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.
2402 
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); }
2406 	return(info);
2407 	}
2408 
2409 mDNSexport void DisposeTCPConn(struct tcpInfo_t *tcp)
2410 	{
2411 	mDNSPlatformTCPCloseConnection(tcp->sock);
2412 	if (tcp->reply) mDNSPlatformMemFree(tcp->reply);
2413 	mDNSPlatformMemFree(tcp);
2414 	}
2415 
2416 // Lock must be held
2417 mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q)
2418 	{
2419 	if (mDNSIPv4AddressIsOnes(m->LLQNAT.ExternalAddress))
2420 		{
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);
2425 		return;
2426 		}
2427 
2428 	if (mDNSIPPortIsZero(m->LLQNAT.ExternalPort))
2429 		{
2430 		LogInfo("startLLQHandshake: Cannot receive inbound packets; will poll for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
2431 		StartLLQPolling(m, q);
2432 		return;
2433 		}
2434 
2435 	if (mDNSIPPortIsZero(q->servPort))
2436 		{
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);
2445 		return;
2446 		}
2447 
2448 	if (q->AuthInfo)
2449 		{
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);
2453 		if (!q->tcp)
2454 			q->ThisQInterval = mDNSPlatformOneSecond * 5;	// If TCP failed (transient networking glitch) try again in five seconds
2455 		else
2456 			{
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;
2460 			}
2461 		q->LastQTime     = m->timenow;
2462 		SetNextQueryTime(m, q);
2463 		}
2464 	else
2465 		{
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));
2470 
2471 		if (q->ntries++ >= kLLQ_MAX_TRIES)
2472 			{
2473 			LogMsg("startLLQHandshake: %d failed attempts for LLQ %##s Polling.", kLLQ_MAX_TRIES, q->qname.c);
2474 			StartLLQPolling(m, q);
2475 			}
2476 		else
2477 			{
2478 			mDNSu8 *end;
2479 			LLQOptData llqData;
2480 
2481 			// set llq rdata
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;
2487 
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; }
2491 
2492 			mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, mDNSNULL, mDNSNULL);
2493 
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);
2500 			}
2501 		}
2502 	}
2503 
2504 // forward declaration so GetServiceTarget can do reverse lookup if needed
2505 mDNSlocal void GetStaticHostname(mDNS *m);
2506 
2507 mDNSexport const domainname *GetServiceTarget(mDNS *m, AuthRecord *const rr)
2508 	{
2509 	debugf("GetServiceTarget %##s", rr->resrec.name->c);
2510 
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);
2513 	else
2514 		{
2515 #if APPLE_OSX_mDNSResponder
2516 		DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name);
2517 		if (AuthInfo && AuthInfo->AutoTunnel)
2518 			{
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);
2525 			}
2526 		else
2527 #endif // APPLE_OSX_mDNSResponder
2528 			{
2529 			const int srvcount = CountLabels(rr->resrec.name);
2530 			HostnameInfo *besthi = mDNSNULL, *hi;
2531 			int best = 0;
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)
2535 					{
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; }
2540 					}
2541 
2542 			if (besthi) return(&besthi->fqdn);
2543 			}
2544 		if (m->StaticHostname.c[0]) return(&m->StaticHostname);
2545 		else GetStaticHostname(m); // asynchronously do reverse lookup for primary IPv4 address
2546 		return(mDNSNULL);
2547 		}
2548 	}
2549 
2550 // Called with lock held
2551 mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs)
2552 	{
2553 	mDNSu8 *ptr = m->omsg.data;
2554 	mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
2555 	mDNSOpaque16 id;
2556 	mStatus err = mStatus_NoError;
2557 	const domainname *target;
2558 	mDNSu32 i;
2559 
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);
2562 
2563 	if (mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4))	// Don't know our UpdateServer yet
2564 		{
2565 		srs->RR_SRV.LastAPTime = m->timenow;
2566 		if (srs->RR_SRV.ThisAPInterval < mDNSPlatformOneSecond * 5)
2567 			srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5;
2568 		return;
2569 		}
2570 
2571 	if (srs->state == regState_Registered) srs->state = regState_Refresh;
2572 
2573 	id = mDNS_NewMessageID(m);
2574 	InitializeDNSMessage(&m->omsg.h, id, UpdateReqFlags);
2575 
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
2579 
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;
2583 
2584 	// construct update packet
2585 	// set zone
2586 	ptr = putZone(&m->omsg, ptr, end, &srs->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
2587 	if (!ptr) { err = mStatus_UnknownErr; goto exit; }
2588 
2589 	if (srs->TestForSelfConflict)
2590 		{
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; }
2594 		}
2595 
2596 	else if (srs->state != regState_Refresh && srs->state != regState_UpdatePending)
2597 		{
2598 		// use SRV name for prereq
2599 		//ptr = putPrereqNameNotInUse(srs->RR_SRV.resrec.name, &m->omsg, ptr, end);
2600 
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; }
2605 		}
2606 
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; }
2609 
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; }
2612 
2613 	if (srs->state == regState_UpdatePending) // we're updating the txt record
2614 		{
2615 		AuthRecord *txt = &srs->RR_TXT;
2616 		// delete old RData
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
2619 
2620 		// add new 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; }
2623 		}
2624 	else
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; }
2626 
2627 	target = GetServiceTarget(m, &srs->RR_SRV);
2628 	if (!target || target->c[0] == 0)
2629 		{
2630 		debugf("SendServiceRegistration - no target for %##s", srs->RR_SRV.resrec.name->c);
2631 		srs->state = regState_NoTarget;
2632 		return;
2633 		}
2634 
2635 	if (!SameDomainName(target, &srs->RR_SRV.resrec.rdata->u.srv.target))
2636 		{
2637 		AssignDomainName(&srs->RR_SRV.resrec.rdata->u.srv.target, target);
2638 		SetNewRData(&srs->RR_SRV.resrec, mDNSNULL, 0);		// Update rdlength, rdestimate, rdatahash
2639 		}
2640 
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; }
2643 
2644 	if (srs->srs_uselease)
2645 		{ ptr = putUpdateLease(&m->omsg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) { err = mStatus_UnknownErr; goto exit; } }
2646 
2647 	if (srs->state != regState_Refresh && srs->state != regState_DeregDeferred && srs->state != regState_UpdatePending)
2648 		srs->state = regState_Pending;
2649 
2650 	srs->id = id;
2651 
2652 	if (srs->Private)
2653 		{
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;
2659 		}
2660 	else
2661 		{
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);
2664 		}
2665 
2666 	SetRecordRetry(m, &srs->RR_SRV, err);
2667 	return;
2668 
2669 exit:
2670 	if (err)
2671 		{
2672 		LogMsg("SendServiceRegistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err, srs->RR_SRV.resrec.name->c);
2673 		unlinkSRS(m, srs);
2674 		srs->state = regState_Unregistered;
2675 
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.
2681 		}
2682 	}
2683 
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";
2686 
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";
2690 
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*)"")
2695 
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);
2699 
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)
2702 	{
2703 	ZoneData *zd = (ZoneData*)question->QuestionContext;
2704 
2705 	debugf("GetZoneData_QuestionCallback: %s %s", AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
2706 
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
2710 
2711 	if (answer->rrtype == kDNSType_SOA)
2712 		{
2713 		debugf("GetZoneData GOT SOA %s", RRDisplayString(m, answer));
2714 		mDNS_StopQuery(m, question);
2715 		if (answer->rdlength)
2716 			{
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);
2721 			}
2722 		else if (zd->CurrentSOA->c[0])
2723 			{
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);
2727 			}
2728 		else
2729 			{
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);
2733 			}
2734 		}
2735 	else if (answer->rrtype == kDNSType_SRV)
2736 		{
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
2742 #if 0
2743 		if (!answer->rdlength && zd->ZonePrivate && zd->ZoneService != ZoneServiceQuery)
2744 			{
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
2747 			}
2748 		else
2749 #endif
2750 			{
2751 			if (answer->rdlength)
2752 				{
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);
2757 				}
2758 			else
2759 				{
2760 				zd->ZonePrivate = mDNSfalse;
2761 				zd->Host.c[0] = 0;
2762 				zd->Port = zeroIPPort;
2763 				zd->Addr = zeroAddr;
2764 				zd->ZoneDataCallback(m, mStatus_NoError, zd);
2765 				mDNSPlatformMemFree(zd);
2766 				}
2767 			}
2768 		}
2769 	else if (answer->rrtype == kDNSType_A)
2770 		{
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
2779 #if 0
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;
2784 #endif
2785 		zd->ZoneDataCallback(m, mStatus_NoError, zd);
2786 		mDNSPlatformMemFree(zd);
2787 		}
2788 	}
2789 
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)
2792 	{
2793 	if (qtype == kDNSType_SRV)
2794 		{
2795 		AssignDomainName(&zd->question.qname, ZoneDataSRV(zd));
2796 		AppendDomainName(&zd->question.qname, &zd->ZoneName);
2797 		debugf("lookupDNSPort %##s", zd->question.qname.c);
2798 		}
2799 
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;
2812 
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));
2815 	}
2816 
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)
2819 	{
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;
2829 	zd->ZoneClass        = 0;
2830 	zd->Host.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;
2836 
2837 	zd->question.QuestionContext = zd;
2838 	AssignDomainName(&zd->question.qname, zd->CurrentSOA);
2839 
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();
2843 
2844 	return zd;
2845 	}
2846 
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
2853 	{
2854 	if (q->QuestionCallback == GetZoneData_QuestionCallback) return(mDNSNULL);
2855 	if (q->qtype            == kDNSType_SOA                ) return(mDNSNULL);
2856 	return(GetAuthInfoForName_internal(m, &q->qname));
2857 	}
2858 
2859 // ***************************************************************************
2860 #if COMPILER_LIKES_PRAGMA_MARK
2861 #pragma mark - host name and interface management
2862 #endif
2863 
2864 // Called in normal client context (lock not held)
2865 mDNSlocal void CompleteSRVNatMap(mDNS *m, NATTraversalInfo *n)
2866 	{
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);
2869 
2870 	if (!srs) { LogMsg("CompleteSRVNatMap called with unknown ServiceRecordSet object"); return; }
2871 	if (!n->NATLease) return;
2872 
2873 	mDNS_Lock(m);
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
2876 	else
2877 		{
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);
2883 		}
2884 	mDNS_Unlock(m);
2885 	}
2886 
2887 mDNSlocal void StartSRVNatMap(mDNS *m, ServiceRecordSet *srs)
2888 	{
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; }
2894 
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);
2904 	}
2905 
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)
2908 	{
2909 	ServiceRecordSet *srs = (ServiceRecordSet *)zoneData->ZoneDataContext;
2910 
2911 	if (m->mDNS_busy != m->mDNS_reentrancy)
2912 		LogMsg("ServiceRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
2913 
2914 	if (!srs->RR_SRV.resrec.rdata)
2915 		{ LogMsg("ServiceRegistrationGotZoneData: ERROR: srs->RR_SRV.resrec.rdata is NULL"); return; }
2916 
2917 	srs->srs_nta = mDNSNULL;
2918 
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;
2922 
2923 	if (err || !zoneData) return;
2924 
2925 	if (mDNSIPPortIsZero(zoneData->Port) || mDNSAddressIsZero(&zoneData->Addr)) return;
2926 
2927 	// cache zone data
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;
2933 
2934 	srs->RR_SRV.LastAPTime     = m->timenow;
2935 	srs->RR_SRV.ThisAPInterval = 0;
2936 
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);
2941 
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)
2949 		{
2950 		srs->state = regState_NATMap;
2951 		debugf("ServiceRegistrationGotZoneData StartSRVNatMap");
2952 		StartSRVNatMap(m, srs);
2953 		}
2954 	else
2955 		{
2956 		mDNS_Lock(m);
2957 		SendServiceRegistration(m, srs);
2958 		mDNS_Unlock(m);
2959 		}
2960 	}
2961 
2962 mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
2963 	{
2964 	mDNSOpaque16 id;
2965 	mDNSu8 *ptr = m->omsg.data;
2966 	mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
2967 	mStatus err = mStatus_UnknownErr;
2968 	mDNSu32 i;
2969 
2970 	if (mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4))	// Don't know our UpdateServer yet
2971 		{
2972 		srs->RR_SRV.LastAPTime = m->timenow;
2973 		if (srs->RR_SRV.ThisAPInterval < mDNSPlatformOneSecond * 5)
2974 			srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5;
2975 		return;
2976 		}
2977 
2978 	id = mDNS_NewMessageID(m);
2979 	InitializeDNSMessage(&m->omsg.h, id, UpdateReqFlags);
2980 
2981 	// put zone
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; }
2984 
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; }
2989 
2990 	srs->id    = id;
2991 	srs->state = regState_DeregPending;
2992 	srs->RR_SRV.expire = 0;		// Indicate that we have no active registration any more
2993 
2994 	if (srs->Private)
2995 		{
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;
3002 		}
3003 	else
3004 		{
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; }
3007 		}
3008 
3009 	SetRecordRetry(m, &srs->RR_SRV, err);
3010 	return;
3011 
3012 exit:
3013 	if (err)
3014 		{
3015 		LogMsg("SendServiceDeregistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err, srs->RR_SRV.resrec.name->c);
3016 		unlinkSRS(m, srs);
3017 		srs->state = regState_Unregistered;
3018 		}
3019 	}
3020 
3021 // Called with lock held
3022 mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs)
3023 	{
3024 	ExtraResourceRecord *e;
3025 
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
3030 
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);
3036 
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
3041 
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);
3047 
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);
3051 
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);
3054 
3055 	if (!TargetChanged && !NATChanged) return;
3056 
3057 	switch(srs->state)
3058 		{
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
3067 			return;
3068 
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;
3074 			return;
3075 
3076 		case regState_NATError:
3077 			if (!NATChanged) return;
3078 			// if nat changed, register if we have a target (below)
3079 
3080 		case regState_NoTarget:
3081 			if (newtarget->c[0])
3082 				{
3083 				debugf("UpdateSRV: %s service %##s", HaveZoneData ? (NATChanged && NowNeedNATMAP ? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs->RR_SRV.resrec.name->c);
3084 				if (!HaveZoneData)
3085 					{
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);
3089 					}
3090 				else
3091 					{
3092 					if (srs->NATinfo.clientContext && (NATChanged || !NowNeedNATMAP))
3093 						{
3094 						mDNS_StopNATOperation_internal(m, &srs->NATinfo);
3095 						srs->NATinfo.clientContext = mDNSNULL;
3096 						}
3097 					if (NATChanged && NowNeedNATMAP && srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP)
3098 						{ srs->state = regState_NATMap; StartSRVNatMap(m, srs); }
3099 					else SendServiceRegistration(m, srs);
3100 					}
3101 				}
3102 			return;
3103 
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);
3110 			return;
3111 
3112 		default: LogMsg("UpdateSRV: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c);
3113 		}
3114 	}
3115 
3116 // Called with lock held
3117 mDNSlocal void UpdateSRVRecords(mDNS *m)
3118 	{
3119 	debugf("UpdateSRVRecords%s", m->SleepState ? " (ignored due to SleepState)" : "");
3120 	if (m->SleepState) return;
3121 
3122 	if (CurrentServiceRecordSet)
3123 		LogMsg("UpdateSRVRecords ERROR CurrentServiceRecordSet already set");
3124 	CurrentServiceRecordSet = m->ServiceRegistrations;
3125 
3126 	while (CurrentServiceRecordSet)
3127 		{
3128 		ServiceRecordSet *s = CurrentServiceRecordSet;
3129 		CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next;
3130 		UpdateSRV(m, s);
3131 		}
3132 
3133 	mDNS_DropLockBeforeCallback();		// mDNS_SetFQDN expects to be called without the lock held, so we emulate that here
3134 	mDNS_SetFQDN(m);
3135 	mDNS_ReclaimLockAfterCallback();
3136 	}
3137 
3138 // Forward reference: AdvertiseHostname references HostnameCallback, and HostnameCallback calls AdvertiseHostname
3139 mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
3140 
3141 // Called in normal client context (lock not held)
3142 mDNSlocal void hostnameGetPublicAddressCallback(mDNS *m, NATTraversalInfo *n)
3143 	{
3144 	HostnameInfo *h = (HostnameInfo *)n->clientContext;
3145 
3146 	if (!h) { LogMsg("RegisterHostnameRecord: registration cancelled"); return; }
3147 
3148 	if (!n->Result)
3149 		{
3150 		if (mDNSIPv4AddressIsZero(n->ExternalAddress) || mDNSv4AddrIsRFC1918(&n->ExternalAddress)) return;
3151 
3152 		if (h->arv4.resrec.RecordType)
3153 			{
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
3158 			}
3159 		else
3160 			{
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);
3165 			}
3166 		}
3167 	}
3168 
3169 // register record or begin NAT traversal
3170 mDNSlocal void AdvertiseHostname(mDNS *m, HostnameInfo *h)
3171 	{
3172 	if (!mDNSIPv4AddressIsZero(m->AdvertisedV4.ip.v4) && h->arv4.resrec.RecordType == kDNSRecordTypeUnregistered)
3173 		{
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))
3179 			{
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);
3189 			}
3190 		else
3191 			{
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);
3195 			}
3196 		}
3197 
3198 	if (!mDNSIPv6AddressIsZero(m->AdvertisedV6.ip.v6) && h->arv6.resrec.RecordType == kDNSRecordTypeUnregistered)
3199 		{
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);
3206 		}
3207 	}
3208 
3209 mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
3210 	{
3211 	HostnameInfo *hi = (HostnameInfo *)rr->RecordContext;
3212 
3213 	if (result == mStatus_MemFree)
3214 		{
3215 		if (hi)
3216 			{
3217 			// If we're still in the Hostnames list, update to new address
3218 			HostnameInfo *i;
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; }
3223 
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)
3227 				{
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
3231 				}
3232 			}
3233 		return;
3234 		}
3235 
3236 	if (result)
3237 		{
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);
3241 		else
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!");
3245 
3246 		if (hi->arv4.state == regState_Unregistered &&
3247 			hi->arv6.state == regState_Unregistered)
3248 			{
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;
3254 			}
3255 		return;
3256 		}
3257 
3258 	// register any pending services that require a target
3259 	mDNS_Lock(m);
3260 	UpdateSRVRecords(m);
3261 	mDNS_Unlock(m);
3262 
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);
3267 	else
3268 		LogInfo("Registered hostname %##s IP %.16a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
3269 
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;
3274 	}
3275 
3276 mDNSlocal void FoundStaticHostname(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
3277 	{
3278 	const domainname *pktname = &answer->rdata->u.name;
3279 	domainname *storedname = &m->StaticHostname;
3280 	HostnameInfo *h = m->Hostnames;
3281 
3282 	(void)question;
3283 
3284 	debugf("FoundStaticHostname: %##s -> %##s (%s)", question->qname.c, answer->rdata->u.name.c, AddRecord ? "added" : "removed");
3285 	if (AddRecord && !SameDomainName(pktname, storedname))
3286 		{
3287 		AssignDomainName(storedname, pktname);
3288 		while (h)
3289 			{
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)
3292 				{
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);
3295 				return;
3296 				}
3297 			h = h->next;
3298 			}
3299 		mDNS_Lock(m);
3300 		UpdateSRVRecords(m);
3301 		mDNS_Unlock(m);
3302 		}
3303 	else if (!AddRecord && SameDomainName(pktname, storedname))
3304 		{
3305 		mDNS_Lock(m);
3306 		storedname->c[0] = 0;
3307 		UpdateSRVRecords(m);
3308 		mDNS_Unlock(m);
3309 		}
3310 	}
3311 
3312 // Called with lock held
3313 mDNSlocal void GetStaticHostname(mDNS *m)
3314 	{
3315 	char buf[MAX_REVERSE_MAPPING_NAME_V4];
3316 	DNSQuestion *q = &m->ReverseMap;
3317 	mDNSu8 *ip = m->AdvertisedV4.ip.v4.b;
3318 	mStatus err;
3319 
3320 	if (m->ReverseMap.ThisQInterval != -1) return; // already running
3321 	if (mDNSIPv4AddressIsZero(m->AdvertisedV4.ip.v4)) return;
3322 
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; }
3327 
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;
3338 
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);
3342 	}
3343 
3344 mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
3345    {
3346 	HostnameInfo **ptr = &m->Hostnames;
3347 
3348 	LogInfo("mDNS_AddDynDNSHostName %##s", fqdn);
3349 
3350 	while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next;
3351 	if (*ptr) { LogMsg("DynDNSHostName %##s already in list", fqdn->c); return; }
3352 
3353 	// allocate and format new address record
3354 	*ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
3355 	if (!*ptr) { LogMsg("ERROR: mDNS_AddDynDNSHostName - malloc"); return; }
3356 
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;
3363 
3364 	AdvertiseHostname(m, *ptr);
3365 	}
3366 
3367 mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn)
3368 	{
3369 	HostnameInfo **ptr = &m->Hostnames;
3370 
3371 	LogInfo("mDNS_RemoveDynDNSHostName %##s", fqdn);
3372 
3373 	while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next;
3374 	if (!*ptr) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn->c);
3375 	else
3376 		{
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
3388 		}
3389 	UpdateSRVRecords(m);
3390 	}
3391 
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)
3395 	{
3396 	mDNSBool v4Changed, v6Changed, RouterChanged;
3397 
3398 	if (m->mDNS_busy != m->mDNS_reentrancy)
3399 		LogMsg("mDNS_SetPrimaryInterfaceInfo: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
3400 
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; }
3404 
3405 	mDNS_Lock(m);
3406 
3407 	if (v4addr && !mDNSv4AddressIsLinkLocal(&v4addr->ip.v4)) v6addr = mDNSNULL;
3408 
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);
3412 
3413 	if (v4addr && (v4Changed || RouterChanged))
3414 		debugf("mDNS_SetPrimaryInterfaceInfo: address changed from %#a to %#a", &m->AdvertisedV4, v4addr);
3415 
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
3420 
3421 	if (v4Changed || RouterChanged || v6Changed)
3422 		{
3423 		HostnameInfo *i;
3424 		LogInfo("mDNS_SetPrimaryInterfaceInfo: %s%s%s%#a %#a %#a",
3425 			v4Changed     ? "v4Changed "     : "",
3426 			RouterChanged ? "RouterChanged " : "",
3427 			v6Changed     ? "v6Changed "     : "", v4addr, v6addr, router);
3428 
3429 		for (i = m->Hostnames; i; i = i->next)
3430 			{
3431 			LogInfo("mDNS_SetPrimaryInterfaceInfo updating host name registrations for %##s", i->fqdn.c);
3432 
3433 			if (i->arv4.resrec.RecordType > kDNSRecordTypeDeregistering &&
3434 				!mDNSSameIPv4Address(i->arv4.resrec.rdata->u.ipv4, m->AdvertisedV4.ip.v4))
3435 				{
3436 				LogInfo("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m, &i->arv4));
3437 				mDNS_Deregister_internal(m, &i->arv4, mDNS_Dereg_normal);
3438 				}
3439 
3440 			if (i->arv6.resrec.RecordType > kDNSRecordTypeDeregistering &&
3441 				!mDNSSameIPv6Address(i->arv6.resrec.rdata->u.ipv6, m->AdvertisedV6.ip.v6))
3442 				{
3443 				LogInfo("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m, &i->arv6));
3444 				mDNS_Deregister_internal(m, &i->arv6, mDNS_Dereg_normal);
3445 				}
3446 
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);
3450 			}
3451 
3452 		if (v4Changed || RouterChanged)
3453 			{
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_
3460 			LNT_ClearState(m);
3461 #endif // _LEGACY_NAT_TRAVERSAL_
3462 			}
3463 
3464 		if (m->ReverseMap.ThisQInterval != -1) mDNS_StopQuery_internal(m, &m->ReverseMap);
3465 		m->StaticHostname.c[0] = 0;
3466 
3467 		UpdateSRVRecords(m); // Will call GetStaticHostname if needed
3468 
3469 #if APPLE_OSX_mDNSResponder
3470 		if (RouterChanged)	uuid_generate(m->asl_uuid);
3471 		UpdateAutoTunnelDomainStatuses(m);
3472 #endif
3473 		}
3474 
3475 	mDNS_Unlock(m);
3476 	}
3477 
3478 // ***************************************************************************
3479 #if COMPILER_LIKES_PRAGMA_MARK
3480 #pragma mark - Incoming Message Processing
3481 #endif
3482 
3483 mDNSlocal mStatus ParseTSIGError(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const domainname *const displayname)
3484 	{
3485 	const mDNSu8 *ptr;
3486 	mStatus err = mStatus_NoError;
3487 	int i;
3488 
3489 	ptr = LocateAdditionals(msg, end);
3490 	if (!ptr) goto finish;
3491 
3492 	for (i = 0; i < msg->h.numAdditionals; i++)
3493 		{
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)
3497 			{
3498 			mDNSu32 macsize;
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;
3512 			rd += macsize;
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
3517 
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; }
3522 			goto finish;
3523 			}
3524 		m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
3525 		}
3526 
3527 	finish:
3528 	m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
3529 	return err;
3530 	}
3531 
3532 mDNSlocal mStatus checkUpdateResult(mDNS *const m, const domainname *const displayname, const mDNSu8 rcode, const DNSMessage *const msg, const mDNSu8 *const end)
3533 	{
3534 	(void)msg;	// currently unused, needed for TSIG errors
3535 	if (!rcode) return mStatus_NoError;
3536 	else if (rcode == kDNSFlag1_RC_YXDomain)
3537 		{
3538 		debugf("name in use: %##s", displayname->c);
3539 		return mStatus_NameConflict;
3540 		}
3541 	else if (rcode == kDNSFlag1_RC_Refused)
3542 		{
3543 		LogMsg("Update %##s refused", displayname->c);
3544 		return mStatus_Refused;
3545 		}
3546 	else if (rcode == kDNSFlag1_RC_NXRRSet)
3547 		{
3548 		LogMsg("Reregister refused (NXRRSET): %##s", displayname->c);
3549 		return mStatus_NoSuchRecord;
3550 		}
3551 	else if (rcode == kDNSFlag1_RC_NotAuth)
3552 		{
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);
3555 		if (!tsigerr)
3556 			{
3557 			LogMsg("Permission denied (NOAUTH): %##s", displayname->c);
3558 			return mStatus_UnknownErr;
3559 			}
3560 		else return tsigerr;
3561 		}
3562 	else if (rcode == kDNSFlag1_RC_FormErr)
3563 		{
3564 		mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
3565 		if (!tsigerr)
3566 			{
3567 			LogMsg("Format Error: %##s", displayname->c);
3568 			return mStatus_UnknownErr;
3569 			}
3570 		else return tsigerr;
3571 		}
3572 	else
3573 		{
3574 		LogMsg("Update %##s failed with rcode %d", displayname->c, rcode);
3575 		return mStatus_UnknownErr;
3576 		}
3577 	}
3578 
3579 // Called with lock held
3580 mDNSlocal void SendRecordRegistration(mDNS *const m, AuthRecord *rr)
3581 	{
3582 	mDNSu8 *ptr = m->omsg.data;
3583 	mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
3584 	mStatus err = mStatus_UnknownErr;
3585 
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);
3588 
3589 	if (mDNSIPv4AddressIsZero(rr->UpdateServer.ip.v4))	// Don't know our UpdateServer yet
3590 		{
3591 		rr->LastAPTime = m->timenow;
3592 		if (rr->ThisAPInterval < mDNSPlatformOneSecond * 5)
3593 			rr->ThisAPInterval = mDNSPlatformOneSecond * 5;
3594 		return;
3595 		}
3596 
3597 	rr->RequireGoodbye = mDNStrue;
3598 	rr->updateid = mDNS_NewMessageID(m);
3599 	InitializeDNSMessage(&m->omsg.h, rr->updateid, UpdateReqFlags);
3600 
3601 	// set zone
3602 	ptr = putZone(&m->omsg, ptr, end, rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
3603 	if (!ptr) { err = mStatus_UnknownErr; goto exit; }
3604 
3605 	if (rr->state == regState_UpdatePending)
3606 		{
3607 		// delete old RData
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
3610 
3611 		// add new 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; }
3614 		}
3615 
3616 	else
3617 		{
3618 		if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
3619 			{
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; }
3623 			}
3624 
3625 		else if (rr->resrec.RecordType != kDNSRecordTypeShared)
3626 			{
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; }
3630 			}
3631 
3632 		ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl);
3633 		if (!ptr) { err = mStatus_UnknownErr; goto exit; }
3634 		}
3635 
3636 	if (rr->uselease)
3637 		{
3638 		ptr = putUpdateLease(&m->omsg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) { err = mStatus_UnknownErr; goto exit; }
3639 		}
3640 
3641 	if (rr->Private)
3642 		{
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;
3649 		}
3650 	else
3651 		{
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);
3654 		}
3655 
3656 	SetRecordRetry(m, rr, err);
3657 
3658 	if (rr->state != regState_Refresh && rr->state != regState_DeregDeferred && rr->state != regState_UpdatePending)
3659 		rr->state = regState_Pending;
3660 
3661 	return;
3662 
3663 exit:
3664 	LogMsg("SendRecordRegistration: Error formatting message for %s", ARDisplayString(m, rr));
3665 	}
3666 
3667 // Called with lock held
3668 mDNSlocal void hndlServiceUpdateReply(mDNS *const m, ServiceRecordSet *srs,  mStatus err)
3669 	{
3670 	mDNSBool InvokeCallback = mDNSfalse;
3671 	ExtraResourceRecord **e = &srs->Extras;
3672 	AuthRecord *txt = &srs->RR_TXT;
3673 
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);
3676 
3677 	debugf("hndlServiceUpdateReply: err %d state %d %##s", err, srs->state, srs->RR_SRV.resrec.name->c);
3678 
3679 	SetRecordRetry(m, &srs->RR_SRV, mStatus_NoError);
3680 
3681 	switch (srs->state)
3682 		{
3683 		case regState_Pending:
3684 			if (err == mStatus_NameConflict && !srs->TestForSelfConflict)
3685 				{
3686 				srs->TestForSelfConflict = mDNStrue;
3687 				debugf("checking for self-conflict of service %##s", srs->RR_SRV.resrec.name->c);
3688 				SendServiceRegistration(m, srs);
3689 				return;
3690 				}
3691 			else if (srs->TestForSelfConflict)
3692 				{
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;
3697 				break;
3698 				}
3699 			else if (srs->srs_uselease && err == mStatus_UnknownErr && mDNSSameIPPort(srs->SRSUpdatePort, UnicastDNSPort))
3700 				{
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);
3704 				return;
3705 				}
3706 			else
3707 				{
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;
3712 				break;
3713 				}
3714 		case regState_Refresh:
3715 			if (err)
3716 				{
3717 				LogMsg("Error %d for refresh of service %##s", err, srs->RR_SRV.resrec.name->c);
3718 				InvokeCallback = mDNStrue;
3719 				}
3720 			else srs->state = regState_Registered;
3721 			break;
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)
3725 				{
3726 				srs->state = regState_NoTarget;	// NoTarget will allow us to pick up new target OR nat traversal state
3727 				break;
3728 				}
3729 			err = mStatus_MemFree;
3730 			InvokeCallback = mDNStrue;
3731 			if (srs->NATinfo.clientContext)
3732 				{
3733 				// deletion completed
3734 				mDNS_StopNATOperation_internal(m, &srs->NATinfo);
3735 				srs->NATinfo.clientContext = mDNSNULL;
3736 				}
3737 			srs->state = regState_Unregistered;
3738 			break;
3739 		case regState_DeregDeferred:
3740 			if (err)
3741 				{
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;
3746 				break;
3747 				}
3748 			else
3749 				{
3750 				debugf("Performing deferred deregistration of %##s", srs->RR_SRV.resrec.name->c);
3751 				srs->state = regState_Registered;
3752 				SendServiceDeregistration(m, srs);
3753 				return;
3754 				}
3755 		case regState_UpdatePending:
3756 			if (err)
3757 				{
3758 				LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs->RR_SRV.resrec.name->c);
3759 				InvokeCallback = mDNStrue;
3760 				}
3761 			else
3762 				{
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;
3769 				}
3770 			break;
3771 		case regState_NoTarget:
3772 			// This state is used when using SendServiceDeregistration() when going to sleep -- no further action required
3773 			return;
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);
3784 		}
3785 
3786 	if ((srs->SRVChanged || srs->SRVUpdateDeferred) && (srs->state == regState_NoTarget || srs->state == regState_Registered))
3787 		{
3788 		debugf("hndlServiceUpdateReply: SRVChanged %d SRVUpdateDeferred %d state %d", srs->SRVChanged, srs->SRVUpdateDeferred, srs->state);
3789 		if (InvokeCallback)
3790 			{
3791 			srs->ClientCallbackDeferred = mDNStrue;
3792 			srs->DeferredStatus = err;
3793 			}
3794 		srs->SRVChanged = srs->SRVUpdateDeferred = mDNSfalse;
3795 		UpdateSRV(m, srs);
3796 		return;
3797 		}
3798 
3799 	while (*e)
3800 		{
3801 		if ((*e)->r.state == regState_ExtraQueued)
3802 			{
3803 			if (srs->state == regState_Registered && !err)
3804 				{
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);
3811 				e = &(*e)->next;
3812 				}
3813 			else if (err && (*e)->r.state != regState_Unregistered)
3814 				{
3815 				// unlink extra from list
3816 				(*e)->r.state = regState_Unregistered;
3817 				*e = (*e)->next;
3818 				}
3819 			else e = &(*e)->next;
3820 			}
3821 		else e = &(*e)->next;
3822 		}
3823 
3824 	if (srs->state == regState_Unregistered)
3825 		{
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);
3829 		unlinkSRS(m, srs);
3830 		}
3831 	else if (txt->QueuedRData && srs->state == regState_Registered)
3832 		{
3833 		if (InvokeCallback)
3834 			{
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;
3838 			}
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);
3846 		return;
3847 		}
3848 
3849 	mDNS_DropLockBeforeCallback();
3850 	if (InvokeCallback)
3851 		srs->ServiceCallback(m, srs, err);
3852 	else if (srs->ClientCallbackDeferred)
3853 		{
3854 		srs->ClientCallbackDeferred = mDNSfalse;
3855 		srs->ServiceCallback(m, srs, srs->DeferredStatus);
3856 		}
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.
3860 	}
3861 
3862 // Called with lock held
3863 mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
3864 	{
3865 	mDNSBool InvokeCallback = mDNStrue;
3866 
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);
3869 
3870 	LogInfo("hndlRecordUpdateReply: err %d state %d %s", err, rr->state, ARDisplayString(m, rr));
3871 
3872 	if (m->SleepState) return;		// If we just sent a deregister on going to sleep, no further action required
3873 
3874 	SetRecordRetry(m, rr, mStatus_NoError);
3875 
3876 	if (rr->state == regState_UpdatePending)
3877 		{
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;
3885 		}
3886 
3887 	if (rr->state == regState_DeregPending)
3888 		{
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;
3894 		}
3895 
3896 	if (rr->state == regState_DeregDeferred)
3897 		{
3898 		if (err)
3899 			{
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;
3903 			}
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);
3907 		return;
3908 		}
3909 
3910 	if (rr->state == regState_Pending || rr->state == regState_Refresh)
3911 		{
3912 		if (!err)
3913 			{
3914 			if (rr->state == regState_Refresh) InvokeCallback = mDNSfalse;
3915 			rr->state = regState_Registered;
3916 			}
3917 		else
3918 			{
3919 			if (rr->uselease && err == mStatus_UnknownErr && mDNSSameIPPort(rr->UpdatePort, UnicastDNSPort))
3920 				{
3921 				LogMsg("Re-trying update of record %##s without lease option", rr->resrec.name->c);
3922 				rr->uselease = mDNSfalse;
3923 				SendRecordRegistration(m, rr);
3924 				return;
3925 				}
3926 			LogMsg("hndlRecordUpdateReply: Registration of record %##s type %d failed with error %d", rr->resrec.name->c, rr->resrec.rrtype, err);
3927 			return;
3928 			}
3929 		}
3930 
3931 	if (rr->state == regState_Unregistered)		// Should never happen
3932 		{
3933 		LogMsg("hndlRecordUpdateReply rr->state == regState_Unregistered %s", ARDisplayString(m, rr));
3934 		return;
3935 		}
3936 
3937 	if (rr->QueuedRData && rr->state == regState_Registered)
3938 		{
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);
3946 		return;
3947 		}
3948 
3949 	if (InvokeCallback && rr->RecordCallback)
3950 		{
3951 		mDNS_DropLockBeforeCallback();
3952 		rr->RecordCallback(m, rr, err);
3953 		mDNS_ReclaimLockAfterCallback();
3954 		}
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.
3957 	}
3958 
3959 mDNSexport void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 *pkt, mDNSu16 len)
3960 	{
3961 	NATTraversalInfo *ptr;
3962 	NATAddrReply     *AddrReply    = (NATAddrReply    *)pkt;
3963 	NATPortMapReply  *PortMapReply = (NATPortMapReply *)pkt;
3964 	mDNSu32 nat_elapsed, our_elapsed;
3965 
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; }
3969 
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]);
3973 
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);
3977 
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); }
3987 
3988 	m->LastNATupseconds      = AddrReply->upseconds;
3989 	m->LastNATReplyLocalTime = m->timenow;
3990 #ifdef _LEGACY_NAT_TRAVERSAL_
3991 	LNT_ClearState(m);
3992 #endif // _LEGACY_NAT_TRAVERSAL_
3993 
3994 	if (AddrReply->opcode == NATOp_AddrResponse)
3995 		{
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, "");
4000 #endif
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);
4003 		}
4004 	else if (AddrReply->opcode == NATOp_MapUDPResponse || AddrReply->opcode == NATOp_MapTCPResponse)
4005 		{
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, "");
4011 #endif
4012 		if (!PortMapReply->err)
4013 			{
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]);
4016 			}
4017 
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;
4022 
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);
4026 		}
4027 	else { LogMsg("Received NAT Traversal response with version unknown opcode 0x%X", AddrReply->opcode); return; }
4028 
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; }
4031 	}
4032 
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
4035 //
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.
4042 //
4043 // Some examples:
4044 //
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.
4048 //
4049 // 2. Any query that results in a large response with the TC bit set.
4050 //
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.
4057 //
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.
4063 //
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.
4070 //
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.
4074 
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";
4078 
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)
4082 	{
4083 	int i;
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
4088 		{
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);
4093 		p += 1 + p[0];
4094 		}
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"));
4098 	}
4099 
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)
4103 	{
4104 	const mDNSu8 *ptr = msg->data;
4105 	DNSQuestion pktq;
4106 	DNSServer *s;
4107 	mDNSu32 result = 0;
4108 
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);
4115 
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;
4120 	else
4121 		result = DNSServer_Passed;
4122 
4123 	// 3. Find occurrences of this server in our list, and mark them appropriately
4124 	for (s = m->DNSServers; s; s = s->next)
4125 		{
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)
4129 			{
4130 			DNSQuestion *q;
4131 			s->teststate = result;
4132 			if (result == DNSServer_Passed)
4133 				{
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");
4137 				}
4138 			else
4139 				{
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");
4143 				}
4144 
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))
4150 						{
4151 						q->ThisQInterval = INIT_UCAST_POLL_INTERVAL / QuestionIntervalStep;
4152 						q->unansweredQueries = 0;
4153 						q->LastQTime = m->timenow - q->ThisQInterval;
4154 						m->NextScheduledQuery = m->timenow;
4155 						}
4156 			}
4157 		}
4158 
4159 	return(mDNStrue); // Return mDNStrue to tell uDNS_ReceiveMsg it doesn't need to process this packet further
4160 	}
4161 
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)
4164 	{
4165 	DNSQuestion *qptr;
4166 	mStatus err = mStatus_NoError;
4167 
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);
4172 
4173 	(void)srcport; // Unused
4174 
4175 	debugf("uDNS_ReceiveMsg from %#-15a with "
4176 		"%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
4177 		srcaddr,
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");
4182 
4183 	if (QR_OP == StdR)
4184 		{
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)
4189 				{
4190 				if (!srcaddr) LogMsg("uDNS_ReceiveMsg: TCP DNS response had TC bit set: ignoring");
4191 				else if (qptr->tcp)
4192 					{
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();
4200 					}
4201 				else qptr->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_Zero, srcaddr, srcport, qptr, mDNSNULL, mDNSNULL);
4202 				}
4203 		}
4204 
4205 	if (QR_OP == UpdateR)
4206 		{
4207 		mDNSu32 lease = GetPktLease(m, msg, end);
4208 		mDNSs32 expire = m->timenow + (mDNSs32)lease * mDNSPlatformOneSecond;
4209 
4210 		//rcode = kDNSFlag1_RC_ServFail;	// Simulate server failure (rcode 2)
4211 
4212 		if (CurrentServiceRecordSet)
4213 			LogMsg("uDNS_ReceiveMsg ERROR CurrentServiceRecordSet already set");
4214 		CurrentServiceRecordSet = m->ServiceRegistrations;
4215 
4216 		while (CurrentServiceRecordSet)
4217 			{
4218 			ServiceRecordSet *sptr = CurrentServiceRecordSet;
4219 			CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next;
4220 
4221 			if (mDNSSameOpaque16(sptr->id, msg->h.id))
4222 				{
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;
4229 				return;
4230 				}
4231 			}
4232 
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)
4237 			{
4238 			AuthRecord *rptr = m->CurrentRecord;
4239 			m->CurrentRecord = m->CurrentRecord->next;
4240 			if (AuthRecord_uDNS(rptr) && mDNSSameOpaque16(rptr->updateid, msg->h.id))
4241 				{
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;
4248 				return;
4249 				}
4250 			}
4251 		}
4252 	debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg->h.id));
4253 	}
4254 
4255 // ***************************************************************************
4256 #if COMPILER_LIKES_PRAGMA_MARK
4257 #pragma mark - Query Routines
4258 #endif
4259 
4260 mDNSexport void sendLLQRefresh(mDNS *m, DNSQuestion *q)
4261 	{
4262 	mDNSu8 *end;
4263 	LLQOptData llq;
4264 
4265 	if (q->ReqLease)
4266 		if ((q->state == LLQ_Established && q->ntries >= kLLQ_MAX_TRIES) || q->expire - m->timenow < 0)
4267 			{
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);
4270 			return;
4271 			}
4272 
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
4276 	llq.id       = q->id;
4277 	llq.llqlease = q->ReqLease;
4278 
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; }
4282 
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; }
4287 
4288 	if (q->AuthInfo)
4289 		{
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; }
4292 		}
4293 
4294 	if (q->AuthInfo && !q->tcp)
4295 		{
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);
4298 		}
4299 	else
4300 		{
4301 		mStatus err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, mDNSNULL);
4302 		if (err)
4303 			{
4304 			LogMsg("sendLLQRefresh: mDNSSendDNSMessage%s failed: %d", q->tcp ? " (TCP)" : "", err);
4305 			if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; }
4306 			}
4307 		}
4308 
4309 	q->ntries++;
4310 
4311 	debugf("sendLLQRefresh ntries %d %##s (%s)", q->ntries, q->qname.c, DNSTypeName(q->qtype));
4312 
4313 	q->LastQTime = m->timenow;
4314 	SetNextQueryTime(m, q);
4315 	}
4316 
4317 mDNSexport void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
4318 	{
4319 	DNSQuestion *q = (DNSQuestion *)zoneInfo->ZoneDataContext;
4320 
4321 	mDNS_Lock(m);
4322 
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).
4326 	q->nta      = mDNSNULL;
4327 	q->servAddr = zeroAddr;
4328 	q->servPort = zeroIPPort;
4329 
4330 	if (!err && zoneInfo && !mDNSIPPortIsZero(zoneInfo->Port) && !mDNSAddressIsZero(&zoneInfo->Addr))
4331 		{
4332 		q->servAddr = zoneInfo->Addr;
4333 		q->servPort = zoneInfo->Port;
4334 		q->AuthInfo = zoneInfo->ZonePrivate ? GetAuthInfoForName_internal(m, &q->qname) : mDNSNULL;
4335 		q->ntries = 0;
4336 		debugf("LLQGotZoneData %#a:%d", &q->servAddr, mDNSVal16(q->servPort));
4337 		startLLQHandshake(m, q);
4338 		}
4339 	else
4340 		{
4341 		StartLLQPolling(m,q);
4342 		if (err == mStatus_NoSuchNameErr)
4343 			{
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;
4347 			}
4348 		}
4349 
4350 	mDNS_Unlock(m);
4351 	}
4352 
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)
4355 	{
4356 	DNSQuestion *q = (DNSQuestion *) zoneInfo->ZoneDataContext;
4357 
4358 	LogInfo("PrivateQueryGotZoneData %##s (%s) err %d Zone %##s Private %d", q->qname.c, DNSTypeName(q->qtype), err, zoneInfo->ZoneName.c, zoneInfo->ZonePrivate);
4359 
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).
4363 	q->nta = mDNSNULL;
4364 
4365 	if (err || !zoneInfo || mDNSAddressIsZero(&zoneInfo->Addr) || mDNSIPPortIsZero(zoneInfo->Port))
4366 		{
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);
4371 		return;
4372 		}
4373 
4374 	if (!zoneInfo->ZonePrivate)
4375 		{
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;
4380 		mDNS_Lock(m);
4381 		SetNextQueryTime(m, q);
4382 		mDNS_Unlock(m);
4383 		return;
4384 		// Next call to uDNS_CheckCurrentQuestion() will do this as a non-private query
4385 		}
4386 
4387 	if (!q->AuthInfo)
4388 		{
4389 		LogMsg("ERROR: PrivateQueryGotZoneData: cannot find credentials for q %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4390 		return;
4391 		}
4392 
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);
4396 	}
4397 
4398 // ***************************************************************************
4399 #if COMPILER_LIKES_PRAGMA_MARK
4400 #pragma mark - Dynamic Updates
4401 #endif
4402 
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)
4405 	{
4406 	AuthRecord *newRR = (AuthRecord*)zoneData->ZoneDataContext;
4407 	AuthRecord *ptr;
4408 	int c1, c2;
4409 
4410 	if (m->mDNS_busy != m->mDNS_reentrancy)
4411 		LogMsg("RecordRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
4412 
4413 	newRR->nta = mDNSNULL;
4414 
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;
4418 
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; }
4422 
4423 	// check error/result
4424 	if (err)
4425 		{
4426 		if (err != mStatus_NoSuchNameErr) LogMsg("RecordRegistrationGotZoneData: error %d", err);
4427 		return;
4428 		}
4429 
4430 	if (!zoneData) { LogMsg("ERROR: RecordRegistrationGotZoneData invoked with NULL result and no error"); return; }
4431 
4432 	if (newRR->resrec.rrclass != zoneData->ZoneClass)
4433 		{
4434 		LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)", newRR->resrec.rrclass, zoneData->ZoneClass);
4435 		return;
4436 		}
4437 
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)
4442 		{
4443 		LogInfo("RecordRegistrationGotZoneData: No name server found claiming responsibility for \"%##s\"!", newRR->resrec.name->c);
4444 		return;
4445 		}
4446 
4447 	// Store discovered zone data
4448 	c1 = CountLabels(newRR->resrec.name);
4449 	c2 = CountLabels(&zoneData->ZoneName);
4450 	if (c2 > c1)
4451 		{
4452 		LogMsg("RecordRegistrationGotZoneData: Zone \"%##s\" is longer than \"%##s\"", zoneData->ZoneName.c, newRR->resrec.name->c);
4453 		return;
4454 		}
4455 	newRR->zone = SkipLeadingLabels(newRR->resrec.name, c1-c2);
4456 	if (!SameDomainName(newRR->zone, &zoneData->ZoneName))
4457 		{
4458 		LogMsg("RecordRegistrationGotZoneData: Zone \"%##s\" does not match \"%##s\" for \"%##s\"", newRR->zone->c, zoneData->ZoneName.c, newRR->resrec.name->c);
4459 		return;
4460 		}
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));
4466 
4467 	if (mDNSIPPortIsZero(zoneData->Port) || mDNSAddressIsZero(&zoneData->Addr))
4468 		{
4469 		LogInfo("RecordRegistrationGotZoneData: No _dns-update._udp service found for \"%##s\"!", newRR->resrec.name->c);
4470 		return;
4471 		}
4472 
4473 	newRR->ThisAPInterval = 5 * mDNSPlatformOneSecond;		// After doubling, first retry will happen after ten seconds
4474 
4475 	mDNS_Lock(m);	// SendRecordRegistration expects to be called with the lock held
4476 	SendRecordRegistration(m, newRR);
4477 	mDNS_Unlock(m);
4478 	}
4479 
4480 mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
4481 	{
4482 	mDNSu8 *ptr = m->omsg.data;
4483 	mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
4484 
4485 	if (mDNSIPv4AddressIsZero(rr->UpdateServer.ip.v4))	// Don't know our UpdateServer yet
4486 		{
4487 		rr->LastAPTime = m->timenow;
4488 		if (rr->ThisAPInterval < mDNSPlatformOneSecond * 5)
4489 			rr->ThisAPInterval = mDNSPlatformOneSecond * 5;
4490 		return;
4491 		}
4492 
4493 	InitializeDNSMessage(&m->omsg.h, rr->updateid, UpdateReqFlags);
4494 
4495 	ptr = putZone(&m->omsg, ptr, end, rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
4496 	if (ptr) ptr = putDeletionRecord(&m->omsg, ptr, &rr->resrec);
4497 	if (!ptr)
4498 		{
4499 		LogMsg("SendRecordDeregistration Error: could not contruct deregistration packet for %s", ARDisplayString(m, rr));
4500 		if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr);
4501 		}
4502 	else
4503 		{
4504 		rr->expire = 0;		// Indicate that we have no active registration any more
4505 		if (rr->Private)
4506 			{
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);
4514 			}
4515 		else
4516 			{
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
4520 			}
4521 		}
4522 	}
4523 
4524 mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr)
4525 	{
4526 	switch (rr->state)
4527 		{
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;
4541 		}
4542 
4543 	if (rr->state != regState_Unregistered) { rr->state = regState_DeregPending; SendRecordDeregistration(m, rr); }
4544 	return mStatus_NoError;
4545 	}
4546 
4547 // Called with lock held
4548 mDNSexport mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs)
4549 	{
4550 	char *errmsg = "Unknown State";
4551 
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);
4554 
4555 	// don't re-register with a new target following deregistration
4556 	srs->SRVChanged = srs->SRVUpdateDeferred = mDNSfalse;
4557 
4558 	if (srs->srs_nta) { CancelGetZoneData(m, srs->srs_nta); srs->srs_nta = mDNSNULL; }
4559 
4560 	if (srs->NATinfo.clientContext)
4561 		{
4562 		mDNS_StopNATOperation_internal(m, &srs->NATinfo);
4563 		srs->NATinfo.clientContext = mDNSNULL;
4564 		}
4565 
4566 	switch (srs->state)
4567 		{
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
4578 			unlinkSRS(m, srs);
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)";
4594 			goto error;
4595 		default: LogMsg("uDNS_DeregisterService: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c);
4596 		}
4597 
4598 	error:
4599 	LogMsg("Error, uDNS_DeregisterService: %s", errmsg);
4600 	return mStatus_BadReferenceErr;
4601 	}
4602 
4603 mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr)
4604 	{
4605 	ServiceRecordSet *parent = mDNSNULL;
4606 	AuthRecord *rptr;
4607 	regState_t *stateptr = mDNSNULL;
4608 
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; }
4612 
4613 	if (!parent)
4614 		{
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;
4619 		}
4620 
4621 	switch(*stateptr)
4622 		{
4623 		case regState_DeregPending:
4624 		case regState_DeregDeferred:
4625 		case regState_Unregistered:
4626 			// not actively registered
4627 			goto unreg_error;
4628 
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;
4638 
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;
4650 
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;
4661 
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
4665 
4666 		default: LogMsg("uDNS_UpdateRecord: Unknown state %d for %##s", *stateptr, rr->resrec.name->c);
4667 		}
4668 
4669 	unreg_error:
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;
4673 	}
4674 
4675 // ***************************************************************************
4676 #if COMPILER_LIKES_PRAGMA_MARK
4677 #pragma mark - Periodic Execution Routines
4678 #endif
4679 
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)
4683 	{
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;
4690 
4691 	if (q->LongLived)
4692 		{
4693 		switch (q->state)
4694 			{
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)
4699 			}
4700 		}
4701 
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))
4704 		{
4705 		if (q->unansweredQueries >= MAX_UCAST_UNANSWERED_QUERIES)
4706 			{
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);
4709 
4710 			PushDNSServerToEnd(m, q);
4711 			q->unansweredQueries = 0;
4712 			}
4713 
4714 		if (q->qDNSServer && q->qDNSServer->teststate != DNSServer_Disabled)
4715 			{
4716 			mDNSu8 *end = m->omsg.data;
4717 			mStatus err = mStatus_NoError;
4718 			mDNSBool private = mDNSfalse;
4719 
4720 			InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
4721 
4722 			if (q->qDNSServer->teststate != DNSServer_Untested || NoTestQuery(q))
4723 				{
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);
4726 				}
4727 			else if (m->timenow - q->qDNSServer->lasttest >= INIT_UCAST_POLL_INTERVAL)	// Make sure at least three seconds has elapsed since last test query
4728 				{
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;
4734 				}
4735 
4736 			if (end > m->omsg.data && (q->qDNSServer->teststate != DNSServer_Failed || NoTestQuery(q)))
4737 				{
4738 				//LogMsg("uDNS_CheckCurrentQuestion %p %d %p %##s (%s)", q, sendtime - m->timenow, private, q->qname.c, DNSTypeName(q->qtype));
4739 				if (private)
4740 					{
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;
4744 					}
4745 				else
4746 					{
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);
4751 					}
4752 				}
4753 
4754 			if (err) debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %d", err); // surpress syslog messages if we have no network
4755 			else
4756 				{
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));
4762 				}
4763 			q->LastQTime = m->timenow;
4764 			SetNextQueryTime(m, q);
4765 			}
4766 		else
4767 			{
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.)
4776 
4777 			CacheRecord *rr;
4778 			const mDNSu32 slot = HashSlot(&q->qname);
4779 			CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
4780 			if (cg)
4781 				for (rr = cg->members; rr; rr=rr->next)
4782 					if (SameNameRecordAnswersQuestion(&rr->resrec, q)) mDNS_PurgeCacheResourceRecord(m, rr);
4783 
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);
4786 
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
4794 			}
4795 		}
4796 	}
4797 
4798 mDNSlocal void CheckNATMappings(mDNS *m)
4799 	{
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;
4804 
4805 	if (HaveRoutable) m->ExternalAddress = m->AdvertisedV4.ip.v4;
4806 
4807 	if (m->NATTraversals && rfc1918)			// Do we need to open NAT-PMP socket to receive multicast announcements from router?
4808 		{
4809 		if (m->NATMcastRecvskt == mDNSNULL)		// If we are behind a NAT and the socket hasn't been opened yet, open it
4810 			{
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)
4815 				{
4816 				if (needLog)
4817 					{
4818 					LogMsg("CheckNATMappings: Failed to allocate port 5350 UDP multicast socket for NAT-PMP announcements");
4819 					needLog = mDNSfalse;
4820 					}
4821 				}
4822 			else
4823 				needLog = mDNStrue;
4824 			}
4825 		}
4826 	else										// else, we don't want to listen for announcements, so close them if they're open
4827 		{
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; }
4830 		}
4831 
4832 	if (m->NATTraversals)
4833 		{
4834 		if (m->timenow - m->retryGetAddr >= 0)
4835 			{
4836 			err = uDNS_SendNATMsg(m, mDNSNULL);		// Will also do UPnP discovery for us, if necessary
4837 			if (!err)
4838 				{
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;
4842 				}
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;
4846 			}
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;
4850 		}
4851 
4852 	if (m->CurrentNATTraversal) LogMsg("WARNING m->CurrentNATTraversal already in use");
4853 	m->CurrentNATTraversal = m->NATTraversals;
4854 
4855 	while (m->CurrentNATTraversal)
4856 		{
4857 		NATTraversalInfo *cur = m->CurrentNATTraversal;
4858 		m->CurrentNATTraversal = m->CurrentNATTraversal->next;
4859 
4860 		if (HaveRoutable)		// If not RFC 1918 address, our own address and port are effectively our external address and port
4861 			{
4862 			cur->ExpiryTime = 0;
4863 			cur->NewResult  = mStatus_NoError;
4864 			}
4865 		else if (cur->Protocol)		// Check if it's time to send port mapping packets
4866 			{
4867 			if (m->timenow - cur->retryPortMap >= 0)						// Time to do something with this mapping
4868 				{
4869 				if (cur->ExpiryTime && cur->ExpiryTime - m->timenow < 0)	// Mapping has expired
4870 					{
4871 					cur->ExpiryTime    = 0;
4872 					cur->retryInterval = NATMAP_INIT_RETRY;
4873 					}
4874 
4875 				//LogMsg("uDNS_SendNATMsg");
4876 				err = uDNS_SendNATMsg(m, cur);
4877 
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
4881 					{
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;
4886 					}
4887 				}
4888 
4889 			if (m->NextScheduledNATOp - cur->retryPortMap > 0)
4890 				m->NextScheduledNATOp = cur->retryPortMap;
4891 			}
4892 
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)
4898 			{
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)
4906 					{
4907 					//LogMsg("NAT callback %d %d %d", cur->Protocol, cur->ExpiryTime, cur->retryInterval);
4908 					if (cur->Protocol && mDNSIPPortIsZero(ExternalPort) && !mDNSIPv4AddressIsZero(m->Router.ip.v4))
4909 						{
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);
4913 						else
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);
4916 						}
4917 
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
4928 					}
4929 			}
4930 		}
4931 	}
4932 
4933 mDNSlocal mDNSs32 CheckRecordRegistrations(mDNS *m)
4934 	{
4935 	AuthRecord *rr;
4936 	mDNSs32 nextevent = m->timenow + 0x3FFFFFFF;
4937 
4938 	for (rr = m->ResourceRecords; rr; rr = rr->next)
4939 		{
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)
4943 			{
4944 			if (rr->LastAPTime + rr->ThisAPInterval - m->timenow < 0)
4945 				{
4946 				if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
4947 				if (rr->state == regState_FetchingZoneData)
4948 					{
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);
4952 					}
4953 				else if (rr->state == regState_DeregPending) SendRecordDeregistration(m, rr);
4954 				else SendRecordRegistration(m, rr);
4955 				}
4956 			if (nextevent - (rr->LastAPTime + rr->ThisAPInterval) > 0)
4957 				nextevent = (rr->LastAPTime + rr->ThisAPInterval);
4958 			}
4959 		}
4960 	return nextevent;
4961 	}
4962 
4963 mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m)
4964 	{
4965 	mDNSs32 nextevent = m->timenow + 0x3FFFFFFF;
4966 
4967 	if (CurrentServiceRecordSet)
4968 		LogMsg("CheckServiceRegistrations ERROR CurrentServiceRecordSet already set");
4969 	CurrentServiceRecordSet = m->ServiceRegistrations;
4970 
4971 	// Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery
4972 	while (CurrentServiceRecordSet)
4973 		{
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)
4979 			{
4980 			if (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval - m->timenow <= 0)
4981 				{
4982 				if (srs->tcp) { DisposeTCPConn(srs->tcp); srs->tcp = mDNSNULL; }
4983 				if (srs->state == regState_FetchingZoneData)
4984 					{
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);
4988 					}
4989 				else if (srs->state == regState_DeregPending) SendServiceDeregistration(m, srs);
4990 				else SendServiceRegistration(m, srs);
4991 				}
4992 			if (nextevent - (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval) > 0)
4993 				nextevent = (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval);
4994 			}
4995 		}
4996 	return nextevent;
4997 	}
4998 
4999 mDNSexport void uDNS_Execute(mDNS *const m)
5000 	{
5001 	mDNSs32 nexte;
5002 
5003 	m->NextuDNSEvent = m->timenow + 0x3FFFFFFF;
5004 
5005 	if (m->NextSRVUpdate && m->NextSRVUpdate - m->timenow < 0)
5006 		{ m->NextSRVUpdate = 0; UpdateSRVRecords(m); }
5007 
5008 	CheckNATMappings(m);
5009 
5010 	if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0)
5011 		m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it
5012 
5013 	nexte = CheckRecordRegistrations(m);
5014 	if (nexte - m->NextuDNSEvent < 0) m->NextuDNSEvent = nexte;
5015 
5016 	nexte = CheckServiceRegistrations(m);
5017 	if (nexte - m->NextuDNSEvent < 0) m->NextuDNSEvent = nexte;
5018 	}
5019 
5020 // ***************************************************************************
5021 #if COMPILER_LIKES_PRAGMA_MARK
5022 #pragma mark - Startup, Shutdown, and Sleep
5023 #endif
5024 
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.
5029 
5030 mDNSexport void SleepRecordRegistrations(mDNS *m)
5031 	{
5032 	AuthRecord *rr;
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)
5037 				{
5038 				SendRecordDeregistration(m, rr);
5039 				rr->state = regState_Refresh;
5040 				rr->LastAPTime = m->timenow;
5041 				rr->ThisAPInterval = 300 * mDNSPlatformOneSecond;
5042 				}
5043 	}
5044 
5045 mDNSexport void SleepServiceRegistrations(mDNS *m)
5046 	{
5047 	ServiceRecordSet *srs = m->ServiceRegistrations;
5048 	while (srs)
5049 		{
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; }
5052 
5053 		if (srs->NATinfo.clientContext)
5054 			{
5055 			mDNS_StopNATOperation_internal(m, &srs->NATinfo);
5056 			srs->NATinfo.clientContext = mDNSNULL;
5057 			}
5058 
5059 		if (srs->state == regState_UpdatePending)
5060 			{
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;
5069 			}
5070 
5071 		if (srs->state == regState_Registered || srs->state == regState_Refresh)
5072 			SendServiceDeregistration(m, srs);
5073 
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
5078 
5079 		srs = srs->uDNS_next;
5080 		}
5081 	}
5082 
5083 mDNSexport void mDNS_AddSearchDomain(const domainname *const domain)
5084 	{
5085 	SearchListElem **p;
5086 
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))
5090 			{
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);
5094 			return;
5095 			}
5096 
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);
5105 	}
5106 
5107 mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
5108 	{
5109 	(void)m;	// unused
5110 	if (result == mStatus_MemFree) mDNSPlatformMemFree(rr->RecordContext);
5111 	}
5112 
5113 mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
5114 	{
5115 	SearchListElem *slElem = question->QuestionContext;
5116 	mStatus err;
5117 	const char *name;
5118 
5119 	if (answer->rrtype != kDNSType_PTR) return;
5120 	if (answer->RecordType == kDNSRecordTypePacketNegative) return;
5121 	if (answer->InterfaceID == mDNSInterface_LocalOnly) return;
5122 
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; }
5129 
5130 	LogInfo("FoundDomain: %p %s %s Q %##s A %s", answer->InterfaceID, AddRecord ? "Add" : "Rmv", name, question->qname.c, RRDisplayString(m, answer));
5131 
5132 	if (AddRecord)
5133 		{
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;
5145 		}
5146 	else
5147 		{
5148 		ARListElem **ptr = &slElem->AuthRecs;
5149 		while (*ptr)
5150 			{
5151 			if (SameDomainName(&(*ptr)->ar.resrec.rdata->u.name, &answer->rdata->u.name))
5152 				{
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
5159 				}
5160 			else
5161 				ptr = &(*ptr)->next;
5162 			}
5163 		}
5164 	}
5165 
5166 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
5167 mDNSexport void udns_validatelists(void *const v)
5168 	{
5169 	mDNS *const m = v;
5170 
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);
5175 
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);
5180 
5181 	DNSServer *d;
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);
5185 
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);
5190 
5191 	HostnameInfo *hi;
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);
5195 
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);
5200 	}
5201 #endif
5202 
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
5205 
5206 mDNSexport mStatus uDNS_RegisterSearchDomains(mDNS *const m)
5207 	{
5208 	SearchListElem **p = &SearchList, *ptr;
5209 	mStatus err;
5210 
5211 	// step 1: mark each element for removal (-1)
5212 	for (ptr = SearchList; ptr; ptr = ptr->next) ptr->flag = -1;
5213 
5214 	// Client has requested domain enumeration or automatic browse -- time to make sure we have the search domains from the platform layer
5215 	mDNS_Lock(m);
5216 	m->RegisterSearchDomains = mDNStrue;
5217 	mDNSPlatformSetDNSConfig(m, mDNSfalse, m->RegisterSearchDomains, mDNSNULL, mDNSNULL, mDNSNULL);
5218 	mDNS_Unlock(m);
5219 
5220 	// delete elems marked for removal, do queries for elems marked add
5221 	while (*p)
5222 		{
5223 		ptr = *p;
5224 		LogInfo("RegisterSearchDomains %d %p %##s", ptr->flag, ptr->AuthRecs, ptr->domain.c);
5225 		if (ptr->flag == -1)	// remove
5226 			{
5227 			ARListElem *arList = ptr->AuthRecs;
5228 			ptr->AuthRecs = mDNSNULL;
5229 			*p = ptr->next;
5230 
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))
5233 				{
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);
5239 				}
5240 			mDNSPlatformMemFree(ptr);
5241 
5242 	        // deregister records generated from answers to the query
5243 			while (arList)
5244 				{
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
5251 				}
5252 			continue;
5253 			}
5254 
5255 		if (ptr->flag == 1)	// add
5256 			{
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))
5259 				{
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);
5274 				}
5275 			ptr->flag = 0;
5276 			}
5277 
5278 		if (ptr->flag) { LogMsg("RegisterSearchDomains - unknown flag %d. Skipping.", ptr->flag); }
5279 
5280 		p = &ptr->next;
5281 		}
5282 
5283 	return mStatus_NoError;
5284 	}
5285 
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)
5295 
5296 struct CompileTimeAssertionChecks_uDNS
5297 	{
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];
5303 	};
5304