]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSCore/uDNS.c
mDNSResponder-107.6.tar.gz
[apple/mdnsresponder.git] / mDNSCore / uDNS.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16
17 Change History (most recent first):
18
19 $Log: uDNS.c,v $
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
22
23 Revision 1.230 2006/06/29 03:02:44 cheshire
24 <rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
25
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
29
30 Revision 1.228 2006/02/26 00:54:42 cheshire
31 Fixes to avoid code generation warning/error on FreeBSD 7
32
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"
35
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
40
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
45
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
48
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().
52
53 Revision 1.222 2005/10/05 23:04:10 cheshire
54 Add more information to unlinkAR and startLLQHandshakeCallback error messages
55
56 Revision 1.221 2005/10/05 17:27:48 herscher
57 <rdar://problem/4272516> Change 200ms delay to 10ms
58
59 Revision 1.220 2005/09/24 01:10:09 cheshire
60 Fix comment typos
61
62 Revision 1.219 2005/09/22 07:28:25 herscher
63 Double the delay to 200000 usec after sending out a DNS query
64
65 Revision 1.218 2005/09/13 01:06:14 herscher
66 <rdar://problem/4248878> Add 100ms delay in sendQuery.
67
68 Revision 1.217 2005/08/04 18:08:24 cheshire
69 Update comments
70
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
74
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
78
79 Revision 1.214 2005/07/29 19:46:10 ksekar
80 <rdar://problem/4191860> reduce polling period on failed LLQs to 15 minutes
81
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
84
85 Revision 1.212 2005/07/22 19:35:50 ksekar
86 <rdar://problem/4188821> SUTiger: LLQ event acknowledgments are not formated correctly
87
88 Revision 1.211 2005/07/21 18:51:04 ksekar
89 <rdar://problem/4103136> mDNSResponder times out when mapping ports after sleep
90
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
93
94 Revision 1.209 2005/07/04 21:16:37 cheshire
95 Minor code tidying -- initialize variables where they are declared
96
97 Revision 1.208 2005/06/28 00:24:28 ksekar
98 <rdar://problem/4157823> memory smasher in conQueryCallback
99
100 Revision 1.207 2005/05/13 20:45:10 ksekar
101 <rdar://problem/4074400> Rapid wide-area txt record updates don't work
102
103 Revision 1.206 2005/03/31 02:19:55 cheshire
104 <rdar://problem/4021486> Fix build warnings
105 Reviewed by: Scott Herscher
106
107 Revision 1.205 2005/03/21 00:33:51 shersche
108 <rdar://problem/4021486> Fix build warnings on Win32 platform
109
110 Revision 1.204 2005/03/16 00:42:32 ksekar
111 <rdar://problem/4012279> Long-lived queries not working on Windows
112
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
115
116 Revision 1.202 2005/03/01 19:29:17 ksekar
117 changed LogMsgs to debugfs
118
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.
123
124 Revision 1.200 2005/02/25 17:47:45 ksekar
125 <rdar://problem/4021868> SendServiceRegistration fails on wake from sleep
126
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
129
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)
134
135 Revision 1.197 2005/02/24 21:56:59 ksekar
136 Change LogMsgs to debugfs
137
138 Revision 1.196 2005/02/24 21:52:28 ksekar
139 <rdar://problem/3922768> Remove "deferred deregistration" logic for hostnames
140
141 Revision 1.195 2005/02/22 17:53:08 ksekar
142 Changed successful NAT Traversals from LogMsg to LogOperation
143
144 Revision 1.194 2005/02/15 18:38:03 ksekar
145 <rdar://problem/3967876> change expected/redundant log messages to debugfs.
146
147 Revision 1.193 2005/02/15 01:17:48 ksekar
148 Fixed build failure.
149
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.
152
153 Revision 1.191 2005/02/14 18:26:51 ksekar
154 <rdar://problem/4005569> mDNSResponder complains about bad LLQ Opcode 2
155
156 Revision 1.190 2005/02/11 19:44:06 shersche
157 Remove extra semicolon at end of line
158
159 Revision 1.189 2005/02/10 21:07:02 ksekar
160 Don't goto error in ReceiveNATAddrResponse if we receive a malformatted response
161
162 Revision 1.188 2005/02/10 02:02:44 ksekar
163 Remove double semi-colon
164
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
168
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.
172
173 Revision 1.185 2005/02/03 23:48:22 ksekar
174 <rdar://problem/3984374> Simultaneous port map requests sometimes fail
175
176 Revision 1.184 2005/02/01 19:33:29 ksekar
177 <rdar://problem/3985239> Keychain format too restrictive
178
179 Revision 1.183 2005/01/27 22:57:55 cheshire
180 Fix compile errors on gcc4
181
182 Revision 1.182 2005/01/25 18:55:05 ksekar
183 Shortened log message
184
185 Revision 1.181 2005/01/25 02:17:32 cheshire
186 <rdar://problem/3971263> Don't use query ID zero in uDNS queries
187
188 Revision 1.180 2005/01/19 21:01:54 ksekar
189 <rdar://problem/3955355> uDNS needs to support subtype registration and browsing
190
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
193
194 Revision 1.178 2005/01/17 23:47:58 cheshire
195 <rdar://problem/3904954> Wide-area services not found on little-endian
196
197 Revision 1.177 2005/01/17 23:41:26 cheshire
198 Fix compile errors
199
200 Revision 1.176 2005/01/17 21:03:04 cheshire
201 <rdar://problem/3904954> Wide-area services not found on little-endian
202
203 Revision 1.175 2005/01/15 00:56:41 ksekar
204 <rdar://problem/3954575> Unicast services don't disappear when logging
205 out of VPN
206
207 Revision 1.174 2005/01/14 18:44:28 ksekar
208 <rdar://problem/3954609> mDNSResponder is crashing when changing domains
209
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
212
213 Revision 1.172 2005/01/11 22:50:52 ksekar
214 Fixed constant naming (was using kLLQ_DefLease for update leases)
215
216 Revision 1.171 2005/01/10 04:52:49 ksekar
217 Changed LogMsg to debugf
218
219 Revision 1.170 2005/01/08 00:50:05 ksekar
220 Fixed spelling mistake in log msg
221
222 Revision 1.169 2005/01/08 00:42:18 ksekar
223 <rdar://problem/3922758> Clean up syslog messages
224
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
227
228 Revision 1.167 2004/12/22 22:25:47 ksekar
229 <rdar://problem/3734265> NATPMP: handle location changes
230
231 Revision 1.166 2004/12/22 00:04:12 ksekar
232 <rdar://problem/3930324> mDNSResponder crashing in ReceivePortMapReply
233
234 Revision 1.165 2004/12/18 03:14:22 cheshire
235 DblNAT -> DoubleNAT
236
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)
240
241 Revision 1.163 2004/12/17 03:51:53 ksekar
242 <rdar://problem/3920991> Don't update TXT record if service registration fails
243
244 Revision 1.162 2004/12/17 01:29:11 ksekar
245 <rdar://problem/3920598> Questions can go deaf on location changes
246
247 Revision 1.161 2004/12/16 20:42:02 cheshire
248 Fix compiler warnings
249
250 Revision 1.160 2004/12/16 20:13:00 cheshire
251 <rdar://problem/3324626> Cache memory management improvements
252
253 Revision 1.159 2004/12/15 02:11:22 ksekar
254 <rdar://problem/3917317> Don't check for Dynamic DNS hostname uniqueness
255
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
258
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
261
262 Revision 1.156 2004/12/15 01:18:57 ksekar
263 <rdar://problem/3825979> Call DeregisterService on nat port map failure
264
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"
267
268 Revision 1.154 2004/12/14 20:52:27 cheshire
269 Add question->qnamehash and cr->resrec.namehash to log message
270
271 Revision 1.153 2004/12/14 20:45:02 cheshire
272 Improved error logging in "unexpected answer" message
273
274 Revision 1.152 2004/12/14 03:02:10 ksekar
275 <rdar://problem/3919016> Rare race condition can cause crash
276
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)
279
280 Revision 1.150 2004/12/13 20:42:41 ksekar
281 Fixed LogMsg
282
283 Revision 1.149 2004/12/13 18:10:03 ksekar
284 Fixed LogMsg
285
286 Revision 1.148 2004/12/13 01:18:04 ksekar
287 Fixed unused variable warning for non-debug builds
288
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
291
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
294
295 Revision 1.145 2004/12/12 22:56:29 ksekar
296 <rdar://problem/3668508> Need to properly handle duplicate long-lived queries
297
298 Revision 1.144 2004/12/11 20:55:29 ksekar
299 <rdar://problem/3916479> Clean up registration state machines
300
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
303
304 Revision 1.142 2004/12/08 02:03:31 ksekar
305 <rdar://problem/3865124> Looping on NAT Traversal error - check for
306 NULL RR on error
307
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.)
311
312 Revision 1.140 2004/12/06 21:15:22 ksekar
313 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
314
315 Revision 1.139 2004/12/06 19:08:03 cheshire
316 Add clarifying comment -- CountLabels() excludes the final root label.
317
318 Revision 1.138 2004/12/06 01:45:54 ksekar
319 Correct wording in LogMsg
320
321 Revision 1.137 2004/12/03 20:40:35 ksekar
322 <rdar://problem/3865124> Looping on NAT Traversal error
323
324 Revision 1.136 2004/12/03 07:20:50 ksekar
325 <rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
326
327 Revision 1.135 2004/12/03 05:18:33 ksekar
328 <rdar://problem/3810596> mDNSResponder needs to return more specific TSIG errors
329
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
332
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
335
336 Revision 1.132 2004/12/01 20:57:19 ksekar
337 <rdar://problem/3873921> Wide Area Service Discovery must be split-DNS aware
338
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
342
343 Revision 1.130 2004/12/01 02:43:23 cheshire
344 Don't call StatusCallback if function pointer is null
345
346 Revision 1.129 2004/11/30 23:51:06 cheshire
347 Remove double semicolons
348
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
351
352 Revision 1.127 2004/11/25 01:41:36 ksekar
353 Changed unnecessary LogMsgs to debugfs
354
355 Revision 1.126 2004/11/23 23:54:17 ksekar
356 <rdar://problem/3890318> Wide-Area DNSServiceRegisterRecord() failures
357 can crash mDNSResponder
358
359 Revision 1.125 2004/11/23 04:16:48 cheshire
360 Removed receiveMsg() routine.
361
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.
365
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
368
369 Revision 1.122 2004/11/19 18:00:34 ksekar
370 <rdar://problem/3682646> Security: use random ID for one-shot unicast queries
371
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
374
375 Revision 1.120 2004/11/19 02:32:43 ksekar
376 <rdar://problem/3682608> Wide-Area Security: Add LLQ-ID to events
377
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
380
381 Revision 1.118 2004/11/18 22:58:37 ksekar
382 Removed old comment.
383
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>
386
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>.
389
390 Revision 1.xxx 2004/11/17 00:45:28 ksekar
391 <rdar://problem/3880688> Result of putUpdateLease not error-checked
392
393 Revision 1.116 2004/11/16 01:41:47 ksekar
394 Fixed typo in debugf
395
396 Revision 1.115 2004/11/15 20:09:24 ksekar
397 <rdar://problem/3719050> Wide Area support for Add/Remove record
398
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
402
403 Revision 1.113 2004/11/13 02:29:52 ksekar
404 <rdar://problem/3878386> LLQ refreshes not reliable
405
406 Revision 1.112 2004/11/11 20:45:14 ksekar
407 <rdar://problem/3876052> self-conflict test not compatible with some BIND servers
408
409 Revision 1.111 2004/11/11 20:14:55 ksekar
410 <rdar://problem/3719574> Wide-Area registrations not deregistered on sleep
411
412 Revision 1.110 2004/11/10 23:53:53 ksekar
413 Remove no longer relevant comment
414
415 Revision 1.109 2004/11/10 20:40:53 ksekar
416 <rdar://problem/3868216> LLQ mobility fragile on non-primary interface
417
418 Revision 1.108 2004/11/01 20:36:16 ksekar
419 <rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
420
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
423
424 Revision 1.106 2004/10/26 03:52:03 cheshire
425 Update checkin comments
426
427 Revision 1.105 2004/10/26 01:15:06 cheshire
428 Use "#if 0" instead of commenting out code
429
430 Revision 1.104 2004/10/25 21:41:38 ksekar
431 <rdar://problem/3852958> wide-area name conflicts can cause crash
432
433 Revision 1.103 2004/10/25 19:30:52 ksekar
434 <rdar://problem/3827956> Simplify dynamic host name structures
435
436 Revision 1.102 2004/10/23 01:16:00 cheshire
437 <rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
438
439 Revision 1.101 2004/10/22 20:52:07 ksekar
440 <rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
441
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
445
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
450
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
453
454 Revision 1.97 2004/10/15 23:00:18 ksekar
455 <rdar://problem/3799242> Need to update LLQs on location changes
456
457 Revision 1.96 2004/10/12 23:30:44 ksekar
458 <rdar://problem/3609944> mDNSResponder needs to follow CNAME referrals
459
460 Revision 1.95 2004/10/12 03:15:09 ksekar
461 <rdar://problem/3835612> mDNS_StartQuery shouldn't return transient no-server error
462
463 Revision 1.94 2004/10/12 02:49:20 ksekar
464 <rdar://problem/3831228> Clean up LLQ sleep/wake, error handling
465
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
468
469 Revision 1.92 2004/10/08 03:54:35 ksekar
470 <rdar://problem/3831802> Refine unicast polling intervals
471
472 Revision 1.91 2004/09/30 17:45:34 ksekar
473 <rdar://problem/3821119> lots of log messages: mDNS_SetPrimaryIP: IP address unchanged
474
475 Revision 1.90 2004/09/25 00:22:13 ksekar
476 <rdar://problem/3815534> Crash in uDNS_RegisterService
477
478 Revision 1.89 2004/09/24 19:14:53 cheshire
479 Remove unused "extern mDNS mDNSStorage"
480
481 Revision 1.88 2004/09/23 20:48:15 ksekar
482 Clarify retransmission debugf messages.
483
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
486
487 Revision 1.86 2004/09/21 23:40:11 ksekar
488 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
489
490 Revision 1.85 2004/09/21 22:38:27 ksekar
491 <rdar://problem/3810286> PrimaryIP type uninitialized
492
493 Revision 1.84 2004/09/18 00:30:39 cheshire
494 <rdar://problem/3806643> Infinite loop in CheckServiceRegistrations
495
496 Revision 1.83 2004/09/17 00:31:51 cheshire
497 For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
498
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
502
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
506
507 Revision 1.80 2004/09/16 01:58:21 cheshire
508 Fix compiler warnings
509
510 Revision 1.79 2004/09/16 00:24:48 cheshire
511 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
512
513 Revision 1.78 2004/09/15 01:16:57 ksekar
514 <rdar://problem/3797598> mDNSResponder printing too many messages
515
516 Revision 1.77 2004/09/14 23:27:47 cheshire
517 Fix compile errors
518
519 Revision 1.76 2004/09/14 22:22:00 ksekar
520 <rdar://problem/3800920> Legacy browses broken against some BIND versions
521
522 Revision 1.75 2004/09/03 19:23:05 ksekar
523 <rdar://problem/3788460>: Need retransmission mechanism for wide-area service registrations
524
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.
528
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
531
532 Revision 1.72 2004/09/01 03:59:29 ksekar
533 <rdar://problem/3783453>: Conditionally compile out uDNS code on Windows
534
535 Revision 1.71 2004/08/27 17:51:53 ksekar
536 Replaced unnecessary LogMsg with debugf.
537
538 Revision 1.70 2004/08/25 00:37:27 ksekar
539 <rdar://problem/3774635>: Cleanup DynDNS hostname registration code
540
541 Revision 1.69 2004/08/18 17:35:41 ksekar
542 <rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
543
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
549
550 Revision 1.67 2004/08/13 23:46:58 cheshire
551 "asyncronous" -> "asynchronous"
552
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
556
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.)
561
562 Revision 1.64 2004/08/13 23:01:05 cheshire
563 Use platform-independent mDNSNULL instead of NULL
564
565 Revision 1.63 2004/08/12 00:32:36 ksekar
566 <rdar://problem/3759567>: LLQ Refreshes never terminate if unanswered
567
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
571
572 Revision 1.61 2004/07/30 17:40:06 ksekar
573 <rdar://problem/3739115>: TXT Record updates not available for wide-area services
574
575 Revision 1.60 2004/07/29 19:40:05 ksekar
576 NATPMP Support - minor fixes and cleanup
577
578 Revision 1.59 2004/07/29 19:27:15 ksekar
579 NATPMP Support - minor fixes and cleanup
580
581 Revision 1.58 2004/07/27 07:35:38 shersche
582 fix syntax error, variables declared in the middle of a block
583
584 Revision 1.57 2004/07/26 22:49:30 ksekar
585 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
586
587 Revision 1.56 2004/07/26 19:14:44 ksekar
588 <rdar://problem/3737814>: 8A210: mDNSResponder crashed in startLLQHandshakeCallback
589
590 Revision 1.55 2004/07/15 19:01:33 ksekar
591 <rdar://problem/3681029>: Check for incorrect time comparisons
592
593 Revision 1.54 2004/06/22 02:10:53 ksekar
594 <rdar://problem/3705433>: Lighthouse failure causes packet flood to DNS
595
596 Revision 1.53 2004/06/17 20:49:09 ksekar
597 <rdar://problem/3690436>: mDNSResponder crash while location cycling
598
599 Revision 1.52 2004/06/17 01:13:11 ksekar
600 <rdar://problem/3696616>: polling interval too short
601
602 Revision 1.51 2004/06/10 04:36:44 cheshire
603 Fix compiler warning
604
605 Revision 1.50 2004/06/10 00:55:13 ksekar
606 <rdar://problem/3686213>: crash on network reconnect
607
608 Revision 1.49 2004/06/10 00:10:50 ksekar
609 <rdar://problem/3686174>: Infinite Loop in uDNS_Execute()
610
611 Revision 1.48 2004/06/09 20:03:37 ksekar
612 <rdar://problem/3686163>: Incorrect copying of resource record in deregistration
613
614 Revision 1.47 2004/06/09 03:48:28 ksekar
615 <rdar://problem/3685226>: nameserver address fails with prod. Lighthouse server
616
617 Revision 1.46 2004/06/09 01:44:30 ksekar
618 <rdar://problem/3681378> reworked Cache Record copy code
619
620 Revision 1.45 2004/06/08 18:54:47 ksekar
621 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
622
623 Revision 1.44 2004/06/05 00:33:51 cheshire
624 <rdar://problem/3681029>: Check for incorrect time comparisons
625
626 Revision 1.43 2004/06/05 00:14:44 cheshire
627 Fix signed/unsigned and other compiler warnings
628
629 Revision 1.42 2004/06/04 22:36:16 ksekar
630 Properly set u->nextevent in uDNS_Execute
631
632 Revision 1.41 2004/06/04 08:58:29 ksekar
633 <rdar://problem/3668624>: Keychain integration for secure dynamic update
634
635 Revision 1.40 2004/06/03 03:09:58 ksekar
636 <rdar://problem/3668626>: Garbage Collection for Dynamic Updates
637
638 Revision 1.39 2004/06/01 23:46:50 ksekar
639 <rdar://problem/3675149>: DynDNS: dynamically look up LLQ/Update ports
640
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
644
645 Revision 1.37 2004/05/28 23:42:37 ksekar
646 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
647
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
650
651 Revision 1.35 2004/05/07 23:01:04 ksekar
652 Cleaned up list traversal in deriveGoodbyes - removed unnecessary
653 conditional assignment.
654
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.
658
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.
663
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.
667
668 Revision 1.31 2004/05/05 17:05:02 ksekar
669 Use LargeCacheRecord structs when pulling records off packets
670
671 Revision 1.30 2004/04/16 21:33:27 ksekar
672 Fixed bug in processing GetZoneData responses that do not use BIND formatting.
673
674 Revision 1.29 2004/04/15 20:03:13 ksekar
675 Clarified log message when pulling bad resource records off packet.
676
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.
680
681 Revision 1.27 2004/04/14 23:09:28 ksekar
682 Support for TSIG signed dynamic updates.
683
684 Revision 1.26 2004/04/14 19:36:05 ksekar
685 Fixed memory corruption error in deriveGoodbyes.
686
687 Revision 1.25 2004/04/14 04:07:11 ksekar
688 Fixed crash in IsActiveUnicastQuery(). Removed redundant checks in routine.
689
690 Revision 1.24 2004/04/08 09:41:40 bradley
691 Added const to AuthRecord in deadvertiseIfCallback to match callback typedef.
692
693 Revision 1.23 2004/03/24 00:29:45 ksekar
694 Make it safe to call StopQuery in a unicast question callback
695
696 Revision 1.22 2004/03/19 10:11:09 bradley
697 Added AuthRecord * cast from umalloc for C++ builds.
698
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++.
702
703 Revision 1.20 2004/03/13 02:07:26 ksekar
704 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
705
706 Revision 1.19 2004/03/13 01:57:33 ksekar
707 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
708
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.
712
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
715
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
718
719 Revision 1.15 2004/02/10 03:02:46 cheshire
720 Fix compiler warning
721
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)
725
726 Revision 1.13 2004/02/03 22:15:01 ksekar
727 Fixed nameToAddr error check: don't abort state machine on nxdomain error.
728
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.
734
735 Revision 1.11 2004/01/30 02:12:30 ksekar
736 Changed uDNS_ReceiveMsg() to correctly return void.
737
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.
744
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.
748
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.
753
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
756
757 Revision 1.6 2004/01/24 23:47:17 cheshire
758 Use mDNSOpaque16fromIntVal() instead of shifting and masking
759
760 Revision 1.5 2004/01/24 04:59:15 cheshire
761 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
762
763 Revision 1.4 2004/01/24 04:19:26 cheshire
764 Restore overwritten checkin 1.2
765
766 Revision 1.3 2004/01/23 23:23:15 ksekar
767 Added TCP support for truncated unicast messages.
768
769 Revision 1.2 2004/01/22 03:48:41 cheshire
770 Make sure uDNS client doesn't accidentally use query ID zero
771
772 Revision 1.1 2003/12/13 03:05:27 ksekar
773 <rdar://problem/3192548>: DynDNS: Unicast query of service records
774
775 */
776
777 #include "uDNS.h"
778
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)
786 #endif
787
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
792
793 // Asynchronous operation types
794
795 typedef enum
796 {
797 zoneDataResult
798 // other async. operation names go here
799 } AsyncOpResultType;
800
801 typedef struct
802 {
803 domainname zoneName;
804 mDNSAddr primaryAddr;
805 mDNSu16 zoneClass;
806 mDNSIPPort llqPort;
807 mDNSIPPort updatePort;
808 } zoneData_t;
809
810 // other async. result struct defs go here
811
812 typedef struct
813 {
814 AsyncOpResultType type;
815 zoneData_t zoneData;
816 // other async result structs go here
817 } AsyncOpResult;
818
819 typedef void AsyncOpCallback(mStatus err, mDNS *const m, void *info, const AsyncOpResult *result);
820
821
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.)
827
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);
840
841 // ***************************************************************************
842 #if COMPILER_LIKES_PRAGMA_MARK
843 #pragma mark - Temporary workaround
844 #endif
845
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
851
852 mDNSlocal mDNSs32 mDNSPlatformTimeNow(mDNS *m)
853 {
854 if (m->mDNS_busy && m->timenow) return(m->timenow);
855 LogMsg("ERROR: uDNS.c code executing without holding main mDNS lock");
856
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:
859 // *(long*)0=0;
860
861 return(mDNS_TimeNow(m));
862 }
863
864 // ***************************************************************************
865 #if COMPILER_LIKES_PRAGMA_MARK
866 #pragma mark - General Utility Functions
867 #endif
868
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)
872 {
873 int count = 0;
874 const mDNSu8 *ptr;
875
876 for (ptr = d->c; *ptr; ptr = ptr + ptr[0] + 1) count++;
877 return count;
878 }
879
880 mDNSlocal mDNSOpaque16 newMessageID(uDNS_GlobalInfo *u)
881 {
882 static mDNSBool randomized = mDNSfalse;
883
884 if (!randomized) { u->NextMessageID = (mDNSu16)mDNSRandom(0xFFFF); randomized = mDNStrue; }
885 if (u->NextMessageID == 0) u->NextMessageID++;
886 return mDNSOpaque16fromIntVal(u->NextMessageID++);
887 }
888
889 // unlink an AuthRecord from a linked list
890 mDNSlocal mStatus unlinkAR(AuthRecord **list, AuthRecord *const rr)
891 {
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);
896 }
897
898 mDNSlocal void unlinkSRS(mDNS *m, ServiceRecordSet *srs)
899 {
900 uDNS_GlobalInfo *u = &m->uDNS_info;
901 ServiceRecordSet **p;
902 NATTraversalInfo *n = u->NATTraversals;
903
904 // verify that no NAT objects reference this service
905 while (n)
906 {
907 if (n->reg.ServiceRegistration == srs)
908 {
909 NATTraversalInfo *tmp = n;
910 n = n->next;
911 LogMsg("ERROR: Unlinking service record set %##s still referenced by NAT traversal object!", srs->RR_SRV.resrec.name->c);
912 FreeNATInfo(m, tmp);
913 }
914 else n = n->next;
915 }
916
917 for (p = &u->ServiceRegistrations; *p; p = &(*p)->next)
918 if (*p == srs)
919 {
920 ExtraResourceRecord *e;
921 *p = srs->next;
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);
926 return;
927 }
928 LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list %##s", srs->RR_SRV.resrec.name->c);
929 }
930
931 mDNSlocal void LinkActiveQuestion(uDNS_GlobalInfo *u, DNSQuestion *q)
932 {
933 if (uDNS_IsActiveQuery(q, u))
934 { LogMsg("LinkActiveQuestion - %##s (%d) already in list!", q->qname.c, q->qtype); return; }
935
936 q->next = u->ActiveQueries;
937 u->ActiveQueries = q;
938 }
939
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)
943 {
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;
948 }
949
950
951 // ***************************************************************************
952 #if COMPILER_LIKES_PRAGMA_MARK
953 #pragma mark - Name Server List Management
954 #endif
955
956 mDNSexport void mDNS_AddDNSServer(mDNS *const m, const mDNSAddr *addr, const domainname *d)
957 {
958 uDNS_GlobalInfo *u = &m->uDNS_info;
959 DNSServer *s, **p = &u->Servers;
960
961 mDNS_Lock(m);
962 if (!d) d = (domainname *)"";
963
964 while (*p) // Check if we already have this {server,domain} pair registered
965 {
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);
968 p=&(*p)->next;
969 }
970
971 // allocate, add to list
972 s = umalloc(sizeof(*s));
973 if (!s) { LogMsg("Error: mDNS_AddDNSServer - malloc"); goto end; }
974 s->addr = *addr;
975 s->del = mDNSfalse;
976 s->teststate = DNSServer_Untested;
977 AssignDomainName(&s->domain, d);
978 s->next = mDNSNULL;
979 *p = s;
980
981 end:
982 mDNS_Unlock(m);
983 }
984
985 mDNSexport void mDNS_DeleteDNSServers(mDNS *const m)
986 {
987 DNSServer *s;
988 mDNS_Lock(m);
989
990 s = m->uDNS_info.Servers;
991 m->uDNS_info.Servers = mDNSNULL;
992 while (s)
993 {
994 DNSServer *tmp = s;
995 s = s->next;
996 ufree(tmp);
997 }
998
999 mDNS_Unlock(m);
1000 }
1001
1002 // ***************************************************************************
1003 #if COMPILER_LIKES_PRAGMA_MARK
1004 #pragma mark - authorization management
1005 #endif
1006
1007 mDNSlocal uDNS_AuthInfo *GetAuthInfoForName(const uDNS_GlobalInfo *u, const domainname *name)
1008 {
1009 uDNS_AuthInfo *ptr;
1010 while (name->c[0])
1011 {
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]);
1015 }
1016 return mDNSNULL;
1017 }
1018
1019 mDNSlocal void DeleteAuthInfoForZone(uDNS_GlobalInfo *u, const domainname *zone)
1020 {
1021 uDNS_AuthInfo *ptr, *prev = mDNSNULL;
1022
1023 for (ptr = u->AuthInfoList; ptr; ptr = ptr->next)
1024 {
1025 if (SameDomainName(&ptr->zone, zone))
1026 {
1027 if (prev) prev->next = ptr->next;
1028 else u->AuthInfoList = ptr->next;
1029 ufree(ptr);
1030 return;
1031 }
1032 prev = ptr;
1033 }
1034 }
1035
1036 mDNSexport mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const domainname *key, const char *sharedSecret)
1037 {
1038 uDNS_AuthInfo *info;
1039 mDNSu8 keybuf[1024];
1040 mDNSs32 keylen;
1041 uDNS_GlobalInfo *u = &m->uDNS_info;
1042 mStatus status = mStatus_NoError;
1043
1044 mDNS_Lock(m);
1045
1046 if (GetAuthInfoForName(u, zone)) DeleteAuthInfoForZone(u, zone);
1047 if (!key) goto exit;
1048
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);
1054
1055 keylen = DNSDigest_Base64ToBin(sharedSecret, keybuf, 1024);
1056 if (keylen < 0)
1057 {
1058 LogMsg("ERROR: mDNS_SetSecretForZone - could not convert shared secret %s from base64", sharedSecret);
1059 ufree(info);
1060 status = mStatus_UnknownErr;
1061 goto exit;
1062 }
1063 DNSDigest_ConstructHMACKey(info, keybuf, (mDNSu32)keylen);
1064
1065 // link into list
1066 info->next = m->uDNS_info.AuthInfoList;
1067 m->uDNS_info.AuthInfoList = info;
1068 exit:
1069 mDNS_Unlock(m);
1070 return status;
1071 }
1072
1073 // ***************************************************************************
1074 #if COMPILER_LIKES_PRAGMA_MARK
1075 #pragma mark - NAT Traversal
1076 #endif
1077
1078 mDNSlocal mDNSBool DomainContainsLabelString(const domainname *d, const char *str)
1079 {
1080 const domainlabel *l;
1081 domainlabel buf;
1082
1083 if (!MakeDomainLabelFromLiteralString(&buf, str)) return mDNSfalse;
1084
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;
1087 return mDNSfalse;
1088 }
1089
1090 // allocate struct, link into global list, initialize
1091 mDNSlocal NATTraversalInfo *AllocNATInfo(mDNS *const m, NATOp_t op, NATResponseHndlr callback)
1092 {
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;
1100 info->op = op;
1101 info->state = NATState_Init;
1102 info->ReceiveResponse = callback;
1103 info->PublicPort.NotAnInteger = 0;
1104 info->Router = u->Router;
1105 return info;
1106 }
1107
1108 // unlink from list, deallocate
1109 mDNSlocal mDNSBool FreeNATInfo(mDNS *m, NATTraversalInfo *n)
1110 {
1111 NATTraversalInfo *ptr, *prev = mDNSNULL;
1112 ServiceRecordSet *s = m->uDNS_info.ServiceRegistrations;
1113
1114 // Verify that object is not referenced by any services
1115 while (s)
1116 {
1117 if (s->uDNS_info.NATinfo == n)
1118 {
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;
1121 }
1122 s = s->next;
1123 }
1124
1125 if (n == m->uDNS_info.LLQNatInfo) m->uDNS_info.LLQNatInfo = mDNSNULL;
1126 ptr = m->uDNS_info.NATTraversals;
1127 while (ptr)
1128 {
1129 if (ptr == n)
1130 {
1131 if (prev) prev->next = ptr->next;
1132 else m->uDNS_info.NATTraversals = ptr->next;
1133 ufree(n);
1134 return mDNStrue;
1135 }
1136 prev = ptr;
1137 ptr = ptr->next;
1138 }
1139 LogMsg("FreeNATInfo: NATTraversalInfo not found in list");
1140 return mDNSfalse;
1141 }
1142
1143 mDNSlocal void SendNATMsg(NATTraversalInfo *info, mDNS *m)
1144 {
1145 mStatus err;
1146 uDNS_GlobalInfo *u = &m->uDNS_info;
1147
1148 if (info->state != NATState_Request && info->state != NATState_Refresh)
1149 { LogMsg("SendNATMsg: Bad state %d", info->state); return; }
1150
1151 if (u->Router.ip.v4.NotAnInteger)
1152 {
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);
1157
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
1160 }
1161
1162 // set retry
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;
1167 }
1168
1169 mDNSlocal mDNSBool ReceiveNATAddrResponse(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len)
1170 {
1171 mStatus err = mStatus_NoError;
1172 AuthRecord *rr = mDNSNULL;
1173 NATAddrReply *response = (NATAddrReply *)pkt;
1174 mDNSAddr addr;
1175
1176 if (n->state != NATState_Request)
1177 {
1178 LogMsg("ReceiveNATAddrResponse: bad state %d", n->state);
1179 return mDNSfalse;
1180 }
1181
1182 rr = n->reg.RecordRegistration;
1183 if (!rr)
1184 {
1185 LogMsg("ReceiveNATAddrResponse: registration cancelled");
1186 return mDNSfalse;
1187 }
1188
1189 addr.type = mDNSAddrType_IPv4;
1190 addr.ip.v4 = rr->resrec.rdata->u.ipv4;
1191
1192 if (!pkt) // timeout
1193 {
1194 #ifdef _LEGACY_NAT_TRAVERSAL_
1195 err = LNT_GetPublicIP(&addr.ip.v4);
1196 if (err) goto end;
1197 else n->state = NATState_Legacy;
1198 #else
1199 debugf("ReceiveNATAddrResponse: timeout");
1200 err = mStatus_NATTraversal;
1201 goto end;
1202 #endif // _LEGACY_NAT_TRAVERSAL_
1203 }
1204 else
1205 {
1206 if (len < sizeof(*response))
1207 {
1208 LogMsg("ReceiveNATAddrResponse: response too short (%d bytes)", len);
1209 return mDNSfalse;
1210 }
1211 if (response->vers != NATMAP_VERS)
1212 {
1213 LogMsg("ReceiveNATAddrResponse: received version %d (expect version %d)", pkt[0], NATMAP_VERS);
1214 return mDNSfalse;
1215 }
1216 if (response->opcode != (NATOp_AddrRequest | NATMAP_RESPONSE_MASK))
1217 {
1218 LogMsg("ReceiveNATAddrResponse: bad response code %d", response->opcode);
1219 return mDNSfalse;
1220 }
1221 if (response->err.NotAnInteger)
1222 { LogMsg("ReceiveAddrResponse: received error %d", mDNSVal16(response->err)); err = mStatus_NATTraversal; goto end; }
1223
1224 addr.ip.v4 = response->PubAddr;
1225 n->state = NATState_Established;
1226 }
1227
1228 if (IsPrivateV4Addr(&addr))
1229 {
1230 LogMsg("ReceiveNATAddrResponse: Double NAT");
1231 err = mStatus_DoubleNAT;
1232 goto end;
1233 }
1234
1235 end:
1236 if (err)
1237 {
1238 FreeNATInfo(m, n);
1239 if (rr)
1240 {
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
1245 }
1246 return mDNStrue;
1247 }
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);
1251 return mDNStrue;
1252 }
1253
1254
1255 mDNSlocal void StartGetPublicAddr(mDNS *m, AuthRecord *AddressRec)
1256 {
1257 NATAddrRequest *req;
1258 uDNS_GlobalInfo *u = &m->uDNS_info;
1259
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;
1265
1266 // format message
1267 req = &info->request.AddrReq;
1268 req->vers = NATMAP_VERS;
1269 req->opcode = NATOp_AddrRequest;
1270
1271 if (!u->Router.ip.v4.NotAnInteger)
1272 {
1273 debugf("No router. Will retry NAT traversal in %ld ticks", NATMAP_INIT_RETRY);
1274 return;
1275 }
1276
1277 SendNATMsg(info, m);
1278 }
1279
1280
1281 mDNSlocal void RefreshNATMapping(NATTraversalInfo *n, mDNS *m)
1282 {
1283 n->state = NATState_Refresh;
1284 n->RetryInterval = NATMAP_INIT_RETRY;
1285 n->ntries = 0;
1286 SendNATMsg(n, m);
1287 }
1288
1289 mDNSlocal void LLQNatMapComplete(mDNS *m)
1290 {
1291 uDNS_GlobalInfo *u = &m->uDNS_info;
1292 LLQ_Info *llqInfo;
1293 NATTraversalInfo *n = u->LLQNatInfo;
1294
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; }
1298
1299 u->CurrentQuery = u->ActiveQueries;
1300 while (u->CurrentQuery)
1301 {
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)
1306 {
1307 if (n->state == NATState_Error)
1308 {
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;
1314 }
1315 else { llqInfo->state = LLQ_GetZoneInfo; startLLQHandshake(m, llqInfo, mDNSfalse); }
1316 }
1317 }
1318 }
1319
1320 mDNSlocal mDNSBool ReceivePortMapReply(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len)
1321 {
1322 ServiceRecordSet *srs = n->reg.ServiceRegistration;
1323 mDNSIPPort priv = srs ? srs->RR_SRV.resrec.rdata->u.srv.port : m->UnicastPort4;
1324 mDNSu32 lease;
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";
1328
1329 if (n->state != NATState_Request && n->state != NATState_Refresh)
1330 { LogMsg("ReceivePortMapReply (%##s): bad state %d", service, n->state); return mDNSfalse; }
1331
1332 if (!pkt && !deletion) // timeout
1333 {
1334 #ifdef _LEGACY_NAT_TRAVERSAL_
1335 mDNSIPPort pub;
1336 int ntries = 0;
1337 mStatus err;
1338 mDNSBool tcp = (srs && DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp"));
1339
1340 pub = priv; // initially request priv == pub
1341 while (1)
1342 {
1343 err = LNT_MapPort(priv, pub, tcp);
1344 if (!err)
1345 {
1346 n->PublicPort = pub;
1347 n->state = NATState_Legacy;
1348 goto end;
1349 }
1350 else if (err != mStatus_AlreadyRegistered || ++ntries > LEGACY_NATMAP_MAX_TRIES)
1351 {
1352 n->state = NATState_Error;
1353 goto end;
1354 }
1355 else
1356 {
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);
1360 }
1361 }
1362 #else
1363 goto end;
1364 #endif // _LEGACY_NAT_TRAVERSAL_
1365 }
1366
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
1372
1373 if (!srs && n != m->uDNS_info.LLQNatInfo)
1374 {
1375 LogMsg("ReceivePortMapReply: registration cancelled"); //!!!KRS change to debugf before checkin
1376 FreeNATInfo(m, n);
1377 return mDNStrue;
1378 }
1379
1380 if (deletion) { n->state = NATState_Deleted; return mDNStrue; }
1381
1382 lease = (mDNSu32)mDNSVal32(reply->lease);
1383 if (lease > 0x70000000UL / mDNSPlatformOneSecond) lease = 0x70000000UL / mDNSPlatformOneSecond;
1384
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
1389
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
1392
1393 n->retry = mDNSPlatformTimeNow(m) + ((mDNSs32)lease * mDNSPlatformOneSecond / 2); // retry half way to expiration
1394
1395 if (n->state == NATState_Refresh) { n->state = NATState_Established; return mDNStrue; }
1396 n->state = NATState_Established;
1397
1398 end:
1399 if (n->state != NATState_Established && n->state != NATState_Legacy)
1400 {
1401 LogMsg("NAT Port Mapping (%##s): timeout", service);
1402 if (pkt) LogMsg("!!! timeout with non-null packet");
1403 n->state = NATState_Error;
1404 if (srs)
1405 {
1406 uDNS_HostnameInfo *hi = m->uDNS_info.Hostnames;
1407 while (hi)
1408 {
1409 if (hi->arv6 && (hi->arv6->uDNS_info.state == regState_Registered || hi->arv6->uDNS_info.state == regState_Refresh)) break;
1410 else hi = hi->next;
1411 }
1412
1413 if (hi)
1414 {
1415 debugf("Port map failed for service %##s - using IPv6 service target", service);
1416 srs->uDNS_info.NATinfo = mDNSNULL;
1417 FreeNATInfo(m, n);
1418 goto register_service;
1419 }
1420 else srs->uDNS_info.state = regState_NATError;
1421 }
1422 else LLQNatMapComplete(m);
1423 return mDNStrue;
1424 }
1425 else LogOperation("Mapped private port %d to public port %d", mDNSVal16(priv), mDNSVal16(n->PublicPort));
1426
1427 if (!srs) { LLQNatMapComplete(m); return mDNStrue; }
1428
1429 register_service:
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
1431 else
1432 {
1433 srs->uDNS_info.state = regState_FetchingZoneData;
1434 startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
1435 }
1436 return mDNStrue;
1437 }
1438
1439 mDNSlocal void FormatPortMaprequest(NATTraversalInfo *info, mDNSIPPort port)
1440 {
1441 NATPortMapRequest *req = &info->request.PortReq;
1442
1443 req->vers = NATMAP_VERS;
1444 req->opcode = info->op;
1445 req->unused.NotAnInteger = 0;
1446 req->priv = port;
1447 req->pub = port;
1448 req->lease = mDNSOpaque32fromIntVal(NATMAP_DEFAULT_LEASE);
1449 }
1450
1451 mDNSlocal void SendInitialPMapReq(mDNS *m, NATTraversalInfo *info)
1452 {
1453 if (!m->uDNS_info.Router.ip.v4.NotAnInteger)
1454 {
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;
1458 return;
1459 }
1460 SendNATMsg(info, m);
1461 return;
1462 }
1463
1464 mDNSlocal void StartNATPortMap(mDNS *m, ServiceRecordSet *srs)
1465 {
1466 NATOp_t op;
1467 NATTraversalInfo *info;
1468
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; }
1472
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;
1478
1479 FormatPortMaprequest(info, srs->RR_SRV.resrec.rdata->u.srv.port);
1480 SendInitialPMapReq(m, info);
1481 return;
1482
1483 error:
1484 startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
1485 }
1486
1487 mDNSlocal void DeleteNATPortMapping(mDNS *m, NATTraversalInfo *nat, ServiceRecordSet *srs)
1488 {
1489 if (nat->state == NATState_Established) // let other edge-case states expire for simplicity
1490 {
1491 // zero lease
1492 nat->request.PortReq.lease.NotAnInteger = 0;
1493 nat->state = NATState_Request;
1494 SendNATMsg(nat, m);
1495 }
1496 #ifdef _LEGACY_NAT_TRAVERSAL_
1497 else if (nat->state == NATState_Legacy)
1498 {
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);
1503 }
1504 #else
1505 (void)srs; // unused
1506 #endif // _LEGACY_NAT_TRAVERSAL_
1507 }
1508
1509 mDNSlocal void StartLLQNatMap(mDNS *m)
1510 {
1511 NATTraversalInfo *info = AllocNATInfo(m, NATOp_MapUDP, ReceivePortMapReply);
1512 uDNS_GlobalInfo *u = &m->uDNS_info;
1513
1514 u->LLQNatInfo = info;
1515
1516 info->reg.RecordRegistration = mDNSNULL;
1517 info->reg.ServiceRegistration = mDNSNULL;
1518 info->state = NATState_Request;
1519 FormatPortMaprequest(info, m->UnicastPort4);
1520 SendInitialPMapReq(m, info);
1521 return;
1522 }
1523
1524 // if LLQ NAT context unreferenced, delete the mapping
1525 mDNSlocal void CheckForUnreferencedLLQMapping(mDNS *m)
1526 {
1527 NATTraversalInfo *nat = m->uDNS_info.LLQNatInfo;
1528 DNSQuestion *q;
1529
1530 if (!nat) return;
1531
1532 for (q = m->uDNS_info.ActiveQueries; q; q = q->next)
1533 if (q->LongLived && q->uDNS_info.llq->NATMap) return;
1534
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
1539 }
1540
1541 // ***************************************************************************
1542 #if COMPILER_LIKES_PRAGMA_MARK
1543 #pragma mark - host name and interface management
1544 #endif
1545
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)
1549 {
1550 uDNS_HostnameInfo *hi = u->Hostnames;
1551 (void)srv; // unused
1552
1553 dst->c[0] = 0;
1554 while (hi)
1555 {
1556 if (hi->arv4 && (hi->arv4->uDNS_info.state == regState_Registered || hi->arv4->uDNS_info.state == regState_Refresh))
1557 {
1558 AssignDomainName(dst, hi->arv4->resrec.name);
1559 return mDNStrue;
1560 }
1561 if (hi->arv6 && (hi->arv6->uDNS_info.state == regState_Registered || hi->arv6->uDNS_info.state == regState_Refresh))
1562 {
1563 AssignDomainName(dst, hi->arv4->resrec.name);
1564 return mDNStrue;
1565 }
1566 hi = hi->next;
1567 }
1568
1569 if (u->StaticHostname.c[0]) { AssignDomainName(dst, &u->StaticHostname); return mDNStrue; }
1570 return mDNSfalse;
1571 }
1572
1573 mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs)
1574 {
1575 uDNS_GlobalInfo *u = &m->uDNS_info;
1576 ExtraResourceRecord *e;
1577
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
1582
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;
1588
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
1593
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;
1601
1602 if (WereBehindNAT && NowBehindNAT && NATRouterChanged) NATChanged = mDNStrue;
1603 else if (!NowBehindNAT && PortWasMapped) NATChanged = mDNStrue;
1604 else if (!WereBehindNAT && NowBehindNAT) NATChanged = mDNStrue;
1605
1606 if (!TargetChanged && !NATChanged) return;
1607
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);
1610
1611 switch(srs->uDNS_info.state)
1612 {
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
1622 return;
1623
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;
1629 return;
1630
1631 case regState_NATError:
1632 if (!NATChanged) return;
1633 // if nat changed, register if we have a target (below)
1634
1635 case regState_NoTarget:
1636 if (HaveTarget)
1637 {
1638 debugf("UpdateSRV: %s service %##s", HaveZoneData ? (NATChanged && NowBehindNAT ? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs->RR_SRV.resrec.name->c);
1639 if (!HaveZoneData)
1640 {
1641 srs->uDNS_info.state = regState_FetchingZoneData;
1642 startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
1643 }
1644 else
1645 {
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);
1649 }
1650 }
1651 return;
1652
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);
1659 return;
1660 }
1661 }
1662
1663 mDNSlocal void UpdateSRVRecords(mDNS *m)
1664 {
1665 ServiceRecordSet *srs;
1666
1667 for (srs = m->uDNS_info.ServiceRegistrations; srs; srs = srs->next) UpdateSRV(m, srs);
1668 }
1669
1670 mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
1671 {
1672 uDNS_HostnameInfo *hi = (uDNS_HostnameInfo *)rr->RecordContext;
1673
1674 if (result == mStatus_MemFree)
1675 {
1676 if (hi)
1677 {
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
1682 }
1683 ufree(rr);
1684 return;
1685 }
1686
1687 if (result)
1688 {
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);
1692 else
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!");
1696
1697 if ((!hi->arv4 || hi->arv4->uDNS_info.state == regState_Unregistered) &&
1698 (!hi->arv6 || hi->arv6->uDNS_info.state == regState_Unregistered))
1699 {
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;
1705 }
1706 return;
1707 }
1708 // register any pending services that require a target
1709 UpdateSRVRecords(m);
1710
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);
1715 else
1716 LogMsg("Registered hostname %##s IP %.16a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
1717
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;
1722 }
1723
1724 // register record or begin NAT traversal
1725 mDNSlocal void AdvertiseHostname(mDNS *m, uDNS_HostnameInfo *h)
1726 {
1727 uDNS_GlobalInfo *u = &m->uDNS_info;
1728
1729 if (u->AdvertisedV4.ip.v4.NotAnInteger && h->arv4->uDNS_info.state == regState_Unregistered)
1730 {
1731 if (IsPrivateV4Addr(&u->AdvertisedV4))
1732 StartGetPublicAddr(m, h->arv4);
1733 else
1734 {
1735 LogMsg("Advertising %##s IP %.4a", h->arv4->resrec.name->c, &u->AdvertisedV4.ip.v4);
1736 uDNS_RegisterRecord(m, h->arv4);
1737 }
1738 }
1739 if (u->AdvertisedV6.ip.v6.b[0] && h->arv6->uDNS_info.state == regState_Unregistered)
1740 {
1741 LogMsg("Advertising %##s IP %.16a", h->arv4->resrec.name->c, &u->AdvertisedV6.ip.v6);
1742 uDNS_RegisterRecord(m, h->arv6);
1743 }
1744 }
1745
1746 mDNSlocal void FoundStaticHostname(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1747 {
1748 const domainname *pktname = &answer->rdata->u.name;
1749 domainname *storedname = &m->uDNS_info.StaticHostname;
1750 uDNS_HostnameInfo *h = m->uDNS_info.Hostnames;
1751
1752 (void)question;
1753
1754 debugf("FoundStaticHostname: %##s -> %##s (%s)", question->qname.c, answer->rdata->u.name.c, AddRecord ? "added" : "removed");
1755 if (AddRecord && !SameDomainName(pktname, storedname))
1756 {
1757 AssignDomainName(storedname, pktname);
1758 while (h)
1759 {
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)))
1762 {
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);
1766 return;
1767 }
1768 h = h->next;
1769 }
1770 UpdateSRVRecords(m);
1771 }
1772 else if (!AddRecord && SameDomainName(pktname, storedname))
1773 {
1774 storedname->c[0] = 0;
1775 UpdateSRVRecords(m);
1776 }
1777 }
1778
1779 mDNSlocal void GetStaticHostname(mDNS *m)
1780 {
1781 char buf[MAX_ESCAPED_DOMAIN_NAME];
1782 DNSQuestion *q = &m->uDNS_info.ReverseMap;
1783 mDNSu8 *ip = m->uDNS_info.AdvertisedV4.ip.v4.b;
1784 mStatus err;
1785
1786 if (m->uDNS_info.ReverseMapActive)
1787 {
1788 uDNS_StopQuery(m, q);
1789 m->uDNS_info.ReverseMapActive = mDNSfalse;
1790 }
1791
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; }
1797
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;
1807
1808 err = uDNS_StartQuery(m, q);
1809 if (err) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err);
1810 else m->uDNS_info.ReverseMapActive = mDNStrue;
1811 }
1812
1813 mDNSlocal void AssignHostnameInfoAuthRecord(mDNS *m, uDNS_HostnameInfo *hi, int type)
1814 {
1815 AuthRecord **dst = (type == mDNSAddrType_IPv4 ? &hi->arv4 : &hi->arv6);
1816 AuthRecord *ar = umalloc(sizeof(*ar));
1817 uDNS_GlobalInfo *u = &m->uDNS_info;
1818
1819 if (type != mDNSAddrType_IPv4 && type != mDNSAddrType_IPv6) { LogMsg("ERROR: AssignHostnameInfoAuthRecord - bad type %d", type); return; }
1820 if (!ar) { LogMsg("ERROR: AssignHostnameInfoAuthRecord - malloc"); return; }
1821
1822 mDNS_SetupResourceRecord(ar, mDNSNULL, 0, type == mDNSAddrType_IPv4 ? kDNSType_A : kDNSType_AAAA, 1, kDNSRecordTypeKnownUnique, HostnameCallback, hi);
1823 AssignDomainName(ar->resrec.name, &hi->fqdn);
1824
1825 // only set RData if we have a valid IP
1826 if (type == mDNSAddrType_IPv4 && u->AdvertisedV4.ip.v4.NotAnInteger)
1827 {
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;
1830 }
1831 else if (type == mDNSAddrType_IPv6 && u->AdvertisedV6.ip.v6.b[0])
1832 {
1833 ar->resrec.rdata->u.ipv6 = u->AdvertisedV6.ip.v6;
1834 }
1835
1836 ar->uDNS_info.state = regState_Unregistered;
1837
1838 if (*dst)
1839 {
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
1843 }
1844
1845 *dst = ar;
1846 }
1847
1848
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)
1852 {
1853 uDNS_GlobalInfo *u = &m->uDNS_info;
1854 uDNS_HostnameInfo *i;
1855
1856 for (i = u->Hostnames; i; i = i->next)
1857 {
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)
1861 {
1862 uDNS_DeregisterRecord(m, i->arv4);
1863 i->arv4 = mDNSNULL;
1864 }
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)
1866 {
1867 uDNS_DeregisterRecord(m, i->arv6);
1868 i->arv6 = mDNSNULL;
1869 }
1870
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;
1875
1876 AdvertiseHostname(m, i);
1877 }
1878 }
1879
1880 mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
1881 {
1882 uDNS_GlobalInfo *u = &m->uDNS_info;
1883 uDNS_HostnameInfo *ptr, *new;
1884
1885 mDNS_Lock(m);
1886
1887 // check if domain already registered
1888 for (ptr = u->Hostnames; ptr; ptr = ptr->next)
1889 {
1890 if (SameDomainName(fqdn, &ptr->fqdn))
1891 { LogMsg("Host Domain %##s already in list", fqdn->c); goto exit; }
1892 }
1893
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;
1899 u->Hostnames = new;
1900
1901 AssignDomainName(&new->fqdn, fqdn);
1902 new->StatusCallback = StatusCallback;
1903 new->StatusContext = StatusContext;
1904
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;
1909
1910 if (u->AdvertisedV6.ip.v6.b[0] || u->AdvertisedV4.ip.v4.NotAnInteger) AdvertiseHostname(m, new);
1911
1912 exit:
1913 mDNS_Unlock(m);
1914 }
1915
1916 mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn)
1917 {
1918 uDNS_GlobalInfo *u = &m->uDNS_info;
1919 uDNS_HostnameInfo **ptr = &u->Hostnames;
1920
1921 mDNS_Lock(m);
1922
1923 while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next;
1924 if (!*ptr) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn->c);
1925 else
1926 {
1927 uDNS_HostnameInfo *hi = *ptr;
1928 *ptr = (*ptr)->next; // unlink
1929 if (hi->arv4)
1930 {
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; }
1934 }
1935 if (hi->arv6)
1936 {
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; }
1940 }
1941 ufree(hi);
1942 }
1943 UpdateSRVRecords(m);
1944 mDNS_Unlock(m);
1945 }
1946
1947 mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router)
1948 {
1949 uDNS_GlobalInfo *u = &m->uDNS_info;
1950 mDNSBool v4Changed, v6Changed, RouterChanged;
1951
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; }
1955
1956 mDNS_Lock(m);
1957
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;
1961
1962 #if MDNS_DEBUGMSGS
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
1968
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
1974
1975 if ((v4Changed || RouterChanged || v6Changed) && v4addr)
1976 {
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
1981 }
1982
1983 mDNS_Unlock(m);
1984 }
1985
1986 // ***************************************************************************
1987 #if COMPILER_LIKES_PRAGMA_MARK
1988 #pragma mark - Incoming Message Processing
1989 #endif
1990
1991 mDNSlocal mDNSBool kaListContainsAnswer(DNSQuestion *question, CacheRecord *rr)
1992 {
1993 CacheRecord *ptr;
1994
1995 for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next)
1996 if (SameResourceRecord(&ptr->resrec, &rr->resrec)) return mDNStrue;
1997
1998 return mDNSfalse;
1999 }
2000
2001
2002 mDNSlocal void removeKnownAnswer(DNSQuestion *question, CacheRecord *rr)
2003 {
2004 CacheRecord *ptr, *prev = mDNSNULL;
2005
2006 for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next)
2007 {
2008 if (SameResourceRecord(&ptr->resrec, &rr->resrec))
2009 {
2010 if (prev) prev->next = ptr->next;
2011 else question->uDNS_info.knownAnswers = ptr->next;
2012 ufree(ptr);
2013 return;
2014 }
2015 prev = ptr;
2016 }
2017 LogMsg("removeKnownAnswer() called for record not in KA list");
2018 }
2019
2020
2021 mDNSlocal void addKnownAnswer(DNSQuestion *question, const CacheRecord *rr)
2022 {
2023 CacheRecord *newCR = mDNSNULL;
2024 mDNSu32 size;
2025
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;
2035 }
2036
2037 mDNSlocal void deriveGoodbyes(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question)
2038 {
2039 const mDNSu8 *ptr;
2040 int i;
2041 CacheRecord *fptr, *ka, *cr, *answers = mDNSNULL, *prev = mDNSNULL;
2042 LargeCacheRecord *lcr;
2043
2044 if (question != m->uDNS_info.CurrentQuery) { LogMsg("ERROR: deriveGoodbyes called without CurrentQuery set!"); return; }
2045
2046 ptr = LocateAnswers(msg, end);
2047 if (!ptr) goto pkt_error;
2048
2049 if (!msg->h.numAnswers)
2050 {
2051 // delete the whole KA list
2052 ka = question->uDNS_info.knownAnswers;
2053 while (ka)
2054 {
2055 debugf("deriving goodbye for %##s", ka->resrec.name->c);
2056
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)
2064 {
2065 debugf("deriveGoodbyes - question removed via callback. returning.");
2066 return;
2067 }
2068 fptr = ka;
2069 ka = ka->next;
2070 ufree(fptr);
2071 }
2072 question->uDNS_info.knownAnswers = mDNSNULL;
2073 return;
2074 }
2075
2076 // make a list of all the new answers
2077 for (i = 0; i < msg->h.numAnswers; i++)
2078 {
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;
2084 cr = &lcr->r;
2085 if (ResourceRecordAnswersQuestion(&cr->resrec, question))
2086 {
2087 cr->next = answers;
2088 answers = cr;
2089 }
2090 else ufree(cr);
2091 }
2092
2093 // make sure every known answer is in the answer list
2094 ka = question->uDNS_info.knownAnswers;
2095 while (ka)
2096 {
2097 for (cr = answers; cr; cr = cr->next)
2098 { if (SameResourceRecord(&ka->resrec, &cr->resrec)) break; }
2099 if (!cr)
2100 {
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)
2112 {
2113 debugf("deriveGoodbyes - question removed via callback. returning.");
2114 return;
2115 }
2116 fptr = ka;
2117 ka = ka->next;
2118 ufree(fptr);
2119 }
2120 else
2121 {
2122 prev = ka;
2123 ka = ka->next;
2124 }
2125 }
2126
2127 // free temp answers list
2128 cr = answers;
2129 while (cr) { fptr = cr; cr = cr->next; ufree(fptr); }
2130
2131 return;
2132
2133 pkt_error:
2134 LogMsg("ERROR: deriveGoodbyes - received malformed response to query for %##s (%d)",
2135 question->qname.c, question->qtype);
2136 return;
2137
2138 malloc_error:
2139 LogMsg("ERROR: Malloc");
2140 }
2141
2142 mDNSlocal void pktResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, mDNSBool llq)
2143 {
2144 const mDNSu8 *ptr;
2145 int i;
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;
2152 origname.c[0] = 0;
2153
2154 if (question != m->uDNS_info.CurrentQuery)
2155 { LogMsg("ERROR: pktResponseHdnlr called without CurrentQuery ptr set!"); return; }
2156
2157 if (question->uDNS_info.Answered == 0 && msg->h.numAnswers == 0 && !llq)
2158 {
2159 /* NXDOMAIN error or empty RR set - notify client */
2160 question->uDNS_info.Answered = mDNStrue;
2161
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;
2175
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)
2185 {
2186 debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning.");
2187 return;
2188 }
2189 }
2190
2191 question->uDNS_info.Answered = mDNStrue;
2192
2193 ptr = LocateAnswers(msg, end);
2194 if (!ptr) goto pkt_error;
2195
2196 for (i = 0; i < msg->h.numAnswers; i++)
2197 {
2198 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &m->rec);
2199 if (!ptr) goto pkt_error;
2200 if (ResourceRecordAnswersQuestion(&cr->resrec, question))
2201 {
2202 goodbye = llq ? ((mDNSs32)cr->resrec.rroriginalttl == -1) : mDNSfalse;
2203 if (cr->resrec.rrtype == kDNSType_CNAME)
2204 {
2205 if (followedCNames > (maxCNames - 1)) LogMsg("Error: too many CNAME referals for question %##s", &origname);
2206 else
2207 {
2208 debugf("Following cname %##s -> %##s", question->qname.c, cr->resrec.rdata->u.name.c);
2209 if (question->ReturnCNAME)
2210 {
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)
2218 {
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.");
2221 return;
2222 }
2223 }
2224 AssignDomainName(&origname, &question->qname);
2225 AssignDomainName(&question->qname, &cr->resrec.rdata->u.name);
2226 question->qnamehash = DomainNameHashValue(&question->qname);
2227 followedCNames++;
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
2231 continue;
2232 }
2233 }
2234
2235 inKAList = kaListContainsAnswer(question, cr);
2236
2237 if ((goodbye && !inKAList) || (!goodbye && inKAList))
2238 {
2239 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
2240 continue; // list up to date
2241 }
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)
2248 {
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");
2251 return;
2252 }
2253 }
2254
2255 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
2256 }
2257
2258 if (!llq || llqInfo->state == LLQ_Poll || llqInfo->deriveRemovesOnResume)
2259 {
2260 deriveGoodbyes(m, msg, end,question);
2261 if (llq && llqInfo->deriveRemovesOnResume) llqInfo->deriveRemovesOnResume = mDNSfalse;
2262 }
2263
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;
2270 return;
2271
2272 pkt_error:
2273 LogMsg("ERROR: pktResponseHndlr - received malformed response to query for %##s (%d)",
2274 question->qname.c, question->qtype);
2275 return;
2276 }
2277
2278 mDNSlocal void simpleResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *context)
2279 {
2280 (void)context; // unused
2281 pktResponseHndlr(m, msg, end, question, mDNSfalse);
2282 }
2283
2284 mDNSlocal void llqResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *context)
2285 {
2286 (void)context; // unused
2287 pktResponseHndlr(m, msg, end, question, mDNStrue);
2288 }
2289
2290 mDNSlocal mStatus ParseTSIGError(mDNS *m, const DNSMessage *msg, const mDNSu8 *end, const domainname *displayname)
2291 {
2292 LargeCacheRecord lcr;
2293 const mDNSu8 *ptr;
2294 mStatus err = mStatus_NoError;
2295 int i;
2296
2297 ptr = LocateAdditionals(msg, end);
2298 if (!ptr) goto finish;
2299
2300 for (i = 0; i < msg->h.numAdditionals; i++)
2301 {
2302 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
2303 if (!ptr) goto finish;
2304 if (lcr.r.resrec.rrtype == kDNSType_TSIG)
2305 {
2306 mDNSu32 macsize;
2307 mDNSu8 *rd = lcr.r.resrec.rdata->u.data;
2308 mDNSu8 *rdend = rd + MaximumRDSize;
2309 int alglen = DomainNameLength(&lcr.r.resrec.rdata->u.name);
2310
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;
2321 rd += macsize;
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
2326
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; }
2331 goto finish;
2332 }
2333 }
2334
2335 finish:
2336 return err;
2337 }
2338
2339 mDNSlocal mStatus checkUpdateResult(domainname *displayname, mDNSu8 rcode, mDNS *m, const DNSMessage *msg, const mDNSu8 *end)
2340 {
2341 (void)msg; // currently unused, needed for TSIG errors
2342 if (!rcode) return mStatus_NoError;
2343 else if (rcode == kDNSFlag1_RC_YXDomain)
2344 {
2345 debugf("name in use: %##s", displayname->c);
2346 return mStatus_NameConflict;
2347 }
2348 else if (rcode == kDNSFlag1_RC_Refused)
2349 {
2350 LogMsg("Update %##s refused", displayname->c);
2351 return mStatus_Refused;
2352 }
2353 else if (rcode == kDNSFlag1_RC_NXRRSet)
2354 {
2355 LogMsg("Reregister refused (NXRRSET): %##s", displayname->c);
2356 return mStatus_NoSuchRecord;
2357 }
2358 else if (rcode == kDNSFlag1_RC_NotAuth)
2359 {
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);
2362 if (!tsigerr)
2363 {
2364 LogMsg("Permission denied (NOAUTH): %##s", displayname->c);
2365 return mStatus_UnknownErr;
2366 }
2367 else return tsigerr;
2368 }
2369 else if (rcode == kDNSFlag1_RC_FmtErr)
2370 {
2371 mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
2372 if (!tsigerr)
2373 {
2374 LogMsg("Format Error: %##s", displayname->c);
2375 return mStatus_UnknownErr;
2376 }
2377 else return tsigerr;
2378 }
2379 else
2380 {
2381 LogMsg("Update %##s failed with rcode %d", displayname->c, rcode);
2382 return mStatus_UnknownErr;
2383 }
2384 }
2385
2386 mDNSlocal void hndlServiceUpdateReply(mDNS * const m, ServiceRecordSet *srs, mStatus err)
2387 {
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)
2395 {
2396 case regState_Pending:
2397 if (err == mStatus_NameConflict && !info->TestForSelfConflict)
2398 {
2399 info->TestForSelfConflict = mDNStrue;
2400 debugf("checking for self-conflict of service %##s", srs->RR_SRV.resrec.name->c);
2401 SendServiceRegistration(m, srs);
2402 return;
2403 }
2404 else if (info->TestForSelfConflict)
2405 {
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;
2411 break;
2412 }
2413 else if (err == mStatus_UnknownErr && info->lease)
2414 {
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);
2418 return;
2419 }
2420 else
2421 {
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;
2425 break;
2426 }
2427 case regState_Refresh:
2428 if (err)
2429 {
2430 LogMsg("Error %ld for refresh of service %##s", err, srs->RR_SRV.resrec.name->c);
2431 InvokeCallback = mDNStrue;
2432 info->state = regState_Unregistered;
2433 }
2434 else info->state = regState_Registered;
2435 break;
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)
2439 {
2440 info->state = regState_NoTarget; // NoTarget will allow us to pick up new target OR nat traversal state
2441 break;
2442 }
2443 err = mStatus_MemFree;
2444 InvokeCallback = mDNStrue;
2445 if (nat)
2446 {
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
2449 }
2450 info->state = regState_Unregistered;
2451 break;
2452 case regState_DeregDeferred:
2453 if (err)
2454 {
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;
2459 break;
2460 }
2461 else
2462 {
2463 debugf("Performing deferred deregistration of %##s", srs->RR_SRV.resrec.name->c);
2464 info->state = regState_Registered;
2465 SendServiceDeregistration(m, srs);
2466 return;
2467 }
2468 case regState_UpdatePending:
2469 if (err)
2470 {
2471 LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs->RR_SRV.resrec.name->c);
2472 info->state = regState_Unregistered;
2473 InvokeCallback = mDNStrue;
2474 }
2475 else
2476 {
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;
2483 }
2484 break;
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;
2496 }
2497
2498 if ((info->SRVChanged || info->SRVUpdateDeferred) && (info->state == regState_NoTarget || info->state == regState_Registered))
2499 {
2500 if (InvokeCallback)
2501 {
2502 info->ClientCallbackDeferred = mDNStrue;
2503 info->DeferredStatus = err;
2504 }
2505 info->SRVChanged = mDNSfalse;
2506 UpdateSRV(m, srs);
2507 return;
2508 }
2509
2510 while (*e)
2511 {
2512 uDNS_RegInfo *einfo = &(*e)->r.uDNS_info;
2513 if (einfo->state == regState_ExtraQueued)
2514 {
2515 if (info->state == regState_Registered && !err)
2516 {
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);
2523 e = &(*e)->next;
2524 }
2525 else if (err && einfo->state != regState_Unregistered)
2526 {
2527 // unlink extra from list
2528 einfo->state = regState_Unregistered;
2529 *e = (*e)->next;
2530 }
2531 else e = &(*e)->next;
2532 }
2533 else e = &(*e)->next;
2534 }
2535
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)
2539 {
2540 if (InvokeCallback)
2541 {
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;
2545 }
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);
2553 return;
2554 }
2555
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)
2559 {
2560 info->ClientCallbackDeferred = mDNSfalse;
2561 srs->ServiceCallback(m, srs, info->DeferredStatus);
2562 }
2563 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2564 // NOTE: do not touch structures after calling ServiceCallback
2565 }
2566
2567 mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
2568 {
2569 uDNS_RegInfo *info = &rr->uDNS_info;
2570 mDNSBool InvokeCallback = mDNStrue;
2571
2572 if (info->state == regState_UpdatePending)
2573 {
2574 if (err)
2575 {
2576 LogMsg("Update record failed for %##s (err %d)", rr->resrec.name->c, err);
2577 info->state = regState_Unregistered;
2578 }
2579 else
2580 {
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;
2588 }
2589 }
2590
2591 if (info->state == regState_DeregPending)
2592 {
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;
2598 }
2599
2600 if (info->state == regState_DeregDeferred)
2601 {
2602 if (err)
2603 {
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;
2607 }
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);
2611 return;
2612 }
2613
2614 if (info->state == regState_Pending || info->state == regState_Refresh)
2615 {
2616 if (!err)
2617 {
2618 info->state = regState_Registered;
2619 if (info->state == regState_Refresh) InvokeCallback = mDNSfalse;
2620 }
2621 else
2622 {
2623 if (info->lease && err == mStatus_UnknownErr)
2624 {
2625 LogMsg("Re-trying update of record %##s without lease option", rr->resrec.name->c);
2626 info->lease = mDNSfalse;
2627 sendRecordRegistration(m, rr);
2628 return;
2629 }
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;
2632 }
2633 }
2634
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.
2637
2638 if (info->QueuedRData && info->state == regState_Registered)
2639 {
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);
2647 return;
2648 }
2649
2650 if (InvokeCallback)
2651 {
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
2655 }
2656 }
2657
2658
2659 mDNSlocal void SetUpdateExpiration(mDNS *m, DNSMessage *msg, const mDNSu8 *end, uDNS_RegInfo *info)
2660 {
2661 LargeCacheRecord lcr;
2662 const mDNSu8 *ptr;
2663 int i;
2664 mDNSu32 lease = 0;
2665 mDNSs32 expire;
2666
2667 ptr = LocateAdditionals(msg, end);
2668
2669 if (info->lease && (ptr = LocateAdditionals(msg, end)))
2670 {
2671 for (i = 0; i < msg->h.numAdditionals; i++)
2672 {
2673 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
2674 if (!ptr) break;
2675 if (lcr.r.resrec.rrtype == kDNSType_OPT)
2676 {
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;
2680 break;
2681 }
2682 }
2683 }
2684
2685 if (lease > 0)
2686 {
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;
2692 }
2693 else info->lease = mDNSfalse;
2694 }
2695
2696 mDNSexport void uDNS_ReceiveNATMap(mDNS *m, mDNSu8 *pkt, mDNSu16 len)
2697 {
2698 uDNS_GlobalInfo *u = &m->uDNS_info;
2699 NATTraversalInfo *ptr = u->NATTraversals;
2700 NATOp_t op;
2701
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; }
2705 op = pkt[1];
2706 if (!(op & NATMAP_RESPONSE_MASK)) { LogMsg("Received NAT Traversal message that is not a response (opcode %d)", op); return; }
2707
2708 while (ptr)
2709 {
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
2712 ptr = ptr->next;
2713 }
2714 }
2715
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";
2719
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)
2723 {
2724 const mDNSu8 *ptr = msg->data;
2725 DNSQuestion q;
2726 DNSServer *s;
2727 mDNSu32 result = 0;
2728 mDNSBool found = mDNSfalse;
2729
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);
2736
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;
2741 else
2742 result = DNSServer_Passed;
2743
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; }
2748
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);
2753
2754 return(mDNStrue); // Return mDNStrue to tell uDNS_ReceiveMsg it doens't need to process this packet further
2755 }
2756
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)
2760 {
2761 DNSQuestion *qptr;
2762 AuthRecord *rptr;
2763 ServiceRecordSet *sptr;
2764 mStatus err = mStatus_NoError;
2765 uDNS_GlobalInfo *u = &m->uDNS_info;
2766
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);
2771
2772 mDNSs32 timenow = mDNSPlatformTimeNow(m);
2773
2774 // unused
2775 (void)dstaddr;
2776 (void)dstport;
2777 (void)InterfaceID;
2778
2779 if (QR_OP == StdR)
2780 {
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;
2784
2785 if (uDNS_ReceiveTestQuestionResponse(m, msg, end, srcaddr, InterfaceID)) return;
2786
2787 for (qptr = u->ActiveQueries; qptr; qptr = qptr->next)
2788 {
2789 //!!!KRS we should have a hashtable, hashed on message id
2790 if (qptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
2791 {
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; }
2796 else
2797 {
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
2802 return;
2803 }
2804 }
2805 }
2806 }
2807 if (QR_OP == UpdateR)
2808 {
2809 for (sptr = u->ServiceRegistrations; sptr; sptr = sptr->next)
2810 {
2811 if (sptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
2812 {
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);
2816 return;
2817 }
2818 }
2819 for (rptr = u->RecordRegistrations; rptr; rptr = rptr->next)
2820 {
2821 if (rptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
2822 {
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);
2826 return;
2827 }
2828 }
2829 }
2830 debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg->h.id));
2831 }
2832
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)
2835 {
2836 DNSServer *curmatch = mDNSNULL, *p = u->Servers;
2837 int i, curmatchlen = -1;
2838 int ncount = name ? CountLabels(name) : 0;
2839
2840 while (p)
2841 {
2842 int scount = CountLabels(&p->domain);
2843 if (scount <= ncount && scount > curmatchlen)
2844 {
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; }
2850 }
2851 p = p->next;
2852 }
2853 return(curmatch);
2854 }
2855
2856 // ***************************************************************************
2857 #if COMPILER_LIKES_PRAGMA_MARK
2858 #pragma mark - Query Routines
2859 #endif
2860
2861 #define sameID(x,y) mDNSPlatformMemSame(x,y,8)
2862
2863 mDNSlocal void initializeQuery(DNSMessage *msg, DNSQuestion *question)
2864 {
2865 ubzero(msg, sizeof(msg));
2866 InitializeDNSMessage(&msg->h, question->uDNS_info.id, uQueryFlags);
2867 }
2868
2869 mDNSlocal mStatus constructQueryMsg(DNSMessage *msg, mDNSu8 **endPtr, DNSQuestion *const question)
2870 {
2871 initializeQuery(msg, question);
2872
2873 *endPtr = putQuestion(msg, msg->data, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
2874 if (!*endPtr)
2875 {
2876 LogMsg("ERROR: Unicast query out of space in packet");
2877 return mStatus_UnknownErr;
2878 }
2879 return mStatus_NoError;
2880 }
2881
2882 mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, DNSQuestion *question, LLQOptData *data, mDNSBool includeQuestion)
2883 {
2884 AuthRecord rr;
2885 ResourceRecord *opt = &rr.resrec;
2886 rdataOpt *optRD;
2887
2888 //!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section
2889 if (includeQuestion)
2890 {
2891 ptr = putQuestion(msg, ptr, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
2892 if (!ptr) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL; }
2893 }
2894 // locate OptRR if it exists, set pointer to end
2895 // !!!KRS implement me
2896
2897
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;
2903
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; }
2910
2911 return ptr;
2912 }
2913
2914
2915 mDNSlocal mDNSBool getLLQAtIndex(mDNS *m, DNSMessage *msg, const mDNSu8 *end, LLQOptData *llq, int index)
2916 {
2917 LargeCacheRecord lcr;
2918 int i;
2919 const mDNSu8 *ptr;
2920
2921 ubzero(&lcr, sizeof(lcr));
2922
2923 ptr = LocateAdditionals(msg, end);
2924 if (!ptr) return mDNSfalse;
2925
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));
2934 return mDNStrue;
2935 }
2936
2937 mDNSlocal void recvRefreshReply(mDNS *m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *q)
2938 {
2939 LLQ_Info *qInfo;
2940 LLQOptData pktData;
2941
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; }
2947
2948 qInfo->expire = mDNSPlatformTimeNow(m) + ((mDNSs32)pktData.lease * mDNSPlatformOneSecond);
2949 qInfo->retry = qInfo->expire - ((mDNSs32)pktData.lease * mDNSPlatformOneSecond/2);
2950
2951 qInfo->origLease = pktData.lease;
2952 qInfo->state = LLQ_Established;
2953 }
2954
2955 mDNSlocal void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease)
2956 {
2957 DNSMessage msg;
2958 mDNSu8 *end;
2959 LLQOptData llq;
2960 LLQ_Info *info = q->uDNS_info.llq;
2961 mStatus err;
2962 mDNSs32 timenow;
2963
2964 timenow = mDNSPlatformTimeNow(m);
2965 if ((info->state == LLQ_Refresh && info->ntries >= kLLQ_MAX_TRIES) ||
2966 info->expire - timenow < 0)
2967 {
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;
2972 return;
2973 //!!!KRS handle this - periodically try to re-establish
2974 }
2975
2976 llq.vers = kLLQ_Vers;
2977 llq.llqOp = kLLQOp_Refresh;
2978 llq.err = LLQErr_NoError;
2979 umemcpy(llq.id, info->id, 8);
2980 llq.lease = lease;
2981
2982 initializeQuery(&msg, q);
2983 end = putLLQ(&msg, msg.data, q, &llq, mDNStrue);
2984 if (!end) { LogMsg("ERROR: sendLLQRefresh - putLLQ"); return; }
2985
2986 err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL);
2987 if (err) debugf("ERROR: sendLLQRefresh - mDNSSendDNSMessage returned %ld", err);
2988
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;
2994 }
2995
2996 mDNSlocal mDNSBool recvLLQEvent(mDNS *m, DNSQuestion *q, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, mDNSInterfaceID InterfaceID)
2997 {
2998 DNSMessage ack;
2999 mDNSu8 *ackEnd = ack.data;
3000 mStatus err;
3001 LLQOptData opt;
3002
3003 (void)InterfaceID; // unused
3004
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; }
3010
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;
3015
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);
3022 return mDNStrue;
3023 }
3024
3025
3026
3027 mDNSlocal void hndlChallengeResponseAck(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q)
3028 {
3029 LLQ_Info *info = q->uDNS_info.llq;
3030
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);
3035
3036 info->origLease = llq->lease;
3037 info->state = LLQ_Established;
3038
3039 q->uDNS_info.responseCallback = llqResponseHndlr;
3040 llqResponseHndlr(m, pktMsg, end, q, mDNSNULL);
3041 return;
3042
3043 error:
3044 info->state = LLQ_Error;
3045 }
3046
3047 mDNSlocal void sendChallengeResponse(mDNS *m, DNSQuestion *q, LLQOptData *llq)
3048 {
3049 LLQ_Info *info = q->uDNS_info.llq;
3050 DNSMessage response;
3051 mDNSu8 *responsePtr = response.data;
3052 mStatus err;
3053 LLQOptData llqBuf;
3054 mDNSs32 timenow = mDNSPlatformTimeNow(m);
3055
3056 if (info->ntries++ == kLLQ_MAX_TRIES)
3057 {
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?
3063 return;
3064 }
3065
3066 if (!llq)
3067 {
3068 llq = &llqBuf;
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;
3074 }
3075
3076 q->LastQTime = timenow;
3077 info->retry = timenow + (kLLQ_INIT_RESEND * info->ntries * mDNSPlatformOneSecond);
3078
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; }
3082
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
3086
3087 return;
3088
3089 error:
3090 info->state = LLQ_Error;
3091 }
3092
3093
3094
3095 mDNSlocal void hndlRequestChallenge(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q)
3096 {
3097 LLQ_Info *info = q->uDNS_info.llq;
3098 mDNSs32 timenow = mDNSPlatformTimeNow(m);
3099 switch(llq->err)
3100 {
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;
3108 case LLQErr_Static:
3109 info->state = LLQ_Static;
3110 LogMsg("LLQ %##s: static", q->qname.c);
3111 simpleResponseHndlr(m, pktMsg, end, q, mDNSNULL);
3112 return;
3113 case LLQErr_FormErr:
3114 LogMsg("ERROR: hndlRequestChallenge - received FormErr from server for LLQ %##s", q->qname.c);
3115 goto error;
3116 case LLQErr_BadVers:
3117 LogMsg("ERROR: hndlRequestChallenge - received BadVers from server");
3118 goto error;
3119 case LLQErr_UnknownErr:
3120 LogMsg("ERROR: hndlRequestChallenge - received UnknownErr from server for LLQ %##s", q->qname.c);
3121 goto error;
3122 default:
3123 LogMsg("ERROR: hndlRequestChallenge - received invalid error %d for LLQ %##s", llq->err, q->qname.c);
3124 goto error;
3125 }
3126
3127 if (info->origLease != llq->lease)
3128 debugf("hndlRequestChallenge: requested lease %lu, granted lease %lu", info->origLease, llq->lease);
3129
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);
3133
3134 // update state
3135 info->state = LLQ_SecondaryRequest;
3136 umemcpy(info->id, llq->id, 8);
3137 info->ntries = 0; // first attempt to send response
3138
3139 sendChallengeResponse(m, q, llq);
3140 return;
3141
3142
3143 error:
3144 info->state = LLQ_Error;
3145 }
3146
3147
3148 // response handler for initial and secondary setup responses
3149 mDNSlocal void recvSetupResponse(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, DNSQuestion *q, void *clientContext)
3150 {
3151 DNSQuestion pktQuestion;
3152 LLQOptData llq;
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);
3156
3157 (void)clientContext; // unused
3158
3159 if (rcode && rcode != kDNSFlag1_RC_NXDomain) goto poll;
3160
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; }
3165
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; }
3169
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);
3173
3174 poll:
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;
3179 }
3180
3181 mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer)
3182 {
3183 DNSMessage msg;
3184 mDNSu8 *end;
3185 LLQOptData llqData;
3186 DNSQuestion *q = info->question;
3187 mStatus err = mStatus_NoError;
3188 mDNSs32 timenow = mDNSPlatformTimeNow(m);
3189 uDNS_GlobalInfo *u = &m->uDNS_info;
3190
3191 if (IsPrivateV4Addr(&u->AdvertisedV4))
3192 {
3193 if (!u->LLQNatInfo)
3194 {
3195 info->state = LLQ_NatMapWait;
3196 StartLLQNatMap(m);
3197 return;
3198 }
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
3203 }
3204
3205 if (info->ntries++ >= kLLQ_MAX_TRIES)
3206 {
3207 debugf("startLLQHandshake: %d failed attempts for LLQ %##s. Polling.", kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60);
3208 goto poll;
3209 }
3210
3211 // set llq rdata
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;
3217
3218 initializeQuery(&msg, q);
3219 end = putLLQ(&msg, msg.data, q, &llqData, mDNStrue);
3220 if (!end)
3221 {
3222 LogMsg("ERROR: startLLQHandshake - putLLQ");
3223 info->state = LLQ_Error;
3224 return;
3225 }
3226
3227 if (!defer) // if we are to defer, we simply set the retry timers so the request goes out in the future
3228 {
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
3232 }
3233
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;
3241 return;
3242
3243 poll:
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;
3248 }
3249
3250 // wrapper for startLLQHandshake, invoked by async op callback
3251 mDNSlocal void startLLQHandshakeCallback(mStatus err, mDNS *const m, void *llqInfo, const AsyncOpResult *result)
3252 {
3253 LLQ_Info *info = (LLQ_Info *)llqInfo;
3254 const zoneData_t *zoneInfo = mDNSNULL;
3255
3256 // check state first to make sure it is OK to touch question object
3257 if (info->state == LLQ_Cancelled)
3258 {
3259 // StopQuery was called while we were getting the zone info
3260 debugf("startLLQHandshake - LLQ Cancelled.");
3261 info->question = mDNSNULL; // question may be deallocated
3262 ufree(info);
3263 return;
3264 }
3265
3266 if (!info->question)
3267 { LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL question"); goto error; }
3268
3269 if (info->state != LLQ_GetZoneInfo)
3270 { LogMsg("ERROR: startLLQHandshake - bad state %d", info->state); goto error; }
3271
3272 if (err)
3273 { LogMsg("ERROR: startLLQHandshakeCallback %##s invoked with error code %ld", info->question->qname.c, err); goto poll; }
3274
3275 if (!result)
3276 { LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL result and no error code"); goto error; }
3277
3278 zoneInfo = &result->zoneData;
3279
3280 if (!zoneInfo->llqPort.NotAnInteger)
3281 { debugf("LLQ port lookup failed - reverting to polling"); info->servPort.NotAnInteger = 0; goto poll; }
3282
3283 // cache necessary zone data
3284 info->servAddr = zoneInfo->primaryAddr;
3285 info->servPort = zoneInfo->llqPort;
3286 info->ntries = 0;
3287
3288 if (info->state == LLQ_SuspendDeferred) info->state = LLQ_Suspended;
3289 else startLLQHandshake(m, info, mDNSfalse);
3290 return;
3291
3292 poll:
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;
3297 return;
3298
3299 error:
3300 info->state = LLQ_Error;
3301 }
3302
3303 mDNSlocal mStatus startLLQ(mDNS *m, DNSQuestion *question)
3304 {
3305 LLQ_Info *info;
3306 mStatus err = mStatus_NoError;
3307
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;
3313
3314 // link info/question
3315 info->question = question;
3316 question->uDNS_info.llq = info;
3317
3318 question->uDNS_info.responseCallback = llqResponseHndlr;
3319
3320 err = startGetZoneData(&question->qname, m, mDNSfalse, mDNStrue, startLLQHandshakeCallback, info);
3321 if (err)
3322 {
3323 LogMsg("ERROR: startLLQ - startGetZoneData returned %ld", err);
3324 info->question = mDNSNULL;
3325 ufree(info);
3326 question->uDNS_info.llq = mDNSNULL;
3327 return err;
3328 }
3329
3330 LinkActiveQuestion(&m->uDNS_info, question);
3331 return err;
3332 }
3333
3334 mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID)
3335 {
3336 DNSQuestion pktQ, *q;
3337 uDNS_GlobalInfo *u = &m->uDNS_info;
3338 const mDNSu8 *ptr = msg->data;
3339 LLQ_Info *llqInfo;
3340
3341 if (!msg->h.numQuestions) return mDNSfalse;
3342
3343 ptr = getQuestion(msg, ptr, end, 0, &pktQ);
3344 if (!ptr) return mDNSfalse;
3345 pktQ.uDNS_info.id = msg->h.id;
3346
3347 q = u->ActiveQueries;
3348 while (q)
3349 {
3350 llqInfo = q->uDNS_info.llq;
3351 if (q->LongLived &&
3352 llqInfo &&
3353 q->qnamehash == pktQ.qnamehash &&
3354 q->qtype == pktQ.qtype &&
3355 SameDomainName(&q->qname, &pktQ.qname))
3356 {
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)
3361 {
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)
3365 {
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; }
3368 }
3369 }
3370 }
3371 q = q->next;
3372 }
3373 return mDNSfalse;
3374 }
3375
3376 mDNSexport mDNSBool uDNS_IsActiveQuery(DNSQuestion *const question, uDNS_GlobalInfo *u)
3377 {
3378 DNSQuestion *q;
3379
3380 for (q = u->ActiveQueries; q; q = q->next)
3381 {
3382 if (q == question)
3383 {
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);
3387 return mDNStrue;
3388 }
3389 }
3390 return mDNSfalse;
3391 }
3392
3393 // stopLLQ happens IN ADDITION to stopQuery
3394 mDNSlocal void stopLLQ(mDNS *m, DNSQuestion *question)
3395 {
3396 LLQ_Info *info = question->uDNS_info.llq;
3397 (void)m; // unused
3398
3399 if (!question->LongLived) { LogMsg("ERROR: stopLLQ - LongLived flag not set"); return; }
3400 if (!info) { LogMsg("ERROR: stopLLQ - llq info is NULL"); return; }
3401
3402 switch (info->state)
3403 {
3404 case LLQ_UnInit:
3405 LogMsg("ERROR: stopLLQ - state LLQ_UnInit");
3406 //!!!KRS should we unlink info<->question here?
3407 return;
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;
3412 return;
3413 case LLQ_Established:
3414 case LLQ_Refresh:
3415 // refresh w/ lease 0
3416 sendLLQRefresh(m, question, 0);
3417 goto end;
3418 default:
3419 debugf("stopLLQ - silently discarding LLQ in state %d", info->state);
3420 goto end;
3421 }
3422
3423 end:
3424 if (info->NATMap) info->NATMap = mDNSfalse;
3425 CheckForUnreferencedLLQMapping(m);
3426 info->question = mDNSNULL;
3427 ufree(info);
3428 question->uDNS_info.llq = mDNSNULL;
3429 question->LongLived = mDNSfalse;
3430 }
3431
3432 mDNSexport mStatus uDNS_StopQuery(mDNS *const m, DNSQuestion *const question)
3433 {
3434 uDNS_GlobalInfo *u = &m->uDNS_info;
3435 DNSQuestion *qptr, *prev = mDNSNULL;
3436 CacheRecord *ka;
3437
3438 qptr = u->ActiveQueries;
3439 while (qptr)
3440 {
3441 if (qptr == question)
3442 {
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)
3448 {
3449 ka = question->uDNS_info.knownAnswers;
3450 question->uDNS_info.knownAnswers = question->uDNS_info.knownAnswers->next;
3451 ufree(ka);
3452 }
3453 if (prev) prev->next = question->next;
3454 else u->ActiveQueries = question->next;
3455 return mStatus_NoError;
3456 }
3457 prev = qptr;
3458 qptr = qptr->next;
3459 }
3460 LogMsg("uDNS_StopQuery: no such active query (%##s)", question->qname.c);
3461 return mStatus_UnknownErr;
3462 }
3463
3464 mDNSlocal mStatus startQuery(mDNS *const m, DNSQuestion *const question, mDNSBool internal)
3465 {
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))
3469 {
3470 LogMsg("Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
3471 return mStatus_Invalid;
3472 }
3473
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;
3478
3479 // break here if its and LLQ
3480 if (question->LongLived) return startLLQ(m, question);
3481
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));
3489
3490 return mStatus_NoError;
3491 }
3492
3493 mDNSexport mStatus uDNS_StartQuery(mDNS *const m, DNSQuestion *const question)
3494 {
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);
3500 }
3501
3502 // explicitly set response handler
3503 mDNSlocal mStatus startInternalQuery(DNSQuestion *q, mDNS *m, InternalResponseHndlr callback, void *hndlrContext)
3504 {
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);
3510 }
3511
3512
3513
3514 // ***************************************************************************
3515 #if COMPILER_LIKES_PRAGMA_MARK
3516 #pragma mark - Domain -> Name Server Conversion
3517 #endif
3518
3519
3520 /* startGetZoneData
3521 *
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.
3527 *
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.
3533 *
3534 * Steps for deriving the zone name are as follows:
3535 *
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.
3538 *
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.
3541 *
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.)
3546 *
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.)
3549 */
3550
3551
3552 // state machine types and structs
3553 //
3554
3555 // state machine states
3556 typedef enum
3557 {
3558 init,
3559 lookupSOA,
3560 foundZone,
3561 lookupNS,
3562 foundNS,
3563 lookupA,
3564 foundA,
3565 lookupPort,
3566 foundPort,
3567 complete
3568 } ntaState;
3569
3570 // state machine actions
3571 typedef enum
3572 {
3573 smContinue, // continue immediately to next state
3574 smBreak, // break until next packet/timeout
3575 smError // terminal error - cleanup and abort
3576 } smAction;
3577
3578 typedef struct
3579 {
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
3583 mDNS *m;
3584 domainname zone; // left-hand-side of SOA record
3585 mDNSu16 zoneClass;
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;
3594 mDNSIPPort llqPort;
3595 AsyncOpCallback *callback; // caller specified function to be called upon completion
3596 void *callbackInfo;
3597 } ntaContext;
3598
3599
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);
3608
3609 // initialization
3610 mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdatePort, mDNSBool findLLQPort,
3611 AsyncOpCallback callback, void *callbackInfo)
3612 {
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;
3618 context->m = m;
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;
3625 }
3626
3627 // state machine entry routine
3628 mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *contextPtr)
3629 {
3630 AsyncOpResult result;
3631 ntaContext *context = (ntaContext*)contextPtr;
3632 smAction action;
3633
3634 // unused
3635 (void)m;
3636 (void)question;
3637
3638 // stop any active question
3639 if (context->questionActive)
3640 {
3641 uDNS_StopQuery(context->m, &context->question);
3642 context->questionActive = mDNSfalse;
3643 }
3644
3645 if (msg && msg->h.flags.b[2] >> 4 && msg->h.flags.b[2] >> 4 != kDNSFlag1_RC_NXDomain)
3646 {
3647 // rcode non-zero, non-nxdomain
3648 LogMsg("ERROR: getZoneData - received response w/ rcode %d", msg->h.flags.b[2] >> 4);
3649 goto error;
3650 }
3651
3652 switch (context->state)
3653 {
3654 case init:
3655 case lookupSOA:
3656 action = hndlLookupSOA(msg, end, context);
3657 if (action == smError) goto error;
3658 if (action == smBreak) return;
3659 case foundZone:
3660 case lookupNS:
3661 action = confirmNS(msg, end, context);
3662 if (action == smError) goto error;
3663 if (action == smBreak) return;
3664 case foundNS:
3665 case lookupA:
3666 action = lookupNSAddr(msg, end, context);
3667 if (action == smError) goto error;
3668 if (action == smBreak) return;
3669 case foundA:
3670 if (!context->findUpdatePort && !context->findLLQPort)
3671 {
3672 context->state = complete;
3673 break;
3674 }
3675 case lookupPort:
3676 action = hndlLookupPorts(msg, end, context);
3677 if (action == smError) goto error;
3678 if (action == smBreak) return;
3679 if (action == smContinue) context->state = complete;
3680 case foundPort:
3681 case complete: break;
3682 }
3683
3684 if (context->state != complete)
3685 {
3686 LogMsg("ERROR: getZoneData - exited state machine with state %d", context->state);
3687 goto error;
3688 }
3689
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);
3698 goto cleanup;
3699
3700 error:
3701 if (context && context->callback)
3702 context->callback(mStatus_UnknownErr, context->m, context->callbackInfo, mDNSNULL);
3703 cleanup:
3704 if (context && context->questionActive)
3705 {
3706 uDNS_StopQuery(context->m, &context->question);
3707 context->questionActive = mDNSfalse;
3708 }
3709 if (context) ufree(context);
3710 }
3711
3712 mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
3713 {
3714 mStatus err;
3715 LargeCacheRecord lcr;
3716 ResourceRecord *rr = &lcr.r.resrec;
3717 DNSQuestion *query = &context->question;
3718 const mDNSu8 *ptr;
3719
3720 if (msg)
3721 {
3722 // if msg contains SOA record in answer or authority sections, update context/state and return
3723 int i;
3724 ptr = LocateAnswers(msg, end);
3725 for (i = 0; i < msg->h.numAnswers; i++)
3726 {
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))
3730 {
3731 processSOA(context, rr);
3732 return smContinue;
3733 }
3734 }
3735 ptr = LocateAuthorities(msg, end);
3736 // SOA not in answers, check in authority
3737 for (i = 0; i < msg->h.numAuthorities; i++)
3738 {
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)
3742 {
3743 processSOA(context, rr);
3744 return smContinue;
3745 }
3746 }
3747 }
3748
3749 if (context->state != init && !context->curSOA->c[0])
3750 {
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);
3754 return smError;
3755 }
3756
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);
3761
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);
3769
3770 return smBreak; // break from state machine until we receive another packet
3771 }
3772
3773 mDNSlocal void processSOA(ntaContext *context, ResourceRecord *rr)
3774 {
3775 AssignDomainName(&context->zone, rr->name);
3776 context->zoneClass = rr->rrclass;
3777 AssignDomainName(&context->ns, &rr->rdata->u.soa.mname);
3778 context->state = foundZone;
3779 }
3780
3781
3782 mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
3783 {
3784 DNSQuestion *query = &context->question;
3785 mStatus err;
3786 LargeCacheRecord lcr;
3787 const ResourceRecord *const rr = &lcr.r.resrec;
3788 const mDNSu8 *ptr;
3789 int i;
3790
3791 if (context->state == foundZone)
3792 {
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
3802 }
3803 else if (context->state == lookupNS)
3804 {
3805 ptr = LocateAnswers(msg, end);
3806 for (i = 0; i < msg->h.numAnswers; i++)
3807 {
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))
3812 {
3813 context->state = foundNS;
3814 return smContinue; // next routine will examine additionals section of A record
3815 }
3816 }
3817 debugf("ERROR: could not confirm existence of record %##s NS %##s", context->zone.c, context->ns.c);
3818 return smError;
3819 }
3820 else { LogMsg("ERROR: confirmNS - bad state %d", context->state); return smError; }
3821 }
3822
3823 mDNSlocal smAction queryNSAddr(ntaContext *context)
3824 {
3825 mStatus err;
3826 DNSQuestion *query = &context->question;
3827
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;
3835 return smBreak;
3836 }
3837
3838 mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
3839 {
3840 const mDNSu8 *ptr;
3841 int i;
3842 LargeCacheRecord lcr;
3843 ResourceRecord *rr = &lcr.r.resrec;
3844
3845 if (context->state == foundNS)
3846 {
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);
3850 if (!ptr)
3851 {
3852 LogMsg("ERROR: lookupNSAddr - LocateAdditionals returned NULL, expected %d additionals", msg->h.numAdditionals);
3853 return queryNSAddr(context);
3854 }
3855 else
3856 {
3857 for (i = 0; i < msg->h.numAdditionals; i++)
3858 {
3859 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
3860 if (!ptr)
3861 {
3862 LogMsg("ERROR: lookupNSAddr, Additionals - GetLargeResourceRecord returned NULL");
3863 return queryNSAddr(context);
3864 }
3865 if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, rr->name))
3866 {
3867 context->addr = rr->rdata->u.ipv4;
3868 context->state = foundA;
3869 return smContinue;
3870 }
3871 }
3872 }
3873 // no A record in Additionals - query the server
3874 return queryNSAddr(context);
3875 }
3876 else if (context->state == lookupA)
3877 {
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++)
3881 {
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))
3885 {
3886 context->addr = rr->rdata->u.ipv4;
3887 context->state = foundA;
3888 return smContinue;
3889 }
3890 }
3891 LogMsg("ERROR: lookupNSAddr: Address record not found in answer section");
3892 return smError;
3893 }
3894 else { LogMsg("ERROR: lookupNSAddr - bad state %d", context->state); return smError; }
3895 }
3896
3897 mDNSlocal smAction lookupDNSPort(DNSMessage *msg, const mDNSu8 *end, ntaContext *context, char *portName, mDNSIPPort *port)
3898 {
3899 int i;
3900 LargeCacheRecord lcr;
3901 const mDNSu8 *ptr;
3902 DNSQuestion *q;
3903 mStatus err;
3904
3905 if (context->state == lookupPort) // we've already issued the query
3906 {
3907 if (!msg) { LogMsg("ERROR: hndlLookupUpdatePort - NULL message"); return smError; }
3908 ptr = LocateAnswers(msg, end);
3909 for (i = 0; i < msg->h.numAnswers; i++)
3910 {
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))
3914 {
3915 *port = lcr.r.resrec.rdata->u.srv.port;
3916 context->state = foundPort;
3917 return smContinue;
3918 }
3919 }
3920 debugf("hndlLookupUpdatePort - no answer for type %s", portName);
3921 port->NotAnInteger = 0;
3922 context->state = foundPort;
3923 return smContinue;
3924 }
3925
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
3937 }
3938
3939 mDNSlocal smAction hndlLookupPorts(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
3940 {
3941 smAction action;
3942
3943 if (context->findUpdatePort && !context->updatePort.NotAnInteger)
3944 {
3945 action = lookupDNSPort(msg, end, context, UPDATE_PORT_NAME, &context->updatePort);
3946 if (action != smContinue) return action;
3947 }
3948 if (context->findLLQPort && !context->llqPort.NotAnInteger)
3949 return lookupDNSPort(msg, end, context, LLQ_PORT_NAME, &context->llqPort);
3950
3951 return smContinue;
3952 }
3953
3954
3955 // ***************************************************************************
3956 #if COMPILER_LIKES_PRAGMA_MARK
3957 #pragma mark - Truncation Handling
3958 #endif
3959
3960 typedef struct
3961 {
3962 DNSQuestion *question;
3963 DNSMessage *reply;
3964 mDNSu16 replylen;
3965 int nread;
3966 mDNS *m;
3967 } tcpInfo_t;
3968
3969 // issue queries over a conected socket
3970 mDNSlocal void conQueryCallback(int sd, void *context, mDNSBool ConnectionEstablished)
3971 {
3972 mStatus err = 0;
3973 char msgbuf[356]; // 96 (hdr) + 256 (domain) + 4 (class/type)
3974 DNSMessage *msg;
3975 mDNSu8 *end;
3976 tcpInfo_t *info = (tcpInfo_t *)context;
3977 DNSQuestion *question = info->question;
3978 int n;
3979 mDNS *m = info->m;
3980
3981 mDNS_Lock(m);
3982
3983 if (ConnectionEstablished)
3984 {
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; }
3992 }
3993 else
3994 {
3995 if (!info->nread)
3996 {
3997 // read msg len
3998 mDNSu8 lenbuf[2];
3999 n = mDNSPlatformReadTCP(sd, lenbuf, 2);
4000 if (n != 2)
4001 {
4002 LogMsg("ERROR:conQueryCallback - attempt to read message length failed (read returned %d)", n);
4003 goto error;
4004 }
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; }
4010 }
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; }
4013 info->nread += n;
4014 if (info->nread == info->replylen)
4015 {
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);
4025 ufree(info->reply);
4026 ufree(info);
4027 }
4028 }
4029
4030 mDNS_Unlock(m);
4031 return;
4032
4033 error:
4034 mDNSPlatformTCPCloseConnection(sd);
4035 if (info->reply) ufree(info->reply);
4036 ufree(info);
4037 mDNS_Unlock(m);
4038 }
4039
4040 mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question, const mDNSAddr *src, mDNS *m)
4041 {
4042 mStatus connectionStatus;
4043 uDNS_QuestionInfo *info = &question->uDNS_info;
4044 int sd;
4045 tcpInfo_t *context;
4046
4047 if (!src) { LogMsg("hndlTruncatedAnswer: TCP DNS response had TC bit set: ignoring"); return; }
4048
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;
4053 context->m = m;
4054 info->id = newMessageID(&m->uDNS_info);
4055
4056 connectionStatus = mDNSPlatformTCPConnect(src, UnicastDNSPort, question->InterfaceID, conQueryCallback, context, &sd);
4057 if (connectionStatus == mStatus_ConnEstablished) // manually invoke callback if connection completes
4058 {
4059 conQueryCallback(sd, context, mDNStrue);
4060 return;
4061 }
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?
4065 }
4066
4067
4068 // ***************************************************************************
4069 #if COMPILER_LIKES_PRAGMA_MARK
4070 #pragma mark - Dynamic Updates
4071 #endif
4072
4073 mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr)
4074 {
4075 DNSMessage msg;
4076 mDNSu8 *ptr = msg.data;
4077 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
4078 uDNS_GlobalInfo *u = &m->uDNS_info;
4079 mDNSOpaque16 id;
4080 uDNS_RegInfo *regInfo = &rr->uDNS_info;
4081 mStatus err = mStatus_UnknownErr;
4082
4083 id = newMessageID(u);
4084 InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
4085 rr->uDNS_info.id = id;
4086
4087 // set zone
4088 ptr = putZone(&msg, ptr, end, &regInfo->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
4089 if (!ptr) goto error;
4090
4091 if (regInfo->state == regState_UpdatePending)
4092 {
4093 // delete old RData
4094 SetNewRData(&rr->resrec, regInfo->OrigRData, regInfo->OrigRDLen);
4095 if (!(ptr = putDeletionRecord(&msg, ptr, &rr->resrec))) goto error; // delete old rdata
4096
4097 // add new 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;
4100 }
4101
4102 else
4103 {
4104 if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
4105 {
4106 // KnownUnique: Delete any previous value
4107 ptr = putDeleteRRSet(&msg, ptr, rr->resrec.name, rr->resrec.rrtype);
4108 if (!ptr) goto error;
4109 }
4110
4111 else if (rr->resrec.RecordType != kDNSRecordTypeShared)
4112 {
4113 ptr = putPrereqNameNotInUse(rr->resrec.name, &msg, ptr, end);
4114 if (!ptr) goto error;
4115 }
4116
4117 ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl);
4118 if (!ptr) goto error;
4119 }
4120
4121 if (rr->uDNS_info.lease)
4122 { ptr = putUpdateLease(&msg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) goto error; }
4123
4124 err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &regInfo->ns, regInfo->port, -1, GetAuthInfoForName(u, rr->resrec.name));
4125 if (err) debugf("ERROR: sendRecordRegistration - mDNSSendDNSMessage - %ld", err);
4126
4127 SetRecordRetry(m, rr, err);
4128
4129 if (regInfo->state != regState_Refresh && regInfo->state != regState_DeregDeferred && regInfo->state != regState_UpdatePending)
4130 regInfo->state = regState_Pending;
4131
4132 return;
4133
4134 error:
4135 LogMsg("sendRecordRegistration: Error formatting message");
4136 if (rr->uDNS_info.state != regState_Unregistered)
4137 {
4138 unlinkAR(&u->RecordRegistrations, rr);
4139 rr->uDNS_info.state = regState_Unregistered;
4140 }
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
4145 }
4146
4147 mDNSlocal void RecordRegistrationCallback(mStatus err, mDNS *const m, void *authPtr, const AsyncOpResult *result)
4148 {
4149 AuthRecord *newRR = (AuthRecord*)authPtr;
4150 const zoneData_t *zoneData = mDNSNULL;
4151 uDNS_GlobalInfo *u = &m->uDNS_info;
4152 AuthRecord *ptr;
4153
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; }
4158
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;
4163
4164 if (newRR->uDNS_info.state == regState_Cancelled)
4165 {
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);
4171 return;
4172 }
4173
4174 if (result->type != zoneDataResult)
4175 {
4176 LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type);
4177 goto error;
4178 }
4179
4180 if (newRR->resrec.rrclass != zoneData->zoneClass)
4181 {
4182 LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)",
4183 newRR->resrec.rrclass, zoneData->zoneClass);
4184 goto error;
4185 }
4186
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)
4191 {
4192 LogMsg("ERROR: Only name server claiming responsibility for \"%##s\" is \"%##s\"!",
4193 newRR->resrec.name->c, zoneData->zoneName.c);
4194 err = mStatus_NoSuchNameErr;
4195 goto error;
4196 }
4197
4198 // cache zone data
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;
4202 else
4203 {
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;
4207 }
4208
4209 sendRecordRegistration(m, newRR);
4210 return;
4211
4212 error:
4213 if (newRR->uDNS_info.state != regState_Unregistered)
4214 {
4215 unlinkAR(&u->RecordRegistrations, newRR);
4216 newRR->uDNS_info.state = regState_Unregistered;
4217 }
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
4223 }
4224
4225 mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs)
4226 {
4227 DNSMessage msg;
4228 mDNSu8 *ptr = msg.data;
4229 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
4230 uDNS_GlobalInfo *u = &m->uDNS_info;
4231 mDNSOpaque16 id;
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;
4237 domainname target;
4238 AuthRecord *srv = &srs->RR_SRV;
4239 mDNSu32 i;
4240
4241 privport = zeroIPPort;
4242
4243 if (!rInfo->ns.ip.v4.NotAnInteger) { LogMsg("SendServiceRegistration - NS not set!"); return; }
4244
4245 id = newMessageID(u);
4246 InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
4247
4248 // setup resource records
4249 SetNewRData(&srs->RR_PTR.resrec, mDNSNULL, 0);
4250 SetNewRData(&srs->RR_TXT.resrec, mDNSNULL, 0);
4251
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))
4255 {
4256 privport = srv->resrec.rdata->u.srv.port;
4257 srv->resrec.rdata->u.srv.port = nat->PublicPort;
4258 mapped = mDNStrue;
4259 }
4260
4261 // construct update packet
4262 // set zone
4263 ptr = putZone(&msg, ptr, end, &rInfo->zone, mDNSOpaque16fromIntVal(srv->resrec.rrclass));
4264 if (!ptr) goto error;
4265
4266 if (srs->uDNS_info.TestForSelfConflict)
4267 {
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;
4271 }
4272
4273 else if (srs->uDNS_info.state != regState_Refresh && srs->uDNS_info.state != regState_UpdatePending)
4274 {
4275 // use SRV name for prereq
4276 ptr = putPrereqNameNotInUse(srv->resrec.name, &msg, ptr, end);
4277 if (!ptr) goto error;
4278 }
4279
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;
4282
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;
4285
4286 if (rInfo->state == regState_UpdatePending) // we're updating the txt record
4287 {
4288 AuthRecord *txt = &srs->RR_TXT;
4289 uDNS_RegInfo *txtInfo = &txt->uDNS_info;
4290 // delete old RData
4291 SetNewRData(&txt->resrec, txtInfo->OrigRData, txtInfo->OrigRDLen);
4292 if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_TXT.resrec))) goto error; // delete old rdata
4293
4294 // add new 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;
4297 }
4298 else
4299 if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) goto error;
4300
4301 if (!GetServiceTarget(u, srv, &target))
4302 {
4303 debugf("Couldn't get target for service %##s", srv->resrec.name->c);
4304 rInfo->state = regState_NoTarget;
4305 return;
4306 }
4307
4308 if (!SameDomainName(&target, &srv->resrec.rdata->u.srv.target))
4309 {
4310 AssignDomainName(&srv->resrec.rdata->u.srv.target, &target);
4311 SetNewRData(&srv->resrec, mDNSNULL, 0);
4312 }
4313
4314 ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srv->resrec, srv->resrec.rroriginalttl);
4315 if (!ptr) goto error;
4316
4317 if (srs->uDNS_info.lease)
4318 { ptr = putUpdateLease(&msg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) goto error; }
4319
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);
4322
4323 if (rInfo->state != regState_Refresh && rInfo->state != regState_DeregDeferred && srs->uDNS_info.state != regState_UpdatePending)
4324 rInfo->state = regState_Pending;
4325
4326 SetRecordRetry(m, &srs->RR_SRV, err);
4327 rInfo->id = id;
4328 if (mapped) srv->resrec.rdata->u.srv.port = privport;
4329 return;
4330
4331 error:
4332 LogMsg("SendServiceRegistration - Error formatting message");
4333 if (mapped) srv->resrec.rdata->u.srv.port = privport;
4334 unlinkSRS(m, srs);
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
4341 }
4342
4343 mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srsPtr, const AsyncOpResult *result)
4344 {
4345 ServiceRecordSet *srs = (ServiceRecordSet *)srsPtr;
4346 const zoneData_t *zoneData = mDNSNULL;
4347
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;
4351
4352 if (result->type != zoneDataResult)
4353 {
4354 LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type);
4355 goto error;
4356 }
4357
4358 if (srs->uDNS_info.state == regState_Cancelled)
4359 {
4360 // client cancelled registration while fetching zone data
4361 srs->uDNS_info.state = regState_Unregistered;
4362 unlinkSRS(m, srs);
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
4366 return;
4367 }
4368
4369 if (srs->RR_SRV.resrec.rrclass != zoneData->zoneClass)
4370 {
4371 LogMsg("Service %##s - class does not match zone", srs->RR_SRV.resrec.name->c);
4372 goto error;
4373 }
4374
4375 // cache zone data
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;
4380 else
4381 {
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;
4385 }
4386
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);
4390 return;
4391
4392 error:
4393 unlinkSRS(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
4399 }
4400
4401 mDNSlocal mStatus SetupRecordRegistration(mDNS *m, AuthRecord *rr)
4402 {
4403 domainname *target = GetRRDomainNameTarget(&rr->resrec);
4404 AuthRecord *ptr = m->uDNS_info.RecordRegistrations;
4405
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; }
4408
4409 if (rr->uDNS_info.state == regState_FetchingZoneData ||
4410 rr->uDNS_info.state == regState_Pending ||
4411 rr->uDNS_info.state == regState_Registered)
4412 {
4413 LogMsg("Requested double-registration of physical record %##s type %d",
4414 rr->resrec.name->c, rr->resrec.rrtype);
4415 return mStatus_AlreadyRegistered;
4416 }
4417
4418 rr->resrec.rdlength = GetRDLength(&rr->resrec, mDNSfalse);
4419 rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue);
4420
4421 if (!ValidateDomainName(rr->resrec.name))
4422 {
4423 LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr));
4424 return mStatus_Invalid;
4425 }
4426
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))
4429 {
4430 LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr));
4431 return mStatus_Invalid;
4432 }
4433
4434 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
4435 rr->resrec.rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(rr->resrec.rdlength, &rr->resrec.rdata->u);
4436
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;
4441
4442 return mStatus_NoError;
4443 }
4444
4445 mDNSexport mStatus uDNS_RegisterRecord(mDNS *const m, AuthRecord *const rr)
4446 {
4447 mStatus err = SetupRecordRegistration(m, rr);
4448 if (err) return err;
4449 else return startGetZoneData(rr->resrec.name, m, mDNStrue, mDNSfalse, RecordRegistrationCallback, rr);
4450 }
4451
4452 mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
4453 {
4454 uDNS_GlobalInfo *u = &m->uDNS_info;
4455 DNSMessage msg;
4456 mDNSu8 *ptr = msg.data;
4457 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
4458 mStatus err;
4459
4460 InitializeDNSMessage(&msg.h, rr->uDNS_info.id, UpdateReqFlags);
4461
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;
4465
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);
4468
4469 SetRecordRetry(m, rr, err);
4470 rr->uDNS_info.state = regState_DeregPending;
4471 return;
4472
4473 error:
4474 LogMsg("Error: SendRecordDeregistration - could not contruct deregistration packet");
4475 unlinkAR(&u->RecordRegistrations, rr);
4476 rr->uDNS_info.state = regState_Unregistered;
4477 }
4478
4479
4480
4481 mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr)
4482 {
4483 uDNS_GlobalInfo *u = &m->uDNS_info;
4484 NATTraversalInfo *n = rr->uDNS_info.NATinfo;
4485
4486 switch (rr->uDNS_info.state)
4487 {
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;
4497 break;
4498 case regState_ExtraQueued:
4499 rr->uDNS_info.state = regState_Unregistered;
4500 break;
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:
4512 break;
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;
4526 }
4527
4528 if (rr->uDNS_info.state == regState_Unregistered)
4529 {
4530 // unlink and deliver memfree
4531
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;
4537 }
4538
4539 rr->uDNS_info.NATinfo = mDNSNULL;
4540 if (n) FreeNATInfo(m, n);
4541
4542 SendRecordDeregistration(m, rr);
4543 return mStatus_NoError;
4544 }
4545
4546 mDNSexport mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs)
4547 {
4548 mDNSu32 i;
4549 domainname target;
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));
4555 *p = srs;
4556 srs->next = mDNSNULL;
4557
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;
4562
4563 info->lease = mDNStrue;
4564
4565 srs->RR_SRV.resrec.rdata->u.srv.target.c[0] = 0;
4566 if (!GetServiceTarget(&m->uDNS_info, &srs->RR_SRV, &target))
4567 {
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;
4572 }
4573
4574 info->state = regState_FetchingZoneData;
4575 return startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
4576 }
4577
4578 mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
4579 {
4580 uDNS_RegInfo *info = &srs->uDNS_info;
4581 uDNS_GlobalInfo *u = &m->uDNS_info;
4582 DNSMessage msg;
4583 mDNSOpaque16 id;
4584 mDNSu8 *ptr = msg.data;
4585 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
4586 mStatus err = mStatus_UnknownErr;
4587 mDNSu32 i;
4588
4589 id = newMessageID(u);
4590 InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
4591
4592 // put zone
4593 ptr = putZone(&msg, ptr, end, &info->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
4594 if (!ptr) { LogMsg("ERROR: SendServiceDeregistration - putZone"); goto error; }
4595
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;
4600
4601
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; }
4604
4605 SetRecordRetry(m, &srs->RR_SRV, err);
4606 info->id = id;
4607 info->state = regState_DeregPending;
4608
4609 return;
4610
4611 error:
4612 unlinkSRS(m, srs);
4613 info->state = regState_Unregistered;
4614 }
4615
4616 mDNSexport mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs)
4617 {
4618 NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
4619 char *errmsg = "Unknown State";
4620
4621 // don't re-register with a new target following deregistration
4622 srs->uDNS_info.SRVChanged = srs->uDNS_info.SRVUpdateDeferred = mDNSfalse;
4623
4624 if (nat)
4625 {
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);
4631 }
4632
4633 switch (srs->uDNS_info.state)
4634 {
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
4656 unlinkSRS(m, srs);
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)";
4668 goto error;
4669 }
4670
4671 error:
4672 LogMsg("Error, uDNS_DeregisterService: %s", errmsg);
4673 return mStatus_BadReferenceErr;
4674 }
4675
4676 mDNSexport mStatus uDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra)
4677 {
4678 mStatus err = mStatus_UnknownErr;
4679
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
4682
4683 if (sr->uDNS_info.state == regState_Registered || sr->uDNS_info.state == regState_Refresh)
4684 err = uDNS_RegisterRecord(m, &extra->r);
4685 else
4686 {
4687 err = SetupRecordRegistration(m, &extra->r);
4688 extra->r.uDNS_info.state = regState_ExtraQueued; // %%% Is it okay to overwrite the previous uDNS_info.state?
4689 }
4690
4691 if (!err)
4692 {
4693 extra->next = sr->Extras;
4694 sr->Extras = extra;
4695 }
4696 return err;
4697 }
4698
4699 mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr)
4700 {
4701 uDNS_GlobalInfo *u = &m->uDNS_info;
4702 ServiceRecordSet *parent = mDNSNULL;
4703 AuthRecord *rptr;
4704 uDNS_RegInfo *info = &rr->uDNS_info;
4705 regState_t *stateptr = mDNSNULL;
4706
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; }
4710
4711 if (!parent)
4712 {
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;
4717 }
4718
4719 switch(*stateptr)
4720 {
4721 case regState_DeregPending:
4722 case regState_DeregDeferred:
4723 case regState_Cancelled:
4724 case regState_Unregistered:
4725 // not actively registered
4726 goto unreg_error;
4727
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;
4737
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;
4749
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;
4760
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
4764 }
4765
4766 unreg_error:
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;
4770 }
4771
4772
4773 // ***************************************************************************
4774 #if COMPILER_LIKES_PRAGMA_MARK
4775 #pragma mark - Periodic Execution Routines
4776 #endif
4777
4778
4779 mDNSlocal mDNSs32 CheckNATMappings(mDNS *m, mDNSs32 timenow)
4780 {
4781 NATTraversalInfo *ptr = m->uDNS_info.NATTraversals;
4782 mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4783
4784 while (ptr)
4785 {
4786 NATTraversalInfo *cur = ptr;
4787 ptr = ptr->next;
4788 if (cur->op != NATOp_AddrRequest || cur->state != NATState_Established) // no refresh necessary for established Add requests
4789 {
4790 if (cur->retry - timenow < 0)
4791 {
4792 if (cur->state == NATState_Established) RefreshNATMapping(cur, m);
4793 else if (cur->state == NATState_Request || cur->state == NATState_Refresh)
4794 {
4795 if (cur->ntries >= NATMAP_MAX_TRIES) cur->ReceiveResponse(cur, m, mDNSNULL, 0); // may invalidate "cur"
4796 else SendNATMsg(cur, m);
4797 }
4798 }
4799 else if (cur->retry - nextevent < 0) nextevent = cur->retry;
4800 }
4801 }
4802 return nextevent;
4803 }
4804
4805 mDNSlocal mDNSs32 CheckQueries(mDNS *m, mDNSs32 timenow)
4806 {
4807 DNSQuestion *q;
4808 uDNS_GlobalInfo *u = &m->uDNS_info;
4809 LLQ_Info *llq;
4810 mDNSs32 sendtime;
4811 mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4812 DNSMessage msg;
4813 mStatus err = mStatus_NoError;
4814 mDNSu8 *end;
4815 uDNS_QuestionInfo *info;
4816
4817 u->CurrentQuery = u->ActiveQueries;
4818 while (u->CurrentQuery)
4819 {
4820 q = u->CurrentQuery;
4821 info = &q->uDNS_info;
4822 llq = info->llq;
4823
4824 if (!info->internal && ((!q->LongLived && !info->Answered) || (llq && llq->state < LLQ_Established)) &&
4825 info->RestartTime + RESTART_GOODBYE_DELAY - timenow < 0)
4826 {
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)
4829 {
4830 CacheRecord *cr = info->knownAnswers;
4831 info->knownAnswers = info->knownAnswers->next;
4832
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
4836 ufree(cr);
4837 if (q != u->CurrentQuery) { debugf("CheckQueries - question removed via callback."); break; }
4838 }
4839 }
4840 if (q != u->CurrentQuery) continue;
4841
4842 if (q->LongLived && llq->state != LLQ_Poll)
4843 {
4844 if (llq->state >= LLQ_InitialRequest && llq->state <= LLQ_Established)
4845 {
4846 if (llq->retry - timenow < 0)
4847 {
4848 // sanity check to avoid packet flood bugs
4849 if (!llq->retry)
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); }
4859 }
4860 else if (llq->retry - nextevent < 0) nextevent = llq->retry;
4861 }
4862 }
4863 else
4864 {
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)
4870 {
4871 DNSServer *server = GetServerForName(&m->uDNS_info, &q->qname);
4872 if (server)
4873 {
4874 if (server->teststate == DNSServer_Untested)
4875 {
4876 InitializeDNSMessage(&msg.h, newMessageID(&m->uDNS_info), uQueryFlags);
4877 end = putQuestion(&msg, msg.data, msg.data + AbsoluteMaxDNSMessageData, DNSRelayTestQuestion, kDNSType_PTR, kDNSClass_IN);
4878 }
4879 else
4880 err = constructQueryMsg(&msg, &end, q);
4881 if (err) LogMsg("Error: uDNS_Idle - constructQueryMsg. Skipping question %##s", q->qname.c);
4882 else
4883 {
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
4890 }
4891 }
4892 }
4893 else if (sendtime - nextevent < 0) nextevent = sendtime;
4894 }
4895 u->CurrentQuery = u->CurrentQuery->next;
4896 }
4897 return nextevent;
4898 }
4899
4900 mDNSlocal mDNSs32 CheckRecordRegistrations(mDNS *m, mDNSs32 timenow)
4901 {
4902 AuthRecord *rr;
4903 uDNS_RegInfo *rInfo;
4904 uDNS_GlobalInfo *u = &m->uDNS_info;
4905 mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4906
4907 //!!!KRS list should be pre-sorted by expiration
4908 for (rr = u->RecordRegistrations; rr; rr = rr->next)
4909 {
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)
4912 {
4913 if (rr->LastAPTime + rr->ThisAPInterval - timenow < 0)
4914 {
4915 #if MDNS_DEBUGMSGS
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);
4921 #endif
4922 //LogMsg("Retransmit record %##s", rr->resrec.name->c);
4923 if (rInfo->state == regState_DeregPending) SendRecordDeregistration(m, rr);
4924 else sendRecordRegistration(m, rr);
4925 }
4926 if (rr->LastAPTime + rr->ThisAPInterval - nextevent < 0) nextevent = rr->LastAPTime + rr->ThisAPInterval;
4927 }
4928 if (rInfo->lease && rInfo->state == regState_Registered)
4929 {
4930 if (rInfo->expire - timenow < 0)
4931 {
4932 debugf("refreshing record %##s", rr->resrec.name->c);
4933 rInfo->state = regState_Refresh;
4934 sendRecordRegistration(m, rr);
4935 }
4936 if (rInfo->expire - nextevent < 0) nextevent = rInfo->expire;
4937 }
4938 }
4939 return nextevent;
4940 }
4941
4942 mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m, mDNSs32 timenow)
4943 {
4944 ServiceRecordSet *s = m->uDNS_info.ServiceRegistrations;
4945 uDNS_RegInfo *rInfo;
4946 mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4947
4948 // Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery
4949 while (s)
4950 {
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
4954 s = s->next;
4955
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)
4958 {
4959 if (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval - timenow < 0)
4960 {
4961 #if MDNS_DEBUGMSGS
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);
4968 #endif
4969 if (rInfo->state == regState_DeregPending) { SendServiceDeregistration(m, srs); continue; }
4970 else SendServiceRegistration (m, srs);
4971 }
4972 if (nextevent - srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval > 0)
4973 nextevent = srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval;
4974 }
4975
4976 if (rInfo->lease && rInfo->state == regState_Registered)
4977 {
4978 if (rInfo->expire - timenow < 0)
4979 {
4980 debugf("refreshing service %##s", srs->RR_SRV.resrec.name->c);
4981 rInfo->state = regState_Refresh;
4982 SendServiceRegistration(m, srs);
4983 }
4984 if (rInfo->expire - nextevent < 0) nextevent = rInfo->expire;
4985 }
4986 }
4987 return nextevent;
4988 }
4989
4990 mDNSexport void uDNS_Execute(mDNS *const m)
4991 {
4992 uDNS_GlobalInfo *u = &m->uDNS_info;
4993 mDNSs32 nexte, timenow = mDNSPlatformTimeNow(m);
4994
4995 u->nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4996
4997 if (u->DelaySRVUpdate && u->NextSRVUpdate - timenow < 0)
4998 {
4999 u->DelaySRVUpdate = mDNSfalse;
5000 UpdateSRVRecords(m);
5001 }
5002
5003 nexte = CheckNATMappings(m, timenow);
5004 if (nexte - u->nextevent < 0) u->nextevent = nexte;
5005
5006 if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0)
5007 m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it
5008
5009 nexte = CheckQueries(m, timenow);
5010 if (nexte - u->nextevent < 0) u->nextevent = nexte;
5011
5012 nexte = CheckRecordRegistrations(m, timenow);
5013 if (nexte - u->nextevent < 0) u->nextevent = nexte;
5014
5015 nexte = CheckServiceRegistrations(m, timenow);
5016 if (nexte - u->nextevent < 0) u->nextevent = nexte;
5017
5018 }
5019
5020 // ***************************************************************************
5021 #if COMPILER_LIKES_PRAGMA_MARK
5022 #pragma mark - Startup, Shutdown, and Sleep
5023 #endif
5024
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.
5028
5029 mDNSlocal void SuspendLLQs(mDNS *m, mDNSBool DeregisterActive)
5030 {
5031 DNSQuestion *q;
5032 LLQ_Info *llq;
5033 for (q = m->uDNS_info.ActiveQueries; q; q = q->next)
5034 {
5035 llq = q->uDNS_info.llq;
5036 if (q->LongLived && llq)
5037 {
5038 if (llq->state == LLQ_GetZoneInfo)
5039 {
5040 debugf("Marking %##s suspend-deferred", q->qname.c);
5041 llq->state = LLQ_SuspendDeferred; // suspend once we're done getting zone info
5042 }
5043 else if (llq->state < LLQ_Suspended)
5044 {
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;
5049 ubzero(llq->id, 8);
5050 }
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
5053 }
5054 }
5055 CheckForUnreferencedLLQMapping(m);
5056 }
5057
5058 mDNSlocal void RestartQueries(mDNS *m)
5059 {
5060 uDNS_GlobalInfo *u = &m->uDNS_info;
5061 DNSQuestion *q;
5062 LLQ_Info *llqInfo;
5063 mDNSs32 timenow = mDNSPlatformTimeNow(m);
5064
5065 u->CurrentQuery = u->ActiveQueries;
5066 while (u->CurrentQuery)
5067 {
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;
5073 if (q->LongLived)
5074 {
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)
5077 {
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
5081 }
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)
5085 {
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);
5091 }
5092 }
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)
5094 }
5095 }
5096
5097 mDNSexport void mDNS_UpdateLLQs(mDNS *m)
5098 {
5099 uDNS_GlobalInfo *u = &m->uDNS_info;
5100
5101 mDNS_Lock(m);
5102 if (u->LLQNatInfo)
5103 {
5104 DeleteNATPortMapping(m, u->LLQNatInfo, mDNSNULL);
5105 FreeNATInfo(m, u->LLQNatInfo); // routine clears u->LLQNatInfo ptr
5106 }
5107 SuspendLLQs(m, mDNStrue);
5108 RestartQueries(m);
5109 mDNS_Unlock(m);
5110 }
5111
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.
5116
5117
5118
5119 mDNSlocal void SleepRecordRegistrations(mDNS *m)
5120 {
5121 DNSMessage msg;
5122 AuthRecord *rr = m->uDNS_info.RecordRegistrations;
5123 mDNSs32 timenow = mDNSPlatformTimeNow(m);
5124
5125 while (rr)
5126 {
5127 if (rr->uDNS_info.state == regState_Registered ||
5128 rr->uDNS_info.state == regState_Refresh)
5129 {
5130 mDNSu8 *ptr = msg.data, *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
5131 InitializeDNSMessage(&msg.h, newMessageID(&m->uDNS_info), UpdateReqFlags);
5132
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; }
5138
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;
5143 }
5144 rr = rr->next;
5145 }
5146 }
5147
5148 mDNSlocal void WakeRecordRegistrations(mDNS *m)
5149 {
5150 mDNSs32 timenow = mDNSPlatformTimeNow(m);
5151 AuthRecord *rr = m->uDNS_info.RecordRegistrations;
5152
5153 while (rr)
5154 {
5155 if (rr->uDNS_info.state == regState_Refresh)
5156 {
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;
5160 }
5161 rr = rr->next;
5162 }
5163 }
5164
5165 mDNSlocal void SleepServiceRegistrations(mDNS *m)
5166 {
5167 ServiceRecordSet *srs = m->uDNS_info.ServiceRegistrations;
5168 while(srs)
5169 {
5170 uDNS_RegInfo *info = &srs->uDNS_info;
5171 NATTraversalInfo *nat = info->NATinfo;
5172
5173 if (nat)
5174 {
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);
5180 }
5181
5182 if (info->state == regState_UpdatePending)
5183 {
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;
5193 }
5194
5195 if (info->state == regState_Registered || info->state == regState_Refresh)
5196 {
5197 mDNSOpaque16 origid = srs->uDNS_info.id;
5198 info->state = regState_DeregPending; // state expected by SendDereg()
5199 SendServiceDeregistration(m, srs);
5200 info->id = origid;
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;
5203 }
5204 srs = srs->next;
5205 }
5206 }
5207
5208 mDNSlocal void WakeServiceRegistrations(mDNS *m)
5209 {
5210 mDNSs32 timenow = mDNSPlatformTimeNow(m);
5211 ServiceRecordSet *srs = m->uDNS_info.ServiceRegistrations;
5212 while(srs)
5213 {
5214 if (srs->uDNS_info.state == regState_Refresh)
5215 {
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;
5219 }
5220 srs = srs->next;
5221 }
5222 }
5223
5224 mDNSexport void uDNS_Init(mDNS *const m)
5225 {
5226 mDNSPlatformMemZero(&m->uDNS_info, sizeof(uDNS_GlobalInfo));
5227 m->uDNS_info.nextevent = m->timenow_last + 0x78000000;
5228 }
5229
5230 mDNSexport void uDNS_Sleep(mDNS *const m)
5231 {
5232 SuspendLLQs(m, mDNStrue);
5233 SleepServiceRegistrations(m);
5234 SleepRecordRegistrations(m);
5235 }
5236
5237 mDNSexport void uDNS_Wake(mDNS *const m)
5238 {
5239 RestartQueries(m);
5240 WakeServiceRegistrations(m);
5241 WakeRecordRegistrations(m);
5242 }