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
24Log: uDNS.c,v $
25Revision 1.617  2009/06/30 20:51:02  cheshire
26Improved "Error! Tried to add a NAT traversal that's already in the active list" debugging message
27
28Revision 1.616  2009/05/27 20:29:36  cheshire
29<rdar://problem/6926465> Sleep is delayed by 10 seconds if BTMM is on
30After receiving confirmation of LLQ deletion, need to schedule another evaluation of whether we're ready to sleep yet
31
32Revision 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
35Revision 1.614  2009/04/24 02:17:57  mcguire
36<rdar://problem/5264124> uDNS: Not always respecting preference order of DNS servers
37
38Revision 1.613  2009/04/23 22:06:29  cheshire
39Added 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
42Revision 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
45Revision 1.611  2009/04/15 20:42:51  mcguire
46<rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures
47
48Revision 1.610  2009/04/15 01:10:39  jessic2
49<rdar://problem/6466541> BTMM: Add support for setting kDNSServiceErr_NoSuchRecord in DynamicStore
50
51Revision 1.609  2009/04/11 00:19:45  jessic2
52<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
53
54Revision 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
57Revision 1.607  2009/04/02 22:36:34  jessic2
58Fix crash when calling debugf with null opt
59
60Revision 1.606  2009/03/26 03:59:00  jessic2
61Changes for <rdar://problem/6492552&6492593&6492609&6492613&6492628&6492640&6492699>
62
63Revision 1.605  2009/03/04 00:40:14  cheshire
64Updated DNS server error codes to be more consistent with definitions at
65<http://www.iana.org/assignments/dns-parameters>
66
67Revision 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
70Revision 1.603  2009/02/27 02:56:57  cheshire
71Moved struct SearchListElem definition from uDNS.c into mDNSEmbeddedAPI.h
72
73Revision 1.602  2009/02/13 06:29:54  cheshire
74Converted LogOperation messages to LogInfo
75
76Revision 1.601  2009/02/12 20:57:25  cheshire
77Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch
78
79Revision 1.600  2009/01/31 21:05:12  cheshire
80Improved "Failed to obtain NAT port mapping" debugging log message
81
82Revision 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
85Revision 1.598  2009/01/21 03:43:57  mcguire
86<rdar://problem/6511765> BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore
87
88Revision 1.597  2009/01/10 01:55:49  cheshire
89Added LogOperation message showing when domains are added and removed in FoundDomain
90
91Revision 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
94Revision 1.595  2008/12/18 23:32:19  mcguire
95<rdar://problem/6019470> BTMM: Include the question in the LLQ notification acknowledgment
96
97Revision 1.594  2008/12/10 02:25:31  cheshire
98Minor fixes to use of LogClientOperations symbol
99
100Revision 1.593  2008/12/10 02:11:42  cheshire
101ARMv5 compiler doesn't like uncommented stuff after #endif
102
103Revision 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
106Revision 1.591  2008/12/06 00:17:11  cheshire
107<rdar://problem/6380477> mDNS_StopNATOperation doesn't handle duplicate NAT mapping requests properly
108Refinement: For duplicate ssh mappings we want to suppress the syslog warning message, but not the "unmap = mDNSfalse"
109
110Revision 1.590  2008/12/04 20:57:36  mcguire
111fix build
112
113Revision 1.589  2008/12/04 02:24:09  cheshire
114Improved NAT-PMP debugging messages
115
116Revision 1.588  2008/11/26 20:38:08  cheshire
117Changed some "LogOperation" debugging messages to "debugf"
118
119Revision 1.587  2008/11/26 19:53:26  cheshire
120Don't overwrite srs->NATinfo.IntPort in StartSRVNatMap()
121
122Revision 1.586  2008/11/25 23:43:07  cheshire
123<rdar://problem/5745355> Crashes at ServiceRegistrationGotZoneData + 397
124Made code more defensive to guard against ServiceRegistrationGotZoneData being called with invalid ServiceRecordSet object
125
126Revision 1.585  2008/11/25 22:46:30  cheshire
127For ease of code searching, renamed ZoneData field of ServiceRecordSet_struct from "nta" to "srs_nta"
128
129Revision 1.584  2008/11/24 19:46:40  cheshire
130When sending query over TCP, don't include LLQ option when we're talking to a conventional DNS server or cache
131
132Revision 1.583  2008/11/21 00:34:58  cheshire
133<rdar://problem/6380477> mDNS_StopNATOperation doesn't handle duplicate NAT mapping requests properly
134
135Revision 1.582  2008/11/20 02:23:37  mcguire
136<rdar://problem/6041208> need to handle URLBase
137
138Revision 1.581  2008/11/20 01:51:19  cheshire
139Exported RecreateNATMappings so it's callable from other files
140
141Revision 1.580  2008/11/13 19:08:45  cheshire
142Fixed code to handle rdataOPT properly
143
144Revision 1.579  2008/11/07 00:18:01  mcguire
145<rdar://problem/6351068> uDNS: Supress reverse DNS query until required
146
147Revision 1.578  2008/11/04 22:21:46  cheshire
148Changed zone field of AuthRecord_struct from domainname to pointer, saving 252 bytes per AuthRecord
149
150Revision 1.577  2008/10/29 21:37:01  cheshire
151Removed some old debugging messages
152
153Revision 1.576  2008/10/23 22:25:57  cheshire
154Renamed field "id" to more descriptive "updateid"
155
156Revision 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
159Revision 1.574  2008/10/14 19:06:45  cheshire
160In uDNS_ReceiveMsg(), only do checkUpdateResult() for uDNS records
161
162Revision 1.573  2008/09/25 20:43:44  cheshire
163<rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
164In UpdateSRVRecords, call mDNS_SetFQDN(m) to update AutoTarget SRV records on the main m->ResourceRecords list
165
166Revision 1.572  2008/09/24 23:48:05  cheshire
167Don't need to pass whole ServiceRecordSet reference to GetServiceTarget;
168it only needs to access the embedded SRV member of the set
169
170Revision 1.571  2008/09/23 22:56:53  cheshire
171<rdar://problem/5298845> Remove dnsbugtest query
172
173Revision 1.570  2008/09/23 01:30:18  cheshire
174The putLLQ() routine was not setting the OPT record's rrclass to NormalMaxDNSMessageData
175
176Revision 1.569  2008/07/25 22:34:11  mcguire
177fix sizecheck issues for 64bit
178
179Revision 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
182Revision 1.567  2008/07/01 01:40:00  mcguire
183<rdar://problem/5823010> 64-bit fixes
184
185Revision 1.566  2008/06/26 17:24:11  mkrochma
186<rdar://problem/5450912> BTMM: Stop listening on UDP 5351 for NAT Status Announcements
187
188Revision 1.565  2008/06/21 19:06:58  mcguire
189<rdar://problem/4206534> Use all configured DNS servers
190
191Revision 1.564  2008/06/19 23:42:03  mcguire
192<rdar://problem/4206534> Use all configured DNS servers
193
194Revision 1.563  2008/06/19 17:46:14  mcguire
195<rdar://problem/4206534> Use all configured DNS servers
196Don't do extra work for log messages if we're not going to log
197
198Revision 1.562  2008/06/19 17:35:19  mcguire
199<rdar://problem/4206534> Use all configured DNS servers
200cleanup log messages
201check for null pointers
202
203Revision 1.561  2008/06/19 01:20:49  mcguire
204<rdar://problem/4206534> Use all configured DNS servers
205
206Revision 1.560  2008/05/31 01:51:09  mcguire
207fixed typo in log message
208
209Revision 1.559  2008/04/15 22:37:58  mkrochma
210Change LogMsg to LogOperation
211
212Revision 1.558  2008/03/17 18:02:35  mkrochma
213Add space to log message for consistency
214
215Revision 1.557  2008/03/14 19:58:38  mcguire
216<rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client
217Make sure we add the record when sending LLQ refreshes
218
219Revision 1.556  2008/03/07 23:55:05  cheshire
220<rdar://problem/5787898> LLQ refresh randomization not working properly
221
222Revision 1.555  2008/03/07 23:25:56  cheshire
223Improved debugging messages
224
225Revision 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
228Revision 1.553  2008/03/06 02:48:34  mcguire
229<rdar://problem/5321824> write status to the DS
230
231Revision 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
234Revision 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
236Added code to suppress logging of multiple identical error results
237
238Revision 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
240Further refinements
241
242Revision 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
245Revision 1.548  2008/02/20 23:54:18  cheshire
246<rdar://problem/5661518> "Failed to obtain NAT port mapping" syslog messages
247Improved log message so it tells us more about what's going on
248
249Revision 1.547  2008/02/20 00:41:09  cheshire
250Change "PrivateQueryGotZoneData ... invoked with error code" from LogMsg to LogOperation
251
252Revision 1.546  2008/02/19 23:26:50  cheshire
253<rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
254
255Revision 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
258Revision 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
260Reordered code to avoid double-TSIGs in some cases
261
262Revision 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
264Need to include TSIG signature when sending LLQ cancellations over TLS
265
266Revision 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
269Revision 1.541  2007/12/15 00:18:51  cheshire
270Renamed question->origLease to question->ReqLease
271
272Revision 1.540  2007/12/14 23:55:28  cheshire
273Moved "struct tcpInfo_t" definition from uDNS.c to mDNSEmbeddedAPI.h
274
275Revision 1.539  2007/12/14 20:44:24  cheshire
276<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
277SleepRecordRegistrations/WakeRecordRegistrations should only operate on uDNS records
278
279Revision 1.538  2007/12/14 01:13:40  cheshire
280<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
281Additional fixes (existing code to deregister private records and services didn't work at all)
282
283Revision 1.537  2007/12/11 00:18:25  cheshire
284<rdar://problem/5569316> BTMM: My iMac has a "ghost" ID associated with it
285There were cases where the code was incorrectly clearing the "uselease" flag, and never resetting it.
286
287Revision 1.536  2007/12/10 23:07:00  cheshire
288Removed some unnecessary log messages
289
290Revision 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
293Revision 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
296Revision 1.533  2007/12/01 01:21:27  jgraessley
297<rdar://problem/5623140> mDNSResponder unicast DNS improvements
298
299Revision 1.532  2007/11/30 20:16:44  cheshire
300Fixed compile warning: declaration of 'end' shadows a previous local
301
302Revision 1.531  2007/11/28 22:00:09  cheshire
303In StartSRVNatMap, change "mDNSu8 *p" to "const mDNSu8 *p"
304
305Revision 1.530  2007/11/16 22:19:40  cheshire
306<rdar://problem/5547474> mDNSResponder leaks on network changes
307The "connection failed" code path in MakeTCPConn was not disposing of the TCPSocket it had created
308
309Revision 1.529  2007/11/15 22:52:29  cheshire
310<rdar://problem/5589039> ERROR: mDNSPlatformWriteTCP - send Broken pipe
311
312Revision 1.528  2007/11/02 21:32:30  cheshire
313<rdar://problem/5575593> BTMM: Deferring deregistration of record log messages on sleep/wake
314
315Revision 1.527  2007/11/01 16:08:51  cheshire
316Tidy up alignment of "SetRecordRetry refresh" log messages
317
318Revision 1.526  2007/10/31 19:26:55  cheshire
319Don't need to log "Permanently abandoning service registration" message when we're intentionally deleting a service
320
321Revision 1.525  2007/10/30 23:58:59  cheshire
322<rdar://problem/5496734> BTMM: Need to retry registrations after failures
323After failure, double retry interval up to maximum of 30 minutes
324
325Revision 1.524  2007/10/30 20:10:47  cheshire
326<rdar://problem/5496734> BTMM: Need to retry registrations after failures
327
328Revision 1.523  2007/10/30 00:54:31  cheshire
329<rdar://problem/5496734> BTMM: Need to retry registrations after failures
330Fixed timing logic to double retry interval properly
331
332Revision 1.522  2007/10/30 00:04:43  cheshire
333<rdar://problem/5496734> BTMM: Need to retry registrations after failures
334Made the code not give up and abandon the record when it gets an error in regState_UpdatePending state
335
336Revision 1.521  2007/10/29 23:58:52  cheshire
337<rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
338Use standard "if (mDNSIPv4AddressIsOnes(....ExternalAddress))" mechanism to determine whether callback has been invoked yet
339
340Revision 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
342Added 10% random variation on LLQ renewal time, to reduce unintended timing correlation between multiple machines
343
344Revision 1.519  2007/10/29 21:37:00  cheshire
345<rdar://problem/5496734> BTMM: Need to retry registrations after failures
346Added 10% random variation on record refresh time, to reduce accidental timing correlation between multiple machines
347
348Revision 1.518  2007/10/26 23:41:29  cheshire
349<rdar://problem/5496734> BTMM: Need to retry registrations after failures
350
351Revision 1.517  2007/10/25 23:30:12  cheshire
352Private DNS registered records now deregistered on sleep and re-registered on wake
353
354Revision 1.516  2007/10/25 22:53:52  cheshire
355<rdar://problem/5496734> BTMM: Need to retry registrations after failures
356Don't unlinkSRS and permanently give up at the first sign of trouble
357
358Revision 1.515  2007/10/25 21:08:07  cheshire
359Don't try to send record registrations/deletions before we have our server address
360
361Revision 1.514  2007/10/25 20:48:47  cheshire
362For naming consistency (with AuthRecord's UpdateServer) renamed 'ns' to 'SRSUpdateServer'
363
364Revision 1.513  2007/10/25 20:06:13  cheshire
365Don't try to do SOA queries using private DNS (TLS over TCP) queries
366
367Revision 1.512  2007/10/25 18:25:15  cheshire
368<rdar://problem/5496734> BTMM: Need to retry registrations after failures
369Don't need a NAT mapping for autotunnel services
370
371Revision 1.511  2007/10/25 00:16:23  cheshire
372<rdar://problem/5496734> BTMM: Need to retry registrations after failures
373Fixed retry timing logic; when DNS server returns an error code, we should retry later,
374instead of just deleting our record ("UnlinkAuthRecord") and completely giving up
375
376Revision 1.510  2007/10/24 22:40:06  cheshire
377Renamed: RecordRegistrationCallback          -> RecordRegistrationGotZoneData
378Renamed: ServiceRegistrationZoneDataComplete -> ServiceRegistrationGotZoneData
379
380Revision 1.509  2007/10/24 00:54:07  cheshire
381<rdar://problem/5496734> BTMM: Need to retry registrations after failures
382
383Revision 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
385When sending TLS/TCP LLQ setup request over VPN, need to set EventPort to 5353, not zero
386
387Revision 1.507  2007/10/23 00:33:36  cheshire
388Improved debugging messages
389
390Revision 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
392Only put EventPort in LLQ request when sending from an RFC 1918 source address, not when sending over VPN
393
394Revision 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
396Additional fixes and refinements
397
398Revision 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
400Additional fixes and refinements
401
402Revision 1.503  2007/10/18 20:23:17  cheshire
403Moved SuspendLLQs into mDNS.c, since it's only called from one place
404
405Revision 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
408Revision 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
411Revision 1.500  2007/10/17 21:53:51  cheshire
412Improved debugging messages; renamed startLLQHandshakeCallback to LLQGotZoneData
413
414Revision 1.499  2007/10/16 21:16:50  cheshire
415Get rid of unused uDNS_Sleep() routine
416
417Revision 1.498  2007/10/16 20:59:41  cheshire
418Export SuspendLLQs/SleepServiceRegistrations/SleepRecordRegistrations so they're callable from other files
419
420Revision 1.497  2007/10/05 18:09:44  cheshire
421<rdar://problem/5524841> Services advertised with wrong target host
422
423Revision 1.496  2007/10/04 22:38:59  cheshire
424Added LogOperation message showing new q->ThisQInterval after sending uDNS query packet
425
426Revision 1.495  2007/10/03 00:16:19  cheshire
427In PrivateQueryGotZoneData, need to grab lock before calling SetNextQueryTime
428
429Revision 1.494  2007/10/02 21:11:08  cheshire
430<rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing
431
432Revision 1.493  2007/10/02 19:50:23  cheshire
433Improved debugging message
434
435Revision 1.492  2007/09/29 03:15:43  cheshire
436<rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
437Use AutoTunnelUnregistered macro instead of checking record state directly
438
439Revision 1.491  2007/09/29 01:33:45  cheshire
440<rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
441
442Revision 1.490  2007/09/29 01:06:17  mcguire
443<rdar://problem/5507862> 9A564: mDNSResponder crash in mDNS_Execute
444
445Revision 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
448Revision 1.488  2007/09/27 21:20:17  cheshire
449Improved debugging syslog messages
450
451Revision 1.487  2007/09/27 18:55:11  cheshire
452<rdar://problem/5477165> BTMM: Multiple SRV records get registered after changing Computer Name
453
454Revision 1.486  2007/09/27 17:42:49  cheshire
455Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask"
456
457Revision 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
460Revision 1.484  2007/09/27 00:25:39  cheshire
461Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
462<rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
463
464Revision 1.483  2007/09/26 23:16:58  cheshire
465<rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac
466
467Revision 1.482  2007/09/26 22:06:02  cheshire
468<rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
469
470Revision 1.481  2007/09/26 00:49:46  cheshire
471Improve packet logging to show sent and received packets,
472transport protocol (UDP/TCP/TLS) and source/destination address:port
473
474Revision 1.480  2007/09/21 21:08:52  cheshire
475Get rid of unnecessary DumpPacket() calls -- it makes more sense
476to do this in mDNSSendDNSMessage and mDNSCoreReceive instead
477
478Revision 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
481Revision 1.478  2007/09/21 19:29:14  cheshire
482Added dump of uDNS questions when in MDNS_LOG_VERBOSE_DEBUG mode
483
484Revision 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
487Revision 1.476  2007/09/20 01:19:49  cheshire
488Improve debugging messages: report startLLQHandshake errors; show state in uDNS_StopLongLivedQuery message
489
490Revision 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
493Revision 1.474  2007/09/19 20:32:09  cheshire
494Export GetAuthInfoForName so it's callable from other files
495
496Revision 1.473  2007/09/18 21:42:29  cheshire
497To reduce programming mistakes, renamed ExtPort to RequestedPort
498
499Revision 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
502Revision 1.471  2007/09/14 01:07:10  cheshire
503If UPnP NAT gateway returns 0.0.0.0 as external address (e.g. because it hasn't
504got a DHCP address yet) then retry periodically until it gives us a real address.
505
506Revision 1.470  2007/09/13 00:36:26  cheshire
507<rdar://problem/5477360> NAT Reboot detection logic incorrect
508
509Revision 1.469  2007/09/13 00:28:50  cheshire
510<rdar://problem/5477354> Host records not updated on NAT address change
511
512Revision 1.468  2007/09/13 00:16:41  cheshire
513<rdar://problem/5468706> Miscellaneous NAT Traversal improvements
514
515Revision 1.467  2007/09/12 23:03:08  cheshire
516<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
517
518Revision 1.466  2007/09/12 22:19:29  cheshire
519<rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
520
521Revision 1.465  2007/09/12 19:22:19  cheshire
522Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
523Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
524
525Revision 1.464  2007/09/12 01:22:13  cheshire
526Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
527
528Revision 1.463  2007/09/11 20:23:28  vazquez
529<rdar://problem/5466719> CrashTracer: 3 crashes in mDNSResponder at mDNSResponder: natTraversalHandlePortMapReply + 107
530Make sure we clean up NATTraversals before free'ing HostnameInfo
531
532Revision 1.462  2007/09/11 19:19:16  cheshire
533Correct capitalization of "uPNP" to "UPnP"
534
535Revision 1.461  2007/09/10 22:08:17  cheshire
536Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
537
538Revision 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
540Try to allocate using port 5350 if we get a failure, and only log message if that fails too.
541
542Revision 1.459  2007/09/07 01:01:05  cheshire
543<rdar://problem/5464844> BTMM: Services being registered and deregistered in a loop
544In hndlServiceUpdateReply, need to clear SRVUpdateDeferred
545
546Revision 1.458  2007/09/06 19:14:33  cheshire
547Fixed minor error introduced in 1.379 (an "if" statement was deleted but the "else" following it was left there)
548
549Revision 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.
551Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance code needs
552to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
553otherwise those records will expire and vanish from the cache.
554
555Revision 1.456  2007/09/05 21:00:17  cheshire
556<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
557Additional refinement: ThisQInterval needs to be restored in tcpCallback, not in PrivateQueryGotZoneData
558
559Revision 1.455  2007/09/05 20:53:06  cheshire
560Tidied up alignment of code layout; code was clearing m->tcpAddrInfo.sock instead of m->tcpDeviceInfo.sock
561
562Revision 1.454  2007/09/05 02:32:55  cheshire
563Fixed posix build error (mixed declarations and code)
564
565Revision 1.453  2007/09/05 02:26:57  cheshire
566<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
567In PrivateQueryGotZoneData, restore q->ThisQInterval to non-zero value after GetZoneData completes
568
569Revision 1.452  2007/08/31 22:58:22  cheshire
570If we have an existing TCP connection we should re-use it instead of just bailing out
571After receiving dnsbugtest response, need to set m->NextScheduledQuery to cause queries to be re-issued
572
573Revision 1.451  2007/08/31 18:49:49  vazquez
574<rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
575
576Revision 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
579Revision 1.449  2007/08/30 00:43:17  cheshire
580Need to clear m->rec.r.resrec.RecordType before returning from uDNS_recvLLQResponse
581
582Revision 1.448  2007/08/30 00:18:46  cheshire
583<rdar://problem/5448804> Error messages: "SendServiceRegistration: Already have TCP connection..."
584
585Revision 1.447  2007/08/29 01:18:33  cheshire
586<rdar://problem/5400181> BTMM: Tunneled services do not need NAT port mappings
587Only create NAT mappings for SRV records with AutoTarget set to Target_AutoHostAndNATMAP
588
589Revision 1.446  2007/08/28 23:58:42  cheshire
590Rename HostTarget -> AutoTarget
591
592Revision 1.445  2007/08/28 23:53:21  cheshire
593Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
594
595Revision 1.444  2007/08/27 20:29:20  cheshire
596Additional debugging messages
597
598Revision 1.443  2007/08/24 23:18:28  cheshire
599mDNS_SetSecretForDomain is called with lock held; needs to use
600GetAuthInfoForName_internal() instead of external version GetAuthInfoForName()
601
602Revision 1.442  2007/08/24 22:43:06  cheshire
603Tidied up coded layout
604
605Revision 1.441  2007/08/24 01:20:55  cheshire
606<rdar://problem/5434381> BTMM: Memory corruption in KeychainChanged event handling
607
608Revision 1.440  2007/08/24 00:15:20  cheshire
609Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
610
611Revision 1.439  2007/08/23 21:47:09  vazquez
612<rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
613make sure we clean up port mappings on base stations by sending a lease value of 0,
614and only send NAT-PMP packets on private networks; also save some memory by
615not using packet structs in NATTraversals.
616
617Revision 1.438  2007/08/22 17:50:08  vazquez
618<rdar://problem/5399276> Need to handle errors returned by NAT-PMP routers properly
619Propagate router errors to clients, and stop logging spurious "message too short" logs.
620
621Revision 1.437  2007/08/18 00:54:15  mcguire
622<rdar://problem/5413147> BTMM: Should not register private addresses or zeros
623
624Revision 1.436  2007/08/08 21:07:48  vazquez
625<rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
626
627Revision 1.435  2007/08/03 02:04:09  vazquez
628<rdar://problem/5371843> BTMM: Private LLQs never fall back to polling
629Fix case where NAT-PMP returns an external address but does not support
630port mappings. Undo previous change and now, if the router returns an
631error in the reply packet we respect it.
632
633Revision 1.434  2007/08/02 21:03:05  vazquez
634Change NAT logic to fix case where base station with port mapping turned off
635returns an external address but does not make port mappings.
636
637Revision 1.433  2007/08/02 03:30:11  vazquez
638<rdar://problem/5371843> BTMM: Private LLQs never fall back to polling
639
640Revision 1.432  2007/08/01 18:15:19  cheshire
641Fixed crash in tcpCallback; fixed some problems with LLQ setup behind NAT
642
643Revision 1.431  2007/08/01 16:11:06  cheshire
644Fixed "mixed declarations and code" compiler error in Posix build
645
646Revision 1.430  2007/08/01 16:09:13  cheshire
647Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
648
649Revision 1.429  2007/08/01 03:09:22  cheshire
650<rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
651
652Revision 1.428  2007/08/01 01:43:36  cheshire
653Need to do mDNS_DropLockBeforeCallback/ReclaimLock around invokation of NAT client callback
654
655Revision 1.427  2007/08/01 01:31:13  cheshire
656Need to initialize traversal->tcpInfo fields or code may crash
657
658Revision 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
661Revision 1.425  2007/08/01 00:04:14  cheshire
662<rdar://problem/5261696> Crash in tcpKQSocketCallback
663Half-open TCP connections were not being cancelled properly
664
665Revision 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
668Revision 1.423  2007/07/30 23:31:26  cheshire
669Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
670
671Revision 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
674Revision 1.421  2007/07/28 00:04:14  cheshire
675Various fixes for comments and debugging messages
676
677Revision 1.420  2007/07/27 23:59:18  cheshire
678Added compile-time structure size checks
679
680Revision 1.419  2007/07/27 20:52:29  cheshire
681Made uDNS_recvLLQResponse() return tri-state result: LLQ_Not, LLQ_First, or LLQ_Events
682
683Revision 1.418  2007/07/27 20:32:05  vazquez
684Flag a UPnP NAT traversal before starting a UPnP port mapping, and make sure all
685calls to mDNS_StopNATOperation() go through the UPnP code
686
687Revision 1.417  2007/07/27 20:19:42  cheshire
688Use MDNS_LOG_VERBOSE_DEBUG for dumping out packets instead of MDNS_LOG_DEBUG
689
690Revision 1.416  2007/07/27 19:59:28  cheshire
691MUST NOT touch m->CurrentQuestion (or q) after calling AnswerCurrentQuestionWithResourceRecord()
692
693Revision 1.415  2007/07/27 19:51:01  cheshire
694Use symbol QC_addnocache instead of literal constant "2"
695
696Revision 1.414  2007/07/27 19:30:39  cheshire
697Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
698to properly reflect tri-state nature of the possible responses
699
700Revision 1.413  2007/07/27 18:44:01  cheshire
701Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
702
703Revision 1.412  2007/07/27 18:38:56  cheshire
704Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
705
706Revision 1.411  2007/07/27 00:57:13  cheshire
707Create hostname address records using standard kHostNameTTL (2 minutes) instead of 1 second
708
709Revision 1.410  2007/07/25 21:41:00  vazquez
710Make sure we clean up opened sockets when there are network transitions and when changing
711port mappings
712
713Revision 1.409  2007/07/25 03:05:02  vazquez
714Fixes for:
715<rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
716<rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
717and a myriad of other security problems
718
719Revision 1.408  2007/07/24 21:47:51  cheshire
720Don't do mDNS_StopNATOperation() for operations we never started
721
722Revision 1.407  2007/07/24 17:23:33  cheshire
723<rdar://problem/5357133> Add list validation checks for debugging
724
725Revision 1.406  2007/07/24 04:14:30  cheshire
726<rdar://problem/5356281> LLQs not working in with NAT Traversal
727
728Revision 1.405  2007/07/24 01:29:03  cheshire
729<rdar://problem/5356026> DNSServiceNATPortMappingCreate() returns stale external address information
730
731Revision 1.404  2007/07/20 23:10:51  cheshire
732Fix code layout
733
734Revision 1.403  2007/07/20 20:12:37  cheshire
735Rename "mDNS_DomainTypeBrowseLegacy" as "mDNS_DomainTypeBrowseAutomatic"
736
737Revision 1.402  2007/07/20 00:54:20  cheshire
738<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
739
740Revision 1.401  2007/07/18 03:23:33  cheshire
741In GetServiceTarget, need to call SetupLocalAutoTunnelInterface_internal to bring up tunnel on demand, if necessary
742
743Revision 1.400  2007/07/18 02:30:25  cheshire
744Defer AutoTunnel server record advertising until we have at least one service to advertise
745Do AutoTunnel target host selection in GetServiceTarget (instead of uDNS_RegisterService)
746
747Revision 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
749Declare records as kDNSRecordTypeKnownUnique so we don't get name conflicts with ourselves
750
751Revision 1.398  2007/07/16 23:54:48  cheshire
752<rdar://problem/5338850> Crash when removing or changing DNS keys
753
754Revision 1.397  2007/07/16 20:13:31  vazquez
755<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
756
757Revision 1.396  2007/07/14 00:33:04  cheshire
758Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working
759
760Revision 1.395  2007/07/12 23:56:23  cheshire
761Change "GetZoneData GOT SRV" message to debugf to reduce verbosity in syslog
762
763Revision 1.394  2007/07/12 23:36:08  cheshire
764Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog
765
766Revision 1.393  2007/07/12 22:15:10  cheshire
767Modified mDNS_SetSecretForDomain() so it can be called to update an existing entry
768
769Revision 1.392  2007/07/12 02:51:27  cheshire
770<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
771
772Revision 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
774Need to prepend _autotunnel._udp to start of AutoTunnel SRV record name
775
776Revision 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
778In mDNS_SetSecretForDomain(), don't register records until after we've validated the parameters
779
780Revision 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
782Set up and register AutoTunnelTarget and AutoTunnelService DNS records
783
784Revision 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
786For temporary testing fake up an IPv4LL address instead of IPv6 ULA
787
788Revision 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
790Add AutoTunnel parameter to mDNS_SetSecretForDomain; Set up AutoTunnel information for domains that require it
791
792Revision 1.386  2007/07/10 01:57:28  cheshire
793<rdar://problem/5196524> uDNS: mDNSresponder is leaking TCP connections to DNS server
794Turned vast chunks of replicated code into a subroutine MakeTCPConn(...);
795Made routines hold on to the reference it returns instead of leaking it
796
797Revision 1.385  2007/07/09 23:50:18  cheshire
798unlinkSRS needs to call mDNS_StopNATOperation_internal(), not mDNS_StopNATOperation()
799
800Revision 1.384  2007/07/06 21:20:21  cheshire
801Fix scheduling error (was causing "Task Scheduling Error: Continuously busy for more than a second")
802
803Revision 1.383  2007/07/06 18:59:59  cheshire
804Avoid spinning in an infinite loop when uDNS_SendNATMsg() returns an error
805
806Revision 1.382  2007/07/04 00:49:43  vazquez
807Clean up extraneous comments
808
809Revision 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
813Revision 1.380  2007/07/02 22:08:47  cheshire
814Fixed crash in "Received public IP address" message
815
816Revision 1.379  2007/06/29 00:08:49  vazquez
817<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
818
819Revision 1.378  2007/06/27 20:25:10  cheshire
820Expanded dnsbugtest comment, explaining requirement that we also need these
821test queries to black-hole before they get to the root name servers.
822
823Revision 1.377  2007/06/22 21:27:21  cheshire
824Modified "could not convert shared secret from base64" log message
825
826Revision 1.376  2007/06/20 01:10:12  cheshire
827<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
828
829Revision 1.375  2007/06/15 21:54:51  cheshire
830<rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
831
832Revision 1.374  2007/06/12 02:15:26  cheshire
833Fix incorrect "DNS Server passed" LogOperation message
834
835Revision 1.373  2007/05/31 00:25:43  cheshire
836<rdar://problem/5238688> Only send dnsbugtest query for questions where it's warranted
837
838Revision 1.372  2007/05/25 17:03:45  cheshire
839lenptr needs to be declared unsigned, otherwise sign extension can mess up the shifting and ORing operations
840
841Revision 1.371  2007/05/24 00:11:44  cheshire
842Remove unnecessary lenbuf field from tcpInfo_t
843
844Revision 1.370  2007/05/23 00:30:59  cheshire
845Don't change question->TargetQID when repeating query over TCP
846
847Revision 1.369  2007/05/21 18:04:40  cheshire
848Updated comments -- port_mapping_create_reply renamed to port_mapping_reply
849
850Revision 1.368  2007/05/17 19:12:16  cheshire
851Updated comment about finding matching pair of sockets
852
853Revision 1.367  2007/05/15 23:38:00  cheshire
854Need to grab lock before calling SendRecordRegistration();
855
856Revision 1.366  2007/05/15 00:43:05  cheshire
857<rdar://problem/4983538> uDNS serviceRegistrationCallback locking failures
858
859Revision 1.365  2007/05/10 21:19:18  cheshire
860Rate-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
863Revision 1.364  2007/05/07 20:43:45  cheshire
864<rdar://problem/4241419> Reduce the number of queries and announcements
865
866Revision 1.363  2007/05/04 22:12:48  cheshire
867Work towards solving <rdar://problem/5176892> "uDNS_CheckQuery: LastQTime" log messages
868When code gets in this invalid state, double ThisQInterval each time, to avoid excessive logging
869
870Revision 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
872Preparatory work to enable us to do a four-way LLQ handshake over TCP, if we decide that's what we want
873
874Revision 1.361  2007/05/03 23:50:48  cheshire
875<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
876In the case of negative answers for the address record, set the server address to zerov4Addr
877
878Revision 1.360  2007/05/03 22:40:38  cheshire
879<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
880
881Revision 1.359  2007/05/02 22:21:33  cheshire
882<rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
883
884Revision 1.358  2007/05/01 21:46:31  cheshire
885Move GetLLQOptData/GetPktLease from uDNS.c into DNSCommon.c so that dnsextd can use them
886
887Revision 1.357  2007/05/01 01:33:49  cheshire
888Removed "#define LLQ_Info DNSQuestion" and manually reconciled code that was still referring to "LLQ_Info"
889
890Revision 1.356  2007/04/30 21:51:06  cheshire
891Updated comments
892
893Revision 1.355  2007/04/30 21:33:38  cheshire
894Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
895is iterating through the m->ServiceRegistrations list
896
897Revision 1.354  2007/04/30 01:30:04  cheshire
898GetZoneData_QuestionCallback needs to call client callback function on error, so client knows operation is finished
899RecordRegistrationCallback and serviceRegistrationCallback need to clear nta reference when they're invoked
900
901Revision 1.353  2007/04/28 01:28:25  cheshire
902Fixed memory leak on error path in FoundDomain
903
904Revision 1.352  2007/04/27 19:49:53  cheshire
905In uDNS_ReceiveTestQuestionResponse, also check that srcport matches
906
907Revision 1.351  2007/04/27 19:28:02  cheshire
908Any code that calls StartGetZoneData needs to keep a handle to the structure, so
909it 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
911StartGetZoneData completed, it had a dangling pointer and crashed.)
912
913Revision 1.350  2007/04/26 22:47:14  cheshire
914Defensive coding: tcpCallback only needs to check "if (closed)", not "if (!n && closed)"
915
916Revision 1.349  2007/04/26 16:04:06  cheshire
917In mDNS_AddDNSServer, check whether port matches
918In uDNS_CheckQuery, handle case where startLLQHandshake changes q->llq->state to LLQ_Poll
919
920Revision 1.348  2007/04/26 04:01:59  cheshire
921Copy-and-paste error: Test should be "if (result == DNSServer_Passed)" not "if (result == DNSServer_Failed)"
922
923Revision 1.347  2007/04/26 00:35:15  cheshire
924<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
925Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
926inside the firewall may give answers where a public one gives none, and vice versa.)
927
928Revision 1.346  2007/04/25 19:16:59  cheshire
929Don't set SuppressStdPort53Queries unless we do actually send a DNS packet
930
931Revision 1.345  2007/04/25 18:05:11  cheshire
932Don't try to restart inactive (duplicate) queries
933
934Revision 1.344  2007/04/25 17:54:07  cheshire
935Don't cancel Private LLQs using a clear-text UDP packet
936
937Revision 1.343  2007/04/25 16:40:08  cheshire
938Add comment explaining uDNS_recvLLQResponse logic
939
940Revision 1.342  2007/04/25 02:14:38  cheshire
941<rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
942Additional fixes to make LLQs work properly
943
944Revision 1.341  2007/04/24 02:07:42  cheshire
945<rdar://problem/4246187> Identical client queries should reference a single shared core query
946Deleted some more redundant code
947
948Revision 1.340  2007/04/23 22:01:23  cheshire
949<rdar://problem/5094009> IPv6 filtering in AirPort base station breaks Wide-Area Bonjour
950As of March 2007, AirPort base stations now block incoming IPv6 connections by default, so there's no point
951advertising IPv6 addresses in DNS any more -- we have to assume that most of the time a host's IPv6 address
952probably won't work for incoming connections (but its IPv4 address probably will, using NAT-PMP).
953
954Revision 1.339  2007/04/22 06:02:03  cheshire
955<rdar://problem/4615977> Query should immediately return failure when no server
956
957Revision 1.338  2007/04/21 19:44:11  cheshire
958Improve uDNS_HandleNATPortMapReply log message
959
960Revision 1.337  2007/04/21 02:03:00  cheshire
961Also need to set AddressRec->resrec.RecordType in the NAT case too
962
963Revision 1.336  2007/04/20 21:16:12  cheshire
964Fixed bogus double-registration of host name -- was causing these warning messages in syslog:
965Error! Tried to register AuthRecord 0181FB0C host.example.com. (Addr) that's already in the list
966
967Revision 1.335  2007/04/19 23:57:20  cheshire
968Temporary workaround for some AirPort base stations that don't seem to like us requesting public port zero
969
970Revision 1.334  2007/04/19 23:21:51  cheshire
971Fixed a couple of places where the StartGetZoneData check was backwards
972
973Revision 1.333  2007/04/19 22:50:53  cheshire
974<rdar://problem/4246187> Identical client queries should reference a single shared core query
975
976Revision 1.332  2007/04/19 20:34:32  cheshire
977Add debugging log message in uDNS_CheckQuery()
978
979Revision 1.331  2007/04/19 20:06:41  cheshire
980Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
981
982Revision 1.330  2007/04/19 19:51:54  cheshire
983Get rid of unnecessary initializeQuery() routine
984
985Revision 1.329  2007/04/19 18:03:52  cheshire
986Improved "mDNS_AddSearchDomain" log message
987
988Revision 1.328  2007/04/18 20:57:20  cheshire
989Commented out "GetAuthInfoForName none found" debugging message
990
991Revision 1.327  2007/04/17 19:21:29  cheshire
992<rdar://problem/5140339> Domain discovery not working over VPN
993
994Revision 1.326  2007/04/16 20:49:39  cheshire
995Fix compile errors for mDNSPosix build
996
997Revision 1.325  2007/04/05 22:55:35  cheshire
998<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
999
1000Revision 1.324  2007/04/05 20:43:30  cheshire
1001Collapse sprawling code onto one line -- this is part of a bigger block of identical
1002code that has been copied-and-pasted into six different places in the same file.
1003This really needs to be turned into a subroutine.
1004
1005Revision 1.323  2007/04/04 21:48:52  cheshire
1006<rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
1007
1008Revision 1.322  2007/04/03 19:53:06  cheshire
1009Use mDNSSameIPPort (and similar) instead of accessing internal fields directly
1010
1011Revision 1.321  2007/04/02 23:44:09  cheshire
1012Minor code tidying
1013
1014Revision 1.320  2007/03/31 01:26:13  cheshire
1015Take out GetAuthInfoForName syslog message
1016
1017Revision 1.319  2007/03/31 01:10:53  cheshire
1018Add debugging
1019
1020Revision 1.318  2007/03/31 00:17:11  cheshire
1021Remove some LogMsgs
1022
1023Revision 1.317  2007/03/29 00:09:31  cheshire
1024Improve "uDNS_InitLongLivedQuery" log message
1025
1026Revision 1.316  2007/03/28 21:16:27  cheshire
1027Remove DumpPacket() call now that OPT pseudo-RR rrclass bug is fixed
1028
1029Revision 1.315  2007/03/28 21:02:18  cheshire
1030<rdar://problem/3810563> Wide-Area Bonjour should work on multi-subnet private network
1031
1032Revision 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
1035Revision 1.313  2007/03/28 01:27:32  cheshire
1036<rdar://problem/4996439> Unicast DNS polling server every three seconds
1037StartLLQPolling was using INIT_UCAST_POLL_INTERVAL instead of LLQ_POLL_INTERVAL for the retry interval
1038
1039Revision 1.312  2007/03/27 23:48:21  cheshire
1040Use mDNS_StopGetDomains(), not mDNS_StopQuery()
1041
1042Revision 1.311  2007/03/27 22:47:51  cheshire
1043Remove unnecessary "*(long*)0 = 0;" to generate crash and stack trace
1044
1045Revision 1.310  2007/03/24 01:24:13  cheshire
1046Add validator for uDNS data structures; fixed crash in RegisterSearchDomains()
1047
1048Revision 1.309  2007/03/24 00:47:53  cheshire
1049<rdar://problem/4983538> serviceRegistrationCallback: Locking Failure! mDNS_busy (1) != mDNS_reentrancy (2)
1050Locking in this file is all messed up. For now we'll just work around the issue.
1051
1052Revision 1.308  2007/03/24 00:41:33  cheshire
1053Minor code cleanup (move variable declarations to minimum enclosing scope)
1054
1055Revision 1.307  2007/03/21 23:06:00  cheshire
1056Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
1057
1058Revision 1.306  2007/03/21 00:30:03  cheshire
1059<rdar://problem/4789455> Multiple errors in DNameList-related code
1060
1061Revision 1.305  2007/03/20 17:07:15  cheshire
1062Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
1063
1064Revision 1.304  2007/03/17 00:02:11  cheshire
1065<rdar://problem/5067013> NAT-PMP: Lease TTL is being ignored
1066
1067Revision 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
1070Revision 1.302  2007/03/10 02:29:58  cheshire
1071Added comments about NAT-PMP response functions
1072
1073Revision 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
1075Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
1076
1077Revision 1.300  2007/03/08 18:56:00  cheshire
1078Fixed typo: "&v4.ip.v4.b[0]" is always non-zero (ampersand should not be there)
1079
1080Revision 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
1084Revision 1.298  2007/02/14 03:16:39  cheshire
1085<rdar://problem/4789477> Eliminate unnecessary malloc/free in mDNSCore code
1086
1087Revision 1.297  2007/02/08 21:12:28  cheshire
1088<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
1089
1090Revision 1.296  2007/01/29 16:03:22  cheshire
1091Fix unused parameter warning
1092
1093Revision 1.295  2007/01/27 03:34:27  cheshire
1094Made GetZoneData use standard queries (and cached results);
1095eliminated GetZoneData_Callback() packet response handler
1096
1097Revision 1.294  2007/01/25 00:40:16  cheshire
1098Unified CNAME-following functionality into cache management code (which means CNAME-following
1099should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine.
1100
1101Revision 1.293  2007/01/23 02:56:11  cheshire
1102Store negative results in the cache, instead of generating them out of pktResponseHndlr()
1103
1104Revision 1.292  2007/01/20 01:32:40  cheshire
1105Update comments and debugging messages
1106
1107Revision 1.291  2007/01/20 00:07:02  cheshire
1108When we have credentials in the keychain for a domain, we attempt private queries, but
1109if the authoritative server is not set up for private queries (i.e. no _dns-query-tls
1110or _dns-llq-tls record) then we need to fall back to conventional non-private queries.
1111
1112Revision 1.290  2007/01/19 23:41:45  cheshire
1113Need to clear m->rec.r.resrec.RecordType after calling GetLLQOptData()
1114
1115Revision 1.289  2007/01/19 23:32:07  cheshire
1116Eliminate pointless timenow variable
1117
1118Revision 1.288  2007/01/19 23:26:08  cheshire
1119Right now tcpCallback does not run holding the lock, so no need to drop the lock before invoking callbacks
1120
1121Revision 1.287  2007/01/19 22:55:41  cheshire
1122Eliminate redundant identical parameters to GetZoneData_StartQuery()
1123
1124Revision 1.286  2007/01/19 21:17:33  cheshire
1125StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
1126
1127Revision 1.285  2007/01/19 18:39:11  cheshire
1128Fix a bunch of parameters that should have been declared "const"
1129
1130Revision 1.284  2007/01/19 18:28:28  cheshire
1131Improved debugging messages
1132
1133Revision 1.283  2007/01/19 18:09:33  cheshire
1134Fixed getLLQAtIndex (now called GetLLQOptData):
11351. It incorrectly assumed all EDNS0 OPT records are the same size (it ignored optlen)
11362. It used inefficient memory copying instead of just returning a pointer
1137
1138Revision 1.282  2007/01/17 22:06:01  cheshire
1139Replace duplicated literal constant "{ { 0 } }" with symbol "zeroIPPort"
1140
1141Revision 1.281  2007/01/17 21:58:13  cheshire
1142For clarity, rename ntaContext field "isPrivate" to "ntaPrivate"
1143
1144Revision 1.280  2007/01/17 21:46:02  cheshire
1145Remove redundant duplicated "isPrivate" field from LLQ_Info
1146
1147Revision 1.279  2007/01/17 21:35:31  cheshire
1148For clarity, rename zoneData_t field "isPrivate" to "zonePrivate"
1149
1150Revision 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
1152Don't cache result of ntaContextSRV(context) in a local variable --
1153the macro evaluates to a different result after we clear "context->isPrivate"
1154
1155Revision 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
1158Revision 1.276  2007/01/10 02:09:30  cheshire
1159Better LogOperation record of keys read from System Keychain
1160
1161Revision 1.275  2007/01/09 22:37:18  cheshire
1162Provide ten-second grace period for deleted keys, to give mDNSResponder
1163time to delete host name before it gives up access to the required key.
1164
1165Revision 1.274  2007/01/09 01:16:32  cheshire
1166Improve "ERROR m->CurrentQuestion already set" debugging messages
1167
1168Revision 1.273  2007/01/08 23:58:00  cheshire
1169Don't request regDomain and browseDomains in uDNS_SetupDNSConfig() -- it just ignores those results
1170
1171Revision 1.272  2007/01/05 08:30:42  cheshire
1172Trim excessive "Log" checkin history from before 2006
1173(checkin history still available via "cvs log ..." of course)
1174
1175Revision 1.271  2007/01/05 06:34:03  cheshire
1176Improve "ERROR m->CurrentQuestion already set" debugging messages
1177
1178Revision 1.270  2007/01/05 05:44:33  cheshire
1179Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c,
1180so that mDNSPosix embedded clients will compile again
1181
1182Revision 1.269  2007/01/04 23:11:13  cheshire
1183<rdar://problem/4720673> uDNS: Need to start caching unicast records
1184When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
1185
1186Revision 1.268  2007/01/04 22:06:38  cheshire
1187Fixed crash in LLQNatMapComplete()
1188
1189Revision 1.267  2007/01/04 21:45:20  cheshire
1190Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
1191to do additional lock sanity checking around callback invocations
1192
1193Revision 1.266  2007/01/04 21:01:20  cheshire
1194<rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
1195Only return NXDOMAIN results to clients that request them using kDNSServiceFlagsReturnIntermediates
1196
1197Revision 1.265  2007/01/04 20:47:17  cheshire
1198Fixed crash in CheckForUnreferencedLLQMapping()
1199
1200Revision 1.264  2007/01/04 20:39:27  cheshire
1201Fix locking mismatch
1202
1203Revision 1.263  2007/01/04 02:39:53  cheshire
1204<rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
1205
1206Revision 1.262  2007/01/04 00:29:25  cheshire
1207Covert LogMsg() in GetAuthInfoForName to LogOperation()
1208
1209Revision 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
1213Revision 1.260  2006/12/21 00:06:07  cheshire
1214Don't need to do mDNSPlatformMemZero() -- mDNS_SetupResourceRecord() does it for us
1215
1216Revision 1.259  2006/12/20 04:07:36  cheshire
1217Remove uDNS_info substructure from AuthRecord_struct
1218
1219Revision 1.258  2006/12/19 22:49:24  cheshire
1220Remove uDNS_info substructure from ServiceRecordSet_struct
1221
1222Revision 1.257  2006/12/19 02:38:20  cheshire
1223Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
1224
1225Revision 1.256  2006/12/19 02:18:48  cheshire
1226Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
1227
1228Revision 1.255  2006/12/16 01:58:31  cheshire
1229<rdar://problem/4720673> uDNS: Need to start caching unicast records
1230
1231Revision 1.254  2006/12/15 19:23:39  cheshire
1232Use new DomainNameLengthLimit() function, to be more defensive against malformed
1233data received from the network.
1234
1235Revision 1.253  2006/12/01 07:43:34  herscher
1236Fix byte ordering problem for one-shot TCP queries.
1237Iterate more intelligently over duplicates in uDNS_ReceiveMsg to avoid spin loops.
1238
1239Revision 1.252  2006/11/30 23:07:57  herscher
1240<rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
1241
1242Revision 1.251  2006/11/28 21:42:11  mkrochma
1243Work around a crashing bug that was introduced by uDNS and mDNS code unification
1244
1245Revision 1.250  2006/11/18 05:01:30  cheshire
1246Preliminary support for unifying the uDNS and mDNS code,
1247including caching of uDNS answers
1248
1249Revision 1.249  2006/11/10 07:44:04  herscher
1250<rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
1251
1252Revision 1.248  2006/11/08 04:26:53  cheshire
1253Fix typo in debugging message
1254
1255Revision 1.247  2006/10/20 05:35:04  herscher
1256<rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
1257
1258Revision 1.246  2006/10/11 19:29:41  herscher
1259<rdar://problem/4744553> uDNS: mDNSResponder-111 using 100% CPU
1260
1261Revision 1.245  2006/10/04 22:21:15  herscher
1262Tidy up references to mDNS_struct introduced when the embedded uDNS_info struct was removed.
1263
1264Revision 1.244  2006/10/04 21:51:27  herscher
1265Replace calls to mDNSPlatformTimeNow(m) with m->timenow
1266
1267Revision 1.243  2006/10/04 21:38:59  herscher
1268Remove uDNS_info substructure from DNSQuestion_struct
1269
1270Revision 1.242  2006/09/27 00:51:46  herscher
1271Fix compile error when _LEGACY_NAT_TRAVERSAL_ is not defined
1272
1273Revision 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
1276Revision 1.240  2006/09/15 21:20:15  cheshire
1277Remove uDNS_info substructure from mDNS_struct
1278
1279Revision 1.239  2006/08/16 02:52:56  mkrochma
1280<rdar://problem/4104154> Actually fix it this time
1281
1282Revision 1.238  2006/08/16 00:31:50  mkrochma
1283<rdar://problem/4386944> Get rid of NotAnInteger references
1284
1285Revision 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
1288Revision 1.236  2006/08/14 23:24:23  cheshire
1289Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
1290
1291Revision 1.235  2006/07/30 05:45:36  cheshire
1292<rdar://problem/4304215> Eliminate MIN_UCAST_PERIODIC_EXEC
1293
1294Revision 1.234  2006/07/22 02:58:36  cheshire
1295Code was clearing namehash twice instead of namehash and rdatahash
1296
1297Revision 1.233  2006/07/20 19:46:51  mkrochma
1298<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1299Fix Private DNS
1300
1301Revision 1.232  2006/07/15 02:01:29  cheshire
1302<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1303Fix broken "empty string" browsing
1304
1305Revision 1.231  2006/07/05 23:28:22  cheshire
1306<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1307
1308Revision 1.230  2006/06/29 03:02:44  cheshire
1309<rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
1310
1311Revision 1.229  2006/03/02 22:03:41  cheshire
1312<rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
1313Refinement: m->rec.r.resrec.RecordType needs to be cleared *every* time around for loop, not just once at the end
1314
1315Revision 1.228  2006/02/26 00:54:42  cheshire
1316Fixes to avoid code generation warning/error on FreeBSD 7
1317
1318Revision 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.
1339mDNSexport 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.
1346ServiceRecordSet *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.
1356mDNSlocal 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)
1373mDNSlocal 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
1401mDNSlocal 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
1445mDNSexport 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
1492mDNSexport 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
1518end:
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
1534mDNSlocal 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
1553mDNSexport 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
1590mDNSexport 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
1600mDNSexport 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
1659mDNSlocal 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
1694mDNSexport 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
1710mDNSexport 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
1748mDNSlocal 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
1757mDNSexport 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
1794mDNSexport 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
1850mDNSexport 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
1900mDNSexport 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
1909mDNSexport 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
1925mDNSlocal 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
1939mDNSlocal 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
1975mDNSlocal 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
1985mDNSlocal 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
2028mDNSlocal 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
2039mDNSlocal 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
2095mDNSexport 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.)
2174struct 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
2178mDNSlocal 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
2329exit:
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
2365mDNSlocal 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
2409mDNSexport 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
2417mDNSexport 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
2505mDNSlocal void GetStaticHostname(mDNS *m);
2506
2507mDNSexport 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
2551mDNSlocal 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
2669exit:
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
2684mDNSlocal const domainname *PUBLIC_UPDATE_SERVICE_TYPE  = (const domainname*)"\x0B_dns-update"     "\x04_udp";
2685mDNSlocal const domainname *PUBLIC_LLQ_SERVICE_TYPE     = (const domainname*)"\x08_dns-llq"        "\x04_udp";
2686
2687mDNSlocal const domainname *PRIVATE_UPDATE_SERVICE_TYPE = (const domainname*)"\x0F_dns-update-tls" "\x04_tcp";
2688mDNSlocal const domainname *PRIVATE_QUERY_SERVICE_TYPE  = (const domainname*)"\x0E_dns-query-tls"  "\x04_tcp";
2689mDNSlocal 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
2698mDNSlocal 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)
2701mDNSlocal 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)
2791mDNSlocal 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)
2818mDNSexport 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
2852mDNSexport 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)
2865mDNSlocal 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
2887mDNSlocal 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)
2907mDNSexport 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
2962mDNSlocal 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
3012exit:
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
3022mDNSlocal 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
3117mDNSlocal 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
3139mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
3140
3141// Called in normal client context (lock not held)
3142mDNSlocal 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
3170mDNSlocal 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
3209mDNSlocal 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
3276mDNSlocal 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
3313mDNSlocal 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
3344mDNSexport 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
3367mDNSexport 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?
3394mDNSexport 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
3483mDNSlocal 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
3532mDNSlocal 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
3580mDNSlocal 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
3663exit:
3664	LogMsg("SendRecordRegistration: Error formatting message for %s", ARDisplayString(m, rr));
3665	}
3666
3667// Called with lock held
3668mDNSlocal 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
3863mDNSlocal 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
3959mDNSexport 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
4075mDNSlocal 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
4081mDNSlocal 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
4101mDNSlocal 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
4163mDNSexport 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
4260mDNSexport 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
4317mDNSexport 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)
4354mDNSlocal 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)
4404mDNSexport 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
4480mDNSlocal 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
4524mDNSexport 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
4548mDNSexport 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
4603mDNSexport 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.
4682mDNSexport 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
4798mDNSlocal 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
4933mDNSlocal 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
4963mDNSlocal 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
4999mDNSexport 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
5030mDNSexport 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
5045mDNSexport 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
5083mDNSexport 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
5107mDNSlocal 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
5113mDNSlocal 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
5167mDNSexport 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
5206mDNSexport 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
5296struct 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