xref: /titanic_51/usr/src/cmd/cmd-inet/usr.lib/mdnsd/uDNS.c (revision b3697b90e692e3e5d859fb77d285d4c056d99eda)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
778 
779 #include "uDNS.h"
780 
781 #if(defined(_MSC_VER))
782 	// Disable "assignment within conditional expression".
783 	// Other compilers understand the convention that if you place the assignment expression within an extra pair
784 	// of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
785 	// The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
786 	// to the compiler that the assignment is intentional, we have to just turn this warning off completely.
787 	#pragma warning(disable:4706)
788 #endif
789 
790 #define umalloc(x)         mDNSPlatformMemAllocate(x)       // short hands for common routines
791 #define ufree(x)           mDNSPlatformMemFree(x)
792 #define ubzero(x,y)        mDNSPlatformMemZero(x,y)
793 #define umemcpy(x, y, l)   mDNSPlatformMemCopy(y, x, l)  // uses memcpy(2) arg ordering
794 
795 // Asynchronous operation types
796 
797 typedef enum
798 	{
799 	zoneDataResult
800 	// other async. operation names go here
801 	} AsyncOpResultType;
802 
803 typedef struct
804 	{
805     domainname zoneName;
806     mDNSAddr primaryAddr;
807     mDNSu16 zoneClass;
808     mDNSIPPort llqPort;
809     mDNSIPPort updatePort;
810 	} zoneData_t;
811 
812 // other async. result struct defs go here
813 
814 typedef struct
815 	{
816     AsyncOpResultType type;
817     zoneData_t zoneData;
818     // other async result structs go here
819 	} AsyncOpResult;
820 
821 typedef void AsyncOpCallback(mStatus err, mDNS *const m, void *info, const AsyncOpResult *result);
822 
823 
824 // Private Function Prototypes
825 // Note:  In general, functions are ordered such that they do not require forward declarations.
826 // However, prototypes are used where cyclic call graphs exist (e.g. foo calls bar, and bar calls
827 // foo), or when they aid in the grouping or readability of code (e.g. state machine code that is easier
828 // read top-to-bottom.)
829 
830 mDNSlocal mDNSBool FreeNATInfo(mDNS *m, NATTraversalInfo *n);
831 mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question,  const mDNSAddr *src, mDNS *m);
832 mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdatePort, mDNSBool findLLQPort, AsyncOpCallback callback, void *callbackInfo);
833 mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID);
834 mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr);
835 mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs);
836 mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs);
837 mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srsPtr, const AsyncOpResult *result);
838 mDNSlocal void SuspendLLQs(mDNS *m, mDNSBool DeregisterActive);
839 mDNSlocal void RestartQueries(mDNS *m);
840 mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer);
841 mDNSlocal void llqResponseHndlr(mDNS * const m, DNSMessage *msg, const  mDNSu8 *end, DNSQuestion *question, void *context);
842 
843 // ***************************************************************************
844 #if COMPILER_LIKES_PRAGMA_MARK
845 #pragma mark - Temporary workaround
846 #endif
847 
848 // 17 Places in this file directly call mDNSPlatformTimeNow(), which is unsafe
849 // The platform function is now called mDNSPlatformRawTime(), and
850 // mDNSPlatformTimeNow() is defined here as a temporary workaround.
851 // This is a gross hack, and after this change has been tested for a while,
852 // all these calls should be replaced by simple references to m->timenow
853 
854 mDNSlocal mDNSs32 mDNSPlatformTimeNow(mDNS *m)
855 	{
856 	if (m->mDNS_busy && m->timenow) return(m->timenow);
857 	LogMsg("ERROR: uDNS.c code executing without holding main mDNS lock");
858 
859 	// To get a quick and easy stack trace to find out *how* this routine
860 	// is being called without holding main mDNS lock, uncomment the line below:
861 	// *(long*)0=0;
862 
863 	return(mDNS_TimeNow(m));
864 	}
865 
866 // ***************************************************************************
867 #if COMPILER_LIKES_PRAGMA_MARK
868 #pragma mark - General Utility Functions
869 #endif
870 
871 // CountLabels() returns number of labels in name, excluding final root label
872 // (e.g. for "apple.com." CountLabels returns 2.)
873 mDNSlocal int CountLabels(const domainname *d)
874 	{
875 	int count = 0;
876 	const mDNSu8 *ptr;
877 
878 	for (ptr = d->c; *ptr; ptr = ptr + ptr[0] + 1) count++;
879 	return count;
880 	}
881 
882 mDNSlocal mDNSOpaque16 newMessageID(uDNS_GlobalInfo *u)
883 	{
884 	static mDNSBool randomized = mDNSfalse;
885 
886 	if (!randomized) { u->NextMessageID = (mDNSu16)mDNSRandom(0xFFFF); randomized = mDNStrue; }
887 	if (u->NextMessageID == 0) u->NextMessageID++;
888 	return mDNSOpaque16fromIntVal(u->NextMessageID++);
889 	}
890 
891 // unlink an AuthRecord from a linked list
892 mDNSlocal mStatus unlinkAR(AuthRecord **list, AuthRecord *const rr)
893 	{
894 	while (*list && *list != rr) list = &(*list)->next;
895 	if (*list) { *list = rr->next; rr->next = mDNSNULL; return(mStatus_NoError); }
896 	LogMsg("ERROR: unlinkAR - no such active record %##s", rr->resrec.name->c);
897 	return(mStatus_NoSuchRecord);
898 	}
899 
900 mDNSlocal void unlinkSRS(mDNS *m, ServiceRecordSet *srs)
901 	{
902 	uDNS_GlobalInfo *u = &m->uDNS_info;
903 	ServiceRecordSet **p;
904 	NATTraversalInfo *n = u->NATTraversals;
905 
906 	// verify that no NAT objects reference this service
907 	while (n)
908 		{
909 		if (n->reg.ServiceRegistration == srs)
910 			{
911 			NATTraversalInfo *tmp = n;
912 			n = n->next;
913 			LogMsg("ERROR: Unlinking service record set %##s still referenced by NAT traversal object!", srs->RR_SRV.resrec.name->c);
914 			FreeNATInfo(m, tmp);
915 			}
916 		else n = n->next;
917 		}
918 
919 	for (p = &u->ServiceRegistrations; *p; p = &(*p)->next)
920 		if (*p == srs)
921 			{
922 			ExtraResourceRecord *e;
923 			*p = srs->next;
924 			srs->next = mDNSNULL;
925 			for (e=srs->Extras; e; e=e->next)
926 				if (unlinkAR(&u->RecordRegistrations, &e->r))
927 					LogMsg("unlinkSRS: extra record %##s not found", e->r.resrec.name->c);
928 			return;
929 			}
930 	LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list %##s", srs->RR_SRV.resrec.name->c);
931 	}
932 
933 mDNSlocal void LinkActiveQuestion(uDNS_GlobalInfo *u, DNSQuestion *q)
934 	{
935 	if (uDNS_IsActiveQuery(q, u))
936 		{ LogMsg("LinkActiveQuestion - %##s (%d) already in list!", q->qname.c, q->qtype); return; }
937 
938 	q->next = u->ActiveQueries;
939 	u->ActiveQueries = q;
940 	}
941 
942 // set retry timestamp for record with exponential backoff
943 // (for service record sets, use RR_SRV as representative for time checks
944 mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mStatus SendErr)
945 	{
946 	rr->LastAPTime = mDNSPlatformTimeNow(m);
947 	if (SendErr == mStatus_TransientErr || rr->ThisAPInterval < INIT_UCAST_POLL_INTERVAL)  rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
948 	else if (rr->ThisAPInterval*2 <= MAX_UCAST_POLL_INTERVAL)                              rr->ThisAPInterval *= 2;
949 	else if (rr->ThisAPInterval != MAX_UCAST_POLL_INTERVAL)                                rr->ThisAPInterval = MAX_UCAST_POLL_INTERVAL;
950 	}
951 
952 
953 // ***************************************************************************
954 #if COMPILER_LIKES_PRAGMA_MARK
955 #pragma mark - Name Server List Management
956 #endif
957 
958 mDNSexport void mDNS_AddDNSServer(mDNS *const m, const mDNSAddr *addr, const domainname *d)
959     {
960     uDNS_GlobalInfo *u = &m->uDNS_info;
961 	DNSServer *s, **p = &u->Servers;
962 
963 	mDNS_Lock(m);
964 	if (!d) d = (domainname *)"";
965 
966 	while (*p)                 // Check if we already have this {server,domain} pair registered
967 		{
968 		if (mDNSSameAddress(&(*p)->addr, addr) && SameDomainName(&(*p)->domain, d))
969 			LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr, d->c);
970 		p=&(*p)->next;
971 		}
972 
973 	// allocate, add to list
974 	s = umalloc(sizeof(*s));
975 	if (!s) { LogMsg("Error: mDNS_AddDNSServer - malloc"); goto end; }
976 	s->addr      = *addr;
977 	s->del       = mDNSfalse;
978 	s->teststate = DNSServer_Untested;
979 	AssignDomainName(&s->domain, d);
980 	s->next = mDNSNULL;
981 	*p = s;
982 
983 	end:
984 	mDNS_Unlock(m);
985     }
986 
987 mDNSexport void mDNS_DeleteDNSServers(mDNS *const m)
988     {
989 	DNSServer *s;
990 	mDNS_Lock(m);
991 
992 	s = m->uDNS_info.Servers;
993 	m->uDNS_info.Servers = mDNSNULL;
994 	while (s)
995 		{
996 		DNSServer *tmp = s;
997 		s = s->next;
998 		ufree(tmp);
999 		}
1000 
1001 	mDNS_Unlock(m);
1002     }
1003 
1004  // ***************************************************************************
1005 #if COMPILER_LIKES_PRAGMA_MARK
1006 #pragma mark - authorization management
1007 #endif
1008 
1009 mDNSlocal uDNS_AuthInfo *GetAuthInfoForName(const uDNS_GlobalInfo *u, const domainname *name)
1010 	{
1011 	uDNS_AuthInfo *ptr;
1012 	while (name->c[0])
1013 		{
1014 		for (ptr = u->AuthInfoList; ptr; ptr = ptr->next)
1015 			if (SameDomainName(&ptr->zone, name)) return(ptr);
1016 		name = (const domainname *)(name->c + 1 + name->c[0]);
1017 		}
1018 	return mDNSNULL;
1019 	}
1020 
1021 mDNSlocal void DeleteAuthInfoForZone(uDNS_GlobalInfo *u, const domainname *zone)
1022 	{
1023 	uDNS_AuthInfo *ptr, *prev = mDNSNULL;
1024 
1025 	for (ptr = u->AuthInfoList; ptr; ptr = ptr->next)
1026 		{
1027 		if (SameDomainName(&ptr->zone, zone))
1028 			{
1029 			if (prev) prev->next = ptr->next;
1030 			else u->AuthInfoList = ptr->next;
1031 			ufree(ptr);
1032 			return;
1033 			}
1034 		prev = ptr;
1035 		}
1036 	}
1037 
1038 mDNSexport mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const domainname *key, const char *sharedSecret)
1039 	{
1040 	uDNS_AuthInfo *info;
1041 	mDNSu8 keybuf[1024];
1042 	mDNSs32 keylen;
1043 	uDNS_GlobalInfo *u = &m->uDNS_info;
1044 	mStatus status = mStatus_NoError;
1045 
1046 	mDNS_Lock(m);
1047 
1048 	if (GetAuthInfoForName(u, zone)) DeleteAuthInfoForZone(u, zone);
1049 	if (!key) goto exit;
1050 
1051 	info = (uDNS_AuthInfo*)umalloc(sizeof(*info));
1052 	if (!info) { LogMsg("ERROR: umalloc"); status = mStatus_NoMemoryErr; goto exit; }
1053    	ubzero(info, sizeof(*info));
1054 	AssignDomainName(&info->zone, zone);
1055 	AssignDomainName(&info->keyname, key);
1056 
1057 	keylen = DNSDigest_Base64ToBin(sharedSecret, keybuf, 1024);
1058 	if (keylen < 0)
1059 		{
1060 		LogMsg("ERROR: mDNS_SetSecretForZone - could not convert shared secret %s from base64", sharedSecret);
1061 		ufree(info);
1062 		status = mStatus_UnknownErr;
1063 		goto exit;
1064 		}
1065 	DNSDigest_ConstructHMACKey(info, keybuf, (mDNSu32)keylen);
1066 
1067     // link into list
1068 	info->next = m->uDNS_info.AuthInfoList;
1069 	m->uDNS_info.AuthInfoList = info;
1070 exit:
1071 	mDNS_Unlock(m);
1072 	return status;
1073 	}
1074 
1075  // ***************************************************************************
1076 #if COMPILER_LIKES_PRAGMA_MARK
1077 #pragma mark - NAT Traversal
1078 #endif
1079 
1080 mDNSlocal mDNSBool DomainContainsLabelString(const domainname *d, const char *str)
1081 	{
1082 	const domainlabel *l;
1083 	domainlabel buf;
1084 
1085 	if (!MakeDomainLabelFromLiteralString(&buf, str)) return mDNSfalse;
1086 
1087 	for (l = (const domainlabel *)d; l->c[0]; l = (const domainlabel *)(l->c + l->c[0]+1))
1088 		if (SameDomainLabel(l->c, buf.c)) return mDNStrue;
1089 	return mDNSfalse;
1090 	}
1091 
1092 // allocate struct, link into global list, initialize
1093 mDNSlocal NATTraversalInfo *AllocNATInfo(mDNS *const m, NATOp_t op, NATResponseHndlr callback)
1094 	{
1095 	uDNS_GlobalInfo *u = &m->uDNS_info;
1096 	NATTraversalInfo *info = umalloc(sizeof(NATTraversalInfo));
1097 	if (!info) { LogMsg("ERROR: malloc"); return mDNSNULL; }
1098 	ubzero(info, sizeof(NATTraversalInfo));
1099 	info->next = u->NATTraversals;
1100 	u->NATTraversals = info;
1101 	info->retry = mDNSPlatformTimeNow(m) + NATMAP_INIT_RETRY;
1102 	info->op = op;
1103 	info->state = NATState_Init;
1104 	info->ReceiveResponse = callback;
1105 	info->PublicPort.NotAnInteger = 0;
1106 	info->Router = u->Router;
1107 	return info;
1108 	}
1109 
1110 // unlink from list, deallocate
1111 mDNSlocal mDNSBool FreeNATInfo(mDNS *m, NATTraversalInfo *n)
1112 	{
1113 	NATTraversalInfo *ptr, *prev = mDNSNULL;
1114 	ServiceRecordSet *s = m->uDNS_info.ServiceRegistrations;
1115 
1116 	// Verify that object is not referenced by any services
1117 	while (s)
1118 		{
1119 		if (s->uDNS_info.NATinfo == n)
1120 			{
1121 			LogMsg("Error: Freeing NAT info object still referenced by Service Record Set %##s!", s->RR_SRV.resrec.name->c);
1122 			s->uDNS_info.NATinfo = mDNSNULL;
1123 			}
1124 		s = s->next;
1125 		}
1126 
1127 	if (n == m->uDNS_info.LLQNatInfo) m->uDNS_info.LLQNatInfo = mDNSNULL;
1128 	ptr = m->uDNS_info.NATTraversals;
1129 	while (ptr)
1130 		{
1131 		if (ptr == n)
1132 			{
1133 			if (prev) prev->next = ptr->next;
1134 			else m->uDNS_info.NATTraversals = ptr->next;
1135 			ufree(n);
1136 			return mDNStrue;
1137 			}
1138 		prev = ptr;
1139 		ptr = ptr->next;
1140 		}
1141 	LogMsg("FreeNATInfo: NATTraversalInfo not found in list");
1142 	return mDNSfalse;
1143 	}
1144 
1145 mDNSlocal void SendNATMsg(NATTraversalInfo *info, mDNS *m)
1146 	{
1147 	mStatus err;
1148 	uDNS_GlobalInfo *u = &m->uDNS_info;
1149 
1150 	if (info->state != NATState_Request && info->state != NATState_Refresh)
1151 		{ LogMsg("SendNATMsg: Bad state %d", info->state); return; }
1152 
1153 	if (u->Router.ip.v4.NotAnInteger)
1154 		{
1155 		// send msg if we have a router
1156 		const mDNSu8 *end = (mDNSu8 *)&info->request;
1157 		if (info->op == NATOp_AddrRequest) end += sizeof(NATAddrRequest);
1158 		else end += sizeof(NATPortMapRequest);
1159 
1160 		err = mDNSPlatformSendUDP(m, &info->request, end, 0, &u->Router, NATPMPPort);
1161 		if (!err) (info->ntries++);  // don't increment attempt counter if the send failed
1162 		}
1163 
1164 	// set retry
1165 	if (info->RetryInterval < NATMAP_INIT_RETRY) info->RetryInterval = NATMAP_INIT_RETRY;
1166 	else if (info->RetryInterval * 2 > NATMAP_MAX_RETRY) info->RetryInterval = NATMAP_MAX_RETRY;
1167 	else info->RetryInterval *= 2;
1168 	info->retry = mDNSPlatformTimeNow(m) + info->RetryInterval;
1169 	}
1170 
1171 mDNSlocal mDNSBool ReceiveNATAddrResponse(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len)
1172 	{
1173 	mStatus err = mStatus_NoError;
1174 	AuthRecord *rr = mDNSNULL;
1175 	NATAddrReply *response = (NATAddrReply *)pkt;
1176 	mDNSAddr addr;
1177 
1178 	if (n->state != NATState_Request)
1179 		{
1180 		LogMsg("ReceiveNATAddrResponse: bad state %d", n->state);
1181 		return mDNSfalse;
1182 		}
1183 
1184 	rr = n->reg.RecordRegistration;
1185 	if (!rr)
1186 		{
1187 		LogMsg("ReceiveNATAddrResponse: registration cancelled");
1188 		return mDNSfalse;
1189 		}
1190 
1191 	addr.type = mDNSAddrType_IPv4;
1192 	addr.ip.v4 = rr->resrec.rdata->u.ipv4;
1193 
1194 	if (!pkt) // timeout
1195 		{
1196 #ifdef _LEGACY_NAT_TRAVERSAL_
1197 		err = LNT_GetPublicIP(&addr.ip.v4);
1198 		if (err) goto end;
1199 		else n->state = NATState_Legacy;
1200 #else
1201 		debugf("ReceiveNATAddrResponse: timeout");
1202 		err = mStatus_NATTraversal;
1203 		goto end;
1204 #endif // _LEGACY_NAT_TRAVERSAL_
1205 		}
1206 	else
1207 		{
1208 		if (len < sizeof(*response))
1209 			{
1210 			LogMsg("ReceiveNATAddrResponse: response too short (%d bytes)", len);
1211 			return mDNSfalse;
1212 			}
1213 		if (response->vers != NATMAP_VERS)
1214 			{
1215 			LogMsg("ReceiveNATAddrResponse: received  version %d (expect version %d)", pkt[0], NATMAP_VERS);
1216 			return mDNSfalse;
1217 			}
1218 		if (response->opcode != (NATOp_AddrRequest | NATMAP_RESPONSE_MASK))
1219 			{
1220 			LogMsg("ReceiveNATAddrResponse: bad response code %d", response->opcode);
1221 			return mDNSfalse;
1222 			}
1223 		if (response->err.NotAnInteger)
1224 			{ LogMsg("ReceiveAddrResponse: received error %d", mDNSVal16(response->err)); err = mStatus_NATTraversal; goto end; }
1225 
1226 		addr.ip.v4 = response->PubAddr;
1227 		n->state = NATState_Established;
1228 		}
1229 
1230 	if (IsPrivateV4Addr(&addr))
1231 		{
1232 		LogMsg("ReceiveNATAddrResponse: Double NAT");
1233 		err = mStatus_DoubleNAT;
1234 		goto end;
1235 		}
1236 
1237 	end:
1238 	if (err)
1239 		{
1240 		FreeNATInfo(m, n);
1241 		if (rr)
1242 			{
1243 			rr->uDNS_info.NATinfo = mDNSNULL;
1244 			rr->uDNS_info.state = regState_Unregistered;    // note that rr is not yet in global list
1245 			rr->RecordCallback(m, rr, mStatus_NATTraversal);
1246 			// note - unsafe to touch rr after callback
1247 			}
1248 		return mDNStrue;
1249 		}
1250 	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]);
1251 	rr->resrec.rdata->u.ipv4 = addr.ip.v4;  // replace rdata w/ public address
1252 	uDNS_RegisterRecord(m, rr);
1253 	return mDNStrue;
1254 	}
1255 
1256 
1257 mDNSlocal void StartGetPublicAddr(mDNS *m, AuthRecord *AddressRec)
1258 	{
1259 	NATAddrRequest *req;
1260 	uDNS_GlobalInfo *u = &m->uDNS_info;
1261 
1262 	NATTraversalInfo *info = AllocNATInfo(m, NATOp_AddrRequest, ReceiveNATAddrResponse);
1263 	if (!info) { uDNS_RegisterRecord(m, AddressRec); return; }
1264 	AddressRec->uDNS_info.NATinfo = info;
1265 	info->reg.RecordRegistration = AddressRec;
1266 	info->state = NATState_Request;
1267 
1268     // format message
1269 	req = &info->request.AddrReq;
1270 	req->vers = NATMAP_VERS;
1271 	req->opcode = NATOp_AddrRequest;
1272 
1273 	if (!u->Router.ip.v4.NotAnInteger)
1274 		{
1275 		debugf("No router.  Will retry NAT traversal in %ld ticks", NATMAP_INIT_RETRY);
1276 		return;
1277 		}
1278 
1279 	SendNATMsg(info, m);
1280 	}
1281 
1282 
1283 mDNSlocal void RefreshNATMapping(NATTraversalInfo *n, mDNS *m)
1284 	{
1285 	n->state = NATState_Refresh;
1286 	n->RetryInterval = NATMAP_INIT_RETRY;
1287 	n->ntries = 0;
1288 	SendNATMsg(n, m);
1289 	}
1290 
1291 mDNSlocal void LLQNatMapComplete(mDNS *m)
1292 	{
1293 	uDNS_GlobalInfo *u = &m->uDNS_info;
1294 	LLQ_Info *llqInfo;
1295 	NATTraversalInfo *n = u->LLQNatInfo;
1296 
1297 	if (!n) { LogMsg("Error: LLQNatMapComplete called with NULL LLQNatInfo"); return; }
1298 	if (n->state != NATState_Established && n->state != NATState_Legacy && n->state != NATState_Error)
1299 		{ LogMsg("LLQNatMapComplete - bad nat state %d", n->state); return; }
1300 
1301 	u->CurrentQuery = u->ActiveQueries;
1302 	while (u->CurrentQuery)
1303 		{
1304 		DNSQuestion *q = u->CurrentQuery;
1305 		u->CurrentQuery = u->CurrentQuery->next;
1306 		llqInfo = q->uDNS_info.llq;
1307 		if (q->LongLived && llqInfo->state == LLQ_NatMapWait)
1308 			{
1309 			if (n->state == NATState_Error)
1310 				{
1311 				llqInfo->NATMap = mDNSfalse;
1312 				llqInfo->question->uDNS_info.responseCallback = llqResponseHndlr;
1313 				llqInfo->state = LLQ_Poll;
1314 				llqInfo->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL);  // trigger immediate poll
1315 				llqInfo->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
1316 				}
1317 			else { llqInfo->state = LLQ_GetZoneInfo; startLLQHandshake(m, llqInfo, mDNSfalse); }
1318 			}
1319 		}
1320 	}
1321 
1322 mDNSlocal mDNSBool ReceivePortMapReply(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len)
1323 	{
1324 	ServiceRecordSet *srs = n->reg.ServiceRegistration;
1325 	mDNSIPPort priv = srs ? srs->RR_SRV.resrec.rdata->u.srv.port : m->UnicastPort4;
1326 	mDNSu32 lease;
1327 	mDNSBool deletion = !n->request.PortReq.lease.NotAnInteger;
1328 	NATPortMapReply *reply = (NATPortMapReply *)pkt;
1329 	mDNSu8 *service = srs ? srs->RR_SRV.resrec.name->c : (mDNSu8 *)"\016LLQ event port";
1330 
1331 	if (n->state != NATState_Request && n->state != NATState_Refresh)
1332 		{ LogMsg("ReceivePortMapReply (%##s): bad state %d", service, n->state);  return mDNSfalse; }
1333 
1334 	if (!pkt && !deletion) // timeout
1335 		{
1336 #ifdef _LEGACY_NAT_TRAVERSAL_
1337 		mDNSIPPort pub;
1338 		int ntries = 0;
1339 		mStatus err;
1340 		mDNSBool tcp = (srs && DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp"));
1341 
1342 		pub = priv; // initially request priv == pub
1343 		while (1)
1344 			{
1345 			err = LNT_MapPort(priv, pub, tcp);
1346 			if (!err)
1347 				{
1348 				n->PublicPort = pub;
1349 				n->state = NATState_Legacy;
1350 				goto end;
1351 				}
1352 			else if (err != mStatus_AlreadyRegistered || ++ntries > LEGACY_NATMAP_MAX_TRIES)
1353 				{
1354 				n->state = NATState_Error;
1355 				goto end;
1356 				}
1357 			else
1358 				{
1359 				// the mapping we want is taken - try a random port
1360 				mDNSu16 RandPort = mDNSRandom(DYN_PORT_MAX - DYN_PORT_MIN) + DYN_PORT_MIN;
1361 				pub = mDNSOpaque16fromIntVal(RandPort);
1362 				}
1363 			}
1364 #else
1365 		goto end;
1366 #endif // _LEGACY_NAT_TRAVERSAL_
1367 		}
1368 
1369 	if (len < sizeof(*reply)) { LogMsg("ReceivePortMapReply: response too short (%d bytes)", len); return mDNSfalse; }
1370 	if (reply->vers != NATMAP_VERS) { LogMsg("ReceivePortMapReply: received  version %d (expect version %d)", pkt[0], NATMAP_VERS);  return mDNSfalse; }
1371 	if (reply->opcode != (n->op | NATMAP_RESPONSE_MASK)) { LogMsg("ReceivePortMapReply: bad response code %d", pkt[1]); return mDNSfalse; }
1372 	if (reply->err.NotAnInteger) { LogMsg("ReceivePortMapReply: received error %d", mDNSVal16(reply->err));  return mDNSfalse; }
1373 	if (priv.NotAnInteger != reply->priv.NotAnInteger) return mDNSfalse;  // packet does not match this request
1374 
1375 	if (!srs && n != m->uDNS_info.LLQNatInfo)
1376 		{
1377 		LogMsg("ReceivePortMapReply: registration cancelled");  //!!!KRS change to debugf before checkin
1378 		FreeNATInfo(m, n);
1379 		return mDNStrue;
1380 		}
1381 
1382 	if (deletion) { n->state = NATState_Deleted; return mDNStrue; }
1383 
1384 	lease = (mDNSu32)mDNSVal32(reply->lease);
1385 	if (lease > 0x70000000UL / mDNSPlatformOneSecond) lease = 0x70000000UL / mDNSPlatformOneSecond;
1386 
1387 	if (n->state == NATState_Refresh && reply->pub.NotAnInteger != n->PublicPort.NotAnInteger)
1388 		LogMsg("ReceivePortMapReply: NAT refresh changed public port from %d to %d", mDNSVal16(n->PublicPort), mDNSVal16(reply->pub));
1389         // this should never happen
1390 	    // !!!KRS to be defensive, use SRVChanged flag on service and deregister here
1391 
1392 	n->PublicPort = reply->pub;
1393 	if (reply->pub.NotAnInteger != n->request.PortReq.pub.NotAnInteger) n->request.PortReq.pub = reply->pub; // set message buffer for refreshes
1394 
1395 	n->retry = mDNSPlatformTimeNow(m) + ((mDNSs32)lease * mDNSPlatformOneSecond / 2);  // retry half way to expiration
1396 
1397 	if (n->state == NATState_Refresh) { n->state = NATState_Established; return mDNStrue; }
1398 	n->state = NATState_Established;
1399 
1400 	end:
1401 	if (n->state != NATState_Established && n->state != NATState_Legacy)
1402 		{
1403 		LogMsg("NAT Port Mapping (%##s): timeout", service);
1404 		if (pkt) LogMsg("!!! timeout with non-null packet");
1405 		n->state = NATState_Error;
1406 		if (srs)
1407 			{
1408 			uDNS_HostnameInfo *hi = m->uDNS_info.Hostnames;
1409 			while (hi)
1410 				{
1411 				if (hi->arv6 && (hi->arv6->uDNS_info.state == regState_Registered || hi->arv6->uDNS_info.state == regState_Refresh)) break;
1412 				else hi = hi->next;
1413 				}
1414 
1415 			if (hi)
1416 				{
1417 				debugf("Port map failed for service %##s - using IPv6 service target", service);
1418 				srs->uDNS_info.NATinfo = mDNSNULL;
1419 				FreeNATInfo(m, n);
1420 				goto register_service;
1421 				}
1422 			else srs->uDNS_info.state = regState_NATError;
1423 			}
1424 		else LLQNatMapComplete(m);
1425 		return mDNStrue;
1426 		}
1427 	else LogOperation("Mapped private port %d to public port %d", mDNSVal16(priv), mDNSVal16(n->PublicPort));
1428 
1429 	if (!srs) { LLQNatMapComplete(m); return mDNStrue; }
1430 
1431 	register_service:
1432 	if (srs->uDNS_info.ns.ip.v4.NotAnInteger) SendServiceRegistration(m, srs);  // non-zero server address means we already have necessary zone data to send update
1433 	else
1434 		{
1435 		srs->uDNS_info.state = regState_FetchingZoneData;
1436 		startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
1437 		}
1438 	return mDNStrue;
1439 	}
1440 
1441 mDNSlocal void FormatPortMaprequest(NATTraversalInfo *info, mDNSIPPort port)
1442 	{
1443 	NATPortMapRequest *req = &info->request.PortReq;
1444 
1445 	req->vers = NATMAP_VERS;
1446 	req->opcode = info->op;
1447 	req->unused.NotAnInteger = 0;
1448 	req->priv = port;
1449 	req->pub = port;
1450 	req->lease = mDNSOpaque32fromIntVal(NATMAP_DEFAULT_LEASE);
1451 	}
1452 
1453 mDNSlocal void SendInitialPMapReq(mDNS *m, NATTraversalInfo *info)
1454 	{
1455 	if (!m->uDNS_info.Router.ip.v4.NotAnInteger)
1456 		{
1457 		debugf("No router.  Will retry NAT traversal in %ld seconds", NATMAP_INIT_RETRY);
1458 		info->retry = mDNSPlatformTimeNow(m) + NATMAP_INIT_RETRY;
1459 		info->RetryInterval = NATMAP_INIT_RETRY;
1460 		return;
1461 		}
1462     SendNATMsg(info, m);
1463 	return;
1464 	}
1465 
1466 mDNSlocal void StartNATPortMap(mDNS *m, ServiceRecordSet *srs)
1467 	{
1468 	NATOp_t op;
1469 	NATTraversalInfo *info;
1470 
1471    	if (DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp")) op = NATOp_MapTCP;
1472 	else if (DomainContainsLabelString(srs->RR_PTR.resrec.name, "_udp")) op = NATOp_MapUDP;
1473 	else { LogMsg("StartNATPortMap: could not determine transport protocol of service %##s", srs->RR_SRV.resrec.name->c); goto error; }
1474 
1475 	if (srs->uDNS_info.NATinfo) { LogMsg("Error: StartNATPortMap - NAT info already initialized!");  FreeNATInfo(m, srs->uDNS_info.NATinfo); }
1476 	info = AllocNATInfo(m, op, ReceivePortMapReply);
1477 	srs->uDNS_info.NATinfo = info;
1478 	info->reg.ServiceRegistration = srs;
1479 	info->state = NATState_Request;
1480 
1481 	FormatPortMaprequest(info, srs->RR_SRV.resrec.rdata->u.srv.port);
1482 	SendInitialPMapReq(m, info);
1483 	return;
1484 
1485 	error:
1486 	startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
1487 	}
1488 
1489 mDNSlocal void DeleteNATPortMapping(mDNS *m, NATTraversalInfo *nat, ServiceRecordSet *srs)
1490 	{
1491 	if (nat->state == NATState_Established)  // let other edge-case states expire for simplicity
1492 		{
1493 		// zero lease
1494 		nat->request.PortReq.lease.NotAnInteger = 0;
1495 		nat->state = NATState_Request;
1496 		SendNATMsg(nat, m);
1497 		}
1498 #ifdef _LEGACY_NAT_TRAVERSAL_
1499 	else if (nat->state == NATState_Legacy)
1500 		{
1501 		mStatus err = mStatus_NoError;
1502 		mDNSBool tcp = srs ? DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp") : mDNSfalse;
1503 		err = LNT_UnmapPort(nat->PublicPort, tcp);
1504 		if (err) LogMsg("Legacy NAT Traversal - unmap request failed with error %ld", err);
1505 		}
1506 #else
1507 	(void)srs; // unused
1508 #endif // _LEGACY_NAT_TRAVERSAL_
1509 	}
1510 
1511 mDNSlocal void StartLLQNatMap(mDNS *m)
1512 	{
1513 	NATTraversalInfo *info = AllocNATInfo(m, NATOp_MapUDP, ReceivePortMapReply);
1514 	uDNS_GlobalInfo *u = &m->uDNS_info;
1515 
1516 	u->LLQNatInfo = info;
1517 
1518 	info->reg.RecordRegistration = mDNSNULL;
1519 	info->reg.ServiceRegistration = mDNSNULL;
1520     info->state = NATState_Request;
1521 	FormatPortMaprequest(info, m->UnicastPort4);
1522     SendInitialPMapReq(m, info);
1523 	return;
1524 	}
1525 
1526 // if LLQ NAT context unreferenced, delete the mapping
1527 mDNSlocal void CheckForUnreferencedLLQMapping(mDNS *m)
1528 	{
1529 	NATTraversalInfo *nat = m->uDNS_info.LLQNatInfo;
1530 	DNSQuestion *q;
1531 
1532 	if (!nat) return;
1533 
1534 	for (q = m->uDNS_info.ActiveQueries; q; q = q->next)
1535 		if (q->LongLived && q->uDNS_info.llq->NATMap) return;
1536 
1537 	//to avoid race condition if we need to recreate before this finishes, we do one-shot deregistration
1538 	if (nat->state == NATState_Established || nat->state == NATState_Legacy)
1539 		DeleteNATPortMapping(m, nat, mDNSNULL); // for simplicity we allow other states to expire
1540 	FreeNATInfo(m, nat); // note: this clears the global LLQNatInfo pointer
1541 	}
1542 
1543  // ***************************************************************************
1544 #if COMPILER_LIKES_PRAGMA_MARK
1545 #pragma mark - host name and interface management
1546 #endif
1547 
1548 // if we ever want to refine support for multiple hostnames, we can add logic matching service names to a particular hostname
1549 // for now, we grab the first registered DynDNS name, if any, or a static name we learned via a reverse-map query
1550 mDNSlocal mDNSBool GetServiceTarget(uDNS_GlobalInfo *u, AuthRecord *srv, domainname *dst)
1551 	{
1552 	uDNS_HostnameInfo *hi = u->Hostnames;
1553 	(void)srv;  // unused
1554 
1555 	dst->c[0] = 0;
1556 	while (hi)
1557 		{
1558 		if (hi->arv4 && (hi->arv4->uDNS_info.state == regState_Registered || hi->arv4->uDNS_info.state == regState_Refresh))
1559 			{
1560 			AssignDomainName(dst, hi->arv4->resrec.name);
1561 			return mDNStrue;
1562 			}
1563 		if (hi->arv6 && (hi->arv6->uDNS_info.state == regState_Registered || hi->arv6->uDNS_info.state == regState_Refresh))
1564 			{
1565 			AssignDomainName(dst, hi->arv4->resrec.name);
1566 			return mDNStrue;
1567 			}
1568 		hi = hi->next;
1569 		}
1570 
1571 	if (u->StaticHostname.c[0]) { AssignDomainName(dst, &u->StaticHostname); return mDNStrue; }
1572 	return mDNSfalse;
1573 	}
1574 
1575 mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs)
1576 	{
1577 	uDNS_GlobalInfo *u = &m->uDNS_info;
1578 	ExtraResourceRecord *e;
1579 
1580 	// Target change if:
1581 	// We have a target and were previously waiting for one, or
1582 	// We had a target and no longer do, or
1583 	// The target has changed
1584 
1585 	domainname newtarget;
1586 	domainname *curtarget = &srs->RR_SRV.resrec.rdata->u.srv.target;
1587 	mDNSBool HaveTarget = GetServiceTarget(u, &srs->RR_SRV, &newtarget);
1588 	mDNSBool TargetChanged = (HaveTarget && srs->uDNS_info.state == regState_NoTarget) || (curtarget->c[0] && !HaveTarget) || !SameDomainName(curtarget, &newtarget);
1589 	mDNSBool HaveZoneData = srs->uDNS_info.ns.ip.v4.NotAnInteger ? mDNStrue : mDNSfalse;
1590 
1591 	// Nat state change if:
1592 	// We were behind a NAT, and now we are behind a new NAT, or
1593 	// We're not behind a NAT but our port was previously mapped to a different public port
1594 	// We were not behind a NAT and now we are
1595 
1596 	NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
1597 	mDNSIPPort port = srs->RR_SRV.resrec.rdata->u.srv.port;
1598 	mDNSBool NATChanged = mDNSfalse;
1599 	mDNSBool NowBehindNAT = port.NotAnInteger && IsPrivateV4Addr(&u->AdvertisedV4);
1600 	mDNSBool WereBehindNAT = nat != mDNSNULL;
1601 	mDNSBool NATRouterChanged = nat && nat->Router.ip.v4.NotAnInteger != u->Router.ip.v4.NotAnInteger;
1602 	mDNSBool PortWasMapped = nat && (nat->state == NATState_Established || nat->state == NATState_Legacy) && nat->PublicPort.NotAnInteger != port.NotAnInteger;
1603 
1604 	if (WereBehindNAT && NowBehindNAT && NATRouterChanged) NATChanged = mDNStrue;
1605 	else if (!NowBehindNAT && PortWasMapped)               NATChanged = mDNStrue;
1606 	else if (!WereBehindNAT && NowBehindNAT)               NATChanged = mDNStrue;
1607 
1608 	if (!TargetChanged && !NATChanged) return;
1609 
1610 	debugf("UpdateSRV (%##s) HadZoneData=%d, TargetChanged=%d, HaveTarget=%d, NowBehindNAT=%d, WereBehindNAT=%d, NATRouterChanged=%d, PortWasMapped=%d",
1611 		   srs->RR_SRV.resrec.name->c,  HaveZoneData, TargetChanged, HaveTarget, NowBehindNAT, WereBehindNAT, NATRouterChanged, PortWasMapped);
1612 
1613 	switch(srs->uDNS_info.state)
1614 		{
1615 		case regState_FetchingZoneData:
1616 		case regState_Cancelled:
1617 		case regState_DeregPending:
1618 		case regState_DeregDeferred:
1619 		case regState_Unregistered:
1620 		case regState_NATMap:
1621 		case regState_ExtraQueued:
1622 			// In these states, the SRV has either not yet been registered (it will get up-to-date information when it is)
1623 			// or is in the process of, or has already been, deregistered
1624 			return;
1625 
1626 		case regState_Pending:
1627 		case regState_Refresh:
1628 		case regState_UpdatePending:
1629 			// let the in-flight operation complete before updating
1630 			srs->uDNS_info.SRVUpdateDeferred = mDNStrue;
1631 			return;
1632 
1633 		case regState_NATError:
1634 			if (!NATChanged) return;
1635 			// if nat changed, register if we have a target (below)
1636 
1637 		case regState_NoTarget:
1638 			if (HaveTarget)
1639 				{
1640 				debugf("UpdateSRV: %s service %##s", HaveZoneData ? (NATChanged && NowBehindNAT ? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs->RR_SRV.resrec.name->c);
1641 				if (!HaveZoneData)
1642 					{
1643 					srs->uDNS_info.state = regState_FetchingZoneData;
1644 					startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
1645 					}
1646 				else
1647 					{
1648 					if (nat && (NATChanged || !NowBehindNAT)) { srs->uDNS_info.NATinfo = mDNSNULL; FreeNATInfo(m, nat); }
1649 					if (NATChanged && NowBehindNAT) { srs->uDNS_info.state = regState_NATMap; StartNATPortMap(m, srs); }
1650 					else SendServiceRegistration(m, srs);
1651 					}
1652 				}
1653 			return;
1654 
1655 		case regState_Registered:
1656 			// target or nat changed.  deregister service.  upon completion, we'll look for a new target
1657 			debugf("UpdateSRV: SRV record changed for service %##s - deregistering (will re-register with new SRV)",  srs->RR_SRV.resrec.name->c);
1658 			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
1659 			srs->uDNS_info.SRVChanged = mDNStrue;
1660 			SendServiceDeregistration(m, srs);
1661 			return;
1662 		}
1663 	}
1664 
1665 mDNSlocal void UpdateSRVRecords(mDNS *m)
1666 	{
1667 	ServiceRecordSet *srs;
1668 
1669 	for (srs = m->uDNS_info.ServiceRegistrations; srs; srs = srs->next) UpdateSRV(m, srs);
1670 	}
1671 
1672 mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
1673 	{
1674 	uDNS_HostnameInfo *hi = (uDNS_HostnameInfo *)rr->RecordContext;
1675 
1676 	if (result == mStatus_MemFree)
1677 		{
1678 		if (hi)
1679 			{
1680 			if      (hi->arv4 == rr)                hi->arv4 = mDNSNULL;
1681 			else if (hi->arv4 == rr)                hi->arv6 = mDNSNULL;
1682 			rr->RecordContext = mDNSNULL;
1683 			if (!hi->arv4 && !hi->arv6) ufree(hi);  // free hi when both v4 and v6 AuthRecs deallocated
1684 			}
1685 		ufree(rr);
1686 		return;
1687 		}
1688 
1689 	if (result)
1690 		{
1691 		// don't unlink or free - we can retry when we get a new address/router
1692 		if (rr->resrec.rrtype == kDNSType_A)
1693 			LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.4a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv4);
1694 		else
1695 			LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.16a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
1696 		if (!hi) { ufree(rr); return; }
1697 		if (rr->uDNS_info.state != regState_Unregistered) LogMsg("Error: HostnameCallback invoked with error code for record not in regState_Unregistered!");
1698 
1699 		if ((!hi->arv4 || hi->arv4->uDNS_info.state == regState_Unregistered) &&
1700 			(!hi->arv6 || hi->arv6->uDNS_info.state == regState_Unregistered))
1701 			{
1702 			// only deliver status if both v4 and v6 fail
1703 			rr->RecordContext = (void *)hi->StatusContext;
1704 			if (hi->StatusCallback)
1705 				hi->StatusCallback(m, rr, result); // client may NOT make API calls here
1706 			rr->RecordContext = (void *)hi;
1707 			}
1708 		return;
1709 		}
1710 	// register any pending services that require a target
1711 	UpdateSRVRecords(m);
1712 
1713 	// Deliver success to client
1714 	if (!hi) { LogMsg("HostnameCallback invoked with orphaned address record"); return; }
1715 	if (rr->resrec.rrtype == kDNSType_A)
1716 		LogMsg("Registered hostname %##s IP %.4a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv4);
1717 	else
1718 		LogMsg("Registered hostname %##s IP %.16a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
1719 
1720 	rr->RecordContext = (void *)hi->StatusContext;
1721 	if (hi->StatusCallback)
1722 		hi->StatusCallback(m, rr, result); // client may NOT make API calls here
1723 	rr->RecordContext = (void *)hi;
1724 	}
1725 
1726 // register record or begin NAT traversal
1727 mDNSlocal void AdvertiseHostname(mDNS *m, uDNS_HostnameInfo *h)
1728 	{
1729 	uDNS_GlobalInfo *u = &m->uDNS_info;
1730 
1731 	if (u->AdvertisedV4.ip.v4.NotAnInteger && h->arv4->uDNS_info.state == regState_Unregistered)
1732 		{
1733 		if (IsPrivateV4Addr(&u->AdvertisedV4))
1734 			StartGetPublicAddr(m, h->arv4);
1735 		else
1736 			{
1737 			LogMsg("Advertising %##s IP %.4a", h->arv4->resrec.name->c, &u->AdvertisedV4.ip.v4);
1738 			uDNS_RegisterRecord(m, h->arv4);
1739 			}
1740 		}
1741 	if (u->AdvertisedV6.ip.v6.b[0] && h->arv6->uDNS_info.state == regState_Unregistered)
1742 		{
1743 		LogMsg("Advertising %##s IP %.16a", h->arv4->resrec.name->c, &u->AdvertisedV6.ip.v6);
1744 		uDNS_RegisterRecord(m, h->arv6);
1745 		}
1746 	}
1747 
1748 mDNSlocal void FoundStaticHostname(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1749 	{
1750 	const domainname *pktname = &answer->rdata->u.name;
1751 	domainname *storedname = &m->uDNS_info.StaticHostname;
1752 	uDNS_HostnameInfo *h = m->uDNS_info.Hostnames;
1753 
1754 	(void)question;
1755 
1756 	debugf("FoundStaticHostname: %##s -> %##s (%s)", question->qname.c, answer->rdata->u.name.c, AddRecord ? "added" : "removed");
1757 	if (AddRecord && !SameDomainName(pktname, storedname))
1758 		{
1759 		AssignDomainName(storedname, pktname);
1760 		while (h)
1761 			{
1762 			if ((h->arv4 && (h->arv4->uDNS_info.state == regState_FetchingZoneData || h->arv4->uDNS_info.state == regState_Pending || h->arv4->uDNS_info.state == regState_NATMap)) ||
1763 			    (h->arv6 && (h->arv6->uDNS_info.state == regState_FetchingZoneData || h->arv6->uDNS_info.state == regState_Pending)))
1764 				{
1765 				// 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
1766 				m->uDNS_info.DelaySRVUpdate = mDNStrue;
1767 				m->uDNS_info.NextSRVUpdate = mDNSPlatformTimeNow(m) + (5 * mDNSPlatformOneSecond);
1768 				return;
1769 				}
1770 			h = h->next;
1771 			}
1772 		UpdateSRVRecords(m);
1773 		}
1774 	else if (!AddRecord && SameDomainName(pktname, storedname))
1775 		{
1776 		storedname->c[0] = 0;
1777 		UpdateSRVRecords(m);
1778 		}
1779 	}
1780 
1781 mDNSlocal void GetStaticHostname(mDNS *m)
1782 	{
1783 	char buf[MAX_ESCAPED_DOMAIN_NAME];
1784 	DNSQuestion *q = &m->uDNS_info.ReverseMap;
1785 	mDNSu8 *ip = m->uDNS_info.AdvertisedV4.ip.v4.b;
1786 	mStatus err;
1787 
1788 	if (m->uDNS_info.ReverseMapActive)
1789 		{
1790 		uDNS_StopQuery(m, q);
1791 		m->uDNS_info.ReverseMapActive = mDNSfalse;
1792 		}
1793 
1794 	m->uDNS_info.StaticHostname.c[0] = 0;
1795 	if (!m->uDNS_info.AdvertisedV4.ip.v4.NotAnInteger) return;
1796 	ubzero(q, sizeof(*q));
1797 	mDNS_snprintf(buf, MAX_ESCAPED_DOMAIN_NAME, "%d.%d.%d.%d.in-addr.arpa.", ip[3], ip[2], ip[1], ip[0]);
1798     if (!MakeDomainNameFromDNSNameString(&q->qname, buf)) { LogMsg("Error: GetStaticHostname - bad name %s", buf); return; }
1799 
1800 	q->InterfaceID      = mDNSInterface_Any;
1801     q->Target           = zeroAddr;
1802     q->qtype            = kDNSType_PTR;
1803     q->qclass           = kDNSClass_IN;
1804     q->LongLived        = mDNSfalse;
1805     q->ExpectUnique     = mDNSfalse;
1806     q->ForceMCast       = mDNSfalse;
1807     q->QuestionCallback = FoundStaticHostname;
1808     q->QuestionContext  = mDNSNULL;
1809 
1810 	err = uDNS_StartQuery(m, q);
1811 	if (err) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err);
1812 	else m->uDNS_info.ReverseMapActive = mDNStrue;
1813 	}
1814 
1815 mDNSlocal void AssignHostnameInfoAuthRecord(mDNS *m, uDNS_HostnameInfo *hi, int type)
1816 	{
1817 	AuthRecord **dst = (type == mDNSAddrType_IPv4 ? &hi->arv4 : &hi->arv6);
1818 	AuthRecord *ar =  umalloc(sizeof(*ar));
1819 	uDNS_GlobalInfo *u = &m->uDNS_info;
1820 
1821 	if (type != mDNSAddrType_IPv4 && type != mDNSAddrType_IPv6) { LogMsg("ERROR: AssignHostnameInfoAuthRecord - bad type %d", type); return; }
1822 	if (!ar) { LogMsg("ERROR: AssignHostnameInfoAuthRecord - malloc"); return; }
1823 
1824 	mDNS_SetupResourceRecord(ar, mDNSNULL, 0, type == mDNSAddrType_IPv4 ? kDNSType_A : kDNSType_AAAA,  1, kDNSRecordTypeKnownUnique, HostnameCallback, hi);
1825 	AssignDomainName(ar->resrec.name, &hi->fqdn);
1826 
1827 	// only set RData if we have a valid IP
1828 	if (type == mDNSAddrType_IPv4 && u->AdvertisedV4.ip.v4.NotAnInteger)
1829 		{
1830 		if (u->MappedV4.ip.v4.NotAnInteger) ar->resrec.rdata->u.ipv4 = u->MappedV4.ip.v4;
1831 		else                                ar->resrec.rdata->u.ipv4 = u->AdvertisedV4.ip.v4;
1832 		}
1833 	else if (type == mDNSAddrType_IPv6 && u->AdvertisedV6.ip.v6.b[0])
1834 		{
1835 		ar->resrec.rdata->u.ipv6 = u->AdvertisedV6.ip.v6;
1836 		}
1837 
1838 	ar->uDNS_info.state = regState_Unregistered;
1839 
1840 	if (*dst)
1841 		{
1842 		LogMsg("ERROR: AssignHostnameInfoAuthRecord - overwriting %s AuthRec", type == mDNSAddrType_IPv4 ? "IPv4" : "IPv6");
1843 		unlinkAR(&u->RecordRegistrations, *dst);
1844 		(*dst)->RecordContext = mDNSNULL;  // defensively clear backpointer to avoid doubly-referenced context
1845 		}
1846 
1847 	*dst = ar;
1848 	}
1849 
1850 
1851 // Deregister hostnames and register new names for each host domain with the current global
1852 // values for the hostlabel and primary IP address
1853 mDNSlocal void UpdateHostnameRegistrations(mDNS *m)
1854 	{
1855 	uDNS_GlobalInfo *u = &m->uDNS_info;
1856 	uDNS_HostnameInfo *i;
1857 
1858 	for (i = u->Hostnames; i; i = i->next)
1859 		{
1860 		if (i->arv4 && i->arv4->uDNS_info.state != regState_Unregistered &&
1861 			i->arv4->resrec.rdata->u.ipv4.NotAnInteger != u->AdvertisedV4.ip.v4.NotAnInteger &&
1862 			i->arv4->resrec.rdata->u.ipv4.NotAnInteger !=u->MappedV4.ip.v4.NotAnInteger)
1863 			{
1864 			uDNS_DeregisterRecord(m, i->arv4);
1865 			i->arv4 = mDNSNULL;
1866 			}
1867 		if (i->arv6 && !mDNSPlatformMemSame(i->arv6->resrec.rdata->u.ipv6.b, u->AdvertisedV6.ip.v6.b, 16) && i->arv6->uDNS_info.state != regState_Unregistered)
1868 			{
1869 			uDNS_DeregisterRecord(m, i->arv6);
1870 			i->arv6 = mDNSNULL;
1871 			}
1872 
1873 		if (!i->arv4 && u->AdvertisedV4.ip.v4.NotAnInteger)                    AssignHostnameInfoAuthRecord(m, i, mDNSAddrType_IPv4);
1874 		else if (i->arv4 && i->arv4->uDNS_info.state == regState_Unregistered) i->arv4->resrec.rdata->u.ipv4 = u->AdvertisedV4.ip.v4;  // simply overwrite unregistered
1875 		if (!i->arv6 && u->AdvertisedV6.ip.v6.b[0])                            AssignHostnameInfoAuthRecord(m, i, mDNSAddrType_IPv6);
1876 		else if (i->arv6 &&i->arv6->uDNS_info.state == regState_Unregistered)  i->arv6->resrec.rdata->u.ipv6 = u->AdvertisedV6.ip.v6;
1877 
1878 		AdvertiseHostname(m, i);
1879 		}
1880 	}
1881 
1882 mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
1883    {
1884 	uDNS_GlobalInfo *u = &m->uDNS_info;
1885 	uDNS_HostnameInfo *ptr, *new;
1886 
1887 	mDNS_Lock(m);
1888 
1889 	// check if domain already registered
1890 	for (ptr = u->Hostnames; ptr; ptr = ptr->next)
1891 		{
1892 		if (SameDomainName(fqdn, &ptr->fqdn))
1893 			{ LogMsg("Host Domain %##s already in list", fqdn->c); goto exit; }
1894 		}
1895 
1896 	// allocate and format new address record
1897 	new = umalloc(sizeof(*new));
1898 	if (!new) { LogMsg("ERROR: mDNS_AddDynDNSHostname - malloc"); goto exit; }
1899 	ubzero(new, sizeof(*new));
1900     new->next = u->Hostnames;
1901 	u->Hostnames = new;
1902 
1903 	AssignDomainName(&new->fqdn, fqdn);
1904 	new->StatusCallback = StatusCallback;
1905 	new->StatusContext = StatusContext;
1906 
1907 	if (u->AdvertisedV4.ip.v4.NotAnInteger) AssignHostnameInfoAuthRecord(m, new, mDNSAddrType_IPv4);
1908 	else new->arv4 = mDNSNULL;
1909 	if (u->AdvertisedV6.ip.v6.b[0])         AssignHostnameInfoAuthRecord(m, new, mDNSAddrType_IPv6);
1910 	else new->arv6 = mDNSNULL;
1911 
1912 	 if (u->AdvertisedV6.ip.v6.b[0] || u->AdvertisedV4.ip.v4.NotAnInteger) AdvertiseHostname(m, new);
1913 
1914 exit:
1915 	mDNS_Unlock(m);
1916 	}
1917 
1918 mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn)
1919 	{
1920 	uDNS_GlobalInfo *u = &m->uDNS_info;
1921 	uDNS_HostnameInfo **ptr = &u->Hostnames;
1922 
1923 	mDNS_Lock(m);
1924 
1925 	while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next;
1926 	if (!*ptr) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn->c);
1927 	else
1928 		{
1929 		uDNS_HostnameInfo *hi = *ptr;
1930 		*ptr = (*ptr)->next; // unlink
1931 		if (hi->arv4)
1932 			{
1933 			hi->arv4->RecordContext = mDNSNULL; // about to free wrapper struct
1934 			if (hi->arv4->uDNS_info.state != regState_Unregistered) uDNS_DeregisterRecord(m, hi->arv4);
1935 			else { ufree(hi->arv4); hi->arv4 = mDNSNULL; }
1936 			}
1937 		if (hi->arv6)
1938 			{
1939 			hi->arv6->RecordContext = mDNSNULL; // about to free wrapper struct
1940 			if (hi->arv6->uDNS_info.state != regState_Unregistered) uDNS_DeregisterRecord(m, hi->arv6);
1941 			else { ufree(hi->arv6); hi->arv6 = mDNSNULL; }
1942 			}
1943 		ufree(hi);
1944 		}
1945 	UpdateSRVRecords(m);
1946 	mDNS_Unlock(m);
1947 	}
1948 
1949 mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router)
1950 	{
1951 	uDNS_GlobalInfo *u = &m->uDNS_info;
1952 	mDNSBool v4Changed, v6Changed, RouterChanged;
1953 
1954 	if (v4addr && v4addr->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo V4 address - incorrect type.  Discarding."); return; }
1955 	if (v6addr && v6addr->type != mDNSAddrType_IPv6) { LogMsg("mDNS_SetPrimaryInterfaceInfo V6 address - incorrect type.  Discarding."); return; }
1956 	if (router && router->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-V4 router.  Discarding."); return; }
1957 
1958 	mDNS_Lock(m);
1959 
1960 	v4Changed   = (v4addr ? v4addr->ip.v4.NotAnInteger : 0) != u->AdvertisedV4.ip.v4.NotAnInteger;
1961 	v6Changed   = v6addr ? !mDNSPlatformMemSame(v6addr, &u->AdvertisedV6, sizeof(*v6addr)) : (u->AdvertisedV6.ip.v6.b[0] != 0);
1962 	RouterChanged = (router ? router->ip.v4.NotAnInteger : 0) != u->Router.ip.v4.NotAnInteger;
1963 
1964 #if MDNS_DEBUGMSGS
1965 	if (v4addr && (v4Changed || RouterChanged))
1966 		LogMsg("mDNS_SetPrimaryInterfaceInfo: address changed from %d.%d.%d.%d to %d.%d.%d.%d:%d",
1967 			   u->AdvertisedV4.ip.v4.b[0], u->AdvertisedV4.ip.v4.b[1], u->AdvertisedV4.ip.v4.b[2], u->AdvertisedV4.ip.v4.b[3],
1968 			   v4addr->ip.v4.b[0], v4addr->ip.v4.b[1], v4addr->ip.v4.b[2], v4addr->ip.v4.b[3]);
1969 #endif // MDNS_DEBUGMSGS
1970 
1971 	if ((v4Changed || RouterChanged) && u->MappedV4.ip.v4.NotAnInteger) u->MappedV4.ip.v4.NotAnInteger = 0;
1972 	if (v4addr) u->AdvertisedV4 = *v4addr;  else u->AdvertisedV4.ip.v4.NotAnInteger = 0;
1973 	if (v6addr) u->AdvertisedV6 = *v6addr;  else ubzero(u->AdvertisedV6.ip.v6.b, 16);
1974 	if (router) u->Router       = *router;  else u->Router.ip.v4.NotAnInteger = 0;
1975 	// setting router to zero indicates that nat mappings must be reestablished when router is reset
1976 
1977 	if ((v4Changed || RouterChanged || v6Changed) && v4addr)
1978 		{
1979 		// don't update these unless we've got V4
1980 		UpdateHostnameRegistrations(m);
1981 		UpdateSRVRecords(m);
1982 		GetStaticHostname(m);  // look up reverse map record to find any static hostnames for our IP address
1983 		}
1984 
1985 	mDNS_Unlock(m);
1986 	}
1987 
1988 // ***************************************************************************
1989 #if COMPILER_LIKES_PRAGMA_MARK
1990 #pragma mark - Incoming Message Processing
1991 #endif
1992 
1993 mDNSlocal mDNSBool kaListContainsAnswer(DNSQuestion *question, CacheRecord *rr)
1994 	{
1995 	CacheRecord *ptr;
1996 
1997 	for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next)
1998 		if (SameResourceRecord(&ptr->resrec, &rr->resrec)) return mDNStrue;
1999 
2000 	return mDNSfalse;
2001 	}
2002 
2003 
2004 mDNSlocal void removeKnownAnswer(DNSQuestion *question, CacheRecord *rr)
2005 	{
2006 	CacheRecord *ptr, *prev = mDNSNULL;
2007 
2008 	for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next)
2009 		{
2010 		if (SameResourceRecord(&ptr->resrec, &rr->resrec))
2011 			{
2012 			if (prev) prev->next = ptr->next;
2013 			else question->uDNS_info.knownAnswers = ptr->next;
2014 			ufree(ptr);
2015 			return;
2016 			}
2017 		prev = ptr;
2018 		}
2019 	LogMsg("removeKnownAnswer() called for record not in KA list");
2020 	}
2021 
2022 
2023 mDNSlocal void addKnownAnswer(DNSQuestion *question, const CacheRecord *rr)
2024 	{
2025 	CacheRecord *newCR = mDNSNULL;
2026 	mDNSu32 size;
2027 
2028 	size = sizeof(CacheRecord) + rr->resrec.rdlength - InlineCacheRDSize;
2029 	newCR = (CacheRecord *)umalloc(size);
2030 	if (!newCR) { LogMsg("ERROR: addKnownAnswer - malloc"); return; }
2031 	umemcpy(newCR, rr, size);
2032 	newCR->resrec.rdata = (RData*)&newCR->rdatastorage;
2033 	newCR->resrec.rdata->MaxRDLength = rr->resrec.rdlength;
2034 	newCR->resrec.name = &question->qname;
2035 	newCR->next = question->uDNS_info.knownAnswers;
2036 	question->uDNS_info.knownAnswers = newCR;
2037 	}
2038 
2039 mDNSlocal void deriveGoodbyes(mDNS * const m, DNSMessage *msg, const  mDNSu8 *end, DNSQuestion *question)
2040 	{
2041 	const mDNSu8 *ptr;
2042 	int i;
2043 	CacheRecord *fptr, *ka, *cr, *answers = mDNSNULL, *prev = mDNSNULL;
2044 	LargeCacheRecord *lcr;
2045 
2046 	if (question != m->uDNS_info.CurrentQuery) { LogMsg("ERROR: deriveGoodbyes called without CurrentQuery set!"); return; }
2047 
2048 	ptr = LocateAnswers(msg, end);
2049 	if (!ptr) goto pkt_error;
2050 
2051 	if (!msg->h.numAnswers)
2052 		{
2053 		// delete the whole KA list
2054 		ka = question->uDNS_info.knownAnswers;
2055 		while (ka)
2056 			{
2057 			debugf("deriving goodbye for %##s", ka->resrec.name->c);
2058 
2059 			m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2060 			question->QuestionCallback(m, question, &ka->resrec, mDNSfalse);
2061 			m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2062 			// CAUTION: Need to be careful after calling question->QuestionCallback(),
2063 			// because the client's callback function is allowed to do anything,
2064 			// including starting/stopping queries, registering/deregistering records, etc.
2065 			if (question != m->uDNS_info.CurrentQuery)
2066 				{
2067 				debugf("deriveGoodbyes - question removed via callback.  returning.");
2068 				return;
2069 				}
2070 			fptr = ka;
2071 			ka = ka->next;
2072 			ufree(fptr);
2073 			}
2074 		question->uDNS_info.knownAnswers = mDNSNULL;
2075 		return;
2076 		}
2077 
2078 	// make a list of all the new answers
2079 	for (i = 0; i < msg->h.numAnswers; i++)
2080 		{
2081 		lcr = (LargeCacheRecord *)umalloc(sizeof(LargeCacheRecord));
2082 		if (!lcr) goto malloc_error;
2083 		ubzero(lcr, sizeof(LargeCacheRecord));
2084 		ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAns, lcr);
2085 		if (!ptr) goto pkt_error;
2086 		cr = &lcr->r;
2087 		if (ResourceRecordAnswersQuestion(&cr->resrec, question))
2088 			{
2089 			cr->next = answers;
2090 			answers = cr;
2091 			}
2092 		else ufree(cr);
2093 		}
2094 
2095 	// make sure every known answer is in the answer list
2096 	ka = question->uDNS_info.knownAnswers;
2097 	while (ka)
2098 		{
2099 		for (cr = answers; cr; cr = cr->next)
2100 			{ if (SameResourceRecord(&ka->resrec, &cr->resrec)) break; }
2101 		if (!cr)
2102 			{
2103 			// record is in KA list but not answer list - remove from KA list
2104 			if (prev) prev->next = ka->next;
2105 			else question->uDNS_info.knownAnswers = ka->next;
2106 			debugf("deriving goodbye for %##s", ka->resrec.name->c);
2107 			m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2108 			question->QuestionCallback(m, question, &ka->resrec, mDNSfalse);
2109 			m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2110 			// CAUTION: Need to be careful after calling question->QuestionCallback(),
2111 			// because the client's callback function is allowed to do anything,
2112 			// including starting/stopping queries, registering/deregistering records, etc.
2113 			if (question != m->uDNS_info.CurrentQuery)
2114 				{
2115 				debugf("deriveGoodbyes - question removed via callback.  returning.");
2116 				return;
2117 				}
2118 			fptr = ka;
2119 			ka = ka->next;
2120 			ufree(fptr);
2121 			}
2122 		else
2123 			{
2124 			prev = ka;
2125 			ka = ka->next;
2126 			}
2127 		}
2128 
2129 	// free temp answers list
2130 	cr = answers;
2131 	while (cr) { fptr = cr; cr = cr->next; ufree(fptr); }
2132 
2133 	return;
2134 
2135 	pkt_error:
2136 	LogMsg("ERROR: deriveGoodbyes - received malformed response to query for %##s (%d)",
2137 		   question->qname.c, question->qtype);
2138 	return;
2139 
2140 	malloc_error:
2141 	LogMsg("ERROR: Malloc");
2142 	}
2143 
2144 mDNSlocal void pktResponseHndlr(mDNS * const m, DNSMessage *msg, const  mDNSu8 *end, DNSQuestion *question, mDNSBool llq)
2145 	{
2146 	const mDNSu8 *ptr;
2147 	int i;
2148 	CacheRecord *cr = &m->rec.r;
2149 	mDNSBool goodbye, inKAList;
2150 	int	followedCNames = 0;
2151 	static const int maxCNames = 5;
2152 	LLQ_Info *llqInfo = question->uDNS_info.llq;
2153 	domainname origname;
2154 	origname.c[0] = 0;
2155 
2156 	if (question != m->uDNS_info.CurrentQuery)
2157 		{ LogMsg("ERROR: pktResponseHdnlr called without CurrentQuery ptr set!");  return; }
2158 
2159 	if (question->uDNS_info.Answered == 0 && msg->h.numAnswers == 0 && !llq)
2160 		{
2161 		/* NXDOMAIN error or empty RR set - notify client */
2162 		question->uDNS_info.Answered = mDNStrue;
2163 
2164 		/* Create empty resource record */
2165 		cr->resrec.RecordType = kDNSRecordTypeUnregistered;
2166 		cr->resrec.InterfaceID = mDNSNULL;
2167 		cr->resrec.name = &question->qname;
2168 		cr->resrec.rrtype = question->qtype;
2169 		cr->resrec.rrclass = question->qclass;
2170 		cr->resrec.rroriginalttl = 1; /* What should we use for the TTL? TTL from SOA for domain? */
2171 		cr->resrec.rdlength = 0;
2172 		cr->resrec.rdestimate = 0;
2173 		cr->resrec.namehash = 0;
2174 		cr->resrec.namehash = 0;
2175 		cr->resrec.rdata = (RData*)&cr->rdatastorage;
2176 		cr->resrec.rdata->MaxRDLength = cr->resrec.rdlength;
2177 
2178 		/* Pass empty answer to callback */
2179 		m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2180 		question->QuestionCallback(m, question, &cr->resrec, 0);
2181 		m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2182 		// CAUTION: Need to be careful after calling question->QuestionCallback(),
2183 		// because the client's callback function is allowed to do anything,
2184 		// including starting/stopping queries, registering/deregistering records, etc.
2185 		m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
2186 		if (question != m->uDNS_info.CurrentQuery)
2187 			{
2188 			debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning.");
2189 			return;
2190 			}
2191 		}
2192 
2193 	question->uDNS_info.Answered = mDNStrue;
2194 
2195 	ptr = LocateAnswers(msg, end);
2196 	if (!ptr) goto pkt_error;
2197 
2198 	for (i = 0; i < msg->h.numAnswers; i++)
2199 		{
2200 		ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &m->rec);
2201 		if (!ptr) goto pkt_error;
2202 		if (ResourceRecordAnswersQuestion(&cr->resrec, question))
2203 			{
2204 			goodbye = llq ? ((mDNSs32)cr->resrec.rroriginalttl == -1) : mDNSfalse;
2205 			if (cr->resrec.rrtype == kDNSType_CNAME)
2206 				{
2207 				if (followedCNames > (maxCNames - 1)) LogMsg("Error: too many CNAME referals for question %##s", &origname);
2208 				else
2209 					{
2210 					debugf("Following cname %##s -> %##s", question->qname.c, cr->resrec.rdata->u.name.c);
2211 					if (question->ReturnCNAME)
2212 						{
2213 						m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2214 						question->QuestionCallback(m, question, &cr->resrec, !goodbye);
2215 						m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2216 						// CAUTION: Need to be careful after calling question->QuestionCallback(),
2217 						// because the client's callback function is allowed to do anything,
2218 						// including starting/stopping queries, registering/deregistering records, etc.
2219 						if (question != m->uDNS_info.CurrentQuery)
2220 							{
2221 							m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
2222 							debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning.");
2223 							return;
2224 							}
2225 						}
2226 					AssignDomainName(&origname, &question->qname);
2227 					AssignDomainName(&question->qname, &cr->resrec.rdata->u.name);
2228 					question->qnamehash = DomainNameHashValue(&question->qname);
2229 					followedCNames++;
2230 					i = -1; // restart packet answer matching
2231 					ptr = LocateAnswers(msg, end);
2232 					m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
2233 					continue;
2234 					}
2235 				}
2236 
2237 			inKAList = kaListContainsAnswer(question, cr);
2238 
2239 			if ((goodbye && !inKAList) || (!goodbye && inKAList))
2240 				{
2241 				m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
2242 				continue;  // list up to date
2243 				}
2244 			if (!inKAList) addKnownAnswer(question, cr);
2245 			if (goodbye) removeKnownAnswer(question, cr);
2246 			m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2247 			question->QuestionCallback(m, question, &cr->resrec, !goodbye);
2248 			m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2249 			if (question != m->uDNS_info.CurrentQuery)
2250 				{
2251 				m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
2252 				debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning");
2253 				return;
2254 				}
2255 			}
2256 
2257 		m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
2258 		}
2259 
2260 	if (!llq || llqInfo->state == LLQ_Poll || llqInfo->deriveRemovesOnResume)
2261 		{
2262 		deriveGoodbyes(m, msg, end,question);
2263 		if (llq && llqInfo->deriveRemovesOnResume) llqInfo->deriveRemovesOnResume = mDNSfalse;
2264 		}
2265 
2266 	// Our interval may be set lower to recover from failures -- now that we have an answer, fully back off retry.
2267 	// If the server advertised an LLQ-specific port number then that implies that this zone
2268 	// *wants* to support LLQs, so if the setup fails (e.g. because we are behind a NAT)
2269 	// then we use a slightly faster polling rate to give slightly better user experience.
2270 	if (llq && llqInfo->state == LLQ_Poll && llqInfo->servPort.NotAnInteger) question->ThisQInterval = LLQ_POLL_INTERVAL;
2271 	else if (question->ThisQInterval < MAX_UCAST_POLL_INTERVAL) question->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
2272 	return;
2273 
2274 	pkt_error:
2275 	LogMsg("ERROR: pktResponseHndlr - received malformed response to query for %##s (%d)",
2276 		   question->qname.c, question->qtype);
2277 	return;
2278 	}
2279 
2280 mDNSlocal void simpleResponseHndlr(mDNS * const m, DNSMessage *msg, const  mDNSu8 *end, DNSQuestion *question, void *context)
2281 	{
2282 	(void)context; // unused
2283 	pktResponseHndlr(m, msg, end, question, mDNSfalse);
2284 	}
2285 
2286 mDNSlocal void llqResponseHndlr(mDNS * const m, DNSMessage *msg, const  mDNSu8 *end, DNSQuestion *question, void *context)
2287 	{
2288 	(void)context; // unused
2289 	pktResponseHndlr(m, msg, end, question, mDNStrue);
2290 	}
2291 
2292 mDNSlocal mStatus ParseTSIGError(mDNS *m, const DNSMessage *msg, const mDNSu8 *end, const domainname *displayname)
2293 	{
2294 	LargeCacheRecord lcr;
2295 	const mDNSu8 *ptr;
2296 	mStatus err = mStatus_NoError;
2297 	int i;
2298 
2299 	ptr = LocateAdditionals(msg, end);
2300 	if (!ptr) goto finish;
2301 
2302 	for (i = 0; i < msg->h.numAdditionals; i++)
2303 		{
2304 		ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
2305 		if (!ptr) goto finish;
2306 		if (lcr.r.resrec.rrtype == kDNSType_TSIG)
2307 			{
2308 			mDNSu32 macsize;
2309 		    mDNSu8 *rd = lcr.r.resrec.rdata->u.data;
2310 			mDNSu8 *rdend = rd + MaximumRDSize;
2311 			int alglen = DomainNameLength(&lcr.r.resrec.rdata->u.name);
2312 
2313 			if (rd +  alglen > rdend) goto finish;
2314 			rd += alglen;                                       // algorithm name
2315 			if (rd + 6 > rdend) goto finish;
2316 			rd += 6;                                            // 48-bit timestamp
2317 			if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
2318 			rd += sizeof(mDNSOpaque16);                         // fudge
2319 			if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
2320 			macsize = mDNSVal16(*(mDNSOpaque16 *)rd);
2321 			rd += sizeof(mDNSOpaque16);                         // MAC size
2322 			if (rd + macsize > rdend) goto finish;
2323 			rd += macsize;
2324 			if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
2325 			rd += sizeof(mDNSOpaque16);                         // orig id
2326 			if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
2327 			err = mDNSVal16(*(mDNSOpaque16 *)rd);               // error code
2328 
2329 			if (err ==  TSIG_ErrBadSig)      { LogMsg("%##s: bad signature", displayname->c);              err = mStatus_BadSig;     }
2330 			else if (err == TSIG_ErrBadKey)  { LogMsg("%##s: bad key", displayname->c);                    err = mStatus_BadKey;     }
2331 			else if (err == TSIG_ErrBadTime) { LogMsg("%##s: bad time", displayname->c);                   err = mStatus_BadTime;    }
2332 			else if (err)                    { LogMsg("%##s: unknown tsig error %d", displayname->c, err); err = mStatus_UnknownErr; }
2333 			goto finish;
2334 			}
2335 		}
2336 
2337 	finish:
2338 	return err;
2339 	}
2340 
2341 mDNSlocal mStatus checkUpdateResult(domainname *displayname, mDNSu8 rcode, mDNS *m, const DNSMessage *msg, const mDNSu8 *end)
2342 	{
2343 	(void)msg;  // currently unused, needed for TSIG errors
2344 	if (!rcode) return mStatus_NoError;
2345 	else if (rcode == kDNSFlag1_RC_YXDomain)
2346 		{
2347 		debugf("name in use: %##s", displayname->c);
2348 		return mStatus_NameConflict;
2349 		}
2350 	else if (rcode == kDNSFlag1_RC_Refused)
2351 		{
2352 		LogMsg("Update %##s refused", displayname->c);
2353 		return mStatus_Refused;
2354 		}
2355 	else if (rcode == kDNSFlag1_RC_NXRRSet)
2356 		{
2357 		LogMsg("Reregister refused (NXRRSET): %##s", displayname->c);
2358 		return mStatus_NoSuchRecord;
2359 		}
2360 	else if (rcode == kDNSFlag1_RC_NotAuth)
2361 		{
2362 		// TSIG errors should come with FmtErr as per RFC 2845, but BIND 9 sends them with NotAuth so we look here too
2363 		mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
2364 		if (!tsigerr)
2365 			{
2366 			LogMsg("Permission denied (NOAUTH): %##s", displayname->c);
2367 			return mStatus_UnknownErr;
2368 			}
2369 		else return tsigerr;
2370 		}
2371 	else if (rcode == kDNSFlag1_RC_FmtErr)
2372 		{
2373 		mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
2374 		if (!tsigerr)
2375 			{
2376 			LogMsg("Format Error: %##s", displayname->c);
2377 			return mStatus_UnknownErr;
2378 			}
2379 		else return tsigerr;
2380 		}
2381 	else
2382 		{
2383 		LogMsg("Update %##s failed with rcode %d", displayname->c, rcode);
2384 		return mStatus_UnknownErr;
2385 		}
2386 	}
2387 
2388 mDNSlocal void hndlServiceUpdateReply(mDNS * const m, ServiceRecordSet *srs,  mStatus err)
2389 	{
2390 	mDNSBool InvokeCallback = mDNSfalse;
2391 	uDNS_RegInfo *info = &srs->uDNS_info;
2392 	NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
2393 	ExtraResourceRecord **e = &srs->Extras;
2394 	AuthRecord *txt = &srs->RR_TXT;
2395 	uDNS_RegInfo *txtInfo = &txt->uDNS_info;
2396 	switch (info->state)
2397 		{
2398 		case regState_Pending:
2399 			if (err == mStatus_NameConflict && !info->TestForSelfConflict)
2400 				{
2401 				info->TestForSelfConflict = mDNStrue;
2402 				debugf("checking for self-conflict of service %##s", srs->RR_SRV.resrec.name->c);
2403 				SendServiceRegistration(m, srs);
2404 				return;
2405 				}
2406 			else if (info->TestForSelfConflict)
2407 				{
2408 				info->TestForSelfConflict = mDNSfalse;
2409 				if (err == mStatus_NoSuchRecord) err = mStatus_NameConflict;  // NoSuchRecord implies that our prereq was not met, so we actually have a name conflict
2410 				if (err) info->state = regState_Unregistered;
2411 				else info->state = regState_Registered;
2412 				InvokeCallback = mDNStrue;
2413 				break;
2414 				}
2415 			else if (err == mStatus_UnknownErr && info->lease)
2416 				{
2417 				LogMsg("Re-trying update of service %##s without lease option", srs->RR_SRV.resrec.name->c);
2418 				info->lease = mDNSfalse;
2419 				SendServiceRegistration(m, srs);
2420 				return;
2421 				}
2422 			else
2423 				{
2424 				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
2425 				else info->state = regState_Registered;
2426 				InvokeCallback = mDNStrue;
2427 				break;
2428 				}
2429 		case regState_Refresh:
2430 			if (err)
2431 				{
2432 				LogMsg("Error %ld for refresh of service %##s", err, srs->RR_SRV.resrec.name->c);
2433 				InvokeCallback = mDNStrue;
2434 				info->state = regState_Unregistered;
2435 				}
2436 			else info->state = regState_Registered;
2437 			break;
2438 		case regState_DeregPending:
2439 			if (err) LogMsg("Error %ld for deregistration of service %##s", err, srs->RR_SRV.resrec.name->c);
2440 			if (info->SRVChanged)
2441 				{
2442 				info->state = regState_NoTarget;  // NoTarget will allow us to pick up new target OR nat traversal state
2443 				break;
2444 				}
2445 			err = mStatus_MemFree;
2446 			InvokeCallback = mDNStrue;
2447 			if (nat)
2448 				{
2449 				if (nat->state == NATState_Deleted) { info->NATinfo = mDNSNULL; FreeNATInfo(m, nat); } // deletion copmleted
2450 				else nat->reg.ServiceRegistration = mDNSNULL;  // allow mapping deletion to continue
2451 				}
2452 			info->state = regState_Unregistered;
2453 			break;
2454 		case regState_DeregDeferred:
2455 			if (err)
2456 				{
2457 				debugf("Error %ld received prior to deferred derigstration of %##s", err, srs->RR_SRV.resrec.name->c);
2458 				err = mStatus_MemFree;
2459 				InvokeCallback = mDNStrue;
2460 				info->state = regState_Unregistered;
2461 				break;
2462 				}
2463 			else
2464 				{
2465 				debugf("Performing deferred deregistration of %##s", srs->RR_SRV.resrec.name->c);
2466 				info->state = regState_Registered;
2467 				SendServiceDeregistration(m, srs);
2468 				return;
2469 				}
2470 		case regState_UpdatePending:
2471 			if (err)
2472 				{
2473 				LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs->RR_SRV.resrec.name->c);
2474 				info->state = regState_Unregistered;
2475 				InvokeCallback = mDNStrue;
2476 				}
2477 			else
2478 				{
2479 				info->state = regState_Registered;
2480 				// deallocate old RData
2481 				if (txtInfo->UpdateRDCallback) txtInfo->UpdateRDCallback(m, txt, txtInfo->OrigRData);
2482 				SetNewRData(&txt->resrec, txtInfo->InFlightRData, txtInfo->InFlightRDLen);
2483 				txtInfo->OrigRData = mDNSNULL;
2484 				txtInfo->InFlightRData = mDNSNULL;
2485 				}
2486 			break;
2487 		case regState_FetchingZoneData:
2488 		case regState_Registered:
2489 		case regState_Cancelled:
2490 		case regState_Unregistered:
2491 		case regState_NATMap:
2492 		case regState_NoTarget:
2493 		case regState_ExtraQueued:
2494 		case regState_NATError:
2495 			LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %ld.  Unlinking.",
2496 				   srs->RR_SRV.resrec.name->c, info->state, err);
2497 			err = mStatus_UnknownErr;
2498 		}
2499 
2500 	if ((info->SRVChanged || info->SRVUpdateDeferred) && (info->state == regState_NoTarget || info->state == regState_Registered))
2501 		{
2502 		if (InvokeCallback)
2503 			{
2504 			info->ClientCallbackDeferred = mDNStrue;
2505 			info->DeferredStatus = err;
2506 			}
2507 		info->SRVChanged = mDNSfalse;
2508 		UpdateSRV(m, srs);
2509 		return;
2510 		}
2511 
2512 	while (*e)
2513 		{
2514 		uDNS_RegInfo *einfo = &(*e)->r.uDNS_info;
2515 		if (einfo->state == regState_ExtraQueued)
2516 			{
2517 			if (info->state == regState_Registered && !err)
2518 				{
2519 				// extra resource record queued for this service - copy zone info and register
2520 				AssignDomainName(&einfo->zone, &info->zone);
2521 				einfo->ns = info->ns;
2522 				einfo->port = info->port;
2523 				einfo->lease = info->lease;
2524 				sendRecordRegistration(m, &(*e)->r);
2525 				e = &(*e)->next;
2526 				}
2527 			else if (err && einfo->state != regState_Unregistered)
2528 				{
2529 				// unlink extra from list
2530 				einfo->state = regState_Unregistered;
2531 				*e = (*e)->next;
2532 				}
2533 			else e = &(*e)->next;
2534 			}
2535 		else e = &(*e)->next;
2536 		}
2537 
2538 	srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL - 1;  // reset retry delay for future refreshes, dereg, etc.
2539 	if (info->state == regState_Unregistered) unlinkSRS(m, srs);
2540 	else if (txtInfo->QueuedRData && info->state == regState_Registered)
2541 		{
2542 		if (InvokeCallback)
2543 			{
2544 			// if we were supposed to give a client callback, we'll do it after we update the primary txt record
2545 			info->ClientCallbackDeferred = mDNStrue;
2546 			info->DeferredStatus = err;
2547 			}
2548 		info->state = regState_UpdatePending;
2549 		txtInfo->InFlightRData = txtInfo->QueuedRData;
2550 		txtInfo->InFlightRDLen = txtInfo->QueuedRDLen;
2551 		info->OrigRData = txt->resrec.rdata;
2552 		info->OrigRDLen = txt->resrec.rdlength;
2553 		txtInfo->QueuedRData = mDNSNULL;
2554 		SendServiceRegistration(m, srs);
2555 		return;
2556 		}
2557 
2558 	m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2559 	if (InvokeCallback) srs->ServiceCallback(m, srs, err);
2560 	else if (info->ClientCallbackDeferred)
2561 		{
2562 		info->ClientCallbackDeferred = mDNSfalse;
2563 		srs->ServiceCallback(m, srs, info->DeferredStatus);
2564 		}
2565 	m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2566 	// NOTE: do not touch structures after calling ServiceCallback
2567 	}
2568 
2569 mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
2570 	{
2571 	uDNS_RegInfo *info = &rr->uDNS_info;
2572 	mDNSBool InvokeCallback = mDNStrue;
2573 
2574 	if (info->state == regState_UpdatePending)
2575 		{
2576 		if (err)
2577 			{
2578 			LogMsg("Update record failed for %##s (err %d)", rr->resrec.name->c, err);
2579 			info->state = regState_Unregistered;
2580 			}
2581 		else
2582 			{
2583 			debugf("Update record %##s - success", rr->resrec.name->c);
2584 			info->state = regState_Registered;
2585 			// deallocate old RData
2586 			if (info->UpdateRDCallback) info->UpdateRDCallback(m, rr, info->OrigRData);
2587 			SetNewRData(&rr->resrec, info->InFlightRData, info->InFlightRDLen);
2588 			info->OrigRData = mDNSNULL;
2589 			info->InFlightRData = mDNSNULL;
2590 			}
2591 		}
2592 
2593 	if (info->state == regState_DeregPending)
2594 		{
2595 		debugf("Received reply for deregister record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype);
2596 		if (err) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %ld",
2597 						rr->resrec.name->c, rr->resrec.rrtype, err);
2598 		err = mStatus_MemFree;
2599 		info->state = regState_Unregistered;
2600 		}
2601 
2602 	if (info->state == regState_DeregDeferred)
2603 		{
2604 		if (err)
2605 			{
2606 			LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %ld",
2607 				   rr->resrec.name->c, rr->resrec.rrtype, err);
2608 			info->state = regState_Unregistered;
2609 			}
2610 		debugf("Calling deferred deregistration of record %##s type %d",  rr->resrec.name->c, rr->resrec.rrtype);
2611 		info->state = regState_Registered;
2612 		uDNS_DeregisterRecord(m, rr);
2613 		return;
2614 		}
2615 
2616 	if (info->state == regState_Pending || info->state == regState_Refresh)
2617 		{
2618 		if (!err)
2619 			{
2620 			info->state = regState_Registered;
2621 			if (info->state == regState_Refresh) InvokeCallback = mDNSfalse;
2622 			}
2623 		else
2624 			{
2625 			if (info->lease && err == mStatus_UnknownErr)
2626 				{
2627 				LogMsg("Re-trying update of record %##s without lease option", rr->resrec.name->c);
2628 				info->lease = mDNSfalse;
2629 				sendRecordRegistration(m, rr);
2630 				return;
2631 				}
2632 			LogMsg("Registration of record %##s type %d failed with error %ld", rr->resrec.name->c, rr->resrec.rrtype, err);
2633 			info->state = regState_Unregistered;
2634 			}
2635 		}
2636 
2637 	if (info->state == regState_Unregistered) unlinkAR(&m->uDNS_info.RecordRegistrations, rr);
2638 	else rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL - 1;  // reset retry delay for future refreshes, dereg, etc.
2639 
2640 	if (info->QueuedRData && info->state == regState_Registered)
2641 		{
2642 		info->state = regState_UpdatePending;
2643 		info->InFlightRData = info->QueuedRData;
2644 		info->InFlightRDLen = info->QueuedRDLen;
2645 		info->OrigRData = rr->resrec.rdata;
2646 		info->OrigRDLen = rr->resrec.rdlength;
2647 		info->QueuedRData = mDNSNULL;
2648 		sendRecordRegistration(m, rr);
2649 		return;
2650 		}
2651 
2652 	if (InvokeCallback)
2653 		{
2654 		m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2655 		if (rr->RecordCallback) rr->RecordCallback(m, rr, err);
2656 		m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2657 		}
2658 	}
2659 
2660 
2661 mDNSlocal void SetUpdateExpiration(mDNS *m, DNSMessage *msg, const mDNSu8 *end, uDNS_RegInfo *info)
2662 	{
2663 	LargeCacheRecord lcr;
2664 	const mDNSu8 *ptr;
2665 	int i;
2666 	mDNSu32 lease = 0;
2667 	mDNSs32 expire;
2668 
2669 	ptr = LocateAdditionals(msg, end);
2670 
2671 	if (info->lease && (ptr = LocateAdditionals(msg, end)))
2672 		{
2673 		for (i = 0; i < msg->h.numAdditionals; i++)
2674 			{
2675 			ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
2676 			if (!ptr) break;
2677 			if (lcr.r.resrec.rrtype == kDNSType_OPT)
2678 				{
2679 				if (lcr.r.resrec.rdlength < LEASE_OPT_RDLEN) continue;
2680 				if (lcr.r.resrec.rdata->u.opt.opt != kDNSOpt_Lease) continue;
2681 				lease = lcr.r.resrec.rdata->u.opt.OptData.lease;
2682 				break;
2683 				}
2684 			}
2685 		}
2686 
2687 	if (lease > 0)
2688 		{
2689 		expire = (mDNSPlatformTimeNow(m) + (((mDNSs32)lease * mDNSPlatformOneSecond)) * 3/4);
2690 		if (info->state == regState_UpdatePending)
2691             // if updating individual record, the service record set may expire sooner
2692 			{ if (expire - info->expire < 0) info->expire = expire; }
2693 		else info->expire = expire;
2694 		}
2695 	else info->lease = mDNSfalse;
2696 	}
2697 
2698 mDNSexport void uDNS_ReceiveNATMap(mDNS *m, mDNSu8 *pkt, mDNSu16 len)
2699 	{
2700 	uDNS_GlobalInfo *u = &m->uDNS_info;
2701 	NATTraversalInfo *ptr = u->NATTraversals;
2702 	NATOp_t op;
2703 
2704 	// check length, version, opcode
2705 	if (len < sizeof(NATPortMapReply) && len < sizeof(NATAddrReply)) { LogMsg("NAT Traversal message too short (%d bytes)", len); return; }
2706 	if (pkt[0] != NATMAP_VERS) { LogMsg("Received NAT Traversal response with version %d (expect version %d)", pkt[0], NATMAP_VERS); return; }
2707 	op = pkt[1];
2708 	if (!(op & NATMAP_RESPONSE_MASK)) { LogMsg("Received NAT Traversal message that is not a response (opcode %d)", op); return; }
2709 
2710 	while (ptr)
2711 		{
2712 		if ((ptr->state == NATState_Request || ptr->state == NATState_Refresh) && (ptr->op | NATMAP_RESPONSE_MASK) == op)
2713 			if (ptr->ReceiveResponse(ptr, m, pkt, len)) break;  // note callback may invalidate ptr if it return value is non-zero
2714 		ptr = ptr->next;
2715 		}
2716 	}
2717 
2718 mDNSlocal const domainname *DNSRelayTestQuestion = (domainname*)
2719 	"\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\xa" "dnsbugtest"
2720 	"\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\x7" "in-addr" "\x4" "arpa";
2721 
2722 // Returns mDNStrue if response was handled
2723 mDNSlocal mDNSBool uDNS_ReceiveTestQuestionResponse(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
2724 	const mDNSAddr *const srcaddr, const mDNSInterfaceID InterfaceID)
2725 	{
2726 	const mDNSu8 *ptr = msg->data;
2727 	DNSQuestion q;
2728 	DNSServer *s;
2729 	mDNSu32 result = 0;
2730 	mDNSBool found = mDNSfalse;
2731 
2732 	// 1. Find out if this is an answer to one of our test questions
2733 	if (msg->h.numQuestions != 1) return(mDNSfalse);
2734 	ptr = getQuestion(msg, ptr, end, InterfaceID, &q);
2735 	if (!ptr) return(mDNSfalse);
2736 	if (q.qtype != kDNSType_PTR || q.qclass != kDNSClass_IN) return(mDNSfalse);
2737 	if (!SameDomainName(&q.qname, DNSRelayTestQuestion)) return(mDNSfalse);
2738 
2739 	// 2. If the DNS relay gave us a positive response, then it's got buggy firmware
2740 	// else, if the DNS relay gave us an error or no-answer response, it passed our test
2741 	if ((msg->h.flags.b[1] & kDNSFlag1_RC) == kDNSFlag1_RC_NoErr && msg->h.numAnswers > 0)
2742 		result = DNSServer_Failed;
2743 	else
2744 		result = DNSServer_Passed;
2745 
2746 	// 3. Find occurrences of this server in our list, and mark them appropriately
2747 	for (s = m->uDNS_info.Servers; s; s = s->next)
2748 		if (mDNSSameAddress(srcaddr, &s->addr) && s->teststate != result)
2749 			{ s->teststate = result; found = mDNStrue; }
2750 
2751 	// 4. Assuming we found the server in question in our list (don't want to risk being victim of a deliberate DOS attack here)
2752 	// log a message to let the user know why Wide-Area Service Discovery isn't working
2753 	if (found && result == DNSServer_Failed)
2754 		LogMsg("NOTE: Wide-Area Service Discovery disabled to avoid crashing defective DNS relay %#a.", srcaddr);
2755 
2756 	return(mDNStrue); // Return mDNStrue to tell uDNS_ReceiveMsg it doens't need to process this packet further
2757 	}
2758 
2759 mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
2760 	const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr,
2761 	const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID)
2762 	{
2763 	DNSQuestion *qptr;
2764 	AuthRecord *rptr;
2765 	ServiceRecordSet *sptr;
2766 	mStatus err = mStatus_NoError;
2767 	uDNS_GlobalInfo *u = &m->uDNS_info;
2768 
2769 	mDNSu8 StdR    = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
2770 	mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
2771 	mDNSu8 QR_OP   = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
2772 	mDNSu8 rcode   = (mDNSu8)(msg->h.flags.b[1] & kDNSFlag1_RC);
2773 
2774 	mDNSs32 timenow = mDNSPlatformTimeNow(m);
2775 
2776     // unused
2777 	(void)dstaddr;
2778 	(void)dstport;
2779 	(void)InterfaceID;
2780 
2781 	if (QR_OP == StdR)
2782 		{
2783 		// !!!KRS we should to a table lookup here to see if it answers an LLQ or a 1-shot
2784 		// LLQ Responses over TCP not currently supported
2785 		if (srcaddr && recvLLQResponse(m, msg, end, srcaddr, srcport, InterfaceID)) return;
2786 
2787 		if (uDNS_ReceiveTestQuestionResponse(m, msg, end, srcaddr, InterfaceID)) return;
2788 
2789 		for (qptr = u->ActiveQueries; qptr; qptr = qptr->next)
2790 			{
2791 			//!!!KRS we should have a hashtable, hashed on message id
2792 			if (qptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
2793 				{
2794 				if (timenow - (qptr->LastQTime + RESPONSE_WINDOW) > 0)
2795 					{ debugf("uDNS_ReceiveMsg - response received after maximum allowed window.  Discarding"); return; }
2796 				if (msg->h.flags.b[0] & kDNSFlag0_TC)
2797 					{ hndlTruncatedAnswer(qptr, srcaddr, m); return; }
2798 				else
2799 					{
2800 					u->CurrentQuery = qptr;
2801 					qptr->uDNS_info.responseCallback(m, msg, end, qptr, qptr->uDNS_info.context);
2802 					u->CurrentQuery = mDNSNULL;
2803 					// Note: responseCallback can invalidate qptr
2804 					return;
2805 					}
2806 				}
2807 			}
2808 		}
2809 	if (QR_OP == UpdateR)
2810 		{
2811 		for (sptr = u->ServiceRegistrations; sptr; sptr = sptr->next)
2812 			{
2813 			if (sptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
2814 				{
2815 				err = checkUpdateResult(sptr->RR_SRV.resrec.name, rcode, m, msg, end);
2816 				if (!err) SetUpdateExpiration(m, msg, end, &sptr->uDNS_info);
2817 				hndlServiceUpdateReply(m, sptr, err);
2818 				return;
2819 				}
2820 			}
2821 		for (rptr = u->RecordRegistrations; rptr; rptr = rptr->next)
2822 			{
2823 			if (rptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
2824 				{
2825 				err = checkUpdateResult(rptr->resrec.name, rcode, m, msg, end);
2826 				if (!err) SetUpdateExpiration(m, msg, end, &rptr->uDNS_info);
2827 				hndlRecordUpdateReply(m, rptr, err);
2828 				return;
2829 				}
2830 			}
2831 		}
2832 	debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg->h.id));
2833 	}
2834 
2835 // lookup a DNS Server, matching by name in split-dns configurations.  Result stored in addr parameter if successful
2836 mDNSlocal DNSServer *GetServerForName(uDNS_GlobalInfo *u, const domainname *name)
2837     {
2838 	DNSServer *curmatch = mDNSNULL, *p = u->Servers;
2839 	int i, curmatchlen = -1;
2840 	int ncount = name ? CountLabels(name) : 0;
2841 
2842 	while (p)
2843 		{
2844 		int scount = CountLabels(&p->domain);
2845 		if (scount <= ncount && scount > curmatchlen)
2846 			{
2847 			// only inspect if server's domain is longer than current best match and shorter than the name itself
2848 			const domainname *tail = name;
2849 			for (i = 0; i < ncount - scount; i++)
2850 				tail = (domainname *)(tail->c + 1 + tail->c[0]);  // find "tail" (scount labels) of name
2851 			if (SameDomainName(tail, &p->domain)) { curmatch = p; curmatchlen = scount; }
2852 			}
2853 		p = p->next;
2854 		}
2855 	return(curmatch);
2856 	}
2857 
2858 // ***************************************************************************
2859 #if COMPILER_LIKES_PRAGMA_MARK
2860 #pragma mark - Query Routines
2861 #endif
2862 
2863 #define sameID(x,y) mDNSPlatformMemSame(x,y,8)
2864 
2865 mDNSlocal void initializeQuery(DNSMessage *msg, DNSQuestion *question)
2866 	{
2867 	ubzero(msg, sizeof(msg));
2868     InitializeDNSMessage(&msg->h, question->uDNS_info.id, uQueryFlags);
2869 	}
2870 
2871 mDNSlocal mStatus constructQueryMsg(DNSMessage *msg, mDNSu8 **endPtr, DNSQuestion *const question)
2872 	{
2873 	initializeQuery(msg, question);
2874 
2875 	*endPtr = putQuestion(msg, msg->data, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
2876     if (!*endPtr)
2877         {
2878         LogMsg("ERROR: Unicast query out of space in packet");
2879         return mStatus_UnknownErr;
2880         }
2881 	return mStatus_NoError;
2882 	}
2883 
2884 mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, DNSQuestion *question, LLQOptData *data, mDNSBool includeQuestion)
2885 	{
2886 	AuthRecord rr;
2887 	ResourceRecord *opt = &rr.resrec;
2888 	rdataOpt *optRD;
2889 
2890 	//!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section
2891 	if (includeQuestion)
2892 		{
2893 		ptr = putQuestion(msg, ptr, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
2894 		if (!ptr) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL; }
2895 		}
2896 	// locate OptRR if it exists, set pointer to end
2897 	// !!!KRS implement me
2898 
2899 
2900 	// format opt rr (fields not specified are zero-valued)
2901 	ubzero(&rr, sizeof(AuthRecord));
2902 	mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
2903 	opt->rdlength = LLQ_OPT_RDLEN;
2904 	opt->rdestimate = LLQ_OPT_RDLEN;
2905 
2906 	optRD = &rr.resrec.rdata->u.opt;
2907 	optRD->opt = kDNSOpt_LLQ;
2908 	optRD->optlen = LLQ_OPTLEN;
2909 	umemcpy(&optRD->OptData.llq, data, sizeof(*data));
2910 	ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.numAdditionals, opt, 0);
2911 	if (!ptr) { LogMsg("ERROR: putLLQ - PutResourceRecordTTLJumbo"); return mDNSNULL; }
2912 
2913 	return ptr;
2914 	}
2915 
2916 
2917 mDNSlocal mDNSBool getLLQAtIndex(mDNS *m, DNSMessage *msg, const mDNSu8 *end, LLQOptData *llq, int index)
2918 	{
2919 	LargeCacheRecord lcr;
2920 	int i;
2921 	const mDNSu8 *ptr;
2922 
2923 	ubzero(&lcr, sizeof(lcr));
2924 
2925 	ptr = LocateAdditionals(msg, end);
2926 	if (!ptr) return mDNSfalse;
2927 
2928 	// find the last additional
2929 	for (i = 0; i < msg->h.numAdditionals; i++)
2930 //		{ ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; }
2931 //!!!KRS workaround for LH server bug, which puts OPT as first additional
2932 		{ ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; if (lcr.r.resrec.rrtype == kDNSType_OPT) break; }
2933 	if (lcr.r.resrec.rrtype != kDNSType_OPT) return mDNSfalse;
2934 	if (lcr.r.resrec.rdlength < (index + 1) * LLQ_OPT_RDLEN) return mDNSfalse;  // rdata too small
2935 	umemcpy(llq, (mDNSu8 *)&lcr.r.resrec.rdata->u.opt.OptData.llq + (index * sizeof(*llq)), sizeof(*llq));
2936 	return mDNStrue;
2937 	}
2938 
2939 mDNSlocal void recvRefreshReply(mDNS *m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *q)
2940 	{
2941 	LLQ_Info *qInfo;
2942 	LLQOptData pktData;
2943 
2944 	qInfo = q->uDNS_info.llq;
2945 	if (!getLLQAtIndex(m, msg, end, &pktData, 0)) { LogMsg("ERROR recvRefreshReply - getLLQAtIndex"); return; }
2946 	if (pktData.llqOp != kLLQOp_Refresh) return;
2947 	if (!sameID(pktData.id, qInfo->id)) { LogMsg("recvRefreshReply - ID mismatch.  Discarding");  return; }
2948 	if (pktData.err != LLQErr_NoError) { LogMsg("recvRefreshReply: received error %d from server", pktData.err); return; }
2949 
2950 	qInfo->expire = mDNSPlatformTimeNow(m) + ((mDNSs32)pktData.lease * mDNSPlatformOneSecond);
2951 	qInfo->retry = qInfo->expire - ((mDNSs32)pktData.lease * mDNSPlatformOneSecond/2);
2952 
2953 	qInfo->origLease = pktData.lease;
2954 	qInfo->state = LLQ_Established;
2955 	}
2956 
2957 mDNSlocal void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease)
2958 	{
2959 	DNSMessage msg;
2960 	mDNSu8 *end;
2961 	LLQOptData llq;
2962 	LLQ_Info *info = q->uDNS_info.llq;
2963 	mStatus err;
2964 	mDNSs32 timenow;
2965 
2966 	timenow = mDNSPlatformTimeNow(m);
2967 	if ((info->state == LLQ_Refresh && info->ntries >= kLLQ_MAX_TRIES) ||
2968 		info->expire - timenow < 0)
2969 		{
2970 		LogMsg("Unable to refresh LLQ %##s - will retry in %d minutes", q->qname.c, kLLQ_DEF_RETRY/60);
2971 		info->state = LLQ_Retry;
2972 		info->retry = mDNSPlatformTimeNow(m) + kLLQ_DEF_RETRY * mDNSPlatformOneSecond;
2973 		info->deriveRemovesOnResume = mDNStrue;
2974 		return;
2975 		//!!!KRS handle this - periodically try to re-establish
2976 		}
2977 
2978 	llq.vers = kLLQ_Vers;
2979 	llq.llqOp = kLLQOp_Refresh;
2980 	llq.err = LLQErr_NoError;
2981 	umemcpy(llq.id, info->id, 8);
2982 	llq.lease = lease;
2983 
2984 	initializeQuery(&msg, q);
2985 	end = putLLQ(&msg, msg.data, q, &llq, mDNStrue);
2986 	if (!end) { LogMsg("ERROR: sendLLQRefresh - putLLQ"); return; }
2987 
2988 	err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL);
2989 	if (err) debugf("ERROR: sendLLQRefresh - mDNSSendDNSMessage returned %ld", err);
2990 
2991 	if (info->state == LLQ_Established) info->ntries = 1;
2992 	else info->ntries++;
2993 	info->state = LLQ_Refresh;
2994 	q->LastQTime = timenow;
2995 	info->retry = (info->expire - q->LastQTime) / 2;
2996 	}
2997 
2998 mDNSlocal mDNSBool recvLLQEvent(mDNS *m, DNSQuestion *q, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, mDNSInterfaceID InterfaceID)
2999 	{
3000 	DNSMessage ack;
3001 	mDNSu8 *ackEnd = ack.data;
3002 	mStatus err;
3003 	LLQOptData opt;
3004 
3005 	(void)InterfaceID;  // unused
3006 
3007     // find Opt RR, verify correct ID
3008 	if (!getLLQAtIndex(m, msg, end, &opt, 0))  { debugf("Pkt does not contain LLQ Opt");                                   return mDNSfalse; }
3009 	if (!q->uDNS_info.llq) { LogMsg("Error: recvLLQEvent - question object does not contain LLQ metadata");                return mDNSfalse; }
3010 	if (!sameID(opt.id, q->uDNS_info.llq->id)) {                                                                           return mDNSfalse; }
3011 	if (opt.llqOp != kLLQOp_Event) { if (!q->uDNS_info.llq->ntries) LogMsg("recvLLQEvent - Bad LLQ Opcode %d", opt.llqOp); return mDNSfalse; }
3012 
3013     // invoke response handler
3014 	m->uDNS_info.CurrentQuery = q;
3015 	q->uDNS_info.responseCallback(m, msg, end, q, q->uDNS_info.context);
3016 	if (m->uDNS_info.CurrentQuery != q) return mDNStrue;
3017 
3018     //  format and send ack
3019 	InitializeDNSMessage(&ack.h, msg->h.id, ResponseFlags);
3020 	ackEnd = putLLQ(&ack, ack.data, mDNSNULL, &opt, mDNSfalse);
3021 	if (!ackEnd) { LogMsg("ERROR: recvLLQEvent - putLLQ");  return mDNSfalse; }
3022 	err = mDNSSendDNSMessage(m, &ack, ackEnd, mDNSInterface_Any, srcaddr, srcport, -1, mDNSNULL);
3023 	if (err) debugf("ERROR: recvLLQEvent - mDNSSendDNSMessage returned %ld", err);
3024 	return mDNStrue;
3025 	}
3026 
3027 
3028 
3029 mDNSlocal void hndlChallengeResponseAck(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q)
3030 	{
3031 	LLQ_Info *info = q->uDNS_info.llq;
3032 
3033 	if (llq->err) { LogMsg("hndlChallengeResponseAck - received error %d from server", llq->err); goto error; }
3034 	if (!sameID(info->id, llq->id)) { LogMsg("hndlChallengeResponseAck - ID changed.  discarding"); return; } // this can happen rarely (on packet loss + reordering)
3035 	info->expire = mDNSPlatformTimeNow(m) + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
3036 	info->retry = info->expire - ((mDNSs32)llq->lease * mDNSPlatformOneSecond / 2);
3037 
3038 	info->origLease = llq->lease;
3039 	info->state = LLQ_Established;
3040 
3041 	q->uDNS_info.responseCallback = llqResponseHndlr;
3042 	llqResponseHndlr(m, pktMsg, end, q, mDNSNULL);
3043 	return;
3044 
3045 	error:
3046 	info->state = LLQ_Error;
3047 	}
3048 
3049 mDNSlocal void sendChallengeResponse(mDNS *m, DNSQuestion *q, LLQOptData *llq)
3050 	{
3051 	LLQ_Info *info = q->uDNS_info.llq;
3052 	DNSMessage response;
3053 	mDNSu8 *responsePtr = response.data;
3054 	mStatus err;
3055 	LLQOptData llqBuf;
3056 	mDNSs32 timenow = mDNSPlatformTimeNow(m);
3057 
3058 	if (info->ntries++ == kLLQ_MAX_TRIES)
3059 		{
3060 		LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s. Will re-try in %d minutes",
3061 			   kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60);
3062 		info->state = LLQ_Retry;
3063 		info->retry = timenow + (kLLQ_DEF_RETRY * mDNSPlatformOneSecond);
3064 		// !!!KRS give a callback error in these cases?
3065 		return;
3066 		}
3067 
3068 	if (!llq)
3069 		{
3070 		llq = &llqBuf;
3071 		llq->vers    = kLLQ_Vers;
3072 		llq->llqOp   = kLLQOp_Setup;
3073 		llq->err     = LLQErr_NoError;
3074 		umemcpy(llq->id, info->id, 8);
3075 		llq->lease    = info->origLease;
3076 		}
3077 
3078 	q->LastQTime = timenow;
3079 	info->retry = timenow  + (kLLQ_INIT_RESEND * info->ntries * mDNSPlatformOneSecond);
3080 
3081 	if (constructQueryMsg(&response, &responsePtr, q)) goto error;
3082 	responsePtr = putLLQ(&response, responsePtr, q, llq, mDNSfalse);
3083 	if (!responsePtr) { LogMsg("ERROR: sendChallengeResponse - putLLQ"); goto error; }
3084 
3085 	err = mDNSSendDNSMessage(m, &response, responsePtr, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL);
3086 	if (err) debugf("ERROR: sendChallengeResponse - mDNSSendDNSMessage returned %ld", err);
3087 	// on error, we procede as normal and retry after the appropriate interval
3088 
3089 	return;
3090 
3091 	error:
3092 	info->state = LLQ_Error;
3093 	}
3094 
3095 
3096 
3097 mDNSlocal void hndlRequestChallenge(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q)
3098 	{
3099 	LLQ_Info *info = q->uDNS_info.llq;
3100 	mDNSs32 timenow = mDNSPlatformTimeNow(m);
3101 	switch(llq->err)
3102 		{
3103 		case LLQErr_NoError: break;
3104 		case LLQErr_ServFull:
3105 			LogMsg("hndlRequestChallenge - received ServFull from server for LLQ %##s.  Retry in %lu sec", q->qname.c, llq->lease);
3106 			info->retry = timenow + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
3107 			info->state = LLQ_Retry;
3108 			simpleResponseHndlr(m, pktMsg, end, q, mDNSNULL);  // get available answers
3109 			info->deriveRemovesOnResume = mDNStrue;
3110 		case LLQErr_Static:
3111 			info->state = LLQ_Static;
3112 			LogMsg("LLQ %##s: static", q->qname.c);
3113 			simpleResponseHndlr(m, pktMsg, end, q, mDNSNULL);
3114 			return;
3115 		case LLQErr_FormErr:
3116 			LogMsg("ERROR: hndlRequestChallenge - received FormErr from server for LLQ %##s", q->qname.c);
3117 			goto error;
3118 		case LLQErr_BadVers:
3119 			LogMsg("ERROR: hndlRequestChallenge - received BadVers from server");
3120 			goto error;
3121 		case LLQErr_UnknownErr:
3122 			LogMsg("ERROR: hndlRequestChallenge - received UnknownErr from server for LLQ %##s", q->qname.c);
3123 			goto error;
3124 		default:
3125 			LogMsg("ERROR: hndlRequestChallenge - received invalid error %d for LLQ %##s", llq->err, q->qname.c);
3126 			goto error;
3127 		}
3128 
3129 	if (info->origLease != llq->lease)
3130 		debugf("hndlRequestChallenge: requested lease %lu, granted lease %lu", info->origLease, llq->lease);
3131 
3132 	// cache expiration in case we go to sleep before finishing setup
3133 	info->origLease = llq->lease;
3134 	info->expire = timenow + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
3135 
3136 	// update state
3137 	info->state = LLQ_SecondaryRequest;
3138 	umemcpy(info->id, llq->id, 8);
3139 	info->ntries = 0; // first attempt to send response
3140 
3141 	sendChallengeResponse(m, q, llq);
3142 	return;
3143 
3144 
3145 	error:
3146 	info->state = LLQ_Error;
3147 	}
3148 
3149 
3150 // response handler for initial and secondary setup responses
3151 mDNSlocal void recvSetupResponse(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, DNSQuestion *q, void *clientContext)
3152 	{
3153 	DNSQuestion pktQuestion;
3154 	LLQOptData llq;
3155 	const mDNSu8 *ptr = pktMsg->data;
3156 	LLQ_Info *info = q->uDNS_info.llq;
3157 	mDNSu8 rcode = (mDNSu8)(pktMsg->h.flags.b[1] & kDNSFlag1_RC);
3158 
3159 	(void)clientContext;  // unused
3160 
3161 	if (rcode && rcode != kDNSFlag1_RC_NXDomain) goto poll;
3162 
3163 	ptr = getQuestion(pktMsg, ptr, end, 0, &pktQuestion);
3164 	if (!ptr) { LogMsg("ERROR: recvSetupResponse - getQuestion"); goto poll; }
3165 	if (!SameDomainName(&q->qname, &pktQuestion.qname))
3166 		{ LogMsg("ERROR: recvSetupResponse - mismatched question in response for llq setup %##s", q->qname.c);   goto poll; }
3167 
3168 	if (!getLLQAtIndex(m, pktMsg, end, &llq, 0)) { debugf("recvSetupResponse - GetLLQAtIndex"); goto poll; }
3169 	if (llq.llqOp != kLLQOp_Setup) { LogMsg("ERROR: recvSetupResponse - bad op %d", llq.llqOp); goto poll; }
3170 	if (llq.vers != kLLQ_Vers) { LogMsg("ERROR: recvSetupResponse - bad vers %d", llq.vers);  goto poll; }
3171 
3172 	if (info->state == LLQ_InitialRequest) { hndlRequestChallenge(m, pktMsg, end, &llq, q); return; }
3173 	if (info->state == LLQ_SecondaryRequest) { hndlChallengeResponseAck(m, pktMsg, end, &llq, q); return; }
3174 	LogMsg("recvSetupResponse - bad state %d", info->state);
3175 
3176 	poll:
3177 	info->state = LLQ_Poll;
3178 	q->uDNS_info.responseCallback = llqResponseHndlr;
3179 	info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL);  // trigger immediate poll
3180 	info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
3181 	}
3182 
3183 mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer)
3184 	{
3185 	DNSMessage msg;
3186 	mDNSu8 *end;
3187 	LLQOptData llqData;
3188 	DNSQuestion *q = info->question;
3189 	mStatus err = mStatus_NoError;
3190 	mDNSs32 timenow = mDNSPlatformTimeNow(m);
3191 	uDNS_GlobalInfo *u = &m->uDNS_info;
3192 
3193 	if (IsPrivateV4Addr(&u->AdvertisedV4))
3194 		{
3195 		if (!u->LLQNatInfo)
3196 			{
3197 			info->state = LLQ_NatMapWait;
3198 			StartLLQNatMap(m);
3199 			return;
3200 			}
3201 		if (u->LLQNatInfo->state == NATState_Error) goto poll;
3202 		if (u->LLQNatInfo->state != NATState_Established && u->LLQNatInfo->state != NATState_Legacy)
3203 			{ info->state = LLQ_NatMapWait; info->NATMap = mDNStrue; return; }
3204 		info->NATMap = mDNStrue;  // this llq references the global llq nat mapping
3205 		}
3206 
3207 	if (info->ntries++ >= kLLQ_MAX_TRIES)
3208 		{
3209 		debugf("startLLQHandshake: %d failed attempts for LLQ %##s.  Polling.", kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60);
3210 		goto poll;
3211 		}
3212 
3213     // set llq rdata
3214 	llqData.vers    = kLLQ_Vers;
3215 	llqData.llqOp   = kLLQOp_Setup;
3216 	llqData.err     = LLQErr_NoError;
3217 	ubzero(llqData.id, 8);
3218 	llqData.lease    = kLLQ_DefLease;
3219 
3220 	initializeQuery(&msg, q);
3221 	end = putLLQ(&msg, msg.data, q, &llqData, mDNStrue);
3222 	if (!end)
3223 		{
3224 		LogMsg("ERROR: startLLQHandshake - putLLQ");
3225 		info->state = LLQ_Error;
3226 		return;
3227 		}
3228 
3229 	if (!defer) // if we are to defer, we simply set the retry timers so the request goes out in the future
3230 		{
3231 		err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL);
3232 		if (err) debugf("ERROR: startLLQHandshake - mDNSSendDNSMessage returned %ld", err);
3233 		// on error, we procede as normal and retry after the appropriate interval
3234 		}
3235 
3236 	// update question/info state
3237 	info->state = LLQ_InitialRequest;
3238 	info->origLease = kLLQ_DefLease;
3239     info->retry = timenow + (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
3240 	q->LastQTime = timenow;
3241 	q->uDNS_info.responseCallback = recvSetupResponse;
3242 	q->uDNS_info.internal = mDNStrue;
3243 	return;
3244 
3245 	poll:
3246 	info->question->uDNS_info.responseCallback = llqResponseHndlr;
3247 	info->state = LLQ_Poll;
3248 	info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL);  // trigger immediate poll
3249 	info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
3250 	}
3251 
3252 // wrapper for startLLQHandshake, invoked by async op callback
3253 mDNSlocal void startLLQHandshakeCallback(mStatus err, mDNS *const m, void *llqInfo, const AsyncOpResult *result)
3254 	{
3255 	LLQ_Info *info = (LLQ_Info *)llqInfo;
3256 	const zoneData_t *zoneInfo = mDNSNULL;
3257 
3258     // check state first to make sure it is OK to touch question object
3259 	if (info->state == LLQ_Cancelled)
3260 		{
3261 		// StopQuery was called while we were getting the zone info
3262 		debugf("startLLQHandshake - LLQ Cancelled.");
3263 		info->question = mDNSNULL;  // question may be deallocated
3264 		ufree(info);
3265 		return;
3266 		}
3267 
3268 	if (!info->question)
3269 		{ LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL question"); goto error; }
3270 
3271 	if (info->state != LLQ_GetZoneInfo)
3272 		{ LogMsg("ERROR: startLLQHandshake - bad state %d", info->state); goto error; }
3273 
3274 	if (err)
3275 		{ LogMsg("ERROR: startLLQHandshakeCallback %##s invoked with error code %ld", info->question->qname.c, err); goto poll; }
3276 
3277 	if (!result)
3278 		{ LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL result and no error code"); goto error; }
3279 
3280 	zoneInfo = &result->zoneData;
3281 
3282 	if (!zoneInfo->llqPort.NotAnInteger)
3283 		{ debugf("LLQ port lookup failed - reverting to polling"); info->servPort.NotAnInteger = 0; goto poll; }
3284 
3285     // cache necessary zone data
3286 	info->servAddr = zoneInfo->primaryAddr;
3287 	info->servPort = zoneInfo->llqPort;
3288     info->ntries = 0;
3289 
3290 	if (info->state == LLQ_SuspendDeferred) info->state = LLQ_Suspended;
3291 	else startLLQHandshake(m, info, mDNSfalse);
3292 	return;
3293 
3294 	poll:
3295 	info->question->uDNS_info.responseCallback = llqResponseHndlr;
3296 	info->state = LLQ_Poll;
3297 	info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL);  // trigger immediate poll
3298 	info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
3299 	return;
3300 
3301 	error:
3302 	info->state = LLQ_Error;
3303 	}
3304 
3305 mDNSlocal mStatus startLLQ(mDNS *m, DNSQuestion *question)
3306     {
3307 	LLQ_Info *info;
3308 	mStatus err = mStatus_NoError;
3309 
3310 	// allocate / init info struct
3311     info = umalloc(sizeof(LLQ_Info));
3312     if (!info) { LogMsg("ERROR: startLLQ - malloc"); return mStatus_NoMemoryErr; }
3313 	ubzero(info, sizeof(LLQ_Info));
3314     info->state = LLQ_GetZoneInfo;
3315 
3316 	// link info/question
3317 	info->question = question;
3318 	question->uDNS_info.llq = info;
3319 
3320 	question->uDNS_info.responseCallback = llqResponseHndlr;
3321 
3322 	err = startGetZoneData(&question->qname, m, mDNSfalse, mDNStrue, startLLQHandshakeCallback, info);
3323     if (err)
3324 		{
3325 		LogMsg("ERROR: startLLQ - startGetZoneData returned %ld", err);
3326 		info->question = mDNSNULL;
3327 		ufree(info);
3328 		question->uDNS_info.llq = mDNSNULL;
3329 		return err;
3330 		}
3331 
3332 	LinkActiveQuestion(&m->uDNS_info, question);
3333 	return err;
3334 	}
3335 
3336 mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID)
3337 	{
3338 	DNSQuestion pktQ, *q;
3339 	uDNS_GlobalInfo *u = &m->uDNS_info;
3340 	const mDNSu8 *ptr = msg->data;
3341 	LLQ_Info *llqInfo;
3342 
3343 	if (!msg->h.numQuestions) return mDNSfalse;
3344 
3345 	ptr = getQuestion(msg, ptr, end, 0, &pktQ);
3346 	if (!ptr) return mDNSfalse;
3347 	pktQ.uDNS_info.id = msg->h.id;
3348 
3349 	q = u->ActiveQueries;
3350 	while (q)
3351 		{
3352 		llqInfo = q->uDNS_info.llq;
3353 		if (q->LongLived &&
3354 			llqInfo &&
3355 			q->qnamehash == pktQ.qnamehash &&
3356 			q->qtype == pktQ.qtype &&
3357 			SameDomainName(&q->qname, &pktQ.qname))
3358 			{
3359 			u->CurrentQuery = q;
3360 			if (llqInfo->state == LLQ_Established || (llqInfo->state == LLQ_Refresh && msg->h.numAnswers))
3361 				{ if (recvLLQEvent(m, q, msg, end, srcaddr, srcport, InterfaceID)) return mDNStrue; }
3362 			else if (msg->h.id.NotAnInteger == q->uDNS_info.id.NotAnInteger)
3363 				{
3364 				if (llqInfo->state == LLQ_Refresh && msg->h.numAdditionals && !msg->h.numAnswers)
3365 					{ recvRefreshReply(m, msg, end, q); return mDNStrue; }
3366 				if (llqInfo->state < LLQ_Static)
3367 					{
3368 					if ((llqInfo->state != LLQ_InitialRequest && llqInfo->state != LLQ_SecondaryRequest) || mDNSSameAddress(srcaddr, &llqInfo->servAddr))
3369 						{ q->uDNS_info.responseCallback(m, msg, end, q, q->uDNS_info.context); return mDNStrue; }
3370 					}
3371 				}
3372 			}
3373 		q = q->next;
3374 		}
3375 	return mDNSfalse;
3376 	}
3377 
3378 mDNSexport mDNSBool uDNS_IsActiveQuery(DNSQuestion *const question, uDNS_GlobalInfo *u)
3379     {
3380 	DNSQuestion *q;
3381 
3382 	for (q = u->ActiveQueries; q; q = q->next)
3383 		{
3384 		if (q == question)
3385 			{
3386 			if (!question->uDNS_info.id.NotAnInteger || question->InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&question->qname))
3387 				LogMsg("Warning: Question %##s in Active Unicast Query list with id %d, interfaceID %p",
3388 					   question->qname.c, question->uDNS_info.id.NotAnInteger, question->InterfaceID);
3389 			return mDNStrue;
3390 			}
3391 		}
3392 	return mDNSfalse;
3393 	}
3394 
3395 // stopLLQ happens IN ADDITION to stopQuery
3396 mDNSlocal void stopLLQ(mDNS *m, DNSQuestion *question)
3397 	{
3398 	LLQ_Info *info = question->uDNS_info.llq;
3399 	(void)m;  // unused
3400 
3401 	if (!question->LongLived) { LogMsg("ERROR: stopLLQ - LongLived flag not set"); return; }
3402 	if (!info)                { LogMsg("ERROR: stopLLQ - llq info is NULL");       return; }
3403 
3404 	switch (info->state)
3405 		{
3406 		case LLQ_UnInit:
3407 			LogMsg("ERROR: stopLLQ - state LLQ_UnInit");
3408 			//!!!KRS should we unlink info<->question here?
3409 			return;
3410 		case LLQ_GetZoneInfo:
3411 		case LLQ_SuspendDeferred:
3412 			info->question = mDNSNULL; // remove ref to question, as it may be freed when we get called back from async op
3413 			info->state = LLQ_Cancelled;
3414 			return;
3415 		case LLQ_Established:
3416 		case LLQ_Refresh:
3417 			// refresh w/ lease 0
3418 			sendLLQRefresh(m, question, 0);
3419 			goto end;
3420 		default:
3421 			debugf("stopLLQ - silently discarding LLQ in state %d", info->state);
3422 			goto end;
3423 		}
3424 
3425 	end:
3426 	if (info->NATMap) info->NATMap = mDNSfalse;
3427 	CheckForUnreferencedLLQMapping(m);
3428 	info->question = mDNSNULL;
3429 	ufree(info);
3430 	question->uDNS_info.llq = mDNSNULL;
3431 	question->LongLived = mDNSfalse;
3432 	}
3433 
3434 mDNSexport mStatus uDNS_StopQuery(mDNS *const m, DNSQuestion *const question)
3435 	{
3436 	uDNS_GlobalInfo *u = &m->uDNS_info;
3437 	DNSQuestion *qptr, *prev = mDNSNULL;
3438 	CacheRecord *ka;
3439 
3440 	qptr = u->ActiveQueries;
3441 	while (qptr)
3442         {
3443         if (qptr == question)
3444             {
3445 			if (question->LongLived && question->uDNS_info.llq)
3446 				stopLLQ(m, question);
3447 			if (m->uDNS_info.CurrentQuery == question)
3448 				m->uDNS_info.CurrentQuery = m->uDNS_info.CurrentQuery->next;
3449 			while (question->uDNS_info.knownAnswers)
3450 				{
3451 				ka = question->uDNS_info.knownAnswers;
3452 				question->uDNS_info.knownAnswers = question->uDNS_info.knownAnswers->next;
3453 				ufree(ka);
3454 				}
3455 			if (prev) prev->next = question->next;
3456             else u->ActiveQueries = question->next;
3457 			return mStatus_NoError;
3458             }
3459         prev = qptr;
3460 		qptr = qptr->next;
3461         }
3462     LogMsg("uDNS_StopQuery: no such active query (%##s)", question->qname.c);
3463     return mStatus_UnknownErr;
3464     }
3465 
3466 mDNSlocal mStatus startQuery(mDNS *const m, DNSQuestion *const question, mDNSBool internal)
3467     {
3468     uDNS_GlobalInfo *u = &m->uDNS_info;
3469     //!!!KRS we should check if the question is already in our activequestion list
3470 	if (!ValidateDomainName(&question->qname))
3471 		{
3472 		LogMsg("Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
3473 		return mStatus_Invalid;
3474 		}
3475 
3476 	question->next = mDNSNULL;
3477 	question->qnamehash = DomainNameHashValue(&question->qname);    // to do quick domain name comparisons
3478     question->uDNS_info.id = newMessageID(u);
3479 	question->uDNS_info.Answered = mDNSfalse;
3480 
3481 	// break here if its and LLQ
3482 	if (question->LongLived) return startLLQ(m, question);
3483 
3484 	question->ThisQInterval = INIT_UCAST_POLL_INTERVAL / 2;
3485 	question->LastQTime = mDNSPlatformTimeNow(m) - question->ThisQInterval;
3486     // store the question/id in active question list
3487 	question->uDNS_info.internal = internal;
3488 	LinkActiveQuestion(u, question);
3489 	question->uDNS_info.knownAnswers = mDNSNULL;
3490 	LogOperation("uDNS startQuery: %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
3491 
3492 	return mStatus_NoError;
3493 	}
3494 
3495 mDNSexport mStatus uDNS_StartQuery(mDNS *const m, DNSQuestion *const question)
3496     {
3497 	ubzero(&question->uDNS_info, sizeof(uDNS_QuestionInfo));
3498 	question->uDNS_info.responseCallback = simpleResponseHndlr;
3499 	question->uDNS_info.context = mDNSNULL;
3500 	//LogOperation("uDNS_StartQuery %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
3501 	return startQuery(m, question, 0);
3502     }
3503 
3504 // explicitly set response handler
3505 mDNSlocal mStatus startInternalQuery(DNSQuestion *q, mDNS *m, InternalResponseHndlr callback, void *hndlrContext)
3506     {
3507 	ubzero(&q->uDNS_info, sizeof(uDNS_QuestionInfo));
3508     q->QuestionContext = hndlrContext;
3509     q->uDNS_info.responseCallback = callback;
3510 	q->uDNS_info.context = hndlrContext;
3511     return startQuery(m, q, 1);
3512     }
3513 
3514 
3515 
3516 // ***************************************************************************
3517 #if COMPILER_LIKES_PRAGMA_MARK
3518 #pragma mark - Domain -> Name Server Conversion
3519 #endif
3520 
3521 
3522 /* startGetZoneData
3523  *
3524  * Asynchronously find the address of the nameserver for the enclosing zone for a given domain name,
3525  * i.e. the server to which update and LLQ requests will be sent for a given name.  Once the address is
3526  * derived, it will be passed to the callback, along with a context pointer.  If the zone cannot
3527  * be determined or if an error occurs, an all-zeros address will be passed and a message will be
3528  * written to the syslog.
3529  *
3530  * If the FindUpdatePort arg is set, the port on which the server accepts dynamic updates is determined
3531  * by querying for the _dns-update._udp.<zone>. SRV record.  Likewise, if the FindLLQPort arg is set,
3532  * the port on which the server accepts long lived queries is determined by querying for
3533  * _dns-llq._udp.<zone>. record.  If either of these queries fail, or flags are not specified,
3534  * the llqPort and updatePort fields in the result structure are set to zero.
3535  *
3536  *  Steps for deriving the zone name are as follows:
3537  *
3538  * Query for an SOA record for the required domain.  If we don't get an answer (or an SOA in the Authority
3539  * section), we strip the leading label from the name and repeat, until we get an answer.
3540  *
3541  * The name of the SOA record is our enclosing zone.  The mname field in the SOA rdata is the domain
3542  * name of the primary NS.
3543  *
3544  * We verify that there is an NS record with this zone for a name and the mname for its rdata.
3545  * (!!!KRS this seems redundant, but BIND does this, and it should normally be zero-overhead since
3546  * the NS query will get us address records in the additionals section, which we'd otherwise have to
3547  * explicitly query for.)
3548  *
3549  * We then query for the address record for this nameserver (if it is not in the addionals section of
3550  * the NS record response.)
3551  */
3552 
3553 
3554 // state machine types and structs
3555 //
3556 
3557 // state machine states
3558 typedef enum
3559     {
3560     init,
3561     lookupSOA,
3562 	foundZone,
3563 	lookupNS,
3564 	foundNS,
3565 	lookupA,
3566 	foundA,
3567 	lookupPort,
3568 	foundPort,
3569 	complete
3570     } ntaState;
3571 
3572 // state machine actions
3573 typedef enum
3574     {
3575     smContinue,  // continue immediately to next state
3576     smBreak,     // break until next packet/timeout
3577 	smError      // terminal error - cleanup and abort
3578     } smAction;
3579 
3580 typedef struct
3581     {
3582     domainname 	origName;            // name we originally try to convert
3583     domainname 	*curSOA;             // name we have an outstanding SOA query for
3584     ntaState  	state;               // determines what we do upon receiving a packet
3585     mDNS	    *m;
3586     domainname  zone;                // left-hand-side of SOA record
3587     mDNSu16     zoneClass;
3588     domainname  ns;                  // mname in SOA rdata, verified in confirmNS state
3589     mDNSv4Addr  addr;                // address of nameserver
3590     DNSQuestion question;            // storage for any active question
3591     DNSQuestion extraQuestion;       // additional storage
3592     mDNSBool    questionActive;      // if true, StopQuery() can be called on the question field
3593     mDNSBool    findUpdatePort;
3594     mDNSBool    findLLQPort;
3595     mDNSIPPort  updatePort;
3596     mDNSIPPort  llqPort;
3597     AsyncOpCallback *callback;       // caller specified function to be called upon completion
3598     void        *callbackInfo;
3599     } ntaContext;
3600 
3601 
3602 // function prototypes (for routines that must be used as fn pointers prior to their definitions,
3603 // and allows states to be read top-to-bottom in logical order)
3604 mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *contextPtr);
3605 mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
3606 mDNSlocal void processSOA(ntaContext *context, ResourceRecord *rr);
3607 mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
3608 mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
3609 mDNSlocal smAction hndlLookupPorts(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
3610 
3611 // initialization
3612 mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdatePort, mDNSBool findLLQPort,
3613 								   AsyncOpCallback callback, void *callbackInfo)
3614     {
3615     ntaContext *context = (ntaContext*)umalloc(sizeof(ntaContext));
3616     if (!context) { LogMsg("ERROR: startGetZoneData - umalloc failed");  return mStatus_NoMemoryErr; }
3617 	ubzero(context, sizeof(ntaContext));
3618     AssignDomainName(&context->origName, name);
3619     context->state = init;
3620     context->m = m;
3621 	context->callback = callback;
3622 	context->callbackInfo = callbackInfo;
3623 	context->findUpdatePort = findUpdatePort;
3624 	context->findLLQPort = findLLQPort;
3625     getZoneData(m, mDNSNULL, mDNSNULL, mDNSNULL, context);
3626     return mStatus_NoError;
3627     }
3628 
3629 // state machine entry routine
3630 mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *contextPtr)
3631     {
3632 	AsyncOpResult result;
3633 	ntaContext *context = (ntaContext*)contextPtr;
3634 	smAction action;
3635 
3636     // unused
3637 	(void)m;
3638 	(void)question;
3639 
3640 	// stop any active question
3641 	if (context->questionActive)
3642 		{
3643 		uDNS_StopQuery(context->m, &context->question);
3644 		context->questionActive = mDNSfalse;
3645 		}
3646 
3647 	if (msg && msg->h.flags.b[2] >> 4 && msg->h.flags.b[2] >> 4 != kDNSFlag1_RC_NXDomain)
3648 		{
3649 		// rcode non-zero, non-nxdomain
3650 		LogMsg("ERROR: getZoneData - received response w/ rcode %d", msg->h.flags.b[2] >> 4);
3651 		goto error;
3652 		}
3653 
3654 	switch (context->state)
3655         {
3656         case init:
3657         case lookupSOA:
3658             action = hndlLookupSOA(msg, end, context);
3659 			if (action == smError) goto error;
3660 			if (action == smBreak) return;
3661 		case foundZone:
3662 		case lookupNS:
3663 			action = confirmNS(msg, end, context);
3664 			if (action == smError) goto error;
3665 			if (action == smBreak) return;
3666 		case foundNS:
3667 		case lookupA:
3668 			action = lookupNSAddr(msg, end, context);
3669 			if (action == smError) goto error;
3670 			if (action == smBreak) return;
3671 		case foundA:
3672 			if (!context->findUpdatePort && !context->findLLQPort)
3673 				{
3674 				context->state = complete;
3675 				break;
3676 				}
3677 		case lookupPort:
3678 			action = hndlLookupPorts(msg, end, context);
3679 			if (action == smError) goto error;
3680 			if (action == smBreak) return;
3681 			if (action == smContinue) context->state = complete;
3682 		case foundPort:
3683 		case complete: break;
3684 		}
3685 
3686 	if (context->state != complete)
3687 		{
3688 		LogMsg("ERROR: getZoneData - exited state machine with state %d", context->state);
3689 		goto error;
3690 		}
3691 
3692 	result.type = zoneDataResult;
3693 	result.zoneData.primaryAddr.ip.v4 = context->addr;
3694 	result.zoneData.primaryAddr.type = mDNSAddrType_IPv4;
3695 	AssignDomainName(&result.zoneData.zoneName, &context->zone);
3696 	result.zoneData.zoneClass = context->zoneClass;
3697 
3698 	if (context->findLLQPort)
3699 		result.zoneData.llqPort = context->llqPort;
3700 	else
3701 		result.zoneData.llqPort = zeroIPPort;
3702 
3703 	if (context->findUpdatePort)
3704 		result.zoneData.updatePort = context->updatePort;
3705         else
3706 		result.zoneData.updatePort = zeroIPPort;
3707 
3708 	context->callback(mStatus_NoError, context->m, context->callbackInfo, &result);
3709 	goto cleanup;
3710 
3711 error:
3712 	if (context && context->callback)
3713 		context->callback(mStatus_UnknownErr, context->m, context->callbackInfo, mDNSNULL);
3714 cleanup:
3715 	if (context && context->questionActive)
3716 		{
3717 		uDNS_StopQuery(context->m, &context->question);
3718 		context->questionActive = mDNSfalse;
3719 		}
3720     if (context) ufree(context);
3721 	}
3722 
3723 mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
3724     {
3725     mStatus err;
3726     LargeCacheRecord lcr;
3727 	ResourceRecord *rr = &lcr.r.resrec;
3728 	DNSQuestion *query = &context->question;
3729 	const mDNSu8 *ptr;
3730 
3731     if (msg)
3732         {
3733         // if msg contains SOA record in answer or authority sections, update context/state and return
3734 		int i;
3735 		ptr = LocateAnswers(msg, end);
3736 		for (i = 0; i < msg->h.numAnswers; i++)
3737 			{
3738 			ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
3739 			if (!ptr) { LogMsg("ERROR: hndlLookupSOA, Answers - GetLargeResourceRecord returned NULL");  return smError; }
3740 			if (rr->rrtype == kDNSType_SOA && SameDomainName(context->curSOA, rr->name))
3741 				{
3742 				processSOA(context, rr);
3743 				return smContinue;
3744 				}
3745 			}
3746 		ptr = LocateAuthorities(msg, end);
3747 		// SOA not in answers, check in authority
3748 		for (i = 0; i < msg->h.numAuthorities; i++)
3749 			{
3750 			ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); ///!!!KRS using type PacketAns for auth
3751 			if (!ptr) { LogMsg("ERROR: hndlLookupSOA, Authority - GetLargeResourceRecord returned NULL");  return smError; }
3752 			if (rr->rrtype == kDNSType_SOA)
3753 				{
3754 				processSOA(context, rr);
3755 				return smContinue;
3756 				}
3757 			}
3758 		}
3759 
3760     if (context->state != init && !context->curSOA->c[0])
3761         {
3762         // we've gone down to the root and have not found an SOA
3763         LogMsg("ERROR: hndlLookupSOA - recursed to root label of %##s without finding SOA",
3764                 context->origName.c);
3765 		return smError;
3766         }
3767 
3768     ubzero(query, sizeof(DNSQuestion));
3769     // chop off leading label unless this is our first try
3770     if (context->state == init)  context->curSOA = &context->origName;
3771     else                         context->curSOA = (domainname *)(context->curSOA->c + context->curSOA->c[0]+1);
3772 
3773     context->state = lookupSOA;
3774     AssignDomainName(&query->qname, context->curSOA);
3775     query->qtype = kDNSType_SOA;
3776     query->qclass = kDNSClass_IN;
3777     err = startInternalQuery(query, context->m, getZoneData, context);
3778 	context->questionActive = mDNStrue;
3779 	if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err);
3780 
3781     return smBreak;     // break from state machine until we receive another packet
3782     }
3783 
3784 mDNSlocal void processSOA(ntaContext *context, ResourceRecord *rr)
3785 	{
3786 	AssignDomainName(&context->zone, rr->name);
3787 	context->zoneClass = rr->rrclass;
3788 	AssignDomainName(&context->ns, &rr->rdata->u.soa.mname);
3789 	context->state = foundZone;
3790 	}
3791 
3792 
3793 mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
3794 	{
3795 	DNSQuestion *query = &context->question;
3796 	mStatus err;
3797 	LargeCacheRecord lcr;
3798 	const ResourceRecord *const rr = &lcr.r.resrec;
3799 	const mDNSu8 *ptr;
3800 	int i;
3801 
3802 	if (context->state == foundZone)
3803 		{
3804 		// we've just learned the zone.  confirm that an NS record exists
3805 		AssignDomainName(&query->qname, &context->zone);
3806 		query->qtype = kDNSType_NS;
3807 		query->qclass = kDNSClass_IN;
3808 		err = startInternalQuery(query, context->m, getZoneData, context);
3809 		context->questionActive = mDNStrue;
3810 		if (err) LogMsg("confirmNS: startInternalQuery returned error %ld (breaking until next periodic retransmission", err);
3811 		context->state = lookupNS;
3812 		return smBreak;  // break from SM until we receive another packet
3813 		}
3814 	else if (context->state == lookupNS)
3815 		{
3816 		ptr = LocateAnswers(msg, end);
3817 		for (i = 0; i < msg->h.numAnswers; i++)
3818 			{
3819 			ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
3820 			if (!ptr) { LogMsg("ERROR: confirmNS, Answers - GetLargeResourceRecord returned NULL");  return smError; }
3821 			if (rr->rrtype == kDNSType_NS &&
3822 				SameDomainName(&context->zone, rr->name) && SameDomainName(&context->ns, &rr->rdata->u.name))
3823 				{
3824 				context->state = foundNS;
3825 				return smContinue;  // next routine will examine additionals section of A record
3826 				}
3827 			}
3828 		debugf("ERROR: could not confirm existence of record %##s NS %##s", context->zone.c, context->ns.c);
3829 		return smError;
3830 		}
3831 	else { LogMsg("ERROR: confirmNS - bad state %d", context->state); return smError; }
3832 	}
3833 
3834 mDNSlocal smAction queryNSAddr(ntaContext *context)
3835 	{
3836 	mStatus err;
3837 	DNSQuestion *query = &context->question;
3838 
3839 	AssignDomainName(&query->qname, &context->ns);
3840 	query->qtype = kDNSType_A;
3841 	query->qclass = kDNSClass_IN;
3842 	err = startInternalQuery(query, context->m, getZoneData, context);
3843 	context->questionActive = mDNStrue;
3844 	if (err) LogMsg("confirmNS: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err);
3845 	context->state = lookupA;
3846 	return smBreak;
3847 	}
3848 
3849 mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
3850 	{
3851 	const mDNSu8 *ptr;
3852 	int i;
3853 	LargeCacheRecord lcr;
3854 	ResourceRecord *rr = &lcr.r.resrec;
3855 
3856 	if (context->state == foundNS)
3857 		{
3858 		// we just found the NS record - look for the corresponding A record in the Additionals section
3859 		if (!msg->h.numAdditionals) return queryNSAddr(context);
3860 		ptr = LocateAdditionals(msg, end);
3861 		if (!ptr)
3862 			{
3863 			LogMsg("ERROR: lookupNSAddr - LocateAdditionals returned NULL, expected %d additionals", msg->h.numAdditionals);
3864 			return queryNSAddr(context);
3865 			}
3866 		else
3867 			{
3868 			for (i = 0; i < msg->h.numAdditionals; i++)
3869 				{
3870 				ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
3871 				if (!ptr)
3872 					{
3873 					LogMsg("ERROR: lookupNSAddr, Additionals - GetLargeResourceRecord returned NULL");
3874 					return queryNSAddr(context);
3875 					}
3876 				if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, rr->name))
3877 					{
3878 					context->addr = rr->rdata->u.ipv4;
3879 					context->state = foundA;
3880 					return smContinue;
3881 					}
3882 				}
3883 			}
3884 		// no A record in Additionals - query the server
3885 		return queryNSAddr(context);
3886 		}
3887 	else if (context->state == lookupA)
3888 		{
3889 		ptr = LocateAnswers(msg, end);
3890 		if (!ptr) { LogMsg("ERROR: lookupNSAddr: LocateAnswers returned NULL");  return smError; }
3891 		for (i = 0; i < msg->h.numAnswers; i++)
3892 			{
3893 			ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
3894 			if (!ptr) { LogMsg("ERROR: lookupNSAddr, Answers - GetLargeResourceRecord returned NULL"); break; }
3895 			if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, rr->name))
3896 				{
3897 				context->addr = rr->rdata->u.ipv4;
3898 				context->state = foundA;
3899 				return smContinue;
3900 				}
3901 			}
3902 		LogMsg("ERROR: lookupNSAddr: Address record not found in answer section");
3903 		return smError;
3904 		}
3905 	else { LogMsg("ERROR: lookupNSAddr - bad state %d", context->state); return smError; }
3906 	}
3907 
3908 mDNSlocal smAction lookupDNSPort(DNSMessage *msg, const mDNSu8 *end, ntaContext *context, char *portName, mDNSIPPort *port)
3909 	{
3910 	int i;
3911 	LargeCacheRecord lcr;
3912 	const mDNSu8 *ptr;
3913 	DNSQuestion *q;
3914 	mStatus err;
3915 
3916 	if (context->state == lookupPort)  // we've already issued the query
3917 		{
3918 		if (!msg) { LogMsg("ERROR: hndlLookupUpdatePort - NULL message"); return smError; }
3919 		ptr = LocateAnswers(msg, end);
3920 		for (i = 0; i < msg->h.numAnswers; i++)
3921 			{
3922 			ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
3923 			if (!ptr) { LogMsg("ERROR: hndlLookupUpdatePort - GetLargeResourceRecord returned NULL");  return smError; }
3924 			if (ResourceRecordAnswersQuestion(&lcr.r.resrec, &context->question))
3925 				{
3926 				*port = lcr.r.resrec.rdata->u.srv.port;
3927 				context->state = foundPort;
3928 				return smContinue;
3929 				}
3930 			}
3931 		debugf("hndlLookupUpdatePort - no answer for type %s", portName);
3932 		port->NotAnInteger = 0;
3933 		context->state = foundPort;
3934 		return smContinue;
3935 		}
3936 
3937 	// query the server for the update port for the zone
3938 	context->state = lookupPort;
3939 	q = &context->question;
3940 	MakeDomainNameFromDNSNameString(&q->qname, portName);
3941 	AppendDomainName(&q->qname, &context->zone);
3942     q->qtype = kDNSType_SRV;
3943     q->qclass = kDNSClass_IN;
3944     err = startInternalQuery(q, context->m, getZoneData, context);
3945 	context->questionActive = mDNStrue;
3946     if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err);
3947     return smBreak;     // break from state machine until we receive another packet
3948 	}
3949 
3950 mDNSlocal smAction hndlLookupPorts(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
3951 	{
3952 	smAction action;
3953 
3954 	if (context->findUpdatePort && !context->updatePort.NotAnInteger)
3955 		{
3956 		action = lookupDNSPort(msg, end, context, UPDATE_PORT_NAME, &context->updatePort);
3957 		if (action != smContinue) return action;
3958 		}
3959 	if (context->findLLQPort && !context->llqPort.NotAnInteger)
3960 		return lookupDNSPort(msg, end, context, LLQ_PORT_NAME, &context->llqPort);
3961 
3962 	return smContinue;
3963 	}
3964 
3965 
3966 // ***************************************************************************
3967 #if COMPILER_LIKES_PRAGMA_MARK
3968 #pragma mark - Truncation Handling
3969 #endif
3970 
3971 typedef struct
3972 	{
3973     DNSQuestion  *question;
3974     DNSMessage *reply;
3975     mDNSu16  replylen;
3976     int nread;
3977     mDNS *m;
3978 	} tcpInfo_t;
3979 
3980 // issue queries over a conected socket
3981 mDNSlocal void conQueryCallback(int sd, void *context, mDNSBool ConnectionEstablished)
3982 	{
3983 	mStatus err = 0;
3984 	char msgbuf[356];  // 96 (hdr) + 256 (domain) + 4 (class/type)
3985 	DNSMessage *msg;
3986 	mDNSu8 *end;
3987 	tcpInfo_t *info = (tcpInfo_t *)context;
3988 	DNSQuestion *question = info->question;
3989 	int n;
3990 	mDNS *m = info->m;
3991 
3992 	mDNS_Lock(m);
3993 
3994 	if (ConnectionEstablished)
3995 		{
3996 		// connection is established - send the message
3997 		msg = (DNSMessage *)&msgbuf;
3998 		err = constructQueryMsg(msg, &end, question);
3999 		if (err) { LogMsg("ERROR: conQueryCallback: constructQueryMsg - %ld", err);  goto error; }
4000 		err = mDNSSendDNSMessage(m, msg, end, mDNSInterface_Any, &zeroAddr, zeroIPPort, sd, mDNSNULL);
4001 		question->LastQTime = mDNSPlatformTimeNow(m);
4002 		if (err) { debugf("ERROR: conQueryCallback: mDNSSendDNSMessage_tcp - %ld", err);  goto error; }
4003 		}
4004 	else
4005 		{
4006 		if (!info->nread)
4007 			{
4008 			// read msg len
4009 			mDNSu8 lenbuf[2];
4010 			n = mDNSPlatformReadTCP(sd, lenbuf, 2);
4011 			if (n != 2)
4012 				{
4013 				LogMsg("ERROR:conQueryCallback - attempt to read message length failed (read returned %d)", n);
4014 				goto error;
4015 				}
4016 			info->replylen = (mDNSu16)((mDNSu16)lenbuf[0] << 8 | lenbuf[1]);
4017 			if (info->replylen < sizeof(DNSMessageHeader))
4018 				{ LogMsg("ERROR: conQueryCallback - length too short (%d bytes)", info->replylen);  goto error; }
4019 			info->reply = umalloc(info->replylen);
4020 			if (!info->reply) { LogMsg("ERROR: conQueryCallback - malloc failed"); goto error; }
4021 			}
4022 		n = mDNSPlatformReadTCP(sd, ((char *)info->reply) + info->nread, info->replylen - info->nread);
4023 		if (n < 0) { LogMsg("ERROR: conQueryCallback - read returned %d", n); goto error; }
4024 		info->nread += n;
4025 		if (info->nread == info->replylen)
4026 			{
4027 			// Finished reading message; convert the integer parts which are in IETF byte-order (MSB first, LSB second)
4028 			DNSMessage *msg = info->reply;
4029 			mDNSu8 *ptr = (mDNSu8 *)&msg->h.numQuestions;
4030 			msg->h.numQuestions   = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
4031 			msg->h.numAnswers     = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
4032 			msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]);
4033 			msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]);
4034 			uDNS_ReceiveMsg(m, msg, (mDNSu8 *)msg + info->replylen, mDNSNULL, zeroIPPort, mDNSNULL, zeroIPPort, question->InterfaceID);
4035 			mDNSPlatformTCPCloseConnection(sd);
4036 			ufree(info->reply);
4037 			ufree(info);
4038 			}
4039 		}
4040 
4041 	mDNS_Unlock(m);
4042 	return;
4043 
4044 	error:
4045 	mDNSPlatformTCPCloseConnection(sd);
4046 	if (info->reply) ufree(info->reply);
4047 	ufree(info);
4048 	mDNS_Unlock(m);
4049 	}
4050 
4051 mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question, const  mDNSAddr *src, mDNS *m)
4052 	{
4053 	mStatus connectionStatus;
4054 	uDNS_QuestionInfo *info = &question->uDNS_info;
4055 	int sd;
4056 	tcpInfo_t *context;
4057 
4058 	if (!src) { LogMsg("hndlTruncatedAnswer: TCP DNS response had TC bit set: ignoring"); return; }
4059 
4060 	context = (tcpInfo_t *)umalloc(sizeof(tcpInfo_t));
4061 	if (!context) { LogMsg("ERROR: hndlTruncatedAnswer - memallocate failed"); return; }
4062 	ubzero(context, sizeof(tcpInfo_t));
4063 	context->question = question;
4064 	context->m = m;
4065 	info->id = newMessageID(&m->uDNS_info);
4066 
4067 	connectionStatus = mDNSPlatformTCPConnect(src, UnicastDNSPort, question->InterfaceID, conQueryCallback, context, &sd);
4068 	if (connectionStatus == mStatus_ConnEstablished)  // manually invoke callback if connection completes
4069 		{
4070 		conQueryCallback(sd, context, mDNStrue);
4071 		return;
4072 		}
4073 	if (connectionStatus == mStatus_ConnPending) return; // callback will be automatically invoked when connection completes
4074 	LogMsg("hndlTruncatedAnswer: connection failed");
4075 	uDNS_StopQuery(m, question);  //!!!KRS can we really call this here?
4076 	}
4077 
4078 
4079 // ***************************************************************************
4080 #if COMPILER_LIKES_PRAGMA_MARK
4081 #pragma mark - Dynamic Updates
4082 #endif
4083 
4084 mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr)
4085 	{
4086 	DNSMessage msg;
4087 	mDNSu8 *ptr = msg.data;
4088 	mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
4089 	uDNS_GlobalInfo *u = &m->uDNS_info;
4090 	mDNSOpaque16 id;
4091 	uDNS_RegInfo *regInfo = &rr->uDNS_info;
4092 	mStatus err = mStatus_UnknownErr;
4093 
4094 	id = newMessageID(u);
4095 	InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
4096 	rr->uDNS_info.id = id;
4097 
4098     // set zone
4099 	ptr = putZone(&msg, ptr, end, &regInfo->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
4100 	if (!ptr) goto error;
4101 
4102 	if (regInfo->state == regState_UpdatePending)
4103 		{
4104 		// delete old RData
4105 		SetNewRData(&rr->resrec, regInfo->OrigRData, regInfo->OrigRDLen);
4106 		if (!(ptr = putDeletionRecord(&msg, ptr, &rr->resrec))) goto error;  // delete old rdata
4107 
4108 		// add new RData
4109 		SetNewRData(&rr->resrec, regInfo->InFlightRData, regInfo->InFlightRDLen);
4110 		if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl))) goto error;
4111 		}
4112 
4113 	else
4114 		{
4115 		if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
4116 			{
4117 			// KnownUnique: Delete any previous value
4118 			ptr = putDeleteRRSet(&msg, ptr, rr->resrec.name, rr->resrec.rrtype);
4119 			if (!ptr) goto error;
4120 			}
4121 
4122 		else if (rr->resrec.RecordType != kDNSRecordTypeShared)
4123 			{
4124 			ptr = putPrereqNameNotInUse(rr->resrec.name, &msg, ptr, end);
4125 			if (!ptr) goto error;
4126 			}
4127 
4128 		ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl);
4129 		if (!ptr) goto error;
4130 		}
4131 
4132 	if (rr->uDNS_info.lease)
4133 		{ ptr = putUpdateLease(&msg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) goto error; }
4134 
4135 	err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &regInfo->ns, regInfo->port, -1, GetAuthInfoForName(u, rr->resrec.name));
4136 	if (err) debugf("ERROR: sendRecordRegistration - mDNSSendDNSMessage - %ld", err);
4137 
4138 	SetRecordRetry(m, rr, err);
4139 
4140 	if (regInfo->state != regState_Refresh && regInfo->state != regState_DeregDeferred && regInfo->state != regState_UpdatePending)
4141 		regInfo->state = regState_Pending;
4142 
4143 	return;
4144 
4145 error:
4146 	LogMsg("sendRecordRegistration: Error formatting message");
4147 	if (rr->uDNS_info.state != regState_Unregistered)
4148 		{
4149 		unlinkAR(&u->RecordRegistrations, rr);
4150 		rr->uDNS_info.state = regState_Unregistered;
4151 		}
4152 	m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4153 	if (rr->RecordCallback) rr->RecordCallback(m, rr, err);
4154 	m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4155 	// NOTE: not safe to touch any client structures here
4156 	}
4157 
4158 mDNSlocal void RecordRegistrationCallback(mStatus err, mDNS *const m, void *authPtr, const AsyncOpResult *result)
4159 	{
4160 	AuthRecord *newRR = (AuthRecord*)authPtr;
4161 	const zoneData_t *zoneData = mDNSNULL;
4162 	uDNS_GlobalInfo *u = &m->uDNS_info;
4163 	AuthRecord *ptr;
4164 
4165 	// make sure record is still in list
4166 	for (ptr = u->RecordRegistrations; ptr; ptr = ptr->next)
4167 		if (ptr == newRR) break;
4168 	if (!ptr) { LogMsg("RecordRegistrationCallback - RR no longer in list.  Discarding."); return; }
4169 
4170 	// check error/result
4171 	if (err) { LogMsg("RecordRegistrationCallback: error %ld", err); goto error; }
4172 	if (!result) { LogMsg("ERROR: RecordRegistrationCallback invoked with NULL result and no error"); goto error;  }
4173 	else zoneData = &result->zoneData;
4174 
4175 	if (newRR->uDNS_info.state == regState_Cancelled)
4176 		{
4177 		//!!!KRS we should send a memfree callback here!
4178 		debugf("Registration of %##s type %d cancelled prior to update",
4179 			   newRR->resrec.name->c, newRR->resrec.rrtype);
4180 		newRR->uDNS_info.state = regState_Unregistered;
4181 		unlinkAR(&u->RecordRegistrations, newRR);
4182 		return;
4183 		}
4184 
4185 	if (result->type != zoneDataResult)
4186 		{
4187 		LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type);
4188 		goto error;
4189 		}
4190 
4191 	if (newRR->resrec.rrclass != zoneData->zoneClass)
4192 		{
4193 		LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)",
4194 			   newRR->resrec.rrclass, zoneData->zoneClass);
4195 		goto error;
4196 		}
4197 
4198 	// Don't try to do updates to the root name server.
4199 	// We might be tempted also to block updates to any single-label name server (e.g. com, edu, net, etc.) but some
4200 	// organizations use their own private pseudo-TLD, like ".home", etc, and we don't want to block that.
4201 	if (zoneData->zoneName.c[0] == 0)
4202 		{
4203 		LogMsg("ERROR: Only name server claiming responsibility for \"%##s\" is \"%##s\"!",
4204 			newRR->resrec.name->c, zoneData->zoneName.c);
4205 		err = mStatus_NoSuchNameErr;
4206 		goto error;
4207 		}
4208 
4209 	// cache zone data
4210 	AssignDomainName(&newRR->uDNS_info.zone, &zoneData->zoneName);
4211 	newRR->uDNS_info.ns = zoneData->primaryAddr;
4212 	if (zoneData->updatePort.NotAnInteger) newRR->uDNS_info.port = zoneData->updatePort;
4213 	else
4214 		{
4215 		debugf("Update port not advertised via SRV - guessing port 53, no lease option");
4216 		newRR->uDNS_info.port = UnicastDNSPort;
4217 		newRR->uDNS_info.lease = mDNSfalse;
4218 		}
4219 
4220 	sendRecordRegistration(m, newRR);
4221 	return;
4222 
4223 error:
4224 	if (newRR->uDNS_info.state != regState_Unregistered)
4225 		{
4226 		unlinkAR(&u->RecordRegistrations, newRR);
4227 		newRR->uDNS_info.state = regState_Unregistered;
4228 		}
4229 	m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4230 	if (newRR->RecordCallback)
4231 		newRR->RecordCallback(m, newRR, err);
4232 	m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4233 	// NOTE: not safe to touch any client structures here
4234 	}
4235 
4236 mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs)
4237 	{
4238 	DNSMessage msg;
4239 	mDNSu8 *ptr = msg.data;
4240 	mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
4241 	uDNS_GlobalInfo *u = &m->uDNS_info;
4242 	mDNSOpaque16 id;
4243 	uDNS_RegInfo *rInfo = &srs->uDNS_info;
4244 	mStatus err = mStatus_UnknownErr;
4245 	mDNSIPPort privport;
4246 	NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
4247 	mDNSBool mapped = mDNSfalse;
4248 	domainname target;
4249 	AuthRecord *srv = &srs->RR_SRV;
4250 	mDNSu32 i;
4251 
4252 	privport = zeroIPPort;
4253 
4254 	if (!rInfo->ns.ip.v4.NotAnInteger) { LogMsg("SendServiceRegistration - NS not set!"); return; }
4255 
4256 	id = newMessageID(u);
4257 	InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
4258 
4259 	// setup resource records
4260 	SetNewRData(&srs->RR_PTR.resrec, mDNSNULL, 0);
4261 	SetNewRData(&srs->RR_TXT.resrec, mDNSNULL, 0);
4262 
4263 	// replace port w/ NAT mapping if necessary
4264  	if (nat && nat->PublicPort.NotAnInteger &&
4265 		(nat->state == NATState_Established || nat->state == NATState_Refresh || nat->state == NATState_Legacy))
4266 		{
4267 		privport = srv->resrec.rdata->u.srv.port;
4268 		srv->resrec.rdata->u.srv.port = nat->PublicPort;
4269 		mapped = mDNStrue;
4270 		}
4271 
4272 	// construct update packet
4273     // set zone
4274 	ptr = putZone(&msg, ptr, end, &rInfo->zone, mDNSOpaque16fromIntVal(srv->resrec.rrclass));
4275 	if (!ptr) goto error;
4276 
4277 	if (srs->uDNS_info.TestForSelfConflict)
4278 		{
4279 		// update w/ prereq that SRV already exist to make sure previous registration was ours, and delete any stale TXT records
4280 		if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numPrereqs, &srs->RR_SRV.resrec, 0))) goto error;
4281 		if (!(ptr = putDeleteRRSet(&msg, ptr, srs->RR_TXT.resrec.name, srs->RR_TXT.resrec.rrtype)))       goto error;
4282 		}
4283 
4284 	else if (srs->uDNS_info.state != regState_Refresh && srs->uDNS_info.state != regState_UpdatePending)
4285 		{
4286 		// use SRV name for prereq
4287 		ptr = putPrereqNameNotInUse(srv->resrec.name, &msg, ptr, end);
4288 		if (!ptr) goto error;
4289 		}
4290 
4291 	//!!!KRS  Need to do bounds checking and use TCP if it won't fit!!!
4292 	if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_PTR.resrec, srs->RR_PTR.resrec.rroriginalttl))) goto error;
4293 
4294 	for (i = 0; i < srs->NumSubTypes; i++)
4295 		if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->SubTypes[i].resrec, srs->SubTypes[i].resrec.rroriginalttl))) goto error;
4296 
4297 	if (rInfo->state == regState_UpdatePending) // we're updating the txt record
4298 		{
4299 		AuthRecord *txt = &srs->RR_TXT;
4300 		uDNS_RegInfo *txtInfo = &txt->uDNS_info;
4301 		// delete old RData
4302 		SetNewRData(&txt->resrec, txtInfo->OrigRData, txtInfo->OrigRDLen);
4303 		if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_TXT.resrec))) goto error;  // delete old rdata
4304 
4305 		// add new RData
4306 		SetNewRData(&txt->resrec, txtInfo->InFlightRData, txtInfo->InFlightRDLen);
4307 		if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) goto error;
4308 		}
4309 	else
4310 		if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) goto error;
4311 
4312 	 if (!GetServiceTarget(u, srv, &target))
4313 		{
4314 		debugf("Couldn't get target for service %##s", srv->resrec.name->c);
4315 		rInfo->state = regState_NoTarget;
4316 		return;
4317 		}
4318 
4319 	 if (!SameDomainName(&target, &srv->resrec.rdata->u.srv.target))
4320 		 {
4321 		 AssignDomainName(&srv->resrec.rdata->u.srv.target, &target);
4322 		 SetNewRData(&srv->resrec, mDNSNULL, 0);
4323 		 }
4324 
4325 	ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srv->resrec, srv->resrec.rroriginalttl);
4326 	if (!ptr) goto error;
4327 
4328 	if (srs->uDNS_info.lease)
4329 		{ ptr = putUpdateLease(&msg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) goto error; }
4330 
4331 	err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rInfo->ns, rInfo->port, -1, GetAuthInfoForName(u, srs->RR_SRV.resrec.name));
4332 	if (err) debugf("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %ld", err);
4333 
4334 	if (rInfo->state != regState_Refresh && rInfo->state != regState_DeregDeferred && srs->uDNS_info.state != regState_UpdatePending)
4335 		rInfo->state = regState_Pending;
4336 
4337 	SetRecordRetry(m, &srs->RR_SRV, err);
4338 	rInfo->id = id;
4339 	if (mapped) srv->resrec.rdata->u.srv.port = privport;
4340 	return;
4341 
4342 error:
4343 	LogMsg("SendServiceRegistration - Error formatting message");
4344 	if (mapped) srv->resrec.rdata->u.srv.port = privport;
4345 	unlinkSRS(m, srs);
4346 	rInfo->state = regState_Unregistered;
4347 	m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4348 	srs->ServiceCallback(m, srs, err);
4349 	m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4350 	//!!!KRS will mem still be free'd on error?
4351 	// NOTE: not safe to touch any client structures here
4352 	}
4353 
4354 mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srsPtr, const AsyncOpResult *result)
4355 	{
4356 	ServiceRecordSet *srs = (ServiceRecordSet *)srsPtr;
4357 	const zoneData_t *zoneData = mDNSNULL;
4358 
4359 	if (err) goto error;
4360 	if (!result) { LogMsg("ERROR: serviceRegistrationCallback invoked with NULL result and no error");  goto error; }
4361 	else zoneData = &result->zoneData;
4362 
4363 	if (result->type != zoneDataResult)
4364 		{
4365 		LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type);
4366 		goto error;
4367 		}
4368 
4369 	if (srs->uDNS_info.state == regState_Cancelled)
4370 		{
4371 		// client cancelled registration while fetching zone data
4372 		srs->uDNS_info.state = regState_Unregistered;
4373 		unlinkSRS(m, srs);
4374 		m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4375 		srs->ServiceCallback(m, srs, mStatus_MemFree);
4376 		m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4377 		return;
4378 		}
4379 
4380 	if (srs->RR_SRV.resrec.rrclass != zoneData->zoneClass)
4381 		{
4382 		LogMsg("Service %##s - class does not match zone", srs->RR_SRV.resrec.name->c);
4383 		goto error;
4384 		}
4385 
4386 	// cache zone data
4387 	AssignDomainName(&srs->uDNS_info.zone, &zoneData->zoneName);
4388     srs->uDNS_info.ns.type = mDNSAddrType_IPv4;
4389 	srs->uDNS_info.ns = zoneData->primaryAddr;
4390 	if (zoneData->updatePort.NotAnInteger) srs->uDNS_info.port = zoneData->updatePort;
4391 	else
4392 		{
4393 		debugf("Update port not advertised via SRV - guessing port 53, no lease option");
4394 		srs->uDNS_info.port = UnicastDNSPort;
4395 		srs->uDNS_info.lease = mDNSfalse;
4396 		}
4397 
4398 	if (srs->RR_SRV.resrec.rdata->u.srv.port.NotAnInteger && IsPrivateV4Addr(&m->uDNS_info.AdvertisedV4))
4399 		{ srs->uDNS_info.state = regState_NATMap; StartNATPortMap(m, srs); }
4400 	else SendServiceRegistration(m, srs);
4401 	return;
4402 
4403 error:
4404 	unlinkSRS(m, srs);
4405 	srs->uDNS_info.state = regState_Unregistered;
4406 	m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4407 	srs->ServiceCallback(m, srs, err);
4408 	m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4409 	// NOTE: not safe to touch any client structures here
4410 	}
4411 
4412 mDNSlocal mStatus SetupRecordRegistration(mDNS *m, AuthRecord *rr)
4413 	{
4414 	domainname *target = GetRRDomainNameTarget(&rr->resrec);
4415 	AuthRecord *ptr = m->uDNS_info.RecordRegistrations;
4416 
4417 	while (ptr && ptr != rr) ptr = ptr->next;
4418 	if (ptr) { LogMsg("Error: SetupRecordRegistration - record %##s already in list!", rr->resrec.name->c); return mStatus_AlreadyRegistered; }
4419 
4420 	if (rr->uDNS_info.state == regState_FetchingZoneData ||
4421 		rr->uDNS_info.state == regState_Pending ||
4422 		rr->uDNS_info.state ==  regState_Registered)
4423 		{
4424 		LogMsg("Requested double-registration of physical record %##s type %d",
4425 			   rr->resrec.name->c, rr->resrec.rrtype);
4426 		return mStatus_AlreadyRegistered;
4427 		}
4428 
4429 	rr->resrec.rdlength   = GetRDLength(&rr->resrec, mDNSfalse);
4430 	rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue);
4431 
4432 	if (!ValidateDomainName(rr->resrec.name))
4433 		{
4434 		LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr));
4435 		return mStatus_Invalid;
4436 		}
4437 
4438 	// Don't do this until *after* we've set rr->resrec.rdlength
4439 	if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata))
4440 		{
4441 		LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr));
4442 		return mStatus_Invalid;
4443 		}
4444 
4445 	rr->resrec.namehash   = DomainNameHashValue(rr->resrec.name);
4446 	rr->resrec.rdatahash  = target ? DomainNameHashValue(target) : RDataHashValue(rr->resrec.rdlength, &rr->resrec.rdata->u);
4447 
4448 	rr->uDNS_info.state = regState_FetchingZoneData;
4449 	rr->next = m->uDNS_info.RecordRegistrations;
4450 	m->uDNS_info.RecordRegistrations = rr;
4451 	rr->uDNS_info.lease = mDNStrue;
4452 
4453 	return mStatus_NoError;
4454 	}
4455 
4456 mDNSexport mStatus uDNS_RegisterRecord(mDNS *const m, AuthRecord *const rr)
4457 	{
4458 	mStatus err = SetupRecordRegistration(m, rr);
4459 	if (err) return err;
4460 	else return startGetZoneData(rr->resrec.name, m, mDNStrue, mDNSfalse, RecordRegistrationCallback, rr);
4461 	}
4462 
4463 mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
4464 	{
4465 	uDNS_GlobalInfo *u = &m->uDNS_info;
4466 	DNSMessage msg;
4467 	mDNSu8 *ptr = msg.data;
4468 	mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
4469 	mStatus err;
4470 
4471 	InitializeDNSMessage(&msg.h, rr->uDNS_info.id, UpdateReqFlags);
4472 
4473 	ptr = putZone(&msg, ptr, end, &rr->uDNS_info.zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
4474 	if (!ptr) goto error;
4475 	if (!(ptr = putDeletionRecord(&msg, ptr, &rr->resrec))) goto error;
4476 
4477 	err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rr->uDNS_info.ns, rr->uDNS_info.port, -1, GetAuthInfoForName(u, rr->resrec.name));
4478 	if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %ld", err);
4479 
4480 	SetRecordRetry(m, rr, err);
4481 	rr->uDNS_info.state = regState_DeregPending;
4482 	return;
4483 
4484 	error:
4485 	LogMsg("Error: SendRecordDeregistration - could not contruct deregistration packet");
4486 	unlinkAR(&u->RecordRegistrations, rr);
4487 	rr->uDNS_info.state = regState_Unregistered;
4488 	}
4489 
4490 
4491 
4492 mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr)
4493 	{
4494 	uDNS_GlobalInfo *u = &m->uDNS_info;
4495 	NATTraversalInfo *n = rr->uDNS_info.NATinfo;
4496 
4497 	switch (rr->uDNS_info.state)
4498 		{
4499 		case regState_NATMap:
4500             // we're in the middle of a NAT traversal operation
4501             rr->uDNS_info.NATinfo = mDNSNULL;
4502 			if (!n) LogMsg("uDNS_DeregisterRecord: no NAT info context");
4503 			else FreeNATInfo(m, n); // cause response to outstanding request to be ignored.
4504 			                        // Note: normally here we're trying to determine our public address,
4505 			                        //in which case there is not state to be torn down.  For simplicity,
4506 			                        //we allow other operations to expire.
4507 			rr->uDNS_info.state = regState_Unregistered;
4508 			break;
4509 		case regState_ExtraQueued:
4510 			rr->uDNS_info.state = regState_Unregistered;
4511 			break;
4512 		case regState_FetchingZoneData:
4513 			rr->uDNS_info.state = regState_Cancelled;
4514 			return mStatus_NoError;
4515 		case regState_Refresh:
4516 		case regState_Pending:
4517 		case regState_UpdatePending:
4518 			rr->uDNS_info.state = regState_DeregDeferred;
4519 			LogMsg("Deferring deregistration of record %##s until registration completes", rr->resrec.name->c);
4520 			return mStatus_NoError;
4521 		case regState_Registered:
4522 		case regState_DeregPending:
4523 			break;
4524 		case regState_DeregDeferred:
4525 		case regState_Cancelled:
4526 			LogMsg("Double deregistration of record %##s type %d",
4527 				   rr->resrec.name->c, rr->resrec.rrtype);
4528 			return mStatus_UnknownErr;
4529 		case regState_Unregistered:
4530 			LogMsg("Requested deregistration of unregistered record %##s type %d",
4531 				   rr->resrec.name->c, rr->resrec.rrtype);
4532 			return mStatus_UnknownErr;
4533 		case regState_NATError:
4534 		case  regState_NoTarget:
4535 			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");
4536 			return mStatus_UnknownErr;
4537 		}
4538 
4539 	if (rr->uDNS_info.state == regState_Unregistered)
4540 		{
4541 		// unlink and deliver memfree
4542 
4543 		unlinkAR(&u->RecordRegistrations, rr);
4544 		m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4545 		if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_MemFree);
4546 		m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4547 		return mStatus_NoError;
4548 		}
4549 
4550 	rr->uDNS_info.NATinfo = mDNSNULL;
4551 	if (n) FreeNATInfo(m, n);
4552 
4553 	SendRecordDeregistration(m, rr);
4554 	return mStatus_NoError;
4555 	}
4556 
4557 mDNSexport mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs)
4558 	{
4559 	mDNSu32 i;
4560 	domainname target;
4561 	uDNS_RegInfo *info = &srs->uDNS_info;
4562 	ServiceRecordSet **p = &m->uDNS_info.ServiceRegistrations;
4563 	while (*p && *p != srs) p=&(*p)->next;
4564 	if (*p) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs, srs->RR_SRV.resrec.name->c); return(mStatus_AlreadyRegistered); }
4565 	ubzero(info, sizeof(*info));
4566 	*p = srs;
4567 	srs->next = mDNSNULL;
4568 
4569 	srs->RR_SRV.resrec.rroriginalttl = kWideAreaTTL;
4570 	srs->RR_TXT.resrec.rroriginalttl = kWideAreaTTL;
4571 	srs->RR_PTR.resrec.rroriginalttl = kWideAreaTTL;
4572 	for (i = 0; i < srs->NumSubTypes;i++) srs->SubTypes[i].resrec.rroriginalttl = kWideAreaTTL;
4573 
4574 	info->lease = mDNStrue;
4575 
4576 	srs->RR_SRV.resrec.rdata->u.srv.target.c[0] = 0;
4577 	if (!GetServiceTarget(&m->uDNS_info, &srs->RR_SRV, &target))
4578 		{
4579 		// defer registration until we've got a target
4580 		debugf("uDNS_RegisterService - no target for %##s", srs->RR_SRV.resrec.name->c);
4581 		info->state = regState_NoTarget;
4582 		return mStatus_NoError;
4583 		}
4584 
4585 	info->state = regState_FetchingZoneData;
4586 	return startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
4587 	}
4588 
4589 mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
4590 	{
4591 	uDNS_RegInfo *info = &srs->uDNS_info;
4592 	uDNS_GlobalInfo *u = &m->uDNS_info;
4593 	DNSMessage msg;
4594 	mDNSOpaque16 id;
4595 	mDNSu8 *ptr = msg.data;
4596 	mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
4597 	mStatus err = mStatus_UnknownErr;
4598 	mDNSu32 i;
4599 
4600 	id = newMessageID(u);
4601 	InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
4602 
4603     // put zone
4604 	ptr = putZone(&msg, ptr, end, &info->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
4605 	if (!ptr) { LogMsg("ERROR: SendServiceDeregistration - putZone"); goto error; }
4606 
4607 	if (!(ptr = putDeleteAllRRSets(&msg, ptr, srs->RR_SRV.resrec.name))) goto error;  // this deletes SRV, TXT, and Extras
4608 	if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_PTR.resrec))) goto error;
4609 	for (i = 0; i < srs->NumSubTypes; i++)
4610 		if (!(ptr = putDeletionRecord(&msg, ptr, &srs->SubTypes[i].resrec))) goto error;
4611 
4612 
4613 	err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &info->ns, info->port, -1, GetAuthInfoForName(u, srs->RR_SRV.resrec.name));
4614 	if (err && err != mStatus_TransientErr) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %ld", err); goto error; }
4615 
4616 	SetRecordRetry(m, &srs->RR_SRV, err);
4617     info->id = id;
4618 	info->state = regState_DeregPending;
4619 
4620 	return;
4621 
4622 	error:
4623 	unlinkSRS(m, srs);
4624 	info->state = regState_Unregistered;
4625 	}
4626 
4627 mDNSexport mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs)
4628 	{
4629 	NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
4630 	char *errmsg = "Unknown State";
4631 
4632 	// don't re-register with a new target following deregistration
4633 	srs->uDNS_info.SRVChanged = srs->uDNS_info.SRVUpdateDeferred = mDNSfalse;
4634 
4635 	if (nat)
4636 		{
4637 		if (nat->state == NATState_Established || nat->state == NATState_Refresh || nat->state == NATState_Legacy)
4638 			DeleteNATPortMapping(m, nat, srs);
4639 		nat->reg.ServiceRegistration = mDNSNULL;
4640 		srs->uDNS_info.NATinfo = mDNSNULL;
4641 		FreeNATInfo(m, nat);
4642 		}
4643 
4644 	switch (srs->uDNS_info.state)
4645 		{
4646 		case regState_Unregistered:
4647 			debugf("uDNS_DeregisterService - service %##s not registered", srs->RR_SRV.resrec.name->c);
4648 			return mStatus_BadReferenceErr;
4649 		case regState_FetchingZoneData:
4650 			// let the async op complete, then terminate
4651 			srs->uDNS_info.state = regState_Cancelled;
4652 			return mStatus_NoError;  // deliver memfree upon completion of async op
4653 		case regState_Pending:
4654 		case regState_Refresh:
4655 		case regState_UpdatePending:
4656 			// deregister following completion of in-flight operation
4657 			srs->uDNS_info.state = regState_DeregDeferred;
4658 			return mStatus_NoError;
4659 		case regState_DeregPending:
4660 		case regState_DeregDeferred:
4661 		case regState_Cancelled:
4662 			debugf("Double deregistration of service %##s", srs->RR_SRV.resrec.name->c);
4663 			return mStatus_NoError;
4664 		case regState_NATError:  // not registered
4665 		case regState_NATMap:    // not registered
4666 		case regState_NoTarget:  // not registered
4667 			unlinkSRS(m, srs);
4668 			srs->uDNS_info.state = regState_Unregistered;
4669 			m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4670 			srs->ServiceCallback(m, srs, mStatus_MemFree);
4671 			m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4672 			return mStatus_NoError;
4673 		case regState_Registered:
4674 			srs->uDNS_info.state = regState_DeregPending;
4675 			SendServiceDeregistration(m, srs);
4676 			return mStatus_NoError;
4677 		case regState_ExtraQueued: // only for record registrations
4678 			errmsg = "bad state (regState_ExtraQueued)";
4679 			goto error;
4680 		}
4681 
4682 	error:
4683 	LogMsg("Error, uDNS_DeregisterService: %s", errmsg);
4684 	return mStatus_BadReferenceErr;
4685 	}
4686 
4687 mDNSexport mStatus uDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra)
4688 	{
4689 	mStatus err = mStatus_UnknownErr;
4690 
4691 	extra->r.resrec.RecordType = kDNSRecordTypeShared;  // don't want it to conflict with the service name
4692 	extra->r.RecordCallback = mDNSNULL;  // don't generate callbacks for extra RRs
4693 
4694 	if (sr->uDNS_info.state == regState_Registered || sr->uDNS_info.state == regState_Refresh)
4695 		err = uDNS_RegisterRecord(m, &extra->r);
4696 	else
4697 		{
4698 		err = SetupRecordRegistration(m, &extra->r);
4699 		extra->r.uDNS_info.state = regState_ExtraQueued; // %%% Is it okay to overwrite the previous uDNS_info.state?
4700 		}
4701 
4702 	if (!err)
4703 		{
4704 		extra->next = sr->Extras;
4705 		sr->Extras = extra;
4706 		}
4707 	return err;
4708 	}
4709 
4710 mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr)
4711 	{
4712 	uDNS_GlobalInfo *u = &m->uDNS_info;
4713 	ServiceRecordSet *parent = mDNSNULL;
4714 	AuthRecord *rptr;
4715 	uDNS_RegInfo *info = &rr->uDNS_info;
4716 	regState_t *stateptr = mDNSNULL;
4717 
4718 	// find the record in registered service list
4719 	for (parent = u->ServiceRegistrations; parent; parent = parent->next)
4720 		if (&parent->RR_TXT == rr) { stateptr = &parent->uDNS_info.state; break; }
4721 
4722 	if (!parent)
4723 		{
4724 		// record not part of a service - check individual record registrations
4725 		for (rptr = u->RecordRegistrations; rptr; rptr = rptr->next)
4726 			if (rptr == rr) { stateptr = &rr->uDNS_info.state; break; }
4727 		if (!rptr) goto unreg_error;
4728 		}
4729 
4730 	switch(*stateptr)
4731 		{
4732 		case regState_DeregPending:
4733 		case regState_DeregDeferred:
4734 		case regState_Cancelled:
4735 		case regState_Unregistered:
4736 			// not actively registered
4737 			goto unreg_error;
4738 
4739 		case regState_FetchingZoneData:
4740 		case regState_NATMap:
4741 		case regState_ExtraQueued:
4742 		case regState_NoTarget:
4743 			// change rdata directly since it hasn't been sent yet
4744 			if (info->UpdateRDCallback) info->UpdateRDCallback(m, rr, rr->resrec.rdata);
4745 			SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
4746 			rr->NewRData = mDNSNULL;
4747 			return mStatus_NoError;
4748 
4749 		case regState_Pending:
4750 		case regState_Refresh:
4751 		case regState_UpdatePending:
4752 			// registration in-flight.  queue rdata and return
4753 			if (info->QueuedRData && info->UpdateRDCallback)
4754 				// if unsent rdata is already queued, free it before we replace it
4755 				info->UpdateRDCallback(m, rr, info->QueuedRData);
4756 			info->QueuedRData = rr->NewRData;
4757 			info->QueuedRDLen = rr->newrdlength;
4758 			rr->NewRData = mDNSNULL;
4759 			return mStatus_NoError;
4760 
4761 		case regState_Registered:
4762 			info->OrigRData = rr->resrec.rdata;
4763 			info->OrigRDLen = rr->resrec.rdlength;
4764 			info->InFlightRData = rr->NewRData;
4765 			info->InFlightRDLen = rr->newrdlength;
4766 			rr->NewRData = mDNSNULL;
4767 			*stateptr = regState_UpdatePending;
4768 			if (parent)  SendServiceRegistration(m, parent);
4769 			else sendRecordRegistration(m, rr);
4770 			return mStatus_NoError;
4771 
4772 		case regState_NATError:
4773 			LogMsg("ERROR: uDNS_UpdateRecord called for record %##s with bad state regState_NATError", rr->resrec.name->c);
4774 			return mStatus_UnknownErr;  // states for service records only
4775 		}
4776 
4777 	unreg_error:
4778 	LogMsg("Requested update of record %##s type %d, part of service not currently registered",
4779 		   rr->resrec.name->c, rr->resrec.rrtype);
4780 	return mStatus_Invalid;
4781 	}
4782 
4783 
4784 // ***************************************************************************
4785 #if COMPILER_LIKES_PRAGMA_MARK
4786 #pragma mark - Periodic Execution Routines
4787 #endif
4788 
4789 
4790 mDNSlocal mDNSs32 CheckNATMappings(mDNS *m, mDNSs32 timenow)
4791 	{
4792 	NATTraversalInfo *ptr = m->uDNS_info.NATTraversals;
4793 	mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4794 
4795 	while (ptr)
4796 		{
4797 		NATTraversalInfo *cur = ptr;
4798 		ptr = ptr->next;
4799 		if (cur->op != NATOp_AddrRequest || cur->state != NATState_Established)  // no refresh necessary for established Add requests
4800 			{
4801 			if (cur->retry - timenow < 0)
4802 				{
4803 				if (cur->state == NATState_Established) RefreshNATMapping(cur, m);
4804 				else if (cur->state == NATState_Request || cur->state == NATState_Refresh)
4805 					{
4806 					if (cur->ntries >= NATMAP_MAX_TRIES) cur->ReceiveResponse(cur, m, mDNSNULL, 0); // may invalidate "cur"
4807 					else SendNATMsg(cur, m);
4808 					}
4809 				}
4810 			else if (cur->retry - nextevent < 0) nextevent = cur->retry;
4811 			}
4812 		}
4813 	return nextevent;
4814 	}
4815 
4816 mDNSlocal mDNSs32 CheckQueries(mDNS *m, mDNSs32 timenow)
4817 	{
4818 	DNSQuestion *q;
4819 	uDNS_GlobalInfo *u = &m->uDNS_info;
4820 	LLQ_Info *llq;
4821 	mDNSs32 sendtime;
4822 	mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4823 	DNSMessage msg;
4824 	mStatus err = mStatus_NoError;
4825 	mDNSu8 *end;
4826 	uDNS_QuestionInfo *info;
4827 
4828 	u->CurrentQuery = u->ActiveQueries;
4829 	while (u->CurrentQuery)
4830 		{
4831 		q = u->CurrentQuery;
4832 		info = &q->uDNS_info;
4833 		llq = info->llq;
4834 
4835 		if (!info->internal && ((!q->LongLived && !info->Answered) || (llq && llq->state < LLQ_Established)) &&
4836 			info->RestartTime + RESTART_GOODBYE_DELAY - timenow < 0)
4837 			{
4838 			// if we've been spinning on restart setup, and we have known answers, give goodbyes (they may be re-added later)
4839 			while (info->knownAnswers)
4840 				{
4841 				CacheRecord *cr = info->knownAnswers;
4842 				info->knownAnswers = info->knownAnswers->next;
4843 
4844 				m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4845 				q->QuestionCallback(m, q, &cr->resrec, mDNSfalse);
4846 				m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4847 				ufree(cr);
4848 				if (q != u->CurrentQuery) { debugf("CheckQueries - question removed via callback."); break; }
4849 				}
4850 			}
4851 		if (q != u->CurrentQuery) continue;
4852 
4853 		if (q->LongLived && llq->state != LLQ_Poll)
4854 			{
4855 			if (llq->state >= LLQ_InitialRequest && llq->state <= LLQ_Established)
4856 				{
4857 				if (llq->retry - timenow < 0)
4858 					{
4859 					// sanity check to avoid packet flood bugs
4860 					if (!llq->retry)
4861 						LogMsg("ERROR: retry timer not set for LLQ %##s in state %d", q->qname.c, llq->state);
4862 					else if (llq->state == LLQ_Established || llq->state == LLQ_Refresh)
4863 						sendLLQRefresh(m, q, llq->origLease);
4864 					else if (llq->state == LLQ_InitialRequest)
4865 						startLLQHandshake(m, llq, mDNSfalse);
4866 					else if (llq->state == LLQ_SecondaryRequest)
4867 						sendChallengeResponse(m, q, mDNSNULL);
4868 					else if (llq->state == LLQ_Retry)
4869 						{ llq->ntries = 0; startLLQHandshake(m, llq, mDNSfalse); }
4870 					}
4871 				else if (llq->retry - nextevent < 0) nextevent = llq->retry;
4872 				}
4873 			}
4874 		else
4875 			{
4876 			sendtime = q->LastQTime + q->ThisQInterval;
4877 			if (m->SuppressStdPort53Queries &&
4878 				sendtime - m->SuppressStdPort53Queries < 0) // Don't allow sendtime to be earlier than SuppressStdPort53Queries
4879 				sendtime = m->SuppressStdPort53Queries;
4880 			if (sendtime - timenow < 0)
4881 				{
4882 				DNSServer *server = GetServerForName(&m->uDNS_info, &q->qname);
4883 				if (server)
4884 					{
4885 					if (server->teststate == DNSServer_Untested)
4886 						{
4887 						InitializeDNSMessage(&msg.h, newMessageID(&m->uDNS_info), uQueryFlags);
4888 						end = putQuestion(&msg, msg.data, msg.data + AbsoluteMaxDNSMessageData, DNSRelayTestQuestion, kDNSType_PTR, kDNSClass_IN);
4889 						}
4890 					else
4891 						err = constructQueryMsg(&msg, &end, q);
4892 					if (err)  LogMsg("Error: uDNS_Idle - constructQueryMsg.  Skipping question %##s", q->qname.c);
4893 					else
4894 						{
4895 						if (server->teststate != DNSServer_Failed)
4896 							err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &server->addr, UnicastDNSPort, -1, mDNSNULL);
4897 						m->SuppressStdPort53Queries = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+99)/100);
4898 						q->LastQTime = timenow;
4899 						if (err) debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %ld", err); // surpress syslog messages if we have no network
4900 						else if (q->ThisQInterval < MAX_UCAST_POLL_INTERVAL) q->ThisQInterval = q->ThisQInterval * 2;  // don't increase interval if send failed
4901 						}
4902 					}
4903 				}
4904 			else if (sendtime - nextevent < 0) nextevent = sendtime;
4905 			}
4906 		u->CurrentQuery = u->CurrentQuery->next;
4907 		}
4908 	return nextevent;
4909 	}
4910 
4911 mDNSlocal mDNSs32 CheckRecordRegistrations(mDNS *m, mDNSs32 timenow)
4912 	{
4913 	AuthRecord *rr;
4914 	uDNS_RegInfo *rInfo;
4915 	uDNS_GlobalInfo *u = &m->uDNS_info;
4916  	mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4917 
4918 	//!!!KRS list should be pre-sorted by expiration
4919 	for (rr = u->RecordRegistrations; rr; rr = rr->next)
4920 		{
4921 		rInfo = &rr->uDNS_info;
4922 		if (rInfo->state == regState_Pending || rInfo->state == regState_DeregPending || rInfo->state == regState_UpdatePending || rInfo->state == regState_DeregDeferred || rInfo->state == regState_Refresh)
4923 			{
4924 			if (rr->LastAPTime + rr->ThisAPInterval - timenow < 0)
4925 				{
4926 #if MDNS_DEBUGMSGS
4927 				char *op = "(unknown operation)";
4928 				if (rInfo->state == regState_Pending) op = "registration";
4929 				else if (rInfo->state == regState_DeregPending) op = "deregistration";
4930 				else if (rInfo->state == regState_Refresh) op = "refresh";
4931 				debugf("Retransmit record %s %##s", op, rr->resrec.name->c);
4932 #endif
4933 				//LogMsg("Retransmit record %##s", rr->resrec.name->c);
4934 				if      (rInfo->state == regState_DeregPending)   SendRecordDeregistration(m, rr);
4935 				else                                              sendRecordRegistration(m, rr);
4936 				}
4937 			if (rr->LastAPTime + rr->ThisAPInterval - nextevent < 0) nextevent = rr->LastAPTime + rr->ThisAPInterval;
4938 			}
4939 		if (rInfo->lease && rInfo->state == regState_Registered)
4940 		    {
4941 		    if (rInfo->expire - timenow < 0)
4942 		        {
4943 		        debugf("refreshing record %##s", rr->resrec.name->c);
4944 		        rInfo->state = regState_Refresh;
4945 		        sendRecordRegistration(m, rr);
4946 		        }
4947 		    if (rInfo->expire - nextevent < 0) nextevent = rInfo->expire;
4948 		    }
4949 		}
4950 	return nextevent;
4951 	}
4952 
4953 mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m, mDNSs32 timenow)
4954 	{
4955 	ServiceRecordSet *s = m->uDNS_info.ServiceRegistrations;
4956 	uDNS_RegInfo *rInfo;
4957 	mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4958 
4959 	// Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery
4960 	while (s)
4961 		{
4962 		ServiceRecordSet *srs = s;
4963 		// NOTE: Must advance s here -- SendServiceDeregistration may delete the object we're looking at,
4964 		// and then if we tried to do srs = srs->next at the end we'd be referencing a dead object
4965 		s = s->next;
4966 
4967 		rInfo = &srs->uDNS_info;
4968 		if (rInfo->state == regState_Pending || rInfo->state == regState_DeregPending || rInfo->state == regState_DeregDeferred || rInfo->state == regState_Refresh  || rInfo->state == regState_UpdatePending)
4969 			{
4970 			if (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval - timenow < 0)
4971 				{
4972 #if MDNS_DEBUGMSGS
4973 				char *op = "unknown";
4974 				if (rInfo->state == regState_Pending) op = "registration";
4975 				else if (rInfo->state == regState_DeregPending) op = "deregistration";
4976 				else if (rInfo->state == regState_Refresh) op = "refresh";
4977 				else if (rInfo->state == regState_UpdatePending) op = "txt record update";
4978 				debugf("Retransmit service %s %##s", op, srs->RR_SRV.resrec.name->c);
4979 #endif
4980 				if (rInfo->state == regState_DeregPending) { SendServiceDeregistration(m, srs); continue; }
4981 				else                                         SendServiceRegistration  (m, srs);
4982 				}
4983 			if (nextevent - srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval > 0)
4984 				nextevent = srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval;
4985 			}
4986 
4987 		if (rInfo->lease && rInfo->state == regState_Registered)
4988 		    {
4989 		    if (rInfo->expire - timenow < 0)
4990 		        {
4991 			    debugf("refreshing service %##s", srs->RR_SRV.resrec.name->c);
4992 			    rInfo->state = regState_Refresh;
4993 			    SendServiceRegistration(m, srs);
4994 		        }
4995 		    if (rInfo->expire - nextevent < 0) nextevent = rInfo->expire;
4996 		    }
4997 		}
4998 	return nextevent;
4999 	}
5000 
5001 mDNSexport void uDNS_Execute(mDNS *const m)
5002 	{
5003 	uDNS_GlobalInfo *u = &m->uDNS_info;
5004 	mDNSs32 nexte, timenow = mDNSPlatformTimeNow(m);
5005 
5006 	u->nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
5007 
5008 	if (u->DelaySRVUpdate && u->NextSRVUpdate - timenow < 0)
5009 		{
5010 		u->DelaySRVUpdate = mDNSfalse;
5011 		UpdateSRVRecords(m);
5012 		}
5013 
5014 	nexte = CheckNATMappings(m, timenow);
5015 	if (nexte - u->nextevent < 0) u->nextevent = nexte;
5016 
5017 	if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0)
5018 		m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it
5019 
5020 	nexte = CheckQueries(m, timenow);
5021 	if (nexte - u->nextevent < 0) u->nextevent = nexte;
5022 
5023 	nexte = CheckRecordRegistrations(m, timenow);
5024 	if (nexte - u->nextevent < 0) u->nextevent = nexte;
5025 
5026 	nexte = CheckServiceRegistrations(m, timenow);
5027 	if (nexte - u->nextevent < 0) u->nextevent = nexte;
5028 
5029 	}
5030 
5031 // ***************************************************************************
5032 #if COMPILER_LIKES_PRAGMA_MARK
5033 #pragma mark - Startup, Shutdown, and Sleep
5034 #endif
5035 
5036 // DeregisterActive causes active LLQs to be removed from the server, e.g. before sleep.  Pass false
5037 // following a location change, as the server will reject deletions from a source address different
5038 // from the address on which the LLQ was created.
5039 
5040 mDNSlocal void SuspendLLQs(mDNS *m, mDNSBool DeregisterActive)
5041 	{
5042 	DNSQuestion *q;
5043 	LLQ_Info *llq;
5044 	for (q = m->uDNS_info.ActiveQueries; q; q = q->next)
5045 		{
5046 		llq = q->uDNS_info.llq;
5047 		if (q->LongLived && llq)
5048 			{
5049 			if (llq->state == LLQ_GetZoneInfo)
5050 				{
5051 				debugf("Marking %##s suspend-deferred", q->qname.c);
5052 				llq->state = LLQ_SuspendDeferred;  // suspend once we're done getting zone info
5053 				}
5054 			else if (llq->state < LLQ_Suspended)
5055 				{
5056 				if (DeregisterActive && (llq->state == LLQ_Established || llq->state == LLQ_Refresh))
5057 					{ debugf("Deleting LLQ %##s", q->qname.c); sendLLQRefresh(m, q, 0); }
5058 				debugf("Marking %##s suspended", q->qname.c);
5059 				llq->state = LLQ_Suspended;
5060 				ubzero(llq->id, 8);
5061 				}
5062 			else if (llq->state == LLQ_Poll) { debugf("Marking %##s suspended-poll", q->qname.c); llq->state = LLQ_SuspendedPoll; }
5063 			if (llq->NATMap) llq->NATMap = mDNSfalse;  // may not need nat mapping if we restart with new route
5064 			}
5065 		}
5066 	CheckForUnreferencedLLQMapping(m);
5067 	}
5068 
5069 mDNSlocal void RestartQueries(mDNS *m)
5070 	{
5071 	uDNS_GlobalInfo *u = &m->uDNS_info;
5072 	DNSQuestion *q;
5073 	LLQ_Info *llqInfo;
5074 	mDNSs32 timenow = mDNSPlatformTimeNow(m);
5075 
5076 	u->CurrentQuery = u->ActiveQueries;
5077 	while (u->CurrentQuery)
5078 		{
5079 		q = u->CurrentQuery;
5080 		u->CurrentQuery = u->CurrentQuery->next;
5081 		llqInfo = q->uDNS_info.llq;
5082 		q->uDNS_info.RestartTime = timenow;
5083 		q->uDNS_info.Answered = mDNSfalse;
5084 		if (q->LongLived)
5085 			{
5086 			if (!llqInfo) { LogMsg("Error: RestartQueries - %##s long-lived with NULL info", q->qname.c); continue; }
5087 			if (llqInfo->state == LLQ_Suspended || llqInfo->state == LLQ_NatMapWait)
5088 				{
5089 				llqInfo->ntries = -1;
5090 				llqInfo->deriveRemovesOnResume = mDNStrue;
5091 				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
5092 				}
5093 			else if (llqInfo->state == LLQ_SuspendDeferred)
5094 				llqInfo->state = LLQ_GetZoneInfo; // we never finished getting zone data - proceed as usual
5095 			else if (llqInfo->state == LLQ_SuspendedPoll)
5096 				{
5097 				// if we were polling, we may have had bad zone data due to firewall, etc. - refetch
5098 				llqInfo->ntries = 0;
5099 				llqInfo->deriveRemovesOnResume = mDNStrue;
5100 				llqInfo->state = LLQ_GetZoneInfo;
5101 				startGetZoneData(&q->qname, m, mDNSfalse, mDNStrue, startLLQHandshakeCallback, llqInfo);
5102 				}
5103 			}
5104 		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)
5105 		}
5106 	}
5107 
5108 mDNSexport void mDNS_UpdateLLQs(mDNS *m)
5109 	{
5110 	uDNS_GlobalInfo *u = &m->uDNS_info;
5111 
5112 	mDNS_Lock(m);
5113 	if (u->LLQNatInfo)
5114 		{
5115 		DeleteNATPortMapping(m, u->LLQNatInfo, mDNSNULL);
5116 		FreeNATInfo(m, u->LLQNatInfo);  // routine clears u->LLQNatInfo ptr
5117 		}
5118 	SuspendLLQs(m, mDNStrue);
5119 	RestartQueries(m);
5120 	mDNS_Unlock(m);
5121 	}
5122 
5123 // simplest sleep logic - rather than having sleep states that must be dealt with explicitly in all parts of
5124 // the code, we simply send a deregistration, and put the service in Refresh state, with a timeout far enough
5125 // in the future that we'll sleep (or the sleep will be cancelled) before it is retransmitted.  Then to wake,
5126 // we just move up the timers.
5127 
5128 
5129 
5130 mDNSlocal void SleepRecordRegistrations(mDNS *m)
5131 	{
5132 	DNSMessage msg;
5133 	AuthRecord *rr = m->uDNS_info.RecordRegistrations;
5134 	mDNSs32 timenow = mDNSPlatformTimeNow(m);
5135 
5136 	while (rr)
5137 		{
5138 		if (rr->uDNS_info.state == regState_Registered ||
5139 			rr->uDNS_info.state == regState_Refresh)
5140 			{
5141 			mDNSu8 *ptr = msg.data, *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
5142 			InitializeDNSMessage(&msg.h, newMessageID(&m->uDNS_info), UpdateReqFlags);
5143 
5144 			// construct deletion update
5145 			ptr = putZone(&msg, ptr, end, &rr->uDNS_info.zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
5146 			if (!ptr) { LogMsg("Error: SleepRecordRegistrations - could not put zone"); return; }
5147 			ptr = putDeletionRecord(&msg, ptr, &rr->resrec);
5148 			if (!ptr) {  LogMsg("Error: SleepRecordRegistrations - could not put deletion record"); return; }
5149 
5150 			mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rr->uDNS_info.ns, rr->uDNS_info.port, -1, GetAuthInfoForName(&m->uDNS_info, rr->resrec.name));
5151 			rr->uDNS_info.state = regState_Refresh;
5152 			rr->LastAPTime = timenow;
5153 			rr->ThisAPInterval = 300 * mDNSPlatformOneSecond;
5154 			}
5155 		rr = rr->next;
5156 		}
5157 	}
5158 
5159 mDNSlocal void WakeRecordRegistrations(mDNS *m)
5160 	{
5161 	mDNSs32 timenow = mDNSPlatformTimeNow(m);
5162 	AuthRecord *rr = m->uDNS_info.RecordRegistrations;
5163 
5164 	while (rr)
5165 		{
5166 		if (rr->uDNS_info.state == regState_Refresh)
5167 			{
5168 			// trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets)
5169 			rr->LastAPTime = timenow;
5170 			rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
5171 			}
5172 		rr = rr->next;
5173 		}
5174 	}
5175 
5176 mDNSlocal void SleepServiceRegistrations(mDNS *m)
5177 	{
5178 	ServiceRecordSet *srs = m->uDNS_info.ServiceRegistrations;
5179 	while(srs)
5180 		{
5181 		uDNS_RegInfo *info = &srs->uDNS_info;
5182 		NATTraversalInfo *nat = info->NATinfo;
5183 
5184 		if (nat)
5185 			{
5186 			if (nat->state == NATState_Established || nat->state == NATState_Refresh || nat->state == NATState_Legacy)
5187 				DeleteNATPortMapping(m, nat, srs);
5188 			nat->reg.ServiceRegistration = mDNSNULL;
5189 			srs->uDNS_info.NATinfo = mDNSNULL;
5190 			FreeNATInfo(m, nat);
5191 			}
5192 
5193 		if (info->state == regState_UpdatePending)
5194 			{
5195 			// act as if the update succeeded, since we're about to delete the name anyway
5196 			AuthRecord *txt = &srs->RR_TXT;
5197 			uDNS_RegInfo *txtInfo = &txt->uDNS_info;
5198 			info->state = regState_Registered;
5199 			// deallocate old RData
5200 			if (txtInfo->UpdateRDCallback) txtInfo->UpdateRDCallback(m, txt, txtInfo->OrigRData);
5201 			SetNewRData(&txt->resrec, txtInfo->InFlightRData, txtInfo->InFlightRDLen);
5202 			txtInfo->OrigRData = mDNSNULL;
5203 			txtInfo->InFlightRData = mDNSNULL;
5204 			}
5205 
5206 		if (info->state == regState_Registered || info->state == regState_Refresh)
5207 			{
5208 			mDNSOpaque16 origid  = srs->uDNS_info.id;
5209 			info->state = regState_DeregPending;  // state expected by SendDereg()
5210 			SendServiceDeregistration(m, srs);
5211 			info->id = origid;
5212 			info->state = regState_NoTarget;  // when we wake, we'll re-register (and optionally nat-map) once our address record completes
5213 			srs->RR_SRV.resrec.rdata->u.srv.target.c[0] = 0;
5214 			}
5215 		srs = srs->next;
5216 		}
5217 	}
5218 
5219 mDNSlocal void WakeServiceRegistrations(mDNS *m)
5220 	{
5221 	mDNSs32 timenow = mDNSPlatformTimeNow(m);
5222 	ServiceRecordSet *srs = m->uDNS_info.ServiceRegistrations;
5223 	while(srs)
5224 		{
5225 		if (srs->uDNS_info.state == regState_Refresh)
5226 			{
5227 			// trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets)
5228 			srs->RR_SRV.LastAPTime = timenow;
5229 			srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
5230 			}
5231 		srs = srs->next;
5232 		}
5233 	}
5234 
5235 mDNSexport void uDNS_Init(mDNS *const m)
5236 	{
5237 	mDNSPlatformMemZero(&m->uDNS_info, sizeof(uDNS_GlobalInfo));
5238 	m->uDNS_info.nextevent = m->timenow_last + 0x78000000;
5239 	}
5240 
5241 mDNSexport void uDNS_Sleep(mDNS *const m)
5242 	{
5243 	SuspendLLQs(m, mDNStrue);
5244 	SleepServiceRegistrations(m);
5245 	SleepRecordRegistrations(m);
5246 	}
5247 
5248 mDNSexport void uDNS_Wake(mDNS *const m)
5249 	{
5250 	RestartQueries(m);
5251 	WakeServiceRegistrations(m);
5252 	WakeRecordRegistrations(m);
5253 	}
5254