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