1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 Change History (most recent first):
20 Revision 1.230.2.1 2006/08/29 06:24:23 cheshire
21 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
23 Revision 1.230 2006/06/29 03:02:44 cheshire
24 <rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
26 Revision 1.229 2006/03/02 22:03:41 cheshire
27 <rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
28 Refinement: m->rec.r.resrec.RecordType needs to be cleared *every* time around for loop, not just once at the end
30 Revision 1.228 2006/02/26 00:54:42 cheshire
31 Fixes to avoid code generation warning/error on FreeBSD 7
33 Revision 1.227 2006/01/09 20:47:05 cheshire
34 <rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
36 Revision 1.226 2005/12/20 02:46:33 cheshire
37 <rdar://problem/4175520> mDNSPosix wide-area registration broken
38 Check too strict -- we can still do wide-area registration (without NAT-PMP)
39 without having to know our gateway address
41 Revision 1.225 2005/10/21 22:51:17 cheshire
42 <rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code
43 Refinement: Shorten "check-for-broken-dns-relay" to just "dnsbugtest"
44 to avoid crashing NAT gateways that have a different DNS relay bug
46 Revision 1.224 2005/10/20 00:10:33 cheshire
47 <rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code
49 Revision 1.223 2005/10/17 18:52:42 cheshire
50 <rdar://problem/4271183> mDNSResponder crashed in CheckRecordRegistrations
51 Move code to unregister the service's extra records from uDNS_DeregisterService() to unlinkSRS().
53 Revision 1.222 2005/10/05 23:04:10 cheshire
54 Add more information to unlinkAR and startLLQHandshakeCallback error messages
56 Revision 1.221 2005/10/05 17:27:48 herscher
57 <rdar://problem/4272516> Change 200ms delay to 10ms
59 Revision 1.220 2005/09/24 01:10:09 cheshire
62 Revision 1.219 2005/09/22 07:28:25 herscher
63 Double the delay to 200000 usec after sending out a DNS query
65 Revision 1.218 2005/09/13 01:06:14 herscher
66 <rdar://problem/4248878> Add 100ms delay in sendQuery.
68 Revision 1.217 2005/08/04 18:08:24 cheshire
71 Revision 1.216 2005/07/29 23:05:22 ksekar
72 <rdar://problem/4137930> Hostname registration should register IPv6 AAAA record with DNS Update
73 Services should point to IPv6 address if IPv4 NAT mapping fails
75 Revision 1.215 2005/07/29 21:01:51 ksekar
76 <rdar://problem/4137930> Hostname registration should register IPv6 AAAA record with DNS Update
77 correction to original checkin - misplaced return in HostnameCallback and logic error determining v6 changes
79 Revision 1.214 2005/07/29 19:46:10 ksekar
80 <rdar://problem/4191860> reduce polling period on failed LLQs to 15 minutes
82 Revision 1.213 2005/07/29 18:04:22 ksekar
83 <rdar://problem/4137930> Hostname registration should register IPv6 AAAA record with DNS Update
85 Revision 1.212 2005/07/22 19:35:50 ksekar
86 <rdar://problem/4188821> SUTiger: LLQ event acknowledgments are not formated correctly
88 Revision 1.211 2005/07/21 18:51:04 ksekar
89 <rdar://problem/4103136> mDNSResponder times out when mapping ports after sleep
91 Revision 1.210 2005/07/21 18:47:31 ksekar
92 <rdar://problem/4137283> NAT-PMP refresh Requested Public Port should contain actual mapped port
94 Revision 1.209 2005/07/04 21:16:37 cheshire
95 Minor code tidying -- initialize variables where they are declared
97 Revision 1.208 2005/06/28 00:24:28 ksekar
98 <rdar://problem/4157823> memory smasher in conQueryCallback
100 Revision 1.207 2005/05/13 20:45:10 ksekar
101 <rdar://problem/4074400> Rapid wide-area txt record updates don't work
103 Revision 1.206 2005/03/31 02:19:55 cheshire
104 <rdar://problem/4021486> Fix build warnings
105 Reviewed by: Scott Herscher
107 Revision 1.205 2005/03/21 00:33:51 shersche
108 <rdar://problem/4021486> Fix build warnings on Win32 platform
110 Revision 1.204 2005/03/16 00:42:32 ksekar
111 <rdar://problem/4012279> Long-lived queries not working on Windows
113 Revision 1.203 2005/03/04 03:00:03 ksekar
114 <rdar://problem/4026546> Retransmissions happen too early, causing registrations to conflict with themselves
116 Revision 1.202 2005/03/01 19:29:17 ksekar
117 changed LogMsgs to debugfs
119 Revision 1.201 2005/02/26 03:04:13 cheshire
120 <rdar://problem/4017292> Should not indicate successful dynamic update if no network connection
121 Don't try to do updates to root name server. This ensures status dot turns red if user
122 enters a bad host name such as just "fred" instead of a properly fully-qualified name.
124 Revision 1.200 2005/02/25 17:47:45 ksekar
125 <rdar://problem/4021868> SendServiceRegistration fails on wake from sleep
127 Revision 1.199 2005/02/25 04:21:00 cheshire
128 <rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing
130 Revision 1.198 2005/02/25 02:35:22 cheshire
131 <rdar://problem/4017292> Should not indicate successful dynamic update if no network connection
132 If we get NXDomain error looking for the _dns-update._udp record,
133 update status from 1 (in progress) to mStatus_NoSuchNameErr (failed)
135 Revision 1.197 2005/02/24 21:56:59 ksekar
136 Change LogMsgs to debugfs
138 Revision 1.196 2005/02/24 21:52:28 ksekar
139 <rdar://problem/3922768> Remove "deferred deregistration" logic for hostnames
141 Revision 1.195 2005/02/22 17:53:08 ksekar
142 Changed successful NAT Traversals from LogMsg to LogOperation
144 Revision 1.194 2005/02/15 18:38:03 ksekar
145 <rdar://problem/3967876> change expected/redundant log messages to debugfs.
147 Revision 1.193 2005/02/15 01:17:48 ksekar
150 Revision 1.192 2005/02/14 23:01:28 ksekar
151 Refinement to previous checkin - don't log bad LLQ opcode if we had to send the request more than once.
153 Revision 1.191 2005/02/14 18:26:51 ksekar
154 <rdar://problem/4005569> mDNSResponder complains about bad LLQ Opcode 2
156 Revision 1.190 2005/02/11 19:44:06 shersche
157 Remove extra semicolon at end of line
159 Revision 1.189 2005/02/10 21:07:02 ksekar
160 Don't goto error in ReceiveNATAddrResponse if we receive a malformatted response
162 Revision 1.188 2005/02/10 02:02:44 ksekar
163 Remove double semi-colon
165 Revision 1.187 2005/02/09 23:28:01 ksekar
166 <rdar://problem/3984374> NAT-PMP response callback should return a
167 boolean indicating if the packet matched the request
169 Revision 1.186 2005/02/04 21:56:29 ksekar
170 <rdar://problem/3984374> Simultaneous port map requests sometimes fail
171 - Refinement to previous checkin.
173 Revision 1.185 2005/02/03 23:48:22 ksekar
174 <rdar://problem/3984374> Simultaneous port map requests sometimes fail
176 Revision 1.184 2005/02/01 19:33:29 ksekar
177 <rdar://problem/3985239> Keychain format too restrictive
179 Revision 1.183 2005/01/27 22:57:55 cheshire
180 Fix compile errors on gcc4
182 Revision 1.182 2005/01/25 18:55:05 ksekar
183 Shortened log message
185 Revision 1.181 2005/01/25 02:17:32 cheshire
186 <rdar://problem/3971263> Don't use query ID zero in uDNS queries
188 Revision 1.180 2005/01/19 21:01:54 ksekar
189 <rdar://problem/3955355> uDNS needs to support subtype registration and browsing
191 Revision 1.179 2005/01/19 19:15:35 ksekar
192 Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
194 Revision 1.178 2005/01/17 23:47:58 cheshire
195 <rdar://problem/3904954> Wide-area services not found on little-endian
197 Revision 1.177 2005/01/17 23:41:26 cheshire
200 Revision 1.176 2005/01/17 21:03:04 cheshire
201 <rdar://problem/3904954> Wide-area services not found on little-endian
203 Revision 1.175 2005/01/15 00:56:41 ksekar
204 <rdar://problem/3954575> Unicast services don't disappear when logging
207 Revision 1.174 2005/01/14 18:44:28 ksekar
208 <rdar://problem/3954609> mDNSResponder is crashing when changing domains
210 Revision 1.173 2005/01/14 18:34:22 ksekar
211 <rdar://problem/3954571> Services registered outside of firewall don't succeed after location change
213 Revision 1.172 2005/01/11 22:50:52 ksekar
214 Fixed constant naming (was using kLLQ_DefLease for update leases)
216 Revision 1.171 2005/01/10 04:52:49 ksekar
217 Changed LogMsg to debugf
219 Revision 1.170 2005/01/08 00:50:05 ksekar
220 Fixed spelling mistake in log msg
222 Revision 1.169 2005/01/08 00:42:18 ksekar
223 <rdar://problem/3922758> Clean up syslog messages
225 Revision 1.168 2004/12/23 23:22:47 ksekar
226 <rdar://problem/3933606> Unicast known answers "name" pointers point to garbage stack memory
228 Revision 1.167 2004/12/22 22:25:47 ksekar
229 <rdar://problem/3734265> NATPMP: handle location changes
231 Revision 1.166 2004/12/22 00:04:12 ksekar
232 <rdar://problem/3930324> mDNSResponder crashing in ReceivePortMapReply
234 Revision 1.165 2004/12/18 03:14:22 cheshire
237 Revision 1.164 2004/12/17 03:55:40 ksekar
238 Don't use -1 as special meaning for expiration timer (it is a valid
239 value, and is redundant with our state variables)
241 Revision 1.163 2004/12/17 03:51:53 ksekar
242 <rdar://problem/3920991> Don't update TXT record if service registration fails
244 Revision 1.162 2004/12/17 01:29:11 ksekar
245 <rdar://problem/3920598> Questions can go deaf on location changes
247 Revision 1.161 2004/12/16 20:42:02 cheshire
248 Fix compiler warnings
250 Revision 1.160 2004/12/16 20:13:00 cheshire
251 <rdar://problem/3324626> Cache memory management improvements
253 Revision 1.159 2004/12/15 02:11:22 ksekar
254 <rdar://problem/3917317> Don't check for Dynamic DNS hostname uniqueness
256 Revision 1.158 2004/12/15 02:04:28 ksekar
257 Refinement to previous checkin - we should still return NatTraversal error when the port mapping fails
259 Revision 1.157 2004/12/15 01:39:21 ksekar
260 Refinement to previous checkin - we should still return NatTraversal error when the port mapping fails
262 Revision 1.156 2004/12/15 01:18:57 ksekar
263 <rdar://problem/3825979> Call DeregisterService on nat port map failure
265 Revision 1.155 2004/12/14 21:21:20 ksekar
266 <rdar://problem/3825979> NAT-PMP: Update response format to contain "Seconds Since Boot"
268 Revision 1.154 2004/12/14 20:52:27 cheshire
269 Add question->qnamehash and cr->resrec.namehash to log message
271 Revision 1.153 2004/12/14 20:45:02 cheshire
272 Improved error logging in "unexpected answer" message
274 Revision 1.152 2004/12/14 03:02:10 ksekar
275 <rdar://problem/3919016> Rare race condition can cause crash
277 Revision 1.151 2004/12/13 21:45:08 ksekar
278 uDNS_DeregisterService should return NoError if called twice (to follow mDNS behavior expected by daemon layer)
280 Revision 1.150 2004/12/13 20:42:41 ksekar
283 Revision 1.149 2004/12/13 18:10:03 ksekar
286 Revision 1.148 2004/12/13 01:18:04 ksekar
287 Fixed unused variable warning for non-debug builds
289 Revision 1.147 2004/12/12 23:51:42 ksekar
290 <rdar://problem/3845683> Wide-area registrations should fallback to using DHCP hostname as target
292 Revision 1.146 2004/12/12 23:30:40 ksekar
293 <rdar://problem/3916987> Extra RRs not properly unlinked when parent service registration fails
295 Revision 1.145 2004/12/12 22:56:29 ksekar
296 <rdar://problem/3668508> Need to properly handle duplicate long-lived queries
298 Revision 1.144 2004/12/11 20:55:29 ksekar
299 <rdar://problem/3916479> Clean up registration state machines
301 Revision 1.143 2004/12/10 01:21:27 cheshire
302 <rdar://problem/3914089> Get rid of "LLQ Responses over TCP not currently supported" message
304 Revision 1.142 2004/12/08 02:03:31 ksekar
305 <rdar://problem/3865124> Looping on NAT Traversal error - check for
308 Revision 1.141 2004/12/07 01:39:28 cheshire
309 Don't fail if the same server is responsible for more than one domain
310 (e.g. the same DNS server may be responsible for both apple.com. and 17.in-addr.arpa.)
312 Revision 1.140 2004/12/06 21:15:22 ksekar
313 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
315 Revision 1.139 2004/12/06 19:08:03 cheshire
316 Add clarifying comment -- CountLabels() excludes the final root label.
318 Revision 1.138 2004/12/06 01:45:54 ksekar
319 Correct wording in LogMsg
321 Revision 1.137 2004/12/03 20:40:35 ksekar
322 <rdar://problem/3865124> Looping on NAT Traversal error
324 Revision 1.136 2004/12/03 07:20:50 ksekar
325 <rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
327 Revision 1.135 2004/12/03 05:18:33 ksekar
328 <rdar://problem/3810596> mDNSResponder needs to return more specific TSIG errors
330 Revision 1.134 2004/12/02 20:03:49 ksekar
331 <rdar://problem/3889647> Still publishes wide-area domains even after switching to a local subnet
333 Revision 1.133 2004/12/02 18:37:52 ksekar
334 <rdar://problem/3758233> Registering with port number zero should not create a port mapping
336 Revision 1.132 2004/12/01 20:57:19 ksekar
337 <rdar://problem/3873921> Wide Area Service Discovery must be split-DNS aware
339 Revision 1.131 2004/12/01 19:59:27 cheshire
340 <rdar://problem/3882643> Crash in mDNSPlatformTCPConnect
341 If a TCP response has the TC bit set, don't respond by just trying another TCP connection
343 Revision 1.130 2004/12/01 02:43:23 cheshire
344 Don't call StatusCallback if function pointer is null
346 Revision 1.129 2004/11/30 23:51:06 cheshire
347 Remove double semicolons
349 Revision 1.128 2004/11/25 01:48:30 ksekar
350 <rdar://problem/3878991> Logging into VPN does not trigger registration of address record
352 Revision 1.127 2004/11/25 01:41:36 ksekar
353 Changed unnecessary LogMsgs to debugfs
355 Revision 1.126 2004/11/23 23:54:17 ksekar
356 <rdar://problem/3890318> Wide-Area DNSServiceRegisterRecord() failures
357 can crash mDNSResponder
359 Revision 1.125 2004/11/23 04:16:48 cheshire
360 Removed receiveMsg() routine.
362 Revision 1.124 2004/11/23 04:06:51 cheshire
363 Get rid of floating point constant -- in a small embedded device, bringing in all
364 the floating point libraries just to halve an integer value is a bit too heavyweight.
366 Revision 1.123 2004/11/22 17:16:20 ksekar
367 <rdar://problem/3854298> Unicast services don't disappear when you disable all networking
369 Revision 1.122 2004/11/19 18:00:34 ksekar
370 <rdar://problem/3682646> Security: use random ID for one-shot unicast queries
372 Revision 1.121 2004/11/19 04:24:08 ksekar
373 <rdar://problem/3682609> Security: Enforce a "window" on one-shot wide-area queries
375 Revision 1.120 2004/11/19 02:32:43 ksekar
376 <rdar://problem/3682608> Wide-Area Security: Add LLQ-ID to events
378 Revision 1.119 2004/11/18 23:21:24 ksekar
379 <rdar://problem/3764544> LLQ Security: Need to verify src port/address for LLQ handshake
381 Revision 1.118 2004/11/18 22:58:37 ksekar
384 Revision 1.117 2004/11/18 18:04:21 ksekar
385 Restore checkins lost due to repository disk failure: Update comments & <rdar://problem/3880688>
387 Revision 1.xxx 2004/11/17 06:17:57 cheshire
388 Update comments to show correct SRV names: _dns-update._udp.<zone>. and _dns-llq._udp.<zone>.
390 Revision 1.xxx 2004/11/17 00:45:28 ksekar
391 <rdar://problem/3880688> Result of putUpdateLease not error-checked
393 Revision 1.116 2004/11/16 01:41:47 ksekar
396 Revision 1.115 2004/11/15 20:09:24 ksekar
397 <rdar://problem/3719050> Wide Area support for Add/Remove record
399 Revision 1.114 2004/11/13 02:32:47 ksekar
400 <rdar://problem/3868216> LLQ mobility fragile on non-primary interface
401 - fixed incorrect state comparison in CheckQueries
403 Revision 1.113 2004/11/13 02:29:52 ksekar
404 <rdar://problem/3878386> LLQ refreshes not reliable
406 Revision 1.112 2004/11/11 20:45:14 ksekar
407 <rdar://problem/3876052> self-conflict test not compatible with some BIND servers
409 Revision 1.111 2004/11/11 20:14:55 ksekar
410 <rdar://problem/3719574> Wide-Area registrations not deregistered on sleep
412 Revision 1.110 2004/11/10 23:53:53 ksekar
413 Remove no longer relevant comment
415 Revision 1.109 2004/11/10 20:40:53 ksekar
416 <rdar://problem/3868216> LLQ mobility fragile on non-primary interface
418 Revision 1.108 2004/11/01 20:36:16 ksekar
419 <rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
421 Revision 1.107 2004/10/26 06:11:41 cheshire
422 Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
424 Revision 1.106 2004/10/26 03:52:03 cheshire
425 Update checkin comments
427 Revision 1.105 2004/10/26 01:15:06 cheshire
428 Use "#if 0" instead of commenting out code
430 Revision 1.104 2004/10/25 21:41:38 ksekar
431 <rdar://problem/3852958> wide-area name conflicts can cause crash
433 Revision 1.103 2004/10/25 19:30:52 ksekar
434 <rdar://problem/3827956> Simplify dynamic host name structures
436 Revision 1.102 2004/10/23 01:16:00 cheshire
437 <rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
439 Revision 1.101 2004/10/22 20:52:07 ksekar
440 <rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
442 Revision 1.100 2004/10/20 02:16:41 cheshire
443 Improve "could not confirm existence of NS record" error message
444 Don't call newRR->RecordCallback if it is NULL
446 Revision 1.99 2004/10/19 21:33:18 cheshire
447 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
448 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
449 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
451 Revision 1.98 2004/10/16 00:16:59 cheshire
452 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
454 Revision 1.97 2004/10/15 23:00:18 ksekar
455 <rdar://problem/3799242> Need to update LLQs on location changes
457 Revision 1.96 2004/10/12 23:30:44 ksekar
458 <rdar://problem/3609944> mDNSResponder needs to follow CNAME referrals
460 Revision 1.95 2004/10/12 03:15:09 ksekar
461 <rdar://problem/3835612> mDNS_StartQuery shouldn't return transient no-server error
463 Revision 1.94 2004/10/12 02:49:20 ksekar
464 <rdar://problem/3831228> Clean up LLQ sleep/wake, error handling
466 Revision 1.93 2004/10/08 04:17:25 ksekar
467 <rdar://problem/3831819> Don't use DNS extensions if the server does not advertise required SRV record
469 Revision 1.92 2004/10/08 03:54:35 ksekar
470 <rdar://problem/3831802> Refine unicast polling intervals
472 Revision 1.91 2004/09/30 17:45:34 ksekar
473 <rdar://problem/3821119> lots of log messages: mDNS_SetPrimaryIP: IP address unchanged
475 Revision 1.90 2004/09/25 00:22:13 ksekar
476 <rdar://problem/3815534> Crash in uDNS_RegisterService
478 Revision 1.89 2004/09/24 19:14:53 cheshire
479 Remove unused "extern mDNS mDNSStorage"
481 Revision 1.88 2004/09/23 20:48:15 ksekar
482 Clarify retransmission debugf messages.
484 Revision 1.87 2004/09/22 00:41:59 cheshire
485 Move tcp connection status codes into the legal range allocated for mDNS use
487 Revision 1.86 2004/09/21 23:40:11 ksekar
488 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
490 Revision 1.85 2004/09/21 22:38:27 ksekar
491 <rdar://problem/3810286> PrimaryIP type uninitialized
493 Revision 1.84 2004/09/18 00:30:39 cheshire
494 <rdar://problem/3806643> Infinite loop in CheckServiceRegistrations
496 Revision 1.83 2004/09/17 00:31:51 cheshire
497 For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
499 Revision 1.82 2004/09/16 21:36:36 cheshire
500 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
501 Changes to add necessary locking calls around unicast DNS operations
503 Revision 1.81 2004/09/16 02:29:39 cheshire
504 Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
505 uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
507 Revision 1.80 2004/09/16 01:58:21 cheshire
508 Fix compiler warnings
510 Revision 1.79 2004/09/16 00:24:48 cheshire
511 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
513 Revision 1.78 2004/09/15 01:16:57 ksekar
514 <rdar://problem/3797598> mDNSResponder printing too many messages
516 Revision 1.77 2004/09/14 23:27:47 cheshire
519 Revision 1.76 2004/09/14 22:22:00 ksekar
520 <rdar://problem/3800920> Legacy browses broken against some BIND versions
522 Revision 1.75 2004/09/03 19:23:05 ksekar
523 <rdar://problem/3788460>: Need retransmission mechanism for wide-area service registrations
525 Revision 1.74 2004/09/02 17:49:04 ksekar
526 <rdar://problem/3785135>: 8A246: mDNSResponder crash while logging on restart
527 Fixed incorrect conversions, changed %s to %##s for all domain names.
529 Revision 1.73 2004/09/02 01:39:40 cheshire
530 For better readability, follow consistent convention that QR bit comes first, followed by OP bits
532 Revision 1.72 2004/09/01 03:59:29 ksekar
533 <rdar://problem/3783453>: Conditionally compile out uDNS code on Windows
535 Revision 1.71 2004/08/27 17:51:53 ksekar
536 Replaced unnecessary LogMsg with debugf.
538 Revision 1.70 2004/08/25 00:37:27 ksekar
539 <rdar://problem/3774635>: Cleanup DynDNS hostname registration code
541 Revision 1.69 2004/08/18 17:35:41 ksekar
542 <rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
544 Revision 1.68 2004/08/14 03:22:41 cheshire
545 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
546 Add GetUserSpecifiedDDNSName() routine
547 Convert ServiceRegDomain to domainname instead of C string
548 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
550 Revision 1.67 2004/08/13 23:46:58 cheshire
551 "asyncronous" -> "asynchronous"
553 Revision 1.66 2004/08/13 23:37:02 cheshire
554 Now that we do both uDNS and mDNS, global replace "uDNS_info.hostname" with
555 "uDNS_info.UnicastHostname" for clarity
557 Revision 1.65 2004/08/13 23:12:32 cheshire
558 Don't use strcpy() and strlen() on "struct domainname" objects;
559 use AssignDomainName() and DomainNameLength() instead
560 (A "struct domainname" is a collection of packed pascal strings, not a C string.)
562 Revision 1.64 2004/08/13 23:01:05 cheshire
563 Use platform-independent mDNSNULL instead of NULL
565 Revision 1.63 2004/08/12 00:32:36 ksekar
566 <rdar://problem/3759567>: LLQ Refreshes never terminate if unanswered
568 Revision 1.62 2004/08/10 23:19:14 ksekar
569 <rdar://problem/3722542>: DNS Extension daemon for Wide Area Service Discovery
570 Moved routines/constants to allow extern access for garbage collection daemon
572 Revision 1.61 2004/07/30 17:40:06 ksekar
573 <rdar://problem/3739115>: TXT Record updates not available for wide-area services
575 Revision 1.60 2004/07/29 19:40:05 ksekar
576 NATPMP Support - minor fixes and cleanup
578 Revision 1.59 2004/07/29 19:27:15 ksekar
579 NATPMP Support - minor fixes and cleanup
581 Revision 1.58 2004/07/27 07:35:38 shersche
582 fix syntax error, variables declared in the middle of a block
584 Revision 1.57 2004/07/26 22:49:30 ksekar
585 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
587 Revision 1.56 2004/07/26 19:14:44 ksekar
588 <rdar://problem/3737814>: 8A210: mDNSResponder crashed in startLLQHandshakeCallback
590 Revision 1.55 2004/07/15 19:01:33 ksekar
591 <rdar://problem/3681029>: Check for incorrect time comparisons
593 Revision 1.54 2004/06/22 02:10:53 ksekar
594 <rdar://problem/3705433>: Lighthouse failure causes packet flood to DNS
596 Revision 1.53 2004/06/17 20:49:09 ksekar
597 <rdar://problem/3690436>: mDNSResponder crash while location cycling
599 Revision 1.52 2004/06/17 01:13:11 ksekar
600 <rdar://problem/3696616>: polling interval too short
602 Revision 1.51 2004/06/10 04:36:44 cheshire
605 Revision 1.50 2004/06/10 00:55:13 ksekar
606 <rdar://problem/3686213>: crash on network reconnect
608 Revision 1.49 2004/06/10 00:10:50 ksekar
609 <rdar://problem/3686174>: Infinite Loop in uDNS_Execute()
611 Revision 1.48 2004/06/09 20:03:37 ksekar
612 <rdar://problem/3686163>: Incorrect copying of resource record in deregistration
614 Revision 1.47 2004/06/09 03:48:28 ksekar
615 <rdar://problem/3685226>: nameserver address fails with prod. Lighthouse server
617 Revision 1.46 2004/06/09 01:44:30 ksekar
618 <rdar://problem/3681378> reworked Cache Record copy code
620 Revision 1.45 2004/06/08 18:54:47 ksekar
621 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
623 Revision 1.44 2004/06/05 00:33:51 cheshire
624 <rdar://problem/3681029>: Check for incorrect time comparisons
626 Revision 1.43 2004/06/05 00:14:44 cheshire
627 Fix signed/unsigned and other compiler warnings
629 Revision 1.42 2004/06/04 22:36:16 ksekar
630 Properly set u->nextevent in uDNS_Execute
632 Revision 1.41 2004/06/04 08:58:29 ksekar
633 <rdar://problem/3668624>: Keychain integration for secure dynamic update
635 Revision 1.40 2004/06/03 03:09:58 ksekar
636 <rdar://problem/3668626>: Garbage Collection for Dynamic Updates
638 Revision 1.39 2004/06/01 23:46:50 ksekar
639 <rdar://problem/3675149>: DynDNS: dynamically look up LLQ/Update ports
641 Revision 1.38 2004/05/31 22:19:44 ksekar
642 <rdar://problem/3258021>: Feature: DNS server->client notification on
643 record changes (#7805) - revert to polling mode on setup errors
645 Revision 1.37 2004/05/28 23:42:37 ksekar
646 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
648 Revision 1.36 2004/05/18 23:51:25 cheshire
649 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
651 Revision 1.35 2004/05/07 23:01:04 ksekar
652 Cleaned up list traversal in deriveGoodbyes - removed unnecessary
653 conditional assignment.
655 Revision 1.34 2004/05/05 18:26:12 ksekar
656 Periodically re-transmit questions if the send() fails. Include
657 internal questions in retransmission.
659 Revision 1.33 2004/05/05 17:40:06 ksekar
660 Removed prerequisite from deregistration update - it does not work for
661 shared records, and is unnecessary until we have more sophisticated
662 name conflict management.
664 Revision 1.32 2004/05/05 17:32:18 ksekar
665 Prevent registration of loopback interface caused by removal of
666 Multicast flag in interface structure.
668 Revision 1.31 2004/05/05 17:05:02 ksekar
669 Use LargeCacheRecord structs when pulling records off packets
671 Revision 1.30 2004/04/16 21:33:27 ksekar
672 Fixed bug in processing GetZoneData responses that do not use BIND formatting.
674 Revision 1.29 2004/04/15 20:03:13 ksekar
675 Clarified log message when pulling bad resource records off packet.
677 Revision 1.28 2004/04/15 00:51:28 bradley
678 Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers.
679 Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers.
681 Revision 1.27 2004/04/14 23:09:28 ksekar
682 Support for TSIG signed dynamic updates.
684 Revision 1.26 2004/04/14 19:36:05 ksekar
685 Fixed memory corruption error in deriveGoodbyes.
687 Revision 1.25 2004/04/14 04:07:11 ksekar
688 Fixed crash in IsActiveUnicastQuery(). Removed redundant checks in routine.
690 Revision 1.24 2004/04/08 09:41:40 bradley
691 Added const to AuthRecord in deadvertiseIfCallback to match callback typedef.
693 Revision 1.23 2004/03/24 00:29:45 ksekar
694 Make it safe to call StopQuery in a unicast question callback
696 Revision 1.22 2004/03/19 10:11:09 bradley
697 Added AuthRecord * cast from umalloc for C++ builds.
699 Revision 1.21 2004/03/15 02:03:45 bradley
700 Added const to params where needed to match prototypes. Changed SetNewRData calls to use 0 instead
701 of -1 for unused size to fix warning. Disable assignment within conditional warnings with Visual C++.
703 Revision 1.20 2004/03/13 02:07:26 ksekar
704 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
706 Revision 1.19 2004/03/13 01:57:33 ksekar
707 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
709 Revision 1.18 2004/02/21 08:34:15 bradley
710 Added casts from void * to specific type for C++ builds. Changed void * l-value cast
711 r-value cast to fix problems with VC++ builds. Removed empty switch to fix VC++ error.
713 Revision 1.17 2004/02/21 02:06:24 cheshire
714 Can't use anonymous unions -- they're non-standard and don't work on all compilers
716 Revision 1.16 2004/02/12 01:51:45 cheshire
717 Don't try to send uDNS queries unless we have at least one uDNS server available
719 Revision 1.15 2004/02/10 03:02:46 cheshire
722 Revision 1.14 2004/02/06 23:04:19 ksekar
723 Basic Dynamic Update support via mDNS_Register (dissabled via
724 UNICAST_REGISTRATION #define)
726 Revision 1.13 2004/02/03 22:15:01 ksekar
727 Fixed nameToAddr error check: don't abort state machine on nxdomain error.
729 Revision 1.12 2004/02/03 19:47:36 ksekar
730 Added an asynchronous state machine mechanism to uDNS.c, including
731 calls to find the parent zone for a domain name. Changes include code
732 in repository previously dissabled via "#if 0 incomplete". Codepath
733 is currently unused, and will be called to create update records, etc.
735 Revision 1.11 2004/01/30 02:12:30 ksekar
736 Changed uDNS_ReceiveMsg() to correctly return void.
738 Revision 1.10 2004/01/29 02:59:17 ksekar
739 Unicast DNS: Changed from a resource record oriented question/response
740 matching to packet based matching. New callback architecture allows
741 collections of records in a response to be processed differently
742 depending on the nature of the request, and allows the same structure
743 to be used for internal and client-driven queries with different processing needs.
745 Revision 1.9 2004/01/28 20:20:45 ksekar
746 Unified ActiveQueries and ActiveInternalQueries lists, using a flag to
747 demux them. Check-in includes work-in-progress code, #ifdef'd out.
749 Revision 1.8 2004/01/28 02:30:07 ksekar
750 Added default Search Domains to unicast browsing, controlled via
751 Networking sharing prefs pane. Stopped sending unicast messages on
752 every interface. Fixed unicast resolving via mach-port API.
754 Revision 1.7 2004/01/27 20:15:22 cheshire
755 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
757 Revision 1.6 2004/01/24 23:47:17 cheshire
758 Use mDNSOpaque16fromIntVal() instead of shifting and masking
760 Revision 1.5 2004/01/24 04:59:15 cheshire
761 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
763 Revision 1.4 2004/01/24 04:19:26 cheshire
764 Restore overwritten checkin 1.2
766 Revision 1.3 2004/01/23 23:23:15 ksekar
767 Added TCP support for truncated unicast messages.
769 Revision 1.2 2004/01/22 03:48:41 cheshire
770 Make sure uDNS client doesn't accidentally use query ID zero
772 Revision 1.1 2003/12/13 03:05:27 ksekar
773 <rdar://problem/3192548>: DynDNS: Unicast query of service records
779 #if(defined(_MSC_VER))
780 // Disable "assignment within conditional expression".
781 // Other compilers understand the convention that if you place the assignment expression within an extra pair
782 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
783 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
784 // to the compiler that the assignment is intentional, we have to just turn this warning off completely.
785 #pragma warning(disable:4706)
788 #define umalloc(x) mDNSPlatformMemAllocate(x) // short hands for common routines
789 #define ufree(x) mDNSPlatformMemFree(x)
790 #define ubzero(x,y) mDNSPlatformMemZero(x,y)
791 #define umemcpy(x, y, l) mDNSPlatformMemCopy(y, x, l) // uses memcpy(2) arg ordering
793 // Asynchronous operation types
798 // other async. operation names go here
804 mDNSAddr primaryAddr
;
807 mDNSIPPort updatePort
;
810 // other async. result struct defs go here
814 AsyncOpResultType type
;
816 // other async result structs go here
819 typedef void AsyncOpCallback(mStatus err
, mDNS
*const m
, void *info
, const AsyncOpResult
*result
);
822 // Private Function Prototypes
823 // Note: In general, functions are ordered such that they do not require forward declarations.
824 // However, prototypes are used where cyclic call graphs exist (e.g. foo calls bar, and bar calls
825 // foo), or when they aid in the grouping or readability of code (e.g. state machine code that is easier
826 // read top-to-bottom.)
828 mDNSlocal mDNSBool
FreeNATInfo(mDNS
*m
, NATTraversalInfo
*n
);
829 mDNSlocal
void hndlTruncatedAnswer(DNSQuestion
*question
, const mDNSAddr
*src
, mDNS
*m
);
830 mDNSlocal mStatus
startGetZoneData(domainname
*name
, mDNS
*m
, mDNSBool findUpdatePort
, mDNSBool findLLQPort
, AsyncOpCallback callback
, void *callbackInfo
);
831 mDNSlocal mDNSBool
recvLLQResponse(mDNS
*m
, DNSMessage
*msg
, const mDNSu8
*end
, const mDNSAddr
*srcaddr
, mDNSIPPort srcport
, const mDNSInterfaceID InterfaceID
);
832 mDNSlocal
void sendRecordRegistration(mDNS
*const m
, AuthRecord
*rr
);
833 mDNSlocal
void SendServiceRegistration(mDNS
*m
, ServiceRecordSet
*srs
);
834 mDNSlocal
void SendServiceDeregistration(mDNS
*m
, ServiceRecordSet
*srs
);
835 mDNSlocal
void serviceRegistrationCallback(mStatus err
, mDNS
*const m
, void *srsPtr
, const AsyncOpResult
*result
);
836 mDNSlocal
void SuspendLLQs(mDNS
*m
, mDNSBool DeregisterActive
);
837 mDNSlocal
void RestartQueries(mDNS
*m
);
838 mDNSlocal
void startLLQHandshake(mDNS
*m
, LLQ_Info
*info
, mDNSBool defer
);
839 mDNSlocal
void llqResponseHndlr(mDNS
* const m
, DNSMessage
*msg
, const mDNSu8
*end
, DNSQuestion
*question
, void *context
);
841 // ***************************************************************************
842 #if COMPILER_LIKES_PRAGMA_MARK
843 #pragma mark - Temporary workaround
846 // 17 Places in this file directly call mDNSPlatformTimeNow(), which is unsafe
847 // The platform function is now called mDNSPlatformRawTime(), and
848 // mDNSPlatformTimeNow() is defined here as a temporary workaround.
849 // This is a gross hack, and after this change has been tested for a while,
850 // all these calls should be replaced by simple references to m->timenow
852 mDNSlocal mDNSs32
mDNSPlatformTimeNow(mDNS
*m
)
854 if (m
->mDNS_busy
&& m
->timenow
) return(m
->timenow
);
855 LogMsg("ERROR: uDNS.c code executing without holding main mDNS lock");
857 // To get a quick and easy stack trace to find out *how* this routine
858 // is being called without holding main mDNS lock, uncomment the line below:
861 return(mDNS_TimeNow(m
));
864 // ***************************************************************************
865 #if COMPILER_LIKES_PRAGMA_MARK
866 #pragma mark - General Utility Functions
869 // CountLabels() returns number of labels in name, excluding final root label
870 // (e.g. for "apple.com." CountLabels returns 2.)
871 mDNSlocal
int CountLabels(const domainname
*d
)
876 for (ptr
= d
->c
; *ptr
; ptr
= ptr
+ ptr
[0] + 1) count
++;
880 mDNSlocal mDNSOpaque16
newMessageID(uDNS_GlobalInfo
*u
)
882 static mDNSBool randomized
= mDNSfalse
;
884 if (!randomized
) { u
->NextMessageID
= (mDNSu16
)mDNSRandom(0xFFFF); randomized
= mDNStrue
; }
885 if (u
->NextMessageID
== 0) u
->NextMessageID
++;
886 return mDNSOpaque16fromIntVal(u
->NextMessageID
++);
889 // unlink an AuthRecord from a linked list
890 mDNSlocal mStatus
unlinkAR(AuthRecord
**list
, AuthRecord
*const rr
)
892 while (*list
&& *list
!= rr
) list
= &(*list
)->next
;
893 if (*list
) { *list
= rr
->next
; rr
->next
= mDNSNULL
; return(mStatus_NoError
); }
894 LogMsg("ERROR: unlinkAR - no such active record %##s", rr
->resrec
.name
->c
);
895 return(mStatus_NoSuchRecord
);
898 mDNSlocal
void unlinkSRS(mDNS
*m
, ServiceRecordSet
*srs
)
900 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
901 ServiceRecordSet
**p
;
902 NATTraversalInfo
*n
= u
->NATTraversals
;
904 // verify that no NAT objects reference this service
907 if (n
->reg
.ServiceRegistration
== srs
)
909 NATTraversalInfo
*tmp
= n
;
911 LogMsg("ERROR: Unlinking service record set %##s still referenced by NAT traversal object!", srs
->RR_SRV
.resrec
.name
->c
);
917 for (p
= &u
->ServiceRegistrations
; *p
; p
= &(*p
)->next
)
920 ExtraResourceRecord
*e
;
922 srs
->next
= mDNSNULL
;
923 for (e
=srs
->Extras
; e
; e
=e
->next
)
924 if (unlinkAR(&u
->RecordRegistrations
, &e
->r
))
925 LogMsg("unlinkSRS: extra record %##s not found", e
->r
.resrec
.name
->c
);
928 LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list %##s", srs
->RR_SRV
.resrec
.name
->c
);
931 mDNSlocal
void LinkActiveQuestion(uDNS_GlobalInfo
*u
, DNSQuestion
*q
)
933 if (uDNS_IsActiveQuery(q
, u
))
934 { LogMsg("LinkActiveQuestion - %##s (%d) already in list!", q
->qname
.c
, q
->qtype
); return; }
936 q
->next
= u
->ActiveQueries
;
937 u
->ActiveQueries
= q
;
940 // set retry timestamp for record with exponential backoff
941 // (for service record sets, use RR_SRV as representative for time checks
942 mDNSlocal
void SetRecordRetry(mDNS
*const m
, AuthRecord
*rr
, mStatus SendErr
)
944 rr
->LastAPTime
= mDNSPlatformTimeNow(m
);
945 if (SendErr
== mStatus_TransientErr
|| rr
->ThisAPInterval
< INIT_UCAST_POLL_INTERVAL
) rr
->ThisAPInterval
= INIT_UCAST_POLL_INTERVAL
;
946 else if (rr
->ThisAPInterval
*2 <= MAX_UCAST_POLL_INTERVAL
) rr
->ThisAPInterval
*= 2;
947 else if (rr
->ThisAPInterval
!= MAX_UCAST_POLL_INTERVAL
) rr
->ThisAPInterval
= MAX_UCAST_POLL_INTERVAL
;
951 // ***************************************************************************
952 #if COMPILER_LIKES_PRAGMA_MARK
953 #pragma mark - Name Server List Management
956 mDNSexport
void mDNS_AddDNSServer(mDNS
*const m
, const mDNSAddr
*addr
, const domainname
*d
)
958 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
959 DNSServer
*s
, **p
= &u
->Servers
;
962 if (!d
) d
= (domainname
*)"";
964 while (*p
) // Check if we already have this {server,domain} pair registered
966 if (mDNSSameAddress(&(*p
)->addr
, addr
) && SameDomainName(&(*p
)->domain
, d
))
967 LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr
, d
->c
);
971 // allocate, add to list
972 s
= umalloc(sizeof(*s
));
973 if (!s
) { LogMsg("Error: mDNS_AddDNSServer - malloc"); goto end
; }
976 s
->teststate
= DNSServer_Untested
;
977 AssignDomainName(&s
->domain
, d
);
985 mDNSexport
void mDNS_DeleteDNSServers(mDNS
*const m
)
990 s
= m
->uDNS_info
.Servers
;
991 m
->uDNS_info
.Servers
= mDNSNULL
;
1002 // ***************************************************************************
1003 #if COMPILER_LIKES_PRAGMA_MARK
1004 #pragma mark - authorization management
1007 mDNSlocal uDNS_AuthInfo
*GetAuthInfoForName(const uDNS_GlobalInfo
*u
, const domainname
*name
)
1012 for (ptr
= u
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
1013 if (SameDomainName(&ptr
->zone
, name
)) return(ptr
);
1014 name
= (const domainname
*)(name
->c
+ 1 + name
->c
[0]);
1019 mDNSlocal
void DeleteAuthInfoForZone(uDNS_GlobalInfo
*u
, const domainname
*zone
)
1021 uDNS_AuthInfo
*ptr
, *prev
= mDNSNULL
;
1023 for (ptr
= u
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
1025 if (SameDomainName(&ptr
->zone
, zone
))
1027 if (prev
) prev
->next
= ptr
->next
;
1028 else u
->AuthInfoList
= ptr
->next
;
1036 mDNSexport mStatus
mDNS_SetSecretForZone(mDNS
*m
, const domainname
*zone
, const domainname
*key
, const char *sharedSecret
)
1038 uDNS_AuthInfo
*info
;
1039 mDNSu8 keybuf
[1024];
1041 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1042 mStatus status
= mStatus_NoError
;
1046 if (GetAuthInfoForName(u
, zone
)) DeleteAuthInfoForZone(u
, zone
);
1047 if (!key
) goto exit
;
1049 info
= (uDNS_AuthInfo
*)umalloc(sizeof(*info
));
1050 if (!info
) { LogMsg("ERROR: umalloc"); status
= mStatus_NoMemoryErr
; goto exit
; }
1051 ubzero(info
, sizeof(*info
));
1052 AssignDomainName(&info
->zone
, zone
);
1053 AssignDomainName(&info
->keyname
, key
);
1055 keylen
= DNSDigest_Base64ToBin(sharedSecret
, keybuf
, 1024);
1058 LogMsg("ERROR: mDNS_SetSecretForZone - could not convert shared secret %s from base64", sharedSecret
);
1060 status
= mStatus_UnknownErr
;
1063 DNSDigest_ConstructHMACKey(info
, keybuf
, (mDNSu32
)keylen
);
1066 info
->next
= m
->uDNS_info
.AuthInfoList
;
1067 m
->uDNS_info
.AuthInfoList
= info
;
1073 // ***************************************************************************
1074 #if COMPILER_LIKES_PRAGMA_MARK
1075 #pragma mark - NAT Traversal
1078 mDNSlocal mDNSBool
DomainContainsLabelString(const domainname
*d
, const char *str
)
1080 const domainlabel
*l
;
1083 if (!MakeDomainLabelFromLiteralString(&buf
, str
)) return mDNSfalse
;
1085 for (l
= (const domainlabel
*)d
; l
->c
[0]; l
= (const domainlabel
*)(l
->c
+ l
->c
[0]+1))
1086 if (SameDomainLabel(l
->c
, buf
.c
)) return mDNStrue
;
1090 // allocate struct, link into global list, initialize
1091 mDNSlocal NATTraversalInfo
*AllocNATInfo(mDNS
*const m
, NATOp_t op
, NATResponseHndlr callback
)
1093 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1094 NATTraversalInfo
*info
= umalloc(sizeof(NATTraversalInfo
));
1095 if (!info
) { LogMsg("ERROR: malloc"); return mDNSNULL
; }
1096 ubzero(info
, sizeof(NATTraversalInfo
));
1097 info
->next
= u
->NATTraversals
;
1098 u
->NATTraversals
= info
;
1099 info
->retry
= mDNSPlatformTimeNow(m
) + NATMAP_INIT_RETRY
;
1101 info
->state
= NATState_Init
;
1102 info
->ReceiveResponse
= callback
;
1103 info
->PublicPort
.NotAnInteger
= 0;
1104 info
->Router
= u
->Router
;
1108 // unlink from list, deallocate
1109 mDNSlocal mDNSBool
FreeNATInfo(mDNS
*m
, NATTraversalInfo
*n
)
1111 NATTraversalInfo
*ptr
, *prev
= mDNSNULL
;
1112 ServiceRecordSet
*s
= m
->uDNS_info
.ServiceRegistrations
;
1114 // Verify that object is not referenced by any services
1117 if (s
->uDNS_info
.NATinfo
== n
)
1119 LogMsg("Error: Freeing NAT info object still referenced by Service Record Set %##s!", s
->RR_SRV
.resrec
.name
->c
);
1120 s
->uDNS_info
.NATinfo
= mDNSNULL
;
1125 if (n
== m
->uDNS_info
.LLQNatInfo
) m
->uDNS_info
.LLQNatInfo
= mDNSNULL
;
1126 ptr
= m
->uDNS_info
.NATTraversals
;
1131 if (prev
) prev
->next
= ptr
->next
;
1132 else m
->uDNS_info
.NATTraversals
= ptr
->next
;
1139 LogMsg("FreeNATInfo: NATTraversalInfo not found in list");
1143 mDNSlocal
void SendNATMsg(NATTraversalInfo
*info
, mDNS
*m
)
1146 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1148 if (info
->state
!= NATState_Request
&& info
->state
!= NATState_Refresh
)
1149 { LogMsg("SendNATMsg: Bad state %d", info
->state
); return; }
1151 if (u
->Router
.ip
.v4
.NotAnInteger
)
1153 // send msg if we have a router
1154 const mDNSu8
*end
= (mDNSu8
*)&info
->request
;
1155 if (info
->op
== NATOp_AddrRequest
) end
+= sizeof(NATAddrRequest
);
1156 else end
+= sizeof(NATPortMapRequest
);
1158 err
= mDNSPlatformSendUDP(m
, &info
->request
, end
, 0, &u
->Router
, NATPMPPort
);
1159 if (!err
) (info
->ntries
++); // don't increment attempt counter if the send failed
1163 if (info
->RetryInterval
< NATMAP_INIT_RETRY
) info
->RetryInterval
= NATMAP_INIT_RETRY
;
1164 else if (info
->RetryInterval
* 2 > NATMAP_MAX_RETRY
) info
->RetryInterval
= NATMAP_MAX_RETRY
;
1165 else info
->RetryInterval
*= 2;
1166 info
->retry
= mDNSPlatformTimeNow(m
) + info
->RetryInterval
;
1169 mDNSlocal mDNSBool
ReceiveNATAddrResponse(NATTraversalInfo
*n
, mDNS
*m
, mDNSu8
*pkt
, mDNSu16 len
)
1171 mStatus err
= mStatus_NoError
;
1172 AuthRecord
*rr
= mDNSNULL
;
1173 NATAddrReply
*response
= (NATAddrReply
*)pkt
;
1176 if (n
->state
!= NATState_Request
)
1178 LogMsg("ReceiveNATAddrResponse: bad state %d", n
->state
);
1182 rr
= n
->reg
.RecordRegistration
;
1185 LogMsg("ReceiveNATAddrResponse: registration cancelled");
1189 addr
.type
= mDNSAddrType_IPv4
;
1190 addr
.ip
.v4
= rr
->resrec
.rdata
->u
.ipv4
;
1192 if (!pkt
) // timeout
1194 #ifdef _LEGACY_NAT_TRAVERSAL_
1195 err
= LNT_GetPublicIP(&addr
.ip
.v4
);
1197 else n
->state
= NATState_Legacy
;
1199 debugf("ReceiveNATAddrResponse: timeout");
1200 err
= mStatus_NATTraversal
;
1202 #endif // _LEGACY_NAT_TRAVERSAL_
1206 if (len
< sizeof(*response
))
1208 LogMsg("ReceiveNATAddrResponse: response too short (%d bytes)", len
);
1211 if (response
->vers
!= NATMAP_VERS
)
1213 LogMsg("ReceiveNATAddrResponse: received version %d (expect version %d)", pkt
[0], NATMAP_VERS
);
1216 if (response
->opcode
!= (NATOp_AddrRequest
| NATMAP_RESPONSE_MASK
))
1218 LogMsg("ReceiveNATAddrResponse: bad response code %d", response
->opcode
);
1221 if (response
->err
.NotAnInteger
)
1222 { LogMsg("ReceiveAddrResponse: received error %d", mDNSVal16(response
->err
)); err
= mStatus_NATTraversal
; goto end
; }
1224 addr
.ip
.v4
= response
->PubAddr
;
1225 n
->state
= NATState_Established
;
1228 if (IsPrivateV4Addr(&addr
))
1230 LogMsg("ReceiveNATAddrResponse: Double NAT");
1231 err
= mStatus_DoubleNAT
;
1241 rr
->uDNS_info
.NATinfo
= mDNSNULL
;
1242 rr
->uDNS_info
.state
= regState_Unregistered
; // note that rr is not yet in global list
1243 rr
->RecordCallback(m
, rr
, mStatus_NATTraversal
);
1244 // note - unsafe to touch rr after callback
1248 else LogOperation("Received public IP address %d.%d.%d.%d from NAT.", addr
.ip
.v4
.b
[0], addr
.ip
.v4
.b
[1], addr
.ip
.v4
.b
[2], addr
.ip
.v4
.b
[3]);
1249 rr
->resrec
.rdata
->u
.ipv4
= addr
.ip
.v4
; // replace rdata w/ public address
1250 uDNS_RegisterRecord(m
, rr
);
1255 mDNSlocal
void StartGetPublicAddr(mDNS
*m
, AuthRecord
*AddressRec
)
1257 NATAddrRequest
*req
;
1258 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1260 NATTraversalInfo
*info
= AllocNATInfo(m
, NATOp_AddrRequest
, ReceiveNATAddrResponse
);
1261 if (!info
) { uDNS_RegisterRecord(m
, AddressRec
); return; }
1262 AddressRec
->uDNS_info
.NATinfo
= info
;
1263 info
->reg
.RecordRegistration
= AddressRec
;
1264 info
->state
= NATState_Request
;
1267 req
= &info
->request
.AddrReq
;
1268 req
->vers
= NATMAP_VERS
;
1269 req
->opcode
= NATOp_AddrRequest
;
1271 if (!u
->Router
.ip
.v4
.NotAnInteger
)
1273 debugf("No router. Will retry NAT traversal in %ld ticks", NATMAP_INIT_RETRY
);
1277 SendNATMsg(info
, m
);
1281 mDNSlocal
void RefreshNATMapping(NATTraversalInfo
*n
, mDNS
*m
)
1283 n
->state
= NATState_Refresh
;
1284 n
->RetryInterval
= NATMAP_INIT_RETRY
;
1289 mDNSlocal
void LLQNatMapComplete(mDNS
*m
)
1291 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1293 NATTraversalInfo
*n
= u
->LLQNatInfo
;
1295 if (!n
) { LogMsg("Error: LLQNatMapComplete called with NULL LLQNatInfo"); return; }
1296 if (n
->state
!= NATState_Established
&& n
->state
!= NATState_Legacy
&& n
->state
!= NATState_Error
)
1297 { LogMsg("LLQNatMapComplete - bad nat state %d", n
->state
); return; }
1299 u
->CurrentQuery
= u
->ActiveQueries
;
1300 while (u
->CurrentQuery
)
1302 DNSQuestion
*q
= u
->CurrentQuery
;
1303 u
->CurrentQuery
= u
->CurrentQuery
->next
;
1304 llqInfo
= q
->uDNS_info
.llq
;
1305 if (q
->LongLived
&& llqInfo
->state
== LLQ_NatMapWait
)
1307 if (n
->state
== NATState_Error
)
1309 llqInfo
->NATMap
= mDNSfalse
;
1310 llqInfo
->question
->uDNS_info
.responseCallback
= llqResponseHndlr
;
1311 llqInfo
->state
= LLQ_Poll
;
1312 llqInfo
->question
->LastQTime
= mDNSPlatformTimeNow(m
) - (2 * INIT_UCAST_POLL_INTERVAL
); // trigger immediate poll
1313 llqInfo
->question
->ThisQInterval
= INIT_UCAST_POLL_INTERVAL
;
1315 else { llqInfo
->state
= LLQ_GetZoneInfo
; startLLQHandshake(m
, llqInfo
, mDNSfalse
); }
1320 mDNSlocal mDNSBool
ReceivePortMapReply(NATTraversalInfo
*n
, mDNS
*m
, mDNSu8
*pkt
, mDNSu16 len
)
1322 ServiceRecordSet
*srs
= n
->reg
.ServiceRegistration
;
1323 mDNSIPPort priv
= srs
? srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
: m
->UnicastPort4
;
1325 mDNSBool deletion
= !n
->request
.PortReq
.lease
.NotAnInteger
;
1326 NATPortMapReply
*reply
= (NATPortMapReply
*)pkt
;
1327 mDNSu8
*service
= srs
? srs
->RR_SRV
.resrec
.name
->c
: (mDNSu8
*)"\016LLQ event port";
1329 if (n
->state
!= NATState_Request
&& n
->state
!= NATState_Refresh
)
1330 { LogMsg("ReceivePortMapReply (%##s): bad state %d", service
, n
->state
); return mDNSfalse
; }
1332 if (!pkt
&& !deletion
) // timeout
1334 #ifdef _LEGACY_NAT_TRAVERSAL_
1338 mDNSBool tcp
= (srs
&& DomainContainsLabelString(srs
->RR_PTR
.resrec
.name
, "_tcp"));
1340 pub
= priv
; // initially request priv == pub
1343 err
= LNT_MapPort(priv
, pub
, tcp
);
1346 n
->PublicPort
= pub
;
1347 n
->state
= NATState_Legacy
;
1350 else if (err
!= mStatus_AlreadyRegistered
|| ++ntries
> LEGACY_NATMAP_MAX_TRIES
)
1352 n
->state
= NATState_Error
;
1357 // the mapping we want is taken - try a random port
1358 mDNSu16 RandPort
= mDNSRandom(DYN_PORT_MAX
- DYN_PORT_MIN
) + DYN_PORT_MIN
;
1359 pub
= mDNSOpaque16fromIntVal(RandPort
);
1364 #endif // _LEGACY_NAT_TRAVERSAL_
1367 if (len
< sizeof(*reply
)) { LogMsg("ReceivePortMapReply: response too short (%d bytes)", len
); return mDNSfalse
; }
1368 if (reply
->vers
!= NATMAP_VERS
) { LogMsg("ReceivePortMapReply: received version %d (expect version %d)", pkt
[0], NATMAP_VERS
); return mDNSfalse
; }
1369 if (reply
->opcode
!= (n
->op
| NATMAP_RESPONSE_MASK
)) { LogMsg("ReceivePortMapReply: bad response code %d", pkt
[1]); return mDNSfalse
; }
1370 if (reply
->err
.NotAnInteger
) { LogMsg("ReceivePortMapReply: received error %d", mDNSVal16(reply
->err
)); return mDNSfalse
; }
1371 if (priv
.NotAnInteger
!= reply
->priv
.NotAnInteger
) return mDNSfalse
; // packet does not match this request
1373 if (!srs
&& n
!= m
->uDNS_info
.LLQNatInfo
)
1375 LogMsg("ReceivePortMapReply: registration cancelled"); //!!!KRS change to debugf before checkin
1380 if (deletion
) { n
->state
= NATState_Deleted
; return mDNStrue
; }
1382 lease
= (mDNSu32
)mDNSVal32(reply
->lease
);
1383 if (lease
> 0x70000000UL
/ mDNSPlatformOneSecond
) lease
= 0x70000000UL
/ mDNSPlatformOneSecond
;
1385 if (n
->state
== NATState_Refresh
&& reply
->pub
.NotAnInteger
!= n
->PublicPort
.NotAnInteger
)
1386 LogMsg("ReceivePortMapReply: NAT refresh changed public port from %d to %d", mDNSVal16(n
->PublicPort
), mDNSVal16(reply
->pub
));
1387 // this should never happen
1388 // !!!KRS to be defensive, use SRVChanged flag on service and deregister here
1390 n
->PublicPort
= reply
->pub
;
1391 if (reply
->pub
.NotAnInteger
!= n
->request
.PortReq
.pub
.NotAnInteger
) n
->request
.PortReq
.pub
= reply
->pub
; // set message buffer for refreshes
1393 n
->retry
= mDNSPlatformTimeNow(m
) + ((mDNSs32
)lease
* mDNSPlatformOneSecond
/ 2); // retry half way to expiration
1395 if (n
->state
== NATState_Refresh
) { n
->state
= NATState_Established
; return mDNStrue
; }
1396 n
->state
= NATState_Established
;
1399 if (n
->state
!= NATState_Established
&& n
->state
!= NATState_Legacy
)
1401 LogMsg("NAT Port Mapping (%##s): timeout", service
);
1402 if (pkt
) LogMsg("!!! timeout with non-null packet");
1403 n
->state
= NATState_Error
;
1406 uDNS_HostnameInfo
*hi
= m
->uDNS_info
.Hostnames
;
1409 if (hi
->arv6
&& (hi
->arv6
->uDNS_info
.state
== regState_Registered
|| hi
->arv6
->uDNS_info
.state
== regState_Refresh
)) break;
1415 debugf("Port map failed for service %##s - using IPv6 service target", service
);
1416 srs
->uDNS_info
.NATinfo
= mDNSNULL
;
1418 goto register_service
;
1420 else srs
->uDNS_info
.state
= regState_NATError
;
1422 else LLQNatMapComplete(m
);
1425 else LogOperation("Mapped private port %d to public port %d", mDNSVal16(priv
), mDNSVal16(n
->PublicPort
));
1427 if (!srs
) { LLQNatMapComplete(m
); return mDNStrue
; }
1430 if (srs
->uDNS_info
.ns
.ip
.v4
.NotAnInteger
) SendServiceRegistration(m
, srs
); // non-zero server address means we already have necessary zone data to send update
1433 srs
->uDNS_info
.state
= regState_FetchingZoneData
;
1434 startGetZoneData(srs
->RR_SRV
.resrec
.name
, m
, mDNStrue
, mDNSfalse
, serviceRegistrationCallback
, srs
);
1439 mDNSlocal
void FormatPortMaprequest(NATTraversalInfo
*info
, mDNSIPPort port
)
1441 NATPortMapRequest
*req
= &info
->request
.PortReq
;
1443 req
->vers
= NATMAP_VERS
;
1444 req
->opcode
= info
->op
;
1445 req
->unused
.NotAnInteger
= 0;
1448 req
->lease
= mDNSOpaque32fromIntVal(NATMAP_DEFAULT_LEASE
);
1451 mDNSlocal
void SendInitialPMapReq(mDNS
*m
, NATTraversalInfo
*info
)
1453 if (!m
->uDNS_info
.Router
.ip
.v4
.NotAnInteger
)
1455 debugf("No router. Will retry NAT traversal in %ld seconds", NATMAP_INIT_RETRY
);
1456 info
->retry
= mDNSPlatformTimeNow(m
) + NATMAP_INIT_RETRY
;
1457 info
->RetryInterval
= NATMAP_INIT_RETRY
;
1460 SendNATMsg(info
, m
);
1464 mDNSlocal
void StartNATPortMap(mDNS
*m
, ServiceRecordSet
*srs
)
1467 NATTraversalInfo
*info
;
1469 if (DomainContainsLabelString(srs
->RR_PTR
.resrec
.name
, "_tcp")) op
= NATOp_MapTCP
;
1470 else if (DomainContainsLabelString(srs
->RR_PTR
.resrec
.name
, "_udp")) op
= NATOp_MapUDP
;
1471 else { LogMsg("StartNATPortMap: could not determine transport protocol of service %##s", srs
->RR_SRV
.resrec
.name
->c
); goto error
; }
1473 if (srs
->uDNS_info
.NATinfo
) { LogMsg("Error: StartNATPortMap - NAT info already initialized!"); FreeNATInfo(m
, srs
->uDNS_info
.NATinfo
); }
1474 info
= AllocNATInfo(m
, op
, ReceivePortMapReply
);
1475 srs
->uDNS_info
.NATinfo
= info
;
1476 info
->reg
.ServiceRegistration
= srs
;
1477 info
->state
= NATState_Request
;
1479 FormatPortMaprequest(info
, srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
);
1480 SendInitialPMapReq(m
, info
);
1484 startGetZoneData(srs
->RR_SRV
.resrec
.name
, m
, mDNStrue
, mDNSfalse
, serviceRegistrationCallback
, srs
);
1487 mDNSlocal
void DeleteNATPortMapping(mDNS
*m
, NATTraversalInfo
*nat
, ServiceRecordSet
*srs
)
1489 if (nat
->state
== NATState_Established
) // let other edge-case states expire for simplicity
1492 nat
->request
.PortReq
.lease
.NotAnInteger
= 0;
1493 nat
->state
= NATState_Request
;
1496 #ifdef _LEGACY_NAT_TRAVERSAL_
1497 else if (nat
->state
== NATState_Legacy
)
1499 mStatus err
= mStatus_NoError
;
1500 mDNSBool tcp
= srs
? DomainContainsLabelString(srs
->RR_PTR
.resrec
.name
, "_tcp") : mDNSfalse
;
1501 err
= LNT_UnmapPort(nat
->PublicPort
, tcp
);
1502 if (err
) LogMsg("Legacy NAT Traversal - unmap request failed with error %ld", err
);
1505 (void)srs
; // unused
1506 #endif // _LEGACY_NAT_TRAVERSAL_
1509 mDNSlocal
void StartLLQNatMap(mDNS
*m
)
1511 NATTraversalInfo
*info
= AllocNATInfo(m
, NATOp_MapUDP
, ReceivePortMapReply
);
1512 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1514 u
->LLQNatInfo
= info
;
1516 info
->reg
.RecordRegistration
= mDNSNULL
;
1517 info
->reg
.ServiceRegistration
= mDNSNULL
;
1518 info
->state
= NATState_Request
;
1519 FormatPortMaprequest(info
, m
->UnicastPort4
);
1520 SendInitialPMapReq(m
, info
);
1524 // if LLQ NAT context unreferenced, delete the mapping
1525 mDNSlocal
void CheckForUnreferencedLLQMapping(mDNS
*m
)
1527 NATTraversalInfo
*nat
= m
->uDNS_info
.LLQNatInfo
;
1532 for (q
= m
->uDNS_info
.ActiveQueries
; q
; q
= q
->next
)
1533 if (q
->LongLived
&& q
->uDNS_info
.llq
->NATMap
) return;
1535 //to avoid race condition if we need to recreate before this finishes, we do one-shot deregistration
1536 if (nat
->state
== NATState_Established
|| nat
->state
== NATState_Legacy
)
1537 DeleteNATPortMapping(m
, nat
, mDNSNULL
); // for simplicity we allow other states to expire
1538 FreeNATInfo(m
, nat
); // note: this clears the global LLQNatInfo pointer
1541 // ***************************************************************************
1542 #if COMPILER_LIKES_PRAGMA_MARK
1543 #pragma mark - host name and interface management
1546 // if we ever want to refine support for multiple hostnames, we can add logic matching service names to a particular hostname
1547 // for now, we grab the first registered DynDNS name, if any, or a static name we learned via a reverse-map query
1548 mDNSlocal mDNSBool
GetServiceTarget(uDNS_GlobalInfo
*u
, AuthRecord
*srv
, domainname
*dst
)
1550 uDNS_HostnameInfo
*hi
= u
->Hostnames
;
1551 (void)srv
; // unused
1556 if (hi
->arv4
&& (hi
->arv4
->uDNS_info
.state
== regState_Registered
|| hi
->arv4
->uDNS_info
.state
== regState_Refresh
))
1558 AssignDomainName(dst
, hi
->arv4
->resrec
.name
);
1561 if (hi
->arv6
&& (hi
->arv6
->uDNS_info
.state
== regState_Registered
|| hi
->arv6
->uDNS_info
.state
== regState_Refresh
))
1563 AssignDomainName(dst
, hi
->arv4
->resrec
.name
);
1569 if (u
->StaticHostname
.c
[0]) { AssignDomainName(dst
, &u
->StaticHostname
); return mDNStrue
; }
1573 mDNSlocal
void UpdateSRV(mDNS
*m
, ServiceRecordSet
*srs
)
1575 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1576 ExtraResourceRecord
*e
;
1578 // Target change if:
1579 // We have a target and were previously waiting for one, or
1580 // We had a target and no longer do, or
1581 // The target has changed
1583 domainname newtarget
;
1584 domainname
*curtarget
= &srs
->RR_SRV
.resrec
.rdata
->u
.srv
.target
;
1585 mDNSBool HaveTarget
= GetServiceTarget(u
, &srs
->RR_SRV
, &newtarget
);
1586 mDNSBool TargetChanged
= (HaveTarget
&& srs
->uDNS_info
.state
== regState_NoTarget
) || (curtarget
->c
[0] && !HaveTarget
) || !SameDomainName(curtarget
, &newtarget
);
1587 mDNSBool HaveZoneData
= srs
->uDNS_info
.ns
.ip
.v4
.NotAnInteger
? mDNStrue
: mDNSfalse
;
1589 // Nat state change if:
1590 // We were behind a NAT, and now we are behind a new NAT, or
1591 // We're not behind a NAT but our port was previously mapped to a different public port
1592 // We were not behind a NAT and now we are
1594 NATTraversalInfo
*nat
= srs
->uDNS_info
.NATinfo
;
1595 mDNSIPPort port
= srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
;
1596 mDNSBool NATChanged
= mDNSfalse
;
1597 mDNSBool NowBehindNAT
= port
.NotAnInteger
&& IsPrivateV4Addr(&u
->AdvertisedV4
);
1598 mDNSBool WereBehindNAT
= nat
!= mDNSNULL
;
1599 mDNSBool NATRouterChanged
= nat
&& nat
->Router
.ip
.v4
.NotAnInteger
!= u
->Router
.ip
.v4
.NotAnInteger
;
1600 mDNSBool PortWasMapped
= nat
&& (nat
->state
== NATState_Established
|| nat
->state
== NATState_Legacy
) && nat
->PublicPort
.NotAnInteger
!= port
.NotAnInteger
;
1602 if (WereBehindNAT
&& NowBehindNAT
&& NATRouterChanged
) NATChanged
= mDNStrue
;
1603 else if (!NowBehindNAT
&& PortWasMapped
) NATChanged
= mDNStrue
;
1604 else if (!WereBehindNAT
&& NowBehindNAT
) NATChanged
= mDNStrue
;
1606 if (!TargetChanged
&& !NATChanged
) return;
1608 debugf("UpdateSRV (%##s) HadZoneData=%d, TargetChanged=%d, HaveTarget=%d, NowBehindNAT=%d, WereBehindNAT=%d, NATRouterChanged=%d, PortWasMapped=%d",
1609 srs
->RR_SRV
.resrec
.name
->c
, HaveZoneData
, TargetChanged
, HaveTarget
, NowBehindNAT
, WereBehindNAT
, NATRouterChanged
, PortWasMapped
);
1611 switch(srs
->uDNS_info
.state
)
1613 case regState_FetchingZoneData
:
1614 case regState_Cancelled
:
1615 case regState_DeregPending
:
1616 case regState_DeregDeferred
:
1617 case regState_Unregistered
:
1618 case regState_NATMap
:
1619 case regState_ExtraQueued
:
1620 // In these states, the SRV has either not yet been registered (it will get up-to-date information when it is)
1621 // or is in the process of, or has already been, deregistered
1624 case regState_Pending
:
1625 case regState_Refresh
:
1626 case regState_UpdatePending
:
1627 // let the in-flight operation complete before updating
1628 srs
->uDNS_info
.SRVUpdateDeferred
= mDNStrue
;
1631 case regState_NATError
:
1632 if (!NATChanged
) return;
1633 // if nat changed, register if we have a target (below)
1635 case regState_NoTarget
:
1638 debugf("UpdateSRV: %s service %##s", HaveZoneData
? (NATChanged
&& NowBehindNAT
? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs
->RR_SRV
.resrec
.name
->c
);
1641 srs
->uDNS_info
.state
= regState_FetchingZoneData
;
1642 startGetZoneData(srs
->RR_SRV
.resrec
.name
, m
, mDNStrue
, mDNSfalse
, serviceRegistrationCallback
, srs
);
1646 if (nat
&& (NATChanged
|| !NowBehindNAT
)) { srs
->uDNS_info
.NATinfo
= mDNSNULL
; FreeNATInfo(m
, nat
); }
1647 if (NATChanged
&& NowBehindNAT
) { srs
->uDNS_info
.state
= regState_NATMap
; StartNATPortMap(m
, srs
); }
1648 else SendServiceRegistration(m
, srs
);
1653 case regState_Registered
:
1654 // target or nat changed. deregister service. upon completion, we'll look for a new target
1655 debugf("UpdateSRV: SRV record changed for service %##s - deregistering (will re-register with new SRV)", srs
->RR_SRV
.resrec
.name
->c
);
1656 for (e
= srs
->Extras
; e
; e
= e
->next
) e
->r
.uDNS_info
.state
= regState_ExtraQueued
; // extra will be re-registed if the service is re-registered
1657 srs
->uDNS_info
.SRVChanged
= mDNStrue
;
1658 SendServiceDeregistration(m
, srs
);
1663 mDNSlocal
void UpdateSRVRecords(mDNS
*m
)
1665 ServiceRecordSet
*srs
;
1667 for (srs
= m
->uDNS_info
.ServiceRegistrations
; srs
; srs
= srs
->next
) UpdateSRV(m
, srs
);
1670 mDNSlocal
void HostnameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
1672 uDNS_HostnameInfo
*hi
= (uDNS_HostnameInfo
*)rr
->RecordContext
;
1674 if (result
== mStatus_MemFree
)
1678 if (hi
->arv4
== rr
) hi
->arv4
= mDNSNULL
;
1679 else if (hi
->arv4
== rr
) hi
->arv6
= mDNSNULL
;
1680 rr
->RecordContext
= mDNSNULL
;
1681 if (!hi
->arv4
&& !hi
->arv6
) ufree(hi
); // free hi when both v4 and v6 AuthRecs deallocated
1689 // don't unlink or free - we can retry when we get a new address/router
1690 if (rr
->resrec
.rrtype
== kDNSType_A
)
1691 LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.4a", result
, rr
->resrec
.name
->c
, &rr
->resrec
.rdata
->u
.ipv4
);
1693 LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.16a", result
, rr
->resrec
.name
->c
, &rr
->resrec
.rdata
->u
.ipv6
);
1694 if (!hi
) { ufree(rr
); return; }
1695 if (rr
->uDNS_info
.state
!= regState_Unregistered
) LogMsg("Error: HostnameCallback invoked with error code for record not in regState_Unregistered!");
1697 if ((!hi
->arv4
|| hi
->arv4
->uDNS_info
.state
== regState_Unregistered
) &&
1698 (!hi
->arv6
|| hi
->arv6
->uDNS_info
.state
== regState_Unregistered
))
1700 // only deliver status if both v4 and v6 fail
1701 rr
->RecordContext
= (void *)hi
->StatusContext
;
1702 if (hi
->StatusCallback
)
1703 hi
->StatusCallback(m
, rr
, result
); // client may NOT make API calls here
1704 rr
->RecordContext
= (void *)hi
;
1708 // register any pending services that require a target
1709 UpdateSRVRecords(m
);
1711 // Deliver success to client
1712 if (!hi
) { LogMsg("HostnameCallback invoked with orphaned address record"); return; }
1713 if (rr
->resrec
.rrtype
== kDNSType_A
)
1714 LogMsg("Registered hostname %##s IP %.4a", rr
->resrec
.name
->c
, &rr
->resrec
.rdata
->u
.ipv4
);
1716 LogMsg("Registered hostname %##s IP %.16a", rr
->resrec
.name
->c
, &rr
->resrec
.rdata
->u
.ipv6
);
1718 rr
->RecordContext
= (void *)hi
->StatusContext
;
1719 if (hi
->StatusCallback
)
1720 hi
->StatusCallback(m
, rr
, result
); // client may NOT make API calls here
1721 rr
->RecordContext
= (void *)hi
;
1724 // register record or begin NAT traversal
1725 mDNSlocal
void AdvertiseHostname(mDNS
*m
, uDNS_HostnameInfo
*h
)
1727 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1729 if (u
->AdvertisedV4
.ip
.v4
.NotAnInteger
&& h
->arv4
->uDNS_info
.state
== regState_Unregistered
)
1731 if (IsPrivateV4Addr(&u
->AdvertisedV4
))
1732 StartGetPublicAddr(m
, h
->arv4
);
1735 LogMsg("Advertising %##s IP %.4a", h
->arv4
->resrec
.name
->c
, &u
->AdvertisedV4
.ip
.v4
);
1736 uDNS_RegisterRecord(m
, h
->arv4
);
1739 if (u
->AdvertisedV6
.ip
.v6
.b
[0] && h
->arv6
->uDNS_info
.state
== regState_Unregistered
)
1741 LogMsg("Advertising %##s IP %.16a", h
->arv4
->resrec
.name
->c
, &u
->AdvertisedV6
.ip
.v6
);
1742 uDNS_RegisterRecord(m
, h
->arv6
);
1746 mDNSlocal
void FoundStaticHostname(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1748 const domainname
*pktname
= &answer
->rdata
->u
.name
;
1749 domainname
*storedname
= &m
->uDNS_info
.StaticHostname
;
1750 uDNS_HostnameInfo
*h
= m
->uDNS_info
.Hostnames
;
1754 debugf("FoundStaticHostname: %##s -> %##s (%s)", question
->qname
.c
, answer
->rdata
->u
.name
.c
, AddRecord
? "added" : "removed");
1755 if (AddRecord
&& !SameDomainName(pktname
, storedname
))
1757 AssignDomainName(storedname
, pktname
);
1760 if ((h
->arv4
&& (h
->arv4
->uDNS_info
.state
== regState_FetchingZoneData
|| h
->arv4
->uDNS_info
.state
== regState_Pending
|| h
->arv4
->uDNS_info
.state
== regState_NATMap
)) ||
1761 (h
->arv6
&& (h
->arv6
->uDNS_info
.state
== regState_FetchingZoneData
|| h
->arv6
->uDNS_info
.state
== regState_Pending
)))
1763 // 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
1764 m
->uDNS_info
.DelaySRVUpdate
= mDNStrue
;
1765 m
->uDNS_info
.NextSRVUpdate
= mDNSPlatformTimeNow(m
) + (5 * mDNSPlatformOneSecond
);
1770 UpdateSRVRecords(m
);
1772 else if (!AddRecord
&& SameDomainName(pktname
, storedname
))
1774 storedname
->c
[0] = 0;
1775 UpdateSRVRecords(m
);
1779 mDNSlocal
void GetStaticHostname(mDNS
*m
)
1781 char buf
[MAX_ESCAPED_DOMAIN_NAME
];
1782 DNSQuestion
*q
= &m
->uDNS_info
.ReverseMap
;
1783 mDNSu8
*ip
= m
->uDNS_info
.AdvertisedV4
.ip
.v4
.b
;
1786 if (m
->uDNS_info
.ReverseMapActive
)
1788 uDNS_StopQuery(m
, q
);
1789 m
->uDNS_info
.ReverseMapActive
= mDNSfalse
;
1792 m
->uDNS_info
.StaticHostname
.c
[0] = 0;
1793 if (!m
->uDNS_info
.AdvertisedV4
.ip
.v4
.NotAnInteger
) return;
1794 ubzero(q
, sizeof(*q
));
1795 mDNS_snprintf(buf
, MAX_ESCAPED_DOMAIN_NAME
, "%d.%d.%d.%d.in-addr.arpa.", ip
[3], ip
[2], ip
[1], ip
[0]);
1796 if (!MakeDomainNameFromDNSNameString(&q
->qname
, buf
)) { LogMsg("Error: GetStaticHostname - bad name %s", buf
); return; }
1798 q
->InterfaceID
= mDNSInterface_Any
;
1799 q
->Target
= zeroAddr
;
1800 q
->qtype
= kDNSType_PTR
;
1801 q
->qclass
= kDNSClass_IN
;
1802 q
->LongLived
= mDNSfalse
;
1803 q
->ExpectUnique
= mDNSfalse
;
1804 q
->ForceMCast
= mDNSfalse
;
1805 q
->QuestionCallback
= FoundStaticHostname
;
1806 q
->QuestionContext
= mDNSNULL
;
1808 err
= uDNS_StartQuery(m
, q
);
1809 if (err
) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err
);
1810 else m
->uDNS_info
.ReverseMapActive
= mDNStrue
;
1813 mDNSlocal
void AssignHostnameInfoAuthRecord(mDNS
*m
, uDNS_HostnameInfo
*hi
, int type
)
1815 AuthRecord
**dst
= (type
== mDNSAddrType_IPv4
? &hi
->arv4
: &hi
->arv6
);
1816 AuthRecord
*ar
= umalloc(sizeof(*ar
));
1817 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1819 if (type
!= mDNSAddrType_IPv4
&& type
!= mDNSAddrType_IPv6
) { LogMsg("ERROR: AssignHostnameInfoAuthRecord - bad type %d", type
); return; }
1820 if (!ar
) { LogMsg("ERROR: AssignHostnameInfoAuthRecord - malloc"); return; }
1822 mDNS_SetupResourceRecord(ar
, mDNSNULL
, 0, type
== mDNSAddrType_IPv4
? kDNSType_A
: kDNSType_AAAA
, 1, kDNSRecordTypeKnownUnique
, HostnameCallback
, hi
);
1823 AssignDomainName(ar
->resrec
.name
, &hi
->fqdn
);
1825 // only set RData if we have a valid IP
1826 if (type
== mDNSAddrType_IPv4
&& u
->AdvertisedV4
.ip
.v4
.NotAnInteger
)
1828 if (u
->MappedV4
.ip
.v4
.NotAnInteger
) ar
->resrec
.rdata
->u
.ipv4
= u
->MappedV4
.ip
.v4
;
1829 else ar
->resrec
.rdata
->u
.ipv4
= u
->AdvertisedV4
.ip
.v4
;
1831 else if (type
== mDNSAddrType_IPv6
&& u
->AdvertisedV6
.ip
.v6
.b
[0])
1833 ar
->resrec
.rdata
->u
.ipv6
= u
->AdvertisedV6
.ip
.v6
;
1836 ar
->uDNS_info
.state
= regState_Unregistered
;
1840 LogMsg("ERROR: AssignHostnameInfoAuthRecord - overwriting %s AuthRec", type
== mDNSAddrType_IPv4
? "IPv4" : "IPv6");
1841 unlinkAR(&u
->RecordRegistrations
, *dst
);
1842 (*dst
)->RecordContext
= mDNSNULL
; // defensively clear backpointer to avoid doubly-referenced context
1849 // Deregister hostnames and register new names for each host domain with the current global
1850 // values for the hostlabel and primary IP address
1851 mDNSlocal
void UpdateHostnameRegistrations(mDNS
*m
)
1853 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1854 uDNS_HostnameInfo
*i
;
1856 for (i
= u
->Hostnames
; i
; i
= i
->next
)
1858 if (i
->arv4
&& i
->arv4
->uDNS_info
.state
!= regState_Unregistered
&&
1859 i
->arv4
->resrec
.rdata
->u
.ipv4
.NotAnInteger
!= u
->AdvertisedV4
.ip
.v4
.NotAnInteger
&&
1860 i
->arv4
->resrec
.rdata
->u
.ipv4
.NotAnInteger
!=u
->MappedV4
.ip
.v4
.NotAnInteger
)
1862 uDNS_DeregisterRecord(m
, i
->arv4
);
1865 if (i
->arv6
&& !mDNSPlatformMemSame(i
->arv6
->resrec
.rdata
->u
.ipv6
.b
, u
->AdvertisedV6
.ip
.v6
.b
, 16) && i
->arv6
->uDNS_info
.state
!= regState_Unregistered
)
1867 uDNS_DeregisterRecord(m
, i
->arv6
);
1871 if (!i
->arv4
&& u
->AdvertisedV4
.ip
.v4
.NotAnInteger
) AssignHostnameInfoAuthRecord(m
, i
, mDNSAddrType_IPv4
);
1872 else if (i
->arv4
&& i
->arv4
->uDNS_info
.state
== regState_Unregistered
) i
->arv4
->resrec
.rdata
->u
.ipv4
= u
->AdvertisedV4
.ip
.v4
; // simply overwrite unregistered
1873 if (!i
->arv6
&& u
->AdvertisedV6
.ip
.v6
.b
[0]) AssignHostnameInfoAuthRecord(m
, i
, mDNSAddrType_IPv6
);
1874 else if (i
->arv6
&&i
->arv6
->uDNS_info
.state
== regState_Unregistered
) i
->arv6
->resrec
.rdata
->u
.ipv6
= u
->AdvertisedV6
.ip
.v6
;
1876 AdvertiseHostname(m
, i
);
1880 mDNSexport
void mDNS_AddDynDNSHostName(mDNS
*m
, const domainname
*fqdn
, mDNSRecordCallback
*StatusCallback
, const void *StatusContext
)
1882 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1883 uDNS_HostnameInfo
*ptr
, *new;
1887 // check if domain already registered
1888 for (ptr
= u
->Hostnames
; ptr
; ptr
= ptr
->next
)
1890 if (SameDomainName(fqdn
, &ptr
->fqdn
))
1891 { LogMsg("Host Domain %##s already in list", fqdn
->c
); goto exit
; }
1894 // allocate and format new address record
1895 new = umalloc(sizeof(*new));
1896 if (!new) { LogMsg("ERROR: mDNS_AddDynDNSHostname - malloc"); goto exit
; }
1897 ubzero(new, sizeof(*new));
1898 new->next
= u
->Hostnames
;
1901 AssignDomainName(&new->fqdn
, fqdn
);
1902 new->StatusCallback
= StatusCallback
;
1903 new->StatusContext
= StatusContext
;
1905 if (u
->AdvertisedV4
.ip
.v4
.NotAnInteger
) AssignHostnameInfoAuthRecord(m
, new, mDNSAddrType_IPv4
);
1906 else new->arv4
= mDNSNULL
;
1907 if (u
->AdvertisedV6
.ip
.v6
.b
[0]) AssignHostnameInfoAuthRecord(m
, new, mDNSAddrType_IPv6
);
1908 else new->arv6
= mDNSNULL
;
1910 if (u
->AdvertisedV6
.ip
.v6
.b
[0] || u
->AdvertisedV4
.ip
.v4
.NotAnInteger
) AdvertiseHostname(m
, new);
1916 mDNSexport
void mDNS_RemoveDynDNSHostName(mDNS
*m
, const domainname
*fqdn
)
1918 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1919 uDNS_HostnameInfo
**ptr
= &u
->Hostnames
;
1923 while (*ptr
&& !SameDomainName(fqdn
, &(*ptr
)->fqdn
)) ptr
= &(*ptr
)->next
;
1924 if (!*ptr
) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn
->c
);
1927 uDNS_HostnameInfo
*hi
= *ptr
;
1928 *ptr
= (*ptr
)->next
; // unlink
1931 hi
->arv4
->RecordContext
= mDNSNULL
; // about to free wrapper struct
1932 if (hi
->arv4
->uDNS_info
.state
!= regState_Unregistered
) uDNS_DeregisterRecord(m
, hi
->arv4
);
1933 else { ufree(hi
->arv4
); hi
->arv4
= mDNSNULL
; }
1937 hi
->arv6
->RecordContext
= mDNSNULL
; // about to free wrapper struct
1938 if (hi
->arv6
->uDNS_info
.state
!= regState_Unregistered
) uDNS_DeregisterRecord(m
, hi
->arv6
);
1939 else { ufree(hi
->arv6
); hi
->arv6
= mDNSNULL
; }
1943 UpdateSRVRecords(m
);
1947 mDNSexport
void mDNS_SetPrimaryInterfaceInfo(mDNS
*m
, const mDNSAddr
*v4addr
, const mDNSAddr
*v6addr
, const mDNSAddr
*router
)
1949 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1950 mDNSBool v4Changed
, v6Changed
, RouterChanged
;
1952 if (v4addr
&& v4addr
->type
!= mDNSAddrType_IPv4
) { LogMsg("mDNS_SetPrimaryInterfaceInfo V4 address - incorrect type. Discarding."); return; }
1953 if (v6addr
&& v6addr
->type
!= mDNSAddrType_IPv6
) { LogMsg("mDNS_SetPrimaryInterfaceInfo V6 address - incorrect type. Discarding."); return; }
1954 if (router
&& router
->type
!= mDNSAddrType_IPv4
) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-V4 router. Discarding."); return; }
1958 v4Changed
= (v4addr
? v4addr
->ip
.v4
.NotAnInteger
: 0) != u
->AdvertisedV4
.ip
.v4
.NotAnInteger
;
1959 v6Changed
= v6addr
? !mDNSPlatformMemSame(v6addr
, &u
->AdvertisedV6
, sizeof(*v6addr
)) : (u
->AdvertisedV6
.ip
.v6
.b
[0] != 0);
1960 RouterChanged
= (router
? router
->ip
.v4
.NotAnInteger
: 0) != u
->Router
.ip
.v4
.NotAnInteger
;
1963 if (v4addr
&& (v4Changed
|| RouterChanged
))
1964 LogMsg("mDNS_SetPrimaryInterfaceInfo: address changed from %d.%d.%d.%d to %d.%d.%d.%d:%d",
1965 u
->AdvertisedV4
.ip
.v4
.b
[0], u
->AdvertisedV4
.ip
.v4
.b
[1], u
->AdvertisedV4
.ip
.v4
.b
[2], u
->AdvertisedV4
.ip
.v4
.b
[3],
1966 v4addr
->ip
.v4
.b
[0], v4addr
->ip
.v4
.b
[1], v4addr
->ip
.v4
.b
[2], v4addr
->ip
.v4
.b
[3]);
1967 #endif // MDNS_DEBUGMSGS
1969 if ((v4Changed
|| RouterChanged
) && u
->MappedV4
.ip
.v4
.NotAnInteger
) u
->MappedV4
.ip
.v4
.NotAnInteger
= 0;
1970 if (v4addr
) u
->AdvertisedV4
= *v4addr
; else u
->AdvertisedV4
.ip
.v4
.NotAnInteger
= 0;
1971 if (v6addr
) u
->AdvertisedV6
= *v6addr
; else ubzero(u
->AdvertisedV6
.ip
.v6
.b
, 16);
1972 if (router
) u
->Router
= *router
; else u
->Router
.ip
.v4
.NotAnInteger
= 0;
1973 // setting router to zero indicates that nat mappings must be reestablished when router is reset
1975 if ((v4Changed
|| RouterChanged
|| v6Changed
) && v4addr
)
1977 // don't update these unless we've got V4
1978 UpdateHostnameRegistrations(m
);
1979 UpdateSRVRecords(m
);
1980 GetStaticHostname(m
); // look up reverse map record to find any static hostnames for our IP address
1986 // ***************************************************************************
1987 #if COMPILER_LIKES_PRAGMA_MARK
1988 #pragma mark - Incoming Message Processing
1991 mDNSlocal mDNSBool
kaListContainsAnswer(DNSQuestion
*question
, CacheRecord
*rr
)
1995 for (ptr
= question
->uDNS_info
.knownAnswers
; ptr
; ptr
= ptr
->next
)
1996 if (SameResourceRecord(&ptr
->resrec
, &rr
->resrec
)) return mDNStrue
;
2002 mDNSlocal
void removeKnownAnswer(DNSQuestion
*question
, CacheRecord
*rr
)
2004 CacheRecord
*ptr
, *prev
= mDNSNULL
;
2006 for (ptr
= question
->uDNS_info
.knownAnswers
; ptr
; ptr
= ptr
->next
)
2008 if (SameResourceRecord(&ptr
->resrec
, &rr
->resrec
))
2010 if (prev
) prev
->next
= ptr
->next
;
2011 else question
->uDNS_info
.knownAnswers
= ptr
->next
;
2017 LogMsg("removeKnownAnswer() called for record not in KA list");
2021 mDNSlocal
void addKnownAnswer(DNSQuestion
*question
, const CacheRecord
*rr
)
2023 CacheRecord
*newCR
= mDNSNULL
;
2026 size
= sizeof(CacheRecord
) + rr
->resrec
.rdlength
- InlineCacheRDSize
;
2027 newCR
= (CacheRecord
*)umalloc(size
);
2028 if (!newCR
) { LogMsg("ERROR: addKnownAnswer - malloc"); return; }
2029 umemcpy(newCR
, rr
, size
);
2030 newCR
->resrec
.rdata
= (RData
*)&newCR
->rdatastorage
;
2031 newCR
->resrec
.rdata
->MaxRDLength
= rr
->resrec
.rdlength
;
2032 newCR
->resrec
.name
= &question
->qname
;
2033 newCR
->next
= question
->uDNS_info
.knownAnswers
;
2034 question
->uDNS_info
.knownAnswers
= newCR
;
2037 mDNSlocal
void deriveGoodbyes(mDNS
* const m
, DNSMessage
*msg
, const mDNSu8
*end
, DNSQuestion
*question
)
2041 CacheRecord
*fptr
, *ka
, *cr
, *answers
= mDNSNULL
, *prev
= mDNSNULL
;
2042 LargeCacheRecord
*lcr
;
2044 if (question
!= m
->uDNS_info
.CurrentQuery
) { LogMsg("ERROR: deriveGoodbyes called without CurrentQuery set!"); return; }
2046 ptr
= LocateAnswers(msg
, end
);
2047 if (!ptr
) goto pkt_error
;
2049 if (!msg
->h
.numAnswers
)
2051 // delete the whole KA list
2052 ka
= question
->uDNS_info
.knownAnswers
;
2055 debugf("deriving goodbye for %##s", ka
->resrec
.name
->c
);
2057 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
2058 question
->QuestionCallback(m
, question
, &ka
->resrec
, mDNSfalse
);
2059 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
2060 // CAUTION: Need to be careful after calling question->QuestionCallback(),
2061 // because the client's callback function is allowed to do anything,
2062 // including starting/stopping queries, registering/deregistering records, etc.
2063 if (question
!= m
->uDNS_info
.CurrentQuery
)
2065 debugf("deriveGoodbyes - question removed via callback. returning.");
2072 question
->uDNS_info
.knownAnswers
= mDNSNULL
;
2076 // make a list of all the new answers
2077 for (i
= 0; i
< msg
->h
.numAnswers
; i
++)
2079 lcr
= (LargeCacheRecord
*)umalloc(sizeof(LargeCacheRecord
));
2080 if (!lcr
) goto malloc_error
;
2081 ubzero(lcr
, sizeof(LargeCacheRecord
));
2082 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, lcr
);
2083 if (!ptr
) goto pkt_error
;
2085 if (ResourceRecordAnswersQuestion(&cr
->resrec
, question
))
2093 // make sure every known answer is in the answer list
2094 ka
= question
->uDNS_info
.knownAnswers
;
2097 for (cr
= answers
; cr
; cr
= cr
->next
)
2098 { if (SameResourceRecord(&ka
->resrec
, &cr
->resrec
)) break; }
2101 // record is in KA list but not answer list - remove from KA list
2102 if (prev
) prev
->next
= ka
->next
;
2103 else question
->uDNS_info
.knownAnswers
= ka
->next
;
2104 debugf("deriving goodbye for %##s", ka
->resrec
.name
->c
);
2105 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
2106 question
->QuestionCallback(m
, question
, &ka
->resrec
, mDNSfalse
);
2107 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
2108 // CAUTION: Need to be careful after calling question->QuestionCallback(),
2109 // because the client's callback function is allowed to do anything,
2110 // including starting/stopping queries, registering/deregistering records, etc.
2111 if (question
!= m
->uDNS_info
.CurrentQuery
)
2113 debugf("deriveGoodbyes - question removed via callback. returning.");
2127 // free temp answers list
2129 while (cr
) { fptr
= cr
; cr
= cr
->next
; ufree(fptr
); }
2134 LogMsg("ERROR: deriveGoodbyes - received malformed response to query for %##s (%d)",
2135 question
->qname
.c
, question
->qtype
);
2139 LogMsg("ERROR: Malloc");
2142 mDNSlocal
void pktResponseHndlr(mDNS
* const m
, DNSMessage
*msg
, const mDNSu8
*end
, DNSQuestion
*question
, mDNSBool llq
)
2146 CacheRecord
*cr
= &m
->rec
.r
;
2147 mDNSBool goodbye
, inKAList
;
2148 int followedCNames
= 0;
2149 static const int maxCNames
= 5;
2150 LLQ_Info
*llqInfo
= question
->uDNS_info
.llq
;
2151 domainname origname
;
2154 if (question
!= m
->uDNS_info
.CurrentQuery
)
2155 { LogMsg("ERROR: pktResponseHdnlr called without CurrentQuery ptr set!"); return; }
2157 if (question
->uDNS_info
.Answered
== 0 && msg
->h
.numAnswers
== 0 && !llq
)
2159 /* NXDOMAIN error or empty RR set - notify client */
2160 question
->uDNS_info
.Answered
= mDNStrue
;
2162 /* Create empty resource record */
2163 cr
->resrec
.RecordType
= kDNSRecordTypeUnregistered
;
2164 cr
->resrec
.InterfaceID
= mDNSNULL
;
2165 cr
->resrec
.name
= &question
->qname
;
2166 cr
->resrec
.rrtype
= question
->qtype
;
2167 cr
->resrec
.rrclass
= question
->qclass
;
2168 cr
->resrec
.rroriginalttl
= 1; /* What should we use for the TTL? TTL from SOA for domain? */
2169 cr
->resrec
.rdlength
= 0;
2170 cr
->resrec
.rdestimate
= 0;
2171 cr
->resrec
.namehash
= 0;
2172 cr
->resrec
.namehash
= 0;
2173 cr
->resrec
.rdata
= (RData
*)&cr
->rdatastorage
;
2174 cr
->resrec
.rdata
->MaxRDLength
= cr
->resrec
.rdlength
;
2176 /* Pass empty answer to callback */
2177 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
2178 question
->QuestionCallback(m
, question
, &cr
->resrec
, 0);
2179 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
2180 // CAUTION: Need to be careful after calling question->QuestionCallback(),
2181 // because the client's callback function is allowed to do anything,
2182 // including starting/stopping queries, registering/deregistering records, etc.
2183 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
2184 if (question
!= m
->uDNS_info
.CurrentQuery
)
2186 debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning.");
2191 question
->uDNS_info
.Answered
= mDNStrue
;
2193 ptr
= LocateAnswers(msg
, end
);
2194 if (!ptr
) goto pkt_error
;
2196 for (i
= 0; i
< msg
->h
.numAnswers
; i
++)
2198 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &m
->rec
);
2199 if (!ptr
) goto pkt_error
;
2200 if (ResourceRecordAnswersQuestion(&cr
->resrec
, question
))
2202 goodbye
= llq
? ((mDNSs32
)cr
->resrec
.rroriginalttl
== -1) : mDNSfalse
;
2203 if (cr
->resrec
.rrtype
== kDNSType_CNAME
)
2205 if (followedCNames
> (maxCNames
- 1)) LogMsg("Error: too many CNAME referals for question %##s", &origname
);
2208 debugf("Following cname %##s -> %##s", question
->qname
.c
, cr
->resrec
.rdata
->u
.name
.c
);
2209 if (question
->ReturnCNAME
)
2211 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
2212 question
->QuestionCallback(m
, question
, &cr
->resrec
, !goodbye
);
2213 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
2214 // CAUTION: Need to be careful after calling question->QuestionCallback(),
2215 // because the client's callback function is allowed to do anything,
2216 // including starting/stopping queries, registering/deregistering records, etc.
2217 if (question
!= m
->uDNS_info
.CurrentQuery
)
2219 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
2220 debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning.");
2224 AssignDomainName(&origname
, &question
->qname
);
2225 AssignDomainName(&question
->qname
, &cr
->resrec
.rdata
->u
.name
);
2226 question
->qnamehash
= DomainNameHashValue(&question
->qname
);
2228 i
= -1; // restart packet answer matching
2229 ptr
= LocateAnswers(msg
, end
);
2230 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
2235 inKAList
= kaListContainsAnswer(question
, cr
);
2237 if ((goodbye
&& !inKAList
) || (!goodbye
&& inKAList
))
2239 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
2240 continue; // list up to date
2242 if (!inKAList
) addKnownAnswer(question
, cr
);
2243 if (goodbye
) removeKnownAnswer(question
, cr
);
2244 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
2245 question
->QuestionCallback(m
, question
, &cr
->resrec
, !goodbye
);
2246 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
2247 if (question
!= m
->uDNS_info
.CurrentQuery
)
2249 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
2250 debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning");
2255 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
2258 if (!llq
|| llqInfo
->state
== LLQ_Poll
|| llqInfo
->deriveRemovesOnResume
)
2260 deriveGoodbyes(m
, msg
, end
,question
);
2261 if (llq
&& llqInfo
->deriveRemovesOnResume
) llqInfo
->deriveRemovesOnResume
= mDNSfalse
;
2264 // Our interval may be set lower to recover from failures -- now that we have an answer, fully back off retry.
2265 // If the server advertised an LLQ-specific port number then that implies that this zone
2266 // *wants* to support LLQs, so if the setup fails (e.g. because we are behind a NAT)
2267 // then we use a slightly faster polling rate to give slightly better user experience.
2268 if (llq
&& llqInfo
->state
== LLQ_Poll
&& llqInfo
->servPort
.NotAnInteger
) question
->ThisQInterval
= LLQ_POLL_INTERVAL
;
2269 else if (question
->ThisQInterval
< MAX_UCAST_POLL_INTERVAL
) question
->ThisQInterval
= MAX_UCAST_POLL_INTERVAL
;
2273 LogMsg("ERROR: pktResponseHndlr - received malformed response to query for %##s (%d)",
2274 question
->qname
.c
, question
->qtype
);
2278 mDNSlocal
void simpleResponseHndlr(mDNS
* const m
, DNSMessage
*msg
, const mDNSu8
*end
, DNSQuestion
*question
, void *context
)
2280 (void)context
; // unused
2281 pktResponseHndlr(m
, msg
, end
, question
, mDNSfalse
);
2284 mDNSlocal
void llqResponseHndlr(mDNS
* const m
, DNSMessage
*msg
, const mDNSu8
*end
, DNSQuestion
*question
, void *context
)
2286 (void)context
; // unused
2287 pktResponseHndlr(m
, msg
, end
, question
, mDNStrue
);
2290 mDNSlocal mStatus
ParseTSIGError(mDNS
*m
, const DNSMessage
*msg
, const mDNSu8
*end
, const domainname
*displayname
)
2292 LargeCacheRecord lcr
;
2294 mStatus err
= mStatus_NoError
;
2297 ptr
= LocateAdditionals(msg
, end
);
2298 if (!ptr
) goto finish
;
2300 for (i
= 0; i
< msg
->h
.numAdditionals
; i
++)
2302 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &lcr
);
2303 if (!ptr
) goto finish
;
2304 if (lcr
.r
.resrec
.rrtype
== kDNSType_TSIG
)
2307 mDNSu8
*rd
= lcr
.r
.resrec
.rdata
->u
.data
;
2308 mDNSu8
*rdend
= rd
+ MaximumRDSize
;
2309 int alglen
= DomainNameLength(&lcr
.r
.resrec
.rdata
->u
.name
);
2311 if (rd
+ alglen
> rdend
) goto finish
;
2312 rd
+= alglen
; // algorithm name
2313 if (rd
+ 6 > rdend
) goto finish
;
2314 rd
+= 6; // 48-bit timestamp
2315 if (rd
+ sizeof(mDNSOpaque16
) > rdend
) goto finish
;
2316 rd
+= sizeof(mDNSOpaque16
); // fudge
2317 if (rd
+ sizeof(mDNSOpaque16
) > rdend
) goto finish
;
2318 macsize
= mDNSVal16(*(mDNSOpaque16
*)rd
);
2319 rd
+= sizeof(mDNSOpaque16
); // MAC size
2320 if (rd
+ macsize
> rdend
) goto finish
;
2322 if (rd
+ sizeof(mDNSOpaque16
) > rdend
) goto finish
;
2323 rd
+= sizeof(mDNSOpaque16
); // orig id
2324 if (rd
+ sizeof(mDNSOpaque16
) > rdend
) goto finish
;
2325 err
= mDNSVal16(*(mDNSOpaque16
*)rd
); // error code
2327 if (err
== TSIG_ErrBadSig
) { LogMsg("%##s: bad signature", displayname
->c
); err
= mStatus_BadSig
; }
2328 else if (err
== TSIG_ErrBadKey
) { LogMsg("%##s: bad key", displayname
->c
); err
= mStatus_BadKey
; }
2329 else if (err
== TSIG_ErrBadTime
) { LogMsg("%##s: bad time", displayname
->c
); err
= mStatus_BadTime
; }
2330 else if (err
) { LogMsg("%##s: unknown tsig error %d", displayname
->c
, err
); err
= mStatus_UnknownErr
; }
2339 mDNSlocal mStatus
checkUpdateResult(domainname
*displayname
, mDNSu8 rcode
, mDNS
*m
, const DNSMessage
*msg
, const mDNSu8
*end
)
2341 (void)msg
; // currently unused, needed for TSIG errors
2342 if (!rcode
) return mStatus_NoError
;
2343 else if (rcode
== kDNSFlag1_RC_YXDomain
)
2345 debugf("name in use: %##s", displayname
->c
);
2346 return mStatus_NameConflict
;
2348 else if (rcode
== kDNSFlag1_RC_Refused
)
2350 LogMsg("Update %##s refused", displayname
->c
);
2351 return mStatus_Refused
;
2353 else if (rcode
== kDNSFlag1_RC_NXRRSet
)
2355 LogMsg("Reregister refused (NXRRSET): %##s", displayname
->c
);
2356 return mStatus_NoSuchRecord
;
2358 else if (rcode
== kDNSFlag1_RC_NotAuth
)
2360 // TSIG errors should come with FmtErr as per RFC 2845, but BIND 9 sends them with NotAuth so we look here too
2361 mStatus tsigerr
= ParseTSIGError(m
, msg
, end
, displayname
);
2364 LogMsg("Permission denied (NOAUTH): %##s", displayname
->c
);
2365 return mStatus_UnknownErr
;
2367 else return tsigerr
;
2369 else if (rcode
== kDNSFlag1_RC_FmtErr
)
2371 mStatus tsigerr
= ParseTSIGError(m
, msg
, end
, displayname
);
2374 LogMsg("Format Error: %##s", displayname
->c
);
2375 return mStatus_UnknownErr
;
2377 else return tsigerr
;
2381 LogMsg("Update %##s failed with rcode %d", displayname
->c
, rcode
);
2382 return mStatus_UnknownErr
;
2386 mDNSlocal
void hndlServiceUpdateReply(mDNS
* const m
, ServiceRecordSet
*srs
, mStatus err
)
2388 mDNSBool InvokeCallback
= mDNSfalse
;
2389 uDNS_RegInfo
*info
= &srs
->uDNS_info
;
2390 NATTraversalInfo
*nat
= srs
->uDNS_info
.NATinfo
;
2391 ExtraResourceRecord
**e
= &srs
->Extras
;
2392 AuthRecord
*txt
= &srs
->RR_TXT
;
2393 uDNS_RegInfo
*txtInfo
= &txt
->uDNS_info
;
2394 switch (info
->state
)
2396 case regState_Pending
:
2397 if (err
== mStatus_NameConflict
&& !info
->TestForSelfConflict
)
2399 info
->TestForSelfConflict
= mDNStrue
;
2400 debugf("checking for self-conflict of service %##s", srs
->RR_SRV
.resrec
.name
->c
);
2401 SendServiceRegistration(m
, srs
);
2404 else if (info
->TestForSelfConflict
)
2406 info
->TestForSelfConflict
= mDNSfalse
;
2407 if (err
== mStatus_NoSuchRecord
) err
= mStatus_NameConflict
; // NoSuchRecord implies that our prereq was not met, so we actually have a name conflict
2408 if (err
) info
->state
= regState_Unregistered
;
2409 else info
->state
= regState_Registered
;
2410 InvokeCallback
= mDNStrue
;
2413 else if (err
== mStatus_UnknownErr
&& info
->lease
)
2415 LogMsg("Re-trying update of service %##s without lease option", srs
->RR_SRV
.resrec
.name
->c
);
2416 info
->lease
= mDNSfalse
;
2417 SendServiceRegistration(m
, srs
);
2422 if (err
) { LogMsg("Error %ld for registration of service %##s", err
, srs
->RR_SRV
.resrec
.name
->c
); info
->state
= regState_Unregistered
; } //!!!KRS make sure all structs will still get cleaned up when client calls DeregisterService with this state
2423 else info
->state
= regState_Registered
;
2424 InvokeCallback
= mDNStrue
;
2427 case regState_Refresh
:
2430 LogMsg("Error %ld for refresh of service %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
2431 InvokeCallback
= mDNStrue
;
2432 info
->state
= regState_Unregistered
;
2434 else info
->state
= regState_Registered
;
2436 case regState_DeregPending
:
2437 if (err
) LogMsg("Error %ld for deregistration of service %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
2438 if (info
->SRVChanged
)
2440 info
->state
= regState_NoTarget
; // NoTarget will allow us to pick up new target OR nat traversal state
2443 err
= mStatus_MemFree
;
2444 InvokeCallback
= mDNStrue
;
2447 if (nat
->state
== NATState_Deleted
) { info
->NATinfo
= mDNSNULL
; FreeNATInfo(m
, nat
); } // deletion copmleted
2448 else nat
->reg
.ServiceRegistration
= mDNSNULL
; // allow mapping deletion to continue
2450 info
->state
= regState_Unregistered
;
2452 case regState_DeregDeferred
:
2455 debugf("Error %ld received prior to deferred derigstration of %##s", err
, srs
->RR_SRV
.resrec
.name
->c
);
2456 err
= mStatus_MemFree
;
2457 InvokeCallback
= mDNStrue
;
2458 info
->state
= regState_Unregistered
;
2463 debugf("Performing deferred deregistration of %##s", srs
->RR_SRV
.resrec
.name
->c
);
2464 info
->state
= regState_Registered
;
2465 SendServiceDeregistration(m
, srs
);
2468 case regState_UpdatePending
:
2471 LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs
->RR_SRV
.resrec
.name
->c
);
2472 info
->state
= regState_Unregistered
;
2473 InvokeCallback
= mDNStrue
;
2477 info
->state
= regState_Registered
;
2478 // deallocate old RData
2479 if (txtInfo
->UpdateRDCallback
) txtInfo
->UpdateRDCallback(m
, txt
, txtInfo
->OrigRData
);
2480 SetNewRData(&txt
->resrec
, txtInfo
->InFlightRData
, txtInfo
->InFlightRDLen
);
2481 txtInfo
->OrigRData
= mDNSNULL
;
2482 txtInfo
->InFlightRData
= mDNSNULL
;
2485 case regState_FetchingZoneData
:
2486 case regState_Registered
:
2487 case regState_Cancelled
:
2488 case regState_Unregistered
:
2489 case regState_NATMap
:
2490 case regState_NoTarget
:
2491 case regState_ExtraQueued
:
2492 case regState_NATError
:
2493 LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %ld. Unlinking.",
2494 srs
->RR_SRV
.resrec
.name
->c
, info
->state
, err
);
2495 err
= mStatus_UnknownErr
;
2498 if ((info
->SRVChanged
|| info
->SRVUpdateDeferred
) && (info
->state
== regState_NoTarget
|| info
->state
== regState_Registered
))
2502 info
->ClientCallbackDeferred
= mDNStrue
;
2503 info
->DeferredStatus
= err
;
2505 info
->SRVChanged
= mDNSfalse
;
2512 uDNS_RegInfo
*einfo
= &(*e
)->r
.uDNS_info
;
2513 if (einfo
->state
== regState_ExtraQueued
)
2515 if (info
->state
== regState_Registered
&& !err
)
2517 // extra resource record queued for this service - copy zone info and register
2518 AssignDomainName(&einfo
->zone
, &info
->zone
);
2519 einfo
->ns
= info
->ns
;
2520 einfo
->port
= info
->port
;
2521 einfo
->lease
= info
->lease
;
2522 sendRecordRegistration(m
, &(*e
)->r
);
2525 else if (err
&& einfo
->state
!= regState_Unregistered
)
2527 // unlink extra from list
2528 einfo
->state
= regState_Unregistered
;
2531 else e
= &(*e
)->next
;
2533 else e
= &(*e
)->next
;
2536 srs
->RR_SRV
.ThisAPInterval
= INIT_UCAST_POLL_INTERVAL
- 1; // reset retry delay for future refreshes, dereg, etc.
2537 if (info
->state
== regState_Unregistered
) unlinkSRS(m
, srs
);
2538 else if (txtInfo
->QueuedRData
&& info
->state
== regState_Registered
)
2542 // if we were supposed to give a client callback, we'll do it after we update the primary txt record
2543 info
->ClientCallbackDeferred
= mDNStrue
;
2544 info
->DeferredStatus
= err
;
2546 info
->state
= regState_UpdatePending
;
2547 txtInfo
->InFlightRData
= txtInfo
->QueuedRData
;
2548 txtInfo
->InFlightRDLen
= txtInfo
->QueuedRDLen
;
2549 info
->OrigRData
= txt
->resrec
.rdata
;
2550 info
->OrigRDLen
= txt
->resrec
.rdlength
;
2551 txtInfo
->QueuedRData
= mDNSNULL
;
2552 SendServiceRegistration(m
, srs
);
2556 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
2557 if (InvokeCallback
) srs
->ServiceCallback(m
, srs
, err
);
2558 else if (info
->ClientCallbackDeferred
)
2560 info
->ClientCallbackDeferred
= mDNSfalse
;
2561 srs
->ServiceCallback(m
, srs
, info
->DeferredStatus
);
2563 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
2564 // NOTE: do not touch structures after calling ServiceCallback
2567 mDNSlocal
void hndlRecordUpdateReply(mDNS
*m
, AuthRecord
*rr
, mStatus err
)
2569 uDNS_RegInfo
*info
= &rr
->uDNS_info
;
2570 mDNSBool InvokeCallback
= mDNStrue
;
2572 if (info
->state
== regState_UpdatePending
)
2576 LogMsg("Update record failed for %##s (err %d)", rr
->resrec
.name
->c
, err
);
2577 info
->state
= regState_Unregistered
;
2581 debugf("Update record %##s - success", rr
->resrec
.name
->c
);
2582 info
->state
= regState_Registered
;
2583 // deallocate old RData
2584 if (info
->UpdateRDCallback
) info
->UpdateRDCallback(m
, rr
, info
->OrigRData
);
2585 SetNewRData(&rr
->resrec
, info
->InFlightRData
, info
->InFlightRDLen
);
2586 info
->OrigRData
= mDNSNULL
;
2587 info
->InFlightRData
= mDNSNULL
;
2591 if (info
->state
== regState_DeregPending
)
2593 debugf("Received reply for deregister record %##s type %d", rr
->resrec
.name
->c
, rr
->resrec
.rrtype
);
2594 if (err
) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %ld",
2595 rr
->resrec
.name
->c
, rr
->resrec
.rrtype
, err
);
2596 err
= mStatus_MemFree
;
2597 info
->state
= regState_Unregistered
;
2600 if (info
->state
== regState_DeregDeferred
)
2604 LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %ld",
2605 rr
->resrec
.name
->c
, rr
->resrec
.rrtype
, err
);
2606 info
->state
= regState_Unregistered
;
2608 debugf("Calling deferred deregistration of record %##s type %d", rr
->resrec
.name
->c
, rr
->resrec
.rrtype
);
2609 info
->state
= regState_Registered
;
2610 uDNS_DeregisterRecord(m
, rr
);
2614 if (info
->state
== regState_Pending
|| info
->state
== regState_Refresh
)
2618 info
->state
= regState_Registered
;
2619 if (info
->state
== regState_Refresh
) InvokeCallback
= mDNSfalse
;
2623 if (info
->lease
&& err
== mStatus_UnknownErr
)
2625 LogMsg("Re-trying update of record %##s without lease option", rr
->resrec
.name
->c
);
2626 info
->lease
= mDNSfalse
;
2627 sendRecordRegistration(m
, rr
);
2630 LogMsg("Registration of record %##s type %d failed with error %ld", rr
->resrec
.name
->c
, rr
->resrec
.rrtype
, err
);
2631 info
->state
= regState_Unregistered
;
2635 if (info
->state
== regState_Unregistered
) unlinkAR(&m
->uDNS_info
.RecordRegistrations
, rr
);
2636 else rr
->ThisAPInterval
= INIT_UCAST_POLL_INTERVAL
- 1; // reset retry delay for future refreshes, dereg, etc.
2638 if (info
->QueuedRData
&& info
->state
== regState_Registered
)
2640 info
->state
= regState_UpdatePending
;
2641 info
->InFlightRData
= info
->QueuedRData
;
2642 info
->InFlightRDLen
= info
->QueuedRDLen
;
2643 info
->OrigRData
= rr
->resrec
.rdata
;
2644 info
->OrigRDLen
= rr
->resrec
.rdlength
;
2645 info
->QueuedRData
= mDNSNULL
;
2646 sendRecordRegistration(m
, rr
);
2652 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
2653 if (rr
->RecordCallback
) rr
->RecordCallback(m
, rr
, err
);
2654 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
2659 mDNSlocal
void SetUpdateExpiration(mDNS
*m
, DNSMessage
*msg
, const mDNSu8
*end
, uDNS_RegInfo
*info
)
2661 LargeCacheRecord lcr
;
2667 ptr
= LocateAdditionals(msg
, end
);
2669 if (info
->lease
&& (ptr
= LocateAdditionals(msg
, end
)))
2671 for (i
= 0; i
< msg
->h
.numAdditionals
; i
++)
2673 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &lcr
);
2675 if (lcr
.r
.resrec
.rrtype
== kDNSType_OPT
)
2677 if (lcr
.r
.resrec
.rdlength
< LEASE_OPT_RDLEN
) continue;
2678 if (lcr
.r
.resrec
.rdata
->u
.opt
.opt
!= kDNSOpt_Lease
) continue;
2679 lease
= lcr
.r
.resrec
.rdata
->u
.opt
.OptData
.lease
;
2687 expire
= (mDNSPlatformTimeNow(m
) + (((mDNSs32
)lease
* mDNSPlatformOneSecond
)) * 3/4);
2688 if (info
->state
== regState_UpdatePending
)
2689 // if updating individual record, the service record set may expire sooner
2690 { if (expire
- info
->expire
< 0) info
->expire
= expire
; }
2691 else info
->expire
= expire
;
2693 else info
->lease
= mDNSfalse
;
2696 mDNSexport
void uDNS_ReceiveNATMap(mDNS
*m
, mDNSu8
*pkt
, mDNSu16 len
)
2698 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
2699 NATTraversalInfo
*ptr
= u
->NATTraversals
;
2702 // check length, version, opcode
2703 if (len
< sizeof(NATPortMapReply
) && len
< sizeof(NATAddrReply
)) { LogMsg("NAT Traversal message too short (%d bytes)", len
); return; }
2704 if (pkt
[0] != NATMAP_VERS
) { LogMsg("Received NAT Traversal response with version %d (expect version %d)", pkt
[0], NATMAP_VERS
); return; }
2706 if (!(op
& NATMAP_RESPONSE_MASK
)) { LogMsg("Received NAT Traversal message that is not a response (opcode %d)", op
); return; }
2710 if ((ptr
->state
== NATState_Request
|| ptr
->state
== NATState_Refresh
) && (ptr
->op
| NATMAP_RESPONSE_MASK
) == op
)
2711 if (ptr
->ReceiveResponse(ptr
, m
, pkt
, len
)) break; // note callback may invalidate ptr if it return value is non-zero
2716 mDNSlocal
const domainname
*DNSRelayTestQuestion
= (domainname
*)
2717 "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\xa" "dnsbugtest"
2718 "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\x7" "in-addr" "\x4" "arpa";
2720 // Returns mDNStrue if response was handled
2721 mDNSlocal mDNSBool
uDNS_ReceiveTestQuestionResponse(mDNS
*const m
, DNSMessage
*const msg
, const mDNSu8
*const end
,
2722 const mDNSAddr
*const srcaddr
, const mDNSInterfaceID InterfaceID
)
2724 const mDNSu8
*ptr
= msg
->data
;
2728 mDNSBool found
= mDNSfalse
;
2730 // 1. Find out if this is an answer to one of our test questions
2731 if (msg
->h
.numQuestions
!= 1) return(mDNSfalse
);
2732 ptr
= getQuestion(msg
, ptr
, end
, InterfaceID
, &q
);
2733 if (!ptr
) return(mDNSfalse
);
2734 if (q
.qtype
!= kDNSType_PTR
|| q
.qclass
!= kDNSClass_IN
) return(mDNSfalse
);
2735 if (!SameDomainName(&q
.qname
, DNSRelayTestQuestion
)) return(mDNSfalse
);
2737 // 2. If the DNS relay gave us a positive response, then it's got buggy firmware
2738 // else, if the DNS relay gave us an error or no-answer response, it passed our test
2739 if ((msg
->h
.flags
.b
[1] & kDNSFlag1_RC
) == kDNSFlag1_RC_NoErr
&& msg
->h
.numAnswers
> 0)
2740 result
= DNSServer_Failed
;
2742 result
= DNSServer_Passed
;
2744 // 3. Find occurrences of this server in our list, and mark them appropriately
2745 for (s
= m
->uDNS_info
.Servers
; s
; s
= s
->next
)
2746 if (mDNSSameAddress(srcaddr
, &s
->addr
) && s
->teststate
!= result
)
2747 { s
->teststate
= result
; found
= mDNStrue
; }
2749 // 4. Assuming we found the server in question in our list (don't want to risk being victim of a deliberate DOS attack here)
2750 // log a message to let the user know why Wide-Area Service Discovery isn't working
2751 if (found
&& result
== DNSServer_Failed
)
2752 LogMsg("NOTE: Wide-Area Service Discovery disabled to avoid crashing defective DNS relay %#a.", srcaddr
);
2754 return(mDNStrue
); // Return mDNStrue to tell uDNS_ReceiveMsg it doens't need to process this packet further
2757 mDNSexport
void uDNS_ReceiveMsg(mDNS
*const m
, DNSMessage
*const msg
, const mDNSu8
*const end
,
2758 const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
, const mDNSAddr
*const dstaddr
,
2759 const mDNSIPPort dstport
, const mDNSInterfaceID InterfaceID
)
2763 ServiceRecordSet
*sptr
;
2764 mStatus err
= mStatus_NoError
;
2765 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
2767 mDNSu8 StdR
= kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
;
2768 mDNSu8 UpdateR
= kDNSFlag0_QR_Response
| kDNSFlag0_OP_Update
;
2769 mDNSu8 QR_OP
= (mDNSu8
)(msg
->h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
);
2770 mDNSu8 rcode
= (mDNSu8
)(msg
->h
.flags
.b
[1] & kDNSFlag1_RC
);
2772 mDNSs32 timenow
= mDNSPlatformTimeNow(m
);
2781 // !!!KRS we should to a table lookup here to see if it answers an LLQ or a 1-shot
2782 // LLQ Responses over TCP not currently supported
2783 if (srcaddr
&& recvLLQResponse(m
, msg
, end
, srcaddr
, srcport
, InterfaceID
)) return;
2785 if (uDNS_ReceiveTestQuestionResponse(m
, msg
, end
, srcaddr
, InterfaceID
)) return;
2787 for (qptr
= u
->ActiveQueries
; qptr
; qptr
= qptr
->next
)
2789 //!!!KRS we should have a hashtable, hashed on message id
2790 if (qptr
->uDNS_info
.id
.NotAnInteger
== msg
->h
.id
.NotAnInteger
)
2792 if (timenow
- (qptr
->LastQTime
+ RESPONSE_WINDOW
) > 0)
2793 { debugf("uDNS_ReceiveMsg - response received after maximum allowed window. Discarding"); return; }
2794 if (msg
->h
.flags
.b
[0] & kDNSFlag0_TC
)
2795 { hndlTruncatedAnswer(qptr
, srcaddr
, m
); return; }
2798 u
->CurrentQuery
= qptr
;
2799 qptr
->uDNS_info
.responseCallback(m
, msg
, end
, qptr
, qptr
->uDNS_info
.context
);
2800 u
->CurrentQuery
= mDNSNULL
;
2801 // Note: responseCallback can invalidate qptr
2807 if (QR_OP
== UpdateR
)
2809 for (sptr
= u
->ServiceRegistrations
; sptr
; sptr
= sptr
->next
)
2811 if (sptr
->uDNS_info
.id
.NotAnInteger
== msg
->h
.id
.NotAnInteger
)
2813 err
= checkUpdateResult(sptr
->RR_SRV
.resrec
.name
, rcode
, m
, msg
, end
);
2814 if (!err
) SetUpdateExpiration(m
, msg
, end
, &sptr
->uDNS_info
);
2815 hndlServiceUpdateReply(m
, sptr
, err
);
2819 for (rptr
= u
->RecordRegistrations
; rptr
; rptr
= rptr
->next
)
2821 if (rptr
->uDNS_info
.id
.NotAnInteger
== msg
->h
.id
.NotAnInteger
)
2823 err
= checkUpdateResult(rptr
->resrec
.name
, rcode
, m
, msg
, end
);
2824 if (!err
) SetUpdateExpiration(m
, msg
, end
, &rptr
->uDNS_info
);
2825 hndlRecordUpdateReply(m
, rptr
, err
);
2830 debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg
->h
.id
));
2833 // lookup a DNS Server, matching by name in split-dns configurations. Result stored in addr parameter if successful
2834 mDNSlocal DNSServer
*GetServerForName(uDNS_GlobalInfo
*u
, const domainname
*name
)
2836 DNSServer
*curmatch
= mDNSNULL
, *p
= u
->Servers
;
2837 int i
, curmatchlen
= -1;
2838 int ncount
= name
? CountLabels(name
) : 0;
2842 int scount
= CountLabels(&p
->domain
);
2843 if (scount
<= ncount
&& scount
> curmatchlen
)
2845 // only inspect if server's domain is longer than current best match and shorter than the name itself
2846 const domainname
*tail
= name
;
2847 for (i
= 0; i
< ncount
- scount
; i
++)
2848 tail
= (domainname
*)(tail
->c
+ 1 + tail
->c
[0]); // find "tail" (scount labels) of name
2849 if (SameDomainName(tail
, &p
->domain
)) { curmatch
= p
; curmatchlen
= scount
; }
2856 // ***************************************************************************
2857 #if COMPILER_LIKES_PRAGMA_MARK
2858 #pragma mark - Query Routines
2861 #define sameID(x,y) mDNSPlatformMemSame(x,y,8)
2863 mDNSlocal
void initializeQuery(DNSMessage
*msg
, DNSQuestion
*question
)
2865 ubzero(msg
, sizeof(msg
));
2866 InitializeDNSMessage(&msg
->h
, question
->uDNS_info
.id
, uQueryFlags
);
2869 mDNSlocal mStatus
constructQueryMsg(DNSMessage
*msg
, mDNSu8
**endPtr
, DNSQuestion
*const question
)
2871 initializeQuery(msg
, question
);
2873 *endPtr
= putQuestion(msg
, msg
->data
, msg
->data
+ AbsoluteMaxDNSMessageData
, &question
->qname
, question
->qtype
, question
->qclass
);
2876 LogMsg("ERROR: Unicast query out of space in packet");
2877 return mStatus_UnknownErr
;
2879 return mStatus_NoError
;
2882 mDNSlocal mDNSu8
*putLLQ(DNSMessage
*const msg
, mDNSu8
*ptr
, DNSQuestion
*question
, LLQOptData
*data
, mDNSBool includeQuestion
)
2885 ResourceRecord
*opt
= &rr
.resrec
;
2888 //!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section
2889 if (includeQuestion
)
2891 ptr
= putQuestion(msg
, ptr
, msg
->data
+ AbsoluteMaxDNSMessageData
, &question
->qname
, question
->qtype
, question
->qclass
);
2892 if (!ptr
) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL
; }
2894 // locate OptRR if it exists, set pointer to end
2895 // !!!KRS implement me
2898 // format opt rr (fields not specified are zero-valued)
2899 ubzero(&rr
, sizeof(AuthRecord
));
2900 mDNS_SetupResourceRecord(&rr
, mDNSNULL
, mDNSInterface_Any
, kDNSType_OPT
, kStandardTTL
, kDNSRecordTypeKnownUnique
, mDNSNULL
, mDNSNULL
);
2901 opt
->rdlength
= LLQ_OPT_RDLEN
;
2902 opt
->rdestimate
= LLQ_OPT_RDLEN
;
2904 optRD
= &rr
.resrec
.rdata
->u
.opt
;
2905 optRD
->opt
= kDNSOpt_LLQ
;
2906 optRD
->optlen
= LLQ_OPTLEN
;
2907 umemcpy(&optRD
->OptData
.llq
, data
, sizeof(*data
));
2908 ptr
= PutResourceRecordTTLJumbo(msg
, ptr
, &msg
->h
.numAdditionals
, opt
, 0);
2909 if (!ptr
) { LogMsg("ERROR: putLLQ - PutResourceRecordTTLJumbo"); return mDNSNULL
; }
2915 mDNSlocal mDNSBool
getLLQAtIndex(mDNS
*m
, DNSMessage
*msg
, const mDNSu8
*end
, LLQOptData
*llq
, int index
)
2917 LargeCacheRecord lcr
;
2921 ubzero(&lcr
, sizeof(lcr
));
2923 ptr
= LocateAdditionals(msg
, end
);
2924 if (!ptr
) return mDNSfalse
;
2926 // find the last additional
2927 for (i
= 0; i
< msg
->h
.numAdditionals
; i
++)
2928 // { ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; }
2929 //!!!KRS workaround for LH server bug, which puts OPT as first additional
2930 { ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &lcr
); if (!ptr
) return mDNSfalse
; if (lcr
.r
.resrec
.rrtype
== kDNSType_OPT
) break; }
2931 if (lcr
.r
.resrec
.rrtype
!= kDNSType_OPT
) return mDNSfalse
;
2932 if (lcr
.r
.resrec
.rdlength
< (index
+ 1) * LLQ_OPT_RDLEN
) return mDNSfalse
; // rdata too small
2933 umemcpy(llq
, (mDNSu8
*)&lcr
.r
.resrec
.rdata
->u
.opt
.OptData
.llq
+ (index
* sizeof(*llq
)), sizeof(*llq
));
2937 mDNSlocal
void recvRefreshReply(mDNS
*m
, DNSMessage
*msg
, const mDNSu8
*end
, DNSQuestion
*q
)
2942 qInfo
= q
->uDNS_info
.llq
;
2943 if (!getLLQAtIndex(m
, msg
, end
, &pktData
, 0)) { LogMsg("ERROR recvRefreshReply - getLLQAtIndex"); return; }
2944 if (pktData
.llqOp
!= kLLQOp_Refresh
) return;
2945 if (!sameID(pktData
.id
, qInfo
->id
)) { LogMsg("recvRefreshReply - ID mismatch. Discarding"); return; }
2946 if (pktData
.err
!= LLQErr_NoError
) { LogMsg("recvRefreshReply: received error %d from server", pktData
.err
); return; }
2948 qInfo
->expire
= mDNSPlatformTimeNow(m
) + ((mDNSs32
)pktData
.lease
* mDNSPlatformOneSecond
);
2949 qInfo
->retry
= qInfo
->expire
- ((mDNSs32
)pktData
.lease
* mDNSPlatformOneSecond
/2);
2951 qInfo
->origLease
= pktData
.lease
;
2952 qInfo
->state
= LLQ_Established
;
2955 mDNSlocal
void sendLLQRefresh(mDNS
*m
, DNSQuestion
*q
, mDNSu32 lease
)
2960 LLQ_Info
*info
= q
->uDNS_info
.llq
;
2964 timenow
= mDNSPlatformTimeNow(m
);
2965 if ((info
->state
== LLQ_Refresh
&& info
->ntries
>= kLLQ_MAX_TRIES
) ||
2966 info
->expire
- timenow
< 0)
2968 LogMsg("Unable to refresh LLQ %##s - will retry in %d minutes", q
->qname
.c
, kLLQ_DEF_RETRY
/60);
2969 info
->state
= LLQ_Retry
;
2970 info
->retry
= mDNSPlatformTimeNow(m
) + kLLQ_DEF_RETRY
* mDNSPlatformOneSecond
;
2971 info
->deriveRemovesOnResume
= mDNStrue
;
2973 //!!!KRS handle this - periodically try to re-establish
2976 llq
.vers
= kLLQ_Vers
;
2977 llq
.llqOp
= kLLQOp_Refresh
;
2978 llq
.err
= LLQErr_NoError
;
2979 umemcpy(llq
.id
, info
->id
, 8);
2982 initializeQuery(&msg
, q
);
2983 end
= putLLQ(&msg
, msg
.data
, q
, &llq
, mDNStrue
);
2984 if (!end
) { LogMsg("ERROR: sendLLQRefresh - putLLQ"); return; }
2986 err
= mDNSSendDNSMessage(m
, &msg
, end
, mDNSInterface_Any
, &info
->servAddr
, info
->servPort
, -1, mDNSNULL
);
2987 if (err
) debugf("ERROR: sendLLQRefresh - mDNSSendDNSMessage returned %ld", err
);
2989 if (info
->state
== LLQ_Established
) info
->ntries
= 1;
2990 else info
->ntries
++;
2991 info
->state
= LLQ_Refresh
;
2992 q
->LastQTime
= timenow
;
2993 info
->retry
= (info
->expire
- q
->LastQTime
) / 2;
2996 mDNSlocal mDNSBool
recvLLQEvent(mDNS
*m
, DNSQuestion
*q
, DNSMessage
*msg
, const mDNSu8
*end
, const mDNSAddr
*srcaddr
, mDNSIPPort srcport
, mDNSInterfaceID InterfaceID
)
2999 mDNSu8
*ackEnd
= ack
.data
;
3003 (void)InterfaceID
; // unused
3005 // find Opt RR, verify correct ID
3006 if (!getLLQAtIndex(m
, msg
, end
, &opt
, 0)) { debugf("Pkt does not contain LLQ Opt"); return mDNSfalse
; }
3007 if (!q
->uDNS_info
.llq
) { LogMsg("Error: recvLLQEvent - question object does not contain LLQ metadata"); return mDNSfalse
; }
3008 if (!sameID(opt
.id
, q
->uDNS_info
.llq
->id
)) { return mDNSfalse
; }
3009 if (opt
.llqOp
!= kLLQOp_Event
) { if (!q
->uDNS_info
.llq
->ntries
) LogMsg("recvLLQEvent - Bad LLQ Opcode %d", opt
.llqOp
); return mDNSfalse
; }
3011 // invoke response handler
3012 m
->uDNS_info
.CurrentQuery
= q
;
3013 q
->uDNS_info
.responseCallback(m
, msg
, end
, q
, q
->uDNS_info
.context
);
3014 if (m
->uDNS_info
.CurrentQuery
!= q
) return mDNStrue
;
3016 // format and send ack
3017 InitializeDNSMessage(&ack
.h
, msg
->h
.id
, ResponseFlags
);
3018 ackEnd
= putLLQ(&ack
, ack
.data
, mDNSNULL
, &opt
, mDNSfalse
);
3019 if (!ackEnd
) { LogMsg("ERROR: recvLLQEvent - putLLQ"); return mDNSfalse
; }
3020 err
= mDNSSendDNSMessage(m
, &ack
, ackEnd
, mDNSInterface_Any
, srcaddr
, srcport
, -1, mDNSNULL
);
3021 if (err
) debugf("ERROR: recvLLQEvent - mDNSSendDNSMessage returned %ld", err
);
3027 mDNSlocal
void hndlChallengeResponseAck(mDNS
*m
, DNSMessage
*pktMsg
, const mDNSu8
*end
, LLQOptData
*llq
, DNSQuestion
*q
)
3029 LLQ_Info
*info
= q
->uDNS_info
.llq
;
3031 if (llq
->err
) { LogMsg("hndlChallengeResponseAck - received error %d from server", llq
->err
); goto error
; }
3032 if (!sameID(info
->id
, llq
->id
)) { LogMsg("hndlChallengeResponseAck - ID changed. discarding"); return; } // this can happen rarely (on packet loss + reordering)
3033 info
->expire
= mDNSPlatformTimeNow(m
) + ((mDNSs32
)llq
->lease
* mDNSPlatformOneSecond
);
3034 info
->retry
= info
->expire
- ((mDNSs32
)llq
->lease
* mDNSPlatformOneSecond
/ 2);
3036 info
->origLease
= llq
->lease
;
3037 info
->state
= LLQ_Established
;
3039 q
->uDNS_info
.responseCallback
= llqResponseHndlr
;
3040 llqResponseHndlr(m
, pktMsg
, end
, q
, mDNSNULL
);
3044 info
->state
= LLQ_Error
;
3047 mDNSlocal
void sendChallengeResponse(mDNS
*m
, DNSQuestion
*q
, LLQOptData
*llq
)
3049 LLQ_Info
*info
= q
->uDNS_info
.llq
;
3050 DNSMessage response
;
3051 mDNSu8
*responsePtr
= response
.data
;
3054 mDNSs32 timenow
= mDNSPlatformTimeNow(m
);
3056 if (info
->ntries
++ == kLLQ_MAX_TRIES
)
3058 LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s. Will re-try in %d minutes",
3059 kLLQ_MAX_TRIES
, q
->qname
.c
, kLLQ_DEF_RETRY
/ 60);
3060 info
->state
= LLQ_Retry
;
3061 info
->retry
= timenow
+ (kLLQ_DEF_RETRY
* mDNSPlatformOneSecond
);
3062 // !!!KRS give a callback error in these cases?
3069 llq
->vers
= kLLQ_Vers
;
3070 llq
->llqOp
= kLLQOp_Setup
;
3071 llq
->err
= LLQErr_NoError
;
3072 umemcpy(llq
->id
, info
->id
, 8);
3073 llq
->lease
= info
->origLease
;
3076 q
->LastQTime
= timenow
;
3077 info
->retry
= timenow
+ (kLLQ_INIT_RESEND
* info
->ntries
* mDNSPlatformOneSecond
);
3079 if (constructQueryMsg(&response
, &responsePtr
, q
)) goto error
;
3080 responsePtr
= putLLQ(&response
, responsePtr
, q
, llq
, mDNSfalse
);
3081 if (!responsePtr
) { LogMsg("ERROR: sendChallengeResponse - putLLQ"); goto error
; }
3083 err
= mDNSSendDNSMessage(m
, &response
, responsePtr
, mDNSInterface_Any
, &info
->servAddr
, info
->servPort
, -1, mDNSNULL
);
3084 if (err
) debugf("ERROR: sendChallengeResponse - mDNSSendDNSMessage returned %ld", err
);
3085 // on error, we procede as normal and retry after the appropriate interval
3090 info
->state
= LLQ_Error
;
3095 mDNSlocal
void hndlRequestChallenge(mDNS
*m
, DNSMessage
*pktMsg
, const mDNSu8
*end
, LLQOptData
*llq
, DNSQuestion
*q
)
3097 LLQ_Info
*info
= q
->uDNS_info
.llq
;
3098 mDNSs32 timenow
= mDNSPlatformTimeNow(m
);
3101 case LLQErr_NoError
: break;
3102 case LLQErr_ServFull
:
3103 LogMsg("hndlRequestChallenge - received ServFull from server for LLQ %##s. Retry in %lu sec", q
->qname
.c
, llq
->lease
);
3104 info
->retry
= timenow
+ ((mDNSs32
)llq
->lease
* mDNSPlatformOneSecond
);
3105 info
->state
= LLQ_Retry
;
3106 simpleResponseHndlr(m
, pktMsg
, end
, q
, mDNSNULL
); // get available answers
3107 info
->deriveRemovesOnResume
= mDNStrue
;
3109 info
->state
= LLQ_Static
;
3110 LogMsg("LLQ %##s: static", q
->qname
.c
);
3111 simpleResponseHndlr(m
, pktMsg
, end
, q
, mDNSNULL
);
3113 case LLQErr_FormErr
:
3114 LogMsg("ERROR: hndlRequestChallenge - received FormErr from server for LLQ %##s", q
->qname
.c
);
3116 case LLQErr_BadVers
:
3117 LogMsg("ERROR: hndlRequestChallenge - received BadVers from server");
3119 case LLQErr_UnknownErr
:
3120 LogMsg("ERROR: hndlRequestChallenge - received UnknownErr from server for LLQ %##s", q
->qname
.c
);
3123 LogMsg("ERROR: hndlRequestChallenge - received invalid error %d for LLQ %##s", llq
->err
, q
->qname
.c
);
3127 if (info
->origLease
!= llq
->lease
)
3128 debugf("hndlRequestChallenge: requested lease %lu, granted lease %lu", info
->origLease
, llq
->lease
);
3130 // cache expiration in case we go to sleep before finishing setup
3131 info
->origLease
= llq
->lease
;
3132 info
->expire
= timenow
+ ((mDNSs32
)llq
->lease
* mDNSPlatformOneSecond
);
3135 info
->state
= LLQ_SecondaryRequest
;
3136 umemcpy(info
->id
, llq
->id
, 8);
3137 info
->ntries
= 0; // first attempt to send response
3139 sendChallengeResponse(m
, q
, llq
);
3144 info
->state
= LLQ_Error
;
3148 // response handler for initial and secondary setup responses
3149 mDNSlocal
void recvSetupResponse(mDNS
*m
, DNSMessage
*pktMsg
, const mDNSu8
*end
, DNSQuestion
*q
, void *clientContext
)
3151 DNSQuestion pktQuestion
;
3153 const mDNSu8
*ptr
= pktMsg
->data
;
3154 LLQ_Info
*info
= q
->uDNS_info
.llq
;
3155 mDNSu8 rcode
= (mDNSu8
)(pktMsg
->h
.flags
.b
[1] & kDNSFlag1_RC
);
3157 (void)clientContext
; // unused
3159 if (rcode
&& rcode
!= kDNSFlag1_RC_NXDomain
) goto poll
;
3161 ptr
= getQuestion(pktMsg
, ptr
, end
, 0, &pktQuestion
);
3162 if (!ptr
) { LogMsg("ERROR: recvSetupResponse - getQuestion"); goto poll
; }
3163 if (!SameDomainName(&q
->qname
, &pktQuestion
.qname
))
3164 { LogMsg("ERROR: recvSetupResponse - mismatched question in response for llq setup %##s", q
->qname
.c
); goto poll
; }
3166 if (!getLLQAtIndex(m
, pktMsg
, end
, &llq
, 0)) { debugf("recvSetupResponse - GetLLQAtIndex"); goto poll
; }
3167 if (llq
.llqOp
!= kLLQOp_Setup
) { LogMsg("ERROR: recvSetupResponse - bad op %d", llq
.llqOp
); goto poll
; }
3168 if (llq
.vers
!= kLLQ_Vers
) { LogMsg("ERROR: recvSetupResponse - bad vers %d", llq
.vers
); goto poll
; }
3170 if (info
->state
== LLQ_InitialRequest
) { hndlRequestChallenge(m
, pktMsg
, end
, &llq
, q
); return; }
3171 if (info
->state
== LLQ_SecondaryRequest
) { hndlChallengeResponseAck(m
, pktMsg
, end
, &llq
, q
); return; }
3172 LogMsg("recvSetupResponse - bad state %d", info
->state
);
3175 info
->state
= LLQ_Poll
;
3176 q
->uDNS_info
.responseCallback
= llqResponseHndlr
;
3177 info
->question
->LastQTime
= mDNSPlatformTimeNow(m
) - (2 * INIT_UCAST_POLL_INTERVAL
); // trigger immediate poll
3178 info
->question
->ThisQInterval
= INIT_UCAST_POLL_INTERVAL
;
3181 mDNSlocal
void startLLQHandshake(mDNS
*m
, LLQ_Info
*info
, mDNSBool defer
)
3186 DNSQuestion
*q
= info
->question
;
3187 mStatus err
= mStatus_NoError
;
3188 mDNSs32 timenow
= mDNSPlatformTimeNow(m
);
3189 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
3191 if (IsPrivateV4Addr(&u
->AdvertisedV4
))
3195 info
->state
= LLQ_NatMapWait
;
3199 if (u
->LLQNatInfo
->state
== NATState_Error
) goto poll
;
3200 if (u
->LLQNatInfo
->state
!= NATState_Established
&& u
->LLQNatInfo
->state
!= NATState_Legacy
)
3201 { info
->state
= LLQ_NatMapWait
; info
->NATMap
= mDNStrue
; return; }
3202 info
->NATMap
= mDNStrue
; // this llq references the global llq nat mapping
3205 if (info
->ntries
++ >= kLLQ_MAX_TRIES
)
3207 debugf("startLLQHandshake: %d failed attempts for LLQ %##s. Polling.", kLLQ_MAX_TRIES
, q
->qname
.c
, kLLQ_DEF_RETRY
/ 60);
3212 llqData
.vers
= kLLQ_Vers
;
3213 llqData
.llqOp
= kLLQOp_Setup
;
3214 llqData
.err
= LLQErr_NoError
;
3215 ubzero(llqData
.id
, 8);
3216 llqData
.lease
= kLLQ_DefLease
;
3218 initializeQuery(&msg
, q
);
3219 end
= putLLQ(&msg
, msg
.data
, q
, &llqData
, mDNStrue
);
3222 LogMsg("ERROR: startLLQHandshake - putLLQ");
3223 info
->state
= LLQ_Error
;
3227 if (!defer
) // if we are to defer, we simply set the retry timers so the request goes out in the future
3229 err
= mDNSSendDNSMessage(m
, &msg
, end
, mDNSInterface_Any
, &info
->servAddr
, info
->servPort
, -1, mDNSNULL
);
3230 if (err
) debugf("ERROR: startLLQHandshake - mDNSSendDNSMessage returned %ld", err
);
3231 // on error, we procede as normal and retry after the appropriate interval
3234 // update question/info state
3235 info
->state
= LLQ_InitialRequest
;
3236 info
->origLease
= kLLQ_DefLease
;
3237 info
->retry
= timenow
+ (kLLQ_INIT_RESEND
* mDNSPlatformOneSecond
);
3238 q
->LastQTime
= timenow
;
3239 q
->uDNS_info
.responseCallback
= recvSetupResponse
;
3240 q
->uDNS_info
.internal
= mDNStrue
;
3244 info
->question
->uDNS_info
.responseCallback
= llqResponseHndlr
;
3245 info
->state
= LLQ_Poll
;
3246 info
->question
->LastQTime
= mDNSPlatformTimeNow(m
) - (2 * INIT_UCAST_POLL_INTERVAL
); // trigger immediate poll
3247 info
->question
->ThisQInterval
= INIT_UCAST_POLL_INTERVAL
;
3250 // wrapper for startLLQHandshake, invoked by async op callback
3251 mDNSlocal
void startLLQHandshakeCallback(mStatus err
, mDNS
*const m
, void *llqInfo
, const AsyncOpResult
*result
)
3253 LLQ_Info
*info
= (LLQ_Info
*)llqInfo
;
3254 const zoneData_t
*zoneInfo
= mDNSNULL
;
3256 // check state first to make sure it is OK to touch question object
3257 if (info
->state
== LLQ_Cancelled
)
3259 // StopQuery was called while we were getting the zone info
3260 debugf("startLLQHandshake - LLQ Cancelled.");
3261 info
->question
= mDNSNULL
; // question may be deallocated
3266 if (!info
->question
)
3267 { LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL question"); goto error
; }
3269 if (info
->state
!= LLQ_GetZoneInfo
)
3270 { LogMsg("ERROR: startLLQHandshake - bad state %d", info
->state
); goto error
; }
3273 { LogMsg("ERROR: startLLQHandshakeCallback %##s invoked with error code %ld", info
->question
->qname
.c
, err
); goto poll
; }
3276 { LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL result and no error code"); goto error
; }
3278 zoneInfo
= &result
->zoneData
;
3280 if (!zoneInfo
->llqPort
.NotAnInteger
)
3281 { debugf("LLQ port lookup failed - reverting to polling"); info
->servPort
.NotAnInteger
= 0; goto poll
; }
3283 // cache necessary zone data
3284 info
->servAddr
= zoneInfo
->primaryAddr
;
3285 info
->servPort
= zoneInfo
->llqPort
;
3288 if (info
->state
== LLQ_SuspendDeferred
) info
->state
= LLQ_Suspended
;
3289 else startLLQHandshake(m
, info
, mDNSfalse
);
3293 info
->question
->uDNS_info
.responseCallback
= llqResponseHndlr
;
3294 info
->state
= LLQ_Poll
;
3295 info
->question
->LastQTime
= mDNSPlatformTimeNow(m
) - (2 * INIT_UCAST_POLL_INTERVAL
); // trigger immediate poll
3296 info
->question
->ThisQInterval
= INIT_UCAST_POLL_INTERVAL
;
3300 info
->state
= LLQ_Error
;
3303 mDNSlocal mStatus
startLLQ(mDNS
*m
, DNSQuestion
*question
)
3306 mStatus err
= mStatus_NoError
;
3308 // allocate / init info struct
3309 info
= umalloc(sizeof(LLQ_Info
));
3310 if (!info
) { LogMsg("ERROR: startLLQ - malloc"); return mStatus_NoMemoryErr
; }
3311 ubzero(info
, sizeof(LLQ_Info
));
3312 info
->state
= LLQ_GetZoneInfo
;
3314 // link info/question
3315 info
->question
= question
;
3316 question
->uDNS_info
.llq
= info
;
3318 question
->uDNS_info
.responseCallback
= llqResponseHndlr
;
3320 err
= startGetZoneData(&question
->qname
, m
, mDNSfalse
, mDNStrue
, startLLQHandshakeCallback
, info
);
3323 LogMsg("ERROR: startLLQ - startGetZoneData returned %ld", err
);
3324 info
->question
= mDNSNULL
;
3326 question
->uDNS_info
.llq
= mDNSNULL
;
3330 LinkActiveQuestion(&m
->uDNS_info
, question
);
3334 mDNSlocal mDNSBool
recvLLQResponse(mDNS
*m
, DNSMessage
*msg
, const mDNSu8
*end
, const mDNSAddr
*srcaddr
, mDNSIPPort srcport
, const mDNSInterfaceID InterfaceID
)
3336 DNSQuestion pktQ
, *q
;
3337 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
3338 const mDNSu8
*ptr
= msg
->data
;
3341 if (!msg
->h
.numQuestions
) return mDNSfalse
;
3343 ptr
= getQuestion(msg
, ptr
, end
, 0, &pktQ
);
3344 if (!ptr
) return mDNSfalse
;
3345 pktQ
.uDNS_info
.id
= msg
->h
.id
;
3347 q
= u
->ActiveQueries
;
3350 llqInfo
= q
->uDNS_info
.llq
;
3353 q
->qnamehash
== pktQ
.qnamehash
&&
3354 q
->qtype
== pktQ
.qtype
&&
3355 SameDomainName(&q
->qname
, &pktQ
.qname
))
3357 u
->CurrentQuery
= q
;
3358 if (llqInfo
->state
== LLQ_Established
|| (llqInfo
->state
== LLQ_Refresh
&& msg
->h
.numAnswers
))
3359 { if (recvLLQEvent(m
, q
, msg
, end
, srcaddr
, srcport
, InterfaceID
)) return mDNStrue
; }
3360 else if (msg
->h
.id
.NotAnInteger
== q
->uDNS_info
.id
.NotAnInteger
)
3362 if (llqInfo
->state
== LLQ_Refresh
&& msg
->h
.numAdditionals
&& !msg
->h
.numAnswers
)
3363 { recvRefreshReply(m
, msg
, end
, q
); return mDNStrue
; }
3364 if (llqInfo
->state
< LLQ_Static
)
3366 if ((llqInfo
->state
!= LLQ_InitialRequest
&& llqInfo
->state
!= LLQ_SecondaryRequest
) || mDNSSameAddress(srcaddr
, &llqInfo
->servAddr
))
3367 { q
->uDNS_info
.responseCallback(m
, msg
, end
, q
, q
->uDNS_info
.context
); return mDNStrue
; }
3376 mDNSexport mDNSBool
uDNS_IsActiveQuery(DNSQuestion
*const question
, uDNS_GlobalInfo
*u
)
3380 for (q
= u
->ActiveQueries
; q
; q
= q
->next
)
3384 if (!question
->uDNS_info
.id
.NotAnInteger
|| question
->InterfaceID
== mDNSInterface_LocalOnly
|| IsLocalDomain(&question
->qname
))
3385 LogMsg("Warning: Question %##s in Active Unicast Query list with id %d, interfaceID %p",
3386 question
->qname
.c
, question
->uDNS_info
.id
.NotAnInteger
, question
->InterfaceID
);
3393 // stopLLQ happens IN ADDITION to stopQuery
3394 mDNSlocal
void stopLLQ(mDNS
*m
, DNSQuestion
*question
)
3396 LLQ_Info
*info
= question
->uDNS_info
.llq
;
3399 if (!question
->LongLived
) { LogMsg("ERROR: stopLLQ - LongLived flag not set"); return; }
3400 if (!info
) { LogMsg("ERROR: stopLLQ - llq info is NULL"); return; }
3402 switch (info
->state
)
3405 LogMsg("ERROR: stopLLQ - state LLQ_UnInit");
3406 //!!!KRS should we unlink info<->question here?
3408 case LLQ_GetZoneInfo
:
3409 case LLQ_SuspendDeferred
:
3410 info
->question
= mDNSNULL
; // remove ref to question, as it may be freed when we get called back from async op
3411 info
->state
= LLQ_Cancelled
;
3413 case LLQ_Established
:
3415 // refresh w/ lease 0
3416 sendLLQRefresh(m
, question
, 0);
3419 debugf("stopLLQ - silently discarding LLQ in state %d", info
->state
);
3424 if (info
->NATMap
) info
->NATMap
= mDNSfalse
;
3425 CheckForUnreferencedLLQMapping(m
);
3426 info
->question
= mDNSNULL
;
3428 question
->uDNS_info
.llq
= mDNSNULL
;
3429 question
->LongLived
= mDNSfalse
;
3432 mDNSexport mStatus
uDNS_StopQuery(mDNS
*const m
, DNSQuestion
*const question
)
3434 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
3435 DNSQuestion
*qptr
, *prev
= mDNSNULL
;
3438 qptr
= u
->ActiveQueries
;
3441 if (qptr
== question
)
3443 if (question
->LongLived
&& question
->uDNS_info
.llq
)
3444 stopLLQ(m
, question
);
3445 if (m
->uDNS_info
.CurrentQuery
== question
)
3446 m
->uDNS_info
.CurrentQuery
= m
->uDNS_info
.CurrentQuery
->next
;
3447 while (question
->uDNS_info
.knownAnswers
)
3449 ka
= question
->uDNS_info
.knownAnswers
;
3450 question
->uDNS_info
.knownAnswers
= question
->uDNS_info
.knownAnswers
->next
;
3453 if (prev
) prev
->next
= question
->next
;
3454 else u
->ActiveQueries
= question
->next
;
3455 return mStatus_NoError
;
3460 LogMsg("uDNS_StopQuery: no such active query (%##s)", question
->qname
.c
);
3461 return mStatus_UnknownErr
;
3464 mDNSlocal mStatus
startQuery(mDNS
*const m
, DNSQuestion
*const question
, mDNSBool internal
)
3466 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
3467 //!!!KRS we should check if the question is already in our activequestion list
3468 if (!ValidateDomainName(&question
->qname
))
3470 LogMsg("Attempt to start query with invalid qname %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
3471 return mStatus_Invalid
;
3474 question
->next
= mDNSNULL
;
3475 question
->qnamehash
= DomainNameHashValue(&question
->qname
); // to do quick domain name comparisons
3476 question
->uDNS_info
.id
= newMessageID(u
);
3477 question
->uDNS_info
.Answered
= mDNSfalse
;
3479 // break here if its and LLQ
3480 if (question
->LongLived
) return startLLQ(m
, question
);
3482 question
->ThisQInterval
= INIT_UCAST_POLL_INTERVAL
/ 2;
3483 question
->LastQTime
= mDNSPlatformTimeNow(m
) - question
->ThisQInterval
;
3484 // store the question/id in active question list
3485 question
->uDNS_info
.internal
= internal
;
3486 LinkActiveQuestion(u
, question
);
3487 question
->uDNS_info
.knownAnswers
= mDNSNULL
;
3488 LogOperation("uDNS startQuery: %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
3490 return mStatus_NoError
;
3493 mDNSexport mStatus
uDNS_StartQuery(mDNS
*const m
, DNSQuestion
*const question
)
3495 ubzero(&question
->uDNS_info
, sizeof(uDNS_QuestionInfo
));
3496 question
->uDNS_info
.responseCallback
= simpleResponseHndlr
;
3497 question
->uDNS_info
.context
= mDNSNULL
;
3498 //LogOperation("uDNS_StartQuery %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
3499 return startQuery(m
, question
, 0);
3502 // explicitly set response handler
3503 mDNSlocal mStatus
startInternalQuery(DNSQuestion
*q
, mDNS
*m
, InternalResponseHndlr callback
, void *hndlrContext
)
3505 ubzero(&q
->uDNS_info
, sizeof(uDNS_QuestionInfo
));
3506 q
->QuestionContext
= hndlrContext
;
3507 q
->uDNS_info
.responseCallback
= callback
;
3508 q
->uDNS_info
.context
= hndlrContext
;
3509 return startQuery(m
, q
, 1);
3514 // ***************************************************************************
3515 #if COMPILER_LIKES_PRAGMA_MARK
3516 #pragma mark - Domain -> Name Server Conversion
3522 * Asynchronously find the address of the nameserver for the enclosing zone for a given domain name,
3523 * i.e. the server to which update and LLQ requests will be sent for a given name. Once the address is
3524 * derived, it will be passed to the callback, along with a context pointer. If the zone cannot
3525 * be determined or if an error occurs, an all-zeros address will be passed and a message will be
3526 * written to the syslog.
3528 * If the FindUpdatePort arg is set, the port on which the server accepts dynamic updates is determined
3529 * by querying for the _dns-update._udp.<zone>. SRV record. Likewise, if the FindLLQPort arg is set,
3530 * the port on which the server accepts long lived queries is determined by querying for
3531 * _dns-llq._udp.<zone>. record. If either of these queries fail, or flags are not specified,
3532 * the llqPort and updatePort fields in the result structure are set to zero.
3534 * Steps for deriving the zone name are as follows:
3536 * Query for an SOA record for the required domain. If we don't get an answer (or an SOA in the Authority
3537 * section), we strip the leading label from the name and repeat, until we get an answer.
3539 * The name of the SOA record is our enclosing zone. The mname field in the SOA rdata is the domain
3540 * name of the primary NS.
3542 * We verify that there is an NS record with this zone for a name and the mname for its rdata.
3543 * (!!!KRS this seems redundant, but BIND does this, and it should normally be zero-overhead since
3544 * the NS query will get us address records in the additionals section, which we'd otherwise have to
3545 * explicitly query for.)
3547 * We then query for the address record for this nameserver (if it is not in the addionals section of
3548 * the NS record response.)
3552 // state machine types and structs
3555 // state machine states
3570 // state machine actions
3573 smContinue
, // continue immediately to next state
3574 smBreak
, // break until next packet/timeout
3575 smError
// terminal error - cleanup and abort
3580 domainname origName
; // name we originally try to convert
3581 domainname
*curSOA
; // name we have an outstanding SOA query for
3582 ntaState state
; // determines what we do upon receiving a packet
3584 domainname zone
; // left-hand-side of SOA record
3586 domainname ns
; // mname in SOA rdata, verified in confirmNS state
3587 mDNSv4Addr addr
; // address of nameserver
3588 DNSQuestion question
; // storage for any active question
3589 DNSQuestion extraQuestion
; // additional storage
3590 mDNSBool questionActive
; // if true, StopQuery() can be called on the question field
3591 mDNSBool findUpdatePort
;
3592 mDNSBool findLLQPort
;
3593 mDNSIPPort updatePort
;
3595 AsyncOpCallback
*callback
; // caller specified function to be called upon completion
3600 // function prototypes (for routines that must be used as fn pointers prior to their definitions,
3601 // and allows states to be read top-to-bottom in logical order)
3602 mDNSlocal
void getZoneData(mDNS
*const m
, DNSMessage
*msg
, const mDNSu8
*end
, DNSQuestion
*question
, void *contextPtr
);
3603 mDNSlocal smAction
hndlLookupSOA(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
);
3604 mDNSlocal
void processSOA(ntaContext
*context
, ResourceRecord
*rr
);
3605 mDNSlocal smAction
confirmNS(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
);
3606 mDNSlocal smAction
lookupNSAddr(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
);
3607 mDNSlocal smAction
hndlLookupPorts(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
);
3610 mDNSlocal mStatus
startGetZoneData(domainname
*name
, mDNS
*m
, mDNSBool findUpdatePort
, mDNSBool findLLQPort
,
3611 AsyncOpCallback callback
, void *callbackInfo
)
3613 ntaContext
*context
= (ntaContext
*)umalloc(sizeof(ntaContext
));
3614 if (!context
) { LogMsg("ERROR: startGetZoneData - umalloc failed"); return mStatus_NoMemoryErr
; }
3615 ubzero(context
, sizeof(ntaContext
));
3616 AssignDomainName(&context
->origName
, name
);
3617 context
->state
= init
;
3619 context
->callback
= callback
;
3620 context
->callbackInfo
= callbackInfo
;
3621 context
->findUpdatePort
= findUpdatePort
;
3622 context
->findLLQPort
= findLLQPort
;
3623 getZoneData(m
, mDNSNULL
, mDNSNULL
, mDNSNULL
, context
);
3624 return mStatus_NoError
;
3627 // state machine entry routine
3628 mDNSlocal
void getZoneData(mDNS
*const m
, DNSMessage
*msg
, const mDNSu8
*end
, DNSQuestion
*question
, void *contextPtr
)
3630 AsyncOpResult result
;
3631 ntaContext
*context
= (ntaContext
*)contextPtr
;
3638 // stop any active question
3639 if (context
->questionActive
)
3641 uDNS_StopQuery(context
->m
, &context
->question
);
3642 context
->questionActive
= mDNSfalse
;
3645 if (msg
&& msg
->h
.flags
.b
[2] >> 4 && msg
->h
.flags
.b
[2] >> 4 != kDNSFlag1_RC_NXDomain
)
3647 // rcode non-zero, non-nxdomain
3648 LogMsg("ERROR: getZoneData - received response w/ rcode %d", msg
->h
.flags
.b
[2] >> 4);
3652 switch (context
->state
)
3656 action
= hndlLookupSOA(msg
, end
, context
);
3657 if (action
== smError
) goto error
;
3658 if (action
== smBreak
) return;
3661 action
= confirmNS(msg
, end
, context
);
3662 if (action
== smError
) goto error
;
3663 if (action
== smBreak
) return;
3666 action
= lookupNSAddr(msg
, end
, context
);
3667 if (action
== smError
) goto error
;
3668 if (action
== smBreak
) return;
3670 if (!context
->findUpdatePort
&& !context
->findLLQPort
)
3672 context
->state
= complete
;
3676 action
= hndlLookupPorts(msg
, end
, context
);
3677 if (action
== smError
) goto error
;
3678 if (action
== smBreak
) return;
3679 if (action
== smContinue
) context
->state
= complete
;
3681 case complete
: break;
3684 if (context
->state
!= complete
)
3686 LogMsg("ERROR: getZoneData - exited state machine with state %d", context
->state
);
3690 result
.type
= zoneDataResult
;
3691 result
.zoneData
.primaryAddr
.ip
.v4
= context
->addr
;
3692 result
.zoneData
.primaryAddr
.type
= mDNSAddrType_IPv4
;
3693 AssignDomainName(&result
.zoneData
.zoneName
, &context
->zone
);
3694 result
.zoneData
.zoneClass
= context
->zoneClass
;
3695 result
.zoneData
.llqPort
= context
->findLLQPort
? context
->llqPort
: zeroIPPort
;
3696 result
.zoneData
.updatePort
= context
->findUpdatePort
? context
->updatePort
: zeroIPPort
;
3697 context
->callback(mStatus_NoError
, context
->m
, context
->callbackInfo
, &result
);
3701 if (context
&& context
->callback
)
3702 context
->callback(mStatus_UnknownErr
, context
->m
, context
->callbackInfo
, mDNSNULL
);
3704 if (context
&& context
->questionActive
)
3706 uDNS_StopQuery(context
->m
, &context
->question
);
3707 context
->questionActive
= mDNSfalse
;
3709 if (context
) ufree(context
);
3712 mDNSlocal smAction
hndlLookupSOA(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
)
3715 LargeCacheRecord lcr
;
3716 ResourceRecord
*rr
= &lcr
.r
.resrec
;
3717 DNSQuestion
*query
= &context
->question
;
3722 // if msg contains SOA record in answer or authority sections, update context/state and return
3724 ptr
= LocateAnswers(msg
, end
);
3725 for (i
= 0; i
< msg
->h
.numAnswers
; i
++)
3727 ptr
= GetLargeResourceRecord(context
->m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
3728 if (!ptr
) { LogMsg("ERROR: hndlLookupSOA, Answers - GetLargeResourceRecord returned NULL"); return smError
; }
3729 if (rr
->rrtype
== kDNSType_SOA
&& SameDomainName(context
->curSOA
, rr
->name
))
3731 processSOA(context
, rr
);
3735 ptr
= LocateAuthorities(msg
, end
);
3736 // SOA not in answers, check in authority
3737 for (i
= 0; i
< msg
->h
.numAuthorities
; i
++)
3739 ptr
= GetLargeResourceRecord(context
->m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
); ///!!!KRS using type PacketAns for auth
3740 if (!ptr
) { LogMsg("ERROR: hndlLookupSOA, Authority - GetLargeResourceRecord returned NULL"); return smError
; }
3741 if (rr
->rrtype
== kDNSType_SOA
)
3743 processSOA(context
, rr
);
3749 if (context
->state
!= init
&& !context
->curSOA
->c
[0])
3751 // we've gone down to the root and have not found an SOA
3752 LogMsg("ERROR: hndlLookupSOA - recursed to root label of %##s without finding SOA",
3753 context
->origName
.c
);
3757 ubzero(query
, sizeof(DNSQuestion
));
3758 // chop off leading label unless this is our first try
3759 if (context
->state
== init
) context
->curSOA
= &context
->origName
;
3760 else context
->curSOA
= (domainname
*)(context
->curSOA
->c
+ context
->curSOA
->c
[0]+1);
3762 context
->state
= lookupSOA
;
3763 AssignDomainName(&query
->qname
, context
->curSOA
);
3764 query
->qtype
= kDNSType_SOA
;
3765 query
->qclass
= kDNSClass_IN
;
3766 err
= startInternalQuery(query
, context
->m
, getZoneData
, context
);
3767 context
->questionActive
= mDNStrue
;
3768 if (err
) LogMsg("hndlLookupSOA: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err
);
3770 return smBreak
; // break from state machine until we receive another packet
3773 mDNSlocal
void processSOA(ntaContext
*context
, ResourceRecord
*rr
)
3775 AssignDomainName(&context
->zone
, rr
->name
);
3776 context
->zoneClass
= rr
->rrclass
;
3777 AssignDomainName(&context
->ns
, &rr
->rdata
->u
.soa
.mname
);
3778 context
->state
= foundZone
;
3782 mDNSlocal smAction
confirmNS(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
)
3784 DNSQuestion
*query
= &context
->question
;
3786 LargeCacheRecord lcr
;
3787 const ResourceRecord
*const rr
= &lcr
.r
.resrec
;
3791 if (context
->state
== foundZone
)
3793 // we've just learned the zone. confirm that an NS record exists
3794 AssignDomainName(&query
->qname
, &context
->zone
);
3795 query
->qtype
= kDNSType_NS
;
3796 query
->qclass
= kDNSClass_IN
;
3797 err
= startInternalQuery(query
, context
->m
, getZoneData
, context
);
3798 context
->questionActive
= mDNStrue
;
3799 if (err
) LogMsg("confirmNS: startInternalQuery returned error %ld (breaking until next periodic retransmission", err
);
3800 context
->state
= lookupNS
;
3801 return smBreak
; // break from SM until we receive another packet
3803 else if (context
->state
== lookupNS
)
3805 ptr
= LocateAnswers(msg
, end
);
3806 for (i
= 0; i
< msg
->h
.numAnswers
; i
++)
3808 ptr
= GetLargeResourceRecord(context
->m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
3809 if (!ptr
) { LogMsg("ERROR: confirmNS, Answers - GetLargeResourceRecord returned NULL"); return smError
; }
3810 if (rr
->rrtype
== kDNSType_NS
&&
3811 SameDomainName(&context
->zone
, rr
->name
) && SameDomainName(&context
->ns
, &rr
->rdata
->u
.name
))
3813 context
->state
= foundNS
;
3814 return smContinue
; // next routine will examine additionals section of A record
3817 debugf("ERROR: could not confirm existence of record %##s NS %##s", context
->zone
.c
, context
->ns
.c
);
3820 else { LogMsg("ERROR: confirmNS - bad state %d", context
->state
); return smError
; }
3823 mDNSlocal smAction
queryNSAddr(ntaContext
*context
)
3826 DNSQuestion
*query
= &context
->question
;
3828 AssignDomainName(&query
->qname
, &context
->ns
);
3829 query
->qtype
= kDNSType_A
;
3830 query
->qclass
= kDNSClass_IN
;
3831 err
= startInternalQuery(query
, context
->m
, getZoneData
, context
);
3832 context
->questionActive
= mDNStrue
;
3833 if (err
) LogMsg("confirmNS: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err
);
3834 context
->state
= lookupA
;
3838 mDNSlocal smAction
lookupNSAddr(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
)
3842 LargeCacheRecord lcr
;
3843 ResourceRecord
*rr
= &lcr
.r
.resrec
;
3845 if (context
->state
== foundNS
)
3847 // we just found the NS record - look for the corresponding A record in the Additionals section
3848 if (!msg
->h
.numAdditionals
) return queryNSAddr(context
);
3849 ptr
= LocateAdditionals(msg
, end
);
3852 LogMsg("ERROR: lookupNSAddr - LocateAdditionals returned NULL, expected %d additionals", msg
->h
.numAdditionals
);
3853 return queryNSAddr(context
);
3857 for (i
= 0; i
< msg
->h
.numAdditionals
; i
++)
3859 ptr
= GetLargeResourceRecord(context
->m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
3862 LogMsg("ERROR: lookupNSAddr, Additionals - GetLargeResourceRecord returned NULL");
3863 return queryNSAddr(context
);
3865 if (rr
->rrtype
== kDNSType_A
&& SameDomainName(&context
->ns
, rr
->name
))
3867 context
->addr
= rr
->rdata
->u
.ipv4
;
3868 context
->state
= foundA
;
3873 // no A record in Additionals - query the server
3874 return queryNSAddr(context
);
3876 else if (context
->state
== lookupA
)
3878 ptr
= LocateAnswers(msg
, end
);
3879 if (!ptr
) { LogMsg("ERROR: lookupNSAddr: LocateAnswers returned NULL"); return smError
; }
3880 for (i
= 0; i
< msg
->h
.numAnswers
; i
++)
3882 ptr
= GetLargeResourceRecord(context
->m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
3883 if (!ptr
) { LogMsg("ERROR: lookupNSAddr, Answers - GetLargeResourceRecord returned NULL"); break; }
3884 if (rr
->rrtype
== kDNSType_A
&& SameDomainName(&context
->ns
, rr
->name
))
3886 context
->addr
= rr
->rdata
->u
.ipv4
;
3887 context
->state
= foundA
;
3891 LogMsg("ERROR: lookupNSAddr: Address record not found in answer section");
3894 else { LogMsg("ERROR: lookupNSAddr - bad state %d", context
->state
); return smError
; }
3897 mDNSlocal smAction
lookupDNSPort(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
, char *portName
, mDNSIPPort
*port
)
3900 LargeCacheRecord lcr
;
3905 if (context
->state
== lookupPort
) // we've already issued the query
3907 if (!msg
) { LogMsg("ERROR: hndlLookupUpdatePort - NULL message"); return smError
; }
3908 ptr
= LocateAnswers(msg
, end
);
3909 for (i
= 0; i
< msg
->h
.numAnswers
; i
++)
3911 ptr
= GetLargeResourceRecord(context
->m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
3912 if (!ptr
) { LogMsg("ERROR: hndlLookupUpdatePort - GetLargeResourceRecord returned NULL"); return smError
; }
3913 if (ResourceRecordAnswersQuestion(&lcr
.r
.resrec
, &context
->question
))
3915 *port
= lcr
.r
.resrec
.rdata
->u
.srv
.port
;
3916 context
->state
= foundPort
;
3920 debugf("hndlLookupUpdatePort - no answer for type %s", portName
);
3921 port
->NotAnInteger
= 0;
3922 context
->state
= foundPort
;
3926 // query the server for the update port for the zone
3927 context
->state
= lookupPort
;
3928 q
= &context
->question
;
3929 MakeDomainNameFromDNSNameString(&q
->qname
, portName
);
3930 AppendDomainName(&q
->qname
, &context
->zone
);
3931 q
->qtype
= kDNSType_SRV
;
3932 q
->qclass
= kDNSClass_IN
;
3933 err
= startInternalQuery(q
, context
->m
, getZoneData
, context
);
3934 context
->questionActive
= mDNStrue
;
3935 if (err
) LogMsg("hndlLookupSOA: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err
);
3936 return smBreak
; // break from state machine until we receive another packet
3939 mDNSlocal smAction
hndlLookupPorts(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
)
3943 if (context
->findUpdatePort
&& !context
->updatePort
.NotAnInteger
)
3945 action
= lookupDNSPort(msg
, end
, context
, UPDATE_PORT_NAME
, &context
->updatePort
);
3946 if (action
!= smContinue
) return action
;
3948 if (context
->findLLQPort
&& !context
->llqPort
.NotAnInteger
)
3949 return lookupDNSPort(msg
, end
, context
, LLQ_PORT_NAME
, &context
->llqPort
);
3955 // ***************************************************************************
3956 #if COMPILER_LIKES_PRAGMA_MARK
3957 #pragma mark - Truncation Handling
3962 DNSQuestion
*question
;
3969 // issue queries over a conected socket
3970 mDNSlocal
void conQueryCallback(int sd
, void *context
, mDNSBool ConnectionEstablished
)
3973 char msgbuf
[356]; // 96 (hdr) + 256 (domain) + 4 (class/type)
3976 tcpInfo_t
*info
= (tcpInfo_t
*)context
;
3977 DNSQuestion
*question
= info
->question
;
3983 if (ConnectionEstablished
)
3985 // connection is established - send the message
3986 msg
= (DNSMessage
*)&msgbuf
;
3987 err
= constructQueryMsg(msg
, &end
, question
);
3988 if (err
) { LogMsg("ERROR: conQueryCallback: constructQueryMsg - %ld", err
); goto error
; }
3989 err
= mDNSSendDNSMessage(m
, msg
, end
, mDNSInterface_Any
, &zeroAddr
, zeroIPPort
, sd
, mDNSNULL
);
3990 question
->LastQTime
= mDNSPlatformTimeNow(m
);
3991 if (err
) { debugf("ERROR: conQueryCallback: mDNSSendDNSMessage_tcp - %ld", err
); goto error
; }
3999 n
= mDNSPlatformReadTCP(sd
, lenbuf
, 2);
4002 LogMsg("ERROR:conQueryCallback - attempt to read message length failed (read returned %d)", n
);
4005 info
->replylen
= (mDNSu16
)((mDNSu16
)lenbuf
[0] << 8 | lenbuf
[1]);
4006 if (info
->replylen
< sizeof(DNSMessageHeader
))
4007 { LogMsg("ERROR: conQueryCallback - length too short (%d bytes)", info
->replylen
); goto error
; }
4008 info
->reply
= umalloc(info
->replylen
);
4009 if (!info
->reply
) { LogMsg("ERROR: conQueryCallback - malloc failed"); goto error
; }
4011 n
= mDNSPlatformReadTCP(sd
, ((char *)info
->reply
) + info
->nread
, info
->replylen
- info
->nread
);
4012 if (n
< 0) { LogMsg("ERROR: conQueryCallback - read returned %d", n
); goto error
; }
4014 if (info
->nread
== info
->replylen
)
4016 // Finished reading message; convert the integer parts which are in IETF byte-order (MSB first, LSB second)
4017 DNSMessage
*msg
= info
->reply
;
4018 mDNSu8
*ptr
= (mDNSu8
*)&msg
->h
.numQuestions
;
4019 msg
->h
.numQuestions
= (mDNSu16
)((mDNSu16
)ptr
[0] << 8 | ptr
[1]);
4020 msg
->h
.numAnswers
= (mDNSu16
)((mDNSu16
)ptr
[2] << 8 | ptr
[3]);
4021 msg
->h
.numAuthorities
= (mDNSu16
)((mDNSu16
)ptr
[4] << 8 | ptr
[5]);
4022 msg
->h
.numAdditionals
= (mDNSu16
)((mDNSu16
)ptr
[6] << 8 | ptr
[7]);
4023 uDNS_ReceiveMsg(m
, msg
, (mDNSu8
*)msg
+ info
->replylen
, mDNSNULL
, zeroIPPort
, mDNSNULL
, zeroIPPort
, question
->InterfaceID
);
4024 mDNSPlatformTCPCloseConnection(sd
);
4034 mDNSPlatformTCPCloseConnection(sd
);
4035 if (info
->reply
) ufree(info
->reply
);
4040 mDNSlocal
void hndlTruncatedAnswer(DNSQuestion
*question
, const mDNSAddr
*src
, mDNS
*m
)
4042 mStatus connectionStatus
;
4043 uDNS_QuestionInfo
*info
= &question
->uDNS_info
;
4047 if (!src
) { LogMsg("hndlTruncatedAnswer: TCP DNS response had TC bit set: ignoring"); return; }
4049 context
= (tcpInfo_t
*)umalloc(sizeof(tcpInfo_t
));
4050 if (!context
) { LogMsg("ERROR: hndlTruncatedAnswer - memallocate failed"); return; }
4051 ubzero(context
, sizeof(tcpInfo_t
));
4052 context
->question
= question
;
4054 info
->id
= newMessageID(&m
->uDNS_info
);
4056 connectionStatus
= mDNSPlatformTCPConnect(src
, UnicastDNSPort
, question
->InterfaceID
, conQueryCallback
, context
, &sd
);
4057 if (connectionStatus
== mStatus_ConnEstablished
) // manually invoke callback if connection completes
4059 conQueryCallback(sd
, context
, mDNStrue
);
4062 if (connectionStatus
== mStatus_ConnPending
) return; // callback will be automatically invoked when connection completes
4063 LogMsg("hndlTruncatedAnswer: connection failed");
4064 uDNS_StopQuery(m
, question
); //!!!KRS can we really call this here?
4068 // ***************************************************************************
4069 #if COMPILER_LIKES_PRAGMA_MARK
4070 #pragma mark - Dynamic Updates
4073 mDNSlocal
void sendRecordRegistration(mDNS
*const m
, AuthRecord
*rr
)
4076 mDNSu8
*ptr
= msg
.data
;
4077 mDNSu8
*end
= (mDNSu8
*)&msg
+ sizeof(DNSMessage
);
4078 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
4080 uDNS_RegInfo
*regInfo
= &rr
->uDNS_info
;
4081 mStatus err
= mStatus_UnknownErr
;
4083 id
= newMessageID(u
);
4084 InitializeDNSMessage(&msg
.h
, id
, UpdateReqFlags
);
4085 rr
->uDNS_info
.id
= id
;
4088 ptr
= putZone(&msg
, ptr
, end
, ®Info
->zone
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
4089 if (!ptr
) goto error
;
4091 if (regInfo
->state
== regState_UpdatePending
)
4094 SetNewRData(&rr
->resrec
, regInfo
->OrigRData
, regInfo
->OrigRDLen
);
4095 if (!(ptr
= putDeletionRecord(&msg
, ptr
, &rr
->resrec
))) goto error
; // delete old rdata
4098 SetNewRData(&rr
->resrec
, regInfo
->InFlightRData
, regInfo
->InFlightRDLen
);
4099 if (!(ptr
= PutResourceRecordTTLJumbo(&msg
, ptr
, &msg
.h
.mDNS_numUpdates
, &rr
->resrec
, rr
->resrec
.rroriginalttl
))) goto error
;
4104 if (rr
->resrec
.RecordType
== kDNSRecordTypeKnownUnique
)
4106 // KnownUnique: Delete any previous value
4107 ptr
= putDeleteRRSet(&msg
, ptr
, rr
->resrec
.name
, rr
->resrec
.rrtype
);
4108 if (!ptr
) goto error
;
4111 else if (rr
->resrec
.RecordType
!= kDNSRecordTypeShared
)
4113 ptr
= putPrereqNameNotInUse(rr
->resrec
.name
, &msg
, ptr
, end
);
4114 if (!ptr
) goto error
;
4117 ptr
= PutResourceRecordTTLJumbo(&msg
, ptr
, &msg
.h
.mDNS_numUpdates
, &rr
->resrec
, rr
->resrec
.rroriginalttl
);
4118 if (!ptr
) goto error
;
4121 if (rr
->uDNS_info
.lease
)
4122 { ptr
= putUpdateLease(&msg
, ptr
, DEFAULT_UPDATE_LEASE
); if (!ptr
) goto error
; }
4124 err
= mDNSSendDNSMessage(m
, &msg
, ptr
, mDNSInterface_Any
, ®Info
->ns
, regInfo
->port
, -1, GetAuthInfoForName(u
, rr
->resrec
.name
));
4125 if (err
) debugf("ERROR: sendRecordRegistration - mDNSSendDNSMessage - %ld", err
);
4127 SetRecordRetry(m
, rr
, err
);
4129 if (regInfo
->state
!= regState_Refresh
&& regInfo
->state
!= regState_DeregDeferred
&& regInfo
->state
!= regState_UpdatePending
)
4130 regInfo
->state
= regState_Pending
;
4135 LogMsg("sendRecordRegistration: Error formatting message");
4136 if (rr
->uDNS_info
.state
!= regState_Unregistered
)
4138 unlinkAR(&u
->RecordRegistrations
, rr
);
4139 rr
->uDNS_info
.state
= regState_Unregistered
;
4141 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
4142 if (rr
->RecordCallback
) rr
->RecordCallback(m
, rr
, err
);
4143 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
4144 // NOTE: not safe to touch any client structures here
4147 mDNSlocal
void RecordRegistrationCallback(mStatus err
, mDNS
*const m
, void *authPtr
, const AsyncOpResult
*result
)
4149 AuthRecord
*newRR
= (AuthRecord
*)authPtr
;
4150 const zoneData_t
*zoneData
= mDNSNULL
;
4151 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
4154 // make sure record is still in list
4155 for (ptr
= u
->RecordRegistrations
; ptr
; ptr
= ptr
->next
)
4156 if (ptr
== newRR
) break;
4157 if (!ptr
) { LogMsg("RecordRegistrationCallback - RR no longer in list. Discarding."); return; }
4159 // check error/result
4160 if (err
) { LogMsg("RecordRegistrationCallback: error %ld", err
); goto error
; }
4161 if (!result
) { LogMsg("ERROR: RecordRegistrationCallback invoked with NULL result and no error"); goto error
; }
4162 else zoneData
= &result
->zoneData
;
4164 if (newRR
->uDNS_info
.state
== regState_Cancelled
)
4166 //!!!KRS we should send a memfree callback here!
4167 debugf("Registration of %##s type %d cancelled prior to update",
4168 newRR
->resrec
.name
->c
, newRR
->resrec
.rrtype
);
4169 newRR
->uDNS_info
.state
= regState_Unregistered
;
4170 unlinkAR(&u
->RecordRegistrations
, newRR
);
4174 if (result
->type
!= zoneDataResult
)
4176 LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result
->type
);
4180 if (newRR
->resrec
.rrclass
!= zoneData
->zoneClass
)
4182 LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)",
4183 newRR
->resrec
.rrclass
, zoneData
->zoneClass
);
4187 // Don't try to do updates to the root name server.
4188 // We might be tempted also to block updates to any single-label name server (e.g. com, edu, net, etc.) but some
4189 // organizations use their own private pseudo-TLD, like ".home", etc, and we don't want to block that.
4190 if (zoneData
->zoneName
.c
[0] == 0)
4192 LogMsg("ERROR: Only name server claiming responsibility for \"%##s\" is \"%##s\"!",
4193 newRR
->resrec
.name
->c
, zoneData
->zoneName
.c
);
4194 err
= mStatus_NoSuchNameErr
;
4199 AssignDomainName(&newRR
->uDNS_info
.zone
, &zoneData
->zoneName
);
4200 newRR
->uDNS_info
.ns
= zoneData
->primaryAddr
;
4201 if (zoneData
->updatePort
.NotAnInteger
) newRR
->uDNS_info
.port
= zoneData
->updatePort
;
4204 debugf("Update port not advertised via SRV - guessing port 53, no lease option");
4205 newRR
->uDNS_info
.port
= UnicastDNSPort
;
4206 newRR
->uDNS_info
.lease
= mDNSfalse
;
4209 sendRecordRegistration(m
, newRR
);
4213 if (newRR
->uDNS_info
.state
!= regState_Unregistered
)
4215 unlinkAR(&u
->RecordRegistrations
, newRR
);
4216 newRR
->uDNS_info
.state
= regState_Unregistered
;
4218 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
4219 if (newRR
->RecordCallback
)
4220 newRR
->RecordCallback(m
, newRR
, err
);
4221 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
4222 // NOTE: not safe to touch any client structures here
4225 mDNSlocal
void SendServiceRegistration(mDNS
*m
, ServiceRecordSet
*srs
)
4228 mDNSu8
*ptr
= msg
.data
;
4229 mDNSu8
*end
= (mDNSu8
*)&msg
+ sizeof(DNSMessage
);
4230 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
4232 uDNS_RegInfo
*rInfo
= &srs
->uDNS_info
;
4233 mStatus err
= mStatus_UnknownErr
;
4234 mDNSIPPort privport
;
4235 NATTraversalInfo
*nat
= srs
->uDNS_info
.NATinfo
;
4236 mDNSBool mapped
= mDNSfalse
;
4238 AuthRecord
*srv
= &srs
->RR_SRV
;
4241 privport
= zeroIPPort
;
4243 if (!rInfo
->ns
.ip
.v4
.NotAnInteger
) { LogMsg("SendServiceRegistration - NS not set!"); return; }
4245 id
= newMessageID(u
);
4246 InitializeDNSMessage(&msg
.h
, id
, UpdateReqFlags
);
4248 // setup resource records
4249 SetNewRData(&srs
->RR_PTR
.resrec
, mDNSNULL
, 0);
4250 SetNewRData(&srs
->RR_TXT
.resrec
, mDNSNULL
, 0);
4252 // replace port w/ NAT mapping if necessary
4253 if (nat
&& nat
->PublicPort
.NotAnInteger
&&
4254 (nat
->state
== NATState_Established
|| nat
->state
== NATState_Refresh
|| nat
->state
== NATState_Legacy
))
4256 privport
= srv
->resrec
.rdata
->u
.srv
.port
;
4257 srv
->resrec
.rdata
->u
.srv
.port
= nat
->PublicPort
;
4261 // construct update packet
4263 ptr
= putZone(&msg
, ptr
, end
, &rInfo
->zone
, mDNSOpaque16fromIntVal(srv
->resrec
.rrclass
));
4264 if (!ptr
) goto error
;
4266 if (srs
->uDNS_info
.TestForSelfConflict
)
4268 // update w/ prereq that SRV already exist to make sure previous registration was ours, and delete any stale TXT records
4269 if (!(ptr
= PutResourceRecordTTLJumbo(&msg
, ptr
, &msg
.h
.mDNS_numPrereqs
, &srs
->RR_SRV
.resrec
, 0))) goto error
;
4270 if (!(ptr
= putDeleteRRSet(&msg
, ptr
, srs
->RR_TXT
.resrec
.name
, srs
->RR_TXT
.resrec
.rrtype
))) goto error
;
4273 else if (srs
->uDNS_info
.state
!= regState_Refresh
&& srs
->uDNS_info
.state
!= regState_UpdatePending
)
4275 // use SRV name for prereq
4276 ptr
= putPrereqNameNotInUse(srv
->resrec
.name
, &msg
, ptr
, end
);
4277 if (!ptr
) goto error
;
4280 //!!!KRS Need to do bounds checking and use TCP if it won't fit!!!
4281 if (!(ptr
= PutResourceRecordTTLJumbo(&msg
, ptr
, &msg
.h
.mDNS_numUpdates
, &srs
->RR_PTR
.resrec
, srs
->RR_PTR
.resrec
.rroriginalttl
))) goto error
;
4283 for (i
= 0; i
< srs
->NumSubTypes
; i
++)
4284 if (!(ptr
= PutResourceRecordTTLJumbo(&msg
, ptr
, &msg
.h
.mDNS_numUpdates
, &srs
->SubTypes
[i
].resrec
, srs
->SubTypes
[i
].resrec
.rroriginalttl
))) goto error
;
4286 if (rInfo
->state
== regState_UpdatePending
) // we're updating the txt record
4288 AuthRecord
*txt
= &srs
->RR_TXT
;
4289 uDNS_RegInfo
*txtInfo
= &txt
->uDNS_info
;
4291 SetNewRData(&txt
->resrec
, txtInfo
->OrigRData
, txtInfo
->OrigRDLen
);
4292 if (!(ptr
= putDeletionRecord(&msg
, ptr
, &srs
->RR_TXT
.resrec
))) goto error
; // delete old rdata
4295 SetNewRData(&txt
->resrec
, txtInfo
->InFlightRData
, txtInfo
->InFlightRDLen
);
4296 if (!(ptr
= PutResourceRecordTTLJumbo(&msg
, ptr
, &msg
.h
.mDNS_numUpdates
, &srs
->RR_TXT
.resrec
, srs
->RR_TXT
.resrec
.rroriginalttl
))) goto error
;
4299 if (!(ptr
= PutResourceRecordTTLJumbo(&msg
, ptr
, &msg
.h
.mDNS_numUpdates
, &srs
->RR_TXT
.resrec
, srs
->RR_TXT
.resrec
.rroriginalttl
))) goto error
;
4301 if (!GetServiceTarget(u
, srv
, &target
))
4303 debugf("Couldn't get target for service %##s", srv
->resrec
.name
->c
);
4304 rInfo
->state
= regState_NoTarget
;
4308 if (!SameDomainName(&target
, &srv
->resrec
.rdata
->u
.srv
.target
))
4310 AssignDomainName(&srv
->resrec
.rdata
->u
.srv
.target
, &target
);
4311 SetNewRData(&srv
->resrec
, mDNSNULL
, 0);
4314 ptr
= PutResourceRecordTTLJumbo(&msg
, ptr
, &msg
.h
.mDNS_numUpdates
, &srv
->resrec
, srv
->resrec
.rroriginalttl
);
4315 if (!ptr
) goto error
;
4317 if (srs
->uDNS_info
.lease
)
4318 { ptr
= putUpdateLease(&msg
, ptr
, DEFAULT_UPDATE_LEASE
); if (!ptr
) goto error
; }
4320 err
= mDNSSendDNSMessage(m
, &msg
, ptr
, mDNSInterface_Any
, &rInfo
->ns
, rInfo
->port
, -1, GetAuthInfoForName(u
, srs
->RR_SRV
.resrec
.name
));
4321 if (err
) debugf("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %ld", err
);
4323 if (rInfo
->state
!= regState_Refresh
&& rInfo
->state
!= regState_DeregDeferred
&& srs
->uDNS_info
.state
!= regState_UpdatePending
)
4324 rInfo
->state
= regState_Pending
;
4326 SetRecordRetry(m
, &srs
->RR_SRV
, err
);
4328 if (mapped
) srv
->resrec
.rdata
->u
.srv
.port
= privport
;
4332 LogMsg("SendServiceRegistration - Error formatting message");
4333 if (mapped
) srv
->resrec
.rdata
->u
.srv
.port
= privport
;
4335 rInfo
->state
= regState_Unregistered
;
4336 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
4337 srs
->ServiceCallback(m
, srs
, err
);
4338 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
4339 //!!!KRS will mem still be free'd on error?
4340 // NOTE: not safe to touch any client structures here
4343 mDNSlocal
void serviceRegistrationCallback(mStatus err
, mDNS
*const m
, void *srsPtr
, const AsyncOpResult
*result
)
4345 ServiceRecordSet
*srs
= (ServiceRecordSet
*)srsPtr
;
4346 const zoneData_t
*zoneData
= mDNSNULL
;
4348 if (err
) goto error
;
4349 if (!result
) { LogMsg("ERROR: serviceRegistrationCallback invoked with NULL result and no error"); goto error
; }
4350 else zoneData
= &result
->zoneData
;
4352 if (result
->type
!= zoneDataResult
)
4354 LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result
->type
);
4358 if (srs
->uDNS_info
.state
== regState_Cancelled
)
4360 // client cancelled registration while fetching zone data
4361 srs
->uDNS_info
.state
= regState_Unregistered
;
4363 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
4364 srs
->ServiceCallback(m
, srs
, mStatus_MemFree
);
4365 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
4369 if (srs
->RR_SRV
.resrec
.rrclass
!= zoneData
->zoneClass
)
4371 LogMsg("Service %##s - class does not match zone", srs
->RR_SRV
.resrec
.name
->c
);
4376 AssignDomainName(&srs
->uDNS_info
.zone
, &zoneData
->zoneName
);
4377 srs
->uDNS_info
.ns
.type
= mDNSAddrType_IPv4
;
4378 srs
->uDNS_info
.ns
= zoneData
->primaryAddr
;
4379 if (zoneData
->updatePort
.NotAnInteger
) srs
->uDNS_info
.port
= zoneData
->updatePort
;
4382 debugf("Update port not advertised via SRV - guessing port 53, no lease option");
4383 srs
->uDNS_info
.port
= UnicastDNSPort
;
4384 srs
->uDNS_info
.lease
= mDNSfalse
;
4387 if (srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
.NotAnInteger
&& IsPrivateV4Addr(&m
->uDNS_info
.AdvertisedV4
))
4388 { srs
->uDNS_info
.state
= regState_NATMap
; StartNATPortMap(m
, srs
); }
4389 else SendServiceRegistration(m
, srs
);
4394 srs
->uDNS_info
.state
= regState_Unregistered
;
4395 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
4396 srs
->ServiceCallback(m
, srs
, err
);
4397 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
4398 // NOTE: not safe to touch any client structures here
4401 mDNSlocal mStatus
SetupRecordRegistration(mDNS
*m
, AuthRecord
*rr
)
4403 domainname
*target
= GetRRDomainNameTarget(&rr
->resrec
);
4404 AuthRecord
*ptr
= m
->uDNS_info
.RecordRegistrations
;
4406 while (ptr
&& ptr
!= rr
) ptr
= ptr
->next
;
4407 if (ptr
) { LogMsg("Error: SetupRecordRegistration - record %##s already in list!", rr
->resrec
.name
->c
); return mStatus_AlreadyRegistered
; }
4409 if (rr
->uDNS_info
.state
== regState_FetchingZoneData
||
4410 rr
->uDNS_info
.state
== regState_Pending
||
4411 rr
->uDNS_info
.state
== regState_Registered
)
4413 LogMsg("Requested double-registration of physical record %##s type %d",
4414 rr
->resrec
.name
->c
, rr
->resrec
.rrtype
);
4415 return mStatus_AlreadyRegistered
;
4418 rr
->resrec
.rdlength
= GetRDLength(&rr
->resrec
, mDNSfalse
);
4419 rr
->resrec
.rdestimate
= GetRDLength(&rr
->resrec
, mDNStrue
);
4421 if (!ValidateDomainName(rr
->resrec
.name
))
4423 LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m
, rr
));
4424 return mStatus_Invalid
;
4427 // Don't do this until *after* we've set rr->resrec.rdlength
4428 if (!ValidateRData(rr
->resrec
.rrtype
, rr
->resrec
.rdlength
, rr
->resrec
.rdata
))
4430 LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m
, rr
));
4431 return mStatus_Invalid
;
4434 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
4435 rr
->resrec
.rdatahash
= target
? DomainNameHashValue(target
) : RDataHashValue(rr
->resrec
.rdlength
, &rr
->resrec
.rdata
->u
);
4437 rr
->uDNS_info
.state
= regState_FetchingZoneData
;
4438 rr
->next
= m
->uDNS_info
.RecordRegistrations
;
4439 m
->uDNS_info
.RecordRegistrations
= rr
;
4440 rr
->uDNS_info
.lease
= mDNStrue
;
4442 return mStatus_NoError
;
4445 mDNSexport mStatus
uDNS_RegisterRecord(mDNS
*const m
, AuthRecord
*const rr
)
4447 mStatus err
= SetupRecordRegistration(m
, rr
);
4448 if (err
) return err
;
4449 else return startGetZoneData(rr
->resrec
.name
, m
, mDNStrue
, mDNSfalse
, RecordRegistrationCallback
, rr
);
4452 mDNSlocal
void SendRecordDeregistration(mDNS
*m
, AuthRecord
*rr
)
4454 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
4456 mDNSu8
*ptr
= msg
.data
;
4457 mDNSu8
*end
= (mDNSu8
*)&msg
+ sizeof(DNSMessage
);
4460 InitializeDNSMessage(&msg
.h
, rr
->uDNS_info
.id
, UpdateReqFlags
);
4462 ptr
= putZone(&msg
, ptr
, end
, &rr
->uDNS_info
.zone
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
4463 if (!ptr
) goto error
;
4464 if (!(ptr
= putDeletionRecord(&msg
, ptr
, &rr
->resrec
))) goto error
;
4466 err
= mDNSSendDNSMessage(m
, &msg
, ptr
, mDNSInterface_Any
, &rr
->uDNS_info
.ns
, rr
->uDNS_info
.port
, -1, GetAuthInfoForName(u
, rr
->resrec
.name
));
4467 if (err
) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %ld", err
);
4469 SetRecordRetry(m
, rr
, err
);
4470 rr
->uDNS_info
.state
= regState_DeregPending
;
4474 LogMsg("Error: SendRecordDeregistration - could not contruct deregistration packet");
4475 unlinkAR(&u
->RecordRegistrations
, rr
);
4476 rr
->uDNS_info
.state
= regState_Unregistered
;
4481 mDNSexport mStatus
uDNS_DeregisterRecord(mDNS
*const m
, AuthRecord
*const rr
)
4483 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
4484 NATTraversalInfo
*n
= rr
->uDNS_info
.NATinfo
;
4486 switch (rr
->uDNS_info
.state
)
4488 case regState_NATMap
:
4489 // we're in the middle of a NAT traversal operation
4490 rr
->uDNS_info
.NATinfo
= mDNSNULL
;
4491 if (!n
) LogMsg("uDNS_DeregisterRecord: no NAT info context");
4492 else FreeNATInfo(m
, n
); // cause response to outstanding request to be ignored.
4493 // Note: normally here we're trying to determine our public address,
4494 //in which case there is not state to be torn down. For simplicity,
4495 //we allow other operations to expire.
4496 rr
->uDNS_info
.state
= regState_Unregistered
;
4498 case regState_ExtraQueued
:
4499 rr
->uDNS_info
.state
= regState_Unregistered
;
4501 case regState_FetchingZoneData
:
4502 rr
->uDNS_info
.state
= regState_Cancelled
;
4503 return mStatus_NoError
;
4504 case regState_Refresh
:
4505 case regState_Pending
:
4506 case regState_UpdatePending
:
4507 rr
->uDNS_info
.state
= regState_DeregDeferred
;
4508 LogMsg("Deferring deregistration of record %##s until registration completes", rr
->resrec
.name
->c
);
4509 return mStatus_NoError
;
4510 case regState_Registered
:
4511 case regState_DeregPending
:
4513 case regState_DeregDeferred
:
4514 case regState_Cancelled
:
4515 LogMsg("Double deregistration of record %##s type %d",
4516 rr
->resrec
.name
->c
, rr
->resrec
.rrtype
);
4517 return mStatus_UnknownErr
;
4518 case regState_Unregistered
:
4519 LogMsg("Requested deregistration of unregistered record %##s type %d",
4520 rr
->resrec
.name
->c
, rr
->resrec
.rrtype
);
4521 return mStatus_UnknownErr
;
4522 case regState_NATError
:
4523 case regState_NoTarget
:
4524 LogMsg("ERROR: uDNS_DeregisterRecord called for record %##s with bad state %s", rr
->resrec
.name
->c
, rr
->uDNS_info
.state
== regState_NoTarget
? "regState_NoTarget" : "regState_NATError");
4525 return mStatus_UnknownErr
;
4528 if (rr
->uDNS_info
.state
== regState_Unregistered
)
4530 // unlink and deliver memfree
4532 unlinkAR(&u
->RecordRegistrations
, rr
);
4533 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
4534 if (rr
->RecordCallback
) rr
->RecordCallback(m
, rr
, mStatus_MemFree
);
4535 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
4536 return mStatus_NoError
;
4539 rr
->uDNS_info
.NATinfo
= mDNSNULL
;
4540 if (n
) FreeNATInfo(m
, n
);
4542 SendRecordDeregistration(m
, rr
);
4543 return mStatus_NoError
;
4546 mDNSexport mStatus
uDNS_RegisterService(mDNS
*const m
, ServiceRecordSet
*srs
)
4550 uDNS_RegInfo
*info
= &srs
->uDNS_info
;
4551 ServiceRecordSet
**p
= &m
->uDNS_info
.ServiceRegistrations
;
4552 while (*p
&& *p
!= srs
) p
=&(*p
)->next
;
4553 if (*p
) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs
, srs
->RR_SRV
.resrec
.name
->c
); return(mStatus_AlreadyRegistered
); }
4554 ubzero(info
, sizeof(*info
));
4556 srs
->next
= mDNSNULL
;
4558 srs
->RR_SRV
.resrec
.rroriginalttl
= kWideAreaTTL
;
4559 srs
->RR_TXT
.resrec
.rroriginalttl
= kWideAreaTTL
;
4560 srs
->RR_PTR
.resrec
.rroriginalttl
= kWideAreaTTL
;
4561 for (i
= 0; i
< srs
->NumSubTypes
;i
++) srs
->SubTypes
[i
].resrec
.rroriginalttl
= kWideAreaTTL
;
4563 info
->lease
= mDNStrue
;
4565 srs
->RR_SRV
.resrec
.rdata
->u
.srv
.target
.c
[0] = 0;
4566 if (!GetServiceTarget(&m
->uDNS_info
, &srs
->RR_SRV
, &target
))
4568 // defer registration until we've got a target
4569 debugf("uDNS_RegisterService - no target for %##s", srs
->RR_SRV
.resrec
.name
->c
);
4570 info
->state
= regState_NoTarget
;
4571 return mStatus_NoError
;
4574 info
->state
= regState_FetchingZoneData
;
4575 return startGetZoneData(srs
->RR_SRV
.resrec
.name
, m
, mDNStrue
, mDNSfalse
, serviceRegistrationCallback
, srs
);
4578 mDNSlocal
void SendServiceDeregistration(mDNS
*m
, ServiceRecordSet
*srs
)
4580 uDNS_RegInfo
*info
= &srs
->uDNS_info
;
4581 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
4584 mDNSu8
*ptr
= msg
.data
;
4585 mDNSu8
*end
= (mDNSu8
*)&msg
+ sizeof(DNSMessage
);
4586 mStatus err
= mStatus_UnknownErr
;
4589 id
= newMessageID(u
);
4590 InitializeDNSMessage(&msg
.h
, id
, UpdateReqFlags
);
4593 ptr
= putZone(&msg
, ptr
, end
, &info
->zone
, mDNSOpaque16fromIntVal(srs
->RR_SRV
.resrec
.rrclass
));
4594 if (!ptr
) { LogMsg("ERROR: SendServiceDeregistration - putZone"); goto error
; }
4596 if (!(ptr
= putDeleteAllRRSets(&msg
, ptr
, srs
->RR_SRV
.resrec
.name
))) goto error
; // this deletes SRV, TXT, and Extras
4597 if (!(ptr
= putDeletionRecord(&msg
, ptr
, &srs
->RR_PTR
.resrec
))) goto error
;
4598 for (i
= 0; i
< srs
->NumSubTypes
; i
++)
4599 if (!(ptr
= putDeletionRecord(&msg
, ptr
, &srs
->SubTypes
[i
].resrec
))) goto error
;
4602 err
= mDNSSendDNSMessage(m
, &msg
, ptr
, mDNSInterface_Any
, &info
->ns
, info
->port
, -1, GetAuthInfoForName(u
, srs
->RR_SRV
.resrec
.name
));
4603 if (err
&& err
!= mStatus_TransientErr
) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %ld", err
); goto error
; }
4605 SetRecordRetry(m
, &srs
->RR_SRV
, err
);
4607 info
->state
= regState_DeregPending
;
4613 info
->state
= regState_Unregistered
;
4616 mDNSexport mStatus
uDNS_DeregisterService(mDNS
*const m
, ServiceRecordSet
*srs
)
4618 NATTraversalInfo
*nat
= srs
->uDNS_info
.NATinfo
;
4619 char *errmsg
= "Unknown State";
4621 // don't re-register with a new target following deregistration
4622 srs
->uDNS_info
.SRVChanged
= srs
->uDNS_info
.SRVUpdateDeferred
= mDNSfalse
;
4626 if (nat
->state
== NATState_Established
|| nat
->state
== NATState_Refresh
|| nat
->state
== NATState_Legacy
)
4627 DeleteNATPortMapping(m
, nat
, srs
);
4628 nat
->reg
.ServiceRegistration
= mDNSNULL
;
4629 srs
->uDNS_info
.NATinfo
= mDNSNULL
;
4630 FreeNATInfo(m
, nat
);
4633 switch (srs
->uDNS_info
.state
)
4635 case regState_Unregistered
:
4636 debugf("uDNS_DeregisterService - service %##s not registered", srs
->RR_SRV
.resrec
.name
->c
);
4637 return mStatus_BadReferenceErr
;
4638 case regState_FetchingZoneData
:
4639 // let the async op complete, then terminate
4640 srs
->uDNS_info
.state
= regState_Cancelled
;
4641 return mStatus_NoError
; // deliver memfree upon completion of async op
4642 case regState_Pending
:
4643 case regState_Refresh
:
4644 case regState_UpdatePending
:
4645 // deregister following completion of in-flight operation
4646 srs
->uDNS_info
.state
= regState_DeregDeferred
;
4647 return mStatus_NoError
;
4648 case regState_DeregPending
:
4649 case regState_DeregDeferred
:
4650 case regState_Cancelled
:
4651 debugf("Double deregistration of service %##s", srs
->RR_SRV
.resrec
.name
->c
);
4652 return mStatus_NoError
;
4653 case regState_NATError
: // not registered
4654 case regState_NATMap
: // not registered
4655 case regState_NoTarget
: // not registered
4657 srs
->uDNS_info
.state
= regState_Unregistered
;
4658 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
4659 srs
->ServiceCallback(m
, srs
, mStatus_MemFree
);
4660 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
4661 return mStatus_NoError
;
4662 case regState_Registered
:
4663 srs
->uDNS_info
.state
= regState_DeregPending
;
4664 SendServiceDeregistration(m
, srs
);
4665 return mStatus_NoError
;
4666 case regState_ExtraQueued
: // only for record registrations
4667 errmsg
= "bad state (regState_ExtraQueued)";
4672 LogMsg("Error, uDNS_DeregisterService: %s", errmsg
);
4673 return mStatus_BadReferenceErr
;
4676 mDNSexport mStatus
uDNS_AddRecordToService(mDNS
*const m
, ServiceRecordSet
*sr
, ExtraResourceRecord
*extra
)
4678 mStatus err
= mStatus_UnknownErr
;
4680 extra
->r
.resrec
.RecordType
= kDNSRecordTypeShared
; // don't want it to conflict with the service name
4681 extra
->r
.RecordCallback
= mDNSNULL
; // don't generate callbacks for extra RRs
4683 if (sr
->uDNS_info
.state
== regState_Registered
|| sr
->uDNS_info
.state
== regState_Refresh
)
4684 err
= uDNS_RegisterRecord(m
, &extra
->r
);
4687 err
= SetupRecordRegistration(m
, &extra
->r
);
4688 extra
->r
.uDNS_info
.state
= regState_ExtraQueued
; // %%% Is it okay to overwrite the previous uDNS_info.state?
4693 extra
->next
= sr
->Extras
;
4699 mDNSexport mStatus
uDNS_UpdateRecord(mDNS
*m
, AuthRecord
*rr
)
4701 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
4702 ServiceRecordSet
*parent
= mDNSNULL
;
4704 uDNS_RegInfo
*info
= &rr
->uDNS_info
;
4705 regState_t
*stateptr
= mDNSNULL
;
4707 // find the record in registered service list
4708 for (parent
= u
->ServiceRegistrations
; parent
; parent
= parent
->next
)
4709 if (&parent
->RR_TXT
== rr
) { stateptr
= &parent
->uDNS_info
.state
; break; }
4713 // record not part of a service - check individual record registrations
4714 for (rptr
= u
->RecordRegistrations
; rptr
; rptr
= rptr
->next
)
4715 if (rptr
== rr
) { stateptr
= &rr
->uDNS_info
.state
; break; }
4716 if (!rptr
) goto unreg_error
;
4721 case regState_DeregPending
:
4722 case regState_DeregDeferred
:
4723 case regState_Cancelled
:
4724 case regState_Unregistered
:
4725 // not actively registered
4728 case regState_FetchingZoneData
:
4729 case regState_NATMap
:
4730 case regState_ExtraQueued
:
4731 case regState_NoTarget
:
4732 // change rdata directly since it hasn't been sent yet
4733 if (info
->UpdateRDCallback
) info
->UpdateRDCallback(m
, rr
, rr
->resrec
.rdata
);
4734 SetNewRData(&rr
->resrec
, rr
->NewRData
, rr
->newrdlength
);
4735 rr
->NewRData
= mDNSNULL
;
4736 return mStatus_NoError
;
4738 case regState_Pending
:
4739 case regState_Refresh
:
4740 case regState_UpdatePending
:
4741 // registration in-flight. queue rdata and return
4742 if (info
->QueuedRData
&& info
->UpdateRDCallback
)
4743 // if unsent rdata is already queued, free it before we replace it
4744 info
->UpdateRDCallback(m
, rr
, info
->QueuedRData
);
4745 info
->QueuedRData
= rr
->NewRData
;
4746 info
->QueuedRDLen
= rr
->newrdlength
;
4747 rr
->NewRData
= mDNSNULL
;
4748 return mStatus_NoError
;
4750 case regState_Registered
:
4751 info
->OrigRData
= rr
->resrec
.rdata
;
4752 info
->OrigRDLen
= rr
->resrec
.rdlength
;
4753 info
->InFlightRData
= rr
->NewRData
;
4754 info
->InFlightRDLen
= rr
->newrdlength
;
4755 rr
->NewRData
= mDNSNULL
;
4756 *stateptr
= regState_UpdatePending
;
4757 if (parent
) SendServiceRegistration(m
, parent
);
4758 else sendRecordRegistration(m
, rr
);
4759 return mStatus_NoError
;
4761 case regState_NATError
:
4762 LogMsg("ERROR: uDNS_UpdateRecord called for record %##s with bad state regState_NATError", rr
->resrec
.name
->c
);
4763 return mStatus_UnknownErr
; // states for service records only
4767 LogMsg("Requested update of record %##s type %d, part of service not currently registered",
4768 rr
->resrec
.name
->c
, rr
->resrec
.rrtype
);
4769 return mStatus_Invalid
;
4773 // ***************************************************************************
4774 #if COMPILER_LIKES_PRAGMA_MARK
4775 #pragma mark - Periodic Execution Routines
4779 mDNSlocal mDNSs32
CheckNATMappings(mDNS
*m
, mDNSs32 timenow
)
4781 NATTraversalInfo
*ptr
= m
->uDNS_info
.NATTraversals
;
4782 mDNSs32 nextevent
= timenow
+ MIN_UCAST_PERIODIC_EXEC
;
4786 NATTraversalInfo
*cur
= ptr
;
4788 if (cur
->op
!= NATOp_AddrRequest
|| cur
->state
!= NATState_Established
) // no refresh necessary for established Add requests
4790 if (cur
->retry
- timenow
< 0)
4792 if (cur
->state
== NATState_Established
) RefreshNATMapping(cur
, m
);
4793 else if (cur
->state
== NATState_Request
|| cur
->state
== NATState_Refresh
)
4795 if (cur
->ntries
>= NATMAP_MAX_TRIES
) cur
->ReceiveResponse(cur
, m
, mDNSNULL
, 0); // may invalidate "cur"
4796 else SendNATMsg(cur
, m
);
4799 else if (cur
->retry
- nextevent
< 0) nextevent
= cur
->retry
;
4805 mDNSlocal mDNSs32
CheckQueries(mDNS
*m
, mDNSs32 timenow
)
4808 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
4811 mDNSs32 nextevent
= timenow
+ MIN_UCAST_PERIODIC_EXEC
;
4813 mStatus err
= mStatus_NoError
;
4815 uDNS_QuestionInfo
*info
;
4817 u
->CurrentQuery
= u
->ActiveQueries
;
4818 while (u
->CurrentQuery
)
4820 q
= u
->CurrentQuery
;
4821 info
= &q
->uDNS_info
;
4824 if (!info
->internal
&& ((!q
->LongLived
&& !info
->Answered
) || (llq
&& llq
->state
< LLQ_Established
)) &&
4825 info
->RestartTime
+ RESTART_GOODBYE_DELAY
- timenow
< 0)
4827 // if we've been spinning on restart setup, and we have known answers, give goodbyes (they may be re-added later)
4828 while (info
->knownAnswers
)
4830 CacheRecord
*cr
= info
->knownAnswers
;
4831 info
->knownAnswers
= info
->knownAnswers
->next
;
4833 m
->mDNS_reentrancy
++; // Increment to allow client to legally make mDNS API calls from the callback
4834 q
->QuestionCallback(m
, q
, &cr
->resrec
, mDNSfalse
);
4835 m
->mDNS_reentrancy
--; // Decrement to block mDNS API calls again
4837 if (q
!= u
->CurrentQuery
) { debugf("CheckQueries - question removed via callback."); break; }
4840 if (q
!= u
->CurrentQuery
) continue;
4842 if (q
->LongLived
&& llq
->state
!= LLQ_Poll
)
4844 if (llq
->state
>= LLQ_InitialRequest
&& llq
->state
<= LLQ_Established
)
4846 if (llq
->retry
- timenow
< 0)
4848 // sanity check to avoid packet flood bugs
4850 LogMsg("ERROR: retry timer not set for LLQ %##s in state %d", q
->qname
.c
, llq
->state
);
4851 else if (llq
->state
== LLQ_Established
|| llq
->state
== LLQ_Refresh
)
4852 sendLLQRefresh(m
, q
, llq
->origLease
);
4853 else if (llq
->state
== LLQ_InitialRequest
)
4854 startLLQHandshake(m
, llq
, mDNSfalse
);
4855 else if (llq
->state
== LLQ_SecondaryRequest
)
4856 sendChallengeResponse(m
, q
, mDNSNULL
);
4857 else if (llq
->state
== LLQ_Retry
)
4858 { llq
->ntries
= 0; startLLQHandshake(m
, llq
, mDNSfalse
); }
4860 else if (llq
->retry
- nextevent
< 0) nextevent
= llq
->retry
;
4865 sendtime
= q
->LastQTime
+ q
->ThisQInterval
;
4866 if (m
->SuppressStdPort53Queries
&&
4867 sendtime
- m
->SuppressStdPort53Queries
< 0) // Don't allow sendtime to be earlier than SuppressStdPort53Queries
4868 sendtime
= m
->SuppressStdPort53Queries
;
4869 if (sendtime
- timenow
< 0)
4871 DNSServer
*server
= GetServerForName(&m
->uDNS_info
, &q
->qname
);
4874 if (server
->teststate
== DNSServer_Untested
)
4876 InitializeDNSMessage(&msg
.h
, newMessageID(&m
->uDNS_info
), uQueryFlags
);
4877 end
= putQuestion(&msg
, msg
.data
, msg
.data
+ AbsoluteMaxDNSMessageData
, DNSRelayTestQuestion
, kDNSType_PTR
, kDNSClass_IN
);
4880 err
= constructQueryMsg(&msg
, &end
, q
);
4881 if (err
) LogMsg("Error: uDNS_Idle - constructQueryMsg. Skipping question %##s", q
->qname
.c
);
4884 if (server
->teststate
!= DNSServer_Failed
)
4885 err
= mDNSSendDNSMessage(m
, &msg
, end
, mDNSInterface_Any
, &server
->addr
, UnicastDNSPort
, -1, mDNSNULL
);
4886 m
->SuppressStdPort53Queries
= NonZeroTime(m
->timenow
+ (mDNSPlatformOneSecond
+99)/100);
4887 q
->LastQTime
= timenow
;
4888 if (err
) debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %ld", err
); // surpress syslog messages if we have no network
4889 else if (q
->ThisQInterval
< MAX_UCAST_POLL_INTERVAL
) q
->ThisQInterval
= q
->ThisQInterval
* 2; // don't increase interval if send failed
4893 else if (sendtime
- nextevent
< 0) nextevent
= sendtime
;
4895 u
->CurrentQuery
= u
->CurrentQuery
->next
;
4900 mDNSlocal mDNSs32
CheckRecordRegistrations(mDNS
*m
, mDNSs32 timenow
)
4903 uDNS_RegInfo
*rInfo
;
4904 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
4905 mDNSs32 nextevent
= timenow
+ MIN_UCAST_PERIODIC_EXEC
;
4907 //!!!KRS list should be pre-sorted by expiration
4908 for (rr
= u
->RecordRegistrations
; rr
; rr
= rr
->next
)
4910 rInfo
= &rr
->uDNS_info
;
4911 if (rInfo
->state
== regState_Pending
|| rInfo
->state
== regState_DeregPending
|| rInfo
->state
== regState_UpdatePending
|| rInfo
->state
== regState_DeregDeferred
|| rInfo
->state
== regState_Refresh
)
4913 if (rr
->LastAPTime
+ rr
->ThisAPInterval
- timenow
< 0)
4916 char *op
= "(unknown operation)";
4917 if (rInfo
->state
== regState_Pending
) op
= "registration";
4918 else if (rInfo
->state
== regState_DeregPending
) op
= "deregistration";
4919 else if (rInfo
->state
== regState_Refresh
) op
= "refresh";
4920 debugf("Retransmit record %s %##s", op
, rr
->resrec
.name
->c
);
4922 //LogMsg("Retransmit record %##s", rr->resrec.name->c);
4923 if (rInfo
->state
== regState_DeregPending
) SendRecordDeregistration(m
, rr
);
4924 else sendRecordRegistration(m
, rr
);
4926 if (rr
->LastAPTime
+ rr
->ThisAPInterval
- nextevent
< 0) nextevent
= rr
->LastAPTime
+ rr
->ThisAPInterval
;
4928 if (rInfo
->lease
&& rInfo
->state
== regState_Registered
)
4930 if (rInfo
->expire
- timenow
< 0)
4932 debugf("refreshing record %##s", rr
->resrec
.name
->c
);
4933 rInfo
->state
= regState_Refresh
;
4934 sendRecordRegistration(m
, rr
);
4936 if (rInfo
->expire
- nextevent
< 0) nextevent
= rInfo
->expire
;
4942 mDNSlocal mDNSs32
CheckServiceRegistrations(mDNS
*m
, mDNSs32 timenow
)
4944 ServiceRecordSet
*s
= m
->uDNS_info
.ServiceRegistrations
;
4945 uDNS_RegInfo
*rInfo
;
4946 mDNSs32 nextevent
= timenow
+ MIN_UCAST_PERIODIC_EXEC
;
4948 // Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery
4951 ServiceRecordSet
*srs
= s
;
4952 // NOTE: Must advance s here -- SendServiceDeregistration may delete the object we're looking at,
4953 // and then if we tried to do srs = srs->next at the end we'd be referencing a dead object
4956 rInfo
= &srs
->uDNS_info
;
4957 if (rInfo
->state
== regState_Pending
|| rInfo
->state
== regState_DeregPending
|| rInfo
->state
== regState_DeregDeferred
|| rInfo
->state
== regState_Refresh
|| rInfo
->state
== regState_UpdatePending
)
4959 if (srs
->RR_SRV
.LastAPTime
+ srs
->RR_SRV
.ThisAPInterval
- timenow
< 0)
4962 char *op
= "unknown";
4963 if (rInfo
->state
== regState_Pending
) op
= "registration";
4964 else if (rInfo
->state
== regState_DeregPending
) op
= "deregistration";
4965 else if (rInfo
->state
== regState_Refresh
) op
= "refresh";
4966 else if (rInfo
->state
== regState_UpdatePending
) op
= "txt record update";
4967 debugf("Retransmit service %s %##s", op
, srs
->RR_SRV
.resrec
.name
->c
);
4969 if (rInfo
->state
== regState_DeregPending
) { SendServiceDeregistration(m
, srs
); continue; }
4970 else SendServiceRegistration (m
, srs
);
4972 if (nextevent
- srs
->RR_SRV
.LastAPTime
+ srs
->RR_SRV
.ThisAPInterval
> 0)
4973 nextevent
= srs
->RR_SRV
.LastAPTime
+ srs
->RR_SRV
.ThisAPInterval
;
4976 if (rInfo
->lease
&& rInfo
->state
== regState_Registered
)
4978 if (rInfo
->expire
- timenow
< 0)
4980 debugf("refreshing service %##s", srs
->RR_SRV
.resrec
.name
->c
);
4981 rInfo
->state
= regState_Refresh
;
4982 SendServiceRegistration(m
, srs
);
4984 if (rInfo
->expire
- nextevent
< 0) nextevent
= rInfo
->expire
;
4990 mDNSexport
void uDNS_Execute(mDNS
*const m
)
4992 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
4993 mDNSs32 nexte
, timenow
= mDNSPlatformTimeNow(m
);
4995 u
->nextevent
= timenow
+ MIN_UCAST_PERIODIC_EXEC
;
4997 if (u
->DelaySRVUpdate
&& u
->NextSRVUpdate
- timenow
< 0)
4999 u
->DelaySRVUpdate
= mDNSfalse
;
5000 UpdateSRVRecords(m
);
5003 nexte
= CheckNATMappings(m
, timenow
);
5004 if (nexte
- u
->nextevent
< 0) u
->nextevent
= nexte
;
5006 if (m
->SuppressStdPort53Queries
&& m
->timenow
- m
->SuppressStdPort53Queries
>= 0)
5007 m
->SuppressStdPort53Queries
= 0; // If suppression time has passed, clear it
5009 nexte
= CheckQueries(m
, timenow
);
5010 if (nexte
- u
->nextevent
< 0) u
->nextevent
= nexte
;
5012 nexte
= CheckRecordRegistrations(m
, timenow
);
5013 if (nexte
- u
->nextevent
< 0) u
->nextevent
= nexte
;
5015 nexte
= CheckServiceRegistrations(m
, timenow
);
5016 if (nexte
- u
->nextevent
< 0) u
->nextevent
= nexte
;
5020 // ***************************************************************************
5021 #if COMPILER_LIKES_PRAGMA_MARK
5022 #pragma mark - Startup, Shutdown, and Sleep
5025 // DeregisterActive causes active LLQs to be removed from the server, e.g. before sleep. Pass false
5026 // following a location change, as the server will reject deletions from a source address different
5027 // from the address on which the LLQ was created.
5029 mDNSlocal
void SuspendLLQs(mDNS
*m
, mDNSBool DeregisterActive
)
5033 for (q
= m
->uDNS_info
.ActiveQueries
; q
; q
= q
->next
)
5035 llq
= q
->uDNS_info
.llq
;
5036 if (q
->LongLived
&& llq
)
5038 if (llq
->state
== LLQ_GetZoneInfo
)
5040 debugf("Marking %##s suspend-deferred", q
->qname
.c
);
5041 llq
->state
= LLQ_SuspendDeferred
; // suspend once we're done getting zone info
5043 else if (llq
->state
< LLQ_Suspended
)
5045 if (DeregisterActive
&& (llq
->state
== LLQ_Established
|| llq
->state
== LLQ_Refresh
))
5046 { debugf("Deleting LLQ %##s", q
->qname
.c
); sendLLQRefresh(m
, q
, 0); }
5047 debugf("Marking %##s suspended", q
->qname
.c
);
5048 llq
->state
= LLQ_Suspended
;
5051 else if (llq
->state
== LLQ_Poll
) { debugf("Marking %##s suspended-poll", q
->qname
.c
); llq
->state
= LLQ_SuspendedPoll
; }
5052 if (llq
->NATMap
) llq
->NATMap
= mDNSfalse
; // may not need nat mapping if we restart with new route
5055 CheckForUnreferencedLLQMapping(m
);
5058 mDNSlocal
void RestartQueries(mDNS
*m
)
5060 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
5063 mDNSs32 timenow
= mDNSPlatformTimeNow(m
);
5065 u
->CurrentQuery
= u
->ActiveQueries
;
5066 while (u
->CurrentQuery
)
5068 q
= u
->CurrentQuery
;
5069 u
->CurrentQuery
= u
->CurrentQuery
->next
;
5070 llqInfo
= q
->uDNS_info
.llq
;
5071 q
->uDNS_info
.RestartTime
= timenow
;
5072 q
->uDNS_info
.Answered
= mDNSfalse
;
5075 if (!llqInfo
) { LogMsg("Error: RestartQueries - %##s long-lived with NULL info", q
->qname
.c
); continue; }
5076 if (llqInfo
->state
== LLQ_Suspended
|| llqInfo
->state
== LLQ_NatMapWait
)
5078 llqInfo
->ntries
= -1;
5079 llqInfo
->deriveRemovesOnResume
= mDNStrue
;
5080 startLLQHandshake(m
, llqInfo
, mDNStrue
); // we set defer to true since several events that may generate restarts often arrive in rapid succession, and this cuts unnecessary packets
5082 else if (llqInfo
->state
== LLQ_SuspendDeferred
)
5083 llqInfo
->state
= LLQ_GetZoneInfo
; // we never finished getting zone data - proceed as usual
5084 else if (llqInfo
->state
== LLQ_SuspendedPoll
)
5086 // if we were polling, we may have had bad zone data due to firewall, etc. - refetch
5087 llqInfo
->ntries
= 0;
5088 llqInfo
->deriveRemovesOnResume
= mDNStrue
;
5089 llqInfo
->state
= LLQ_GetZoneInfo
;
5090 startGetZoneData(&q
->qname
, m
, mDNSfalse
, mDNStrue
, startLLQHandshakeCallback
, llqInfo
);
5093 else { q
->LastQTime
= timenow
; q
->ThisQInterval
= INIT_UCAST_POLL_INTERVAL
; } // trigger poll in 1 second (to reduce packet rate when restarts come in rapid succession)
5097 mDNSexport
void mDNS_UpdateLLQs(mDNS
*m
)
5099 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
5104 DeleteNATPortMapping(m
, u
->LLQNatInfo
, mDNSNULL
);
5105 FreeNATInfo(m
, u
->LLQNatInfo
); // routine clears u->LLQNatInfo ptr
5107 SuspendLLQs(m
, mDNStrue
);
5112 // simplest sleep logic - rather than having sleep states that must be dealt with explicitly in all parts of
5113 // the code, we simply send a deregistration, and put the service in Refresh state, with a timeout far enough
5114 // in the future that we'll sleep (or the sleep will be cancelled) before it is retransmitted. Then to wake,
5115 // we just move up the timers.
5119 mDNSlocal
void SleepRecordRegistrations(mDNS
*m
)
5122 AuthRecord
*rr
= m
->uDNS_info
.RecordRegistrations
;
5123 mDNSs32 timenow
= mDNSPlatformTimeNow(m
);
5127 if (rr
->uDNS_info
.state
== regState_Registered
||
5128 rr
->uDNS_info
.state
== regState_Refresh
)
5130 mDNSu8
*ptr
= msg
.data
, *end
= (mDNSu8
*)&msg
+ sizeof(DNSMessage
);
5131 InitializeDNSMessage(&msg
.h
, newMessageID(&m
->uDNS_info
), UpdateReqFlags
);
5133 // construct deletion update
5134 ptr
= putZone(&msg
, ptr
, end
, &rr
->uDNS_info
.zone
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
5135 if (!ptr
) { LogMsg("Error: SleepRecordRegistrations - could not put zone"); return; }
5136 ptr
= putDeletionRecord(&msg
, ptr
, &rr
->resrec
);
5137 if (!ptr
) { LogMsg("Error: SleepRecordRegistrations - could not put deletion record"); return; }
5139 mDNSSendDNSMessage(m
, &msg
, ptr
, mDNSInterface_Any
, &rr
->uDNS_info
.ns
, rr
->uDNS_info
.port
, -1, GetAuthInfoForName(&m
->uDNS_info
, rr
->resrec
.name
));
5140 rr
->uDNS_info
.state
= regState_Refresh
;
5141 rr
->LastAPTime
= timenow
;
5142 rr
->ThisAPInterval
= 300 * mDNSPlatformOneSecond
;
5148 mDNSlocal
void WakeRecordRegistrations(mDNS
*m
)
5150 mDNSs32 timenow
= mDNSPlatformTimeNow(m
);
5151 AuthRecord
*rr
= m
->uDNS_info
.RecordRegistrations
;
5155 if (rr
->uDNS_info
.state
== regState_Refresh
)
5157 // trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets)
5158 rr
->LastAPTime
= timenow
;
5159 rr
->ThisAPInterval
= INIT_UCAST_POLL_INTERVAL
;
5165 mDNSlocal
void SleepServiceRegistrations(mDNS
*m
)
5167 ServiceRecordSet
*srs
= m
->uDNS_info
.ServiceRegistrations
;
5170 uDNS_RegInfo
*info
= &srs
->uDNS_info
;
5171 NATTraversalInfo
*nat
= info
->NATinfo
;
5175 if (nat
->state
== NATState_Established
|| nat
->state
== NATState_Refresh
|| nat
->state
== NATState_Legacy
)
5176 DeleteNATPortMapping(m
, nat
, srs
);
5177 nat
->reg
.ServiceRegistration
= mDNSNULL
;
5178 srs
->uDNS_info
.NATinfo
= mDNSNULL
;
5179 FreeNATInfo(m
, nat
);
5182 if (info
->state
== regState_UpdatePending
)
5184 // act as if the update succeeded, since we're about to delete the name anyway
5185 AuthRecord
*txt
= &srs
->RR_TXT
;
5186 uDNS_RegInfo
*txtInfo
= &txt
->uDNS_info
;
5187 info
->state
= regState_Registered
;
5188 // deallocate old RData
5189 if (txtInfo
->UpdateRDCallback
) txtInfo
->UpdateRDCallback(m
, txt
, txtInfo
->OrigRData
);
5190 SetNewRData(&txt
->resrec
, txtInfo
->InFlightRData
, txtInfo
->InFlightRDLen
);
5191 txtInfo
->OrigRData
= mDNSNULL
;
5192 txtInfo
->InFlightRData
= mDNSNULL
;
5195 if (info
->state
== regState_Registered
|| info
->state
== regState_Refresh
)
5197 mDNSOpaque16 origid
= srs
->uDNS_info
.id
;
5198 info
->state
= regState_DeregPending
; // state expected by SendDereg()
5199 SendServiceDeregistration(m
, srs
);
5201 info
->state
= regState_NoTarget
; // when we wake, we'll re-register (and optionally nat-map) once our address record completes
5202 srs
->RR_SRV
.resrec
.rdata
->u
.srv
.target
.c
[0] = 0;
5208 mDNSlocal
void WakeServiceRegistrations(mDNS
*m
)
5210 mDNSs32 timenow
= mDNSPlatformTimeNow(m
);
5211 ServiceRecordSet
*srs
= m
->uDNS_info
.ServiceRegistrations
;
5214 if (srs
->uDNS_info
.state
== regState_Refresh
)
5216 // trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets)
5217 srs
->RR_SRV
.LastAPTime
= timenow
;
5218 srs
->RR_SRV
.ThisAPInterval
= INIT_UCAST_POLL_INTERVAL
;
5224 mDNSexport
void uDNS_Init(mDNS
*const m
)
5226 mDNSPlatformMemZero(&m
->uDNS_info
, sizeof(uDNS_GlobalInfo
));
5227 m
->uDNS_info
.nextevent
= m
->timenow_last
+ 0x78000000;
5230 mDNSexport
void uDNS_Sleep(mDNS
*const m
)
5232 SuspendLLQs(m
, mDNStrue
);
5233 SleepServiceRegistrations(m
);
5234 SleepRecordRegistrations(m
);
5237 mDNSexport
void uDNS_Wake(mDNS
*const m
)
5240 WakeServiceRegistrations(m
);
5241 WakeRecordRegistrations(m
);