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