]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSCore/uDNS.c
mDNSResponder-214.3.tar.gz
[apple/mdnsresponder.git] / mDNSCore / uDNS.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16
17 * To Do:
18 * Elimate all mDNSPlatformMemAllocate/mDNSPlatformMemFree from this code -- the core code
19 * is supposed to be malloc-free so that it runs in constant memory determined at compile-time.
20 * Any dynamic run-time requirements should be handled by the platform layer below or client layer above
21
22 Change History (most recent first):
23
24 $Log: uDNS.c,v $
25 Revision 1.617 2009/06/30 20:51:02 cheshire
26 Improved "Error! Tried to add a NAT traversal that's already in the active list" debugging message
27
28 Revision 1.616 2009/05/27 20:29:36 cheshire
29 <rdar://problem/6926465> Sleep is delayed by 10 seconds if BTMM is on
30 After receiving confirmation of LLQ deletion, need to schedule another evaluation of whether we're ready to sleep yet
31
32 Revision 1.615 2009/05/05 01:32:50 jessic2
33 <rdar://problem/6830541> regservice_callback: instance->request is NULL 0 -- Clean up spurious logs resulting from fixing this bug.
34
35 Revision 1.614 2009/04/24 02:17:57 mcguire
36 <rdar://problem/5264124> uDNS: Not always respecting preference order of DNS servers
37
38 Revision 1.613 2009/04/23 22:06:29 cheshire
39 Added CacheRecord and InterfaceID parameters to MakeNegativeCacheRecord, in preparation for:
40 <rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
41
42 Revision 1.612 2009/04/22 01:19:57 jessic2
43 <rdar://problem/6814585> Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32
44
45 Revision 1.611 2009/04/15 20:42:51 mcguire
46 <rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures
47
48 Revision 1.610 2009/04/15 01:10:39 jessic2
49 <rdar://problem/6466541> BTMM: Add support for setting kDNSServiceErr_NoSuchRecord in DynamicStore
50
51 Revision 1.609 2009/04/11 00:19:45 jessic2
52 <rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
53
54 Revision 1.608 2009/04/06 23:44:59 cheshire
55 <rdar://problem/6757838> mDNSResponder thrashing kernel lock in the UDP close path, hurting SPECweb performance
56
57 Revision 1.607 2009/04/02 22:36:34 jessic2
58 Fix crash when calling debugf with null opt
59
60 Revision 1.606 2009/03/26 03:59:00 jessic2
61 Changes for <rdar://problem/6492552&6492593&6492609&6492613&6492628&6492640&6492699>
62
63 Revision 1.605 2009/03/04 00:40:14 cheshire
64 Updated DNS server error codes to be more consistent with definitions at
65 <http://www.iana.org/assignments/dns-parameters>
66
67 Revision 1.604 2009/02/27 03:08:47 cheshire
68 <rdar://problem/6547720> Crash while shutting down when "local" is in the user's DNS searchlist
69
70 Revision 1.603 2009/02/27 02:56:57 cheshire
71 Moved struct SearchListElem definition from uDNS.c into mDNSEmbeddedAPI.h
72
73 Revision 1.602 2009/02/13 06:29:54 cheshire
74 Converted LogOperation messages to LogInfo
75
76 Revision 1.601 2009/02/12 20:57:25 cheshire
77 Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch
78
79 Revision 1.600 2009/01/31 21:05:12 cheshire
80 Improved "Failed to obtain NAT port mapping" debugging log message
81
82 Revision 1.599 2009/01/23 00:38:36 mcguire
83 <rdar://problem/5570906> BTMM: Doesn't work with Linksys WRT54GS firmware 4.71.1
84
85 Revision 1.598 2009/01/21 03:43:57 mcguire
86 <rdar://problem/6511765> BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore
87
88 Revision 1.597 2009/01/10 01:55:49 cheshire
89 Added LogOperation message showing when domains are added and removed in FoundDomain
90
91 Revision 1.596 2008/12/19 20:23:33 mcguire
92 <rdar://problem/6459269> Lots of duplicate log messages about failure to bind to NAT-PMP Announcement port
93
94 Revision 1.595 2008/12/18 23:32:19 mcguire
95 <rdar://problem/6019470> BTMM: Include the question in the LLQ notification acknowledgment
96
97 Revision 1.594 2008/12/10 02:25:31 cheshire
98 Minor fixes to use of LogClientOperations symbol
99
100 Revision 1.593 2008/12/10 02:11:42 cheshire
101 ARMv5 compiler doesn't like uncommented stuff after #endif
102
103 Revision 1.592 2008/12/06 01:42:55 mcguire
104 <rdar://problem/6418958> Need to exponentially back-off after failure to get public address
105
106 Revision 1.591 2008/12/06 00:17:11 cheshire
107 <rdar://problem/6380477> mDNS_StopNATOperation doesn't handle duplicate NAT mapping requests properly
108 Refinement: For duplicate ssh mappings we want to suppress the syslog warning message, but not the "unmap = mDNSfalse"
109
110 Revision 1.590 2008/12/04 20:57:36 mcguire
111 fix build
112
113 Revision 1.589 2008/12/04 02:24:09 cheshire
114 Improved NAT-PMP debugging messages
115
116 Revision 1.588 2008/11/26 20:38:08 cheshire
117 Changed some "LogOperation" debugging messages to "debugf"
118
119 Revision 1.587 2008/11/26 19:53:26 cheshire
120 Don't overwrite srs->NATinfo.IntPort in StartSRVNatMap()
121
122 Revision 1.586 2008/11/25 23:43:07 cheshire
123 <rdar://problem/5745355> Crashes at ServiceRegistrationGotZoneData + 397
124 Made code more defensive to guard against ServiceRegistrationGotZoneData being called with invalid ServiceRecordSet object
125
126 Revision 1.585 2008/11/25 22:46:30 cheshire
127 For ease of code searching, renamed ZoneData field of ServiceRecordSet_struct from "nta" to "srs_nta"
128
129 Revision 1.584 2008/11/24 19:46:40 cheshire
130 When sending query over TCP, don't include LLQ option when we're talking to a conventional DNS server or cache
131
132 Revision 1.583 2008/11/21 00:34:58 cheshire
133 <rdar://problem/6380477> mDNS_StopNATOperation doesn't handle duplicate NAT mapping requests properly
134
135 Revision 1.582 2008/11/20 02:23:37 mcguire
136 <rdar://problem/6041208> need to handle URLBase
137
138 Revision 1.581 2008/11/20 01:51:19 cheshire
139 Exported RecreateNATMappings so it's callable from other files
140
141 Revision 1.580 2008/11/13 19:08:45 cheshire
142 Fixed code to handle rdataOPT properly
143
144 Revision 1.579 2008/11/07 00:18:01 mcguire
145 <rdar://problem/6351068> uDNS: Supress reverse DNS query until required
146
147 Revision 1.578 2008/11/04 22:21:46 cheshire
148 Changed zone field of AuthRecord_struct from domainname to pointer, saving 252 bytes per AuthRecord
149
150 Revision 1.577 2008/10/29 21:37:01 cheshire
151 Removed some old debugging messages
152
153 Revision 1.576 2008/10/23 22:25:57 cheshire
154 Renamed field "id" to more descriptive "updateid"
155
156 Revision 1.575 2008/10/20 02:07:49 mkrochma
157 <rdar://problem/6296804> Remove Note: DNS Server <ip> for domain <d> registered more than once
158
159 Revision 1.574 2008/10/14 19:06:45 cheshire
160 In uDNS_ReceiveMsg(), only do checkUpdateResult() for uDNS records
161
162 Revision 1.573 2008/09/25 20:43:44 cheshire
163 <rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
164 In UpdateSRVRecords, call mDNS_SetFQDN(m) to update AutoTarget SRV records on the main m->ResourceRecords list
165
166 Revision 1.572 2008/09/24 23:48:05 cheshire
167 Don't need to pass whole ServiceRecordSet reference to GetServiceTarget;
168 it only needs to access the embedded SRV member of the set
169
170 Revision 1.571 2008/09/23 22:56:53 cheshire
171 <rdar://problem/5298845> Remove dnsbugtest query
172
173 Revision 1.570 2008/09/23 01:30:18 cheshire
174 The putLLQ() routine was not setting the OPT record's rrclass to NormalMaxDNSMessageData
175
176 Revision 1.569 2008/07/25 22:34:11 mcguire
177 fix sizecheck issues for 64bit
178
179 Revision 1.568 2008/07/24 20:23:03 cheshire
180 <rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
181
182 Revision 1.567 2008/07/01 01:40:00 mcguire
183 <rdar://problem/5823010> 64-bit fixes
184
185 Revision 1.566 2008/06/26 17:24:11 mkrochma
186 <rdar://problem/5450912> BTMM: Stop listening on UDP 5351 for NAT Status Announcements
187
188 Revision 1.565 2008/06/21 19:06:58 mcguire
189 <rdar://problem/4206534> Use all configured DNS servers
190
191 Revision 1.564 2008/06/19 23:42:03 mcguire
192 <rdar://problem/4206534> Use all configured DNS servers
193
194 Revision 1.563 2008/06/19 17:46:14 mcguire
195 <rdar://problem/4206534> Use all configured DNS servers
196 Don't do extra work for log messages if we're not going to log
197
198 Revision 1.562 2008/06/19 17:35:19 mcguire
199 <rdar://problem/4206534> Use all configured DNS servers
200 cleanup log messages
201 check for null pointers
202
203 Revision 1.561 2008/06/19 01:20:49 mcguire
204 <rdar://problem/4206534> Use all configured DNS servers
205
206 Revision 1.560 2008/05/31 01:51:09 mcguire
207 fixed typo in log message
208
209 Revision 1.559 2008/04/15 22:37:58 mkrochma
210 Change LogMsg to LogOperation
211
212 Revision 1.558 2008/03/17 18:02:35 mkrochma
213 Add space to log message for consistency
214
215 Revision 1.557 2008/03/14 19:58:38 mcguire
216 <rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client
217 Make sure we add the record when sending LLQ refreshes
218
219 Revision 1.556 2008/03/07 23:55:05 cheshire
220 <rdar://problem/5787898> LLQ refresh randomization not working properly
221
222 Revision 1.555 2008/03/07 23:25:56 cheshire
223 Improved debugging messages
224
225 Revision 1.554 2008/03/07 18:56:03 cheshire
226 <rdar://problem/5777647> dnsbugtest query every three seconds when source IP address of response doesn't match
227
228 Revision 1.553 2008/03/06 02:48:34 mcguire
229 <rdar://problem/5321824> write status to the DS
230
231 Revision 1.552 2008/03/05 01:56:42 cheshire
232 <rdar://problem/5687667> BTMM: Don't fallback to unencrypted operations when SRV lookup fails
233
234 Revision 1.551 2008/03/01 01:43:04 cheshire
235 <rdar://problem/5631565> BTMM: Lots of "Error getting external address 3" when double-NATed prevents sleep
236 Added code to suppress logging of multiple identical error results
237
238 Revision 1.550 2008/03/01 01:34:47 cheshire
239 <rdar://problem/5736313> BTMM: Double-NAT'd machines register all but AutoTunnel v4 address records
240 Further refinements
241
242 Revision 1.549 2008/02/29 01:35:37 mcguire
243 <rdar://problem/5736313> BTMM: Double-NAT'd machines register all but AutoTunnel v4 address records
244
245 Revision 1.548 2008/02/20 23:54:18 cheshire
246 <rdar://problem/5661518> "Failed to obtain NAT port mapping" syslog messages
247 Improved log message so it tells us more about what's going on
248
249 Revision 1.547 2008/02/20 00:41:09 cheshire
250 Change "PrivateQueryGotZoneData ... invoked with error code" from LogMsg to LogOperation
251
252 Revision 1.546 2008/02/19 23:26:50 cheshire
253 <rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
254
255 Revision 1.545 2007/12/22 02:25:29 cheshire
256 <rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep
257
258 Revision 1.544 2007/12/18 00:40:11 cheshire
259 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
260 Reordered code to avoid double-TSIGs in some cases
261
262 Revision 1.543 2007/12/17 23:57:43 cheshire
263 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
264 Need to include TSIG signature when sending LLQ cancellations over TLS
265
266 Revision 1.542 2007/12/15 01:12:27 cheshire
267 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
268
269 Revision 1.541 2007/12/15 00:18:51 cheshire
270 Renamed question->origLease to question->ReqLease
271
272 Revision 1.540 2007/12/14 23:55:28 cheshire
273 Moved "struct tcpInfo_t" definition from uDNS.c to mDNSEmbeddedAPI.h
274
275 Revision 1.539 2007/12/14 20:44:24 cheshire
276 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
277 SleepRecordRegistrations/WakeRecordRegistrations should only operate on uDNS records
278
279 Revision 1.538 2007/12/14 01:13:40 cheshire
280 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
281 Additional fixes (existing code to deregister private records and services didn't work at all)
282
283 Revision 1.537 2007/12/11 00:18:25 cheshire
284 <rdar://problem/5569316> BTMM: My iMac has a "ghost" ID associated with it
285 There were cases where the code was incorrectly clearing the "uselease" flag, and never resetting it.
286
287 Revision 1.536 2007/12/10 23:07:00 cheshire
288 Removed some unnecessary log messages
289
290 Revision 1.535 2007/12/06 00:22:27 mcguire
291 <rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
292
293 Revision 1.534 2007/12/04 00:49:37 cheshire
294 <rdar://problem/5607082> BTMM: mDNSResponder taking 100 percent CPU after upgrading to 10.5.1
295
296 Revision 1.533 2007/12/01 01:21:27 jgraessley
297 <rdar://problem/5623140> mDNSResponder unicast DNS improvements
298
299 Revision 1.532 2007/11/30 20:16:44 cheshire
300 Fixed compile warning: declaration of 'end' shadows a previous local
301
302 Revision 1.531 2007/11/28 22:00:09 cheshire
303 In StartSRVNatMap, change "mDNSu8 *p" to "const mDNSu8 *p"
304
305 Revision 1.530 2007/11/16 22:19:40 cheshire
306 <rdar://problem/5547474> mDNSResponder leaks on network changes
307 The "connection failed" code path in MakeTCPConn was not disposing of the TCPSocket it had created
308
309 Revision 1.529 2007/11/15 22:52:29 cheshire
310 <rdar://problem/5589039> ERROR: mDNSPlatformWriteTCP - send Broken pipe
311
312 Revision 1.528 2007/11/02 21:32:30 cheshire
313 <rdar://problem/5575593> BTMM: Deferring deregistration of record log messages on sleep/wake
314
315 Revision 1.527 2007/11/01 16:08:51 cheshire
316 Tidy up alignment of "SetRecordRetry refresh" log messages
317
318 Revision 1.526 2007/10/31 19:26:55 cheshire
319 Don't need to log "Permanently abandoning service registration" message when we're intentionally deleting a service
320
321 Revision 1.525 2007/10/30 23:58:59 cheshire
322 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
323 After failure, double retry interval up to maximum of 30 minutes
324
325 Revision 1.524 2007/10/30 20:10:47 cheshire
326 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
327
328 Revision 1.523 2007/10/30 00:54:31 cheshire
329 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
330 Fixed timing logic to double retry interval properly
331
332 Revision 1.522 2007/10/30 00:04:43 cheshire
333 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
334 Made the code not give up and abandon the record when it gets an error in regState_UpdatePending state
335
336 Revision 1.521 2007/10/29 23:58:52 cheshire
337 <rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
338 Use standard "if (mDNSIPv4AddressIsOnes(....ExternalAddress))" mechanism to determine whether callback has been invoked yet
339
340 Revision 1.520 2007/10/29 21:48:36 cheshire
341 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
342 Added 10% random variation on LLQ renewal time, to reduce unintended timing correlation between multiple machines
343
344 Revision 1.519 2007/10/29 21:37:00 cheshire
345 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
346 Added 10% random variation on record refresh time, to reduce accidental timing correlation between multiple machines
347
348 Revision 1.518 2007/10/26 23:41:29 cheshire
349 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
350
351 Revision 1.517 2007/10/25 23:30:12 cheshire
352 Private DNS registered records now deregistered on sleep and re-registered on wake
353
354 Revision 1.516 2007/10/25 22:53:52 cheshire
355 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
356 Don't unlinkSRS and permanently give up at the first sign of trouble
357
358 Revision 1.515 2007/10/25 21:08:07 cheshire
359 Don't try to send record registrations/deletions before we have our server address
360
361 Revision 1.514 2007/10/25 20:48:47 cheshire
362 For naming consistency (with AuthRecord's UpdateServer) renamed 'ns' to 'SRSUpdateServer'
363
364 Revision 1.513 2007/10/25 20:06:13 cheshire
365 Don't try to do SOA queries using private DNS (TLS over TCP) queries
366
367 Revision 1.512 2007/10/25 18:25:15 cheshire
368 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
369 Don't need a NAT mapping for autotunnel services
370
371 Revision 1.511 2007/10/25 00:16:23 cheshire
372 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
373 Fixed retry timing logic; when DNS server returns an error code, we should retry later,
374 instead of just deleting our record ("UnlinkAuthRecord") and completely giving up
375
376 Revision 1.510 2007/10/24 22:40:06 cheshire
377 Renamed: RecordRegistrationCallback -> RecordRegistrationGotZoneData
378 Renamed: ServiceRegistrationZoneDataComplete -> ServiceRegistrationGotZoneData
379
380 Revision 1.509 2007/10/24 00:54:07 cheshire
381 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
382
383 Revision 1.508 2007/10/24 00:05:03 cheshire
384 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
385 When sending TLS/TCP LLQ setup request over VPN, need to set EventPort to 5353, not zero
386
387 Revision 1.507 2007/10/23 00:33:36 cheshire
388 Improved debugging messages
389
390 Revision 1.506 2007/10/22 19:54:13 cheshire
391 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
392 Only put EventPort in LLQ request when sending from an RFC 1918 source address, not when sending over VPN
393
394 Revision 1.505 2007/10/19 22:08:49 cheshire
395 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
396 Additional fixes and refinements
397
398 Revision 1.504 2007/10/18 23:06:43 cheshire
399 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
400 Additional fixes and refinements
401
402 Revision 1.503 2007/10/18 20:23:17 cheshire
403 Moved SuspendLLQs into mDNS.c, since it's only called from one place
404
405 Revision 1.502 2007/10/17 22:49:54 cheshire
406 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
407
408 Revision 1.501 2007/10/17 22:37:23 cheshire
409 <rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
410
411 Revision 1.500 2007/10/17 21:53:51 cheshire
412 Improved debugging messages; renamed startLLQHandshakeCallback to LLQGotZoneData
413
414 Revision 1.499 2007/10/16 21:16:50 cheshire
415 Get rid of unused uDNS_Sleep() routine
416
417 Revision 1.498 2007/10/16 20:59:41 cheshire
418 Export SuspendLLQs/SleepServiceRegistrations/SleepRecordRegistrations so they're callable from other files
419
420 Revision 1.497 2007/10/05 18:09:44 cheshire
421 <rdar://problem/5524841> Services advertised with wrong target host
422
423 Revision 1.496 2007/10/04 22:38:59 cheshire
424 Added LogOperation message showing new q->ThisQInterval after sending uDNS query packet
425
426 Revision 1.495 2007/10/03 00:16:19 cheshire
427 In PrivateQueryGotZoneData, need to grab lock before calling SetNextQueryTime
428
429 Revision 1.494 2007/10/02 21:11:08 cheshire
430 <rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing
431
432 Revision 1.493 2007/10/02 19:50:23 cheshire
433 Improved debugging message
434
435 Revision 1.492 2007/09/29 03:15:43 cheshire
436 <rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
437 Use AutoTunnelUnregistered macro instead of checking record state directly
438
439 Revision 1.491 2007/09/29 01:33:45 cheshire
440 <rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
441
442 Revision 1.490 2007/09/29 01:06:17 mcguire
443 <rdar://problem/5507862> 9A564: mDNSResponder crash in mDNS_Execute
444
445 Revision 1.489 2007/09/27 22:02:33 cheshire
446 <rdar://problem/5464941> BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord
447
448 Revision 1.488 2007/09/27 21:20:17 cheshire
449 Improved debugging syslog messages
450
451 Revision 1.487 2007/09/27 18:55:11 cheshire
452 <rdar://problem/5477165> BTMM: Multiple SRV records get registered after changing Computer Name
453
454 Revision 1.486 2007/09/27 17:42:49 cheshire
455 Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask"
456
457 Revision 1.485 2007/09/27 02:16:30 cheshire
458 <rdar://problem/5500111> BTMM: LLQ refreshes being sent in the clear to the wrong port
459
460 Revision 1.484 2007/09/27 00:25:39 cheshire
461 Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
462 <rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
463
464 Revision 1.483 2007/09/26 23:16:58 cheshire
465 <rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac
466
467 Revision 1.482 2007/09/26 22:06:02 cheshire
468 <rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
469
470 Revision 1.481 2007/09/26 00:49:46 cheshire
471 Improve packet logging to show sent and received packets,
472 transport protocol (UDP/TCP/TLS) and source/destination address:port
473
474 Revision 1.480 2007/09/21 21:08:52 cheshire
475 Get rid of unnecessary DumpPacket() calls -- it makes more sense
476 to do this in mDNSSendDNSMessage and mDNSCoreReceive instead
477
478 Revision 1.479 2007/09/21 20:01:17 cheshire
479 <rdar://problem/5496750> BTMM: Skip directly to member name in SOA queries to avoid sending names in the clear
480
481 Revision 1.478 2007/09/21 19:29:14 cheshire
482 Added dump of uDNS questions when in MDNS_LOG_VERBOSE_DEBUG mode
483
484 Revision 1.477 2007/09/20 02:29:37 cheshire
485 <rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
486
487 Revision 1.476 2007/09/20 01:19:49 cheshire
488 Improve debugging messages: report startLLQHandshake errors; show state in uDNS_StopLongLivedQuery message
489
490 Revision 1.475 2007/09/19 23:51:26 cheshire
491 <rdar://problem/5480517> BTMM: Need to log a message when NAT port mapping fails
492
493 Revision 1.474 2007/09/19 20:32:09 cheshire
494 Export GetAuthInfoForName so it's callable from other files
495
496 Revision 1.473 2007/09/18 21:42:29 cheshire
497 To reduce programming mistakes, renamed ExtPort to RequestedPort
498
499 Revision 1.472 2007/09/14 21:26:08 cheshire
500 <rdar://problem/5482627> BTMM: Need to manually avoid port conflicts when using UPnP gateways
501
502 Revision 1.471 2007/09/14 01:07:10 cheshire
503 If UPnP NAT gateway returns 0.0.0.0 as external address (e.g. because it hasn't
504 got a DHCP address yet) then retry periodically until it gives us a real address.
505
506 Revision 1.470 2007/09/13 00:36:26 cheshire
507 <rdar://problem/5477360> NAT Reboot detection logic incorrect
508
509 Revision 1.469 2007/09/13 00:28:50 cheshire
510 <rdar://problem/5477354> Host records not updated on NAT address change
511
512 Revision 1.468 2007/09/13 00:16:41 cheshire
513 <rdar://problem/5468706> Miscellaneous NAT Traversal improvements
514
515 Revision 1.467 2007/09/12 23:03:08 cheshire
516 <rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
517
518 Revision 1.466 2007/09/12 22:19:29 cheshire
519 <rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
520
521 Revision 1.465 2007/09/12 19:22:19 cheshire
522 Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
523 Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
524
525 Revision 1.464 2007/09/12 01:22:13 cheshire
526 Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
527
528 Revision 1.463 2007/09/11 20:23:28 vazquez
529 <rdar://problem/5466719> CrashTracer: 3 crashes in mDNSResponder at mDNSResponder: natTraversalHandlePortMapReply + 107
530 Make sure we clean up NATTraversals before free'ing HostnameInfo
531
532 Revision 1.462 2007/09/11 19:19:16 cheshire
533 Correct capitalization of "uPNP" to "UPnP"
534
535 Revision 1.461 2007/09/10 22:08:17 cheshire
536 Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
537
538 Revision 1.460 2007/09/07 21:47:43 vazquez
539 <rdar://problem/5460210> BTMM: SetupSocket 5351 failed; Can't allocate UDP multicast socket spew on wake from sleep with internet sharing on
540 Try to allocate using port 5350 if we get a failure, and only log message if that fails too.
541
542 Revision 1.459 2007/09/07 01:01:05 cheshire
543 <rdar://problem/5464844> BTMM: Services being registered and deregistered in a loop
544 In hndlServiceUpdateReply, need to clear SRVUpdateDeferred
545
546 Revision 1.458 2007/09/06 19:14:33 cheshire
547 Fixed minor error introduced in 1.379 (an "if" statement was deleted but the "else" following it was left there)
548
549 Revision 1.457 2007/09/05 21:48:01 cheshire
550 <rdar://problem/5385864> BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone.
551 Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance code needs
552 to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
553 otherwise those records will expire and vanish from the cache.
554
555 Revision 1.456 2007/09/05 21:00:17 cheshire
556 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
557 Additional refinement: ThisQInterval needs to be restored in tcpCallback, not in PrivateQueryGotZoneData
558
559 Revision 1.455 2007/09/05 20:53:06 cheshire
560 Tidied up alignment of code layout; code was clearing m->tcpAddrInfo.sock instead of m->tcpDeviceInfo.sock
561
562 Revision 1.454 2007/09/05 02:32:55 cheshire
563 Fixed posix build error (mixed declarations and code)
564
565 Revision 1.453 2007/09/05 02:26:57 cheshire
566 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
567 In PrivateQueryGotZoneData, restore q->ThisQInterval to non-zero value after GetZoneData completes
568
569 Revision 1.452 2007/08/31 22:58:22 cheshire
570 If we have an existing TCP connection we should re-use it instead of just bailing out
571 After receiving dnsbugtest response, need to set m->NextScheduledQuery to cause queries to be re-issued
572
573 Revision 1.451 2007/08/31 18:49:49 vazquez
574 <rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
575
576 Revision 1.450 2007/08/30 22:50:04 mcguire
577 <rdar://problem/5430628> BTMM: Tunneled services are registered when autotunnel can't be setup
578
579 Revision 1.449 2007/08/30 00:43:17 cheshire
580 Need to clear m->rec.r.resrec.RecordType before returning from uDNS_recvLLQResponse
581
582 Revision 1.448 2007/08/30 00:18:46 cheshire
583 <rdar://problem/5448804> Error messages: "SendServiceRegistration: Already have TCP connection..."
584
585 Revision 1.447 2007/08/29 01:18:33 cheshire
586 <rdar://problem/5400181> BTMM: Tunneled services do not need NAT port mappings
587 Only create NAT mappings for SRV records with AutoTarget set to Target_AutoHostAndNATMAP
588
589 Revision 1.446 2007/08/28 23:58:42 cheshire
590 Rename HostTarget -> AutoTarget
591
592 Revision 1.445 2007/08/28 23:53:21 cheshire
593 Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
594
595 Revision 1.444 2007/08/27 20:29:20 cheshire
596 Additional debugging messages
597
598 Revision 1.443 2007/08/24 23:18:28 cheshire
599 mDNS_SetSecretForDomain is called with lock held; needs to use
600 GetAuthInfoForName_internal() instead of external version GetAuthInfoForName()
601
602 Revision 1.442 2007/08/24 22:43:06 cheshire
603 Tidied up coded layout
604
605 Revision 1.441 2007/08/24 01:20:55 cheshire
606 <rdar://problem/5434381> BTMM: Memory corruption in KeychainChanged event handling
607
608 Revision 1.440 2007/08/24 00:15:20 cheshire
609 Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
610
611 Revision 1.439 2007/08/23 21:47:09 vazquez
612 <rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
613 make sure we clean up port mappings on base stations by sending a lease value of 0,
614 and only send NAT-PMP packets on private networks; also save some memory by
615 not using packet structs in NATTraversals.
616
617 Revision 1.438 2007/08/22 17:50:08 vazquez
618 <rdar://problem/5399276> Need to handle errors returned by NAT-PMP routers properly
619 Propagate router errors to clients, and stop logging spurious "message too short" logs.
620
621 Revision 1.437 2007/08/18 00:54:15 mcguire
622 <rdar://problem/5413147> BTMM: Should not register private addresses or zeros
623
624 Revision 1.436 2007/08/08 21:07:48 vazquez
625 <rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
626
627 Revision 1.435 2007/08/03 02:04:09 vazquez
628 <rdar://problem/5371843> BTMM: Private LLQs never fall back to polling
629 Fix case where NAT-PMP returns an external address but does not support
630 port mappings. Undo previous change and now, if the router returns an
631 error in the reply packet we respect it.
632
633 Revision 1.434 2007/08/02 21:03:05 vazquez
634 Change NAT logic to fix case where base station with port mapping turned off
635 returns an external address but does not make port mappings.
636
637 Revision 1.433 2007/08/02 03:30:11 vazquez
638 <rdar://problem/5371843> BTMM: Private LLQs never fall back to polling
639
640 Revision 1.432 2007/08/01 18:15:19 cheshire
641 Fixed crash in tcpCallback; fixed some problems with LLQ setup behind NAT
642
643 Revision 1.431 2007/08/01 16:11:06 cheshire
644 Fixed "mixed declarations and code" compiler error in Posix build
645
646 Revision 1.430 2007/08/01 16:09:13 cheshire
647 Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
648
649 Revision 1.429 2007/08/01 03:09:22 cheshire
650 <rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
651
652 Revision 1.428 2007/08/01 01:43:36 cheshire
653 Need to do mDNS_DropLockBeforeCallback/ReclaimLock around invokation of NAT client callback
654
655 Revision 1.427 2007/08/01 01:31:13 cheshire
656 Need to initialize traversal->tcpInfo fields or code may crash
657
658 Revision 1.426 2007/08/01 01:15:57 cheshire
659 <rdar://problem/5375791> Need to invoke NAT client callback when not on RFC1918 private network
660
661 Revision 1.425 2007/08/01 00:04:14 cheshire
662 <rdar://problem/5261696> Crash in tcpKQSocketCallback
663 Half-open TCP connections were not being cancelled properly
664
665 Revision 1.424 2007/07/31 02:28:35 vazquez
666 <rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
667
668 Revision 1.423 2007/07/30 23:31:26 cheshire
669 Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
670
671 Revision 1.422 2007/07/28 01:25:57 cheshire
672 <rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
673
674 Revision 1.421 2007/07/28 00:04:14 cheshire
675 Various fixes for comments and debugging messages
676
677 Revision 1.420 2007/07/27 23:59:18 cheshire
678 Added compile-time structure size checks
679
680 Revision 1.419 2007/07/27 20:52:29 cheshire
681 Made uDNS_recvLLQResponse() return tri-state result: LLQ_Not, LLQ_First, or LLQ_Events
682
683 Revision 1.418 2007/07/27 20:32:05 vazquez
684 Flag a UPnP NAT traversal before starting a UPnP port mapping, and make sure all
685 calls to mDNS_StopNATOperation() go through the UPnP code
686
687 Revision 1.417 2007/07/27 20:19:42 cheshire
688 Use MDNS_LOG_VERBOSE_DEBUG for dumping out packets instead of MDNS_LOG_DEBUG
689
690 Revision 1.416 2007/07/27 19:59:28 cheshire
691 MUST NOT touch m->CurrentQuestion (or q) after calling AnswerCurrentQuestionWithResourceRecord()
692
693 Revision 1.415 2007/07/27 19:51:01 cheshire
694 Use symbol QC_addnocache instead of literal constant "2"
695
696 Revision 1.414 2007/07/27 19:30:39 cheshire
697 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
698 to properly reflect tri-state nature of the possible responses
699
700 Revision 1.413 2007/07/27 18:44:01 cheshire
701 Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
702
703 Revision 1.412 2007/07/27 18:38:56 cheshire
704 Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
705
706 Revision 1.411 2007/07/27 00:57:13 cheshire
707 Create hostname address records using standard kHostNameTTL (2 minutes) instead of 1 second
708
709 Revision 1.410 2007/07/25 21:41:00 vazquez
710 Make sure we clean up opened sockets when there are network transitions and when changing
711 port mappings
712
713 Revision 1.409 2007/07/25 03:05:02 vazquez
714 Fixes for:
715 <rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
716 <rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
717 and a myriad of other security problems
718
719 Revision 1.408 2007/07/24 21:47:51 cheshire
720 Don't do mDNS_StopNATOperation() for operations we never started
721
722 Revision 1.407 2007/07/24 17:23:33 cheshire
723 <rdar://problem/5357133> Add list validation checks for debugging
724
725 Revision 1.406 2007/07/24 04:14:30 cheshire
726 <rdar://problem/5356281> LLQs not working in with NAT Traversal
727
728 Revision 1.405 2007/07/24 01:29:03 cheshire
729 <rdar://problem/5356026> DNSServiceNATPortMappingCreate() returns stale external address information
730
731 Revision 1.404 2007/07/20 23:10:51 cheshire
732 Fix code layout
733
734 Revision 1.403 2007/07/20 20:12:37 cheshire
735 Rename "mDNS_DomainTypeBrowseLegacy" as "mDNS_DomainTypeBrowseAutomatic"
736
737 Revision 1.402 2007/07/20 00:54:20 cheshire
738 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
739
740 Revision 1.401 2007/07/18 03:23:33 cheshire
741 In GetServiceTarget, need to call SetupLocalAutoTunnelInterface_internal to bring up tunnel on demand, if necessary
742
743 Revision 1.400 2007/07/18 02:30:25 cheshire
744 Defer AutoTunnel server record advertising until we have at least one service to advertise
745 Do AutoTunnel target host selection in GetServiceTarget (instead of uDNS_RegisterService)
746
747 Revision 1.399 2007/07/18 01:02:28 cheshire
748 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
749 Declare records as kDNSRecordTypeKnownUnique so we don't get name conflicts with ourselves
750
751 Revision 1.398 2007/07/16 23:54:48 cheshire
752 <rdar://problem/5338850> Crash when removing or changing DNS keys
753
754 Revision 1.397 2007/07/16 20:13:31 vazquez
755 <rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
756
757 Revision 1.396 2007/07/14 00:33:04 cheshire
758 Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working
759
760 Revision 1.395 2007/07/12 23:56:23 cheshire
761 Change "GetZoneData GOT SRV" message to debugf to reduce verbosity in syslog
762
763 Revision 1.394 2007/07/12 23:36:08 cheshire
764 Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog
765
766 Revision 1.393 2007/07/12 22:15:10 cheshire
767 Modified mDNS_SetSecretForDomain() so it can be called to update an existing entry
768
769 Revision 1.392 2007/07/12 02:51:27 cheshire
770 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
771
772 Revision 1.391 2007/07/11 23:16:31 cheshire
773 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
774 Need to prepend _autotunnel._udp to start of AutoTunnel SRV record name
775
776 Revision 1.390 2007/07/11 22:47:55 cheshire
777 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
778 In mDNS_SetSecretForDomain(), don't register records until after we've validated the parameters
779
780 Revision 1.389 2007/07/11 21:33:10 cheshire
781 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
782 Set up and register AutoTunnelTarget and AutoTunnelService DNS records
783
784 Revision 1.388 2007/07/11 19:27:10 cheshire
785 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
786 For temporary testing fake up an IPv4LL address instead of IPv6 ULA
787
788 Revision 1.387 2007/07/11 03:04:08 cheshire
789 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
790 Add AutoTunnel parameter to mDNS_SetSecretForDomain; Set up AutoTunnel information for domains that require it
791
792 Revision 1.386 2007/07/10 01:57:28 cheshire
793 <rdar://problem/5196524> uDNS: mDNSresponder is leaking TCP connections to DNS server
794 Turned vast chunks of replicated code into a subroutine MakeTCPConn(...);
795 Made routines hold on to the reference it returns instead of leaking it
796
797 Revision 1.385 2007/07/09 23:50:18 cheshire
798 unlinkSRS needs to call mDNS_StopNATOperation_internal(), not mDNS_StopNATOperation()
799
800 Revision 1.384 2007/07/06 21:20:21 cheshire
801 Fix scheduling error (was causing "Task Scheduling Error: Continuously busy for more than a second")
802
803 Revision 1.383 2007/07/06 18:59:59 cheshire
804 Avoid spinning in an infinite loop when uDNS_SendNATMsg() returns an error
805
806 Revision 1.382 2007/07/04 00:49:43 vazquez
807 Clean up extraneous comments
808
809 Revision 1.381 2007/07/03 00:41:14 vazquez
810 More changes for <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
811 Safely deal with packet replies and client callbacks
812
813 Revision 1.380 2007/07/02 22:08:47 cheshire
814 Fixed crash in "Received public IP address" message
815
816 Revision 1.379 2007/06/29 00:08:49 vazquez
817 <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
818
819 Revision 1.378 2007/06/27 20:25:10 cheshire
820 Expanded dnsbugtest comment, explaining requirement that we also need these
821 test queries to black-hole before they get to the root name servers.
822
823 Revision 1.377 2007/06/22 21:27:21 cheshire
824 Modified "could not convert shared secret from base64" log message
825
826 Revision 1.376 2007/06/20 01:10:12 cheshire
827 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
828
829 Revision 1.375 2007/06/15 21:54:51 cheshire
830 <rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
831
832 Revision 1.374 2007/06/12 02:15:26 cheshire
833 Fix incorrect "DNS Server passed" LogOperation message
834
835 Revision 1.373 2007/05/31 00:25:43 cheshire
836 <rdar://problem/5238688> Only send dnsbugtest query for questions where it's warranted
837
838 Revision 1.372 2007/05/25 17:03:45 cheshire
839 lenptr needs to be declared unsigned, otherwise sign extension can mess up the shifting and ORing operations
840
841 Revision 1.371 2007/05/24 00:11:44 cheshire
842 Remove unnecessary lenbuf field from tcpInfo_t
843
844 Revision 1.370 2007/05/23 00:30:59 cheshire
845 Don't change question->TargetQID when repeating query over TCP
846
847 Revision 1.369 2007/05/21 18:04:40 cheshire
848 Updated comments -- port_mapping_create_reply renamed to port_mapping_reply
849
850 Revision 1.368 2007/05/17 19:12:16 cheshire
851 Updated comment about finding matching pair of sockets
852
853 Revision 1.367 2007/05/15 23:38:00 cheshire
854 Need to grab lock before calling SendRecordRegistration();
855
856 Revision 1.366 2007/05/15 00:43:05 cheshire
857 <rdar://problem/4983538> uDNS serviceRegistrationCallback locking failures
858
859 Revision 1.365 2007/05/10 21:19:18 cheshire
860 Rate-limit DNS test queries to at most one per three seconds
861 (useful when we have a dozen active WAB queries, and then we join a new network)
862
863 Revision 1.364 2007/05/07 20:43:45 cheshire
864 <rdar://problem/4241419> Reduce the number of queries and announcements
865
866 Revision 1.363 2007/05/04 22:12:48 cheshire
867 Work towards solving <rdar://problem/5176892> "uDNS_CheckQuery: LastQTime" log messages
868 When code gets in this invalid state, double ThisQInterval each time, to avoid excessive logging
869
870 Revision 1.362 2007/05/04 21:23:05 cheshire
871 <rdar://problem/5167263> Private DNS always returns no answers in the initial LLQ setup response
872 Preparatory work to enable us to do a four-way LLQ handshake over TCP, if we decide that's what we want
873
874 Revision 1.361 2007/05/03 23:50:48 cheshire
875 <rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
876 In the case of negative answers for the address record, set the server address to zerov4Addr
877
878 Revision 1.360 2007/05/03 22:40:38 cheshire
879 <rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
880
881 Revision 1.359 2007/05/02 22:21:33 cheshire
882 <rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
883
884 Revision 1.358 2007/05/01 21:46:31 cheshire
885 Move GetLLQOptData/GetPktLease from uDNS.c into DNSCommon.c so that dnsextd can use them
886
887 Revision 1.357 2007/05/01 01:33:49 cheshire
888 Removed "#define LLQ_Info DNSQuestion" and manually reconciled code that was still referring to "LLQ_Info"
889
890 Revision 1.356 2007/04/30 21:51:06 cheshire
891 Updated comments
892
893 Revision 1.355 2007/04/30 21:33:38 cheshire
894 Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
895 is iterating through the m->ServiceRegistrations list
896
897 Revision 1.354 2007/04/30 01:30:04 cheshire
898 GetZoneData_QuestionCallback needs to call client callback function on error, so client knows operation is finished
899 RecordRegistrationCallback and serviceRegistrationCallback need to clear nta reference when they're invoked
900
901 Revision 1.353 2007/04/28 01:28:25 cheshire
902 Fixed memory leak on error path in FoundDomain
903
904 Revision 1.352 2007/04/27 19:49:53 cheshire
905 In uDNS_ReceiveTestQuestionResponse, also check that srcport matches
906
907 Revision 1.351 2007/04/27 19:28:02 cheshire
908 Any code that calls StartGetZoneData needs to keep a handle to the structure, so
909 it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
910 -- it would start a query and then quickly cancel it, and then when
911 StartGetZoneData completed, it had a dangling pointer and crashed.)
912
913 Revision 1.350 2007/04/26 22:47:14 cheshire
914 Defensive coding: tcpCallback only needs to check "if (closed)", not "if (!n && closed)"
915
916 Revision 1.349 2007/04/26 16:04:06 cheshire
917 In mDNS_AddDNSServer, check whether port matches
918 In uDNS_CheckQuery, handle case where startLLQHandshake changes q->llq->state to LLQ_Poll
919
920 Revision 1.348 2007/04/26 04:01:59 cheshire
921 Copy-and-paste error: Test should be "if (result == DNSServer_Passed)" not "if (result == DNSServer_Failed)"
922
923 Revision 1.347 2007/04/26 00:35:15 cheshire
924 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
925 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
926 inside the firewall may give answers where a public one gives none, and vice versa.)
927
928 Revision 1.346 2007/04/25 19:16:59 cheshire
929 Don't set SuppressStdPort53Queries unless we do actually send a DNS packet
930
931 Revision 1.345 2007/04/25 18:05:11 cheshire
932 Don't try to restart inactive (duplicate) queries
933
934 Revision 1.344 2007/04/25 17:54:07 cheshire
935 Don't cancel Private LLQs using a clear-text UDP packet
936
937 Revision 1.343 2007/04/25 16:40:08 cheshire
938 Add comment explaining uDNS_recvLLQResponse logic
939
940 Revision 1.342 2007/04/25 02:14:38 cheshire
941 <rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
942 Additional fixes to make LLQs work properly
943
944 Revision 1.341 2007/04/24 02:07:42 cheshire
945 <rdar://problem/4246187> Identical client queries should reference a single shared core query
946 Deleted some more redundant code
947
948 Revision 1.340 2007/04/23 22:01:23 cheshire
949 <rdar://problem/5094009> IPv6 filtering in AirPort base station breaks Wide-Area Bonjour
950 As of March 2007, AirPort base stations now block incoming IPv6 connections by default, so there's no point
951 advertising IPv6 addresses in DNS any more -- we have to assume that most of the time a host's IPv6 address
952 probably won't work for incoming connections (but its IPv4 address probably will, using NAT-PMP).
953
954 Revision 1.339 2007/04/22 06:02:03 cheshire
955 <rdar://problem/4615977> Query should immediately return failure when no server
956
957 Revision 1.338 2007/04/21 19:44:11 cheshire
958 Improve uDNS_HandleNATPortMapReply log message
959
960 Revision 1.337 2007/04/21 02:03:00 cheshire
961 Also need to set AddressRec->resrec.RecordType in the NAT case too
962
963 Revision 1.336 2007/04/20 21:16:12 cheshire
964 Fixed bogus double-registration of host name -- was causing these warning messages in syslog:
965 Error! Tried to register AuthRecord 0181FB0C host.example.com. (Addr) that's already in the list
966
967 Revision 1.335 2007/04/19 23:57:20 cheshire
968 Temporary workaround for some AirPort base stations that don't seem to like us requesting public port zero
969
970 Revision 1.334 2007/04/19 23:21:51 cheshire
971 Fixed a couple of places where the StartGetZoneData check was backwards
972
973 Revision 1.333 2007/04/19 22:50:53 cheshire
974 <rdar://problem/4246187> Identical client queries should reference a single shared core query
975
976 Revision 1.332 2007/04/19 20:34:32 cheshire
977 Add debugging log message in uDNS_CheckQuery()
978
979 Revision 1.331 2007/04/19 20:06:41 cheshire
980 Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
981
982 Revision 1.330 2007/04/19 19:51:54 cheshire
983 Get rid of unnecessary initializeQuery() routine
984
985 Revision 1.329 2007/04/19 18:03:52 cheshire
986 Improved "mDNS_AddSearchDomain" log message
987
988 Revision 1.328 2007/04/18 20:57:20 cheshire
989 Commented out "GetAuthInfoForName none found" debugging message
990
991 Revision 1.327 2007/04/17 19:21:29 cheshire
992 <rdar://problem/5140339> Domain discovery not working over VPN
993
994 Revision 1.326 2007/04/16 20:49:39 cheshire
995 Fix compile errors for mDNSPosix build
996
997 Revision 1.325 2007/04/05 22:55:35 cheshire
998 <rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
999
1000 Revision 1.324 2007/04/05 20:43:30 cheshire
1001 Collapse sprawling code onto one line -- this is part of a bigger block of identical
1002 code that has been copied-and-pasted into six different places in the same file.
1003 This really needs to be turned into a subroutine.
1004
1005 Revision 1.323 2007/04/04 21:48:52 cheshire
1006 <rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
1007
1008 Revision 1.322 2007/04/03 19:53:06 cheshire
1009 Use mDNSSameIPPort (and similar) instead of accessing internal fields directly
1010
1011 Revision 1.321 2007/04/02 23:44:09 cheshire
1012 Minor code tidying
1013
1014 Revision 1.320 2007/03/31 01:26:13 cheshire
1015 Take out GetAuthInfoForName syslog message
1016
1017 Revision 1.319 2007/03/31 01:10:53 cheshire
1018 Add debugging
1019
1020 Revision 1.318 2007/03/31 00:17:11 cheshire
1021 Remove some LogMsgs
1022
1023 Revision 1.317 2007/03/29 00:09:31 cheshire
1024 Improve "uDNS_InitLongLivedQuery" log message
1025
1026 Revision 1.316 2007/03/28 21:16:27 cheshire
1027 Remove DumpPacket() call now that OPT pseudo-RR rrclass bug is fixed
1028
1029 Revision 1.315 2007/03/28 21:02:18 cheshire
1030 <rdar://problem/3810563> Wide-Area Bonjour should work on multi-subnet private network
1031
1032 Revision 1.314 2007/03/28 15:56:37 cheshire
1033 <rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
1034
1035 Revision 1.313 2007/03/28 01:27:32 cheshire
1036 <rdar://problem/4996439> Unicast DNS polling server every three seconds
1037 StartLLQPolling was using INIT_UCAST_POLL_INTERVAL instead of LLQ_POLL_INTERVAL for the retry interval
1038
1039 Revision 1.312 2007/03/27 23:48:21 cheshire
1040 Use mDNS_StopGetDomains(), not mDNS_StopQuery()
1041
1042 Revision 1.311 2007/03/27 22:47:51 cheshire
1043 Remove unnecessary "*(long*)0 = 0;" to generate crash and stack trace
1044
1045 Revision 1.310 2007/03/24 01:24:13 cheshire
1046 Add validator for uDNS data structures; fixed crash in RegisterSearchDomains()
1047
1048 Revision 1.309 2007/03/24 00:47:53 cheshire
1049 <rdar://problem/4983538> serviceRegistrationCallback: Locking Failure! mDNS_busy (1) != mDNS_reentrancy (2)
1050 Locking in this file is all messed up. For now we'll just work around the issue.
1051
1052 Revision 1.308 2007/03/24 00:41:33 cheshire
1053 Minor code cleanup (move variable declarations to minimum enclosing scope)
1054
1055 Revision 1.307 2007/03/21 23:06:00 cheshire
1056 Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
1057
1058 Revision 1.306 2007/03/21 00:30:03 cheshire
1059 <rdar://problem/4789455> Multiple errors in DNameList-related code
1060
1061 Revision 1.305 2007/03/20 17:07:15 cheshire
1062 Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
1063
1064 Revision 1.304 2007/03/17 00:02:11 cheshire
1065 <rdar://problem/5067013> NAT-PMP: Lease TTL is being ignored
1066
1067 Revision 1.303 2007/03/10 03:26:44 cheshire
1068 <rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
1069
1070 Revision 1.302 2007/03/10 02:29:58 cheshire
1071 Added comments about NAT-PMP response functions
1072
1073 Revision 1.301 2007/03/10 02:02:58 cheshire
1074 <rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
1075 Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
1076
1077 Revision 1.300 2007/03/08 18:56:00 cheshire
1078 Fixed typo: "&v4.ip.v4.b[0]" is always non-zero (ampersand should not be there)
1079
1080 Revision 1.299 2007/02/28 01:45:47 cheshire
1081 <rdar://problem/4683261> NAT-PMP: Port mapping refreshes should contain actual public port
1082 <rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
1083
1084 Revision 1.298 2007/02/14 03:16:39 cheshire
1085 <rdar://problem/4789477> Eliminate unnecessary malloc/free in mDNSCore code
1086
1087 Revision 1.297 2007/02/08 21:12:28 cheshire
1088 <rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
1089
1090 Revision 1.296 2007/01/29 16:03:22 cheshire
1091 Fix unused parameter warning
1092
1093 Revision 1.295 2007/01/27 03:34:27 cheshire
1094 Made GetZoneData use standard queries (and cached results);
1095 eliminated GetZoneData_Callback() packet response handler
1096
1097 Revision 1.294 2007/01/25 00:40:16 cheshire
1098 Unified CNAME-following functionality into cache management code (which means CNAME-following
1099 should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine.
1100
1101 Revision 1.293 2007/01/23 02:56:11 cheshire
1102 Store negative results in the cache, instead of generating them out of pktResponseHndlr()
1103
1104 Revision 1.292 2007/01/20 01:32:40 cheshire
1105 Update comments and debugging messages
1106
1107 Revision 1.291 2007/01/20 00:07:02 cheshire
1108 When we have credentials in the keychain for a domain, we attempt private queries, but
1109 if the authoritative server is not set up for private queries (i.e. no _dns-query-tls
1110 or _dns-llq-tls record) then we need to fall back to conventional non-private queries.
1111
1112 Revision 1.290 2007/01/19 23:41:45 cheshire
1113 Need to clear m->rec.r.resrec.RecordType after calling GetLLQOptData()
1114
1115 Revision 1.289 2007/01/19 23:32:07 cheshire
1116 Eliminate pointless timenow variable
1117
1118 Revision 1.288 2007/01/19 23:26:08 cheshire
1119 Right now tcpCallback does not run holding the lock, so no need to drop the lock before invoking callbacks
1120
1121 Revision 1.287 2007/01/19 22:55:41 cheshire
1122 Eliminate redundant identical parameters to GetZoneData_StartQuery()
1123
1124 Revision 1.286 2007/01/19 21:17:33 cheshire
1125 StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
1126
1127 Revision 1.285 2007/01/19 18:39:11 cheshire
1128 Fix a bunch of parameters that should have been declared "const"
1129
1130 Revision 1.284 2007/01/19 18:28:28 cheshire
1131 Improved debugging messages
1132
1133 Revision 1.283 2007/01/19 18:09:33 cheshire
1134 Fixed getLLQAtIndex (now called GetLLQOptData):
1135 1. It incorrectly assumed all EDNS0 OPT records are the same size (it ignored optlen)
1136 2. It used inefficient memory copying instead of just returning a pointer
1137
1138 Revision 1.282 2007/01/17 22:06:01 cheshire
1139 Replace duplicated literal constant "{ { 0 } }" with symbol "zeroIPPort"
1140
1141 Revision 1.281 2007/01/17 21:58:13 cheshire
1142 For clarity, rename ntaContext field "isPrivate" to "ntaPrivate"
1143
1144 Revision 1.280 2007/01/17 21:46:02 cheshire
1145 Remove redundant duplicated "isPrivate" field from LLQ_Info
1146
1147 Revision 1.279 2007/01/17 21:35:31 cheshire
1148 For clarity, rename zoneData_t field "isPrivate" to "zonePrivate"
1149
1150 Revision 1.278 2007/01/16 03:04:16 cheshire
1151 <rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
1152 Don't cache result of ntaContextSRV(context) in a local variable --
1153 the macro evaluates to a different result after we clear "context->isPrivate"
1154
1155 Revision 1.277 2007/01/10 22:51:58 cheshire
1156 <rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
1157
1158 Revision 1.276 2007/01/10 02:09:30 cheshire
1159 Better LogOperation record of keys read from System Keychain
1160
1161 Revision 1.275 2007/01/09 22:37:18 cheshire
1162 Provide ten-second grace period for deleted keys, to give mDNSResponder
1163 time to delete host name before it gives up access to the required key.
1164
1165 Revision 1.274 2007/01/09 01:16:32 cheshire
1166 Improve "ERROR m->CurrentQuestion already set" debugging messages
1167
1168 Revision 1.273 2007/01/08 23:58:00 cheshire
1169 Don't request regDomain and browseDomains in uDNS_SetupDNSConfig() -- it just ignores those results
1170
1171 Revision 1.272 2007/01/05 08:30:42 cheshire
1172 Trim excessive "$Log" checkin history from before 2006
1173 (checkin history still available via "cvs log ..." of course)
1174
1175 Revision 1.271 2007/01/05 06:34:03 cheshire
1176 Improve "ERROR m->CurrentQuestion already set" debugging messages
1177
1178 Revision 1.270 2007/01/05 05:44:33 cheshire
1179 Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c,
1180 so that mDNSPosix embedded clients will compile again
1181
1182 Revision 1.269 2007/01/04 23:11:13 cheshire
1183 <rdar://problem/4720673> uDNS: Need to start caching unicast records
1184 When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
1185
1186 Revision 1.268 2007/01/04 22:06:38 cheshire
1187 Fixed crash in LLQNatMapComplete()
1188
1189 Revision 1.267 2007/01/04 21:45:20 cheshire
1190 Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
1191 to do additional lock sanity checking around callback invocations
1192
1193 Revision 1.266 2007/01/04 21:01:20 cheshire
1194 <rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
1195 Only return NXDOMAIN results to clients that request them using kDNSServiceFlagsReturnIntermediates
1196
1197 Revision 1.265 2007/01/04 20:47:17 cheshire
1198 Fixed crash in CheckForUnreferencedLLQMapping()
1199
1200 Revision 1.264 2007/01/04 20:39:27 cheshire
1201 Fix locking mismatch
1202
1203 Revision 1.263 2007/01/04 02:39:53 cheshire
1204 <rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
1205
1206 Revision 1.262 2007/01/04 00:29:25 cheshire
1207 Covert LogMsg() in GetAuthInfoForName to LogOperation()
1208
1209 Revision 1.261 2006/12/22 20:59:49 cheshire
1210 <rdar://problem/4742742> Read *all* DNS keys from keychain,
1211 not just key for the system-wide default registration domain
1212
1213 Revision 1.260 2006/12/21 00:06:07 cheshire
1214 Don't need to do mDNSPlatformMemZero() -- mDNS_SetupResourceRecord() does it for us
1215
1216 Revision 1.259 2006/12/20 04:07:36 cheshire
1217 Remove uDNS_info substructure from AuthRecord_struct
1218
1219 Revision 1.258 2006/12/19 22:49:24 cheshire
1220 Remove uDNS_info substructure from ServiceRecordSet_struct
1221
1222 Revision 1.257 2006/12/19 02:38:20 cheshire
1223 Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
1224
1225 Revision 1.256 2006/12/19 02:18:48 cheshire
1226 Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
1227
1228 Revision 1.255 2006/12/16 01:58:31 cheshire
1229 <rdar://problem/4720673> uDNS: Need to start caching unicast records
1230
1231 Revision 1.254 2006/12/15 19:23:39 cheshire
1232 Use new DomainNameLengthLimit() function, to be more defensive against malformed
1233 data received from the network.
1234
1235 Revision 1.253 2006/12/01 07:43:34 herscher
1236 Fix byte ordering problem for one-shot TCP queries.
1237 Iterate more intelligently over duplicates in uDNS_ReceiveMsg to avoid spin loops.
1238
1239 Revision 1.252 2006/11/30 23:07:57 herscher
1240 <rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
1241
1242 Revision 1.251 2006/11/28 21:42:11 mkrochma
1243 Work around a crashing bug that was introduced by uDNS and mDNS code unification
1244
1245 Revision 1.250 2006/11/18 05:01:30 cheshire
1246 Preliminary support for unifying the uDNS and mDNS code,
1247 including caching of uDNS answers
1248
1249 Revision 1.249 2006/11/10 07:44:04 herscher
1250 <rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
1251
1252 Revision 1.248 2006/11/08 04:26:53 cheshire
1253 Fix typo in debugging message
1254
1255 Revision 1.247 2006/10/20 05:35:04 herscher
1256 <rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
1257
1258 Revision 1.246 2006/10/11 19:29:41 herscher
1259 <rdar://problem/4744553> uDNS: mDNSResponder-111 using 100% CPU
1260
1261 Revision 1.245 2006/10/04 22:21:15 herscher
1262 Tidy up references to mDNS_struct introduced when the embedded uDNS_info struct was removed.
1263
1264 Revision 1.244 2006/10/04 21:51:27 herscher
1265 Replace calls to mDNSPlatformTimeNow(m) with m->timenow
1266
1267 Revision 1.243 2006/10/04 21:38:59 herscher
1268 Remove uDNS_info substructure from DNSQuestion_struct
1269
1270 Revision 1.242 2006/09/27 00:51:46 herscher
1271 Fix compile error when _LEGACY_NAT_TRAVERSAL_ is not defined
1272
1273 Revision 1.241 2006/09/26 01:54:47 herscher
1274 <rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
1275
1276 Revision 1.240 2006/09/15 21:20:15 cheshire
1277 Remove uDNS_info substructure from mDNS_struct
1278
1279 Revision 1.239 2006/08/16 02:52:56 mkrochma
1280 <rdar://problem/4104154> Actually fix it this time
1281
1282 Revision 1.238 2006/08/16 00:31:50 mkrochma
1283 <rdar://problem/4386944> Get rid of NotAnInteger references
1284
1285 Revision 1.237 2006/08/15 23:38:17 mkrochma
1286 <rdar://problem/4104154> Requested Public Port field should be set to zero on mapping deletion
1287
1288 Revision 1.236 2006/08/14 23:24:23 cheshire
1289 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
1290
1291 Revision 1.235 2006/07/30 05:45:36 cheshire
1292 <rdar://problem/4304215> Eliminate MIN_UCAST_PERIODIC_EXEC
1293
1294 Revision 1.234 2006/07/22 02:58:36 cheshire
1295 Code was clearing namehash twice instead of namehash and rdatahash
1296
1297 Revision 1.233 2006/07/20 19:46:51 mkrochma
1298 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1299 Fix Private DNS
1300
1301 Revision 1.232 2006/07/15 02:01:29 cheshire
1302 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1303 Fix broken "empty string" browsing
1304
1305 Revision 1.231 2006/07/05 23:28:22 cheshire
1306 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1307
1308 Revision 1.230 2006/06/29 03:02:44 cheshire
1309 <rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
1310
1311 Revision 1.229 2006/03/02 22:03:41 cheshire
1312 <rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
1313 Refinement: m->rec.r.resrec.RecordType needs to be cleared *every* time around for loop, not just once at the end
1314
1315 Revision 1.228 2006/02/26 00:54:42 cheshire
1316 Fixes to avoid code generation warning/error on FreeBSD 7
1317
1318 Revision 1.227 2006/01/09 20:47:05 cheshire
1319 <rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
1320
1321 */
1322
1323 #include "uDNS.h"
1324
1325 #if(defined(_MSC_VER))
1326 // Disable "assignment within conditional expression".
1327 // Other compilers understand the convention that if you place the assignment expression within an extra pair
1328 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
1329 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
1330 // to the compiler that the assignment is intentional, we have to just turn this warning off completely.
1331 #pragma warning(disable:4706)
1332 #endif
1333
1334 // For domain enumeration and automatic browsing
1335 // This is the user's DNS search list.
1336 // In each of these domains we search for our special pointer records (lb._dns-sd._udp.<domain>, etc.)
1337 // to discover recommended domains for domain enumeration (browse, default browse, registration,
1338 // default registration) and possibly one or more recommended automatic browsing domains.
1339 mDNSexport SearchListElem *SearchList = mDNSNULL;
1340
1341 // Temporary workaround to make ServiceRecordSet list management safe.
1342 // Ideally a ServiceRecordSet shouldn't be a special entity that's given special treatment by the uDNS code
1343 // -- it should just be a grouping of records that are treated the same as any other registered records.
1344 // In that case it may no longer be necessary to keep an explicit list of ServiceRecordSets, which in turn
1345 // would avoid the perils of modifying that list cleanly while some other piece of code is iterating through it.
1346 ServiceRecordSet *CurrentServiceRecordSet = mDNSNULL;
1347
1348 // The value can be set to true by the Platform code e.g., MacOSX uses the plist mechanism
1349 mDNSBool StrictUnicastOrdering = mDNSfalse;
1350
1351 // ***************************************************************************
1352 #if COMPILER_LIKES_PRAGMA_MARK
1353 #pragma mark - General Utility Functions
1354 #endif
1355
1356 // Unlink an AuthRecord from the m->ResourceRecords list.
1357 // This seems risky. Probably some (or maybe all) of the places calling UnlinkAuthRecord to directly
1358 // remove a record from the list should actually be using mDNS_Deregister/mDNS_Deregister_internal.
1359 mDNSlocal mStatus UnlinkAuthRecord(mDNS *const m, AuthRecord *const rr)
1360 {
1361 AuthRecord **list = &m->ResourceRecords;
1362 if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next;
1363 if (m->CurrentRecord == rr) m->CurrentRecord = rr->next;
1364 while (*list && *list != rr) list = &(*list)->next;
1365 if (!*list)
1366 {
1367 list = &m->DuplicateRecords;
1368 while (*list && *list != rr) list = &(*list)->next;
1369 }
1370 if (*list) { *list = rr->next; rr->next = mDNSNULL; return(mStatus_NoError); }
1371 LogMsg("ERROR: UnlinkAuthRecord - no such active record %##s", rr->resrec.name->c);
1372 return(mStatus_NoSuchRecord);
1373 }
1374
1375 // unlinkSRS is an internal routine (i.e. must be called with the lock already held)
1376 mDNSlocal void unlinkSRS(mDNS *const m, ServiceRecordSet *srs)
1377 {
1378 ServiceRecordSet **p;
1379
1380 if (srs->NATinfo.clientContext)
1381 {
1382 mDNS_StopNATOperation_internal(m, &srs->NATinfo);
1383 srs->NATinfo.clientContext = mDNSNULL;
1384 }
1385
1386 for (p = &m->ServiceRegistrations; *p; p = &(*p)->uDNS_next)
1387 if (*p == srs)
1388 {
1389 ExtraResourceRecord *e;
1390 *p = srs->uDNS_next;
1391 if (CurrentServiceRecordSet == srs)
1392 CurrentServiceRecordSet = srs->uDNS_next;
1393 srs->uDNS_next = mDNSNULL;
1394 for (e=srs->Extras; e; e=e->next)
1395 if (UnlinkAuthRecord(m, &e->r))
1396 LogMsg("unlinkSRS: extra record %##s not found", e->r.resrec.name->c);
1397 return;
1398 }
1399 LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list %##s", srs->RR_SRV.resrec.name->c);
1400 }
1401
1402 // set retry timestamp for record with exponential backoff
1403 // (for service record sets, use RR_SRV as representative for time checks
1404 mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mStatus SendErr)
1405 {
1406 mDNSs32 elapsed = m->timenow - rr->LastAPTime;
1407 rr->LastAPTime = m->timenow;
1408
1409 #if 0
1410 // Code for stress-testing registration renewal code
1411 if (rr->expire && rr->expire - m->timenow > mDNSPlatformOneSecond * 120)
1412 {
1413 LogInfo("Adjusting expiry from %d to 120 seconds for %s",
1414 (rr->expire - m->timenow) / mDNSPlatformOneSecond, ARDisplayString(m, rr));
1415 rr->expire = m->timenow + mDNSPlatformOneSecond * 120;
1416 }
1417 #endif
1418
1419 if (rr->expire && rr->expire - m->timenow > mDNSPlatformOneSecond)
1420 {
1421 mDNSs32 remaining = rr->expire - m->timenow;
1422 rr->ThisAPInterval = remaining/2 + mDNSRandom(remaining/10);
1423 debugf("SetRecordRetry refresh in %4d of %4d for %s",
1424 rr->ThisAPInterval / mDNSPlatformOneSecond, (rr->expire - m->timenow) / mDNSPlatformOneSecond, ARDisplayString(m, rr));
1425 return;
1426 }
1427
1428 rr->expire = 0;
1429
1430 // If at least half our our time interval has elapsed, it's time to double rr->ThisAPInterval
1431 // If resulting interval is too small, set to at least INIT_UCAST_POLL_INTERVAL (3 seconds)
1432 // If resulting interval is too large, set to at most 30 minutes
1433 if (rr->ThisAPInterval / 2 <= elapsed) rr->ThisAPInterval *= 2;
1434 if (rr->ThisAPInterval < INIT_UCAST_POLL_INTERVAL || SendErr == mStatus_TransientErr)
1435 rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
1436 rr->ThisAPInterval += mDNSRandom(rr->ThisAPInterval/20);
1437 if (rr->ThisAPInterval > 30 * 60 * mDNSPlatformOneSecond)
1438 rr->ThisAPInterval = 30 * 60 * mDNSPlatformOneSecond;
1439
1440 LogInfo("SetRecordRetry retry in %4d for %s", rr->ThisAPInterval / mDNSPlatformOneSecond, ARDisplayString(m, rr));
1441 }
1442
1443 // ***************************************************************************
1444 #if COMPILER_LIKES_PRAGMA_MARK
1445 #pragma mark - Name Server List Management
1446 #endif
1447
1448 mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port)
1449 {
1450 DNSServer **p = &m->DNSServers;
1451 DNSServer *tmp = mDNSNULL;
1452
1453 if (!d) d = (const domainname *)"";
1454
1455 LogInfo("mDNS_AddDNSServer: Adding %#a for %##s", addr, d->c);
1456 if (m->mDNS_busy != m->mDNS_reentrancy+1)
1457 LogMsg("mDNS_AddDNSServer: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
1458
1459 while (*p) // Check if we already have this {interface,address,port,domain} tuple registered
1460 {
1461 if ((*p)->interface == interface && (*p)->teststate != DNSServer_Disabled &&
1462 mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d))
1463 {
1464 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);
1465 (*p)->flags &= ~DNSServer_FlagDelete;
1466 tmp = *p;
1467 *p = tmp->next;
1468 tmp->next = mDNSNULL;
1469 }
1470 else
1471 p=&(*p)->next;
1472 }
1473
1474 if (tmp) *p = tmp; // move to end of list, to ensure ordering from platform layer
1475 else
1476 {
1477 // allocate, add to list
1478 *p = mDNSPlatformMemAllocate(sizeof(**p));
1479 if (!*p) LogMsg("Error: mDNS_AddDNSServer - malloc");
1480 else
1481 {
1482 (*p)->interface = interface;
1483 (*p)->addr = *addr;
1484 (*p)->port = port;
1485 (*p)->flags = DNSServer_FlagNew;
1486 (*p)->teststate = /* DNSServer_Untested */ DNSServer_Passed;
1487 (*p)->lasttest = m->timenow - INIT_UCAST_POLL_INTERVAL;
1488 AssignDomainName(&(*p)->domain, d);
1489 (*p)->next = mDNSNULL;
1490 }
1491 }
1492 (*p)->penaltyTime = 0;
1493 return(*p);
1494 }
1495
1496 // PenalizeDNSServer is called when the number of queries to the unicast
1497 // DNS server exceeds MAX_UCAST_UNANSWERED_QUERIES or when we receive an
1498 // error e.g., SERV_FAIL from DNS server. QueryFail is TRUE if this function
1499 // is called when we exceed MAX_UCAST_UNANSWERED_QUERIES
1500
1501 mDNSexport void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSBool QueryFail)
1502 {
1503 DNSServer *orig = q->qDNSServer;
1504
1505 if (m->mDNS_busy != m->mDNS_reentrancy+1)
1506 LogMsg("PenalizeDNSServer: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
1507
1508 if (!q->qDNSServer)
1509 {
1510 LogMsg("PenalizeDNSServer: Null DNS server for %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), q->unansweredQueries);
1511 goto end;
1512 }
1513
1514 if (QueryFail)
1515 {
1516 LogInfo("PenalizeDNSServer: DNS server %#a:%d (%##s) %d unanswered queries for %##s (%s)",
1517 &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c, q->unansweredQueries, q->qname.c, DNSTypeName(q->qtype));
1518 }
1519 else
1520 {
1521 LogInfo("PenalizeDNSServer: DNS server %#a:%d (%##s) Server Error for %##s (%s)",
1522 &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c, q->qname.c, DNSTypeName(q->qtype));
1523 }
1524
1525
1526 // If strict ordering of unicast servers needs to be preserved, we just lookup
1527 // the next best match server below
1528 //
1529 // If strict ordering is not required which is the default behavior, we penalize the server
1530 // for DNSSERVER_PENALTY_TIME. We may also use additional logic e.g., don't penalize for PTR
1531 // in the future.
1532
1533 if (!StrictUnicastOrdering)
1534 {
1535 LogInfo("PenalizeDNSServer: Strict Unicast Ordering is FALSE");
1536 // We penalize the server so that new queries don't pick this server for DNSSERVER_PENALTY_TIME
1537 // XXX Include other logic here to see if this server should really be penalized
1538 //
1539 if (q->qtype == kDNSType_PTR)
1540 {
1541 LogInfo("PenalizeDNSServer: Not Penalizing PTR question");
1542 }
1543 else
1544 {
1545 LogInfo("PenalizeDNSServer: Penalizing question type %d", q->qtype);
1546 q->qDNSServer->penaltyTime = NonZeroTime(m->timenow + DNSSERVER_PENALTY_TIME);
1547 }
1548 }
1549 else
1550 {
1551 LogInfo("PenalizeDNSServer: Strict Unicast Ordering is TRUE");
1552 }
1553
1554 end:
1555 q->qDNSServer = GetServerForName(m, &q->qname, q->qDNSServer);
1556
1557 if ((q->qDNSServer != orig) && (QueryFail))
1558 {
1559 // We picked a new server. In the case where QueryFail is true, the code has already incremented the interval
1560 // and to compensate that we decrease it here. When two queries are sent, the QuestionIntervalStep is at 9. We just
1561 // move it back to 3 here when we pick a new server. We can't start at 1 because if we have two servers failing, we will never
1562 // backoff
1563 //
1564 q->ThisQInterval = q->ThisQInterval / QuestionIntervalStep;
1565 if (q->qDNSServer) LogInfo("PenalizeDNSServer: Server for %##s (%s) changed to %#a:%d (%##s), Question Interval %u", q->qname.c, DNSTypeName(q->qtype), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c, q->ThisQInterval);
1566 else LogInfo("PenalizeDNSServer: Server for %##s (%s) changed to <null>, Question Interval %u", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval);
1567
1568 }
1569 else
1570 {
1571 // if we are here it means,
1572 //
1573 // 1) We picked the same server, QueryFail = false
1574 // 2) We picked the same server, QueryFail = true
1575 // 3) We picked a different server, QueryFail = false
1576 //
1577 // For all these three cases, ThisQInterval is already set properly
1578
1579 if (q->qDNSServer)
1580 {
1581 if (q->qDNSServer != orig)
1582 {
1583 LogInfo("PenalizeDNSServer: 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);
1584 }
1585 else
1586 {
1587 LogInfo("PenalizeDNSServer: Server for %##s (%s) remains the same at %#a:%d (%##s)", q->qname.c, DNSTypeName(q->qtype), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c);
1588 }
1589 }
1590 else
1591 {
1592 LogInfo("PenalizeDNSServer: Server for %##s (%s) changed to <null>", q->qname.c, DNSTypeName(q->qtype));
1593 }
1594 }
1595 q->unansweredQueries = 0;
1596 }
1597
1598 // ***************************************************************************
1599 #if COMPILER_LIKES_PRAGMA_MARK
1600 #pragma mark - authorization management
1601 #endif
1602
1603 mDNSlocal DomainAuthInfo *GetAuthInfoForName_direct(mDNS *m, const domainname *const name)
1604 {
1605 const domainname *n = name;
1606 while (n->c[0])
1607 {
1608 DomainAuthInfo *ptr;
1609 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
1610 if (SameDomainName(&ptr->domain, n))
1611 {
1612 debugf("GetAuthInfoForName %##s Matched %##s Key name %##s", name->c, ptr->domain.c, ptr->keyname.c);
1613 return(ptr);
1614 }
1615 n = (const domainname *)(n->c + 1 + n->c[0]);
1616 }
1617 //LogInfo("GetAuthInfoForName none found for %##s", name->c);
1618 return mDNSNULL;
1619 }
1620
1621 // MUST be called with lock held
1622 mDNSexport DomainAuthInfo *GetAuthInfoForName_internal(mDNS *m, const domainname *const name)
1623 {
1624 DomainAuthInfo **p = &m->AuthInfoList;
1625
1626 if (m->mDNS_busy != m->mDNS_reentrancy+1)
1627 LogMsg("GetAuthInfoForName_internal: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
1628
1629 // First purge any dead keys from the list
1630 while (*p)
1631 {
1632 if ((*p)->deltime && m->timenow - (*p)->deltime >= 0 && AutoTunnelUnregistered(*p))
1633 {
1634 DNSQuestion *q;
1635 DomainAuthInfo *info = *p;
1636 LogInfo("GetAuthInfoForName_internal deleting expired key %##s %##s", info->domain.c, info->keyname.c);
1637 *p = info->next; // Cut DomainAuthInfo from list *before* scanning our question list updating AuthInfo pointers
1638 for (q = m->Questions; q; q=q->next)
1639 if (q->AuthInfo == info)
1640 {
1641 q->AuthInfo = GetAuthInfoForName_direct(m, &q->qname);
1642 debugf("GetAuthInfoForName_internal updated q->AuthInfo from %##s to %##s for %##s (%s)",
1643 info->domain.c, q->AuthInfo ? q->AuthInfo->domain.c : mDNSNULL, q->qname.c, DNSTypeName(q->qtype));
1644 }
1645
1646 // Probably not essential, but just to be safe, zero out the secret key data
1647 // so we don't leave it hanging around in memory
1648 // (where it could potentially get exposed via some other bug)
1649 mDNSPlatformMemZero(info, sizeof(*info));
1650 mDNSPlatformMemFree(info);
1651 }
1652 else
1653 p = &(*p)->next;
1654 }
1655
1656 return(GetAuthInfoForName_direct(m, name));
1657 }
1658
1659 mDNSexport DomainAuthInfo *GetAuthInfoForName(mDNS *m, const domainname *const name)
1660 {
1661 DomainAuthInfo *d;
1662 mDNS_Lock(m);
1663 d = GetAuthInfoForName_internal(m, name);
1664 mDNS_Unlock(m);
1665 return(d);
1666 }
1667
1668 // MUST be called with the lock held
1669 mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
1670 const domainname *domain, const domainname *keyname, const char *b64keydata, mDNSBool AutoTunnel)
1671 {
1672 DNSQuestion *q;
1673 DomainAuthInfo **p = &m->AuthInfoList;
1674 if (!info || !b64keydata) { LogMsg("mDNS_SetSecretForDomain: ERROR: info %p b64keydata %p", info, b64keydata); return(mStatus_BadParamErr); }
1675
1676 LogInfo("mDNS_SetSecretForDomain: domain %##s key %##s%s", domain->c, keyname->c, AutoTunnel ? " AutoTunnel" : "");
1677
1678 info->AutoTunnel = AutoTunnel;
1679 AssignDomainName(&info->domain, domain);
1680 AssignDomainName(&info->keyname, keyname);
1681 mDNS_snprintf(info->b64keydata, sizeof(info->b64keydata), "%s", b64keydata);
1682
1683 if (DNSDigest_ConstructHMACKeyfromBase64(info, b64keydata) < 0)
1684 {
1685 LogMsg("mDNS_SetSecretForDomain: ERROR: Could not convert shared secret from base64: domain %##s key %##s %s", domain->c, keyname->c, mDNS_LoggingEnabled ? b64keydata : "");
1686 return(mStatus_BadParamErr);
1687 }
1688
1689 // Don't clear deltime until after we've ascertained that b64keydata is valid
1690 info->deltime = 0;
1691
1692 while (*p && (*p) != info) p=&(*p)->next;
1693 if (*p) return(mStatus_AlreadyRegistered);
1694
1695 // Caution: Only zero AutoTunnelHostRecord.namestorage and AutoTunnelNAT.clientContext AFTER we've determined that this is a NEW DomainAuthInfo
1696 // being added to the list. Otherwise we risk smashing our AutoTunnel host records and NATOperation that are already active and in use.
1697 info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
1698 info->AutoTunnelHostRecord.namestorage.c[0] = 0;
1699 info->AutoTunnelTarget .resrec.RecordType = kDNSRecordTypeUnregistered;
1700 info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeUnregistered;
1701 info->AutoTunnelService .resrec.RecordType = kDNSRecordTypeUnregistered;
1702 info->AutoTunnelNAT.clientContext = mDNSNULL;
1703 info->next = mDNSNULL;
1704 *p = info;
1705
1706 // Check to see if adding this new DomainAuthInfo has changed the credentials for any of our questions
1707 for (q = m->Questions; q; q=q->next)
1708 {
1709 DomainAuthInfo *newinfo = GetAuthInfoForQuestion(m, q);
1710 if (q->AuthInfo != newinfo)
1711 {
1712 debugf("mDNS_SetSecretForDomain updating q->AuthInfo from %##s to %##s for %##s (%s)",
1713 q->AuthInfo ? q->AuthInfo->domain.c : mDNSNULL,
1714 newinfo ? newinfo ->domain.c : mDNSNULL, q->qname.c, DNSTypeName(q->qtype));
1715 q->AuthInfo = newinfo;
1716 }
1717 }
1718
1719 return(mStatus_NoError);
1720 }
1721
1722 // ***************************************************************************
1723 #if COMPILER_LIKES_PRAGMA_MARK
1724 #pragma mark -
1725 #pragma mark - NAT Traversal
1726 #endif
1727
1728 mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info)
1729 {
1730 mStatus err = mStatus_NoError;
1731
1732 // send msg if we have a router and it is a private address
1733 if (!mDNSIPv4AddressIsZero(m->Router.ip.v4) && mDNSv4AddrIsRFC1918(&m->Router.ip.v4))
1734 {
1735 union { NATAddrRequest NATAddrReq; NATPortMapRequest NATPortReq; } u = { { NATMAP_VERS, NATOp_AddrRequest } } ;
1736 const mDNSu8 *end = (mDNSu8 *)&u + sizeof(NATAddrRequest);
1737
1738 if (info) // For NATOp_MapUDP and NATOp_MapTCP, fill in additional fields
1739 {
1740 mDNSu8 *p = (mDNSu8 *)&u.NATPortReq.NATReq_lease;
1741 u.NATPortReq.opcode = info->Protocol;
1742 u.NATPortReq.unused = zeroID;
1743 u.NATPortReq.intport = info->IntPort;
1744 u.NATPortReq.extport = info->RequestedPort;
1745 p[0] = (mDNSu8)((info->NATLease >> 24) & 0xFF);
1746 p[1] = (mDNSu8)((info->NATLease >> 16) & 0xFF);
1747 p[2] = (mDNSu8)((info->NATLease >> 8) & 0xFF);
1748 p[3] = (mDNSu8)( info->NATLease & 0xFF);
1749 end = (mDNSu8 *)&u + sizeof(NATPortMapRequest);
1750 }
1751
1752 err = mDNSPlatformSendUDP(m, (mDNSu8 *)&u, end, 0, mDNSNULL, &m->Router, NATPMPPort);
1753
1754 #ifdef _LEGACY_NAT_TRAVERSAL_
1755 if (mDNSIPPortIsZero(m->UPnPRouterPort) || mDNSIPPortIsZero(m->UPnPSOAPPort)) LNT_SendDiscoveryMsg(m);
1756 else if (info) err = LNT_MapPort(m, info);
1757 else err = LNT_GetExternalAddress(m);
1758 #endif // _LEGACY_NAT_TRAVERSAL_
1759 }
1760 return(err);
1761 }
1762
1763 mDNSexport void RecreateNATMappings(mDNS *const m)
1764 {
1765 NATTraversalInfo *n;
1766 for (n = m->NATTraversals; n; n=n->next)
1767 {
1768 n->ExpiryTime = 0; // Mark this mapping as expired
1769 n->retryInterval = NATMAP_INIT_RETRY;
1770 n->retryPortMap = m->timenow;
1771 #ifdef _LEGACY_NAT_TRAVERSAL_
1772 if (n->tcpInfo.sock) { mDNSPlatformTCPCloseConnection(n->tcpInfo.sock); n->tcpInfo.sock = mDNSNULL; }
1773 #endif // _LEGACY_NAT_TRAVERSAL_
1774 }
1775
1776 m->NextScheduledNATOp = m->timenow; // Need to send packets immediately
1777 }
1778
1779 mDNSexport void natTraversalHandleAddressReply(mDNS *const m, mDNSu16 err, mDNSv4Addr ExtAddr)
1780 {
1781 static mDNSu16 last_err = 0;
1782
1783 if (err)
1784 {
1785 if (err != last_err) LogMsg("Error getting external address %d", err);
1786 ExtAddr = zerov4Addr;
1787 }
1788 else
1789 {
1790 LogInfo("Received external IP address %.4a from NAT", &ExtAddr);
1791 if (mDNSv4AddrIsRFC1918(&ExtAddr))
1792 LogMsg("Double NAT (external NAT gateway address %.4a is also a private RFC 1918 address)", &ExtAddr);
1793 if (mDNSIPv4AddressIsZero(ExtAddr))
1794 err = NATErr_NetFail; // fake error to handle routers that pathologically report success with the zero address
1795 }
1796
1797 if (!mDNSSameIPv4Address(m->ExternalAddress, ExtAddr))
1798 {
1799 m->ExternalAddress = ExtAddr;
1800 RecreateNATMappings(m); // Also sets NextScheduledNATOp for us
1801 }
1802
1803 if (!err) // Success, back-off to maximum interval
1804 m->retryIntervalGetAddr = NATMAP_MAX_RETRY_INTERVAL;
1805 else if (!last_err) // Failure after success, retry quickly (then back-off exponentially)
1806 m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
1807 // else back-off normally in case of pathological failures
1808
1809 m->retryGetAddr = m->timenow + m->retryIntervalGetAddr;
1810 if (m->NextScheduledNATOp - m->retryIntervalGetAddr > 0)
1811 m->NextScheduledNATOp = m->retryIntervalGetAddr;
1812
1813 last_err = err;
1814 }
1815
1816 // Both places that call NATSetNextRenewalTime() update m->NextScheduledNATOp correctly afterwards
1817 mDNSlocal void NATSetNextRenewalTime(mDNS *const m, NATTraversalInfo *n)
1818 {
1819 n->retryInterval = (n->ExpiryTime - m->timenow)/2;
1820 if (n->retryInterval < NATMAP_MIN_RETRY_INTERVAL) // Min retry interval is 2 seconds
1821 n->retryInterval = NATMAP_MIN_RETRY_INTERVAL;
1822 n->retryPortMap = m->timenow + n->retryInterval;
1823 }
1824
1825 // Note: When called from handleLNTPortMappingResponse() only pkt->err, pkt->extport and pkt->NATRep_lease fields are filled in
1826 mDNSexport void natTraversalHandlePortMapReply(mDNS *const m, NATTraversalInfo *n, const mDNSInterfaceID InterfaceID, mDNSu16 err, mDNSIPPort extport, mDNSu32 lease)
1827 {
1828 const char *prot = n->Protocol == NATOp_MapUDP ? "UDP" : n->Protocol == NATOp_MapTCP ? "TCP" : "?";
1829 (void)prot;
1830 n->NewResult = err;
1831 if (err || lease == 0 || mDNSIPPortIsZero(extport))
1832 {
1833 LogInfo("natTraversalHandlePortMapReply: %p Response %s Port %5d External Port %5d lease %d error %d",
1834 n, prot, mDNSVal16(n->IntPort), mDNSVal16(extport), lease, err);
1835 n->retryInterval = NATMAP_MAX_RETRY_INTERVAL;
1836 n->retryPortMap = m->timenow + NATMAP_MAX_RETRY_INTERVAL;
1837 // No need to set m->NextScheduledNATOp here, since we're only ever extending the m->retryPortMap time
1838 if (err == NATErr_Refused) n->NewResult = mStatus_NATPortMappingDisabled;
1839 else if (err > NATErr_None && err <= NATErr_Opcode) n->NewResult = mStatus_NATPortMappingUnsupported;
1840 }
1841 else
1842 {
1843 if (lease > 999999999UL / mDNSPlatformOneSecond)
1844 lease = 999999999UL / mDNSPlatformOneSecond;
1845 n->ExpiryTime = NonZeroTime(m->timenow + lease * mDNSPlatformOneSecond);
1846
1847 if (!mDNSSameIPPort(n->RequestedPort, extport))
1848 LogInfo("natTraversalHandlePortMapReply: %p Response %s Port %5d External Port %5d changed to %5d",
1849 n, prot, mDNSVal16(n->IntPort), mDNSVal16(n->RequestedPort), mDNSVal16(extport));
1850
1851 n->InterfaceID = InterfaceID;
1852 n->RequestedPort = extport;
1853
1854 LogInfo("natTraversalHandlePortMapReply: %p Response %s Port %5d External Port %5d lease %d",
1855 n, prot, mDNSVal16(n->IntPort), mDNSVal16(extport), lease);
1856
1857 NATSetNextRenewalTime(m, n); // Got our port mapping; now set timer to renew it at halfway point
1858 m->NextScheduledNATOp = m->timenow; // May need to invoke client callback immediately
1859 }
1860 }
1861
1862 // Must be called with the mDNS_Lock held
1863 mDNSexport mStatus mDNS_StartNATOperation_internal(mDNS *const m, NATTraversalInfo *traversal)
1864 {
1865 NATTraversalInfo **n;
1866
1867 LogInfo("mDNS_StartNATOperation_internal Protocol %d IntPort %d RequestedPort %d NATLease %d",
1868 traversal->Protocol, mDNSVal16(traversal->IntPort), mDNSVal16(traversal->RequestedPort), traversal->NATLease);
1869
1870 // Note: It important that new traversal requests are appended at the *end* of the list, not prepended at the start
1871 for (n = &m->NATTraversals; *n; n=&(*n)->next)
1872 {
1873 if (traversal == *n)
1874 {
1875 LogMsg("Error! Tried to add a NAT traversal that's already in the active list: request %p Prot %d Int %d TTL %d",
1876 traversal, traversal->Protocol, mDNSVal16(traversal->IntPort), traversal->NATLease);
1877 return(mStatus_AlreadyRegistered);
1878 }
1879 if (traversal->Protocol && traversal->Protocol == (*n)->Protocol && mDNSSameIPPort(traversal->IntPort, (*n)->IntPort) &&
1880 !mDNSSameIPPort(traversal->IntPort, SSHPort))
1881 LogMsg("Warning: Created port mapping request %p Prot %d Int %d TTL %d "
1882 "duplicates existing port mapping request %p Prot %d Int %d TTL %d",
1883 traversal, traversal->Protocol, mDNSVal16(traversal->IntPort), traversal->NATLease,
1884 *n, (*n) ->Protocol, mDNSVal16((*n) ->IntPort), (*n) ->NATLease);
1885 }
1886
1887 // Initialize necessary fields
1888 traversal->next = mDNSNULL;
1889 traversal->ExpiryTime = 0;
1890 traversal->retryInterval = NATMAP_INIT_RETRY;
1891 traversal->retryPortMap = m->timenow;
1892 traversal->NewResult = mStatus_NoError;
1893 traversal->ExternalAddress = onesIPv4Addr;
1894 traversal->ExternalPort = zeroIPPort;
1895 traversal->Lifetime = 0;
1896 traversal->Result = mStatus_NoError;
1897
1898 // set default lease if necessary
1899 if (!traversal->NATLease) traversal->NATLease = NATMAP_DEFAULT_LEASE;
1900
1901 #ifdef _LEGACY_NAT_TRAVERSAL_
1902 mDNSPlatformMemZero(&traversal->tcpInfo, sizeof(traversal->tcpInfo));
1903 #endif // _LEGACY_NAT_TRAVERSAL_
1904
1905 if (!m->NATTraversals) // If this is our first NAT request, kick off an address request too
1906 {
1907 m->retryGetAddr = m->timenow;
1908 m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
1909 }
1910
1911 m->NextScheduledNATOp = m->timenow; // This will always trigger sending the packet ASAP, and generate client callback if necessary
1912
1913 *n = traversal; // Append new NATTraversalInfo to the end of our list
1914
1915 return(mStatus_NoError);
1916 }
1917
1918 // Must be called with the mDNS_Lock held
1919 mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *traversal)
1920 {
1921 mDNSBool unmap = mDNStrue;
1922 NATTraversalInfo *p;
1923 NATTraversalInfo **ptr = &m->NATTraversals;
1924
1925 while (*ptr && *ptr != traversal) ptr=&(*ptr)->next;
1926 if (*ptr) *ptr = (*ptr)->next; // If we found it, cut this NATTraversalInfo struct from our list
1927 else
1928 {
1929 LogMsg("mDNS_StopNATOperation: NATTraversalInfo %p not found in list", traversal);
1930 return(mStatus_BadReferenceErr);
1931 }
1932
1933 LogInfo("mDNS_StopNATOperation_internal %d %d %d %d",
1934 traversal->Protocol, mDNSVal16(traversal->IntPort), mDNSVal16(traversal->RequestedPort), traversal->NATLease);
1935
1936 if (m->CurrentNATTraversal == traversal)
1937 m->CurrentNATTraversal = m->CurrentNATTraversal->next;
1938
1939 if (traversal->Protocol)
1940 for (p = m->NATTraversals; p; p=p->next)
1941 if (traversal->Protocol == p->Protocol && mDNSSameIPPort(traversal->IntPort, p->IntPort))
1942 {
1943 if (!mDNSSameIPPort(traversal->IntPort, SSHPort))
1944 LogMsg("Warning: Removed port mapping request %p Prot %d Int %d TTL %d "
1945 "duplicates existing port mapping request %p Prot %d Int %d TTL %d",
1946 traversal, traversal->Protocol, mDNSVal16(traversal->IntPort), traversal->NATLease,
1947 p, p ->Protocol, mDNSVal16(p ->IntPort), p ->NATLease);
1948 unmap = mDNSfalse;
1949 }
1950
1951 if (traversal->ExpiryTime && unmap)
1952 {
1953 traversal->NATLease = 0;
1954 traversal->retryInterval = 0;
1955 uDNS_SendNATMsg(m, traversal);
1956 }
1957
1958 // 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
1959 #ifdef _LEGACY_NAT_TRAVERSAL_
1960 {
1961 mStatus err = LNT_UnmapPort(m, traversal);
1962 if (err) LogMsg("Legacy NAT Traversal - unmap request failed with error %d", err);
1963 }
1964 #endif // _LEGACY_NAT_TRAVERSAL_
1965
1966 return(mStatus_NoError);
1967 }
1968
1969 mDNSexport mStatus mDNS_StartNATOperation(mDNS *m, NATTraversalInfo *traversal)
1970 {
1971 mStatus status;
1972 mDNS_Lock(m);
1973 status = mDNS_StartNATOperation_internal(m, traversal);
1974 mDNS_Unlock(m);
1975 return(status);
1976 }
1977
1978 mDNSexport mStatus mDNS_StopNATOperation(mDNS *m, NATTraversalInfo *traversal)
1979 {
1980 mStatus status;
1981 mDNS_Lock(m);
1982 status = mDNS_StopNATOperation_internal(m, traversal);
1983 mDNS_Unlock(m);
1984 return(status);
1985 }
1986
1987 // ***************************************************************************
1988 #if COMPILER_LIKES_PRAGMA_MARK
1989 #pragma mark -
1990 #pragma mark - Long-Lived Queries
1991 #endif
1992
1993 // Lock must be held -- otherwise m->timenow is undefined
1994 mDNSlocal void StartLLQPolling(mDNS *const m, DNSQuestion *q)
1995 {
1996 debugf("StartLLQPolling: %##s", q->qname.c);
1997 q->state = LLQ_Poll;
1998 q->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
1999 // We want to send our poll query ASAP, but the "+ 1" is because if we set the time to now,
2000 // we risk causing spurious "SendQueries didn't send all its queries" log messages
2001 q->LastQTime = m->timenow - q->ThisQInterval + 1;
2002 SetNextQueryTime(m, q);
2003 #if APPLE_OSX_mDNSResponder
2004 UpdateAutoTunnelDomainStatuses(m);
2005 #endif
2006 }
2007
2008 mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, const DNSQuestion *const question, const LLQOptData *const data)
2009 {
2010 AuthRecord rr;
2011 ResourceRecord *opt = &rr.resrec;
2012 rdataOPT *optRD;
2013
2014 //!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section
2015 ptr = putQuestion(msg, ptr, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
2016 if (!ptr) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL; }
2017
2018 // locate OptRR if it exists, set pointer to end
2019 // !!!KRS implement me
2020
2021 // format opt rr (fields not specified are zero-valued)
2022 mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
2023 opt->rrclass = NormalMaxDNSMessageData;
2024 opt->rdlength = sizeof(rdataOPT); // One option in this OPT record
2025 opt->rdestimate = sizeof(rdataOPT);
2026
2027 optRD = &rr.resrec.rdata->u.opt[0];
2028 optRD->opt = kDNSOpt_LLQ;
2029 optRD->u.llq = *data;
2030 ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.numAdditionals, opt, 0);
2031 if (!ptr) { LogMsg("ERROR: putLLQ - PutResourceRecordTTLJumbo"); return mDNSNULL; }
2032
2033 return ptr;
2034 }
2035
2036 // Normally we'd just request event packets be sent directly to m->LLQNAT.ExternalPort, except...
2037 // with LLQs over TLS/TCP we're doing a weird thing where instead of requesting packets be sent to ExternalAddress:ExternalPort
2038 // we're requesting that packets be sent to ExternalPort, but at the source address of our outgoing TCP connection.
2039 // Normally, after going through the NAT gateway, the source address of our outgoing TCP connection is the same as ExternalAddress,
2040 // so this is fine, except when the TCP connection ends up going over a VPN tunnel instead.
2041 // 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
2042 // LLQ server to send events to us directly at port 5353 on that address, instead of at our mapped external NAT port.
2043
2044 mDNSlocal mDNSu16 GetLLQEventPort(const mDNS *const m, const mDNSAddr *const dst)
2045 {
2046 mDNSAddr src;
2047 mDNSPlatformSourceAddrForDest(&src, dst);
2048 //LogMsg("GetLLQEventPort: src %#a for dst %#a (%d)", &src, dst, mDNSv4AddrIsRFC1918(&src.ip.v4) ? mDNSVal16(m->LLQNAT.ExternalPort) : 0);
2049 return(mDNSv4AddrIsRFC1918(&src.ip.v4) ? mDNSVal16(m->LLQNAT.ExternalPort) : mDNSVal16(MulticastDNSPort));
2050 }
2051
2052 // Normally called with llq set.
2053 // May be called with llq NULL, when retransmitting a lost Challenge Response
2054 mDNSlocal void sendChallengeResponse(mDNS *const m, DNSQuestion *const q, const LLQOptData *llq)
2055 {
2056 mDNSu8 *responsePtr = m->omsg.data;
2057 LLQOptData llqBuf;
2058
2059 if (q->ntries++ == kLLQ_MAX_TRIES)
2060 {
2061 LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s", kLLQ_MAX_TRIES, q->qname.c);
2062 StartLLQPolling(m,q);
2063 return;
2064 }
2065
2066 if (!llq) // Retransmission: need to make a new LLQOptData
2067 {
2068 llqBuf.vers = kLLQ_Vers;
2069 llqBuf.llqOp = kLLQOp_Setup;
2070 llqBuf.err = LLQErr_NoError; // Don't need to tell server UDP notification port when sending over UDP
2071 llqBuf.id = q->id;
2072 llqBuf.llqlease = q->ReqLease;
2073 llq = &llqBuf;
2074 }
2075
2076 q->LastQTime = m->timenow;
2077 q->ThisQInterval = q->tcp ? 0 : (kLLQ_INIT_RESEND * q->ntries * mDNSPlatformOneSecond); // If using TCP, don't need to retransmit
2078 SetNextQueryTime(m, q);
2079
2080 // To simulate loss of challenge response packet, uncomment line below
2081 //if (q->ntries == 1) return;
2082
2083 InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
2084 responsePtr = putLLQ(&m->omsg, responsePtr, q, llq);
2085 if (responsePtr)
2086 {
2087 mStatus err = mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, q->AuthInfo);
2088 if (err)
2089 {
2090 LogMsg("sendChallengeResponse: mDNSSendDNSMessage%s failed: %d", q->tcp ? " (TCP)" : "", err);
2091 if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; }
2092 }
2093 }
2094 else StartLLQPolling(m,q);
2095 }
2096
2097 mDNSlocal void SetLLQTimer(mDNS *const m, DNSQuestion *const q, const LLQOptData *const llq)
2098 {
2099 mDNSs32 lease = (mDNSs32)llq->llqlease * mDNSPlatformOneSecond;
2100 q->ReqLease = llq->llqlease;
2101 q->LastQTime = m->timenow;
2102 q->expire = m->timenow + lease;
2103 q->ThisQInterval = lease/2 + mDNSRandom(lease/10);
2104 debugf("SetLLQTimer setting %##s (%s) to %d %d", q->qname.c, DNSTypeName(q->qtype), lease/mDNSPlatformOneSecond, q->ThisQInterval/mDNSPlatformOneSecond);
2105 SetNextQueryTime(m, q);
2106 }
2107
2108 mDNSlocal void recvSetupResponse(mDNS *const m, mDNSu8 rcode, DNSQuestion *const q, const LLQOptData *const llq)
2109 {
2110 if (rcode && rcode != kDNSFlag1_RC_NXDomain)
2111 { LogMsg("ERROR: recvSetupResponse %##s (%s) - rcode && rcode != kDNSFlag1_RC_NXDomain", q->qname.c, DNSTypeName(q->qtype)); return; }
2112
2113 if (llq->llqOp != kLLQOp_Setup)
2114 { LogMsg("ERROR: recvSetupResponse %##s (%s) - bad op %d", q->qname.c, DNSTypeName(q->qtype), llq->llqOp); return; }
2115
2116 if (llq->vers != kLLQ_Vers)
2117 { LogMsg("ERROR: recvSetupResponse %##s (%s) - bad vers %d", q->qname.c, DNSTypeName(q->qtype), llq->vers); return; }
2118
2119 if (q->state == LLQ_InitialRequest)
2120 {
2121 //LogInfo("Got LLQ_InitialRequest");
2122
2123 if (llq->err) { LogMsg("recvSetupResponse - received llq->err %d from server", llq->err); StartLLQPolling(m,q); return; }
2124
2125 if (q->ReqLease != llq->llqlease)
2126 debugf("recvSetupResponse: requested lease %lu, granted lease %lu", q->ReqLease, llq->llqlease);
2127
2128 // cache expiration in case we go to sleep before finishing setup
2129 q->ReqLease = llq->llqlease;
2130 q->expire = m->timenow + ((mDNSs32)llq->llqlease * mDNSPlatformOneSecond);
2131
2132 // update state
2133 q->state = LLQ_SecondaryRequest;
2134 q->id = llq->id;
2135 q->ntries = 0; // first attempt to send response
2136 sendChallengeResponse(m, q, llq);
2137 }
2138 else if (q->state == LLQ_SecondaryRequest)
2139 {
2140 //LogInfo("Got LLQ_SecondaryRequest");
2141
2142 // Fix this immediately if not sooner. Copy the id from the LLQOptData into our DNSQuestion struct. This is only
2143 // an issue for private LLQs, because we skip parts 2 and 3 of the handshake. This is related to a bigger
2144 // problem of the current implementation of TCP LLQ setup: we're not handling state transitions correctly
2145 // if the server sends back SERVFULL or STATIC.
2146 if (q->AuthInfo)
2147 {
2148 LogInfo("Private LLQ_SecondaryRequest; copying id %08X%08X", llq->id.l[0], llq->id.l[1]);
2149 q->id = llq->id;
2150 }
2151
2152 if (llq->err) { LogMsg("ERROR: recvSetupResponse %##s (%s) code %d from server", q->qname.c, DNSTypeName(q->qtype), llq->err); StartLLQPolling(m,q); return; }
2153 if (!mDNSSameOpaque64(&q->id, &llq->id))
2154 { LogMsg("recvSetupResponse - ID changed. discarding"); return; } // this can happen rarely (on packet loss + reordering)
2155 q->state = LLQ_Established;
2156 q->ntries = 0;
2157 SetLLQTimer(m, q, llq);
2158 #if APPLE_OSX_mDNSResponder
2159 UpdateAutoTunnelDomainStatuses(m);
2160 #endif
2161 }
2162 }
2163
2164 mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport)
2165 {
2166 DNSQuestion pktQ, *q;
2167 if (msg->h.numQuestions && getQuestion(msg, msg->data, end, 0, &pktQ))
2168 {
2169 const rdataOPT *opt = GetLLQOptData(m, msg, end);
2170
2171 for (q = m->Questions; q; q = q->next)
2172 {
2173 if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->qtype == pktQ.qtype && q->qnamehash == pktQ.qnamehash && SameDomainName(&q->qname, &pktQ.qname))
2174 {
2175 debugf("uDNS_recvLLQResponse found %##s (%s) %d %#a %#a %X %X %X %X %d",
2176 q->qname.c, DNSTypeName(q->qtype), q->state, srcaddr, &q->servAddr,
2177 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);
2178 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));
2179 if (q->state == LLQ_Poll && mDNSSameOpaque16(msg->h.id, q->TargetQID))
2180 {
2181 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
2182 debugf("uDNS_recvLLQResponse got poll response; moving to LLQ_InitialRequest for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
2183 q->state = LLQ_InitialRequest;
2184 q->servPort = zeroIPPort; // Clear servPort so that startLLQHandshake will retry the GetZoneData processing
2185 q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10); // Retry LLQ setup in approx 15 minutes
2186 q->LastQTime = m->timenow;
2187 SetNextQueryTime(m, q);
2188 return uDNS_LLQ_Entire; // uDNS_LLQ_Entire means flush stale records; assume a large effective TTL
2189 }
2190 // 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
2191 else if (opt && q->state == LLQ_Established && opt->u.llq.llqOp == kLLQOp_Event && mDNSSameOpaque64(&opt->u.llq.id, &q->id))
2192 {
2193 mDNSu8 *ackEnd;
2194 //debugf("Sending LLQ ack for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
2195 InitializeDNSMessage(&m->omsg.h, msg->h.id, ResponseFlags);
2196 ackEnd = putLLQ(&m->omsg, m->omsg.data, q, &opt->u.llq);
2197 if (ackEnd) mDNSSendDNSMessage(m, &m->omsg, ackEnd, mDNSInterface_Any, q->LocalSocket, srcaddr, srcport, mDNSNULL, mDNSNULL);
2198 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
2199 debugf("uDNS_LLQ_Events: q->state == LLQ_Established msg->h.id %d q->TargetQID %d", mDNSVal16(msg->h.id), mDNSVal16(q->TargetQID));
2200 return uDNS_LLQ_Events;
2201 }
2202 if (opt && mDNSSameOpaque16(msg->h.id, q->TargetQID))
2203 {
2204 if (q->state == LLQ_Established && opt->u.llq.llqOp == kLLQOp_Refresh && mDNSSameOpaque64(&opt->u.llq.id, &q->id) && msg->h.numAdditionals && !msg->h.numAnswers)
2205 {
2206 if (opt->u.llq.err != LLQErr_NoError) LogMsg("recvRefreshReply: received error %d from server", opt->u.llq.err);
2207 else
2208 {
2209 //LogInfo("Received refresh confirmation ntries %d for %##s (%s)", q->ntries, q->qname.c, DNSTypeName(q->qtype));
2210 // If we're waiting to go to sleep, then this LLQ deletion may have been the thing
2211 // we were waiting for, so schedule another check to see if we can sleep now.
2212 if (opt->u.llq.llqlease == 0 && m->SleepLimit) m->NextScheduledSPRetry = m->timenow;
2213 GrantCacheExtensions(m, q, opt->u.llq.llqlease);
2214 SetLLQTimer(m, q, &opt->u.llq);
2215 q->ntries = 0;
2216 }
2217 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
2218 return uDNS_LLQ_Ignore;
2219 }
2220 if (q->state < LLQ_Established && mDNSSameAddress(srcaddr, &q->servAddr))
2221 {
2222 LLQ_State oldstate = q->state;
2223 recvSetupResponse(m, msg->h.flags.b[1] & kDNSFlag1_RC_Mask, q, &opt->u.llq);
2224 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
2225 // We have a protocol anomaly here in the LLQ definition.
2226 // Both the challenge packet from the server and the ack+answers packet have opt->u.llq.llqOp == kLLQOp_Setup.
2227 // However, we need to treat them differently:
2228 // The challenge packet has no answers in it, and tells us nothing about whether our cache entries
2229 // are still valid, so this packet should not cause us to do anything that messes with our cache.
2230 // The ack+answers packet gives us the whole truth, so we should handle it by updating our cache
2231 // to match the answers in the packet, and only the answers in the packet.
2232 return (oldstate == LLQ_SecondaryRequest ? uDNS_LLQ_Entire : uDNS_LLQ_Ignore);
2233 }
2234 }
2235 }
2236 }
2237 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
2238 }
2239 return uDNS_LLQ_Not;
2240 }
2241
2242 // Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
2243 struct TCPSocket_struct { TCPSocketFlags flags; /* ... */ };
2244
2245 // tcpCallback is called to handle events (e.g. connection opening and data reception) on TCP connections for
2246 // Private DNS operations -- private queries, private LLQs, private record updates and private service updates
2247 mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err)
2248 {
2249 tcpInfo_t *tcpInfo = (tcpInfo_t *)context;
2250 mDNSBool closed = mDNSfalse;
2251 mDNS *m = tcpInfo->m;
2252 DNSQuestion *const q = tcpInfo->question;
2253 tcpInfo_t **backpointer =
2254 q ? &q ->tcp :
2255 tcpInfo->srs ? &tcpInfo->srs->tcp :
2256 tcpInfo->rr ? &tcpInfo->rr ->tcp : mDNSNULL;
2257 if (backpointer && *backpointer != tcpInfo)
2258 LogMsg("tcpCallback: %d backpointer %p incorrect tcpInfo %p question %p srs %p rr %p",
2259 mDNSPlatformTCPGetFD(tcpInfo->sock), *backpointer, tcpInfo, q, tcpInfo->srs, tcpInfo->rr);
2260
2261 if (err) goto exit;
2262
2263 if (ConnectionEstablished)
2264 {
2265 mDNSu8 *end = ((mDNSu8*) &tcpInfo->request) + tcpInfo->requestLen;
2266 DomainAuthInfo *AuthInfo;
2267
2268 // Defensive coding for <rdar://problem/5546824> Crash in mDNSResponder at GetAuthInfoForName_internal + 366
2269 // 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
2270 if (tcpInfo->srs && tcpInfo->srs->RR_SRV.resrec.name != &tcpInfo->srs->RR_SRV.namestorage)
2271 LogMsg("tcpCallback: ERROR: tcpInfo->srs->RR_SRV.resrec.name %p != &tcpInfo->srs->RR_SRV.namestorage %p",
2272 tcpInfo->srs->RR_SRV.resrec.name, &tcpInfo->srs->RR_SRV.namestorage);
2273 if (tcpInfo->rr && tcpInfo->rr->resrec.name != &tcpInfo->rr->namestorage)
2274 LogMsg("tcpCallback: ERROR: tcpInfo->rr->resrec.name %p != &tcpInfo->rr->namestorage %p",
2275 tcpInfo->rr->resrec.name, &tcpInfo->rr->namestorage);
2276 if (tcpInfo->srs && tcpInfo->srs->RR_SRV.resrec.name != &tcpInfo->srs->RR_SRV.namestorage) return;
2277 if (tcpInfo->rr && tcpInfo->rr-> resrec.name != &tcpInfo->rr-> namestorage) return;
2278
2279 AuthInfo = tcpInfo->srs ? GetAuthInfoForName(m, tcpInfo->srs->RR_SRV.resrec.name) :
2280 tcpInfo->rr ? GetAuthInfoForName(m, tcpInfo->rr->resrec.name) : mDNSNULL;
2281
2282 // connection is established - send the message
2283 if (q && q->LongLived && q->state == LLQ_Established)
2284 {
2285 // Lease renewal over TCP, resulting from opening a TCP connection in sendLLQRefresh
2286 end = ((mDNSu8*) &tcpInfo->request) + tcpInfo->requestLen;
2287 }
2288 else if (q && q->LongLived && q->state != LLQ_Poll && !mDNSIPPortIsZero(m->LLQNAT.ExternalPort) && !mDNSIPPortIsZero(q->servPort))
2289 {
2290 // Notes:
2291 // If we have a NAT port mapping, ExternalPort is the external port
2292 // If we have a routable address so we don't need a port mapping, ExternalPort is the same as our own internal port
2293 // If we need a NAT port mapping but can't get one, then ExternalPort is zero
2294 LLQOptData llqData; // set llq rdata
2295 llqData.vers = kLLQ_Vers;
2296 llqData.llqOp = kLLQOp_Setup;
2297 llqData.err = GetLLQEventPort(m, &tcpInfo->Addr); // We're using TCP; tell server what UDP port to send notifications to
2298 LogInfo("tcpCallback: eventPort %d", llqData.err);
2299 llqData.id = zeroOpaque64;
2300 llqData.llqlease = kLLQ_DefLease;
2301 InitializeDNSMessage(&tcpInfo->request.h, q->TargetQID, uQueryFlags);
2302 end = putLLQ(&tcpInfo->request, tcpInfo->request.data, q, &llqData);
2303 if (!end) { LogMsg("ERROR: tcpCallback - putLLQ"); err = mStatus_UnknownErr; goto exit; }
2304 AuthInfo = q->AuthInfo; // Need to add TSIG to this message
2305 q->ntries = 0; // Reset ntries so that tcp/tls connection failures don't affect sendChallengeResponse failures
2306 }
2307 else if (q)
2308 {
2309 // LLQ Polling mode or non-LLQ uDNS over TCP
2310 InitializeDNSMessage(&tcpInfo->request.h, q->TargetQID, uQueryFlags);
2311 end = putQuestion(&tcpInfo->request, tcpInfo->request.data, tcpInfo->request.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
2312 AuthInfo = q->AuthInfo; // Need to add TSIG to this message
2313 }
2314
2315 err = mDNSSendDNSMessage(m, &tcpInfo->request, end, mDNSInterface_Any, mDNSNULL, &tcpInfo->Addr, tcpInfo->Port, sock, AuthInfo);
2316 if (err) { debugf("ERROR: tcpCallback: mDNSSendDNSMessage - %d", err); err = mStatus_UnknownErr; goto exit; }
2317
2318 // Record time we sent this question
2319 if (q)
2320 {
2321 mDNS_Lock(m);
2322 q->LastQTime = m->timenow;
2323 if (q->ThisQInterval < (256 * mDNSPlatformOneSecond)) // Now we have a TCP connection open, make sure we wait at least 256 seconds before retrying
2324 q->ThisQInterval = (256 * mDNSPlatformOneSecond);
2325 SetNextQueryTime(m, q);
2326 mDNS_Unlock(m);
2327 }
2328 }
2329 else
2330 {
2331 long n;
2332 if (tcpInfo->nread < 2) // First read the two-byte length preceeding the DNS message
2333 {
2334 mDNSu8 *lenptr = (mDNSu8 *)&tcpInfo->replylen;
2335 n = mDNSPlatformReadTCP(sock, lenptr + tcpInfo->nread, 2 - tcpInfo->nread, &closed);
2336 if (n < 0)
2337 {
2338 LogMsg("ERROR: tcpCallback - attempt to read message length failed (%d)", n);
2339 err = mStatus_ConnFailed;
2340 goto exit;
2341 }
2342 else if (closed)
2343 {
2344 // It's perfectly fine for this socket to close after the first reply. The server might
2345 // be sending gratuitous replies using UDP and doesn't have a need to leave the TCP socket open.
2346 // We'll only log this event if we've never received a reply before.
2347 // BIND 9 appears to close an idle connection after 30 seconds.
2348 if (tcpInfo->numReplies == 0)
2349 {
2350 LogMsg("ERROR: socket closed prematurely tcpInfo->nread = %d", tcpInfo->nread);
2351 err = mStatus_ConnFailed;
2352 goto exit;
2353 }
2354 else
2355 {
2356 // Note that we may not be doing the best thing if an error occurs after we've sent a second request
2357 // over this tcp connection. That is, we only track whether we've received at least one response
2358 // which may have been to a previous request sent over this tcp connection.
2359 if (backpointer) *backpointer = mDNSNULL; // Clear client backpointer FIRST so we don't risk double-disposing our tcpInfo_t
2360 DisposeTCPConn(tcpInfo);
2361 return;
2362 }
2363 }
2364
2365 tcpInfo->nread += n;
2366 if (tcpInfo->nread < 2) goto exit;
2367
2368 tcpInfo->replylen = (mDNSu16)((mDNSu16)lenptr[0] << 8 | lenptr[1]);
2369 if (tcpInfo->replylen < sizeof(DNSMessageHeader))
2370 { LogMsg("ERROR: tcpCallback - length too short (%d bytes)", tcpInfo->replylen); err = mStatus_UnknownErr; goto exit; }
2371
2372 tcpInfo->reply = mDNSPlatformMemAllocate(tcpInfo->replylen);
2373 if (!tcpInfo->reply) { LogMsg("ERROR: tcpCallback - malloc failed"); err = mStatus_NoMemoryErr; goto exit; }
2374 }
2375
2376 n = mDNSPlatformReadTCP(sock, ((char *)tcpInfo->reply) + (tcpInfo->nread - 2), tcpInfo->replylen - (tcpInfo->nread - 2), &closed);
2377
2378 if (n < 0)
2379 {
2380 LogMsg("ERROR: tcpCallback - read returned %d", n);
2381 err = mStatus_ConnFailed;
2382 goto exit;
2383 }
2384 else if (closed)
2385 {
2386 if (tcpInfo->numReplies == 0)
2387 {
2388 LogMsg("ERROR: socket closed prematurely tcpInfo->nread = %d", tcpInfo->nread);
2389 err = mStatus_ConnFailed;
2390 goto exit;
2391 }
2392 else
2393 {
2394 // Note that we may not be doing the best thing if an error occurs after we've sent a second request
2395 // over this tcp connection. That is, we only track whether we've received at least one response
2396 // which may have been to a previous request sent over this tcp connection.
2397 if (backpointer) *backpointer = mDNSNULL; // Clear client backpointer FIRST so we don't risk double-disposing our tcpInfo_t
2398 DisposeTCPConn(tcpInfo);
2399 return;
2400 }
2401 }
2402
2403 tcpInfo->nread += n;
2404
2405 if ((tcpInfo->nread - 2) == tcpInfo->replylen)
2406 {
2407 AuthRecord *rr = tcpInfo->rr;
2408 DNSMessage *reply = tcpInfo->reply;
2409 mDNSu8 *end = (mDNSu8 *)tcpInfo->reply + tcpInfo->replylen;
2410 mDNSAddr Addr = tcpInfo->Addr;
2411 mDNSIPPort Port = tcpInfo->Port;
2412 tcpInfo->numReplies++;
2413 tcpInfo->reply = mDNSNULL; // Detach reply buffer from tcpInfo_t, to make sure client callback can't cause it to be disposed
2414 tcpInfo->nread = 0;
2415 tcpInfo->replylen = 0;
2416
2417 // If we're going to dispose this connection, do it FIRST, before calling client callback
2418 // Note: Sleep code depends on us clearing *backpointer here -- it uses the clearing of rr->tcp and srs->tcp
2419 // as the signal that the DNS deregistration operation with the server has completed, and the machine may now sleep
2420 if (backpointer)
2421 if (!q || !q->LongLived || m->SleepState)
2422 { *backpointer = mDNSNULL; DisposeTCPConn(tcpInfo); }
2423
2424 if (rr && rr->resrec.RecordType == kDNSRecordTypeDeregistering)
2425 {
2426 mDNS_Lock(m);
2427 LogInfo("tcpCallback: CompleteDeregistration %s", ARDisplayString(m, rr));
2428 CompleteDeregistration(m, rr); // Don't touch rr after this
2429 mDNS_Unlock(m);
2430 }
2431 else
2432 mDNSCoreReceive(m, reply, end, &Addr, Port, (sock->flags & kTCPSocketFlags_UseTLS) ? (mDNSAddr *)1 : mDNSNULL, zeroIPPort, 0);
2433 // USE CAUTION HERE: Invoking mDNSCoreReceive may have caused the environment to change, including canceling this operation itself
2434
2435 mDNSPlatformMemFree(reply);
2436 return;
2437 }
2438 }
2439
2440 exit:
2441
2442 if (err)
2443 {
2444 // Clear client backpointer FIRST -- that way if one of the callbacks cancels its operation
2445 // we won't end up double-disposing our tcpInfo_t
2446 if (backpointer) *backpointer = mDNSNULL;
2447
2448 mDNS_Lock(m); // Need to grab the lock to get m->timenow
2449
2450 if (q)
2451 {
2452 if (q->ThisQInterval == 0)
2453 {
2454 // We get here when we fail to establish a new TCP/TLS connection that would have been used for a new LLQ request or an LLQ renewal.
2455 // Note that ThisQInterval is also zero when sendChallengeResponse resends the LLQ request on an extant TCP/TLS connection.
2456 q->LastQTime = m->timenow;
2457 if (q->LongLived)
2458 {
2459 // We didn't get the chance to send our request packet before the TCP/TLS connection failed.
2460 // We want to retry quickly, but want to back off exponentially in case the server is having issues.
2461 // Since ThisQInterval was 0, we can't just multiply by QuestionIntervalStep, we must track the number
2462 // of TCP/TLS connection failures using ntries.
2463 mDNSu32 count = q->ntries + 1; // want to wait at least 1 second before retrying
2464
2465 q->ThisQInterval = InitialQuestionInterval;
2466
2467 for (;count;count--)
2468 q->ThisQInterval *= QuestionIntervalStep;
2469
2470 if (q->ThisQInterval > LLQ_POLL_INTERVAL)
2471 q->ThisQInterval = LLQ_POLL_INTERVAL;
2472 else
2473 q->ntries++;
2474
2475 LogMsg("tcpCallback: stream connection for LLQ %##s (%s) failed %d times, retrying in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ntries, q->ThisQInterval);
2476 }
2477 else
2478 {
2479 q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
2480 LogMsg("tcpCallback: stream connection for %##s (%s) failed, retrying in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval);
2481 }
2482 SetNextQueryTime(m, q);
2483 }
2484 else if (q->LastQTime + q->ThisQInterval - m->timenow > (q->LongLived ? LLQ_POLL_INTERVAL : MAX_UCAST_POLL_INTERVAL))
2485 {
2486 // If we get an error and our next scheduled query for this question is more than the max interval from now,
2487 // reset the next query to ensure we wait no longer the maximum interval from now before trying again.
2488 q->LastQTime = m->timenow;
2489 q->ThisQInterval = q->LongLived ? LLQ_POLL_INTERVAL : MAX_UCAST_POLL_INTERVAL;
2490 SetNextQueryTime(m, q);
2491 LogMsg("tcpCallback: stream connection for %##s (%s) failed, retrying in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval);
2492 }
2493
2494 // We're about to dispose of the TCP connection, so we must reset the state to retry over TCP/TLS
2495 // because sendChallengeResponse will send the query via UDP if we don't have a tcp pointer.
2496 // Resetting to LLQ_InitialRequest will cause uDNS_CheckCurrentQuestion to call startLLQHandshake, which
2497 // will attempt to establish a new tcp connection.
2498 if (q->LongLived && q->state == LLQ_SecondaryRequest)
2499 q->state = LLQ_InitialRequest;
2500
2501 // ConnFailed may happen if the server sends a TCP reset or TLS fails, in which case we want to retry establishing the LLQ
2502 // quickly rather than switching to polling mode. This case is handled by the above code to set q->ThisQInterval just above.
2503 // If the error isn't ConnFailed, then the LLQ is in bad shape, so we switch to polling mode.
2504 if (err != mStatus_ConnFailed)
2505 {
2506 if (q->LongLived && q->state != LLQ_Poll) StartLLQPolling(m, q);
2507 }
2508 }
2509
2510 if (tcpInfo->rr) SetRecordRetry(m, tcpInfo->rr, mStatus_NoError);
2511
2512 if (tcpInfo->srs) SetRecordRetry(m, &tcpInfo->srs->RR_SRV, mStatus_NoError);
2513
2514 mDNS_Unlock(m);
2515
2516 DisposeTCPConn(tcpInfo);
2517 }
2518 }
2519
2520 mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
2521 TCPSocketFlags flags, const mDNSAddr *const Addr, const mDNSIPPort Port,
2522 DNSQuestion *const question, ServiceRecordSet *const srs, AuthRecord *const rr)
2523 {
2524 mStatus err;
2525 mDNSIPPort srcport = zeroIPPort;
2526 tcpInfo_t *info = (tcpInfo_t *)mDNSPlatformMemAllocate(sizeof(tcpInfo_t));
2527 if (!info) { LogMsg("ERROR: MakeTCP - memallocate failed"); return(mDNSNULL); }
2528 mDNSPlatformMemZero(info, sizeof(tcpInfo_t));
2529
2530 info->m = m;
2531 info->sock = mDNSPlatformTCPSocket(m, flags, &srcport);
2532 info->requestLen = 0;
2533 info->question = question;
2534 info->srs = srs;
2535 info->rr = rr;
2536 info->Addr = *Addr;
2537 info->Port = Port;
2538 info->reply = mDNSNULL;
2539 info->replylen = 0;
2540 info->nread = 0;
2541 info->numReplies = 0;
2542
2543 if (msg)
2544 {
2545 info->requestLen = (int) (end - ((mDNSu8*)msg));
2546 mDNSPlatformMemCopy(&info->request, msg, info->requestLen);
2547 }
2548
2549 if (!info->sock) { LogMsg("SendServiceRegistration: unable to create TCP socket"); mDNSPlatformMemFree(info); return(mDNSNULL); }
2550 err = mDNSPlatformTCPConnect(info->sock, Addr, Port, 0, tcpCallback, info);
2551
2552 // Probably suboptimal here.
2553 // Instead of returning mDNSNULL here on failure, we should probably invoke the callback with an error code.
2554 // That way clients can put all the error handling and retry/recovery code in one place,
2555 // instead of having to handle immediate errors in one place and async errors in another.
2556 // Also: "err == mStatus_ConnEstablished" probably never happens.
2557
2558 // Don't need to log "connection failed" in customer builds -- it happens quite often during sleep, wake, configuration changes, etc.
2559 if (err == mStatus_ConnEstablished) { tcpCallback(info->sock, info, mDNStrue, mStatus_NoError); }
2560 else if (err != mStatus_ConnPending ) { LogInfo("MakeTCPConnection: connection failed"); DisposeTCPConn(info); return(mDNSNULL); }
2561 return(info);
2562 }
2563
2564 mDNSexport void DisposeTCPConn(struct tcpInfo_t *tcp)
2565 {
2566 mDNSPlatformTCPCloseConnection(tcp->sock);
2567 if (tcp->reply) mDNSPlatformMemFree(tcp->reply);
2568 mDNSPlatformMemFree(tcp);
2569 }
2570
2571 // Lock must be held
2572 mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q)
2573 {
2574 if (mDNSIPv4AddressIsOnes(m->LLQNAT.ExternalAddress))
2575 {
2576 LogInfo("startLLQHandshake: waiting for NAT status for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
2577 q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10); // Retry in approx 15 minutes
2578 q->LastQTime = m->timenow;
2579 SetNextQueryTime(m, q);
2580 return;
2581 }
2582
2583 if (mDNSIPPortIsZero(m->LLQNAT.ExternalPort))
2584 {
2585 LogInfo("startLLQHandshake: Cannot receive inbound packets; will poll for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
2586 StartLLQPolling(m, q);
2587 return;
2588 }
2589
2590 if (mDNSIPPortIsZero(q->servPort))
2591 {
2592 debugf("startLLQHandshake: StartGetZoneData for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
2593 q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10); // Retry in approx 15 minutes
2594 q->LastQTime = m->timenow;
2595 SetNextQueryTime(m, q);
2596 q->servAddr = zeroAddr;
2597 // We know q->servPort is zero because of check above
2598 if (q->nta) CancelGetZoneData(m, q->nta);
2599 q->nta = StartGetZoneData(m, &q->qname, ZoneServiceLLQ, LLQGotZoneData, q);
2600 return;
2601 }
2602
2603 if (q->AuthInfo)
2604 {
2605 if (q->tcp) LogInfo("startLLQHandshake: Disposing existing TCP connection for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
2606 if (q->tcp) DisposeTCPConn(q->tcp);
2607 q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, q, mDNSNULL, mDNSNULL);
2608 if (!q->tcp)
2609 q->ThisQInterval = mDNSPlatformOneSecond * 5; // If TCP failed (transient networking glitch) try again in five seconds
2610 else
2611 {
2612 q->state = LLQ_SecondaryRequest; // Right now, for private DNS, we skip the four-way LLQ handshake
2613 q->ReqLease = kLLQ_DefLease;
2614 q->ThisQInterval = 0;
2615 }
2616 q->LastQTime = m->timenow;
2617 SetNextQueryTime(m, q);
2618 }
2619 else
2620 {
2621 debugf("startLLQHandshake: m->AdvertisedV4 %#a%s Server %#a:%d%s %##s (%s)",
2622 &m->AdvertisedV4, mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) ? " (RFC 1918)" : "",
2623 &q->servAddr, mDNSVal16(q->servPort), mDNSAddrIsRFC1918(&q->servAddr) ? " (RFC 1918)" : "",
2624 q->qname.c, DNSTypeName(q->qtype));
2625
2626 if (q->ntries++ >= kLLQ_MAX_TRIES)
2627 {
2628 LogMsg("startLLQHandshake: %d failed attempts for LLQ %##s Polling.", kLLQ_MAX_TRIES, q->qname.c);
2629 StartLLQPolling(m, q);
2630 }
2631 else
2632 {
2633 mDNSu8 *end;
2634 LLQOptData llqData;
2635
2636 // set llq rdata
2637 llqData.vers = kLLQ_Vers;
2638 llqData.llqOp = kLLQOp_Setup;
2639 llqData.err = LLQErr_NoError; // Don't need to tell server UDP notification port when sending over UDP
2640 llqData.id = zeroOpaque64;
2641 llqData.llqlease = kLLQ_DefLease;
2642
2643 InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
2644 end = putLLQ(&m->omsg, m->omsg.data, q, &llqData);
2645 if (!end) { LogMsg("ERROR: startLLQHandshake - putLLQ"); StartLLQPolling(m,q); return; }
2646
2647 mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, mDNSNULL, mDNSNULL);
2648
2649 // update question state
2650 q->state = LLQ_InitialRequest;
2651 q->ReqLease = kLLQ_DefLease;
2652 q->ThisQInterval = (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
2653 q->LastQTime = m->timenow;
2654 SetNextQueryTime(m, q);
2655 }
2656 }
2657 }
2658
2659 // forward declaration so GetServiceTarget can do reverse lookup if needed
2660 mDNSlocal void GetStaticHostname(mDNS *m);
2661
2662 mDNSexport const domainname *GetServiceTarget(mDNS *m, AuthRecord *const rr)
2663 {
2664 debugf("GetServiceTarget %##s", rr->resrec.name->c);
2665
2666 if (!rr->AutoTarget) // If not automatically tracking this host's current name, just return the existing target
2667 return(&rr->resrec.rdata->u.srv.target);
2668 else
2669 {
2670 #if APPLE_OSX_mDNSResponder
2671 DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name);
2672 if (AuthInfo && AuthInfo->AutoTunnel)
2673 {
2674 // If this AutoTunnel is not yet active, start it now (which entails activating its NAT Traversal request,
2675 // which will subsequently advertise the appropriate records when the NAT Traversal returns a result)
2676 if (!AuthInfo->AutoTunnelNAT.clientContext && m->AutoTunnelHostAddr.b[0])
2677 SetupLocalAutoTunnelInterface_internal(m);
2678 if (AuthInfo->AutoTunnelHostRecord.namestorage.c[0] == 0) return(mDNSNULL);
2679 return(&AuthInfo->AutoTunnelHostRecord.namestorage);
2680 }
2681 else
2682 #endif // APPLE_OSX_mDNSResponder
2683 {
2684 const int srvcount = CountLabels(rr->resrec.name);
2685 HostnameInfo *besthi = mDNSNULL, *hi;
2686 int best = 0;
2687 for (hi = m->Hostnames; hi; hi = hi->next)
2688 if (hi->arv4.state == regState_Registered || hi->arv4.state == regState_Refresh ||
2689 hi->arv6.state == regState_Registered || hi->arv6.state == regState_Refresh)
2690 {
2691 int x, hostcount = CountLabels(&hi->fqdn);
2692 for (x = hostcount < srvcount ? hostcount : srvcount; x > 0 && x > best; x--)
2693 if (SameDomainName(SkipLeadingLabels(rr->resrec.name, srvcount - x), SkipLeadingLabels(&hi->fqdn, hostcount - x)))
2694 { best = x; besthi = hi; }
2695 }
2696
2697 if (besthi) return(&besthi->fqdn);
2698 }
2699 if (m->StaticHostname.c[0]) return(&m->StaticHostname);
2700 else GetStaticHostname(m); // asynchronously do reverse lookup for primary IPv4 address
2701 return(mDNSNULL);
2702 }
2703 }
2704
2705 // Called with lock held
2706 mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs)
2707 {
2708 mDNSu8 *ptr = m->omsg.data;
2709 mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
2710 mDNSOpaque16 id;
2711 mStatus err = mStatus_NoError;
2712 const domainname *target;
2713 mDNSu32 i;
2714
2715 if (m->mDNS_busy != m->mDNS_reentrancy+1)
2716 LogMsg("SendServiceRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
2717
2718 if (mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4)) // Don't know our UpdateServer yet
2719 {
2720 srs->RR_SRV.LastAPTime = m->timenow;
2721 if (srs->RR_SRV.ThisAPInterval < mDNSPlatformOneSecond * 5)
2722 srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5;
2723 return;
2724 }
2725
2726 if (srs->state == regState_Registered) srs->state = regState_Refresh;
2727
2728 id = mDNS_NewMessageID(m);
2729 InitializeDNSMessage(&m->omsg.h, id, UpdateReqFlags);
2730
2731 // setup resource records
2732 SetNewRData(&srs->RR_PTR.resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash
2733 SetNewRData(&srs->RR_TXT.resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash
2734
2735 // replace port w/ NAT mapping if necessary
2736 if (srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP && !mDNSIPPortIsZero(srs->NATinfo.ExternalPort))
2737 srs->RR_SRV.resrec.rdata->u.srv.port = srs->NATinfo.ExternalPort;
2738
2739 // construct update packet
2740 // set zone
2741 ptr = putZone(&m->omsg, ptr, end, &srs->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
2742 if (!ptr) { err = mStatus_UnknownErr; goto exit; }
2743
2744 if (srs->TestForSelfConflict)
2745 {
2746 // update w/ prereq that SRV already exist to make sure previous registration was ours, and delete any stale TXT records
2747 if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numPrereqs, &srs->RR_SRV.resrec, 0))) { err = mStatus_UnknownErr; goto exit; }
2748 if (!(ptr = putDeleteRRSet(&m->omsg, ptr, srs->RR_TXT.resrec.name, srs->RR_TXT.resrec.rrtype))) { err = mStatus_UnknownErr; goto exit; }
2749 }
2750
2751 else if (srs->state != regState_Refresh && srs->state != regState_UpdatePending)
2752 {
2753 // use SRV name for prereq
2754 //ptr = putPrereqNameNotInUse(srs->RR_SRV.resrec.name, &m->omsg, ptr, end);
2755
2756 // For now, until we implement RFC 4701 (DHCID RR) to detect whether an existing record is someone else using the name, or just a
2757 // stale echo of our own previous registration before we changed our host name, we just overwrite whatever may have already been there
2758 ptr = putDeleteRRSet(&m->omsg, ptr, srs->RR_SRV.resrec.name, kDNSQType_ANY);
2759 if (!ptr) { err = mStatus_UnknownErr; goto exit; }
2760 }
2761
2762 //!!!KRS Need to do bounds checking and use TCP if it won't fit!!!
2763 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; }
2764
2765 for (i = 0; i < srs->NumSubTypes; i++)
2766 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; }
2767
2768 if (srs->state == regState_UpdatePending) // we're updating the txt record
2769 {
2770 AuthRecord *txt = &srs->RR_TXT;
2771 // delete old RData
2772 SetNewRData(&txt->resrec, txt->OrigRData, txt->OrigRDLen);
2773 if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->RR_TXT.resrec))) { err = mStatus_UnknownErr; goto exit; } // delete old rdata
2774
2775 // add new RData
2776 SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen);
2777 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; }
2778 }
2779 else
2780 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; }
2781
2782 target = GetServiceTarget(m, &srs->RR_SRV);
2783 if (!target || target->c[0] == 0)
2784 {
2785 debugf("SendServiceRegistration - no target for %##s", srs->RR_SRV.resrec.name->c);
2786 srs->state = regState_NoTarget;
2787 return;
2788 }
2789
2790 if (!SameDomainName(target, &srs->RR_SRV.resrec.rdata->u.srv.target))
2791 {
2792 AssignDomainName(&srs->RR_SRV.resrec.rdata->u.srv.target, target);
2793 SetNewRData(&srs->RR_SRV.resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash
2794 }
2795
2796 ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_SRV.resrec, srs->RR_SRV.resrec.rroriginalttl);
2797 if (!ptr) { err = mStatus_UnknownErr; goto exit; }
2798
2799 if (srs->srs_uselease)
2800 { ptr = putUpdateLease(&m->omsg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) { err = mStatus_UnknownErr; goto exit; } }
2801
2802 if (srs->state != regState_Refresh && srs->state != regState_DeregDeferred && srs->state != regState_UpdatePending)
2803 srs->state = regState_Pending;
2804
2805 srs->id = id;
2806
2807 if (srs->Private)
2808 {
2809 if (srs->tcp) LogInfo("SendServiceRegistration: Disposing existing TCP connection for %s", ARDisplayString(m, &srs->RR_SRV));
2810 if (srs->tcp) DisposeTCPConn(srs->tcp);
2811 srs->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, srs, mDNSNULL);
2812 if (!srs->tcp) srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2)
2813 else if (srs->RR_SRV.ThisAPInterval < mDNSPlatformOneSecond * 30) srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 30;
2814 }
2815 else
2816 {
2817 err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name));
2818 if (err) debugf("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %d", err);
2819 }
2820
2821 SetRecordRetry(m, &srs->RR_SRV, err);
2822 return;
2823
2824 exit:
2825 if (err)
2826 {
2827 LogMsg("SendServiceRegistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err, srs->RR_SRV.resrec.name->c);
2828 unlinkSRS(m, srs);
2829 srs->state = regState_Unregistered;
2830
2831 mDNS_DropLockBeforeCallback();
2832 srs->ServiceCallback(m, srs, err);
2833 mDNS_ReclaimLockAfterCallback();
2834 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
2835 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
2836 }
2837 }
2838
2839 mDNSlocal const domainname *PUBLIC_UPDATE_SERVICE_TYPE = (const domainname*)"\x0B_dns-update" "\x04_udp";
2840 mDNSlocal const domainname *PUBLIC_LLQ_SERVICE_TYPE = (const domainname*)"\x08_dns-llq" "\x04_udp";
2841
2842 mDNSlocal const domainname *PRIVATE_UPDATE_SERVICE_TYPE = (const domainname*)"\x0F_dns-update-tls" "\x04_tcp";
2843 mDNSlocal const domainname *PRIVATE_QUERY_SERVICE_TYPE = (const domainname*)"\x0E_dns-query-tls" "\x04_tcp";
2844 mDNSlocal const domainname *PRIVATE_LLQ_SERVICE_TYPE = (const domainname*)"\x0C_dns-llq-tls" "\x04_tcp";
2845
2846 #define ZoneDataSRV(X) (\
2847 (X)->ZoneService == ZoneServiceUpdate ? ((X)->ZonePrivate ? PRIVATE_UPDATE_SERVICE_TYPE : PUBLIC_UPDATE_SERVICE_TYPE) : \
2848 (X)->ZoneService == ZoneServiceQuery ? ((X)->ZonePrivate ? PRIVATE_QUERY_SERVICE_TYPE : (const domainname*)"" ) : \
2849 (X)->ZoneService == ZoneServiceLLQ ? ((X)->ZonePrivate ? PRIVATE_LLQ_SERVICE_TYPE : PUBLIC_LLQ_SERVICE_TYPE ) : (const domainname*)"")
2850
2851 // Forward reference: GetZoneData_StartQuery references GetZoneData_QuestionCallback, and
2852 // GetZoneData_QuestionCallback calls GetZoneData_StartQuery
2853 mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qtype);
2854
2855 // GetZoneData_QuestionCallback is called from normal client callback context (core API calls allowed)
2856 mDNSlocal void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
2857 {
2858 ZoneData *zd = (ZoneData*)question->QuestionContext;
2859
2860 debugf("GetZoneData_QuestionCallback: %s %s", AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
2861
2862 if (!AddRecord) return; // Don't care about REMOVE events
2863 if (AddRecord == QC_addnocache && answer->rdlength == 0) return; // Don't care about transient failure indications
2864 if (answer->rrtype != question->qtype) return; // Don't care about CNAMEs
2865
2866 if (answer->rrtype == kDNSType_SOA)
2867 {
2868 debugf("GetZoneData GOT SOA %s", RRDisplayString(m, answer));
2869 mDNS_StopQuery(m, question);
2870 if (answer->rdlength)
2871 {
2872 AssignDomainName(&zd->ZoneName, answer->name);
2873 zd->ZoneClass = answer->rrclass;
2874 AssignDomainName(&zd->question.qname, &zd->ZoneName);
2875 GetZoneData_StartQuery(m, zd, kDNSType_SRV);
2876 }
2877 else if (zd->CurrentSOA->c[0])
2878 {
2879 zd->CurrentSOA = (domainname *)(zd->CurrentSOA->c + zd->CurrentSOA->c[0]+1);
2880 AssignDomainName(&zd->question.qname, zd->CurrentSOA);
2881 GetZoneData_StartQuery(m, zd, kDNSType_SOA);
2882 }
2883 else
2884 {
2885 LogInfo("GetZoneData recursed to root label of %##s without finding SOA", zd->ChildName.c);
2886 zd->ZoneDataCallback(m, mStatus_NoSuchNameErr, zd);
2887 mDNSPlatformMemFree(zd);
2888 }
2889 }
2890 else if (answer->rrtype == kDNSType_SRV)
2891 {
2892 debugf("GetZoneData GOT SRV %s", RRDisplayString(m, answer));
2893 mDNS_StopQuery(m, question);
2894 // Right now we don't want to fail back to non-encrypted operations
2895 // If the AuthInfo has the AutoTunnel field set, then we want private or nothing
2896 // <rdar://problem/5687667> BTMM: Don't fallback to unencrypted operations when SRV lookup fails
2897 #if 0
2898 if (!answer->rdlength && zd->ZonePrivate && zd->ZoneService != ZoneServiceQuery)
2899 {
2900 zd->ZonePrivate = mDNSfalse; // Causes ZoneDataSRV() to yield a different SRV name when building the query
2901 GetZoneData_StartQuery(m, zd, kDNSType_SRV); // Try again, non-private this time
2902 }
2903 else
2904 #endif
2905 {
2906 if (answer->rdlength)
2907 {
2908 AssignDomainName(&zd->Host, &answer->rdata->u.srv.target);
2909 zd->Port = answer->rdata->u.srv.port;
2910 AssignDomainName(&zd->question.qname, &zd->Host);
2911 GetZoneData_StartQuery(m, zd, kDNSType_A);
2912 }
2913 else
2914 {
2915 zd->ZonePrivate = mDNSfalse;
2916 zd->Host.c[0] = 0;
2917 zd->Port = zeroIPPort;
2918 zd->Addr = zeroAddr;
2919 zd->ZoneDataCallback(m, mStatus_NoError, zd);
2920 mDNSPlatformMemFree(zd);
2921 }
2922 }
2923 }
2924 else if (answer->rrtype == kDNSType_A)
2925 {
2926 debugf("GetZoneData GOT A %s", RRDisplayString(m, answer));
2927 mDNS_StopQuery(m, question);
2928 zd->Addr.type = mDNSAddrType_IPv4;
2929 zd->Addr.ip.v4 = (answer->rdlength == 4) ? answer->rdata->u.ipv4 : zerov4Addr;
2930 // In order to simulate firewalls blocking our outgoing TCP connections, returning immediate ICMP errors or TCP resets,
2931 // the code below will make us try to connect to loopback, resulting in an immediate "port unreachable" failure.
2932 // This helps us test to make sure we handle this case gracefully
2933 // <rdar://problem/5607082> BTMM: mDNSResponder taking 100 percent CPU after upgrading to 10.5.1
2934 #if 0
2935 zd->Addr.ip.v4.b[0] = 127;
2936 zd->Addr.ip.v4.b[1] = 0;
2937 zd->Addr.ip.v4.b[2] = 0;
2938 zd->Addr.ip.v4.b[3] = 1;
2939 #endif
2940 zd->ZoneDataCallback(m, mStatus_NoError, zd);
2941 mDNSPlatformMemFree(zd);
2942 }
2943 }
2944
2945 // GetZoneData_StartQuery is called from normal client context (lock not held, or client callback)
2946 mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qtype)
2947 {
2948 if (qtype == kDNSType_SRV)
2949 {
2950 AssignDomainName(&zd->question.qname, ZoneDataSRV(zd));
2951 AppendDomainName(&zd->question.qname, &zd->ZoneName);
2952 debugf("lookupDNSPort %##s", zd->question.qname.c);
2953 }
2954
2955 zd->question.ThisQInterval = -1; // So that GetZoneData_QuestionCallback() knows whether to cancel this question (Is this necessary?)
2956 zd->question.InterfaceID = mDNSInterface_Any;
2957 zd->question.Target = zeroAddr;
2958 //zd->question.qname.c[0] = 0; // Already set
2959 zd->question.qtype = qtype;
2960 zd->question.qclass = kDNSClass_IN;
2961 zd->question.LongLived = mDNSfalse;
2962 zd->question.ExpectUnique = mDNStrue;
2963 zd->question.ForceMCast = mDNSfalse;
2964 zd->question.ReturnIntermed = mDNStrue;
2965 zd->question.QuestionCallback = GetZoneData_QuestionCallback;
2966 zd->question.QuestionContext = zd;
2967
2968 //LogMsg("GetZoneData_StartQuery %##s (%s) %p", zd->question.qname.c, DNSTypeName(zd->question.qtype), zd->question.Private);
2969 return(mDNS_StartQuery(m, &zd->question));
2970 }
2971
2972 // StartGetZoneData is an internal routine (i.e. must be called with the lock already held)
2973 mDNSexport ZoneData *StartGetZoneData(mDNS *const m, const domainname *const name, const ZoneService target, ZoneDataCallback callback, void *ZoneDataContext)
2974 {
2975 DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, name);
2976 int initialskip = (AuthInfo && AuthInfo->AutoTunnel) ? DomainNameLength(name) - DomainNameLength(&AuthInfo->domain) : 0;
2977 ZoneData *zd = (ZoneData*)mDNSPlatformMemAllocate(sizeof(ZoneData));
2978 if (!zd) { LogMsg("ERROR: StartGetZoneData - mDNSPlatformMemAllocate failed"); return mDNSNULL; }
2979 mDNSPlatformMemZero(zd, sizeof(ZoneData));
2980 AssignDomainName(&zd->ChildName, name);
2981 zd->ZoneService = target;
2982 zd->CurrentSOA = (domainname *)(&zd->ChildName.c[initialskip]);
2983 zd->ZoneName.c[0] = 0;
2984 zd->ZoneClass = 0;
2985 zd->Host.c[0] = 0;
2986 zd->Port = zeroIPPort;
2987 zd->Addr = zeroAddr;
2988 zd->ZonePrivate = AuthInfo && AuthInfo->AutoTunnel ? mDNStrue : mDNSfalse;
2989 zd->ZoneDataCallback = callback;
2990 zd->ZoneDataContext = ZoneDataContext;
2991
2992 zd->question.QuestionContext = zd;
2993 AssignDomainName(&zd->question.qname, zd->CurrentSOA);
2994
2995 mDNS_DropLockBeforeCallback(); // GetZoneData_StartQuery expects to be called from a normal callback, so we emulate that here
2996 GetZoneData_StartQuery(m, zd, kDNSType_SOA);
2997 mDNS_ReclaimLockAfterCallback();
2998
2999 return zd;
3000 }
3001
3002 // GetZoneData queries are a special case -- even if we have a key for them, we don't do them privately,
3003 // because that would result in an infinite loop (i.e. to do a private query we first need to get
3004 // the _dns-query-tls SRV record for the zone, and we can't do *that* privately because to do so
3005 // we'd need to already know the _dns-query-tls SRV record.
3006 // Also, as a general rule, we never do SOA queries privately
3007 mDNSexport DomainAuthInfo *GetAuthInfoForQuestion(mDNS *m, const DNSQuestion *const q) // Must be called with lock held
3008 {
3009 if (q->QuestionCallback == GetZoneData_QuestionCallback) return(mDNSNULL);
3010 if (q->qtype == kDNSType_SOA ) return(mDNSNULL);
3011 return(GetAuthInfoForName_internal(m, &q->qname));
3012 }
3013
3014 // ***************************************************************************
3015 #if COMPILER_LIKES_PRAGMA_MARK
3016 #pragma mark - host name and interface management
3017 #endif
3018
3019 // Called in normal client context (lock not held)
3020 mDNSlocal void CompleteSRVNatMap(mDNS *m, NATTraversalInfo *n)
3021 {
3022 ServiceRecordSet *srs = (ServiceRecordSet *)n->clientContext;
3023 debugf("SRVNatMap complete %.4a IntPort %u ExternalPort %u NATLease %u", &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), n->NATLease);
3024
3025 if (!srs) { LogMsg("CompleteSRVNatMap called with unknown ServiceRecordSet object"); return; }
3026 if (!n->NATLease) return;
3027
3028 mDNS_Lock(m);
3029 if (!mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4))
3030 SendServiceRegistration(m, srs); // non-zero server address means we already have necessary zone data to send update
3031 else
3032 {
3033 // SHOULD NEVER HAPPEN!
3034 LogInfo("ERROR: CompleteSRVNatMap called but srs->SRSUpdateServer.ip.v4 is zero!");
3035 srs->state = regState_FetchingZoneData;
3036 if (srs->srs_nta) CancelGetZoneData(m, srs->srs_nta); // Make sure we cancel old one before we start a new one
3037 srs->srs_nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs);
3038 }
3039 mDNS_Unlock(m);
3040 }
3041
3042 mDNSlocal void StartSRVNatMap(mDNS *m, ServiceRecordSet *srs)
3043 {
3044 const mDNSu8 *p = srs->RR_PTR.resrec.name->c;
3045 if (p[0]) p += 1 + p[0];
3046 if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp")) srs->NATinfo.Protocol = NATOp_MapTCP;
3047 else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) srs->NATinfo.Protocol = NATOp_MapUDP;
3048 else { LogMsg("StartSRVNatMap: could not determine transport protocol of service %##s", srs->RR_SRV.resrec.name->c); return; }
3049
3050 if (srs->NATinfo.clientContext) mDNS_StopNATOperation_internal(m, &srs->NATinfo);
3051 // Don't try to set IntPort here --
3052 // SendServiceRegistration overwrites srs->RR_SRV.resrec.rdata->u.srv.port with external (mapped) port number
3053 //srs->NATinfo.IntPort = srs->RR_SRV.resrec.rdata->u.srv.port;
3054 srs->NATinfo.RequestedPort = srs->RR_SRV.resrec.rdata->u.srv.port;
3055 srs->NATinfo.NATLease = 0; // Request default lease
3056 srs->NATinfo.clientCallback = CompleteSRVNatMap;
3057 srs->NATinfo.clientContext = srs;
3058 mDNS_StartNATOperation_internal(m, &srs->NATinfo);
3059 }
3060
3061 // Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
3062 mDNSexport void ServiceRegistrationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneData)
3063 {
3064 ServiceRecordSet *srs = (ServiceRecordSet *)zoneData->ZoneDataContext;
3065
3066 if (m->mDNS_busy != m->mDNS_reentrancy)
3067 LogMsg("ServiceRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
3068
3069 if (!srs->RR_SRV.resrec.rdata)
3070 { LogMsg("ServiceRegistrationGotZoneData: ERROR: srs->RR_SRV.resrec.rdata is NULL"); return; }
3071
3072 srs->srs_nta = mDNSNULL;
3073
3074 // Start off assuming we're going to use a lease
3075 // 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
3076 srs->srs_uselease = mDNStrue;
3077
3078 if (err || !zoneData) return;
3079
3080 if (mDNSIPPortIsZero(zoneData->Port) || mDNSAddressIsZero(&zoneData->Addr)) return;
3081
3082 // cache zone data
3083 AssignDomainName(&srs->zone, &zoneData->ZoneName);
3084 srs->SRSUpdateServer.type = mDNSAddrType_IPv4;
3085 srs->SRSUpdateServer = zoneData->Addr;
3086 srs->SRSUpdatePort = zoneData->Port;
3087 srs->Private = zoneData->ZonePrivate;
3088
3089 srs->RR_SRV.LastAPTime = m->timenow;
3090 srs->RR_SRV.ThisAPInterval = 0;
3091
3092 debugf("ServiceRegistrationGotZoneData My IPv4 %#a%s Server %#a:%d%s for %##s",
3093 &m->AdvertisedV4, mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) ? " (RFC1918)" : "",
3094 &srs->SRSUpdateServer, mDNSVal16(srs->SRSUpdatePort), mDNSAddrIsRFC1918(&srs->SRSUpdateServer) ? " (RFC1918)" : "",
3095 srs->RR_SRV.resrec.name->c);
3096
3097 // If we have non-zero service port (always?)
3098 // and a private address, and update server is non-private
3099 // and this service is AutoTarget
3100 // then initiate a NAT mapping request. On completion it will do SendServiceRegistration() for us
3101 if (!mDNSIPPortIsZero(srs->RR_SRV.resrec.rdata->u.srv.port) &&
3102 mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&srs->SRSUpdateServer) &&
3103 srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP)
3104 {
3105 srs->state = regState_NATMap;
3106 debugf("ServiceRegistrationGotZoneData StartSRVNatMap");
3107 StartSRVNatMap(m, srs);
3108 }
3109 else
3110 {
3111 mDNS_Lock(m);
3112 SendServiceRegistration(m, srs);
3113 mDNS_Unlock(m);
3114 }
3115 }
3116
3117 mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
3118 {
3119 mDNSOpaque16 id;
3120 mDNSu8 *ptr = m->omsg.data;
3121 mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
3122 mStatus err = mStatus_UnknownErr;
3123 mDNSu32 i;
3124
3125 if (mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4)) // Don't know our UpdateServer yet
3126 {
3127 srs->RR_SRV.LastAPTime = m->timenow;
3128 if (srs->RR_SRV.ThisAPInterval < mDNSPlatformOneSecond * 5)
3129 srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5;
3130 return;
3131 }
3132
3133 id = mDNS_NewMessageID(m);
3134 InitializeDNSMessage(&m->omsg.h, id, UpdateReqFlags);
3135
3136 // put zone
3137 ptr = putZone(&m->omsg, ptr, end, &srs->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
3138 if (!ptr) { LogMsg("ERROR: SendServiceDeregistration - putZone"); err = mStatus_UnknownErr; goto exit; }
3139
3140 if (!(ptr = putDeleteAllRRSets(&m->omsg, ptr, srs->RR_SRV.resrec.name))) { err = mStatus_UnknownErr; goto exit; } // this deletes SRV, TXT, and Extras
3141 if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->RR_PTR.resrec))) { err = mStatus_UnknownErr; goto exit; }
3142 for (i = 0; i < srs->NumSubTypes; i++)
3143 if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->SubTypes[i].resrec))) { err = mStatus_UnknownErr; goto exit; }
3144
3145 srs->id = id;
3146 srs->state = regState_DeregPending;
3147 srs->RR_SRV.expire = 0; // Indicate that we have no active registration any more
3148
3149 if (srs->Private)
3150 {
3151 LogInfo("SendServiceDeregistration TCP %p %s", srs->tcp, ARDisplayString(m, &srs->RR_SRV));
3152 if (srs->tcp) LogInfo("SendServiceDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m, &srs->RR_SRV));
3153 if (srs->tcp) DisposeTCPConn(srs->tcp);
3154 srs->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, srs, mDNSNULL);
3155 if (!srs->tcp) srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2)
3156 else if (srs->RR_SRV.ThisAPInterval < mDNSPlatformOneSecond * 30) srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 30;
3157 }
3158 else
3159 {
3160 err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name));
3161 if (err && err != mStatus_TransientErr) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %d", err); goto exit; }
3162 }
3163
3164 SetRecordRetry(m, &srs->RR_SRV, err);
3165 return;
3166
3167 exit:
3168 if (err)
3169 {
3170 LogMsg("SendServiceDeregistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err, srs->RR_SRV.resrec.name->c);
3171 unlinkSRS(m, srs);
3172 srs->state = regState_Unregistered;
3173 }
3174 }
3175
3176 // Called with lock held
3177 mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs)
3178 {
3179 ExtraResourceRecord *e;
3180
3181 // Target change if:
3182 // We have a target and were previously waiting for one, or
3183 // We had a target and no longer do, or
3184 // The target has changed
3185
3186 domainname *curtarget = &srs->RR_SRV.resrec.rdata->u.srv.target;
3187 const domainname *const nt = GetServiceTarget(m, &srs->RR_SRV);
3188 const domainname *const newtarget = nt ? nt : (domainname*)"";
3189 mDNSBool TargetChanged = (newtarget->c[0] && srs->state == regState_NoTarget) || !SameDomainName(curtarget, newtarget);
3190 mDNSBool HaveZoneData = !mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4);
3191
3192 // Nat state change if:
3193 // We were behind a NAT, and now we are behind a new NAT, or
3194 // We're not behind a NAT but our port was previously mapped to a different external port
3195 // We were not behind a NAT and now we are
3196
3197 mDNSIPPort port = srs->RR_SRV.resrec.rdata->u.srv.port;
3198 mDNSBool NowNeedNATMAP = (srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP && !mDNSIPPortIsZero(port) && mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&srs->SRSUpdateServer));
3199 mDNSBool WereBehindNAT = (srs->NATinfo.clientContext != mDNSNULL);
3200 mDNSBool PortWasMapped = (srs->NATinfo.clientContext && !mDNSSameIPPort(srs->NATinfo.RequestedPort, port)); // I think this is always false -- SC Sept 07
3201 mDNSBool NATChanged = (!WereBehindNAT && NowNeedNATMAP) || (!NowNeedNATMAP && PortWasMapped);
3202
3203 debugf("UpdateSRV %##s newtarget %##s TargetChanged %d HaveZoneData %d port %d NowNeedNATMAP %d WereBehindNAT %d PortWasMapped %d NATChanged %d",
3204 srs->RR_SRV.resrec.name->c, newtarget,
3205 TargetChanged, HaveZoneData, mDNSVal16(port), NowNeedNATMAP, WereBehindNAT, PortWasMapped, NATChanged);
3206
3207 if (m->mDNS_busy != m->mDNS_reentrancy+1)
3208 LogMsg("UpdateSRV: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
3209
3210 if (!TargetChanged && !NATChanged) return;
3211
3212 switch(srs->state)
3213 {
3214 case regState_FetchingZoneData:
3215 case regState_DeregPending:
3216 case regState_DeregDeferred:
3217 case regState_Unregistered:
3218 case regState_NATMap:
3219 case regState_ExtraQueued:
3220 // In these states, the SRV has either not yet been registered (it will get up-to-date information when it is)
3221 // or is in the process of, or has already been, deregistered
3222 return;
3223
3224 case regState_Pending:
3225 case regState_Refresh:
3226 case regState_UpdatePending:
3227 // let the in-flight operation complete before updating
3228 srs->SRVUpdateDeferred = mDNStrue;
3229 return;
3230
3231 case regState_NATError:
3232 if (!NATChanged) return;
3233 // if nat changed, register if we have a target (below)
3234
3235 case regState_NoTarget:
3236 if (newtarget->c[0])
3237 {
3238 debugf("UpdateSRV: %s service %##s", HaveZoneData ? (NATChanged && NowNeedNATMAP ? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs->RR_SRV.resrec.name->c);
3239 if (!HaveZoneData)
3240 {
3241 srs->state = regState_FetchingZoneData;
3242 if (srs->srs_nta) CancelGetZoneData(m, srs->srs_nta); // Make sure we cancel old one before we start a new one
3243 srs->srs_nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs);
3244 }
3245 else
3246 {
3247 if (srs->NATinfo.clientContext && (NATChanged || !NowNeedNATMAP))
3248 {
3249 mDNS_StopNATOperation_internal(m, &srs->NATinfo);
3250 srs->NATinfo.clientContext = mDNSNULL;
3251 }
3252 if (NATChanged && NowNeedNATMAP && srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP)
3253 { srs->state = regState_NATMap; StartSRVNatMap(m, srs); }
3254 else SendServiceRegistration(m, srs);
3255 }
3256 }
3257 return;
3258
3259 case regState_Registered:
3260 // target or nat changed. deregister service. upon completion, we'll look for a new target
3261 debugf("UpdateSRV: SRV record changed for service %##s - deregistering (will re-register with new SRV)", srs->RR_SRV.resrec.name->c);
3262 for (e = srs->Extras; e; e = e->next) e->r.state = regState_ExtraQueued; // extra will be re-registed if the service is re-registered
3263 srs->SRVChanged = mDNStrue;
3264 SendServiceDeregistration(m, srs);
3265 return;
3266
3267 default: LogMsg("UpdateSRV: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c);
3268 }
3269 }
3270
3271 // Called with lock held
3272 mDNSlocal void UpdateSRVRecords(mDNS *m)
3273 {
3274 debugf("UpdateSRVRecords%s", m->SleepState ? " (ignored due to SleepState)" : "");
3275 if (m->SleepState) return;
3276
3277 if (CurrentServiceRecordSet)
3278 LogMsg("UpdateSRVRecords ERROR CurrentServiceRecordSet already set");
3279 CurrentServiceRecordSet = m->ServiceRegistrations;
3280
3281 while (CurrentServiceRecordSet)
3282 {
3283 ServiceRecordSet *s = CurrentServiceRecordSet;
3284 CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next;
3285 UpdateSRV(m, s);
3286 }
3287
3288 mDNS_DropLockBeforeCallback(); // mDNS_SetFQDN expects to be called without the lock held, so we emulate that here
3289 mDNS_SetFQDN(m);
3290 mDNS_ReclaimLockAfterCallback();
3291 }
3292
3293 // Forward reference: AdvertiseHostname references HostnameCallback, and HostnameCallback calls AdvertiseHostname
3294 mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
3295
3296 // Called in normal client context (lock not held)
3297 mDNSlocal void hostnameGetPublicAddressCallback(mDNS *m, NATTraversalInfo *n)
3298 {
3299 HostnameInfo *h = (HostnameInfo *)n->clientContext;
3300
3301 if (!h) { LogMsg("RegisterHostnameRecord: registration cancelled"); return; }
3302
3303 if (!n->Result)
3304 {
3305 if (mDNSIPv4AddressIsZero(n->ExternalAddress) || mDNSv4AddrIsRFC1918(&n->ExternalAddress)) return;
3306
3307 if (h->arv4.resrec.RecordType)
3308 {
3309 if (mDNSSameIPv4Address(h->arv4.resrec.rdata->u.ipv4, n->ExternalAddress)) return; // If address unchanged, do nothing
3310 LogInfo("Updating hostname %##s IPv4 from %.4a to %.4a (NAT gateway's external address)",
3311 h->arv4.resrec.name->c, &h->arv4.resrec.rdata->u.ipv4, &n->ExternalAddress);
3312 mDNS_Deregister(m, &h->arv4); // mStatus_MemFree callback will re-register with new address
3313 }
3314 else
3315 {
3316 LogInfo("Advertising hostname %##s IPv4 %.4a (NAT gateway's external address)", h->arv4.resrec.name->c, &n->ExternalAddress);
3317 h->arv4.resrec.RecordType = kDNSRecordTypeKnownUnique;
3318 h->arv4.resrec.rdata->u.ipv4 = n->ExternalAddress;
3319 mDNS_Register(m, &h->arv4);
3320 }
3321 }
3322 }
3323
3324 // register record or begin NAT traversal
3325 mDNSlocal void AdvertiseHostname(mDNS *m, HostnameInfo *h)
3326 {
3327 if (!mDNSIPv4AddressIsZero(m->AdvertisedV4.ip.v4) && h->arv4.resrec.RecordType == kDNSRecordTypeUnregistered)
3328 {
3329 mDNS_SetupResourceRecord(&h->arv4, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnregistered, HostnameCallback, h);
3330 AssignDomainName(&h->arv4.namestorage, &h->fqdn);
3331 h->arv4.resrec.rdata->u.ipv4 = m->AdvertisedV4.ip.v4;
3332 h->arv4.state = regState_Unregistered;
3333 if (mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4))
3334 {
3335 // If we already have a NAT query active, stop it and restart it to make sure we get another callback
3336 if (h->natinfo.clientContext) mDNS_StopNATOperation_internal(m, &h->natinfo);
3337 h->natinfo.Protocol = 0;
3338 h->natinfo.IntPort = zeroIPPort;
3339 h->natinfo.RequestedPort = zeroIPPort;
3340 h->natinfo.NATLease = 0;
3341 h->natinfo.clientCallback = hostnameGetPublicAddressCallback;
3342 h->natinfo.clientContext = h;
3343 mDNS_StartNATOperation_internal(m, &h->natinfo);
3344 }
3345 else
3346 {
3347 LogInfo("Advertising hostname %##s IPv4 %.4a", h->arv4.resrec.name->c, &m->AdvertisedV4.ip.v4);
3348 h->arv4.resrec.RecordType = kDNSRecordTypeKnownUnique;
3349 mDNS_Register_internal(m, &h->arv4);
3350 }
3351 }
3352
3353 if (!mDNSIPv6AddressIsZero(m->AdvertisedV6.ip.v6) && h->arv6.resrec.RecordType == kDNSRecordTypeUnregistered)
3354 {
3355 mDNS_SetupResourceRecord(&h->arv6, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL, kDNSRecordTypeKnownUnique, HostnameCallback, h);
3356 AssignDomainName(&h->arv6.namestorage, &h->fqdn);
3357 h->arv6.resrec.rdata->u.ipv6 = m->AdvertisedV6.ip.v6;
3358 h->arv6.state = regState_Unregistered;
3359 LogInfo("Advertising hostname %##s IPv6 %.16a", h->arv6.resrec.name->c, &m->AdvertisedV6.ip.v6);
3360 mDNS_Register_internal(m, &h->arv6);
3361 }
3362 }
3363
3364 mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
3365 {
3366 HostnameInfo *hi = (HostnameInfo *)rr->RecordContext;
3367
3368 if (result == mStatus_MemFree)
3369 {
3370 if (hi)
3371 {
3372 // If we're still in the Hostnames list, update to new address
3373 HostnameInfo *i;
3374 LogInfo("HostnameCallback: Got mStatus_MemFree for %p %p %s", hi, rr, ARDisplayString(m, rr));
3375 for (i = m->Hostnames; i; i = i->next)
3376 if (rr == &i->arv4 || rr == &i->arv6)
3377 { mDNS_Lock(m); AdvertiseHostname(m, i); mDNS_Unlock(m); return; }
3378
3379 // Else, we're not still in the Hostnames list, so free the memory
3380 if (hi->arv4.resrec.RecordType == kDNSRecordTypeUnregistered &&
3381 hi->arv6.resrec.RecordType == kDNSRecordTypeUnregistered)
3382 {
3383 if (hi->natinfo.clientContext) mDNS_StopNATOperation_internal(m, &hi->natinfo);
3384 hi->natinfo.clientContext = mDNSNULL;
3385 mDNSPlatformMemFree(hi); // free hi when both v4 and v6 AuthRecs deallocated
3386 }
3387 }
3388 return;
3389 }
3390
3391 if (result)
3392 {
3393 // don't unlink or free - we can retry when we get a new address/router
3394 if (rr->resrec.rrtype == kDNSType_A)
3395 LogMsg("HostnameCallback: Error %d for registration of %##s IP %.4a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv4);
3396 else
3397 LogMsg("HostnameCallback: Error %d for registration of %##s IP %.16a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
3398 if (!hi) { mDNSPlatformMemFree(rr); return; }
3399 if (rr->state != regState_Unregistered) LogMsg("Error: HostnameCallback invoked with error code for record not in regState_Unregistered!");
3400
3401 if (hi->arv4.state == regState_Unregistered &&
3402 hi->arv6.state == regState_Unregistered)
3403 {
3404 // only deliver status if both v4 and v6 fail
3405 rr->RecordContext = (void *)hi->StatusContext;
3406 if (hi->StatusCallback)
3407 hi->StatusCallback(m, rr, result); // client may NOT make API calls here
3408 rr->RecordContext = (void *)hi;
3409 }
3410 return;
3411 }
3412
3413 // register any pending services that require a target
3414 mDNS_Lock(m);
3415 UpdateSRVRecords(m);
3416 mDNS_Unlock(m);
3417
3418 // Deliver success to client
3419 if (!hi) { LogMsg("HostnameCallback invoked with orphaned address record"); return; }
3420 if (rr->resrec.rrtype == kDNSType_A)
3421 LogInfo("Registered hostname %##s IP %.4a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv4);
3422 else
3423 LogInfo("Registered hostname %##s IP %.16a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
3424
3425 rr->RecordContext = (void *)hi->StatusContext;
3426 if (hi->StatusCallback)
3427 hi->StatusCallback(m, rr, result); // client may NOT make API calls here
3428 rr->RecordContext = (void *)hi;
3429 }
3430
3431 mDNSlocal void FoundStaticHostname(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
3432 {
3433 const domainname *pktname = &answer->rdata->u.name;
3434 domainname *storedname = &m->StaticHostname;
3435 HostnameInfo *h = m->Hostnames;
3436
3437 (void)question;
3438
3439 debugf("FoundStaticHostname: %##s -> %##s (%s)", question->qname.c, answer->rdata->u.name.c, AddRecord ? "added" : "removed");
3440 if (AddRecord && !SameDomainName(pktname, storedname))
3441 {
3442 AssignDomainName(storedname, pktname);
3443 while (h)
3444 {
3445 if (h->arv4.state == regState_FetchingZoneData || h->arv4.state == regState_Pending || h->arv4.state == regState_NATMap ||
3446 h->arv6.state == regState_FetchingZoneData || h->arv6.state == regState_Pending)
3447 {
3448 // 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
3449 m->NextSRVUpdate = NonZeroTime(m->timenow + 5 * mDNSPlatformOneSecond);
3450 return;
3451 }
3452 h = h->next;
3453 }
3454 mDNS_Lock(m);
3455 UpdateSRVRecords(m);
3456 mDNS_Unlock(m);
3457 }
3458 else if (!AddRecord && SameDomainName(pktname, storedname))
3459 {
3460 mDNS_Lock(m);
3461 storedname->c[0] = 0;
3462 UpdateSRVRecords(m);
3463 mDNS_Unlock(m);
3464 }
3465 }
3466
3467 // Called with lock held
3468 mDNSlocal void GetStaticHostname(mDNS *m)
3469 {
3470 char buf[MAX_REVERSE_MAPPING_NAME_V4];
3471 DNSQuestion *q = &m->ReverseMap;
3472 mDNSu8 *ip = m->AdvertisedV4.ip.v4.b;
3473 mStatus err;
3474
3475 if (m->ReverseMap.ThisQInterval != -1) return; // already running
3476 if (mDNSIPv4AddressIsZero(m->AdvertisedV4.ip.v4)) return;
3477
3478 mDNSPlatformMemZero(q, sizeof(*q));
3479 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
3480 mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", ip[3], ip[2], ip[1], ip[0]);
3481 if (!MakeDomainNameFromDNSNameString(&q->qname, buf)) { LogMsg("Error: GetStaticHostname - bad name %s", buf); return; }
3482
3483 q->InterfaceID = mDNSInterface_Any;
3484 q->Target = zeroAddr;
3485 q->qtype = kDNSType_PTR;
3486 q->qclass = kDNSClass_IN;
3487 q->LongLived = mDNSfalse;
3488 q->ExpectUnique = mDNSfalse;
3489 q->ForceMCast = mDNSfalse;
3490 q->ReturnIntermed = mDNStrue;
3491 q->QuestionCallback = FoundStaticHostname;
3492 q->QuestionContext = mDNSNULL;
3493
3494 LogInfo("GetStaticHostname: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3495 err = mDNS_StartQuery_internal(m, q);
3496 if (err) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err);
3497 }
3498
3499 mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
3500 {
3501 HostnameInfo **ptr = &m->Hostnames;
3502
3503 LogInfo("mDNS_AddDynDNSHostName %##s", fqdn);
3504
3505 while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next;
3506 if (*ptr) { LogMsg("DynDNSHostName %##s already in list", fqdn->c); return; }
3507
3508 // allocate and format new address record
3509 *ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
3510 if (!*ptr) { LogMsg("ERROR: mDNS_AddDynDNSHostName - malloc"); return; }
3511
3512 mDNSPlatformMemZero(*ptr, sizeof(**ptr));
3513 AssignDomainName(&(*ptr)->fqdn, fqdn);
3514 (*ptr)->arv4.state = regState_Unregistered;
3515 (*ptr)->arv6.state = regState_Unregistered;
3516 (*ptr)->StatusCallback = StatusCallback;
3517 (*ptr)->StatusContext = StatusContext;
3518
3519 AdvertiseHostname(m, *ptr);
3520 }
3521
3522 mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn)
3523 {
3524 HostnameInfo **ptr = &m->Hostnames;
3525
3526 LogInfo("mDNS_RemoveDynDNSHostName %##s", fqdn);
3527
3528 while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next;
3529 if (!*ptr) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn->c);
3530 else
3531 {
3532 HostnameInfo *hi = *ptr;
3533 // We do it this way because, if we have no active v6 record, the "mDNS_Deregister_internal(m, &hi->arv4);"
3534 // below could free the memory, and we have to make sure we don't touch hi fields after that.
3535 mDNSBool f4 = hi->arv4.resrec.RecordType != kDNSRecordTypeUnregistered && hi->arv4.state != regState_Unregistered;
3536 mDNSBool f6 = hi->arv6.resrec.RecordType != kDNSRecordTypeUnregistered && hi->arv6.state != regState_Unregistered;
3537 if (f4) LogInfo("mDNS_RemoveDynDNSHostName removing v4 %##s", fqdn);
3538 if (f6) LogInfo("mDNS_RemoveDynDNSHostName removing v6 %##s", fqdn);
3539 *ptr = (*ptr)->next; // unlink
3540 if (f4) mDNS_Deregister_internal(m, &hi->arv4, mDNS_Dereg_normal);
3541 if (f6) mDNS_Deregister_internal(m, &hi->arv6, mDNS_Dereg_normal);
3542 // When both deregistrations complete we'll free the memory in the mStatus_MemFree callback
3543 }
3544 UpdateSRVRecords(m);
3545 }
3546
3547 // Currently called without holding the lock
3548 // Maybe we should change that?
3549 mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router)
3550 {
3551 mDNSBool v4Changed, v6Changed, RouterChanged;
3552
3553 if (m->mDNS_busy != m->mDNS_reentrancy)
3554 LogMsg("mDNS_SetPrimaryInterfaceInfo: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
3555
3556 if (v4addr && v4addr->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo v4 address - incorrect type. Discarding. %#a", v4addr); return; }
3557 if (v6addr && v6addr->type != mDNSAddrType_IPv6) { LogMsg("mDNS_SetPrimaryInterfaceInfo v6 address - incorrect type. Discarding. %#a", v6addr); return; }
3558 if (router && router->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-v4 router. Discarding. %#a", router); return; }
3559
3560 mDNS_Lock(m);
3561
3562 if (v4addr && !mDNSv4AddressIsLinkLocal(&v4addr->ip.v4)) v6addr = mDNSNULL;
3563
3564 v4Changed = !mDNSSameIPv4Address(m->AdvertisedV4.ip.v4, v4addr ? v4addr->ip.v4 : zerov4Addr);
3565 v6Changed = !mDNSSameIPv6Address(m->AdvertisedV6.ip.v6, v6addr ? v6addr->ip.v6 : zerov6Addr);
3566 RouterChanged = !mDNSSameIPv4Address(m->Router.ip.v4, router ? router->ip.v4 : zerov4Addr);
3567
3568 if (v4addr && (v4Changed || RouterChanged))
3569 debugf("mDNS_SetPrimaryInterfaceInfo: address changed from %#a to %#a", &m->AdvertisedV4, v4addr);
3570
3571 if (v4addr) m->AdvertisedV4 = *v4addr; else m->AdvertisedV4.ip.v4 = zerov4Addr;
3572 if (v6addr) m->AdvertisedV6 = *v6addr; else m->AdvertisedV6.ip.v6 = zerov6Addr;
3573 if (router) m->Router = *router; else m->Router .ip.v4 = zerov4Addr;
3574 // setting router to zero indicates that nat mappings must be reestablished when router is reset
3575
3576 if (v4Changed || RouterChanged || v6Changed)
3577 {
3578 HostnameInfo *i;
3579 LogInfo("mDNS_SetPrimaryInterfaceInfo: %s%s%s%#a %#a %#a",
3580 v4Changed ? "v4Changed " : "",
3581 RouterChanged ? "RouterChanged " : "",
3582 v6Changed ? "v6Changed " : "", v4addr, v6addr, router);
3583
3584 for (i = m->Hostnames; i; i = i->next)
3585 {
3586 LogInfo("mDNS_SetPrimaryInterfaceInfo updating host name registrations for %##s", i->fqdn.c);
3587
3588 if (i->arv4.resrec.RecordType > kDNSRecordTypeDeregistering &&
3589 !mDNSSameIPv4Address(i->arv4.resrec.rdata->u.ipv4, m->AdvertisedV4.ip.v4))
3590 {
3591 LogInfo("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m, &i->arv4));
3592 mDNS_Deregister_internal(m, &i->arv4, mDNS_Dereg_normal);
3593 }
3594
3595 if (i->arv6.resrec.RecordType > kDNSRecordTypeDeregistering &&
3596 !mDNSSameIPv6Address(i->arv6.resrec.rdata->u.ipv6, m->AdvertisedV6.ip.v6))
3597 {
3598 LogInfo("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m, &i->arv6));
3599 mDNS_Deregister_internal(m, &i->arv6, mDNS_Dereg_normal);
3600 }
3601
3602 // AdvertiseHostname will only register new address records.
3603 // For records still in the process of deregistering it will ignore them, and let the mStatus_MemFree callback handle them.
3604 AdvertiseHostname(m, i);
3605 }
3606
3607 if (v4Changed || RouterChanged)
3608 {
3609 // If we have a non-zero IPv4 address, we should try immediately to see if we have a NAT gateway
3610 // If we have no IPv4 address, we don't want to be in quite such a hurry to report failures to our clients
3611 // <rdar://problem/6935929> Sleeping server sometimes briefly disappears over Back to My Mac after it wakes up
3612 m->ExternalAddress = zerov4Addr;
3613 m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
3614 m->retryGetAddr = m->timenow + (v4addr ? 0 : mDNSPlatformOneSecond * 5);
3615 m->NextScheduledNATOp = m->timenow;
3616 m->LastNATMapResultCode = NATErr_None;
3617 #ifdef _LEGACY_NAT_TRAVERSAL_
3618 LNT_ClearState(m);
3619 #endif // _LEGACY_NAT_TRAVERSAL_
3620 LogInfo("mDNS_SetPrimaryInterfaceInfo:%s%s: retryGetAddr in %d %d",
3621 v4Changed ? " v4Changed" : "",
3622 RouterChanged ? " RouterChanged" : "",
3623 m->retryGetAddr - m->timenow, m->timenow);
3624 }
3625
3626 if (m->ReverseMap.ThisQInterval != -1) mDNS_StopQuery_internal(m, &m->ReverseMap);
3627 m->StaticHostname.c[0] = 0;
3628
3629 UpdateSRVRecords(m); // Will call GetStaticHostname if needed
3630
3631 #if APPLE_OSX_mDNSResponder
3632 if (RouterChanged) uuid_generate(m->asl_uuid);
3633 UpdateAutoTunnelDomainStatuses(m);
3634 #endif
3635 }
3636
3637 mDNS_Unlock(m);
3638 }
3639
3640 // ***************************************************************************
3641 #if COMPILER_LIKES_PRAGMA_MARK
3642 #pragma mark - Incoming Message Processing
3643 #endif
3644
3645 mDNSlocal mStatus ParseTSIGError(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const domainname *const displayname)
3646 {
3647 const mDNSu8 *ptr;
3648 mStatus err = mStatus_NoError;
3649 int i;
3650
3651 ptr = LocateAdditionals(msg, end);
3652 if (!ptr) goto finish;
3653
3654 for (i = 0; i < msg->h.numAdditionals; i++)
3655 {
3656 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
3657 if (!ptr) goto finish;
3658 if (m->rec.r.resrec.rrtype == kDNSType_TSIG)
3659 {
3660 mDNSu32 macsize;
3661 mDNSu8 *rd = m->rec.r.resrec.rdata->u.data;
3662 mDNSu8 *rdend = rd + m->rec.r.resrec.rdlength;
3663 int alglen = DomainNameLengthLimit(&m->rec.r.resrec.rdata->u.name, rdend);
3664 if (alglen > MAX_DOMAIN_NAME) goto finish;
3665 rd += alglen; // algorithm name
3666 if (rd + 6 > rdend) goto finish;
3667 rd += 6; // 48-bit timestamp
3668 if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
3669 rd += sizeof(mDNSOpaque16); // fudge
3670 if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
3671 macsize = mDNSVal16(*(mDNSOpaque16 *)rd);
3672 rd += sizeof(mDNSOpaque16); // MAC size
3673 if (rd + macsize > rdend) goto finish;
3674 rd += macsize;
3675 if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
3676 rd += sizeof(mDNSOpaque16); // orig id
3677 if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
3678 err = mDNSVal16(*(mDNSOpaque16 *)rd); // error code
3679
3680 if (err == TSIG_ErrBadSig) { LogMsg("%##s: bad signature", displayname->c); err = mStatus_BadSig; }
3681 else if (err == TSIG_ErrBadKey) { LogMsg("%##s: bad key", displayname->c); err = mStatus_BadKey; }
3682 else if (err == TSIG_ErrBadTime) { LogMsg("%##s: bad time", displayname->c); err = mStatus_BadTime; }
3683 else if (err) { LogMsg("%##s: unknown tsig error %d", displayname->c, err); err = mStatus_UnknownErr; }
3684 goto finish;
3685 }
3686 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
3687 }
3688
3689 finish:
3690 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
3691 return err;
3692 }
3693
3694 mDNSlocal mStatus checkUpdateResult(mDNS *const m, const domainname *const displayname, const mDNSu8 rcode, const DNSMessage *const msg, const mDNSu8 *const end)
3695 {
3696 (void)msg; // currently unused, needed for TSIG errors
3697 if (!rcode) return mStatus_NoError;
3698 else if (rcode == kDNSFlag1_RC_YXDomain)
3699 {
3700 debugf("name in use: %##s", displayname->c);
3701 return mStatus_NameConflict;
3702 }
3703 else if (rcode == kDNSFlag1_RC_Refused)
3704 {
3705 LogMsg("Update %##s refused", displayname->c);
3706 return mStatus_Refused;
3707 }
3708 else if (rcode == kDNSFlag1_RC_NXRRSet)
3709 {
3710 LogMsg("Reregister refused (NXRRSET): %##s", displayname->c);
3711 return mStatus_NoSuchRecord;
3712 }
3713 else if (rcode == kDNSFlag1_RC_NotAuth)
3714 {
3715 // TSIG errors should come with FormErr as per RFC 2845, but BIND 9 sends them with NotAuth so we look here too
3716 mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
3717 if (!tsigerr)
3718 {
3719 LogMsg("Permission denied (NOAUTH): %##s", displayname->c);
3720 return mStatus_UnknownErr;
3721 }
3722 else return tsigerr;
3723 }
3724 else if (rcode == kDNSFlag1_RC_FormErr)
3725 {
3726 mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
3727 if (!tsigerr)
3728 {
3729 LogMsg("Format Error: %##s", displayname->c);
3730 return mStatus_UnknownErr;
3731 }
3732 else return tsigerr;
3733 }
3734 else
3735 {
3736 LogMsg("Update %##s failed with rcode %d", displayname->c, rcode);
3737 return mStatus_UnknownErr;
3738 }
3739 }
3740
3741 // Called with lock held
3742 mDNSlocal void SendRecordRegistration(mDNS *const m, AuthRecord *rr)
3743 {
3744 mDNSu8 *ptr = m->omsg.data;
3745 mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
3746 mStatus err = mStatus_UnknownErr;
3747
3748 if (m->mDNS_busy != m->mDNS_reentrancy+1)
3749 LogMsg("SendRecordRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
3750
3751 if (mDNSIPv4AddressIsZero(rr->UpdateServer.ip.v4)) // Don't know our UpdateServer yet
3752 {
3753 rr->LastAPTime = m->timenow;
3754 if (rr->ThisAPInterval < mDNSPlatformOneSecond * 5)
3755 rr->ThisAPInterval = mDNSPlatformOneSecond * 5;
3756 return;
3757 }
3758
3759 rr->RequireGoodbye = mDNStrue;
3760 rr->updateid = mDNS_NewMessageID(m);
3761 InitializeDNSMessage(&m->omsg.h, rr->updateid, UpdateReqFlags);
3762
3763 // set zone
3764 ptr = putZone(&m->omsg, ptr, end, rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
3765 if (!ptr) { err = mStatus_UnknownErr; goto exit; }
3766
3767 if (rr->state == regState_UpdatePending)
3768 {
3769 // delete old RData
3770 SetNewRData(&rr->resrec, rr->OrigRData, rr->OrigRDLen);
3771 if (!(ptr = putDeletionRecord(&m->omsg, ptr, &rr->resrec))) { err = mStatus_UnknownErr; goto exit; } // delete old rdata
3772
3773 // add new RData
3774 SetNewRData(&rr->resrec, rr->InFlightRData, rr->InFlightRDLen);
3775 if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
3776 }
3777
3778 else
3779 {
3780 if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
3781 {
3782 // KnownUnique: Delete any previous value
3783 ptr = putDeleteRRSet(&m->omsg, ptr, rr->resrec.name, rr->resrec.rrtype);
3784 if (!ptr) { err = mStatus_UnknownErr; goto exit; }
3785 }
3786
3787 else if (rr->resrec.RecordType != kDNSRecordTypeShared)
3788 {
3789 // For now don't do this, until we have the logic for intelligent grouping of individual recors into logical service record sets
3790 //ptr = putPrereqNameNotInUse(rr->resrec.name, &m->omsg, ptr, end);
3791 if (!ptr) { err = mStatus_UnknownErr; goto exit; }
3792 }
3793
3794 ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl);
3795 if (!ptr) { err = mStatus_UnknownErr; goto exit; }
3796 }
3797
3798 if (rr->uselease)
3799 {
3800 ptr = putUpdateLease(&m->omsg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) { err = mStatus_UnknownErr; goto exit; }
3801 }
3802
3803 if (rr->Private)
3804 {
3805 LogInfo("SendRecordRegistration TCP %p %s", rr->tcp, ARDisplayString(m, rr));
3806 if (rr->tcp) LogInfo("SendRecordRegistration: Disposing existing TCP connection for %s", ARDisplayString(m, rr));
3807 if (rr->tcp) DisposeTCPConn(rr->tcp);
3808 rr->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, mDNSNULL, rr);
3809 if (!rr->tcp) rr->ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2)
3810 else if (rr->ThisAPInterval < mDNSPlatformOneSecond * 30) rr->ThisAPInterval = mDNSPlatformOneSecond * 30;
3811 }
3812 else
3813 {
3814 err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name));
3815 if (err) debugf("ERROR: SendRecordRegistration - mDNSSendDNSMessage - %d", err);
3816 }
3817
3818 SetRecordRetry(m, rr, err);
3819
3820 if (rr->state != regState_Refresh && rr->state != regState_DeregDeferred && rr->state != regState_UpdatePending)
3821 rr->state = regState_Pending;
3822
3823 return;
3824
3825 exit:
3826 LogMsg("SendRecordRegistration: Error formatting message for %s", ARDisplayString(m, rr));
3827 }
3828
3829 // Called with lock held
3830 mDNSlocal void hndlServiceUpdateReply(mDNS *const m, ServiceRecordSet *srs, mStatus err)
3831 {
3832 mDNSBool InvokeCallback = mDNSfalse;
3833 ExtraResourceRecord **e = &srs->Extras;
3834 AuthRecord *txt = &srs->RR_TXT;
3835
3836 if (m->mDNS_busy != m->mDNS_reentrancy+1)
3837 LogMsg("hndlServiceUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
3838
3839 debugf("hndlServiceUpdateReply: err %d state %d %##s", err, srs->state, srs->RR_SRV.resrec.name->c);
3840
3841 SetRecordRetry(m, &srs->RR_SRV, mStatus_NoError);
3842
3843 switch (srs->state)
3844 {
3845 case regState_Pending:
3846 if (err == mStatus_NameConflict && !srs->TestForSelfConflict)
3847 {
3848 srs->TestForSelfConflict = mDNStrue;
3849 debugf("checking for self-conflict of service %##s", srs->RR_SRV.resrec.name->c);
3850 SendServiceRegistration(m, srs);
3851 return;
3852 }
3853 else if (srs->TestForSelfConflict)
3854 {
3855 srs->TestForSelfConflict = mDNSfalse;
3856 if (err == mStatus_NoSuchRecord) err = mStatus_NameConflict; // NoSuchRecord implies that our prereq was not met, so we actually have a name conflict
3857 if (!err) srs->state = regState_Registered;
3858 InvokeCallback = mDNStrue;
3859 break;
3860 }
3861 else if (srs->srs_uselease && err == mStatus_UnknownErr && mDNSSameIPPort(srs->SRSUpdatePort, UnicastDNSPort))
3862 {
3863 LogMsg("Re-trying update of service %##s without lease option", srs->RR_SRV.resrec.name->c);
3864 srs->srs_uselease = mDNSfalse;
3865 SendServiceRegistration(m, srs);
3866 return;
3867 }
3868 else
3869 {
3870 //!!!KRS make sure all structs will still get cleaned up when client calls DeregisterService with this state
3871 if (err) LogMsg("Error %d for registration of service %##s", err, srs->RR_SRV.resrec.name->c);
3872 else srs->state = regState_Registered;
3873 InvokeCallback = mDNStrue;
3874 break;
3875 }
3876 case regState_Refresh:
3877 if (err)
3878 {
3879 LogMsg("Error %d for refresh of service %##s", err, srs->RR_SRV.resrec.name->c);
3880 InvokeCallback = mDNStrue;
3881 }
3882 else srs->state = regState_Registered;
3883 break;
3884 case regState_DeregPending:
3885 if (err) LogMsg("Error %d for deregistration of service %##s", err, srs->RR_SRV.resrec.name->c);
3886 if (srs->SRVChanged)
3887 {
3888 srs->state = regState_NoTarget; // NoTarget will allow us to pick up new target OR nat traversal state
3889 break;
3890 }
3891 err = mStatus_MemFree;
3892 InvokeCallback = mDNStrue;
3893 if (srs->NATinfo.clientContext)
3894 {
3895 // deletion completed
3896 mDNS_StopNATOperation_internal(m, &srs->NATinfo);
3897 srs->NATinfo.clientContext = mDNSNULL;
3898 }
3899 srs->state = regState_Unregistered;
3900 break;
3901 case regState_DeregDeferred:
3902 if (err)
3903 {
3904 debugf("Error %d received prior to deferred deregistration of %##s", err, srs->RR_SRV.resrec.name->c);
3905 err = mStatus_MemFree;
3906 InvokeCallback = mDNStrue;
3907 srs->state = regState_Unregistered;
3908 break;
3909 }
3910 else
3911 {
3912 debugf("Performing deferred deregistration of %##s", srs->RR_SRV.resrec.name->c);
3913 srs->state = regState_Registered;
3914 SendServiceDeregistration(m, srs);
3915 return;
3916 }
3917 case regState_UpdatePending:
3918 if (err)
3919 {
3920 LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs->RR_SRV.resrec.name->c);
3921 InvokeCallback = mDNStrue;
3922 }
3923 else
3924 {
3925 srs->state = regState_Registered;
3926 // deallocate old RData
3927 if (txt->UpdateCallback) txt->UpdateCallback(m, txt, txt->OrigRData);
3928 SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen);
3929 txt->OrigRData = mDNSNULL;
3930 txt->InFlightRData = mDNSNULL;
3931 }
3932 break;
3933 case regState_NoTarget:
3934 // This state is used when using SendServiceDeregistration() when going to sleep -- no further action required
3935 return;
3936 case regState_FetchingZoneData:
3937 case regState_Registered:
3938 case regState_Unregistered:
3939 case regState_NATMap:
3940 case regState_ExtraQueued:
3941 case regState_NATError:
3942 LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %d. Unlinking.",
3943 srs->RR_SRV.resrec.name->c, srs->state, err);
3944 err = mStatus_UnknownErr;
3945 default: LogMsg("hndlServiceUpdateReply: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c);
3946 }
3947
3948 if ((srs->SRVChanged || srs->SRVUpdateDeferred) && (srs->state == regState_NoTarget || srs->state == regState_Registered))
3949 {
3950 debugf("hndlServiceUpdateReply: SRVChanged %d SRVUpdateDeferred %d state %d", srs->SRVChanged, srs->SRVUpdateDeferred, srs->state);
3951 if (InvokeCallback)
3952 {
3953 srs->ClientCallbackDeferred = mDNStrue;
3954 srs->DeferredStatus = err;
3955 }
3956 srs->SRVChanged = srs->SRVUpdateDeferred = mDNSfalse;
3957 UpdateSRV(m, srs);
3958 return;
3959 }
3960
3961 while (*e)
3962 {
3963 if ((*e)->r.state == regState_ExtraQueued)
3964 {
3965 if (srs->state == regState_Registered && !err)
3966 {
3967 // extra resource record queued for this service - copy zone srs and register
3968 (*e)->r.zone = &srs->zone;
3969 (*e)->r.UpdateServer = srs->SRSUpdateServer;
3970 (*e)->r.UpdatePort = srs->SRSUpdatePort;
3971 (*e)->r.uselease = srs->srs_uselease;
3972 SendRecordRegistration(m, &(*e)->r);
3973 e = &(*e)->next;
3974 }
3975 else if (err && (*e)->r.state != regState_Unregistered)
3976 {
3977 // unlink extra from list
3978 (*e)->r.state = regState_Unregistered;
3979 *e = (*e)->next;
3980 }
3981 else e = &(*e)->next;
3982 }
3983 else e = &(*e)->next;
3984 }
3985
3986 if (srs->state == regState_Unregistered)
3987 {
3988 if (err != mStatus_MemFree)
3989 LogMsg("hndlServiceUpdateReply ERROR! state == regState_Unregistered but err != mStatus_MemFree. Permanently abandoning service registration %##s",
3990 srs->RR_SRV.resrec.name->c);
3991 unlinkSRS(m, srs);
3992 }
3993 else if (txt->QueuedRData && srs->state == regState_Registered)
3994 {
3995 if (InvokeCallback)
3996 {
3997 // if we were supposed to give a client callback, we'll do it after we update the primary txt record
3998 srs->ClientCallbackDeferred = mDNStrue;
3999 srs->DeferredStatus = err;
4000 }
4001 srs->state = regState_UpdatePending;
4002 txt->InFlightRData = txt->QueuedRData;
4003 txt->InFlightRDLen = txt->QueuedRDLen;
4004 txt->OrigRData = txt->resrec.rdata;
4005 txt->OrigRDLen = txt->resrec.rdlength;
4006 txt->QueuedRData = mDNSNULL;
4007 SendServiceRegistration(m, srs);
4008 return;
4009 }
4010
4011 mDNS_DropLockBeforeCallback();
4012 if (InvokeCallback)
4013 srs->ServiceCallback(m, srs, err);
4014 else if (srs->ClientCallbackDeferred)
4015 {
4016 srs->ClientCallbackDeferred = mDNSfalse;
4017 srs->ServiceCallback(m, srs, srs->DeferredStatus);
4018 }
4019 mDNS_ReclaimLockAfterCallback();
4020 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
4021 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
4022 }
4023
4024 // Called with lock held
4025 mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
4026 {
4027 mDNSBool InvokeCallback = mDNStrue;
4028
4029 if (m->mDNS_busy != m->mDNS_reentrancy+1)
4030 LogMsg("hndlRecordUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
4031
4032 LogInfo("hndlRecordUpdateReply: err %d state %d %s", err, rr->state, ARDisplayString(m, rr));
4033
4034 if (m->SleepState) return; // If we just sent a deregister on going to sleep, no further action required
4035
4036 SetRecordRetry(m, rr, mStatus_NoError);
4037
4038 if (rr->state == regState_UpdatePending)
4039 {
4040 if (err) LogMsg("Update record failed for %##s (err %d)", rr->resrec.name->c, err);
4041 rr->state = regState_Registered;
4042 // deallocate old RData
4043 if (rr->UpdateCallback) rr->UpdateCallback(m, rr, rr->OrigRData);
4044 SetNewRData(&rr->resrec, rr->InFlightRData, rr->InFlightRDLen);
4045 rr->OrigRData = mDNSNULL;
4046 rr->InFlightRData = mDNSNULL;
4047 }
4048
4049 if (rr->state == regState_DeregPending)
4050 {
4051 debugf("Received reply for deregister record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype);
4052 if (err) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %d",
4053 rr->resrec.name->c, rr->resrec.rrtype, err);
4054 err = mStatus_MemFree;
4055 rr->state = regState_Unregistered;
4056 }
4057
4058 if (rr->state == regState_DeregDeferred)
4059 {
4060 if (err)
4061 {
4062 LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %d",
4063 rr->resrec.name->c, rr->resrec.rrtype, err);
4064 rr->state = regState_Unregistered;
4065 }
4066 debugf("Calling deferred deregistration of record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype);
4067 rr->state = regState_Registered;
4068 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
4069 return;
4070 }
4071
4072 if (rr->state == regState_Pending || rr->state == regState_Refresh)
4073 {
4074 if (!err)
4075 {
4076 if (rr->state == regState_Refresh) InvokeCallback = mDNSfalse;
4077 rr->state = regState_Registered;
4078 }
4079 else
4080 {
4081 if (rr->uselease && err == mStatus_UnknownErr && mDNSSameIPPort(rr->UpdatePort, UnicastDNSPort))
4082 {
4083 LogMsg("Re-trying update of record %##s without lease option", rr->resrec.name->c);
4084 rr->uselease = mDNSfalse;
4085 SendRecordRegistration(m, rr);
4086 return;
4087 }
4088 LogMsg("hndlRecordUpdateReply: Registration of record %##s type %d failed with error %d", rr->resrec.name->c, rr->resrec.rrtype, err);
4089 return;
4090 }
4091 }
4092
4093 if (rr->state == regState_Unregistered) // Should never happen
4094 {
4095 LogMsg("hndlRecordUpdateReply rr->state == regState_Unregistered %s", ARDisplayString(m, rr));
4096 return;
4097 }
4098
4099 if (rr->QueuedRData && rr->state == regState_Registered)
4100 {
4101 rr->state = regState_UpdatePending;
4102 rr->InFlightRData = rr->QueuedRData;
4103 rr->InFlightRDLen = rr->QueuedRDLen;
4104 rr->OrigRData = rr->resrec.rdata;
4105 rr->OrigRDLen = rr->resrec.rdlength;
4106 rr->QueuedRData = mDNSNULL;
4107 SendRecordRegistration(m, rr);
4108 return;
4109 }
4110
4111 if (InvokeCallback && rr->RecordCallback)
4112 {
4113 mDNS_DropLockBeforeCallback();
4114 rr->RecordCallback(m, rr, err);
4115 mDNS_ReclaimLockAfterCallback();
4116 }
4117 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
4118 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
4119 }
4120
4121 mDNSexport void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 *pkt, mDNSu16 len)
4122 {
4123 NATTraversalInfo *ptr;
4124 NATAddrReply *AddrReply = (NATAddrReply *)pkt;
4125 NATPortMapReply *PortMapReply = (NATPortMapReply *)pkt;
4126 mDNSu32 nat_elapsed, our_elapsed;
4127
4128 // Minimum packet is vers (1) opcode (1) err (2) upseconds (4) = 8 bytes
4129 if (!AddrReply->err && len < 8) { LogMsg("NAT Traversal message too short (%d bytes)", len); return; }
4130 if (AddrReply->vers != NATMAP_VERS) { LogMsg("Received NAT Traversal response with version %d (expected %d)", pkt[0], NATMAP_VERS); return; }
4131
4132 // Read multi-byte numeric values (fields are identical in a NATPortMapReply)
4133 AddrReply->err = (mDNSu16) ( (mDNSu16)pkt[2] << 8 | pkt[3]);
4134 AddrReply->upseconds = (mDNSs32) ((mDNSs32)pkt[4] << 24 | (mDNSs32)pkt[5] << 16 | (mDNSs32)pkt[6] << 8 | pkt[7]);
4135
4136 nat_elapsed = AddrReply->upseconds - m->LastNATupseconds;
4137 our_elapsed = (m->timenow - m->LastNATReplyLocalTime) / mDNSPlatformOneSecond;
4138 debugf("uDNS_ReceiveNATPMPPacket %X upseconds %u nat_elapsed %d our_elapsed %d", AddrReply->opcode, AddrReply->upseconds, nat_elapsed, our_elapsed);
4139
4140 // We compute a conservative estimate of how much the NAT gateways's clock should have advanced
4141 // 1. We subtract 12.5% from our own measured elapsed time, to allow for NAT gateways that have an inacurate clock that runs slowly
4142 // 2. We add a two-second safety margin to allow for rounding errors:
4143 // -- e.g. if NAT gateway sends a packet at t=2.00 seconds, then one at t=7.99, that's virtually 6 seconds,
4144 // but based on the values in the packet (2,7) the apparent difference is only 5 seconds
4145 // -- similarly, if we're slow handling packets and/or we have coarse clock granularity, we could over-estimate the true interval
4146 // (e.g. t=1.99 seconds rounded to 1, and t=8.01 rounded to 8, gives an apparent difference of 7 seconds)
4147 if (AddrReply->upseconds < m->LastNATupseconds || nat_elapsed + 2 < our_elapsed - our_elapsed/8)
4148 { LogMsg("NAT gateway %#a rebooted", &m->Router); RecreateNATMappings(m); }
4149
4150 m->LastNATupseconds = AddrReply->upseconds;
4151 m->LastNATReplyLocalTime = m->timenow;
4152 #ifdef _LEGACY_NAT_TRAVERSAL_
4153 LNT_ClearState(m);
4154 #endif // _LEGACY_NAT_TRAVERSAL_
4155
4156 if (AddrReply->opcode == NATOp_AddrResponse)
4157 {
4158 #if APPLE_OSX_mDNSResponder
4159 static char msgbuf[16];
4160 mDNS_snprintf(msgbuf, sizeof(msgbuf), "%d", AddrReply->err);
4161 mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.natpmp.AddressRequest", AddrReply->err ? "failure" : "success", msgbuf, "");
4162 #endif
4163 if (!AddrReply->err && len < sizeof(NATAddrReply)) { LogMsg("NAT Traversal AddrResponse message too short (%d bytes)", len); return; }
4164 natTraversalHandleAddressReply(m, AddrReply->err, AddrReply->ExtAddr);
4165 }
4166 else if (AddrReply->opcode == NATOp_MapUDPResponse || AddrReply->opcode == NATOp_MapTCPResponse)
4167 {
4168 mDNSu8 Protocol = AddrReply->opcode & 0x7F;
4169 #if APPLE_OSX_mDNSResponder
4170 static char msgbuf[16];
4171 mDNS_snprintf(msgbuf, sizeof(msgbuf), "%s - %d", AddrReply->opcode == NATOp_MapUDPResponse ? "UDP" : "TCP", PortMapReply->err);
4172 mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.natpmp.PortMapRequest", PortMapReply->err ? "failure" : "success", msgbuf, "");
4173 #endif
4174 if (!PortMapReply->err)
4175 {
4176 if (len < sizeof(NATPortMapReply)) { LogMsg("NAT Traversal PortMapReply message too short (%d bytes)", len); return; }
4177 PortMapReply->NATRep_lease = (mDNSu32) ((mDNSu32)pkt[12] << 24 | (mDNSu32)pkt[13] << 16 | (mDNSu32)pkt[14] << 8 | pkt[15]);
4178 }
4179
4180 // Since some NAT-PMP server implementations don't return the requested internal port in
4181 // the reply, we can't associate this reply with a particular NATTraversalInfo structure.
4182 // We globally keep track of the most recent error code for mappings.
4183 m->LastNATMapResultCode = PortMapReply->err;
4184
4185 for (ptr = m->NATTraversals; ptr; ptr=ptr->next)
4186 if (ptr->Protocol == Protocol && mDNSSameIPPort(ptr->IntPort, PortMapReply->intport))
4187 natTraversalHandlePortMapReply(m, ptr, InterfaceID, PortMapReply->err, PortMapReply->extport, PortMapReply->NATRep_lease);
4188 }
4189 else { LogMsg("Received NAT Traversal response with version unknown opcode 0x%X", AddrReply->opcode); return; }
4190
4191 // Don't need an SSDP socket if we get a NAT-PMP packet
4192 if (m->SSDPSocket) { debugf("uDNS_ReceiveNATPMPPacket destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
4193 }
4194
4195 // <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
4196 // <rdar://problem/4288449> Add check to avoid crashing NAT gateways that have buggy DNS relay code
4197 //
4198 // We know of bugs in home NAT gateways that cause them to crash if they receive certain DNS queries.
4199 // The DNS queries that make them crash are perfectly legal DNS queries, but even if they weren't,
4200 // the gateway shouldn't crash -- in today's world of viruses and network attacks, software has to
4201 // be written assuming that a malicious attacker could send them any packet, properly-formed or not.
4202 // Still, we don't want to be crashing people's home gateways, so we go out of our way to avoid
4203 // the queries that crash them.
4204 //
4205 // Some examples:
4206 //
4207 // 1. Any query where the name ends in ".in-addr.arpa." and the text before this is 32 or more bytes.
4208 // The query type does not need to be PTR -- the gateway will crash for any query type.
4209 // e.g. "ping long-name-crashes-the-buggy-router.in-addr.arpa" will crash one of these.
4210 //
4211 // 2. Any query that results in a large response with the TC bit set.
4212 //
4213 // 3. Any PTR query that doesn't begin with four decimal numbers.
4214 // These gateways appear to assume that the only possible PTR query is a reverse-mapping query
4215 // (e.g. "1.0.168.192.in-addr.arpa") and if they ever get a PTR query where the first four
4216 // labels are not all decimal numbers in the range 0-255, they handle that by crashing.
4217 // These gateways also ignore the remainder of the name following the four decimal numbers
4218 // -- whether or not it actually says in-addr.arpa, they just make up an answer anyway.
4219 //
4220 // The challenge therefore is to craft a query that will discern whether the DNS server
4221 // is one of these buggy ones, without crashing it. Furthermore we don't want our test
4222 // queries making it all the way to the root name servers, putting extra load on those
4223 // name servers and giving Apple a bad reputation. To this end we send this query:
4224 // dig -t ptr 1.0.0.127.dnsbugtest.1.0.0.127.in-addr.arpa.
4225 //
4226 // The text preceding the ".in-addr.arpa." is under 32 bytes, so it won't cause crash (1).
4227 // It will not yield a large response with the TC bit set, so it won't cause crash (2).
4228 // It starts with four decimal numbers, so it won't cause crash (3).
4229 // The name falls within the "1.0.0.127.in-addr.arpa." domain, the reverse-mapping name for the local
4230 // loopback address, and therefore the query will black-hole at the first properly-configured DNS server
4231 // it reaches, making it highly unlikely that this query will make it all the way to the root.
4232 //
4233 // Finally, the correct response to this query is NXDOMAIN or a similar error, but the
4234 // gateways that ignore the remainder of the name following the four decimal numbers
4235 // give themselves away by actually returning a result for this nonsense query.
4236
4237 mDNSlocal const domainname *DNSRelayTestQuestion = (const domainname*)
4238 "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\xa" "dnsbugtest"
4239 "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\x7" "in-addr" "\x4" "arpa";
4240
4241 // See comments above for DNSRelayTestQuestion
4242 // If this is the kind of query that has the risk of crashing buggy DNS servers, we do a test question first
4243 mDNSlocal mDNSBool NoTestQuery(DNSQuestion *q)
4244 {
4245 int i;
4246 mDNSu8 *p = q->qname.c;
4247 if (q->AuthInfo) return(mDNStrue); // Don't need a test query for private queries sent directly to authoritative server over TLS/TCP
4248 if (q->qtype != kDNSType_PTR) return(mDNStrue); // Don't need a test query for any non-PTR queries
4249 for (i=0; i<4; i++) // If qname does not begin with num.num.num.num, can't skip the test query
4250 {
4251 if (p[0] < 1 || p[0] > 3) return(mDNSfalse);
4252 if ( p[1] < '0' || p[1] > '9' ) return(mDNSfalse);
4253 if (p[0] >= 2 && (p[2] < '0' || p[2] > '9')) return(mDNSfalse);
4254 if (p[0] >= 3 && (p[3] < '0' || p[3] > '9')) return(mDNSfalse);
4255 p += 1 + p[0];
4256 }
4257 // If remainder of qname is ".in-addr.arpa.", this is a vanilla reverse-mapping query and
4258 // we can safely do it without needing a test query first, otherwise we need the test query.
4259 return(SameDomainName((domainname*)p, (const domainname*)"\x7" "in-addr" "\x4" "arpa"));
4260 }
4261
4262 // Returns mDNStrue if response was handled
4263 mDNSlocal mDNSBool uDNS_ReceiveTestQuestionResponse(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
4264 const mDNSAddr *const srcaddr, const mDNSIPPort srcport)
4265 {
4266 const mDNSu8 *ptr = msg->data;
4267 DNSQuestion pktq;
4268 DNSServer *s;
4269 mDNSu32 result = 0;
4270
4271 // 1. Find out if this is an answer to one of our test questions
4272 if (msg->h.numQuestions != 1) return(mDNSfalse);
4273 ptr = getQuestion(msg, ptr, end, mDNSInterface_Any, &pktq);
4274 if (!ptr) return(mDNSfalse);
4275 if (pktq.qtype != kDNSType_PTR || pktq.qclass != kDNSClass_IN) return(mDNSfalse);
4276 if (!SameDomainName(&pktq.qname, DNSRelayTestQuestion)) return(mDNSfalse);
4277
4278 // 2. If the DNS relay gave us a positive response, then it's got buggy firmware
4279 // else, if the DNS relay gave us an error or no-answer response, it passed our test
4280 if ((msg->h.flags.b[1] & kDNSFlag1_RC_Mask) == kDNSFlag1_RC_NoErr && msg->h.numAnswers > 0)
4281 result = DNSServer_Failed;
4282 else
4283 result = DNSServer_Passed;
4284
4285 // 3. Find occurrences of this server in our list, and mark them appropriately
4286 for (s = m->DNSServers; s; s = s->next)
4287 {
4288 mDNSBool matchaddr = (s->teststate != result && mDNSSameAddress(srcaddr, &s->addr) && mDNSSameIPPort(srcport, s->port));
4289 mDNSBool matchid = (s->teststate == DNSServer_Untested && mDNSSameOpaque16(msg->h.id, s->testid));
4290 if (matchaddr || matchid)
4291 {
4292 DNSQuestion *q;
4293 s->teststate = result;
4294 if (result == DNSServer_Passed)
4295 {
4296 LogInfo("DNS Server %#a:%d (%#a:%d) %d passed%s",
4297 &s->addr, mDNSVal16(s->port), srcaddr, mDNSVal16(srcport), mDNSVal16(s->testid),
4298 matchaddr ? "" : " NOTE: Reply did not come from address to which query was sent");
4299 }
4300 else
4301 {
4302 LogMsg("NOTE: Wide-Area Service Discovery disabled to avoid crashing defective DNS relay %#a:%d (%#a:%d) %d%s",
4303 &s->addr, mDNSVal16(s->port), srcaddr, mDNSVal16(srcport), mDNSVal16(s->testid),
4304 matchaddr ? "" : " NOTE: Reply did not come from address to which query was sent");
4305 }
4306
4307 // If this server has just changed state from DNSServer_Untested to DNSServer_Passed, then retrigger any waiting questions.
4308 // We use the NoTestQuery() test so that we only retrigger questions that were actually blocked waiting for this test to complete.
4309 if (result == DNSServer_Passed) // Unblock any questions that were waiting for this result
4310 for (q = m->Questions; q; q=q->next)
4311 if (q->qDNSServer == s && !NoTestQuery(q))
4312 {
4313 q->ThisQInterval = INIT_UCAST_POLL_INTERVAL / QuestionIntervalStep;
4314 q->unansweredQueries = 0;
4315 q->LastQTime = m->timenow - q->ThisQInterval;
4316 m->NextScheduledQuery = m->timenow;
4317 }
4318 }
4319 }
4320
4321 return(mDNStrue); // Return mDNStrue to tell uDNS_ReceiveMsg it doesn't need to process this packet further
4322 }
4323
4324 // Called from mDNSCoreReceive with the lock held
4325 mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport)
4326 {
4327 DNSQuestion *qptr;
4328 mStatus err = mStatus_NoError;
4329
4330 mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
4331 mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
4332 mDNSu8 QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
4333 mDNSu8 rcode = (mDNSu8)(msg->h.flags.b[1] & kDNSFlag1_RC_Mask);
4334
4335 (void)srcport; // Unused
4336
4337 debugf("uDNS_ReceiveMsg from %#-15a with "
4338 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
4339 srcaddr,
4340 msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,",
4341 msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,",
4342 msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,",
4343 msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
4344
4345 if (QR_OP == StdR)
4346 {
4347 //if (srcaddr && recvLLQResponse(m, msg, end, srcaddr, srcport)) return;
4348 if (uDNS_ReceiveTestQuestionResponse(m, msg, end, srcaddr, srcport)) return;
4349 for (qptr = m->Questions; qptr; qptr = qptr->next)
4350 if (msg->h.flags.b[0] & kDNSFlag0_TC && mDNSSameOpaque16(qptr->TargetQID, msg->h.id) && m->timenow - qptr->LastQTime < RESPONSE_WINDOW)
4351 {
4352 if (!srcaddr) LogMsg("uDNS_ReceiveMsg: TCP DNS response had TC bit set: ignoring");
4353 else if (qptr->tcp)
4354 {
4355 // There may be a race condition here, if the server decides to drop the connection just as we decide to reuse it
4356 // For now it should not be serious because our normal retry logic (as used to handle UDP packet loss)
4357 // should take care of it but later we may want to look at handling this case explicitly
4358 LogInfo("uDNS_ReceiveMsg: Using existing TCP connection for %##s (%s)", qptr->qname.c, DNSTypeName(qptr->qtype));
4359 mDNS_DropLockBeforeCallback();
4360 tcpCallback(qptr->tcp->sock, qptr->tcp, mDNStrue, mStatus_NoError);
4361 mDNS_ReclaimLockAfterCallback();
4362 }
4363 else qptr->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_Zero, srcaddr, srcport, qptr, mDNSNULL, mDNSNULL);
4364 }
4365 }
4366
4367 if (QR_OP == UpdateR)
4368 {
4369 mDNSu32 lease = GetPktLease(m, msg, end);
4370 mDNSs32 expire = m->timenow + (mDNSs32)lease * mDNSPlatformOneSecond;
4371
4372 //rcode = kDNSFlag1_RC_ServFail; // Simulate server failure (rcode 2)
4373
4374 if (CurrentServiceRecordSet)
4375 LogMsg("uDNS_ReceiveMsg ERROR CurrentServiceRecordSet already set");
4376 CurrentServiceRecordSet = m->ServiceRegistrations;
4377
4378 while (CurrentServiceRecordSet)
4379 {
4380 ServiceRecordSet *sptr = CurrentServiceRecordSet;
4381 CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next;
4382
4383 if (mDNSSameOpaque16(sptr->id, msg->h.id))
4384 {
4385 err = checkUpdateResult(m, sptr->RR_SRV.resrec.name, rcode, msg, end);
4386 if (!err && sptr->srs_uselease && lease)
4387 if (sptr->RR_SRV.expire - expire >= 0 || sptr->state != regState_UpdatePending)
4388 sptr->RR_SRV.expire = expire;
4389 hndlServiceUpdateReply(m, sptr, err);
4390 CurrentServiceRecordSet = mDNSNULL;
4391 return;
4392 }
4393 }
4394
4395 if (m->CurrentRecord)
4396 LogMsg("uDNS_ReceiveMsg ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
4397 m->CurrentRecord = m->ResourceRecords;
4398 while (m->CurrentRecord)
4399 {
4400 AuthRecord *rptr = m->CurrentRecord;
4401 m->CurrentRecord = m->CurrentRecord->next;
4402 if (AuthRecord_uDNS(rptr) && mDNSSameOpaque16(rptr->updateid, msg->h.id))
4403 {
4404 err = checkUpdateResult(m, rptr->resrec.name, rcode, msg, end);
4405 if (!err && rptr->uselease && lease)
4406 if (rptr->expire - expire >= 0 || rptr->state != regState_UpdatePending)
4407 rptr->expire = expire;
4408 hndlRecordUpdateReply(m, rptr, err);
4409 m->CurrentRecord = mDNSNULL;
4410 return;
4411 }
4412 }
4413 }
4414 debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg->h.id));
4415 }
4416
4417 // ***************************************************************************
4418 #if COMPILER_LIKES_PRAGMA_MARK
4419 #pragma mark - Query Routines
4420 #endif
4421
4422 mDNSexport void sendLLQRefresh(mDNS *m, DNSQuestion *q)
4423 {
4424 mDNSu8 *end;
4425 LLQOptData llq;
4426
4427 if (q->ReqLease)
4428 if ((q->state == LLQ_Established && q->ntries >= kLLQ_MAX_TRIES) || q->expire - m->timenow < 0)
4429 {
4430 LogMsg("Unable to refresh LLQ %##s (%s) - will retry in %d seconds", q->qname.c, DNSTypeName(q->qtype), LLQ_POLL_INTERVAL / mDNSPlatformOneSecond);
4431 StartLLQPolling(m,q);
4432 return;
4433 }
4434
4435 llq.vers = kLLQ_Vers;
4436 llq.llqOp = kLLQOp_Refresh;
4437 llq.err = q->tcp ? GetLLQEventPort(m, &q->servAddr) : LLQErr_NoError; // If using TCP tell server what UDP port to send notifications to
4438 llq.id = q->id;
4439 llq.llqlease = q->ReqLease;
4440
4441 InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
4442 end = putLLQ(&m->omsg, m->omsg.data, q, &llq);
4443 if (!end) { LogMsg("sendLLQRefresh: putLLQ failed %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
4444
4445 // Note that we (conditionally) add HINFO and TSIG here, since the question might be going away,
4446 // so we may not be able to reference it (most importantly it's AuthInfo) when we actually send the message
4447 end = putHINFO(m, &m->omsg, end, q->AuthInfo);
4448 if (!end) { LogMsg("sendLLQRefresh: putHINFO failed %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
4449
4450 if (q->AuthInfo)
4451 {
4452 DNSDigest_SignMessageHostByteOrder(&m->omsg, &end, q->AuthInfo);
4453 if (!end) { LogMsg("sendLLQRefresh: DNSDigest_SignMessage failed %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
4454 }
4455
4456 if (q->AuthInfo && !q->tcp)
4457 {
4458 LogInfo("sendLLQRefresh setting up new TLS session %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4459 q->tcp = MakeTCPConn(m, &m->omsg, end, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, q, mDNSNULL, mDNSNULL);
4460 }
4461 else
4462 {
4463 mStatus err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, mDNSNULL);
4464 if (err)
4465 {
4466 LogMsg("sendLLQRefresh: mDNSSendDNSMessage%s failed: %d", q->tcp ? " (TCP)" : "", err);
4467 if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; }
4468 }
4469 }
4470
4471 q->ntries++;
4472
4473 debugf("sendLLQRefresh ntries %d %##s (%s)", q->ntries, q->qname.c, DNSTypeName(q->qtype));
4474
4475 q->LastQTime = m->timenow;
4476 SetNextQueryTime(m, q);
4477 }
4478
4479 mDNSexport void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
4480 {
4481 DNSQuestion *q = (DNSQuestion *)zoneInfo->ZoneDataContext;
4482
4483 mDNS_Lock(m);
4484
4485 // If we get here it means that the GetZoneData operation has completed, and is is about to cancel
4486 // its question and free the ZoneData memory. We no longer need to hold onto our pointer (which
4487 // we use for cleaning up if our LLQ is cancelled *before* the GetZoneData operation has completes).
4488 q->nta = mDNSNULL;
4489 q->servAddr = zeroAddr;
4490 q->servPort = zeroIPPort;
4491
4492 if (!err && zoneInfo && !mDNSIPPortIsZero(zoneInfo->Port) && !mDNSAddressIsZero(&zoneInfo->Addr))
4493 {
4494 q->servAddr = zoneInfo->Addr;
4495 q->servPort = zoneInfo->Port;
4496 q->AuthInfo = zoneInfo->ZonePrivate ? GetAuthInfoForName_internal(m, &q->qname) : mDNSNULL;
4497 q->ntries = 0;
4498 debugf("LLQGotZoneData %#a:%d", &q->servAddr, mDNSVal16(q->servPort));
4499 startLLQHandshake(m, q);
4500 }
4501 else
4502 {
4503 StartLLQPolling(m,q);
4504 if (err == mStatus_NoSuchNameErr)
4505 {
4506 // this actually failed, so mark it by setting address to all ones
4507 q->servAddr.type = mDNSAddrType_IPv4;
4508 q->servAddr.ip.v4 = onesIPv4Addr;
4509 }
4510 }
4511
4512 mDNS_Unlock(m);
4513 }
4514
4515 // Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
4516 mDNSlocal void PrivateQueryGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
4517 {
4518 DNSQuestion *q = (DNSQuestion *) zoneInfo->ZoneDataContext;
4519
4520 LogInfo("PrivateQueryGotZoneData %##s (%s) err %d Zone %##s Private %d", q->qname.c, DNSTypeName(q->qtype), err, zoneInfo->ZoneName.c, zoneInfo->ZonePrivate);
4521
4522 // If we get here it means that the GetZoneData operation has completed, and is is about to cancel
4523 // its question and free the ZoneData memory. We no longer need to hold onto our pointer (which
4524 // we use for cleaning up if our LLQ is cancelled *before* the GetZoneData operation has completes).
4525 q->nta = mDNSNULL;
4526
4527 if (err || !zoneInfo || mDNSAddressIsZero(&zoneInfo->Addr) || mDNSIPPortIsZero(zoneInfo->Port))
4528 {
4529 LogInfo("ERROR: PrivateQueryGotZoneData %##s (%s) invoked with error code %d %p %#a:%d",
4530 q->qname.c, DNSTypeName(q->qtype), err, zoneInfo,
4531 zoneInfo ? &zoneInfo->Addr : mDNSNULL,
4532 zoneInfo ? mDNSVal16(zoneInfo->Port) : 0);
4533 return;
4534 }
4535
4536 if (!zoneInfo->ZonePrivate)
4537 {
4538 debugf("Private port lookup failed -- retrying without TLS -- %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4539 q->AuthInfo = mDNSNULL; // Clear AuthInfo so we try again non-private
4540 q->ThisQInterval = InitialQuestionInterval;
4541 q->LastQTime = m->timenow - q->ThisQInterval;
4542 mDNS_Lock(m);
4543 SetNextQueryTime(m, q);
4544 mDNS_Unlock(m);
4545 return;
4546 // Next call to uDNS_CheckCurrentQuestion() will do this as a non-private query
4547 }
4548
4549 if (!q->AuthInfo)
4550 {
4551 LogMsg("ERROR: PrivateQueryGotZoneData: cannot find credentials for q %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4552 return;
4553 }
4554
4555 q->TargetQID = mDNS_NewMessageID(m);
4556 if (q->tcp) DisposeTCPConn(q->tcp);
4557 q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &zoneInfo->Addr, zoneInfo->Port, q, mDNSNULL, mDNSNULL);
4558 }
4559
4560 // ***************************************************************************
4561 #if COMPILER_LIKES_PRAGMA_MARK
4562 #pragma mark - Dynamic Updates
4563 #endif
4564
4565 // Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
4566 mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneData)
4567 {
4568 AuthRecord *newRR = (AuthRecord*)zoneData->ZoneDataContext;
4569 AuthRecord *ptr;
4570 int c1, c2;
4571
4572 if (m->mDNS_busy != m->mDNS_reentrancy)
4573 LogMsg("RecordRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
4574
4575 newRR->nta = mDNSNULL;
4576
4577 // Start off assuming we're going to use a lease
4578 // 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
4579 newRR->uselease = mDNStrue;
4580
4581 // make sure record is still in list (!!!)
4582 for (ptr = m->ResourceRecords; ptr; ptr = ptr->next) if (ptr == newRR) break;
4583 if (!ptr) { LogMsg("RecordRegistrationGotZoneData - RR no longer in list. Discarding."); return; }
4584
4585 // check error/result
4586 if (err)
4587 {
4588 if (err != mStatus_NoSuchNameErr) LogMsg("RecordRegistrationGotZoneData: error %d", err);
4589 return;
4590 }
4591
4592 if (!zoneData) { LogMsg("ERROR: RecordRegistrationGotZoneData invoked with NULL result and no error"); return; }
4593
4594 if (newRR->resrec.rrclass != zoneData->ZoneClass)
4595 {
4596 LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)", newRR->resrec.rrclass, zoneData->ZoneClass);
4597 return;
4598 }
4599
4600 // Don't try to do updates to the root name server.
4601 // We might be tempted also to block updates to any single-label name server (e.g. com, edu, net, etc.) but some
4602 // organizations use their own private pseudo-TLD, like ".home", etc, and we don't want to block that.
4603 if (zoneData->ZoneName.c[0] == 0)
4604 {
4605 LogInfo("RecordRegistrationGotZoneData: No name server found claiming responsibility for \"%##s\"!", newRR->resrec.name->c);
4606 return;
4607 }
4608
4609 // Store discovered zone data
4610 c1 = CountLabels(newRR->resrec.name);
4611 c2 = CountLabels(&zoneData->ZoneName);
4612 if (c2 > c1)
4613 {
4614 LogMsg("RecordRegistrationGotZoneData: Zone \"%##s\" is longer than \"%##s\"", zoneData->ZoneName.c, newRR->resrec.name->c);
4615 return;
4616 }
4617 newRR->zone = SkipLeadingLabels(newRR->resrec.name, c1-c2);
4618 if (!SameDomainName(newRR->zone, &zoneData->ZoneName))
4619 {
4620 LogMsg("RecordRegistrationGotZoneData: Zone \"%##s\" does not match \"%##s\" for \"%##s\"", newRR->zone->c, zoneData->ZoneName.c, newRR->resrec.name->c);
4621 return;
4622 }
4623 newRR->UpdateServer = zoneData->Addr;
4624 newRR->UpdatePort = zoneData->Port;
4625 newRR->Private = zoneData->ZonePrivate;
4626 debugf("RecordRegistrationGotZoneData: Set newRR->UpdateServer %##s %##s to %#a:%d",
4627 newRR->resrec.name->c, zoneData->ZoneName.c, &newRR->UpdateServer, mDNSVal16(newRR->UpdatePort));
4628
4629 if (mDNSIPPortIsZero(zoneData->Port) || mDNSAddressIsZero(&zoneData->Addr))
4630 {
4631 LogInfo("RecordRegistrationGotZoneData: No _dns-update._udp service found for \"%##s\"!", newRR->resrec.name->c);
4632 return;
4633 }
4634
4635 newRR->ThisAPInterval = 5 * mDNSPlatformOneSecond; // After doubling, first retry will happen after ten seconds
4636
4637 mDNS_Lock(m); // SendRecordRegistration expects to be called with the lock held
4638 SendRecordRegistration(m, newRR);
4639 mDNS_Unlock(m);
4640 }
4641
4642 mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
4643 {
4644 mDNSu8 *ptr = m->omsg.data;
4645 mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
4646
4647 if (mDNSIPv4AddressIsZero(rr->UpdateServer.ip.v4)) // Don't know our UpdateServer yet
4648 {
4649 rr->LastAPTime = m->timenow;
4650 if (rr->ThisAPInterval < mDNSPlatformOneSecond * 5)
4651 rr->ThisAPInterval = mDNSPlatformOneSecond * 5;
4652 return;
4653 }
4654
4655 InitializeDNSMessage(&m->omsg.h, rr->updateid, UpdateReqFlags);
4656
4657 ptr = putZone(&m->omsg, ptr, end, rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
4658 if (ptr) ptr = putDeletionRecord(&m->omsg, ptr, &rr->resrec);
4659 if (!ptr)
4660 {
4661 LogMsg("SendRecordDeregistration Error: could not contruct deregistration packet for %s", ARDisplayString(m, rr));
4662 if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr);
4663 }
4664 else
4665 {
4666 rr->expire = 0; // Indicate that we have no active registration any more
4667 if (rr->Private)
4668 {
4669 LogInfo("SendRecordDeregistration TCP %p %s", rr->tcp, ARDisplayString(m, rr));
4670 if (rr->tcp) LogInfo("SendRecordDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m, rr));
4671 if (rr->tcp) DisposeTCPConn(rr->tcp);
4672 rr->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, mDNSNULL, rr);
4673 if (!rr->tcp) rr->ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2)
4674 else if (rr->ThisAPInterval < mDNSPlatformOneSecond * 30) rr->ThisAPInterval = mDNSPlatformOneSecond * 30;
4675 SetRecordRetry(m, rr, mStatus_NoError);
4676 }
4677 else
4678 {
4679 mStatus err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name));
4680 if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %d", err);
4681 if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr); // Don't touch rr after this
4682 }
4683 }
4684 }
4685
4686 mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr)
4687 {
4688 switch (rr->state)
4689 {
4690 case regState_NATMap: LogMsg("regState_NATMap %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
4691 case regState_ExtraQueued: rr->state = regState_Unregistered; break;
4692 case regState_Refresh:
4693 case regState_Pending:
4694 case regState_UpdatePending:
4695 case regState_FetchingZoneData:
4696 case regState_Registered: break;
4697 case regState_DeregPending: break;
4698 case regState_DeregDeferred: LogMsg("regState_DeregDeferred %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
4699 case regState_Unregistered: LogMsg("regState_Unregistered %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
4700 case regState_NATError: LogMsg("regState_NATError %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
4701 case regState_NoTarget: LogMsg("regState_NoTarget %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
4702 default: LogMsg("uDNS_DeregisterRecord: State %d for %##s type %s", rr->state, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
4703 }
4704
4705 if (rr->state != regState_Unregistered) { rr->state = regState_DeregPending; SendRecordDeregistration(m, rr); }
4706 return mStatus_NoError;
4707 }
4708
4709 // Called with lock held
4710 mDNSexport mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs)
4711 {
4712 char *errmsg = "Unknown State";
4713
4714 if (m->mDNS_busy != m->mDNS_reentrancy+1)
4715 LogMsg("uDNS_DeregisterService: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
4716
4717 // don't re-register with a new target following deregistration
4718 srs->SRVChanged = srs->SRVUpdateDeferred = mDNSfalse;
4719
4720 if (srs->srs_nta) { CancelGetZoneData(m, srs->srs_nta); srs->srs_nta = mDNSNULL; }
4721
4722 if (srs->NATinfo.clientContext)
4723 {
4724 mDNS_StopNATOperation_internal(m, &srs->NATinfo);
4725 srs->NATinfo.clientContext = mDNSNULL;
4726 }
4727
4728 switch (srs->state)
4729 {
4730 case regState_Unregistered:
4731 debugf("uDNS_DeregisterService - service %##s not registered", srs->RR_SRV.resrec.name->c);
4732 return mStatus_BadReferenceErr;
4733 case regState_DeregPending:
4734 case regState_DeregDeferred:
4735 debugf("Double deregistration of service %##s", srs->RR_SRV.resrec.name->c);
4736 return mStatus_NoError;
4737 case regState_NATError: // not registered
4738 case regState_NATMap: // not registered
4739 case regState_NoTarget: // not registered
4740 unlinkSRS(m, srs);
4741 srs->state = regState_Unregistered;
4742 mDNS_DropLockBeforeCallback();
4743 srs->ServiceCallback(m, srs, mStatus_MemFree);
4744 mDNS_ReclaimLockAfterCallback();
4745 return mStatus_NoError;
4746 case regState_Pending:
4747 case regState_Refresh:
4748 case regState_UpdatePending:
4749 case regState_FetchingZoneData:
4750 case regState_Registered:
4751 srs->state = regState_DeregPending;
4752 SendServiceDeregistration(m, srs);
4753 return mStatus_NoError;
4754 case regState_ExtraQueued: // only for record registrations
4755 errmsg = "bad state (regState_ExtraQueued)";
4756 goto error;
4757 default: LogMsg("uDNS_DeregisterService: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c);
4758 }
4759
4760 error:
4761 LogMsg("Error, uDNS_DeregisterService: %s", errmsg);
4762 return mStatus_BadReferenceErr;
4763 }
4764
4765 mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr)
4766 {
4767 ServiceRecordSet *parent = mDNSNULL;
4768 AuthRecord *rptr;
4769 regState_t *stateptr = mDNSNULL;
4770
4771 // find the record in registered service list
4772 for (parent = m->ServiceRegistrations; parent; parent = parent->uDNS_next)
4773 if (&parent->RR_TXT == rr) { stateptr = &parent->state; break; }
4774
4775 if (!parent)
4776 {
4777 // record not part of a service - check individual record registrations
4778 for (rptr = m->ResourceRecords; rptr; rptr = rptr->next)
4779 if (rptr == rr) { stateptr = &rr->state; break; }
4780 if (!rptr) goto unreg_error;
4781 }
4782
4783 switch(*stateptr)
4784 {
4785 case regState_DeregPending:
4786 case regState_DeregDeferred:
4787 case regState_Unregistered:
4788 // not actively registered
4789 goto unreg_error;
4790
4791 case regState_FetchingZoneData:
4792 case regState_NATMap:
4793 case regState_ExtraQueued:
4794 case regState_NoTarget:
4795 // change rdata directly since it hasn't been sent yet
4796 if (rr->UpdateCallback) rr->UpdateCallback(m, rr, rr->resrec.rdata);
4797 SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
4798 rr->NewRData = mDNSNULL;
4799 return mStatus_NoError;
4800
4801 case regState_Pending:
4802 case regState_Refresh:
4803 case regState_UpdatePending:
4804 // registration in-flight. queue rdata and return
4805 if (rr->QueuedRData && rr->UpdateCallback)
4806 // if unsent rdata is already queued, free it before we replace it
4807 rr->UpdateCallback(m, rr, rr->QueuedRData);
4808 rr->QueuedRData = rr->NewRData;
4809 rr->QueuedRDLen = rr->newrdlength;
4810 rr->NewRData = mDNSNULL;
4811 return mStatus_NoError;
4812
4813 case regState_Registered:
4814 rr->OrigRData = rr->resrec.rdata;
4815 rr->OrigRDLen = rr->resrec.rdlength;
4816 rr->InFlightRData = rr->NewRData;
4817 rr->InFlightRDLen = rr->newrdlength;
4818 rr->NewRData = mDNSNULL;
4819 *stateptr = regState_UpdatePending;
4820 if (parent) SendServiceRegistration(m, parent);
4821 else SendRecordRegistration(m, rr);
4822 return mStatus_NoError;
4823
4824 case regState_NATError:
4825 LogMsg("ERROR: uDNS_UpdateRecord called for record %##s with bad state regState_NATError", rr->resrec.name->c);
4826 return mStatus_UnknownErr; // states for service records only
4827
4828 default: LogMsg("uDNS_UpdateRecord: Unknown state %d for %##s", *stateptr, rr->resrec.name->c);
4829 }
4830
4831 unreg_error:
4832 LogMsg("Requested update of record %##s type %d, part of service not currently registered",
4833 rr->resrec.name->c, rr->resrec.rrtype);
4834 return mStatus_Invalid;
4835 }
4836
4837 // ***************************************************************************
4838 #if COMPILER_LIKES_PRAGMA_MARK
4839 #pragma mark - Periodic Execution Routines
4840 #endif
4841
4842 // The question to be checked is not passed in as an explicit parameter;
4843 // instead it is implicit that the question to be checked is m->CurrentQuestion.
4844 mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
4845 {
4846 DNSQuestion *q = m->CurrentQuestion;
4847 mDNSs32 sendtime = q->LastQTime + q->ThisQInterval;
4848 // Don't allow sendtime to be earlier than SuppressStdPort53Queries
4849 if (!q->LongLived && m->SuppressStdPort53Queries && sendtime - m->SuppressStdPort53Queries < 0)
4850 sendtime = m->SuppressStdPort53Queries;
4851 if (m->timenow - sendtime < 0) return;
4852
4853 if (q->LongLived)
4854 {
4855 switch (q->state)
4856 {
4857 case LLQ_InitialRequest: startLLQHandshake(m, q); break;
4858 case LLQ_SecondaryRequest: sendChallengeResponse(m, q, mDNSNULL); break;
4859 case LLQ_Established: sendLLQRefresh(m, q); break;
4860 case LLQ_Poll: break; // Do nothing (handled below)
4861 }
4862 }
4863
4864 // We repeat the check above (rather than just making this the "else" case) because startLLQHandshake can change q->state to LLQ_Poll
4865 if (!(q->LongLived && q->state != LLQ_Poll))
4866 {
4867 if (q->unansweredQueries >= MAX_UCAST_UNANSWERED_QUERIES)
4868 {
4869 DNSServer *orig = q->qDNSServer;
4870 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);
4871
4872 PenalizeDNSServer(m, q, mDNStrue);
4873 }
4874
4875 if (q->qDNSServer && q->qDNSServer->teststate != DNSServer_Disabled)
4876 {
4877 mDNSu8 *end = m->omsg.data;
4878 mStatus err = mStatus_NoError;
4879 mDNSBool private = mDNSfalse;
4880
4881 InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
4882
4883 if (q->qDNSServer->teststate != DNSServer_Untested || NoTestQuery(q))
4884 {
4885 end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
4886 private = (q->AuthInfo && q->AuthInfo->AutoTunnel);
4887 }
4888 else if (m->timenow - q->qDNSServer->lasttest >= INIT_UCAST_POLL_INTERVAL) // Make sure at least three seconds has elapsed since last test query
4889 {
4890 LogInfo("Sending DNS test query to %#a:%d", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port));
4891 q->ThisQInterval = INIT_UCAST_POLL_INTERVAL / QuestionIntervalStep;
4892 q->qDNSServer->lasttest = m->timenow;
4893 end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, DNSRelayTestQuestion, kDNSType_PTR, kDNSClass_IN);
4894 q->qDNSServer->testid = m->omsg.h.id;
4895 }
4896
4897 if (end > m->omsg.data && (q->qDNSServer->teststate != DNSServer_Failed || NoTestQuery(q)))
4898 {
4899 //LogMsg("uDNS_CheckCurrentQuestion %p %d %p %##s (%s)", q, sendtime - m->timenow, private, q->qname.c, DNSTypeName(q->qtype));
4900 if (private)
4901 {
4902 if (q->nta) CancelGetZoneData(m, q->nta);
4903 q->nta = StartGetZoneData(m, &q->qname, q->LongLived ? ZoneServiceLLQ : ZoneServiceQuery, PrivateQueryGotZoneData, q);
4904 if (q->state == LLQ_Poll) q->ThisQInterval = (LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10)) / QuestionIntervalStep;
4905 }
4906 else
4907 {
4908 if (!q->LocalSocket) q->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort);
4909 if (!q->LocalSocket) err = mStatus_NoMemoryErr; // If failed to make socket (should be very rare), we'll try again next time
4910 else err = mDNSSendDNSMessage(m, &m->omsg, end, q->qDNSServer->interface, q->LocalSocket, &q->qDNSServer->addr, q->qDNSServer->port, mDNSNULL, mDNSNULL);
4911 m->SuppressStdPort53Queries = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+99)/100);
4912 }
4913 }
4914
4915 if (err) debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %d", err); // surpress syslog messages if we have no network
4916 else
4917 {
4918 q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep; // Only increase interval if send succeeded
4919 q->unansweredQueries++;
4920 if (q->ThisQInterval > MAX_UCAST_POLL_INTERVAL)
4921 q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
4922 if (private && q->state != LLQ_Poll)
4923 {
4924 // We don't want to retransmit too soon. Hence, we always schedule our first
4925 // retransmisson at 3 seconds rather than one second
4926 if (q->ThisQInterval < (3 * mDNSPlatformOneSecond))
4927 q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep;
4928 if (q->ThisQInterval > LLQ_POLL_INTERVAL)
4929 q->ThisQInterval = LLQ_POLL_INTERVAL;
4930 LogInfo("uDNS_CheckCurrentQuestion: private non polling question for %##s (%s) will be retried in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval);
4931 }
4932 debugf("Increased ThisQInterval to %d for %##s (%s)", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype));
4933 }
4934 q->LastQTime = m->timenow;
4935 SetNextQueryTime(m, q);
4936 }
4937 else
4938 {
4939 // If we have no server for this query, or the only server is a disabled one, then we deliver
4940 // a transient failure indication to the client. This is important for things like iPhone
4941 // where we want to return timely feedback to the user when no network is available.
4942 // After calling MakeNegativeCacheRecord() we store the resulting record in the
4943 // cache so that it will be visible to other clients asking the same question.
4944 // (When we have a group of identical questions, only the active representative of the group gets
4945 // passed to uDNS_CheckCurrentQuestion -- we only want one set of query packets hitting the wire --
4946 // but we want *all* of the questions to get answer callbacks.)
4947
4948 CacheRecord *rr;
4949 const mDNSu32 slot = HashSlot(&q->qname);
4950 CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
4951 if (cg)
4952 for (rr = cg->members; rr; rr=rr->next)
4953 if (SameNameRecordAnswersQuestion(&rr->resrec, q)) mDNS_PurgeCacheResourceRecord(m, rr);
4954
4955 if (!q->qDNSServer) LogInfo("uDNS_CheckCurrentQuestion no DNS server for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4956 else LogMsg("uDNS_CheckCurrentQuestion DNS server %#a:%d for %##s is disabled", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qname.c);
4957
4958 MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any);
4959 // Inactivate this question until the next change of DNS servers (do this before AnswerCurrentQuestionWithResourceRecord)
4960 q->ThisQInterval = 0;
4961 q->unansweredQueries = 0;
4962 CreateNewCacheEntry(m, slot, cg);
4963 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
4964 // MUST NOT touch m->CurrentQuestion (or q) after this -- client callback could have deleted it
4965 }
4966 }
4967 }
4968
4969 mDNSlocal void CheckNATMappings(mDNS *m)
4970 {
4971 mStatus err = mStatus_NoError;
4972 mDNSBool rfc1918 = mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4);
4973 mDNSBool HaveRoutable = !rfc1918 && !mDNSIPv4AddressIsZero(m->AdvertisedV4.ip.v4);
4974 m->NextScheduledNATOp = m->timenow + 0x3FFFFFFF;
4975
4976 if (HaveRoutable) m->ExternalAddress = m->AdvertisedV4.ip.v4;
4977
4978 if (m->NATTraversals && rfc1918) // Do we need to open NAT-PMP socket to receive multicast announcements from router?
4979 {
4980 if (m->NATMcastRecvskt == mDNSNULL) // If we are behind a NAT and the socket hasn't been opened yet, open it
4981 {
4982 // we need to log a message if we can't get our socket, but only the first time (after success)
4983 static mDNSBool needLog = mDNStrue;
4984 m->NATMcastRecvskt = mDNSPlatformUDPSocket(m, NATPMPAnnouncementPort);
4985 if (!m->NATMcastRecvskt)
4986 {
4987 if (needLog)
4988 {
4989 LogMsg("CheckNATMappings: Failed to allocate port 5350 UDP multicast socket for NAT-PMP announcements");
4990 needLog = mDNSfalse;
4991 }
4992 }
4993 else
4994 needLog = mDNStrue;
4995 }
4996 }
4997 else // else, we don't want to listen for announcements, so close them if they're open
4998 {
4999 if (m->NATMcastRecvskt) { mDNSPlatformUDPClose(m->NATMcastRecvskt); m->NATMcastRecvskt = mDNSNULL; }
5000 if (m->SSDPSocket) { debugf("CheckNATMappings destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
5001 }
5002
5003 if (m->NATTraversals)
5004 {
5005 if (m->timenow - m->retryGetAddr >= 0)
5006 {
5007 err = uDNS_SendNATMsg(m, mDNSNULL); // Will also do UPnP discovery for us, if necessary
5008 if (!err)
5009 {
5010 if (m->retryIntervalGetAddr < NATMAP_INIT_RETRY) m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
5011 else if (m->retryIntervalGetAddr < NATMAP_MAX_RETRY_INTERVAL / 2) m->retryIntervalGetAddr *= 2;
5012 else m->retryIntervalGetAddr = NATMAP_MAX_RETRY_INTERVAL;
5013 }
5014 LogInfo("CheckNATMappings retryGetAddr sent address request err %d interval %d", err, m->retryIntervalGetAddr);
5015
5016 // Always update m->retryGetAddr, even if we fail to send the packet. Otherwise in cases where we can't send the packet
5017 // (like when we have no active interfaces) we'll spin in an infinite loop repeatedly failing to send the packet
5018 m->retryGetAddr = m->timenow + m->retryIntervalGetAddr;
5019 }
5020 // Even when we didn't send the GetAddr packet, still need to make sure NextScheduledNATOp is set correctly
5021 if (m->NextScheduledNATOp - m->retryGetAddr > 0)
5022 m->NextScheduledNATOp = m->retryGetAddr;
5023 }
5024
5025 if (m->CurrentNATTraversal) LogMsg("WARNING m->CurrentNATTraversal already in use");
5026 m->CurrentNATTraversal = m->NATTraversals;
5027
5028 while (m->CurrentNATTraversal)
5029 {
5030 NATTraversalInfo *cur = m->CurrentNATTraversal;
5031 m->CurrentNATTraversal = m->CurrentNATTraversal->next;
5032
5033 if (HaveRoutable) // If not RFC 1918 address, our own address and port are effectively our external address and port
5034 {
5035 cur->ExpiryTime = 0;
5036 cur->NewResult = mStatus_NoError;
5037 }
5038 else if (cur->Protocol) // Check if it's time to send port mapping packets
5039 {
5040 if (m->timenow - cur->retryPortMap >= 0) // Time to do something with this mapping
5041 {
5042 if (cur->ExpiryTime && cur->ExpiryTime - m->timenow < 0) // Mapping has expired
5043 {
5044 cur->ExpiryTime = 0;
5045 cur->retryInterval = NATMAP_INIT_RETRY;
5046 }
5047
5048 //LogMsg("uDNS_SendNATMsg");
5049 err = uDNS_SendNATMsg(m, cur);
5050
5051 if (cur->ExpiryTime) // If have active mapping then set next renewal time halfway to expiry
5052 NATSetNextRenewalTime(m, cur);
5053 else // else no mapping; use exponential backoff sequence
5054 {
5055 if (cur->retryInterval < NATMAP_INIT_RETRY ) cur->retryInterval = NATMAP_INIT_RETRY;
5056 else if (cur->retryInterval < NATMAP_MAX_RETRY_INTERVAL / 2) cur->retryInterval *= 2;
5057 else cur->retryInterval = NATMAP_MAX_RETRY_INTERVAL;
5058 cur->retryPortMap = m->timenow + cur->retryInterval;
5059 }
5060 }
5061
5062 if (m->NextScheduledNATOp - cur->retryPortMap > 0)
5063 m->NextScheduledNATOp = cur->retryPortMap;
5064 }
5065
5066 // Notify the client if necessary. We invoke the callback if:
5067 // (1) we have an ExternalAddress, or we've tried and failed a couple of times to discover it
5068 // 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
5069 // and (3) we have new data to give the client that's changed since the last callback
5070 if (!mDNSIPv4AddressIsZero(m->ExternalAddress) || m->retryIntervalGetAddr > NATMAP_INIT_RETRY * 8)
5071 {
5072 const mStatus EffectiveResult = cur->NewResult ? cur->NewResult : mDNSv4AddrIsRFC1918(&m->ExternalAddress) ? mStatus_DoubleNAT : mStatus_NoError;
5073 const mDNSIPPort ExternalPort = HaveRoutable ? cur->IntPort :
5074 !mDNSIPv4AddressIsZero(m->ExternalAddress) && cur->ExpiryTime ? cur->RequestedPort : zeroIPPort;
5075 if (!cur->Protocol || HaveRoutable || cur->ExpiryTime || cur->retryInterval > NATMAP_INIT_RETRY * 8)
5076 if (!mDNSSameIPv4Address(cur->ExternalAddress, m->ExternalAddress) ||
5077 !mDNSSameIPPort (cur->ExternalPort, ExternalPort) ||
5078 cur->Result != EffectiveResult)
5079 {
5080 //LogMsg("NAT callback %d %d %d", cur->Protocol, cur->ExpiryTime, cur->retryInterval);
5081 if (cur->Protocol && mDNSIPPortIsZero(ExternalPort) && !mDNSIPv4AddressIsZero(m->Router.ip.v4))
5082 {
5083 if (!EffectiveResult)
5084 LogInfo("Failed to obtain NAT port mapping %p from router %#a external address %.4a internal port %5d interval %d error %d",
5085 cur, &m->Router, &m->ExternalAddress, mDNSVal16(cur->IntPort), cur->retryInterval, EffectiveResult);
5086 else
5087 LogMsg("Failed to obtain NAT port mapping %p from router %#a external address %.4a internal port %5d interval %d error %d",
5088 cur, &m->Router, &m->ExternalAddress, mDNSVal16(cur->IntPort), cur->retryInterval, EffectiveResult);
5089 }
5090
5091 cur->ExternalAddress = m->ExternalAddress;
5092 cur->ExternalPort = ExternalPort;
5093 cur->Lifetime = cur->ExpiryTime && !mDNSIPPortIsZero(ExternalPort) ?
5094 (cur->ExpiryTime - m->timenow + mDNSPlatformOneSecond/2) / mDNSPlatformOneSecond : 0;
5095 cur->Result = EffectiveResult;
5096 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
5097 if (cur->clientCallback)
5098 cur->clientCallback(m, cur);
5099 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
5100 // MUST NOT touch cur after invoking the callback
5101 }
5102 }
5103 }
5104 }
5105
5106 mDNSlocal mDNSs32 CheckRecordRegistrations(mDNS *m)
5107 {
5108 AuthRecord *rr;
5109 mDNSs32 nextevent = m->timenow + 0x3FFFFFFF;
5110
5111 for (rr = m->ResourceRecords; rr; rr = rr->next)
5112 {
5113 if (rr->state == regState_FetchingZoneData ||
5114 rr->state == regState_Pending || rr->state == regState_DeregPending || rr->state == regState_UpdatePending ||
5115 rr->state == regState_DeregDeferred || rr->state == regState_Refresh || rr->state == regState_Registered)
5116 {
5117 if (rr->LastAPTime + rr->ThisAPInterval - m->timenow < 0)
5118 {
5119 if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
5120 if (rr->state == regState_FetchingZoneData)
5121 {
5122 if (rr->nta) CancelGetZoneData(m, rr->nta);
5123 rr->nta = StartGetZoneData(m, rr->resrec.name, ZoneServiceUpdate, RecordRegistrationGotZoneData, rr);
5124 SetRecordRetry(m, rr, mStatus_NoError);
5125 }
5126 else if (rr->state == regState_DeregPending) SendRecordDeregistration(m, rr);
5127 else SendRecordRegistration(m, rr);
5128 }
5129 if (nextevent - (rr->LastAPTime + rr->ThisAPInterval) > 0)
5130 nextevent = (rr->LastAPTime + rr->ThisAPInterval);
5131 }
5132 }
5133 return nextevent;
5134 }
5135
5136 mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m)
5137 {
5138 mDNSs32 nextevent = m->timenow + 0x3FFFFFFF;
5139
5140 if (CurrentServiceRecordSet)
5141 LogMsg("CheckServiceRegistrations ERROR CurrentServiceRecordSet already set");
5142 CurrentServiceRecordSet = m->ServiceRegistrations;
5143
5144 // Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery
5145 while (CurrentServiceRecordSet)
5146 {
5147 ServiceRecordSet *srs = CurrentServiceRecordSet;
5148 CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next;
5149 if (srs->state == regState_FetchingZoneData ||
5150 srs->state == regState_Pending || srs->state == regState_DeregPending || srs->state == regState_DeregDeferred ||
5151 srs->state == regState_Refresh || srs->state == regState_UpdatePending || srs->state == regState_Registered)
5152 {
5153 if (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval - m->timenow <= 0)
5154 {
5155 if (srs->tcp) { DisposeTCPConn(srs->tcp); srs->tcp = mDNSNULL; }
5156 if (srs->state == regState_FetchingZoneData)
5157 {
5158 if (srs->srs_nta) CancelGetZoneData(m, srs->srs_nta);
5159 srs->srs_nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs);
5160 SetRecordRetry(m, &srs->RR_SRV, mStatus_NoError);
5161 }
5162 else if (srs->state == regState_DeregPending) SendServiceDeregistration(m, srs);
5163 else SendServiceRegistration(m, srs);
5164 }
5165 if (nextevent - (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval) > 0)
5166 nextevent = (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval);
5167 }
5168 }
5169 return nextevent;
5170 }
5171
5172 // This function is called early on in mDNS_Execute before any uDNS questions are
5173 // dispatched so that if there are some good servers, the uDNS questions can now
5174 // use it
5175 mDNSexport void ResetDNSServerPenalties(mDNS *m)
5176 {
5177 DNSServer *d;
5178 for (d = m->DNSServers; d; d=d->next)
5179 {
5180 if (d->penaltyTime != 0)
5181 {
5182 if (d->penaltyTime - m->timenow <= 0)
5183 {
5184 LogInfo("ResetDNSServerPenalties: DNS server %#a:%d out of penalty box", &d->addr, mDNSVal16(d->port));
5185 d->penaltyTime = 0;
5186 }
5187 }
5188 }
5189 }
5190
5191 mDNSlocal mDNSs32 CheckDNSServerPenalties(mDNS *m)
5192 {
5193 mDNSs32 nextevent = m->timenow + 0x3FFFFFFF;
5194 DNSServer *d;
5195 for (d = m->DNSServers; d; d=d->next)
5196 {
5197 if (d->penaltyTime != 0)
5198 {
5199 if ((nextevent - d->penaltyTime) > 0)
5200 nextevent = d->penaltyTime;
5201 }
5202 }
5203 return nextevent;
5204 }
5205
5206 mDNSexport void uDNS_Execute(mDNS *const m)
5207 {
5208 mDNSs32 nexte;
5209
5210 m->NextuDNSEvent = m->timenow + 0x3FFFFFFF;
5211
5212 if (m->NextSRVUpdate && m->NextSRVUpdate - m->timenow < 0)
5213 { m->NextSRVUpdate = 0; UpdateSRVRecords(m); }
5214
5215 CheckNATMappings(m);
5216
5217 if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0)
5218 m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it
5219
5220 nexte = CheckRecordRegistrations(m);
5221 if (nexte - m->NextuDNSEvent < 0) m->NextuDNSEvent = nexte;
5222
5223 nexte = CheckServiceRegistrations(m);
5224 if (nexte - m->NextuDNSEvent < 0) m->NextuDNSEvent = nexte;
5225
5226 nexte = CheckDNSServerPenalties(m);
5227 if (nexte - m->NextuDNSEvent < 0) m->NextuDNSEvent = nexte;
5228 }
5229
5230 // ***************************************************************************
5231 #if COMPILER_LIKES_PRAGMA_MARK
5232 #pragma mark - Startup, Shutdown, and Sleep
5233 #endif
5234
5235 // simplest sleep logic - rather than having sleep states that must be dealt with explicitly in all parts of
5236 // the code, we simply send a deregistration, and put the service in Refresh state, with a timeout far enough
5237 // in the future that we'll sleep (or the sleep will be cancelled) before it is retransmitted. Then to wake,
5238 // we just move up the timers.
5239
5240 mDNSexport void SleepRecordRegistrations(mDNS *m)
5241 {
5242 AuthRecord *rr;
5243 for (rr = m->ResourceRecords; rr; rr=rr->next)
5244 if (AuthRecord_uDNS(rr))
5245 if (rr->state == regState_Registered ||
5246 rr->state == regState_Refresh)
5247 {
5248 SendRecordDeregistration(m, rr);
5249 rr->state = regState_Refresh;
5250 rr->LastAPTime = m->timenow;
5251 rr->ThisAPInterval = 300 * mDNSPlatformOneSecond;
5252 }
5253 }
5254
5255 mDNSexport void SleepServiceRegistrations(mDNS *m)
5256 {
5257 ServiceRecordSet *srs = m->ServiceRegistrations;
5258 while (srs)
5259 {
5260 LogInfo("SleepServiceRegistrations: state %d %s", srs->state, ARDisplayString(m, &srs->RR_SRV));
5261 if (srs->srs_nta) { CancelGetZoneData(m, srs->srs_nta); srs->srs_nta = mDNSNULL; }
5262
5263 if (srs->NATinfo.clientContext)
5264 {
5265 mDNS_StopNATOperation_internal(m, &srs->NATinfo);
5266 srs->NATinfo.clientContext = mDNSNULL;
5267 }
5268
5269 if (srs->state == regState_UpdatePending)
5270 {
5271 // act as if the update succeeded, since we're about to delete the name anyway
5272 AuthRecord *txt = &srs->RR_TXT;
5273 srs->state = regState_Registered;
5274 // deallocate old RData
5275 if (txt->UpdateCallback) txt->UpdateCallback(m, txt, txt->OrigRData);
5276 SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen);
5277 txt->OrigRData = mDNSNULL;
5278 txt->InFlightRData = mDNSNULL;
5279 }
5280
5281 if (srs->state == regState_Registered || srs->state == regState_Refresh)
5282 SendServiceDeregistration(m, srs);
5283
5284 srs->state = regState_NoTarget; // when we wake, we'll re-register (and optionally nat-map) once our address record completes
5285 srs->RR_SRV.resrec.rdata->u.srv.target.c[0] = 0;
5286 srs->SRSUpdateServer = zeroAddr; // This will cause UpdateSRV to do a new StartGetZoneData
5287 srs->RR_SRV.ThisAPInterval = 5 * mDNSPlatformOneSecond; // After doubling, first retry will happen after ten seconds
5288
5289 srs = srs->uDNS_next;
5290 }
5291 }
5292
5293 mDNSexport void mDNS_AddSearchDomain(const domainname *const domain)
5294 {
5295 SearchListElem **p;
5296
5297 // Check to see if we already have this domain in our list
5298 for (p = &SearchList; *p; p = &(*p)->next)
5299 if (SameDomainName(&(*p)->domain, domain))
5300 {
5301 // If domain is already in list, and marked for deletion, change it to "leave alone"
5302 if ((*p)->flag == -1) (*p)->flag = 0;
5303 LogInfo("mDNS_AddSearchDomain already in list %##s", domain->c);
5304 return;
5305 }
5306
5307 // if domain not in list, add to list, mark as add (1)
5308 *p = mDNSPlatformMemAllocate(sizeof(SearchListElem));
5309 if (!*p) { LogMsg("ERROR: mDNS_AddSearchDomain - malloc"); return; }
5310 mDNSPlatformMemZero(*p, sizeof(SearchListElem));
5311 AssignDomainName(&(*p)->domain, domain);
5312 (*p)->flag = 1; // add
5313 (*p)->next = mDNSNULL;
5314 LogInfo("mDNS_AddSearchDomain created new %##s", domain->c);
5315 }
5316
5317 mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
5318 {
5319 (void)m; // unused
5320 if (result == mStatus_MemFree) mDNSPlatformMemFree(rr->RecordContext);
5321 }
5322
5323 mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
5324 {
5325 SearchListElem *slElem = question->QuestionContext;
5326 mStatus err;
5327 const char *name;
5328
5329 if (answer->rrtype != kDNSType_PTR) return;
5330 if (answer->RecordType == kDNSRecordTypePacketNegative) return;
5331 if (answer->InterfaceID == mDNSInterface_LocalOnly) return;
5332
5333 if (question == &slElem->BrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowse];
5334 else if (question == &slElem->DefBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault];
5335 else if (question == &slElem->AutomaticBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseAutomatic];
5336 else if (question == &slElem->RegisterQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistration];
5337 else if (question == &slElem->DefRegisterQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistrationDefault];
5338 else { LogMsg("FoundDomain - unknown question"); return; }
5339
5340 LogInfo("FoundDomain: %p %s %s Q %##s A %s", answer->InterfaceID, AddRecord ? "Add" : "Rmv", name, question->qname.c, RRDisplayString(m, answer));
5341
5342 if (AddRecord)
5343 {
5344 ARListElem *arElem = mDNSPlatformMemAllocate(sizeof(ARListElem));
5345 if (!arElem) { LogMsg("ERROR: FoundDomain out of memory"); return; }
5346 mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, arElem);
5347 MakeDomainNameFromDNSNameString(&arElem->ar.namestorage, name);
5348 AppendDNSNameString (&arElem->ar.namestorage, "local");
5349 AssignDomainName(&arElem->ar.resrec.rdata->u.name, &answer->rdata->u.name);
5350 LogInfo("FoundDomain: Registering %s", ARDisplayString(m, &arElem->ar));
5351 err = mDNS_Register(m, &arElem->ar);
5352 if (err) { LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err); mDNSPlatformMemFree(arElem); return; }
5353 arElem->next = slElem->AuthRecs;
5354 slElem->AuthRecs = arElem;
5355 }
5356 else
5357 {
5358 ARListElem **ptr = &slElem->AuthRecs;
5359 while (*ptr)
5360 {
5361 if (SameDomainName(&(*ptr)->ar.resrec.rdata->u.name, &answer->rdata->u.name))
5362 {
5363 ARListElem *dereg = *ptr;
5364 *ptr = (*ptr)->next;
5365 LogInfo("FoundDomain: Deregistering %s", ARDisplayString(m, &dereg->ar));
5366 err = mDNS_Deregister(m, &dereg->ar);
5367 if (err) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err);
5368 // Memory will be freed in the FreeARElemCallback
5369 }
5370 else
5371 ptr = &(*ptr)->next;
5372 }
5373 }
5374 }
5375
5376 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
5377 mDNSexport void udns_validatelists(void *const v)
5378 {
5379 mDNS *const m = v;
5380
5381 ServiceRecordSet *s;
5382 for (s = m->ServiceRegistrations; s; s=s->uDNS_next)
5383 if (s->uDNS_next == (ServiceRecordSet*)~0)
5384 LogMemCorruption("m->ServiceRegistrations: %p is garbage (%lX)", s, s->uDNS_next);
5385
5386 NATTraversalInfo *n;
5387 for (n = m->NATTraversals; n; n=n->next)
5388 if (n->next == (NATTraversalInfo *)~0 || n->clientCallback == (NATTraversalClientCallback)~0)
5389 LogMemCorruption("m->NATTraversals: %p is garbage", n);
5390
5391 DNSServer *d;
5392 for (d = m->DNSServers; d; d=d->next)
5393 if (d->next == (DNSServer *)~0 || d->teststate > DNSServer_Disabled)
5394 LogMemCorruption("m->DNSServers: %p is garbage (%d)", d, d->teststate);
5395
5396 DomainAuthInfo *info;
5397 for (info = m->AuthInfoList; info; info = info->next)
5398 if (info->next == (DomainAuthInfo *)~0 || info->AutoTunnel == (mDNSBool)~0)
5399 LogMemCorruption("m->AuthInfoList: %p is garbage (%X)", info, info->AutoTunnel);
5400
5401 HostnameInfo *hi;
5402 for (hi = m->Hostnames; hi; hi = hi->next)
5403 if (hi->next == (HostnameInfo *)~0 || hi->StatusCallback == (mDNSRecordCallback*)~0)
5404 LogMemCorruption("m->Hostnames: %p is garbage", n);
5405
5406 SearchListElem *ptr;
5407 for (ptr = SearchList; ptr; ptr = ptr->next)
5408 if (ptr->next == (SearchListElem *)~0 || ptr->AuthRecs == (void*)~0)
5409 LogMemCorruption("SearchList: %p is garbage (%X)", ptr, ptr->AuthRecs);
5410 }
5411 #endif
5412
5413 // This should probably move to the UDS daemon -- the concept of legacy clients and automatic registration / automatic browsing
5414 // is really a UDS API issue, not something intrinsic to uDNS
5415
5416 mDNSexport mStatus uDNS_RegisterSearchDomains(mDNS *const m)
5417 {
5418 SearchListElem **p = &SearchList, *ptr;
5419 mStatus err;
5420
5421 // step 1: mark each element for removal (-1)
5422 for (ptr = SearchList; ptr; ptr = ptr->next) ptr->flag = -1;
5423
5424 // Client has requested domain enumeration or automatic browse -- time to make sure we have the search domains from the platform layer
5425 mDNS_Lock(m);
5426 m->RegisterSearchDomains = mDNStrue;
5427 mDNSPlatformSetDNSConfig(m, mDNSfalse, m->RegisterSearchDomains, mDNSNULL, mDNSNULL, mDNSNULL);
5428 mDNS_Unlock(m);
5429
5430 // delete elems marked for removal, do queries for elems marked add
5431 while (*p)
5432 {
5433 ptr = *p;
5434 LogInfo("RegisterSearchDomains %d %p %##s", ptr->flag, ptr->AuthRecs, ptr->domain.c);
5435 if (ptr->flag == -1) // remove
5436 {
5437 ARListElem *arList = ptr->AuthRecs;
5438 ptr->AuthRecs = mDNSNULL;
5439 *p = ptr->next;
5440
5441 // If the user has "local" in their DNS searchlist, we ignore that for the purposes of domain enumeration queries
5442 if (!SameDomainName(&ptr->domain, &localdomain))
5443 {
5444 mDNS_StopGetDomains(m, &ptr->BrowseQ);
5445 mDNS_StopGetDomains(m, &ptr->RegisterQ);
5446 mDNS_StopGetDomains(m, &ptr->DefBrowseQ);
5447 mDNS_StopGetDomains(m, &ptr->DefRegisterQ);
5448 mDNS_StopGetDomains(m, &ptr->AutomaticBrowseQ);
5449 }
5450 mDNSPlatformMemFree(ptr);
5451
5452 // deregister records generated from answers to the query
5453 while (arList)
5454 {
5455 ARListElem *dereg = arList;
5456 arList = arList->next;
5457 debugf("Deregistering PTR %##s -> %##s", dereg->ar.resrec.name->c, dereg->ar.resrec.rdata->u.name.c);
5458 err = mDNS_Deregister(m, &dereg->ar);
5459 if (err) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err);
5460 // Memory will be freed in the FreeARElemCallback
5461 }
5462 continue;
5463 }
5464
5465 if (ptr->flag == 1) // add
5466 {
5467 // If the user has "local" in their DNS searchlist, we ignore that for the purposes of domain enumeration queries
5468 if (!SameDomainName(&ptr->domain, &localdomain))
5469 {
5470 mStatus err1, err2, err3, err4, err5;
5471 err1 = mDNS_GetDomains(m, &ptr->BrowseQ, mDNS_DomainTypeBrowse, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
5472 err2 = mDNS_GetDomains(m, &ptr->DefBrowseQ, mDNS_DomainTypeBrowseDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
5473 err3 = mDNS_GetDomains(m, &ptr->RegisterQ, mDNS_DomainTypeRegistration, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
5474 err4 = mDNS_GetDomains(m, &ptr->DefRegisterQ, mDNS_DomainTypeRegistrationDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
5475 err5 = mDNS_GetDomains(m, &ptr->AutomaticBrowseQ, mDNS_DomainTypeBrowseAutomatic, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
5476 if (err1 || err2 || err3 || err4 || err5)
5477 LogMsg("GetDomains for domain %##s returned error(s):\n"
5478 "%d (mDNS_DomainTypeBrowse)\n"
5479 "%d (mDNS_DomainTypeBrowseDefault)\n"
5480 "%d (mDNS_DomainTypeRegistration)\n"
5481 "%d (mDNS_DomainTypeRegistrationDefault)"
5482 "%d (mDNS_DomainTypeBrowseAutomatic)\n",
5483 ptr->domain.c, err1, err2, err3, err4, err5);
5484 }
5485 ptr->flag = 0;
5486 }
5487
5488 if (ptr->flag) { LogMsg("RegisterSearchDomains - unknown flag %d. Skipping.", ptr->flag); }
5489
5490 p = &ptr->next;
5491 }
5492
5493 return mStatus_NoError;
5494 }
5495
5496 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
5497 // 1) query for b._dns-sd._udp.local on LocalOnly interface
5498 // (.local manually generated via explicit callback)
5499 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
5500 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
5501 // 4) result above should generate a callback from question in (1). result added to global list
5502 // 5) global list delivered to client via GetSearchDomainList()
5503 // 6) client calls to enumerate domains now go over LocalOnly interface
5504 // (!!!KRS may add outgoing interface in addition)
5505
5506 struct CompileTimeAssertionChecks_uDNS
5507 {
5508 // Check our structures are reasonable sizes. Including overly-large buffers, or embedding
5509 // other overly-large structures instead of having a pointer to them, can inadvertently
5510 // cause structure sizes (and therefore memory usage) to balloon unreasonably.
5511 char sizecheck_tcpInfo_t [(sizeof(tcpInfo_t) <= 9056) ? 1 : -1];
5512 char sizecheck_SearchListElem[(sizeof(SearchListElem) <= 3920) ? 1 : -1];
5513 };