<rdar://problem/7274595> Don't downgrade long-lived queries to polling queries if...
[people/sha0/mDNSResponder.git] / mDNSCore / uDNS.c
1 /* -*- Mode: C; tab-width: 4 -*-
2  *
3  * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  * 
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  * 
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16
17  * To Do:
18  * Elimate all mDNSPlatformMemAllocate/mDNSPlatformMemFree from this code -- the core code
19  * is supposed to be malloc-free so that it runs in constant memory determined at compile-time.
20  * Any dynamic run-time requirements should be handled by the platform layer below or client layer above
21  */
22
23 #include "uDNS.h"
24
25 #if(defined(_MSC_VER))
26         // Disable "assignment within conditional expression".
27         // Other compilers understand the convention that if you place the assignment expression within an extra pair
28         // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
29         // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
30         // to the compiler that the assignment is intentional, we have to just turn this warning off completely.
31         #pragma warning(disable:4706)
32 #endif
33
34 // For domain enumeration and automatic browsing
35 // This is the user's DNS search list.
36 // In each of these domains we search for our special pointer records (lb._dns-sd._udp.<domain>, etc.)
37 // to discover recommended domains for domain enumeration (browse, default browse, registration,
38 // default registration) and possibly one or more recommended automatic browsing domains.
39 mDNSexport SearchListElem *SearchList = mDNSNULL;
40
41 // Temporary workaround to make ServiceRecordSet list management safe.
42 // Ideally a ServiceRecordSet shouldn't be a special entity that's given special treatment by the uDNS code
43 // -- it should just be a grouping of records that are treated the same as any other registered records.
44 // In that case it may no longer be necessary to keep an explicit list of ServiceRecordSets, which in turn
45 // would avoid the perils of modifying that list cleanly while some other piece of code is iterating through it.
46 ServiceRecordSet *CurrentServiceRecordSet = mDNSNULL;
47
48 // The value can be set to true by the Platform code e.g., MacOSX uses the plist mechanism
49 mDNSBool StrictUnicastOrdering = mDNSfalse;
50
51 // ***************************************************************************
52 #if COMPILER_LIKES_PRAGMA_MARK
53 #pragma mark - General Utility Functions
54 #endif
55
56 // Unlink an AuthRecord from the m->ResourceRecords list.
57 // This seems risky. Probably some (or maybe all) of the places calling UnlinkAuthRecord to directly
58 // remove a record from the list should actually be using mDNS_Deregister/mDNS_Deregister_internal.
59 mDNSlocal mStatus UnlinkAuthRecord(mDNS *const m, AuthRecord *const rr)
60         {
61         AuthRecord **list = &m->ResourceRecords;
62         if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next;
63         if (m->CurrentRecord == rr) m->CurrentRecord = rr->next;
64         while (*list && *list != rr) list = &(*list)->next;
65         if (!*list)
66                 {
67                 list = &m->DuplicateRecords;
68                 while (*list && *list != rr) list = &(*list)->next;
69                 }
70         if (*list) { *list = rr->next; rr->next = mDNSNULL; return(mStatus_NoError); }
71         LogMsg("ERROR: UnlinkAuthRecord - no such active record %##s", rr->resrec.name->c);
72         return(mStatus_NoSuchRecord);
73         }
74
75 // unlinkSRS is an internal routine (i.e. must be called with the lock already held)
76 mDNSlocal void unlinkSRS(mDNS *const m, ServiceRecordSet *srs)
77         {
78         ServiceRecordSet **p;
79
80         if (srs->NATinfo.clientContext)
81                 {
82                 mDNS_StopNATOperation_internal(m, &srs->NATinfo);
83                 srs->NATinfo.clientContext = mDNSNULL;
84                 }
85
86         for (p = &m->ServiceRegistrations; *p; p = &(*p)->uDNS_next)
87                 if (*p == srs)
88                         {
89                         ExtraResourceRecord *e;
90                         *p = srs->uDNS_next;
91                         if (CurrentServiceRecordSet == srs)
92                                 CurrentServiceRecordSet = srs->uDNS_next;
93                         srs->uDNS_next = mDNSNULL;
94                         for (e=srs->Extras; e; e=e->next)
95                                 if (UnlinkAuthRecord(m, &e->r))
96                                         LogMsg("unlinkSRS: extra record %##s not found", e->r.resrec.name->c);
97                         return;
98                         }
99         LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list %##s", srs->RR_SRV.resrec.name->c);
100         }
101
102 // set retry timestamp for record with exponential backoff
103 // (for service record sets, use RR_SRV as representative for time checks
104 mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mStatus SendErr)
105         {
106         mDNSs32 elapsed = m->timenow - rr->LastAPTime;
107         rr->LastAPTime = m->timenow;
108
109 #if 0
110         // Code for stress-testing registration renewal code
111         if (rr->expire && rr->expire - m->timenow > mDNSPlatformOneSecond * 120)
112                 {
113                 LogInfo("Adjusting expiry from %d to 120 seconds for %s",
114                         (rr->expire - m->timenow) / mDNSPlatformOneSecond, ARDisplayString(m, rr));
115                 rr->expire = m->timenow + mDNSPlatformOneSecond * 120;
116                 }
117 #endif
118
119         if (rr->expire && rr->expire - m->timenow > mDNSPlatformOneSecond)
120                 {
121                 mDNSs32 remaining = rr->expire - m->timenow;
122                 rr->ThisAPInterval = remaining/2 + mDNSRandom(remaining/10);
123                 debugf("SetRecordRetry refresh in %4d of %4d for %s",
124                         rr->ThisAPInterval / mDNSPlatformOneSecond, (rr->expire - m->timenow) / mDNSPlatformOneSecond, ARDisplayString(m, rr));
125                 return;
126                 }
127
128         rr->expire = 0;
129
130         // If at least half our our time interval has elapsed, it's time to double rr->ThisAPInterval
131         // If resulting interval is too small, set to at least INIT_UCAST_POLL_INTERVAL (3 seconds)
132         // If resulting interval is too large, set to at most 30 minutes
133         if (rr->ThisAPInterval / 2 <= elapsed) rr->ThisAPInterval *= 2;
134         if (rr->ThisAPInterval < INIT_UCAST_POLL_INTERVAL || SendErr == mStatus_TransientErr)
135                 rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
136         rr->ThisAPInterval += mDNSRandom(rr->ThisAPInterval/20);
137         if (rr->ThisAPInterval > 30 * 60 * mDNSPlatformOneSecond)
138                 rr->ThisAPInterval = 30 * 60 * mDNSPlatformOneSecond;
139
140         LogInfo("SetRecordRetry retry   in %4d for %s", rr->ThisAPInterval / mDNSPlatformOneSecond, ARDisplayString(m, rr));
141         }
142
143 // ***************************************************************************
144 #if COMPILER_LIKES_PRAGMA_MARK
145 #pragma mark - Name Server List Management
146 #endif
147
148 mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port)
149         {
150         DNSServer **p = &m->DNSServers;
151         DNSServer *tmp = mDNSNULL;
152         
153         if (!d) d = (const domainname *)"";
154
155         LogInfo("mDNS_AddDNSServer: Adding %#a for %##s", addr, d->c);
156         if (m->mDNS_busy != m->mDNS_reentrancy+1)
157                 LogMsg("mDNS_AddDNSServer: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
158
159         while (*p)      // Check if we already have this {interface,address,port,domain} tuple registered
160                 {
161                 if ((*p)->interface == interface && (*p)->teststate != DNSServer_Disabled &&
162                         mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d))
163                         {
164                         if (!((*p)->flags & DNSServer_FlagDelete)) debugf("Note: DNS Server %#a:%d for domain %##s (%p) registered more than once", addr, mDNSVal16(port), d->c, interface);
165                         (*p)->flags &= ~DNSServer_FlagDelete;
166                         tmp = *p;
167                         *p = tmp->next;
168                         tmp->next = mDNSNULL;
169                         }
170                 else
171                         p=&(*p)->next;
172                 }
173
174         if (tmp) *p = tmp; // move to end of list, to ensure ordering from platform layer
175         else
176                 {
177                 // allocate, add to list
178                 *p = mDNSPlatformMemAllocate(sizeof(**p));
179                 if (!*p) LogMsg("Error: mDNS_AddDNSServer - malloc");
180                 else
181                         {
182                         (*p)->interface = interface;
183                         (*p)->addr      = *addr;
184                         (*p)->port      = port;
185                         (*p)->flags     = DNSServer_FlagNew;
186                         (*p)->teststate = /* DNSServer_Untested */ DNSServer_Passed;
187                         (*p)->lasttest  = m->timenow - INIT_UCAST_POLL_INTERVAL;
188                         AssignDomainName(&(*p)->domain, d);
189                         (*p)->next = mDNSNULL;
190                         }
191                 }
192         (*p)->penaltyTime = 0;
193         return(*p);
194         }
195
196 // PenalizeDNSServer is called when the number of queries to the unicast
197 // DNS server exceeds MAX_UCAST_UNANSWERED_QUERIES or when we receive an
198 // error e.g., SERV_FAIL from DNS server. QueryFail is TRUE if this function
199 // is called when we exceed MAX_UCAST_UNANSWERED_QUERIES
200
201 mDNSexport void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSBool QueryFail)
202         {
203         DNSServer *orig = q->qDNSServer;
204         
205         if (m->mDNS_busy != m->mDNS_reentrancy+1)
206                 LogMsg("PenalizeDNSServer: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
207
208         if (!q->qDNSServer)
209                 {
210                 LogMsg("PenalizeDNSServer: Null DNS server for %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), q->unansweredQueries);
211                 goto end;
212                 }
213
214         if (QueryFail)
215                 {
216                         LogInfo("PenalizeDNSServer: DNS server %#a:%d (%##s) %d unanswered queries for %##s (%s)",
217                 &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c, q->unansweredQueries, q->qname.c, DNSTypeName(q->qtype));
218                 }
219         else
220                 {
221                         LogInfo("PenalizeDNSServer: DNS server %#a:%d (%##s) Server Error for %##s (%s)",
222                 &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c, q->qname.c, DNSTypeName(q->qtype));
223                 }
224
225
226         // If strict ordering of unicast servers needs to be preserved, we just lookup
227         // the next best match server below
228         //
229         // If strict ordering is not required which is the default behavior, we penalize the server
230         // for DNSSERVER_PENALTY_TIME. We may also use additional logic e.g., don't penalize for PTR
231         // in the future.
232
233         if (!StrictUnicastOrdering)
234                 {
235                 LogInfo("PenalizeDNSServer: Strict Unicast Ordering is FALSE");
236                 // We penalize the server so that new queries don't pick this server for DNSSERVER_PENALTY_TIME
237                 // XXX Include other logic here to see if this server should really be penalized
238                 //
239                 if (q->qtype == kDNSType_PTR)
240                         {
241                         LogInfo("PenalizeDNSServer: Not Penalizing PTR question");
242                         }
243                 else
244                         {
245                         LogInfo("PenalizeDNSServer: Penalizing question type %d", q->qtype);
246                         q->qDNSServer->penaltyTime = NonZeroTime(m->timenow + DNSSERVER_PENALTY_TIME);
247                         }
248                 }
249         else
250                 {
251                 LogInfo("PenalizeDNSServer: Strict Unicast Ordering is TRUE");
252                 }
253
254 end:
255         q->qDNSServer = GetServerForName(m, &q->qname, q->qDNSServer);
256
257         if ((q->qDNSServer != orig) && (QueryFail))
258                 {
259                 // We picked a new server. In the case where QueryFail is true, the code has already incremented the interval
260                 // and to compensate that we decrease it here.  When two queries are sent, the QuestionIntervalStep is at 9. We just
261                 // move it back to 3 here when we pick a new server. We can't start at 1 because if we have two servers failing, we will never
262                 // backoff 
263                 //
264                 q->ThisQInterval = q->ThisQInterval / QuestionIntervalStep;
265                 if (q->qDNSServer) LogInfo("PenalizeDNSServer: Server for %##s (%s) changed to %#a:%d (%##s), Question Interval %u", q->qname.c, DNSTypeName(q->qtype), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c, q->ThisQInterval);
266                 else               LogInfo("PenalizeDNSServer: Server for %##s (%s) changed to <null>, Question Interval %u",        q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval);
267
268                 }
269         else 
270                 {
271                 // if we are here it means,
272                 //
273                 // 1) We picked the same server, QueryFail = false
274                 // 2) We picked the same server, QueryFail = true 
275                 // 3) We picked a different server, QueryFail = false
276                 //
277                 // For all these three cases, ThisQInterval is already set properly
278
279                 if (q->qDNSServer) 
280                         {
281                         if (q->qDNSServer != orig)
282                                 {
283                                 LogInfo("PenalizeDNSServer: Server for %##s (%s) changed to %#a:%d (%##s)", q->qname.c, DNSTypeName(q->qtype), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c);
284                                 }
285                                 else
286                                 {
287                                 LogInfo("PenalizeDNSServer: Server for %##s (%s) remains the same at %#a:%d (%##s)", q->qname.c, DNSTypeName(q->qtype), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c);
288                                 }
289                         }
290                 else
291                         { 
292                         LogInfo("PenalizeDNSServer: Server for %##s (%s) changed to <null>",        q->qname.c, DNSTypeName(q->qtype));
293                         }
294                 }
295         q->unansweredQueries = 0;
296         }
297
298 // ***************************************************************************
299 #if COMPILER_LIKES_PRAGMA_MARK
300 #pragma mark - authorization management
301 #endif
302
303 mDNSlocal DomainAuthInfo *GetAuthInfoForName_direct(mDNS *m, const domainname *const name)
304         {
305         const domainname *n = name;
306         while (n->c[0])
307                 {
308                 DomainAuthInfo *ptr;
309                 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
310                         if (SameDomainName(&ptr->domain, n))
311                                 {
312                                 debugf("GetAuthInfoForName %##s Matched %##s Key name %##s", name->c, ptr->domain.c, ptr->keyname.c);
313                                 return(ptr);
314                                 }
315                 n = (const domainname *)(n->c + 1 + n->c[0]);
316                 }
317         //LogInfo("GetAuthInfoForName none found for %##s", name->c);
318         return mDNSNULL;
319         }
320
321 // MUST be called with lock held
322 mDNSexport DomainAuthInfo *GetAuthInfoForName_internal(mDNS *m, const domainname *const name)
323         {
324         DomainAuthInfo **p = &m->AuthInfoList;
325
326         if (m->mDNS_busy != m->mDNS_reentrancy+1)
327                 LogMsg("GetAuthInfoForName_internal: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
328
329         // First purge any dead keys from the list
330         while (*p)
331                 {
332                 if ((*p)->deltime && m->timenow - (*p)->deltime >= 0 && AutoTunnelUnregistered(*p))
333                         {
334                         DNSQuestion *q;
335                         DomainAuthInfo *info = *p;
336                         LogInfo("GetAuthInfoForName_internal deleting expired key %##s %##s", info->domain.c, info->keyname.c);
337                         *p = info->next;        // Cut DomainAuthInfo from list *before* scanning our question list updating AuthInfo pointers
338                         for (q = m->Questions; q; q=q->next)
339                                 if (q->AuthInfo == info)
340                                         {
341                                         q->AuthInfo = GetAuthInfoForName_direct(m, &q->qname);
342                                         debugf("GetAuthInfoForName_internal updated q->AuthInfo from %##s to %##s for %##s (%s)",
343                                                 info->domain.c, q->AuthInfo ? q->AuthInfo->domain.c : mDNSNULL, q->qname.c, DNSTypeName(q->qtype));
344                                         }
345
346                         // Probably not essential, but just to be safe, zero out the secret key data
347                         // so we don't leave it hanging around in memory
348                         // (where it could potentially get exposed via some other bug)
349                         mDNSPlatformMemZero(info, sizeof(*info));
350                         mDNSPlatformMemFree(info);
351                         }
352                 else
353                         p = &(*p)->next;
354                 }
355
356         return(GetAuthInfoForName_direct(m, name));
357         }
358
359 mDNSexport DomainAuthInfo *GetAuthInfoForName(mDNS *m, const domainname *const name)
360         {
361         DomainAuthInfo *d;
362         mDNS_Lock(m);
363         d = GetAuthInfoForName_internal(m, name);
364         mDNS_Unlock(m);
365         return(d);
366         }
367
368 // MUST be called with the lock held
369 mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
370         const domainname *domain, const domainname *keyname, const char *b64keydata, mDNSBool AutoTunnel)
371         {
372         DNSQuestion *q;
373         DomainAuthInfo **p = &m->AuthInfoList;
374         if (!info || !b64keydata) { LogMsg("mDNS_SetSecretForDomain: ERROR: info %p b64keydata %p", info, b64keydata); return(mStatus_BadParamErr); }
375
376         LogInfo("mDNS_SetSecretForDomain: domain %##s key %##s%s", domain->c, keyname->c, AutoTunnel ? " AutoTunnel" : "");
377
378         info->AutoTunnel = AutoTunnel;
379         AssignDomainName(&info->domain,  domain);
380         AssignDomainName(&info->keyname, keyname);
381         mDNS_snprintf(info->b64keydata, sizeof(info->b64keydata), "%s", b64keydata);
382
383         if (DNSDigest_ConstructHMACKeyfromBase64(info, b64keydata) < 0)
384                 {
385                 LogMsg("mDNS_SetSecretForDomain: ERROR: Could not convert shared secret from base64: domain %##s key %##s %s", domain->c, keyname->c, mDNS_LoggingEnabled ? b64keydata : "");
386                 return(mStatus_BadParamErr);
387                 }
388
389         // Don't clear deltime until after we've ascertained that b64keydata is valid
390         info->deltime = 0;
391
392         while (*p && (*p) != info) p=&(*p)->next;
393         if (*p) return(mStatus_AlreadyRegistered);
394
395         // Caution: Only zero AutoTunnelHostRecord.namestorage and AutoTunnelNAT.clientContext AFTER we've determined that this is a NEW DomainAuthInfo
396         // being added to the list. Otherwise we risk smashing our AutoTunnel host records and NATOperation that are already active and in use.
397         info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
398         info->AutoTunnelHostRecord.namestorage.c[0] = 0;
399         info->AutoTunnelTarget    .resrec.RecordType = kDNSRecordTypeUnregistered;
400         info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeUnregistered;
401         info->AutoTunnelService   .resrec.RecordType = kDNSRecordTypeUnregistered;
402         info->AutoTunnelNAT.clientContext = mDNSNULL;
403         info->next = mDNSNULL;
404         *p = info;
405
406         // Check to see if adding this new DomainAuthInfo has changed the credentials for any of our questions
407         for (q = m->Questions; q; q=q->next)
408                 {
409                 DomainAuthInfo *newinfo = GetAuthInfoForQuestion(m, q);
410                 if (q->AuthInfo != newinfo)
411                         {
412                         debugf("mDNS_SetSecretForDomain updating q->AuthInfo from %##s to %##s for %##s (%s)",
413                                 q->AuthInfo ? q->AuthInfo->domain.c : mDNSNULL,
414                                 newinfo     ? newinfo    ->domain.c : mDNSNULL, q->qname.c, DNSTypeName(q->qtype));
415                         q->AuthInfo = newinfo;
416                         }
417                 }
418
419         return(mStatus_NoError);
420         }
421
422 // ***************************************************************************
423 #if COMPILER_LIKES_PRAGMA_MARK
424 #pragma mark -
425 #pragma mark - NAT Traversal
426 #endif
427
428 mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info)
429         {
430         mStatus err = mStatus_NoError;
431
432         // send msg if we have a router and it is a private address
433         if (!mDNSIPv4AddressIsZero(m->Router.ip.v4) && mDNSv4AddrIsRFC1918(&m->Router.ip.v4))
434                 {
435                 union { NATAddrRequest NATAddrReq; NATPortMapRequest NATPortReq; } u = { { NATMAP_VERS, NATOp_AddrRequest } } ;
436                 const mDNSu8 *end = (mDNSu8 *)&u + sizeof(NATAddrRequest);
437         
438                 if (info)                       // For NATOp_MapUDP and NATOp_MapTCP, fill in additional fields
439                         {
440                         mDNSu8 *p = (mDNSu8 *)&u.NATPortReq.NATReq_lease;
441                         u.NATPortReq.opcode  = info->Protocol;
442                         u.NATPortReq.unused  = zeroID;
443                         u.NATPortReq.intport = info->IntPort;
444                         u.NATPortReq.extport = info->RequestedPort;
445                         p[0] = (mDNSu8)((info->NATLease >> 24) &  0xFF);
446                         p[1] = (mDNSu8)((info->NATLease >> 16) &  0xFF);
447                         p[2] = (mDNSu8)((info->NATLease >>  8) &  0xFF);
448                         p[3] = (mDNSu8)( info->NATLease        &  0xFF);
449                         end = (mDNSu8 *)&u + sizeof(NATPortMapRequest);
450                         }
451
452                 err = mDNSPlatformSendUDP(m, (mDNSu8 *)&u, end, 0, mDNSNULL, &m->Router, NATPMPPort);
453
454 #ifdef _LEGACY_NAT_TRAVERSAL_
455                 if (mDNSIPPortIsZero(m->UPnPRouterPort) || mDNSIPPortIsZero(m->UPnPSOAPPort)) LNT_SendDiscoveryMsg(m);
456                 else if (info) err = LNT_MapPort(m, info);
457                 else err = LNT_GetExternalAddress(m);
458 #endif // _LEGACY_NAT_TRAVERSAL_
459                 }
460         return(err);
461         }
462
463 mDNSexport void RecreateNATMappings(mDNS *const m)
464         {
465         NATTraversalInfo *n;
466         for (n = m->NATTraversals; n; n=n->next)
467                 {
468                 n->ExpiryTime    = 0;           // Mark this mapping as expired
469                 n->retryInterval = NATMAP_INIT_RETRY;
470                 n->retryPortMap  = m->timenow;
471 #ifdef _LEGACY_NAT_TRAVERSAL_
472                 if (n->tcpInfo.sock) { mDNSPlatformTCPCloseConnection(n->tcpInfo.sock); n->tcpInfo.sock = mDNSNULL; }
473 #endif // _LEGACY_NAT_TRAVERSAL_
474                 }
475
476         m->NextScheduledNATOp = m->timenow;             // Need to send packets immediately
477         }
478
479 mDNSexport void natTraversalHandleAddressReply(mDNS *const m, mDNSu16 err, mDNSv4Addr ExtAddr)
480         {
481         static mDNSu16 last_err = 0;
482         
483         if (err)
484                 {
485                 if (err != last_err) LogMsg("Error getting external address %d", err);
486                 ExtAddr = zerov4Addr;
487                 }
488         else
489                 {
490                 LogInfo("Received external IP address %.4a from NAT", &ExtAddr);
491                 if (mDNSv4AddrIsRFC1918(&ExtAddr))
492                         LogMsg("Double NAT (external NAT gateway address %.4a is also a private RFC 1918 address)", &ExtAddr);
493                 if (mDNSIPv4AddressIsZero(ExtAddr))
494                         err = NATErr_NetFail; // fake error to handle routers that pathologically report success with the zero address
495                 }
496                 
497         if (!mDNSSameIPv4Address(m->ExternalAddress, ExtAddr))
498                 {
499                 m->ExternalAddress = ExtAddr;
500                 RecreateNATMappings(m);         // Also sets NextScheduledNATOp for us
501                 }
502
503         if (!err) // Success, back-off to maximum interval
504                 m->retryIntervalGetAddr = NATMAP_MAX_RETRY_INTERVAL;
505         else if (!last_err) // Failure after success, retry quickly (then back-off exponentially)
506                 m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
507         // else back-off normally in case of pathological failures
508
509         m->retryGetAddr = m->timenow + m->retryIntervalGetAddr;
510         if (m->NextScheduledNATOp - m->retryIntervalGetAddr > 0)
511                 m->NextScheduledNATOp = m->retryIntervalGetAddr;
512
513         last_err = err;
514         }
515
516 // Both places that call NATSetNextRenewalTime() update m->NextScheduledNATOp correctly afterwards
517 mDNSlocal void NATSetNextRenewalTime(mDNS *const m, NATTraversalInfo *n)
518         {
519         n->retryInterval = (n->ExpiryTime - m->timenow)/2;
520         if (n->retryInterval < NATMAP_MIN_RETRY_INTERVAL)       // Min retry interval is 2 seconds
521                 n->retryInterval = NATMAP_MIN_RETRY_INTERVAL;
522         n->retryPortMap = m->timenow + n->retryInterval;
523         }
524
525 // Note: When called from handleLNTPortMappingResponse() only pkt->err, pkt->extport and pkt->NATRep_lease fields are filled in
526 mDNSexport void natTraversalHandlePortMapReply(mDNS *const m, NATTraversalInfo *n, const mDNSInterfaceID InterfaceID, mDNSu16 err, mDNSIPPort extport, mDNSu32 lease)
527         {
528         const char *prot = n->Protocol == NATOp_MapUDP ? "UDP" : n->Protocol == NATOp_MapTCP ? "TCP" : "?";
529         (void)prot;
530         n->NewResult = err;
531         if (err || lease == 0 || mDNSIPPortIsZero(extport))
532                 {
533                 LogInfo("natTraversalHandlePortMapReply: %p Response %s Port %5d External Port %5d lease %d error %d",
534                         n, prot, mDNSVal16(n->IntPort), mDNSVal16(extport), lease, err);
535                 n->retryInterval = NATMAP_MAX_RETRY_INTERVAL;
536                 n->retryPortMap = m->timenow + NATMAP_MAX_RETRY_INTERVAL;
537                 // No need to set m->NextScheduledNATOp here, since we're only ever extending the m->retryPortMap time
538                 if      (err == NATErr_Refused)                     n->NewResult = mStatus_NATPortMappingDisabled;
539                 else if (err > NATErr_None && err <= NATErr_Opcode) n->NewResult = mStatus_NATPortMappingUnsupported;
540                 }
541         else
542                 {
543                 if (lease > 999999999UL / mDNSPlatformOneSecond)
544                         lease = 999999999UL / mDNSPlatformOneSecond;
545                 n->ExpiryTime = NonZeroTime(m->timenow + lease * mDNSPlatformOneSecond);
546         
547                 if (!mDNSSameIPPort(n->RequestedPort, extport))
548                         LogInfo("natTraversalHandlePortMapReply: %p Response %s Port %5d External Port %5d changed to %5d",
549                                 n, prot, mDNSVal16(n->IntPort), mDNSVal16(n->RequestedPort), mDNSVal16(extport));
550
551                 n->InterfaceID   = InterfaceID;
552                 n->RequestedPort = extport;
553         
554                 LogInfo("natTraversalHandlePortMapReply: %p Response %s Port %5d External Port %5d lease %d",
555                         n, prot, mDNSVal16(n->IntPort), mDNSVal16(extport), lease);
556         
557                 NATSetNextRenewalTime(m, n);                    // Got our port mapping; now set timer to renew it at halfway point
558                 m->NextScheduledNATOp = m->timenow;             // May need to invoke client callback immediately
559                 }
560         }
561
562 // Must be called with the mDNS_Lock held
563 mDNSexport mStatus mDNS_StartNATOperation_internal(mDNS *const m, NATTraversalInfo *traversal)
564         {
565         NATTraversalInfo **n;
566         
567         LogInfo("mDNS_StartNATOperation_internal Protocol %d IntPort %d RequestedPort %d NATLease %d",
568                 traversal->Protocol, mDNSVal16(traversal->IntPort), mDNSVal16(traversal->RequestedPort), traversal->NATLease);
569
570         // Note: It important that new traversal requests are appended at the *end* of the list, not prepended at the start
571         for (n = &m->NATTraversals; *n; n=&(*n)->next)
572                 {
573                 if (traversal == *n)
574                         {
575                         LogMsg("Error! Tried to add a NAT traversal that's already in the active list: request %p Prot %d Int %d TTL %d",
576                                 traversal, traversal->Protocol, mDNSVal16(traversal->IntPort), traversal->NATLease);
577                         return(mStatus_AlreadyRegistered);
578                         }
579                 if (traversal->Protocol && traversal->Protocol == (*n)->Protocol && mDNSSameIPPort(traversal->IntPort, (*n)->IntPort) &&
580                         !mDNSSameIPPort(traversal->IntPort, SSHPort))
581                         LogMsg("Warning: Created port mapping request %p Prot %d Int %d TTL %d "
582                                 "duplicates existing port mapping request %p Prot %d Int %d TTL %d",
583                                 traversal, traversal->Protocol, mDNSVal16(traversal->IntPort), traversal->NATLease,
584                                 *n,        (*n)     ->Protocol, mDNSVal16((*n)     ->IntPort), (*n)     ->NATLease);
585                 }
586
587         // Initialize necessary fields
588         traversal->next            = mDNSNULL;
589         traversal->ExpiryTime      = 0;
590         traversal->retryInterval   = NATMAP_INIT_RETRY;
591         traversal->retryPortMap    = m->timenow;
592         traversal->NewResult       = mStatus_NoError;
593         traversal->ExternalAddress = onesIPv4Addr;
594         traversal->ExternalPort    = zeroIPPort;
595         traversal->Lifetime        = 0;
596         traversal->Result          = mStatus_NoError;
597
598         // set default lease if necessary
599         if (!traversal->NATLease) traversal->NATLease = NATMAP_DEFAULT_LEASE;
600
601 #ifdef _LEGACY_NAT_TRAVERSAL_
602         mDNSPlatformMemZero(&traversal->tcpInfo, sizeof(traversal->tcpInfo));
603 #endif // _LEGACY_NAT_TRAVERSAL_
604
605         if (!m->NATTraversals)          // If this is our first NAT request, kick off an address request too
606                 {
607                 m->retryGetAddr         = m->timenow;
608                 m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
609                 }
610
611         m->NextScheduledNATOp = m->timenow;     // This will always trigger sending the packet ASAP, and generate client callback if necessary
612
613         *n = traversal;         // Append new NATTraversalInfo to the end of our list
614
615         return(mStatus_NoError);
616         }
617
618 // Must be called with the mDNS_Lock held
619 mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *traversal)
620         {
621         mDNSBool unmap = mDNStrue;
622         NATTraversalInfo *p;
623         NATTraversalInfo **ptr = &m->NATTraversals;
624
625         while (*ptr && *ptr != traversal) ptr=&(*ptr)->next;
626         if (*ptr) *ptr = (*ptr)->next;          // If we found it, cut this NATTraversalInfo struct from our list
627         else
628                 {
629                 LogMsg("mDNS_StopNATOperation: NATTraversalInfo %p not found in list", traversal);
630                 return(mStatus_BadReferenceErr);
631                 }
632
633         LogInfo("mDNS_StopNATOperation_internal %d %d %d %d",
634                 traversal->Protocol, mDNSVal16(traversal->IntPort), mDNSVal16(traversal->RequestedPort), traversal->NATLease);
635
636         if (m->CurrentNATTraversal == traversal)
637                 m->CurrentNATTraversal = m->CurrentNATTraversal->next;
638
639         if (traversal->Protocol)
640                 for (p = m->NATTraversals; p; p=p->next)
641                         if (traversal->Protocol == p->Protocol && mDNSSameIPPort(traversal->IntPort, p->IntPort))
642                                 {
643                                 if (!mDNSSameIPPort(traversal->IntPort, SSHPort))
644                                         LogMsg("Warning: Removed port mapping request %p Prot %d Int %d TTL %d "
645                                                 "duplicates existing port mapping request %p Prot %d Int %d TTL %d",
646                                                 traversal, traversal->Protocol, mDNSVal16(traversal->IntPort), traversal->NATLease,
647                                                 p,         p        ->Protocol, mDNSVal16(p        ->IntPort), p        ->NATLease);
648                                 unmap = mDNSfalse;
649                                 }
650
651         if (traversal->ExpiryTime && unmap)
652                 {
653                 traversal->NATLease = 0;
654                 traversal->retryInterval = 0;
655                 uDNS_SendNATMsg(m, traversal);
656                 }
657
658         // Even if we DIDN'T make a successful UPnP mapping yet, we might still have a partially-open TCP connection we need to clean up
659         #ifdef _LEGACY_NAT_TRAVERSAL_
660                 {
661                 mStatus err = LNT_UnmapPort(m, traversal);
662                 if (err) LogMsg("Legacy NAT Traversal - unmap request failed with error %d", err);
663                 }
664         #endif // _LEGACY_NAT_TRAVERSAL_
665
666         return(mStatus_NoError);
667         }
668
669 mDNSexport mStatus mDNS_StartNATOperation(mDNS *const m, NATTraversalInfo *traversal)
670         {
671         mStatus status;
672         mDNS_Lock(m);
673         status = mDNS_StartNATOperation_internal(m, traversal);
674         mDNS_Unlock(m);
675         return(status);
676         }
677
678 mDNSexport mStatus mDNS_StopNATOperation(mDNS *const m, NATTraversalInfo *traversal)
679         {
680         mStatus status;
681         mDNS_Lock(m);
682         status = mDNS_StopNATOperation_internal(m, traversal);
683         mDNS_Unlock(m);
684         return(status);
685         }
686
687 // ***************************************************************************
688 #if COMPILER_LIKES_PRAGMA_MARK
689 #pragma mark -
690 #pragma mark - Long-Lived Queries
691 #endif
692
693 // Lock must be held -- otherwise m->timenow is undefined
694 mDNSlocal void StartLLQPolling(mDNS *const m, DNSQuestion *q)
695         {
696         debugf("StartLLQPolling: %##s", q->qname.c);
697         q->state = LLQ_Poll;
698         q->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
699         // We want to send our poll query ASAP, but the "+ 1" is because if we set the time to now,
700         // we risk causing spurious "SendQueries didn't send all its queries" log messages
701         q->LastQTime     = m->timenow - q->ThisQInterval + 1;
702         SetNextQueryTime(m, q);
703 #if APPLE_OSX_mDNSResponder
704         UpdateAutoTunnelDomainStatuses(m);
705 #endif
706         }
707
708 mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, const DNSQuestion *const question, const LLQOptData *const data)
709         {
710         AuthRecord rr;
711         ResourceRecord *opt = &rr.resrec;
712         rdataOPT *optRD;
713
714         //!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section
715         ptr = putQuestion(msg, ptr, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
716         if (!ptr) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL; }
717
718         // locate OptRR if it exists, set pointer to end
719         // !!!KRS implement me
720
721         // format opt rr (fields not specified are zero-valued)
722         mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
723         opt->rrclass    = NormalMaxDNSMessageData;
724         opt->rdlength   = sizeof(rdataOPT);     // One option in this OPT record
725         opt->rdestimate = sizeof(rdataOPT);
726
727         optRD = &rr.resrec.rdata->u.opt[0];
728         optRD->opt = kDNSOpt_LLQ;
729         optRD->u.llq = *data;
730         ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.numAdditionals, opt, 0);
731         if (!ptr) { LogMsg("ERROR: putLLQ - PutResourceRecordTTLJumbo"); return mDNSNULL; }
732
733         return ptr;
734         }
735
736 // Normally we'd just request event packets be sent directly to m->LLQNAT.ExternalPort, except...
737 // with LLQs over TLS/TCP we're doing a weird thing where instead of requesting packets be sent to ExternalAddress:ExternalPort
738 // we're requesting that packets be sent to ExternalPort, but at the source address of our outgoing TCP connection.
739 // Normally, after going through the NAT gateway, the source address of our outgoing TCP connection is the same as ExternalAddress,
740 // so this is fine, except when the TCP connection ends up going over a VPN tunnel instead.
741 // To work around this, if we find that the source address for our TCP connection is not a private address, we tell the Dot Mac
742 // LLQ server to send events to us directly at port 5353 on that address, instead of at our mapped external NAT port.
743
744 mDNSlocal mDNSu16 GetLLQEventPort(const mDNS *const m, const mDNSAddr *const dst)
745         {
746         mDNSAddr src;
747         mDNSPlatformSourceAddrForDest(&src, dst);
748         //LogMsg("GetLLQEventPort: src %#a for dst %#a (%d)", &src, dst, mDNSv4AddrIsRFC1918(&src.ip.v4) ? mDNSVal16(m->LLQNAT.ExternalPort) : 0);
749         return(mDNSv4AddrIsRFC1918(&src.ip.v4) ? mDNSVal16(m->LLQNAT.ExternalPort) : mDNSVal16(MulticastDNSPort));
750         }
751
752 // Normally called with llq set.
753 // May be called with llq NULL, when retransmitting a lost Challenge Response
754 mDNSlocal void sendChallengeResponse(mDNS *const m, DNSQuestion *const q, const LLQOptData *llq)
755         {
756         mDNSu8 *responsePtr = m->omsg.data;
757         LLQOptData llqBuf;
758
759         if (q->ntries++ == kLLQ_MAX_TRIES)
760                 {
761                 LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s", kLLQ_MAX_TRIES, q->qname.c);
762                 StartLLQPolling(m,q);
763                 return;
764                 }
765
766         if (!llq)               // Retransmission: need to make a new LLQOptData
767                 {
768                 llqBuf.vers     = kLLQ_Vers;
769                 llqBuf.llqOp    = kLLQOp_Setup;
770                 llqBuf.err      = LLQErr_NoError;       // Don't need to tell server UDP notification port when sending over UDP
771                 llqBuf.id       = q->id;
772                 llqBuf.llqlease = q->ReqLease;
773                 llq = &llqBuf;
774                 }
775
776         q->LastQTime     = m->timenow;
777         q->ThisQInterval = q->tcp ? 0 : (kLLQ_INIT_RESEND * q->ntries * mDNSPlatformOneSecond);         // If using TCP, don't need to retransmit
778         SetNextQueryTime(m, q);
779
780         // To simulate loss of challenge response packet, uncomment line below
781         //if (q->ntries == 1) return;
782
783         InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
784         responsePtr = putLLQ(&m->omsg, responsePtr, q, llq);
785         if (responsePtr)
786                 {
787                 mStatus err = mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, q->AuthInfo);
788                 if (err)
789                         {
790                         LogMsg("sendChallengeResponse: mDNSSendDNSMessage%s failed: %d", q->tcp ? " (TCP)" : "", err);
791                         if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; }
792                         }
793                 }
794         else StartLLQPolling(m,q);
795         }
796
797 mDNSlocal void SetLLQTimer(mDNS *const m, DNSQuestion *const q, const LLQOptData *const llq)
798         {
799         mDNSs32 lease = (mDNSs32)llq->llqlease * mDNSPlatformOneSecond;
800         q->ReqLease      = llq->llqlease;
801         q->LastQTime     = m->timenow;
802         q->expire        = m->timenow + lease;
803         q->ThisQInterval = lease/2 + mDNSRandom(lease/10);
804         debugf("SetLLQTimer setting %##s (%s) to %d %d", q->qname.c, DNSTypeName(q->qtype), lease/mDNSPlatformOneSecond, q->ThisQInterval/mDNSPlatformOneSecond);
805         SetNextQueryTime(m, q);
806         }
807
808 mDNSlocal void recvSetupResponse(mDNS *const m, mDNSu8 rcode, DNSQuestion *const q, const LLQOptData *const llq)
809         {
810         if (rcode && rcode != kDNSFlag1_RC_NXDomain)
811                 { LogMsg("ERROR: recvSetupResponse %##s (%s) - rcode && rcode != kDNSFlag1_RC_NXDomain", q->qname.c, DNSTypeName(q->qtype)); return; }
812
813         if (llq->llqOp != kLLQOp_Setup)
814                 { LogMsg("ERROR: recvSetupResponse %##s (%s) - bad op %d", q->qname.c, DNSTypeName(q->qtype), llq->llqOp); return; }
815
816         if (llq->vers != kLLQ_Vers)
817                 { LogMsg("ERROR: recvSetupResponse %##s (%s) - bad vers %d", q->qname.c, DNSTypeName(q->qtype), llq->vers); return; }
818
819         if (q->state == LLQ_InitialRequest)
820                 {
821                 //LogInfo("Got LLQ_InitialRequest");
822
823                 if (llq->err) { LogMsg("recvSetupResponse - received llq->err %d from server", llq->err); StartLLQPolling(m,q); return; }
824         
825                 if (q->ReqLease != llq->llqlease)
826                         debugf("recvSetupResponse: requested lease %lu, granted lease %lu", q->ReqLease, llq->llqlease);
827         
828                 // cache expiration in case we go to sleep before finishing setup
829                 q->ReqLease = llq->llqlease;
830                 q->expire = m->timenow + ((mDNSs32)llq->llqlease * mDNSPlatformOneSecond);
831         
832                 // update state
833                 q->state  = LLQ_SecondaryRequest;
834                 q->id     = llq->id;
835                 q->ntries = 0; // first attempt to send response
836                 sendChallengeResponse(m, q, llq);
837                 }
838         else if (q->state == LLQ_SecondaryRequest)
839                 {
840                 //LogInfo("Got LLQ_SecondaryRequest");
841
842                 // Fix this immediately if not sooner.  Copy the id from the LLQOptData into our DNSQuestion struct.  This is only
843                 // an issue for private LLQs, because we skip parts 2 and 3 of the handshake.  This is related to a bigger
844                 // problem of the current implementation of TCP LLQ setup: we're not handling state transitions correctly
845                 // if the server sends back SERVFULL or STATIC.
846                 if (q->AuthInfo)
847                         {
848                         LogInfo("Private LLQ_SecondaryRequest; copying id %08X%08X", llq->id.l[0], llq->id.l[1]);
849                         q->id = llq->id;
850                         }
851
852                 if (llq->err) { LogMsg("ERROR: recvSetupResponse %##s (%s) code %d from server", q->qname.c, DNSTypeName(q->qtype), llq->err); StartLLQPolling(m,q); return; }
853                 if (!mDNSSameOpaque64(&q->id, &llq->id))
854                         { LogMsg("recvSetupResponse - ID changed.  discarding"); return; } // this can happen rarely (on packet loss + reordering)
855                 q->state         = LLQ_Established;
856                 q->ntries        = 0;
857                 SetLLQTimer(m, q, llq);
858 #if APPLE_OSX_mDNSResponder
859                 UpdateAutoTunnelDomainStatuses(m);
860 #endif
861                 }
862         }
863
864 mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport)
865         {
866         DNSQuestion pktQ, *q;
867         if (msg->h.numQuestions && getQuestion(msg, msg->data, end, 0, &pktQ))
868                 {
869                 const rdataOPT *opt = GetLLQOptData(m, msg, end);
870
871                 for (q = m->Questions; q; q = q->next)
872                         {
873                         if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->qtype == pktQ.qtype && q->qnamehash == pktQ.qnamehash && SameDomainName(&q->qname, &pktQ.qname))
874                                 {
875                                 debugf("uDNS_recvLLQResponse found %##s (%s) %d %#a %#a %X %X %X %X %d",
876                                         q->qname.c, DNSTypeName(q->qtype), q->state, srcaddr, &q->servAddr,
877                                         opt ? opt->u.llq.id.l[0] : 0, opt ? opt->u.llq.id.l[1] : 0, q->id.l[0], q->id.l[1], opt ? opt->u.llq.llqOp : 0);
878                                 if (q->state == LLQ_Poll) debugf("uDNS_LLQ_Events: q->state == LLQ_Poll msg->h.id %d q->TargetQID %d", mDNSVal16(msg->h.id), mDNSVal16(q->TargetQID));
879                                 if (q->state == LLQ_Poll && mDNSSameOpaque16(msg->h.id, q->TargetQID))
880                                         {
881                                         m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
882                                         debugf("uDNS_recvLLQResponse got poll response; moving to LLQ_InitialRequest for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
883                                         q->state         = LLQ_InitialRequest;
884                                         q->servPort      = zeroIPPort;          // Clear servPort so that startLLQHandshake will retry the GetZoneData processing
885                                         q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10);        // Retry LLQ setup in approx 15 minutes
886                                         q->LastQTime     = m->timenow;
887                                         SetNextQueryTime(m, q);
888                                         return uDNS_LLQ_Entire;         // uDNS_LLQ_Entire means flush stale records; assume a large effective TTL
889                                         }
890                                 // Note: In LLQ Event packets, the msg->h.id does not match our q->TargetQID, because in that case the msg->h.id nonce is selected by the server
891                                 else if (opt && q->state == LLQ_Established && opt->u.llq.llqOp == kLLQOp_Event && mDNSSameOpaque64(&opt->u.llq.id, &q->id))
892                                         {
893                                         mDNSu8 *ackEnd;
894                                         //debugf("Sending LLQ ack for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
895                                         InitializeDNSMessage(&m->omsg.h, msg->h.id, ResponseFlags);
896                                         ackEnd = putLLQ(&m->omsg, m->omsg.data, q, &opt->u.llq);
897                                         if (ackEnd) mDNSSendDNSMessage(m, &m->omsg, ackEnd, mDNSInterface_Any, q->LocalSocket, srcaddr, srcport, mDNSNULL, mDNSNULL);
898                                         m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
899                                         debugf("uDNS_LLQ_Events: q->state == LLQ_Established msg->h.id %d q->TargetQID %d", mDNSVal16(msg->h.id), mDNSVal16(q->TargetQID));
900                                         return uDNS_LLQ_Events;
901                                         }
902                                 if (opt && mDNSSameOpaque16(msg->h.id, q->TargetQID))
903                                         {
904                                         if (q->state == LLQ_Established && opt->u.llq.llqOp == kLLQOp_Refresh && mDNSSameOpaque64(&opt->u.llq.id, &q->id) && msg->h.numAdditionals && !msg->h.numAnswers)
905                                                 {
906                                                 if (opt->u.llq.err != LLQErr_NoError) LogMsg("recvRefreshReply: received error %d from server", opt->u.llq.err);
907                                                 else
908                                                         {
909                                                         //LogInfo("Received refresh confirmation ntries %d for %##s (%s)", q->ntries, q->qname.c, DNSTypeName(q->qtype));
910                                                         // If we're waiting to go to sleep, then this LLQ deletion may have been the thing
911                                                         // we were waiting for, so schedule another check to see if we can sleep now.
912                                                         if (opt->u.llq.llqlease == 0 && m->SleepLimit) m->NextScheduledSPRetry = m->timenow;
913                                                         GrantCacheExtensions(m, q, opt->u.llq.llqlease);
914                                                         SetLLQTimer(m, q, &opt->u.llq);
915                                                         q->ntries = 0;
916                                                         }
917                                                 m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
918                                                 return uDNS_LLQ_Ignore;
919                                                 }
920                                         if (q->state < LLQ_Established && mDNSSameAddress(srcaddr, &q->servAddr))
921                                                 {
922                                                 LLQ_State oldstate = q->state;
923                                                 recvSetupResponse(m, msg->h.flags.b[1] & kDNSFlag1_RC_Mask, q, &opt->u.llq);
924                                                 m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
925                                                 // We have a protocol anomaly here in the LLQ definition.
926                                                 // Both the challenge packet from the server and the ack+answers packet have opt->u.llq.llqOp == kLLQOp_Setup.
927                                                 // However, we need to treat them differently:
928                                                 // The challenge packet has no answers in it, and tells us nothing about whether our cache entries
929                                                 // are still valid, so this packet should not cause us to do anything that messes with our cache.
930                                                 // The ack+answers packet gives us the whole truth, so we should handle it by updating our cache
931                                                 // to match the answers in the packet, and only the answers in the packet.
932                                                 return (oldstate == LLQ_SecondaryRequest ? uDNS_LLQ_Entire : uDNS_LLQ_Ignore);
933                                                 }
934                                         }
935                                 }
936                         }
937                 m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
938                 }
939         return uDNS_LLQ_Not;
940         }
941
942 // Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
943 struct TCPSocket_struct { TCPSocketFlags flags; /* ... */ };
944
945 // tcpCallback is called to handle events (e.g. connection opening and data reception) on TCP connections for
946 // Private DNS operations -- private queries, private LLQs, private record updates and private service updates
947 mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err)
948         {
949         tcpInfo_t *tcpInfo = (tcpInfo_t *)context;
950         mDNSBool   closed  = mDNSfalse;
951         mDNS      *m       = tcpInfo->m;
952         DNSQuestion *const q = tcpInfo->question;
953         tcpInfo_t **backpointer =
954                 q                 ? &q           ->tcp :
955                 tcpInfo->srs      ? &tcpInfo->srs->tcp :
956                 tcpInfo->rr       ? &tcpInfo->rr ->tcp : mDNSNULL;
957         if (backpointer && *backpointer != tcpInfo)
958                 LogMsg("tcpCallback: %d backpointer %p incorrect tcpInfo %p question %p srs %p rr %p",
959                         mDNSPlatformTCPGetFD(tcpInfo->sock), *backpointer, tcpInfo, q, tcpInfo->srs, tcpInfo->rr);
960
961         if (err) goto exit;
962
963         if (ConnectionEstablished)
964                 {
965                 mDNSu8    *end = ((mDNSu8*) &tcpInfo->request) + tcpInfo->requestLen;
966                 DomainAuthInfo *AuthInfo;
967
968                 // Defensive coding for <rdar://problem/5546824> Crash in mDNSResponder at GetAuthInfoForName_internal + 366
969                 // Don't know yet what's causing this, but at least we can be cautious and try to avoid crashing if we find our pointers in an unexpected state
970                 if (tcpInfo->srs && tcpInfo->srs->RR_SRV.resrec.name != &tcpInfo->srs->RR_SRV.namestorage)
971                         LogMsg("tcpCallback: ERROR: tcpInfo->srs->RR_SRV.resrec.name %p != &tcpInfo->srs->RR_SRV.namestorage %p",
972                                 tcpInfo->srs->RR_SRV.resrec.name, &tcpInfo->srs->RR_SRV.namestorage);
973                 if (tcpInfo->rr && tcpInfo->rr->resrec.name != &tcpInfo->rr->namestorage)
974                         LogMsg("tcpCallback: ERROR: tcpInfo->rr->resrec.name %p != &tcpInfo->rr->namestorage %p",
975                                 tcpInfo->rr->resrec.name, &tcpInfo->rr->namestorage);
976                 if (tcpInfo->srs && tcpInfo->srs->RR_SRV.resrec.name != &tcpInfo->srs->RR_SRV.namestorage) return;
977                 if (tcpInfo->rr  && tcpInfo->rr->        resrec.name != &tcpInfo->rr->        namestorage) return;
978
979                 AuthInfo =  tcpInfo->srs ? GetAuthInfoForName(m, tcpInfo->srs->RR_SRV.resrec.name) :
980                                         tcpInfo->rr  ? GetAuthInfoForName(m, tcpInfo->rr->resrec.name)         : mDNSNULL;
981
982                 // connection is established - send the message
983                 if (q && q->LongLived && q->state == LLQ_Established)
984                         {
985                         // Lease renewal over TCP, resulting from opening a TCP connection in sendLLQRefresh
986                         end = ((mDNSu8*) &tcpInfo->request) + tcpInfo->requestLen;
987                         }
988                 else if (q && q->LongLived && q->state != LLQ_Poll && !mDNSIPPortIsZero(m->LLQNAT.ExternalPort) && !mDNSIPPortIsZero(q->servPort))
989                         {
990                         // Notes:
991                         // If we have a NAT port mapping, ExternalPort is the external port
992                         // If we have a routable address so we don't need a port mapping, ExternalPort is the same as our own internal port
993                         // If we need a NAT port mapping but can't get one, then ExternalPort is zero
994                         LLQOptData llqData;                     // set llq rdata
995                         llqData.vers  = kLLQ_Vers;
996                         llqData.llqOp = kLLQOp_Setup;
997                         llqData.err   = GetLLQEventPort(m, &tcpInfo->Addr);     // We're using TCP; tell server what UDP port to send notifications to
998                         LogInfo("tcpCallback: eventPort %d", llqData.err);
999                         llqData.id    = zeroOpaque64;
1000                         llqData.llqlease = kLLQ_DefLease;
1001                         InitializeDNSMessage(&tcpInfo->request.h, q->TargetQID, uQueryFlags);
1002                         end = putLLQ(&tcpInfo->request, tcpInfo->request.data, q, &llqData);
1003                         if (!end) { LogMsg("ERROR: tcpCallback - putLLQ"); err = mStatus_UnknownErr; goto exit; }
1004                         AuthInfo = q->AuthInfo;         // Need to add TSIG to this message
1005                         q->ntries = 0; // Reset ntries so that tcp/tls connection failures don't affect sendChallengeResponse failures
1006                         }
1007                 else if (q)
1008                         {
1009                         // LLQ Polling mode or non-LLQ uDNS over TCP
1010                         InitializeDNSMessage(&tcpInfo->request.h, q->TargetQID, uQueryFlags);
1011                         end = putQuestion(&tcpInfo->request, tcpInfo->request.data, tcpInfo->request.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
1012                         AuthInfo = q->AuthInfo;         // Need to add TSIG to this message
1013                         }
1014
1015                 err = mDNSSendDNSMessage(m, &tcpInfo->request, end, mDNSInterface_Any, mDNSNULL, &tcpInfo->Addr, tcpInfo->Port, sock, AuthInfo);
1016                 if (err) { debugf("ERROR: tcpCallback: mDNSSendDNSMessage - %d", err); err = mStatus_UnknownErr; goto exit; }
1017
1018                 // Record time we sent this question
1019                 if (q)
1020                         {
1021                         mDNS_Lock(m);
1022                         q->LastQTime = m->timenow;
1023                         if (q->ThisQInterval < (256 * mDNSPlatformOneSecond))   // Now we have a TCP connection open, make sure we wait at least 256 seconds before retrying
1024                                 q->ThisQInterval = (256 * mDNSPlatformOneSecond);
1025                         SetNextQueryTime(m, q);
1026                         mDNS_Unlock(m);
1027                         }
1028                 }
1029         else
1030                 {
1031                 long n;
1032                 if (tcpInfo->nread < 2)                 // First read the two-byte length preceeding the DNS message
1033                         {
1034                         mDNSu8 *lenptr = (mDNSu8 *)&tcpInfo->replylen;
1035                         n = mDNSPlatformReadTCP(sock, lenptr + tcpInfo->nread, 2 - tcpInfo->nread, &closed);
1036                         if (n < 0)
1037                                 {
1038                                 LogMsg("ERROR: tcpCallback - attempt to read message length failed (%d)", n);
1039                                 err = mStatus_ConnFailed;
1040                                 goto exit;
1041                                 }
1042                         else if (closed)
1043                                 {
1044                                 // It's perfectly fine for this socket to close after the first reply. The server might
1045                                 // be sending gratuitous replies using UDP and doesn't have a need to leave the TCP socket open.
1046                                 // We'll only log this event if we've never received a reply before.
1047                                 // BIND 9 appears to close an idle connection after 30 seconds.
1048                                 if (tcpInfo->numReplies == 0)
1049                                         {
1050                                         LogMsg("ERROR: socket closed prematurely tcpInfo->nread = %d", tcpInfo->nread);
1051                                         err = mStatus_ConnFailed;
1052                                         goto exit;
1053                                         }
1054                                 else
1055                                         {
1056                                         // Note that we may not be doing the best thing if an error occurs after we've sent a second request
1057                                         // over this tcp connection.  That is, we only track whether we've received at least one response
1058                                         // which may have been to a previous request sent over this tcp connection.
1059                                         if (backpointer) *backpointer = mDNSNULL; // Clear client backpointer FIRST so we don't risk double-disposing our tcpInfo_t 
1060                                         DisposeTCPConn(tcpInfo);
1061                                         return;
1062                                         }
1063                                 }
1064
1065                         tcpInfo->nread += n;
1066                         if (tcpInfo->nread < 2) goto exit;
1067
1068                         tcpInfo->replylen = (mDNSu16)((mDNSu16)lenptr[0] << 8 | lenptr[1]);
1069                         if (tcpInfo->replylen < sizeof(DNSMessageHeader))
1070                                 { LogMsg("ERROR: tcpCallback - length too short (%d bytes)", tcpInfo->replylen); err = mStatus_UnknownErr; goto exit; }
1071
1072                         tcpInfo->reply = mDNSPlatformMemAllocate(tcpInfo->replylen);
1073                         if (!tcpInfo->reply) { LogMsg("ERROR: tcpCallback - malloc failed"); err = mStatus_NoMemoryErr; goto exit; }
1074                         }
1075
1076                 n = mDNSPlatformReadTCP(sock, ((char *)tcpInfo->reply) + (tcpInfo->nread - 2), tcpInfo->replylen - (tcpInfo->nread - 2), &closed);
1077
1078                 if (n < 0)
1079                         {
1080                         LogMsg("ERROR: tcpCallback - read returned %d", n);
1081                         err = mStatus_ConnFailed;
1082                         goto exit;
1083                         }
1084                 else if (closed)
1085                         {
1086                         if (tcpInfo->numReplies == 0)
1087                                 {
1088                                 LogMsg("ERROR: socket closed prematurely tcpInfo->nread = %d", tcpInfo->nread);
1089                                 err = mStatus_ConnFailed;
1090                                 goto exit;
1091                                 }
1092                         else
1093                                 {
1094                                 // Note that we may not be doing the best thing if an error occurs after we've sent a second request
1095                                 // over this tcp connection.  That is, we only track whether we've received at least one response
1096                                 // which may have been to a previous request sent over this tcp connection.
1097                                 if (backpointer) *backpointer = mDNSNULL; // Clear client backpointer FIRST so we don't risk double-disposing our tcpInfo_t 
1098                                 DisposeTCPConn(tcpInfo);
1099                                 return;
1100                                 }
1101                         }
1102
1103                 tcpInfo->nread += n;
1104
1105                 if ((tcpInfo->nread - 2) == tcpInfo->replylen)
1106                         {
1107                         AuthRecord *rr    = tcpInfo->rr;
1108                         DNSMessage *reply = tcpInfo->reply;
1109                         mDNSu8     *end   = (mDNSu8 *)tcpInfo->reply + tcpInfo->replylen;
1110                         mDNSAddr    Addr  = tcpInfo->Addr;
1111                         mDNSIPPort  Port  = tcpInfo->Port;
1112                         tcpInfo->numReplies++;
1113                         tcpInfo->reply    = mDNSNULL;   // Detach reply buffer from tcpInfo_t, to make sure client callback can't cause it to be disposed
1114                         tcpInfo->nread    = 0;
1115                         tcpInfo->replylen = 0;
1116                         
1117                         // If we're going to dispose this connection, do it FIRST, before calling client callback
1118                         // Note: Sleep code depends on us clearing *backpointer here -- it uses the clearing of rr->tcp and srs->tcp
1119                         // as the signal that the DNS deregistration operation with the server has completed, and the machine may now sleep
1120                         if (backpointer)
1121                                 if (!q || !q->LongLived || m->SleepState)
1122                                         { *backpointer = mDNSNULL; DisposeTCPConn(tcpInfo); }
1123                         
1124                         if (rr && rr->resrec.RecordType == kDNSRecordTypeDeregistering)
1125                                 {
1126                                 mDNS_Lock(m);
1127                                 LogInfo("tcpCallback: CompleteDeregistration %s", ARDisplayString(m, rr));
1128                                 CompleteDeregistration(m, rr);          // Don't touch rr after this
1129                                 mDNS_Unlock(m);
1130                                 }
1131                         else
1132                                 mDNSCoreReceive(m, reply, end, &Addr, Port, (sock->flags & kTCPSocketFlags_UseTLS) ? (mDNSAddr *)1 : mDNSNULL, zeroIPPort, 0);
1133                         // USE CAUTION HERE: Invoking mDNSCoreReceive may have caused the environment to change, including canceling this operation itself
1134                         
1135                         mDNSPlatformMemFree(reply);
1136                         return;
1137                         }
1138                 }
1139
1140 exit:
1141
1142         if (err)
1143                 {
1144                 // Clear client backpointer FIRST -- that way if one of the callbacks cancels its operation
1145                 // we won't end up double-disposing our tcpInfo_t
1146                 if (backpointer) *backpointer = mDNSNULL;
1147
1148                 mDNS_Lock(m);           // Need to grab the lock to get m->timenow
1149
1150                 if (q)
1151                         {
1152                         if (q->ThisQInterval == 0)
1153                                 {
1154                                 // We get here when we fail to establish a new TCP/TLS connection that would have been used for a new LLQ request or an LLQ renewal.
1155                                 // Note that ThisQInterval is also zero when sendChallengeResponse resends the LLQ request on an extant TCP/TLS connection.
1156                                 q->LastQTime = m->timenow;
1157                                 if (q->LongLived)
1158                                         {
1159                                         // We didn't get the chance to send our request packet before the TCP/TLS connection failed.
1160                                         // We want to retry quickly, but want to back off exponentially in case the server is having issues.
1161                                         // Since ThisQInterval was 0, we can't just multiply by QuestionIntervalStep, we must track the number
1162                                         // of TCP/TLS connection failures using ntries.
1163                                         mDNSu32 count = q->ntries + 1; // want to wait at least 1 second before retrying
1164
1165                                         q->ThisQInterval = InitialQuestionInterval;
1166
1167                                         for (;count;count--)
1168                                                 q->ThisQInterval *= QuestionIntervalStep;
1169
1170                                         if (q->ThisQInterval > LLQ_POLL_INTERVAL)
1171                                                 q->ThisQInterval = LLQ_POLL_INTERVAL;
1172                                         else
1173                                                 q->ntries++;
1174                                                 
1175                                         LogMsg("tcpCallback: stream connection for LLQ %##s (%s) failed %d times, retrying in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ntries, q->ThisQInterval);
1176                                         }
1177                                 else
1178                                         {
1179                                         q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
1180                                         LogMsg("tcpCallback: stream connection for %##s (%s) failed, retrying in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval);
1181                                         }
1182                                 SetNextQueryTime(m, q);
1183                                 }
1184                         else if (q->LastQTime + q->ThisQInterval - m->timenow > (q->LongLived ? LLQ_POLL_INTERVAL : MAX_UCAST_POLL_INTERVAL))
1185                                 {
1186                                 // If we get an error and our next scheduled query for this question is more than the max interval from now,
1187                                 // reset the next query to ensure we wait no longer the maximum interval from now before trying again.
1188                                 q->LastQTime     = m->timenow;
1189                                 q->ThisQInterval = q->LongLived ? LLQ_POLL_INTERVAL : MAX_UCAST_POLL_INTERVAL;
1190                                 SetNextQueryTime(m, q);
1191                                 }
1192                         
1193                         // We're about to dispose of the TCP connection, so we must reset the state to retry over TCP/TLS
1194                         // because sendChallengeResponse will send the query via UDP if we don't have a tcp pointer.
1195                         // Resetting to LLQ_InitialRequest will cause uDNS_CheckCurrentQuestion to call startLLQHandshake, which
1196                         // will attempt to establish a new tcp connection.
1197                         if (q->LongLived && q->state == LLQ_SecondaryRequest)
1198                                 q->state = LLQ_InitialRequest;
1199                         
1200                         // ConnFailed may happen if the server sends a TCP reset or TLS fails, in which case we want to retry establishing the LLQ
1201                         // quickly rather than switching to polling mode.  This case is handled by the above code to set q->ThisQInterval just above.
1202                         // If the error isn't ConnFailed, then the LLQ is in bad shape, so we switch to polling mode.
1203                         if (err != mStatus_ConnFailed)
1204                                 {
1205                                 if (q->LongLived && q->state != LLQ_Poll) StartLLQPolling(m, q);
1206                                 }
1207                         }
1208
1209                 if (tcpInfo->rr) SetRecordRetry(m, tcpInfo->rr, mStatus_NoError);
1210
1211                 if (tcpInfo->srs) SetRecordRetry(m, &tcpInfo->srs->RR_SRV, mStatus_NoError);
1212
1213                 mDNS_Unlock(m);
1214
1215                 DisposeTCPConn(tcpInfo);
1216                 }
1217         }
1218
1219 mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
1220         TCPSocketFlags flags, const mDNSAddr *const Addr, const mDNSIPPort Port,
1221         DNSQuestion *const question, ServiceRecordSet *const srs, AuthRecord *const rr)
1222         {
1223         mStatus err;
1224         mDNSIPPort srcport = zeroIPPort;
1225         tcpInfo_t *info = (tcpInfo_t *)mDNSPlatformMemAllocate(sizeof(tcpInfo_t));
1226         if (!info) { LogMsg("ERROR: MakeTCP - memallocate failed"); return(mDNSNULL); }
1227         mDNSPlatformMemZero(info, sizeof(tcpInfo_t));
1228
1229         info->m          = m;
1230         info->sock       = mDNSPlatformTCPSocket(m, flags, &srcport);
1231         info->requestLen = 0;
1232         info->question   = question;
1233         info->srs        = srs;
1234         info->rr         = rr;
1235         info->Addr       = *Addr;
1236         info->Port       = Port;
1237         info->reply      = mDNSNULL;
1238         info->replylen   = 0;
1239         info->nread      = 0;
1240         info->numReplies = 0;
1241
1242         if (msg)
1243                 {
1244                 info->requestLen = (int) (end - ((mDNSu8*)msg));
1245                 mDNSPlatformMemCopy(&info->request, msg, info->requestLen);
1246                 }
1247
1248         if (!info->sock) { LogMsg("SendServiceRegistration: unable to create TCP socket"); mDNSPlatformMemFree(info); return(mDNSNULL); }
1249         err = mDNSPlatformTCPConnect(info->sock, Addr, Port, 0, tcpCallback, info);
1250
1251         // Probably suboptimal here.
1252         // Instead of returning mDNSNULL here on failure, we should probably invoke the callback with an error code.
1253         // That way clients can put all the error handling and retry/recovery code in one place,
1254         // instead of having to handle immediate errors in one place and async errors in another.
1255         // Also: "err == mStatus_ConnEstablished" probably never happens.
1256
1257         // Don't need to log "connection failed" in customer builds -- it happens quite often during sleep, wake, configuration changes, etc.
1258         if      (err == mStatus_ConnEstablished) { tcpCallback(info->sock, info, mDNStrue, mStatus_NoError); }
1259         else if (err != mStatus_ConnPending    ) { LogInfo("MakeTCPConnection: connection failed"); DisposeTCPConn(info); return(mDNSNULL); }
1260         return(info);
1261         }
1262
1263 mDNSexport void DisposeTCPConn(struct tcpInfo_t *tcp)
1264         {
1265         mDNSPlatformTCPCloseConnection(tcp->sock);
1266         if (tcp->reply) mDNSPlatformMemFree(tcp->reply);
1267         mDNSPlatformMemFree(tcp);
1268         }
1269
1270 // Lock must be held
1271 mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q)
1272         {
1273         if (mDNSIPv4AddressIsOnes(m->LLQNAT.ExternalAddress))
1274                 {
1275                 LogInfo("startLLQHandshake: waiting for NAT status for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
1276                 q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10);        // Retry in approx 15 minutes
1277                 q->LastQTime = m->timenow;
1278                 SetNextQueryTime(m, q);
1279                 return;
1280                 }
1281
1282         if (mDNSIPPortIsZero(m->LLQNAT.ExternalPort))
1283                 {
1284                 LogInfo("startLLQHandshake: Cannot receive inbound packets; will poll for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
1285                 StartLLQPolling(m, q);
1286                 return;
1287                 }
1288
1289         if (mDNSIPPortIsZero(q->servPort))
1290                 {
1291                 debugf("startLLQHandshake: StartGetZoneData for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
1292                 q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10);        // Retry in approx 15 minutes
1293                 q->LastQTime     = m->timenow;
1294                 SetNextQueryTime(m, q);
1295                 q->servAddr = zeroAddr;
1296                 // We know q->servPort is zero because of check above
1297                 if (q->nta) CancelGetZoneData(m, q->nta);
1298                 q->nta = StartGetZoneData(m, &q->qname, ZoneServiceLLQ, LLQGotZoneData, q);
1299                 return;
1300                 }
1301
1302         if (q->AuthInfo)
1303                 {
1304                 if (q->tcp) LogInfo("startLLQHandshake: Disposing existing TCP connection for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
1305                 if (q->tcp) DisposeTCPConn(q->tcp);
1306                 q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, q, mDNSNULL, mDNSNULL);
1307                 if (!q->tcp)
1308                         q->ThisQInterval = mDNSPlatformOneSecond * 5;   // If TCP failed (transient networking glitch) try again in five seconds
1309                 else
1310                         {
1311                         q->state         = LLQ_SecondaryRequest;                // Right now, for private DNS, we skip the four-way LLQ handshake
1312                         q->ReqLease      = kLLQ_DefLease;
1313                         q->ThisQInterval = 0;
1314                         }
1315                 q->LastQTime     = m->timenow;
1316                 SetNextQueryTime(m, q);
1317                 }
1318         else
1319                 {
1320                 debugf("startLLQHandshake: m->AdvertisedV4 %#a%s Server %#a:%d%s %##s (%s)",
1321                         &m->AdvertisedV4,                     mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) ? " (RFC 1918)" : "",
1322                         &q->servAddr, mDNSVal16(q->servPort), mDNSAddrIsRFC1918(&q->servAddr)             ? " (RFC 1918)" : "",
1323                         q->qname.c, DNSTypeName(q->qtype));
1324
1325                 if (q->ntries++ >= kLLQ_MAX_TRIES)
1326                         {
1327                         LogMsg("startLLQHandshake: %d failed attempts for LLQ %##s Polling.", kLLQ_MAX_TRIES, q->qname.c);
1328                         StartLLQPolling(m, q);
1329                         }
1330                 else
1331                         {
1332                         mDNSu8 *end;
1333                         LLQOptData llqData;
1334
1335                         // set llq rdata
1336                         llqData.vers  = kLLQ_Vers;
1337                         llqData.llqOp = kLLQOp_Setup;
1338                         llqData.err   = LLQErr_NoError; // Don't need to tell server UDP notification port when sending over UDP
1339                         llqData.id    = zeroOpaque64;
1340                         llqData.llqlease = kLLQ_DefLease;
1341         
1342                         InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
1343                         end = putLLQ(&m->omsg, m->omsg.data, q, &llqData);
1344                         if (!end) { LogMsg("ERROR: startLLQHandshake - putLLQ"); StartLLQPolling(m,q); return; }
1345         
1346                         mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, mDNSNULL, mDNSNULL);
1347         
1348                         // update question state
1349                         q->state         = LLQ_InitialRequest;
1350                         q->ReqLease      = kLLQ_DefLease;
1351                         q->ThisQInterval = (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
1352                         q->LastQTime     = m->timenow;
1353                         SetNextQueryTime(m, q);
1354                         }
1355                 }
1356         }
1357
1358 // forward declaration so GetServiceTarget can do reverse lookup if needed
1359 mDNSlocal void GetStaticHostname(mDNS *m);
1360
1361 mDNSexport const domainname *GetServiceTarget(mDNS *m, AuthRecord *const rr)
1362         {
1363         debugf("GetServiceTarget %##s", rr->resrec.name->c);
1364
1365         if (!rr->AutoTarget)            // If not automatically tracking this host's current name, just return the existing target
1366                 return(&rr->resrec.rdata->u.srv.target);
1367         else
1368                 {
1369 #if APPLE_OSX_mDNSResponder
1370                 DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name);
1371                 if (AuthInfo && AuthInfo->AutoTunnel)
1372                         {
1373                         // If this AutoTunnel is not yet active, start it now (which entails activating its NAT Traversal request,
1374                         // which will subsequently advertise the appropriate records when the NAT Traversal returns a result)
1375                         if (!AuthInfo->AutoTunnelNAT.clientContext && m->AutoTunnelHostAddr.b[0])
1376                                 SetupLocalAutoTunnelInterface_internal(m);
1377                         if (AuthInfo->AutoTunnelHostRecord.namestorage.c[0] == 0) return(mDNSNULL);
1378                         return(&AuthInfo->AutoTunnelHostRecord.namestorage);
1379                         }
1380                 else
1381 #endif // APPLE_OSX_mDNSResponder
1382                         {
1383                         const int srvcount = CountLabels(rr->resrec.name);
1384                         HostnameInfo *besthi = mDNSNULL, *hi;
1385                         int best = 0;
1386                         for (hi = m->Hostnames; hi; hi = hi->next)
1387                                 if (hi->arv4.state == regState_Registered || hi->arv4.state == regState_Refresh ||
1388                                         hi->arv6.state == regState_Registered || hi->arv6.state == regState_Refresh)
1389                                         {
1390                                         int x, hostcount = CountLabels(&hi->fqdn);
1391                                         for (x = hostcount < srvcount ? hostcount : srvcount; x > 0 && x > best; x--)
1392                                                 if (SameDomainName(SkipLeadingLabels(rr->resrec.name, srvcount - x), SkipLeadingLabels(&hi->fqdn, hostcount - x)))
1393                                                         { best = x; besthi = hi; }
1394                                         }
1395         
1396                         if (besthi) return(&besthi->fqdn);
1397                         }
1398                 if (m->StaticHostname.c[0]) return(&m->StaticHostname);
1399                 else GetStaticHostname(m); // asynchronously do reverse lookup for primary IPv4 address
1400                 return(mDNSNULL);
1401                 }
1402         }
1403
1404 // Called with lock held
1405 mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs)
1406         {
1407         mDNSu8 *ptr = m->omsg.data;
1408         mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
1409         mDNSOpaque16 id;
1410         mStatus err = mStatus_NoError;
1411         const domainname *target;
1412         mDNSu32 i;
1413
1414         if (m->mDNS_busy != m->mDNS_reentrancy+1)
1415                 LogMsg("SendServiceRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
1416
1417         if (mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4))  // Don't know our UpdateServer yet
1418                 {
1419                 srs->RR_SRV.LastAPTime = m->timenow;
1420                 if (srs->RR_SRV.ThisAPInterval < mDNSPlatformOneSecond * 5)
1421                         srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5;
1422                 return;
1423                 }
1424
1425         if (srs->state == regState_Registered) srs->state = regState_Refresh;
1426
1427         id = mDNS_NewMessageID(m);
1428         InitializeDNSMessage(&m->omsg.h, id, UpdateReqFlags);
1429
1430         // setup resource records
1431         SetNewRData(&srs->RR_PTR.resrec, mDNSNULL, 0);          // Update rdlength, rdestimate, rdatahash
1432         SetNewRData(&srs->RR_TXT.resrec, mDNSNULL, 0);          // Update rdlength, rdestimate, rdatahash
1433
1434         // replace port w/ NAT mapping if necessary
1435         if (srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP && !mDNSIPPortIsZero(srs->NATinfo.ExternalPort))
1436                 srs->RR_SRV.resrec.rdata->u.srv.port = srs->NATinfo.ExternalPort;
1437
1438         // construct update packet
1439         // set zone
1440         ptr = putZone(&m->omsg, ptr, end, &srs->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
1441         if (!ptr) { err = mStatus_UnknownErr; goto exit; }
1442
1443         if (srs->TestForSelfConflict)
1444                 {
1445                 // update w/ prereq that SRV already exist to make sure previous registration was ours, and delete any stale TXT records
1446                 if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numPrereqs, &srs->RR_SRV.resrec, 0))) { err = mStatus_UnknownErr; goto exit; }
1447                 if (!(ptr = putDeleteRRSet(&m->omsg, ptr, srs->RR_TXT.resrec.name, srs->RR_TXT.resrec.rrtype)))            { err = mStatus_UnknownErr; goto exit; }
1448                 }
1449
1450         else if (srs->state != regState_Refresh && srs->state != regState_UpdatePending)
1451                 {
1452                 // use SRV name for prereq
1453                 //ptr = putPrereqNameNotInUse(srs->RR_SRV.resrec.name, &m->omsg, ptr, end);
1454
1455                 // For now, until we implement RFC 4701 (DHCID RR) to detect whether an existing record is someone else using the name, or just a
1456                 // stale echo of our own previous registration before we changed our host name, we just overwrite whatever may have already been there
1457                 ptr = putDeleteRRSet(&m->omsg, ptr, srs->RR_SRV.resrec.name, kDNSQType_ANY);
1458                 if (!ptr) { err = mStatus_UnknownErr; goto exit; }
1459                 }
1460
1461         //!!!KRS Need to do bounds checking and use TCP if it won't fit!!!
1462         if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_PTR.resrec, srs->RR_PTR.resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
1463
1464         for (i = 0; i < srs->NumSubTypes; i++)
1465                 if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->SubTypes[i].resrec, srs->SubTypes[i].resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
1466
1467         if (srs->state == regState_UpdatePending) // we're updating the txt record
1468                 {
1469                 AuthRecord *txt = &srs->RR_TXT;
1470                 // delete old RData
1471                 SetNewRData(&txt->resrec, txt->OrigRData, txt->OrigRDLen);
1472                 if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->RR_TXT.resrec))) { err = mStatus_UnknownErr; goto exit; }    // delete old rdata
1473
1474                 // add new RData
1475                 SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen);
1476                 if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
1477                 }
1478         else
1479                 if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
1480
1481         target = GetServiceTarget(m, &srs->RR_SRV);
1482         if (!target || target->c[0] == 0)
1483                 {
1484                 debugf("SendServiceRegistration - no target for %##s", srs->RR_SRV.resrec.name->c);
1485                 srs->state = regState_NoTarget;
1486                 return;
1487                 }
1488
1489         if (!SameDomainName(target, &srs->RR_SRV.resrec.rdata->u.srv.target))
1490                 {
1491                 AssignDomainName(&srs->RR_SRV.resrec.rdata->u.srv.target, target);
1492                 SetNewRData(&srs->RR_SRV.resrec, mDNSNULL, 0);          // Update rdlength, rdestimate, rdatahash
1493                 }
1494
1495         ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_SRV.resrec, srs->RR_SRV.resrec.rroriginalttl);
1496         if (!ptr) { err = mStatus_UnknownErr; goto exit; }
1497
1498         if (srs->srs_uselease)
1499                 { ptr = putUpdateLease(&m->omsg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) { err = mStatus_UnknownErr; goto exit; } }
1500
1501         if (srs->state != regState_Refresh && srs->state != regState_DeregDeferred && srs->state != regState_UpdatePending)
1502                 srs->state = regState_Pending;
1503
1504         srs->id = id;
1505
1506         if (srs->Private)
1507                 {
1508                 if (srs->tcp) LogInfo("SendServiceRegistration: Disposing existing TCP connection for %s", ARDisplayString(m, &srs->RR_SRV));
1509                 if (srs->tcp) DisposeTCPConn(srs->tcp);
1510                 srs->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, srs, mDNSNULL);
1511                 if (!srs->tcp) srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2)
1512                 else if (srs->RR_SRV.ThisAPInterval < mDNSPlatformOneSecond * 30) srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 30;
1513                 }
1514         else
1515                 {
1516                 err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name));
1517                 if (err) debugf("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %d", err);
1518                 }
1519
1520         SetRecordRetry(m, &srs->RR_SRV, err);
1521         return;
1522
1523 exit:
1524         if (err)
1525                 {
1526                 LogMsg("SendServiceRegistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err, srs->RR_SRV.resrec.name->c);
1527                 unlinkSRS(m, srs);
1528                 srs->state = regState_Unregistered;
1529
1530                 mDNS_DropLockBeforeCallback();
1531                 srs->ServiceCallback(m, srs, err);
1532                 mDNS_ReclaimLockAfterCallback();
1533                 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
1534                 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
1535                 }
1536         }
1537
1538 mDNSlocal const domainname *PUBLIC_UPDATE_SERVICE_TYPE  = (const domainname*)"\x0B_dns-update"     "\x04_udp";
1539 mDNSlocal const domainname *PUBLIC_LLQ_SERVICE_TYPE     = (const domainname*)"\x08_dns-llq"        "\x04_udp";
1540
1541 mDNSlocal const domainname *PRIVATE_UPDATE_SERVICE_TYPE = (const domainname*)"\x0F_dns-update-tls" "\x04_tcp";
1542 mDNSlocal const domainname *PRIVATE_QUERY_SERVICE_TYPE  = (const domainname*)"\x0E_dns-query-tls"  "\x04_tcp";
1543 mDNSlocal const domainname *PRIVATE_LLQ_SERVICE_TYPE    = (const domainname*)"\x0C_dns-llq-tls"    "\x04_tcp";
1544
1545 #define ZoneDataSRV(X) (\
1546         (X)->ZoneService == ZoneServiceUpdate ? ((X)->ZonePrivate ? PRIVATE_UPDATE_SERVICE_TYPE : PUBLIC_UPDATE_SERVICE_TYPE) : \
1547         (X)->ZoneService == ZoneServiceQuery  ? ((X)->ZonePrivate ? PRIVATE_QUERY_SERVICE_TYPE  : (const domainname*)""     ) : \
1548         (X)->ZoneService == ZoneServiceLLQ    ? ((X)->ZonePrivate ? PRIVATE_LLQ_SERVICE_TYPE    : PUBLIC_LLQ_SERVICE_TYPE   ) : (const domainname*)"")
1549
1550 // Forward reference: GetZoneData_StartQuery references GetZoneData_QuestionCallback, and
1551 // GetZoneData_QuestionCallback calls GetZoneData_StartQuery
1552 mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qtype);
1553
1554 // GetZoneData_QuestionCallback is called from normal client callback context (core API calls allowed)
1555 mDNSlocal void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
1556         {
1557         ZoneData *zd = (ZoneData*)question->QuestionContext;
1558
1559         debugf("GetZoneData_QuestionCallback: %s %s", AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
1560
1561         if (!AddRecord) return;                                                                                         // Don't care about REMOVE events
1562         if (AddRecord == QC_addnocache && answer->rdlength == 0) return;        // Don't care about transient failure indications
1563         if (answer->rrtype != question->qtype) return;                                          // Don't care about CNAMEs
1564
1565         if (answer->rrtype == kDNSType_SOA)
1566                 {
1567                 debugf("GetZoneData GOT SOA %s", RRDisplayString(m, answer));
1568                 mDNS_StopQuery(m, question);
1569                 if (answer->rdlength)
1570                         {
1571                         AssignDomainName(&zd->ZoneName, answer->name);
1572                         zd->ZoneClass = answer->rrclass;
1573                         AssignDomainName(&zd->question.qname, &zd->ZoneName);
1574                         GetZoneData_StartQuery(m, zd, kDNSType_SRV);
1575                         }
1576                 else if (zd->CurrentSOA->c[0])
1577                         {
1578                         zd->CurrentSOA = (domainname *)(zd->CurrentSOA->c + zd->CurrentSOA->c[0]+1);
1579                         AssignDomainName(&zd->question.qname, zd->CurrentSOA);
1580                         GetZoneData_StartQuery(m, zd, kDNSType_SOA);
1581                         }
1582                 else
1583                         {
1584                         LogInfo("GetZoneData recursed to root label of %##s without finding SOA", zd->ChildName.c);
1585                         zd->ZoneDataCallback(m, mStatus_NoSuchNameErr, zd);
1586                         mDNSPlatformMemFree(zd);
1587                         }
1588                 }
1589         else if (answer->rrtype == kDNSType_SRV)
1590                 {
1591                 debugf("GetZoneData GOT SRV %s", RRDisplayString(m, answer));
1592                 mDNS_StopQuery(m, question);
1593 // Right now we don't want to fail back to non-encrypted operations
1594 // If the AuthInfo has the AutoTunnel field set, then we want private or nothing
1595 // <rdar://problem/5687667> BTMM: Don't fallback to unencrypted operations when SRV lookup fails
1596 #if 0
1597                 if (!answer->rdlength && zd->ZonePrivate && zd->ZoneService != ZoneServiceQuery)
1598                         {
1599                         zd->ZonePrivate = mDNSfalse;    // Causes ZoneDataSRV() to yield a different SRV name when building the query
1600                         GetZoneData_StartQuery(m, zd, kDNSType_SRV);            // Try again, non-private this time
1601                         }
1602                 else
1603 #endif
1604                         {
1605                         if (answer->rdlength)
1606                                 {
1607                                 AssignDomainName(&zd->Host, &answer->rdata->u.srv.target);
1608                                 zd->Port = answer->rdata->u.srv.port;
1609                                 AssignDomainName(&zd->question.qname, &zd->Host);
1610                                 GetZoneData_StartQuery(m, zd, kDNSType_A);
1611                                 }
1612                         else
1613                                 {
1614                                 zd->ZonePrivate = mDNSfalse;
1615                                 zd->Host.c[0] = 0;
1616                                 zd->Port = zeroIPPort;
1617                                 zd->Addr = zeroAddr;
1618                                 zd->ZoneDataCallback(m, mStatus_NoError, zd);
1619                                 mDNSPlatformMemFree(zd);
1620                                 }
1621                         }
1622                 }
1623         else if (answer->rrtype == kDNSType_A)
1624                 {
1625                 debugf("GetZoneData GOT A %s", RRDisplayString(m, answer));
1626                 mDNS_StopQuery(m, question);
1627                 zd->Addr.type  = mDNSAddrType_IPv4;
1628                 zd->Addr.ip.v4 = (answer->rdlength == 4) ? answer->rdata->u.ipv4 : zerov4Addr;
1629                 // In order to simulate firewalls blocking our outgoing TCP connections, returning immediate ICMP errors or TCP resets,
1630                 // the code below will make us try to connect to loopback, resulting in an immediate "port unreachable" failure.
1631                 // This helps us test to make sure we handle this case gracefully
1632                 // <rdar://problem/5607082> BTMM: mDNSResponder taking 100 percent CPU after upgrading to 10.5.1
1633 #if 0
1634                 zd->Addr.ip.v4.b[0] = 127;
1635                 zd->Addr.ip.v4.b[1] = 0;
1636                 zd->Addr.ip.v4.b[2] = 0;
1637                 zd->Addr.ip.v4.b[3] = 1;
1638 #endif
1639                 zd->ZoneDataCallback(m, mStatus_NoError, zd);
1640                 mDNSPlatformMemFree(zd);
1641                 }
1642         }
1643
1644 // GetZoneData_StartQuery is called from normal client context (lock not held, or client callback)
1645 mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qtype)
1646         {
1647         if (qtype == kDNSType_SRV)
1648                 {
1649                 AssignDomainName(&zd->question.qname, ZoneDataSRV(zd));
1650                 AppendDomainName(&zd->question.qname, &zd->ZoneName);
1651                 debugf("lookupDNSPort %##s", zd->question.qname.c);
1652                 }
1653
1654         zd->question.ThisQInterval       = -1;          // So that GetZoneData_QuestionCallback() knows whether to cancel this question (Is this necessary?)
1655         zd->question.InterfaceID         = mDNSInterface_Any;
1656         zd->question.Target              = zeroAddr;
1657         //zd->question.qname.c[0]        = 0;                   // Already set
1658         zd->question.qtype               = qtype;
1659         zd->question.qclass              = kDNSClass_IN;
1660         zd->question.LongLived           = mDNSfalse;
1661         zd->question.ExpectUnique        = mDNStrue;
1662         zd->question.ForceMCast          = mDNSfalse;
1663         zd->question.ReturnIntermed      = mDNStrue;
1664         zd->question.QuestionCallback    = GetZoneData_QuestionCallback;
1665         zd->question.QuestionContext     = zd;
1666
1667         //LogMsg("GetZoneData_StartQuery %##s (%s) %p", zd->question.qname.c, DNSTypeName(zd->question.qtype), zd->question.Private);
1668         return(mDNS_StartQuery(m, &zd->question));
1669         }
1670
1671 // StartGetZoneData is an internal routine (i.e. must be called with the lock already held)
1672 mDNSexport ZoneData *StartGetZoneData(mDNS *const m, const domainname *const name, const ZoneService target, ZoneDataCallback callback, void *ZoneDataContext)
1673         {
1674         DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, name);
1675         int initialskip = (AuthInfo && AuthInfo->AutoTunnel) ? DomainNameLength(name) - DomainNameLength(&AuthInfo->domain) : 0;
1676         ZoneData *zd = (ZoneData*)mDNSPlatformMemAllocate(sizeof(ZoneData));
1677         if (!zd) { LogMsg("ERROR: StartGetZoneData - mDNSPlatformMemAllocate failed"); return mDNSNULL; }
1678         mDNSPlatformMemZero(zd, sizeof(ZoneData));
1679         AssignDomainName(&zd->ChildName, name);
1680         zd->ZoneService      = target;
1681         zd->CurrentSOA       = (domainname *)(&zd->ChildName.c[initialskip]);
1682         zd->ZoneName.c[0]    = 0;
1683         zd->ZoneClass        = 0;
1684         zd->Host.c[0]        = 0;
1685         zd->Port             = zeroIPPort;
1686         zd->Addr             = zeroAddr;
1687         zd->ZonePrivate      = AuthInfo && AuthInfo->AutoTunnel ? mDNStrue : mDNSfalse;
1688         zd->ZoneDataCallback = callback;
1689         zd->ZoneDataContext  = ZoneDataContext;
1690
1691         zd->question.QuestionContext = zd;
1692         AssignDomainName(&zd->question.qname, zd->CurrentSOA);
1693
1694         mDNS_DropLockBeforeCallback();          // GetZoneData_StartQuery expects to be called from a normal callback, so we emulate that here
1695         GetZoneData_StartQuery(m, zd, kDNSType_SOA);
1696         mDNS_ReclaimLockAfterCallback();
1697
1698         return zd;
1699         }
1700
1701 // GetZoneData queries are a special case -- even if we have a key for them, we don't do them privately,
1702 // because that would result in an infinite loop (i.e. to do a private query we first need to get
1703 // the _dns-query-tls SRV record for the zone, and we can't do *that* privately because to do so
1704 // we'd need to already know the _dns-query-tls SRV record.
1705 // Also, as a general rule, we never do SOA queries privately
1706 mDNSexport DomainAuthInfo *GetAuthInfoForQuestion(mDNS *m, const DNSQuestion *const q)  // Must be called with lock held
1707         {
1708         if (q->QuestionCallback == GetZoneData_QuestionCallback) return(mDNSNULL);
1709         if (q->qtype            == kDNSType_SOA                ) return(mDNSNULL);
1710         return(GetAuthInfoForName_internal(m, &q->qname));
1711         }
1712
1713 // ***************************************************************************
1714 #if COMPILER_LIKES_PRAGMA_MARK
1715 #pragma mark - host name and interface management
1716 #endif
1717
1718 // Called in normal client context (lock not held)
1719 mDNSlocal void CompleteSRVNatMap(mDNS *m, NATTraversalInfo *n)
1720         {
1721         ServiceRecordSet *srs = (ServiceRecordSet *)n->clientContext;
1722         debugf("SRVNatMap complete %.4a IntPort %u ExternalPort %u NATLease %u", &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), n->NATLease);
1723
1724         if (!srs) { LogMsg("CompleteSRVNatMap called with unknown ServiceRecordSet object"); return; }
1725         if (!n->NATLease) return;
1726
1727         mDNS_Lock(m);
1728         if (!mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4))
1729                 SendServiceRegistration(m, srs);        // non-zero server address means we already have necessary zone data to send update
1730         else
1731                 {
1732                 // SHOULD NEVER HAPPEN!
1733                 LogInfo("ERROR: CompleteSRVNatMap called but srs->SRSUpdateServer.ip.v4 is zero!");
1734                 srs->state = regState_FetchingZoneData;
1735                 if (srs->srs_nta) CancelGetZoneData(m, srs->srs_nta); // Make sure we cancel old one before we start a new one
1736                 srs->srs_nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs);
1737                 }
1738         mDNS_Unlock(m);
1739         }
1740
1741 mDNSlocal void StartSRVNatMap(mDNS *m, ServiceRecordSet *srs)
1742         {
1743         const mDNSu8 *p = srs->RR_PTR.resrec.name->c;
1744         if (p[0]) p += 1 + p[0];
1745         if      (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp")) srs->NATinfo.Protocol = NATOp_MapTCP;
1746         else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) srs->NATinfo.Protocol = NATOp_MapUDP;
1747         else { LogMsg("StartSRVNatMap: could not determine transport protocol of service %##s", srs->RR_SRV.resrec.name->c); return; }
1748         
1749         if (srs->NATinfo.clientContext) mDNS_StopNATOperation_internal(m, &srs->NATinfo);
1750         // Don't try to set IntPort here --
1751         // SendServiceRegistration overwrites srs->RR_SRV.resrec.rdata->u.srv.port with external (mapped) port number
1752         //srs->NATinfo.IntPort      = srs->RR_SRV.resrec.rdata->u.srv.port;
1753         srs->NATinfo.RequestedPort  = srs->RR_SRV.resrec.rdata->u.srv.port;
1754         srs->NATinfo.NATLease       = 0;                // Request default lease
1755         srs->NATinfo.clientCallback = CompleteSRVNatMap;
1756         srs->NATinfo.clientContext  = srs;
1757         mDNS_StartNATOperation_internal(m, &srs->NATinfo);
1758         }
1759
1760 // Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
1761 mDNSexport void ServiceRegistrationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneData)
1762         {
1763         ServiceRecordSet *srs = (ServiceRecordSet *)zoneData->ZoneDataContext;
1764
1765         if (m->mDNS_busy != m->mDNS_reentrancy)
1766                 LogMsg("ServiceRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
1767
1768         if (!srs->RR_SRV.resrec.rdata)
1769                 { LogMsg("ServiceRegistrationGotZoneData: ERROR: srs->RR_SRV.resrec.rdata is NULL"); return; }
1770
1771         srs->srs_nta = mDNSNULL;
1772
1773         // Start off assuming we're going to use a lease
1774         // If we get an error from the server, and the update port as given in the SRV record is 53, then we'll retry without the lease option
1775         srs->srs_uselease = mDNStrue;
1776
1777         if (err || !zoneData) return;
1778
1779         if (mDNSIPPortIsZero(zoneData->Port) || mDNSAddressIsZero(&zoneData->Addr)) return;
1780
1781         // cache zone data
1782         AssignDomainName(&srs->zone, &zoneData->ZoneName);
1783         srs->SRSUpdateServer.type = mDNSAddrType_IPv4;
1784         srs->SRSUpdateServer      = zoneData->Addr;
1785         srs->SRSUpdatePort        = zoneData->Port;
1786         srs->Private              = zoneData->ZonePrivate;
1787
1788         srs->RR_SRV.LastAPTime     = m->timenow;
1789         srs->RR_SRV.ThisAPInterval = 0;
1790
1791         debugf("ServiceRegistrationGotZoneData My IPv4 %#a%s Server %#a:%d%s for %##s",
1792                 &m->AdvertisedV4, mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) ? " (RFC1918)" : "",
1793                 &srs->SRSUpdateServer, mDNSVal16(srs->SRSUpdatePort), mDNSAddrIsRFC1918(&srs->SRSUpdateServer) ? " (RFC1918)" : "",
1794                 srs->RR_SRV.resrec.name->c);
1795
1796         // If we have non-zero service port (always?)
1797         // and a private address, and update server is non-private
1798         // and this service is AutoTarget
1799         // then initiate a NAT mapping request. On completion it will do SendServiceRegistration() for us
1800         if (!mDNSIPPortIsZero(srs->RR_SRV.resrec.rdata->u.srv.port) &&
1801                 mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&srs->SRSUpdateServer) &&
1802                 srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP)
1803                 {
1804                 srs->state = regState_NATMap;
1805                 debugf("ServiceRegistrationGotZoneData StartSRVNatMap");
1806                 StartSRVNatMap(m, srs);
1807                 }
1808         else
1809                 {
1810                 mDNS_Lock(m);
1811                 SendServiceRegistration(m, srs);
1812                 mDNS_Unlock(m);
1813                 }
1814         }
1815
1816 mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
1817         {
1818         mDNSOpaque16 id;
1819         mDNSu8 *ptr = m->omsg.data;
1820         mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
1821         mStatus err = mStatus_UnknownErr;
1822         mDNSu32 i;
1823
1824         if (mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4))  // Don't know our UpdateServer yet
1825                 {
1826                 srs->RR_SRV.LastAPTime = m->timenow;
1827                 if (srs->RR_SRV.ThisAPInterval < mDNSPlatformOneSecond * 5)
1828                         srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5;
1829                 return;
1830                 }
1831
1832         id = mDNS_NewMessageID(m);
1833         InitializeDNSMessage(&m->omsg.h, id, UpdateReqFlags);
1834
1835         // put zone
1836         ptr = putZone(&m->omsg, ptr, end, &srs->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
1837         if (!ptr) { LogMsg("ERROR: SendServiceDeregistration - putZone"); err = mStatus_UnknownErr; goto exit; }
1838
1839         if (!(ptr = putDeleteAllRRSets(&m->omsg, ptr, srs->RR_SRV.resrec.name))) { err = mStatus_UnknownErr; goto exit; } // this deletes SRV, TXT, and Extras
1840         if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->RR_PTR.resrec))) { err = mStatus_UnknownErr; goto exit; }
1841         for (i = 0; i < srs->NumSubTypes; i++)
1842                 if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->SubTypes[i].resrec))) { err = mStatus_UnknownErr; goto exit; }
1843
1844         srs->id    = id;
1845         srs->state = regState_DeregPending;
1846         srs->RR_SRV.expire = 0;         // Indicate that we have no active registration any more
1847
1848         if (srs->Private)
1849                 {
1850                 LogInfo("SendServiceDeregistration TCP %p %s", srs->tcp, ARDisplayString(m, &srs->RR_SRV));
1851                 if (srs->tcp) LogInfo("SendServiceDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m, &srs->RR_SRV));
1852                 if (srs->tcp) DisposeTCPConn(srs->tcp);
1853                 srs->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, srs, mDNSNULL);
1854                 if (!srs->tcp) srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2)
1855                 else if (srs->RR_SRV.ThisAPInterval < mDNSPlatformOneSecond * 30) srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 30;
1856                 }
1857         else
1858                 {
1859                 err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name));
1860                 if (err && err != mStatus_TransientErr) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %d", err); goto exit; }
1861                 }
1862
1863         SetRecordRetry(m, &srs->RR_SRV, err);
1864         return;
1865
1866 exit:
1867         if (err)
1868                 {
1869                 LogMsg("SendServiceDeregistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err, srs->RR_SRV.resrec.name->c);
1870                 unlinkSRS(m, srs);
1871                 srs->state = regState_Unregistered;
1872                 }
1873         }
1874
1875 // Called with lock held
1876 mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs)
1877         {
1878         ExtraResourceRecord *e;
1879
1880         // Target change if:
1881         // We have a target and were previously waiting for one, or
1882         // We had a target and no longer do, or
1883         // The target has changed
1884
1885         domainname *curtarget = &srs->RR_SRV.resrec.rdata->u.srv.target;
1886         const domainname *const nt = GetServiceTarget(m, &srs->RR_SRV);
1887         const domainname *const newtarget = nt ? nt : (domainname*)"";
1888         mDNSBool TargetChanged = (newtarget->c[0] && srs->state == regState_NoTarget) || !SameDomainName(curtarget, newtarget);
1889         mDNSBool HaveZoneData  = !mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4);
1890
1891         // Nat state change if:
1892         // We were behind a NAT, and now we are behind a new NAT, or
1893         // We're not behind a NAT but our port was previously mapped to a different external port
1894         // We were not behind a NAT and now we are
1895
1896         mDNSIPPort port        = srs->RR_SRV.resrec.rdata->u.srv.port;
1897         mDNSBool NowNeedNATMAP = (srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP && !mDNSIPPortIsZero(port) && mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&srs->SRSUpdateServer));
1898         mDNSBool WereBehindNAT = (srs->NATinfo.clientContext != mDNSNULL);
1899         mDNSBool PortWasMapped = (srs->NATinfo.clientContext && !mDNSSameIPPort(srs->NATinfo.RequestedPort, port));             // I think this is always false -- SC Sept 07
1900         mDNSBool NATChanged    = (!WereBehindNAT && NowNeedNATMAP) || (!NowNeedNATMAP && PortWasMapped);
1901
1902         debugf("UpdateSRV %##s newtarget %##s TargetChanged %d HaveZoneData %d port %d NowNeedNATMAP %d WereBehindNAT %d PortWasMapped %d NATChanged %d",
1903                 srs->RR_SRV.resrec.name->c, newtarget,
1904                 TargetChanged, HaveZoneData, mDNSVal16(port), NowNeedNATMAP, WereBehindNAT, PortWasMapped, NATChanged);
1905
1906         if (m->mDNS_busy != m->mDNS_reentrancy+1)
1907                 LogMsg("UpdateSRV: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
1908
1909         if (!TargetChanged && !NATChanged) return;
1910
1911         switch(srs->state)
1912                 {
1913                 case regState_FetchingZoneData:
1914                 case regState_DeregPending:
1915                 case regState_DeregDeferred:
1916                 case regState_Unregistered:
1917                 case regState_NATMap:
1918                 case regState_ExtraQueued:
1919                         // In these states, the SRV has either not yet been registered (it will get up-to-date information when it is)
1920                         // or is in the process of, or has already been, deregistered
1921                         return;
1922
1923                 case regState_Pending:
1924                 case regState_Refresh:
1925                 case regState_UpdatePending:
1926                         // let the in-flight operation complete before updating
1927                         srs->SRVUpdateDeferred = mDNStrue;
1928                         return;
1929
1930                 case regState_NATError:
1931                         if (!NATChanged) return;
1932                         // if nat changed, register if we have a target (below)
1933
1934                 case regState_NoTarget:
1935                         if (newtarget->c[0])
1936                                 {
1937                                 debugf("UpdateSRV: %s service %##s", HaveZoneData ? (NATChanged && NowNeedNATMAP ? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs->RR_SRV.resrec.name->c);
1938                                 if (!HaveZoneData)
1939                                         {
1940                                         srs->state = regState_FetchingZoneData;
1941                                         if (srs->srs_nta) CancelGetZoneData(m, srs->srs_nta); // Make sure we cancel old one before we start a new one
1942                                         srs->srs_nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs);
1943                                         }
1944                                 else
1945                                         {
1946                                         if (srs->NATinfo.clientContext && (NATChanged || !NowNeedNATMAP))
1947                                                 {
1948                                                 mDNS_StopNATOperation_internal(m, &srs->NATinfo);
1949                                                 srs->NATinfo.clientContext = mDNSNULL;
1950                                                 }
1951                                         if (NATChanged && NowNeedNATMAP && srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP)
1952                                                 { srs->state = regState_NATMap; StartSRVNatMap(m, srs); }
1953                                         else SendServiceRegistration(m, srs);
1954                                         }
1955                                 }
1956                         return;
1957
1958                 case regState_Registered:
1959                         // target or nat changed.  deregister service.  upon completion, we'll look for a new target
1960                         debugf("UpdateSRV: SRV record changed for service %##s - deregistering (will re-register with new SRV)",  srs->RR_SRV.resrec.name->c);
1961                         for (e = srs->Extras; e; e = e->next) e->r.state = regState_ExtraQueued;        // extra will be re-registed if the service is re-registered
1962                         srs->SRVChanged = mDNStrue;
1963                         SendServiceDeregistration(m, srs);
1964                         return;
1965
1966                 default: LogMsg("UpdateSRV: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c);
1967                 }
1968         }
1969
1970 // Called with lock held
1971 mDNSlocal void UpdateSRVRecords(mDNS *m)
1972         {
1973         debugf("UpdateSRVRecords%s", m->SleepState ? " (ignored due to SleepState)" : "");
1974         if (m->SleepState) return;
1975
1976         if (CurrentServiceRecordSet)
1977                 LogMsg("UpdateSRVRecords ERROR CurrentServiceRecordSet already set");
1978         CurrentServiceRecordSet = m->ServiceRegistrations;
1979         
1980         while (CurrentServiceRecordSet)
1981                 {
1982                 ServiceRecordSet *s = CurrentServiceRecordSet;
1983                 CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next;
1984                 UpdateSRV(m, s);
1985                 }
1986
1987         mDNS_DropLockBeforeCallback();          // mDNS_SetFQDN expects to be called without the lock held, so we emulate that here
1988         mDNS_SetFQDN(m);
1989         mDNS_ReclaimLockAfterCallback();
1990         }
1991
1992 // Forward reference: AdvertiseHostname references HostnameCallback, and HostnameCallback calls AdvertiseHostname
1993 mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
1994
1995 // Called in normal client context (lock not held)
1996 mDNSlocal void hostnameGetPublicAddressCallback(mDNS *m, NATTraversalInfo *n)
1997         {
1998         HostnameInfo *h = (HostnameInfo *)n->clientContext;
1999
2000         if (!h) { LogMsg("RegisterHostnameRecord: registration cancelled"); return; }
2001
2002         if (!n->Result)
2003                 {
2004                 if (mDNSIPv4AddressIsZero(n->ExternalAddress) || mDNSv4AddrIsRFC1918(&n->ExternalAddress)) return;
2005                 
2006                 if (h->arv4.resrec.RecordType)
2007                         {
2008                         if (mDNSSameIPv4Address(h->arv4.resrec.rdata->u.ipv4, n->ExternalAddress)) return;      // If address unchanged, do nothing
2009                         LogInfo("Updating hostname %##s IPv4 from %.4a to %.4a (NAT gateway's external address)",
2010                                 h->arv4.resrec.name->c, &h->arv4.resrec.rdata->u.ipv4, &n->ExternalAddress);
2011                         mDNS_Deregister(m, &h->arv4);   // mStatus_MemFree callback will re-register with new address
2012                         }
2013                 else
2014                         {
2015                         LogInfo("Advertising hostname %##s IPv4 %.4a (NAT gateway's external address)", h->arv4.resrec.name->c, &n->ExternalAddress);
2016                         h->arv4.resrec.RecordType = kDNSRecordTypeKnownUnique;
2017                         h->arv4.resrec.rdata->u.ipv4 = n->ExternalAddress;
2018                         mDNS_Register(m, &h->arv4);
2019                         }
2020                 }
2021         }
2022
2023 // register record or begin NAT traversal
2024 mDNSlocal void AdvertiseHostname(mDNS *m, HostnameInfo *h)
2025         {
2026         if (!mDNSIPv4AddressIsZero(m->AdvertisedV4.ip.v4) && h->arv4.resrec.RecordType == kDNSRecordTypeUnregistered)
2027                 {
2028                 mDNS_SetupResourceRecord(&h->arv4, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnregistered, HostnameCallback, h);
2029                 AssignDomainName(&h->arv4.namestorage, &h->fqdn);
2030                 h->arv4.resrec.rdata->u.ipv4 = m->AdvertisedV4.ip.v4;
2031                 h->arv4.state = regState_Unregistered;
2032                 if (mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4))
2033                         {
2034                         // If we already have a NAT query active, stop it and restart it to make sure we get another callback
2035                         if (h->natinfo.clientContext) mDNS_StopNATOperation_internal(m, &h->natinfo);
2036                         h->natinfo.Protocol         = 0;
2037                         h->natinfo.IntPort          = zeroIPPort;
2038                         h->natinfo.RequestedPort    = zeroIPPort;
2039                         h->natinfo.NATLease         = 0;
2040                         h->natinfo.clientCallback   = hostnameGetPublicAddressCallback;
2041                         h->natinfo.clientContext    = h;
2042                         mDNS_StartNATOperation_internal(m, &h->natinfo);
2043                         }
2044                 else
2045                         {
2046                         LogInfo("Advertising hostname %##s IPv4 %.4a", h->arv4.resrec.name->c, &m->AdvertisedV4.ip.v4);
2047                         h->arv4.resrec.RecordType = kDNSRecordTypeKnownUnique;
2048                         mDNS_Register_internal(m, &h->arv4);
2049                         }
2050                 }
2051
2052         if (!mDNSIPv6AddressIsZero(m->AdvertisedV6.ip.v6) && h->arv6.resrec.RecordType == kDNSRecordTypeUnregistered)
2053                 {
2054                 mDNS_SetupResourceRecord(&h->arv6, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL, kDNSRecordTypeKnownUnique, HostnameCallback, h);
2055                 AssignDomainName(&h->arv6.namestorage, &h->fqdn);
2056                 h->arv6.resrec.rdata->u.ipv6 = m->AdvertisedV6.ip.v6;
2057                 h->arv6.state = regState_Unregistered;
2058                 LogInfo("Advertising hostname %##s IPv6 %.16a", h->arv6.resrec.name->c, &m->AdvertisedV6.ip.v6);
2059                 mDNS_Register_internal(m, &h->arv6);
2060                 }
2061         }
2062
2063 mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
2064         {
2065         HostnameInfo *hi = (HostnameInfo *)rr->RecordContext;
2066
2067         if (result == mStatus_MemFree)
2068                 {
2069                 if (hi)
2070                         {
2071                         // If we're still in the Hostnames list, update to new address
2072                         HostnameInfo *i;
2073                         LogInfo("HostnameCallback: Got mStatus_MemFree for %p %p %s", hi, rr, ARDisplayString(m, rr));
2074                         for (i = m->Hostnames; i; i = i->next)
2075                                 if (rr == &i->arv4 || rr == &i->arv6)
2076                                         { mDNS_Lock(m); AdvertiseHostname(m, i); mDNS_Unlock(m); return; }
2077
2078                         // Else, we're not still in the Hostnames list, so free the memory
2079                         if (hi->arv4.resrec.RecordType == kDNSRecordTypeUnregistered &&
2080                                 hi->arv6.resrec.RecordType == kDNSRecordTypeUnregistered)
2081                                 {
2082                                 if (hi->natinfo.clientContext) mDNS_StopNATOperation_internal(m, &hi->natinfo);
2083                                 hi->natinfo.clientContext = mDNSNULL;
2084                                 mDNSPlatformMemFree(hi);        // free hi when both v4 and v6 AuthRecs deallocated
2085                                 }
2086                         }
2087                 return;
2088                 }
2089
2090         if (result)
2091                 {
2092                 // don't unlink or free - we can retry when we get a new address/router
2093                 if (rr->resrec.rrtype == kDNSType_A)
2094                         LogMsg("HostnameCallback: Error %d for registration of %##s IP %.4a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv4);
2095                 else
2096                         LogMsg("HostnameCallback: Error %d for registration of %##s IP %.16a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
2097                 if (!hi) { mDNSPlatformMemFree(rr); return; }
2098                 if (rr->state != regState_Unregistered) LogMsg("Error: HostnameCallback invoked with error code for record not in regState_Unregistered!");
2099
2100                 if (hi->arv4.state == regState_Unregistered &&
2101                         hi->arv6.state == regState_Unregistered)
2102                         {
2103                         // only deliver status if both v4 and v6 fail
2104                         rr->RecordContext = (void *)hi->StatusContext;
2105                         if (hi->StatusCallback)
2106                                 hi->StatusCallback(m, rr, result); // client may NOT make API calls here
2107                         rr->RecordContext = (void *)hi;
2108                         }
2109                 return;
2110                 }
2111
2112         // register any pending services that require a target
2113         mDNS_Lock(m);
2114         UpdateSRVRecords(m);
2115         mDNS_Unlock(m);
2116
2117         // Deliver success to client
2118         if (!hi) { LogMsg("HostnameCallback invoked with orphaned address record"); return; }
2119         if (rr->resrec.rrtype == kDNSType_A)
2120                 LogInfo("Registered hostname %##s IP %.4a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv4);
2121         else
2122                 LogInfo("Registered hostname %##s IP %.16a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
2123
2124         rr->RecordContext = (void *)hi->StatusContext;
2125         if (hi->StatusCallback)
2126                 hi->StatusCallback(m, rr, result); // client may NOT make API calls here
2127         rr->RecordContext = (void *)hi;
2128         }
2129
2130 mDNSlocal void FoundStaticHostname(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
2131         {
2132         const domainname *pktname = &answer->rdata->u.name;
2133         domainname *storedname = &m->StaticHostname;
2134         HostnameInfo *h = m->Hostnames;
2135
2136         (void)question;
2137
2138         debugf("FoundStaticHostname: %##s -> %##s (%s)", question->qname.c, answer->rdata->u.name.c, AddRecord ? "added" : "removed");
2139         if (AddRecord && !SameDomainName(pktname, storedname))
2140                 {
2141                 AssignDomainName(storedname, pktname);
2142                 while (h)
2143                         {
2144                         if (h->arv4.state == regState_FetchingZoneData || h->arv4.state == regState_Pending || h->arv4.state == regState_NATMap ||
2145                                 h->arv6.state == regState_FetchingZoneData || h->arv6.state == regState_Pending)
2146                                 {
2147                                 // 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
2148                                 m->NextSRVUpdate = NonZeroTime(m->timenow + 5 * mDNSPlatformOneSecond);
2149                                 return;
2150                                 }
2151                         h = h->next;
2152                         }
2153                 mDNS_Lock(m);
2154                 UpdateSRVRecords(m);
2155                 mDNS_Unlock(m);
2156                 }
2157         else if (!AddRecord && SameDomainName(pktname, storedname))
2158                 {
2159                 mDNS_Lock(m);
2160                 storedname->c[0] = 0;
2161                 UpdateSRVRecords(m);
2162                 mDNS_Unlock(m);
2163                 }
2164         }
2165
2166 // Called with lock held
2167 mDNSlocal void GetStaticHostname(mDNS *m)
2168         {
2169         char buf[MAX_REVERSE_MAPPING_NAME_V4];
2170         DNSQuestion *q = &m->ReverseMap;
2171         mDNSu8 *ip = m->AdvertisedV4.ip.v4.b;
2172         mStatus err;
2173
2174         if (m->ReverseMap.ThisQInterval != -1) return; // already running
2175         if (mDNSIPv4AddressIsZero(m->AdvertisedV4.ip.v4)) return;
2176
2177         mDNSPlatformMemZero(q, sizeof(*q));
2178         // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
2179         mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", ip[3], ip[2], ip[1], ip[0]);
2180         if (!MakeDomainNameFromDNSNameString(&q->qname, buf)) { LogMsg("Error: GetStaticHostname - bad name %s", buf); return; }
2181
2182         q->InterfaceID      = mDNSInterface_Any;
2183         q->Target           = zeroAddr;
2184         q->qtype            = kDNSType_PTR;
2185         q->qclass           = kDNSClass_IN;
2186         q->LongLived        = mDNSfalse;
2187         q->ExpectUnique     = mDNSfalse;
2188         q->ForceMCast       = mDNSfalse;
2189         q->ReturnIntermed   = mDNStrue;
2190         q->QuestionCallback = FoundStaticHostname;
2191         q->QuestionContext  = mDNSNULL;
2192
2193         LogInfo("GetStaticHostname: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
2194         err = mDNS_StartQuery_internal(m, q);
2195         if (err) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err);
2196         }
2197
2198 mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
2199    {
2200         HostnameInfo **ptr = &m->Hostnames;
2201
2202         LogInfo("mDNS_AddDynDNSHostName %##s", fqdn);
2203
2204         while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next;
2205         if (*ptr) { LogMsg("DynDNSHostName %##s already in list", fqdn->c); return; }
2206
2207         // allocate and format new address record
2208         *ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
2209         if (!*ptr) { LogMsg("ERROR: mDNS_AddDynDNSHostName - malloc"); return; }
2210
2211         mDNSPlatformMemZero(*ptr, sizeof(**ptr));
2212         AssignDomainName(&(*ptr)->fqdn, fqdn);
2213         (*ptr)->arv4.state     = regState_Unregistered;
2214         (*ptr)->arv6.state     = regState_Unregistered;
2215         (*ptr)->StatusCallback = StatusCallback;
2216         (*ptr)->StatusContext  = StatusContext;
2217
2218         AdvertiseHostname(m, *ptr);
2219         }
2220
2221 mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn)
2222         {
2223         HostnameInfo **ptr = &m->Hostnames;
2224
2225         LogInfo("mDNS_RemoveDynDNSHostName %##s", fqdn);
2226
2227         while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next;
2228         if (!*ptr) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn->c);
2229         else
2230                 {
2231                 HostnameInfo *hi = *ptr;
2232                 // We do it this way because, if we have no active v6 record, the "mDNS_Deregister_internal(m, &hi->arv4);"
2233                 // below could free the memory, and we have to make sure we don't touch hi fields after that.
2234                 mDNSBool f4 = hi->arv4.resrec.RecordType != kDNSRecordTypeUnregistered && hi->arv4.state != regState_Unregistered;
2235                 mDNSBool f6 = hi->arv6.resrec.RecordType != kDNSRecordTypeUnregistered && hi->arv6.state != regState_Unregistered;
2236                 if (f4) LogInfo("mDNS_RemoveDynDNSHostName removing v4 %##s", fqdn);
2237                 if (f6) LogInfo("mDNS_RemoveDynDNSHostName removing v6 %##s", fqdn);
2238                 *ptr = (*ptr)->next; // unlink
2239                 if (f4) mDNS_Deregister_internal(m, &hi->arv4, mDNS_Dereg_normal);
2240                 if (f6) mDNS_Deregister_internal(m, &hi->arv6, mDNS_Dereg_normal);
2241                 // When both deregistrations complete we'll free the memory in the mStatus_MemFree callback
2242                 }
2243         UpdateSRVRecords(m);
2244         }
2245
2246 // Currently called without holding the lock
2247 // Maybe we should change that?
2248 mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router)
2249         {
2250         mDNSBool v4Changed, v6Changed, RouterChanged;
2251
2252         if (m->mDNS_busy != m->mDNS_reentrancy)
2253                 LogMsg("mDNS_SetPrimaryInterfaceInfo: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
2254
2255         if (v4addr && v4addr->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo v4 address - incorrect type.  Discarding. %#a", v4addr); return; }
2256         if (v6addr && v6addr->type != mDNSAddrType_IPv6) { LogMsg("mDNS_SetPrimaryInterfaceInfo v6 address - incorrect type.  Discarding. %#a", v6addr); return; }
2257         if (router && router->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-v4 router.  Discarding. %#a",        router); return; }
2258
2259         mDNS_Lock(m);
2260
2261         if (v4addr && !mDNSv4AddressIsLinkLocal(&v4addr->ip.v4)) v6addr = mDNSNULL;
2262
2263         v4Changed     = !mDNSSameIPv4Address(m->AdvertisedV4.ip.v4, v4addr ? v4addr->ip.v4 : zerov4Addr);
2264         v6Changed     = !mDNSSameIPv6Address(m->AdvertisedV6.ip.v6, v6addr ? v6addr->ip.v6 : zerov6Addr);
2265         RouterChanged = !mDNSSameIPv4Address(m->Router.ip.v4,       router ? router->ip.v4 : zerov4Addr);
2266
2267         if (v4addr && (v4Changed || RouterChanged))
2268                 debugf("mDNS_SetPrimaryInterfaceInfo: address changed from %#a to %#a", &m->AdvertisedV4, v4addr);
2269
2270         if (v4addr) m->AdvertisedV4 = *v4addr; else m->AdvertisedV4.ip.v4 = zerov4Addr;
2271         if (v6addr) m->AdvertisedV6 = *v6addr; else m->AdvertisedV6.ip.v6 = zerov6Addr;
2272         if (router) m->Router       = *router; else m->Router      .ip.v4 = zerov4Addr;
2273         // setting router to zero indicates that nat mappings must be reestablished when router is reset
2274
2275         if (v4Changed || RouterChanged || v6Changed)
2276                 {
2277                 HostnameInfo *i;
2278                 LogInfo("mDNS_SetPrimaryInterfaceInfo: %s%s%s%#a %#a %#a",
2279                         v4Changed     ? "v4Changed "     : "",
2280                         RouterChanged ? "RouterChanged " : "",
2281                         v6Changed     ? "v6Changed "     : "", v4addr, v6addr, router);
2282
2283                 for (i = m->Hostnames; i; i = i->next)
2284                         {
2285                         LogInfo("mDNS_SetPrimaryInterfaceInfo updating host name registrations for %##s", i->fqdn.c);
2286         
2287                         if (i->arv4.resrec.RecordType > kDNSRecordTypeDeregistering &&
2288                                 !mDNSSameIPv4Address(i->arv4.resrec.rdata->u.ipv4, m->AdvertisedV4.ip.v4))
2289                                 {
2290                                 LogInfo("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m, &i->arv4));
2291                                 mDNS_Deregister_internal(m, &i->arv4, mDNS_Dereg_normal);
2292                                 }
2293         
2294                         if (i->arv6.resrec.RecordType > kDNSRecordTypeDeregistering &&
2295                                 !mDNSSameIPv6Address(i->arv6.resrec.rdata->u.ipv6, m->AdvertisedV6.ip.v6))
2296                                 {
2297                                 LogInfo("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m, &i->arv6));
2298                                 mDNS_Deregister_internal(m, &i->arv6, mDNS_Dereg_normal);
2299                                 }
2300
2301                         // AdvertiseHostname will only register new address records.
2302                         // For records still in the process of deregistering it will ignore them, and let the mStatus_MemFree callback handle them.
2303                         AdvertiseHostname(m, i);
2304                         }
2305
2306                 if (v4Changed || RouterChanged)
2307                         {
2308                         m->ExternalAddress      = zerov4Addr;
2309                         m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
2310                         m->retryGetAddr         = m->timenow;
2311                         m->NextScheduledNATOp   = m->timenow;
2312                         m->LastNATMapResultCode = NATErr_None;
2313 #ifdef _LEGACY_NAT_TRAVERSAL_
2314                         LNT_ClearState(m);
2315 #endif // _LEGACY_NAT_TRAVERSAL_
2316                         }
2317
2318                 if (m->ReverseMap.ThisQInterval != -1) mDNS_StopQuery_internal(m, &m->ReverseMap);
2319                 m->StaticHostname.c[0] = 0;
2320                 
2321                 UpdateSRVRecords(m); // Will call GetStaticHostname if needed
2322                 
2323 #if APPLE_OSX_mDNSResponder
2324                 if (RouterChanged)      uuid_generate(m->asl_uuid);
2325                 UpdateAutoTunnelDomainStatuses(m);
2326 #endif
2327                 }
2328
2329         mDNS_Unlock(m);
2330         }
2331
2332 // ***************************************************************************
2333 #if COMPILER_LIKES_PRAGMA_MARK
2334 #pragma mark - Incoming Message Processing
2335 #endif
2336
2337 mDNSlocal mStatus ParseTSIGError(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const domainname *const displayname)
2338         {
2339         const mDNSu8 *ptr;
2340         mStatus err = mStatus_NoError;
2341         int i;
2342
2343         ptr = LocateAdditionals(msg, end);
2344         if (!ptr) goto finish;
2345
2346         for (i = 0; i < msg->h.numAdditionals; i++)
2347                 {
2348                 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
2349                 if (!ptr) goto finish;
2350                 if (m->rec.r.resrec.rrtype == kDNSType_TSIG)
2351                         {
2352                         mDNSu32 macsize;
2353                         mDNSu8 *rd = m->rec.r.resrec.rdata->u.data;
2354                         mDNSu8 *rdend = rd + m->rec.r.resrec.rdlength;
2355                         int alglen = DomainNameLengthLimit(&m->rec.r.resrec.rdata->u.name, rdend);
2356                         if (alglen > MAX_DOMAIN_NAME) goto finish;
2357                         rd += alglen;                                       // algorithm name
2358                         if (rd + 6 > rdend) goto finish;
2359                         rd += 6;                                            // 48-bit timestamp
2360                         if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
2361                         rd += sizeof(mDNSOpaque16);                         // fudge
2362                         if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
2363                         macsize = mDNSVal16(*(mDNSOpaque16 *)rd);
2364                         rd += sizeof(mDNSOpaque16);                         // MAC size
2365                         if (rd + macsize > rdend) goto finish;
2366                         rd += macsize;
2367                         if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
2368                         rd += sizeof(mDNSOpaque16);                         // orig id
2369                         if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
2370                         err = mDNSVal16(*(mDNSOpaque16 *)rd);               // error code
2371
2372                         if      (err == TSIG_ErrBadSig)  { LogMsg("%##s: bad signature", displayname->c);              err = mStatus_BadSig;     }
2373                         else if (err == TSIG_ErrBadKey)  { LogMsg("%##s: bad key", displayname->c);                    err = mStatus_BadKey;     }
2374                         else if (err == TSIG_ErrBadTime) { LogMsg("%##s: bad time", displayname->c);                   err = mStatus_BadTime;    }
2375                         else if (err)                    { LogMsg("%##s: unknown tsig error %d", displayname->c, err); err = mStatus_UnknownErr; }
2376                         goto finish;
2377                         }
2378                 m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
2379                 }
2380
2381         finish:
2382         m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
2383         return err;
2384         }
2385
2386 mDNSlocal mStatus checkUpdateResult(mDNS *const m, const domainname *const displayname, const mDNSu8 rcode, const DNSMessage *const msg, const mDNSu8 *const end)
2387         {
2388         (void)msg;      // currently unused, needed for TSIG errors
2389         if (!rcode) return mStatus_NoError;
2390         else if (rcode == kDNSFlag1_RC_YXDomain)
2391                 {
2392                 debugf("name in use: %##s", displayname->c);
2393                 return mStatus_NameConflict;
2394                 }
2395         else if (rcode == kDNSFlag1_RC_Refused)
2396                 {
2397                 LogMsg("Update %##s refused", displayname->c);
2398                 return mStatus_Refused;
2399                 }
2400         else if (rcode == kDNSFlag1_RC_NXRRSet)
2401                 {
2402                 LogMsg("Reregister refused (NXRRSET): %##s", displayname->c);
2403                 return mStatus_NoSuchRecord;
2404                 }
2405         else if (rcode == kDNSFlag1_RC_NotAuth)
2406                 {
2407                 // TSIG errors should come with FormErr as per RFC 2845, but BIND 9 sends them with NotAuth so we look here too
2408                 mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
2409                 if (!tsigerr)
2410                         {
2411                         LogMsg("Permission denied (NOAUTH): %##s", displayname->c);
2412                         return mStatus_UnknownErr;
2413                         }
2414                 else return tsigerr;
2415                 }
2416         else if (rcode == kDNSFlag1_RC_FormErr)
2417                 {
2418                 mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
2419                 if (!tsigerr)
2420                         {
2421                         LogMsg("Format Error: %##s", displayname->c);
2422                         return mStatus_UnknownErr;
2423                         }
2424                 else return tsigerr;
2425                 }
2426         else
2427                 {
2428                 LogMsg("Update %##s failed with rcode %d", displayname->c, rcode);
2429                 return mStatus_UnknownErr;
2430                 }
2431         }
2432
2433 // Called with lock held
2434 mDNSlocal void SendRecordRegistration(mDNS *const m, AuthRecord *rr)
2435         {
2436         mDNSu8 *ptr = m->omsg.data;
2437         mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
2438         mStatus err = mStatus_UnknownErr;
2439
2440         if (m->mDNS_busy != m->mDNS_reentrancy+1)
2441                 LogMsg("SendRecordRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
2442
2443         if (mDNSIPv4AddressIsZero(rr->UpdateServer.ip.v4))      // Don't know our UpdateServer yet
2444                 {
2445                 rr->LastAPTime = m->timenow;
2446                 if (rr->ThisAPInterval < mDNSPlatformOneSecond * 5)
2447                         rr->ThisAPInterval = mDNSPlatformOneSecond * 5;
2448                 return;
2449                 }
2450
2451         rr->RequireGoodbye = mDNStrue;
2452         rr->updateid = mDNS_NewMessageID(m);
2453         InitializeDNSMessage(&m->omsg.h, rr->updateid, UpdateReqFlags);
2454
2455         // set zone
2456         ptr = putZone(&m->omsg, ptr, end, rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
2457         if (!ptr) { err = mStatus_UnknownErr; goto exit; }
2458
2459         if (rr->state == regState_UpdatePending)
2460                 {
2461                 // delete old RData
2462                 SetNewRData(&rr->resrec, rr->OrigRData, rr->OrigRDLen);
2463                 if (!(ptr = putDeletionRecord(&m->omsg, ptr, &rr->resrec))) { err = mStatus_UnknownErr; goto exit; } // delete old rdata
2464
2465                 // add new RData
2466                 SetNewRData(&rr->resrec, rr->InFlightRData, rr->InFlightRDLen);
2467                 if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
2468                 }
2469
2470         else
2471                 {
2472                 if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
2473                         {
2474                         // KnownUnique: Delete any previous value
2475                         ptr = putDeleteRRSet(&m->omsg, ptr, rr->resrec.name, rr->resrec.rrtype);
2476                         if (!ptr) { err = mStatus_UnknownErr; goto exit; }
2477                         }
2478
2479                 else if (rr->resrec.RecordType != kDNSRecordTypeShared)
2480                         {
2481                         // For now don't do this, until we have the logic for intelligent grouping of individual recors into logical service record sets
2482                         //ptr = putPrereqNameNotInUse(rr->resrec.name, &m->omsg, ptr, end);
2483                         if (!ptr) { err = mStatus_UnknownErr; goto exit; }
2484                         }
2485
2486                 ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl);
2487                 if (!ptr) { err = mStatus_UnknownErr; goto exit; }
2488                 }
2489
2490         if (rr->uselease)
2491                 {
2492                 ptr = putUpdateLease(&m->omsg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) { err = mStatus_UnknownErr; goto exit; }
2493                 }
2494
2495         if (rr->Private)
2496                 {
2497                 LogInfo("SendRecordRegistration TCP %p %s", rr->tcp, ARDisplayString(m, rr));
2498                 if (rr->tcp) LogInfo("SendRecordRegistration: Disposing existing TCP connection for %s", ARDisplayString(m, rr));
2499                 if (rr->tcp) DisposeTCPConn(rr->tcp);
2500                 rr->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, mDNSNULL, rr);
2501                 if (!rr->tcp) rr->ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2)
2502                 else if (rr->ThisAPInterval < mDNSPlatformOneSecond * 30) rr->ThisAPInterval = mDNSPlatformOneSecond * 30;
2503                 }
2504         else
2505                 {
2506                 err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name));
2507                 if (err) debugf("ERROR: SendRecordRegistration - mDNSSendDNSMessage - %d", err);
2508                 }
2509
2510         SetRecordRetry(m, rr, err);
2511
2512         if (rr->state != regState_Refresh && rr->state != regState_DeregDeferred && rr->state != regState_UpdatePending)
2513                 rr->state = regState_Pending;
2514
2515         return;
2516
2517 exit:
2518         LogMsg("SendRecordRegistration: Error formatting message for %s", ARDisplayString(m, rr));
2519         }
2520
2521 // Called with lock held
2522 mDNSlocal void hndlServiceUpdateReply(mDNS *const m, ServiceRecordSet *srs,  mStatus err)
2523         {
2524         mDNSBool InvokeCallback = mDNSfalse;
2525         ExtraResourceRecord **e = &srs->Extras;
2526         AuthRecord *txt = &srs->RR_TXT;
2527
2528         if (m->mDNS_busy != m->mDNS_reentrancy+1)
2529                 LogMsg("hndlServiceUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
2530
2531         debugf("hndlServiceUpdateReply: err %d state %d %##s", err, srs->state, srs->RR_SRV.resrec.name->c);
2532
2533         SetRecordRetry(m, &srs->RR_SRV, mStatus_NoError);
2534
2535         switch (srs->state)
2536                 {
2537                 case regState_Pending:
2538                         if (err == mStatus_NameConflict && !srs->TestForSelfConflict)
2539                                 {
2540                                 srs->TestForSelfConflict = mDNStrue;
2541                                 debugf("checking for self-conflict of service %##s", srs->RR_SRV.resrec.name->c);
2542                                 SendServiceRegistration(m, srs);
2543                                 return;
2544                                 }
2545                         else if (srs->TestForSelfConflict)
2546                                 {
2547                                 srs->TestForSelfConflict = mDNSfalse;
2548                                 if (err == mStatus_NoSuchRecord) err = mStatus_NameConflict;    // NoSuchRecord implies that our prereq was not met, so we actually have a name conflict
2549                                 if (!err) srs->state = regState_Registered;
2550                                 InvokeCallback = mDNStrue;
2551                                 break;
2552                                 }
2553                         else if (srs->srs_uselease && err == mStatus_UnknownErr && mDNSSameIPPort(srs->SRSUpdatePort, UnicastDNSPort))
2554                                 {
2555                                 LogMsg("Re-trying update of service %##s without lease option", srs->RR_SRV.resrec.name->c);
2556                                 srs->srs_uselease = mDNSfalse;
2557                                 SendServiceRegistration(m, srs);
2558                                 return;
2559                                 }
2560                         else
2561                                 {
2562                                 //!!!KRS make sure all structs will still get cleaned up when client calls DeregisterService with this state
2563                                 if (err) LogMsg("Error %d for registration of service %##s", err, srs->RR_SRV.resrec.name->c);
2564                                 else srs->state = regState_Registered;
2565                                 InvokeCallback = mDNStrue;
2566                                 break;
2567                                 }
2568                 case regState_Refresh:
2569                         if (err)
2570                                 {
2571                                 LogMsg("Error %d for refresh of service %##s", err, srs->RR_SRV.resrec.name->c);
2572                                 InvokeCallback = mDNStrue;
2573                                 }
2574                         else srs->state = regState_Registered;
2575                         break;
2576                 case regState_DeregPending:
2577                         if (err) LogMsg("Error %d for deregistration of service %##s", err, srs->RR_SRV.resrec.name->c);
2578                         if (srs->SRVChanged)
2579                                 {
2580                                 srs->state = regState_NoTarget; // NoTarget will allow us to pick up new target OR nat traversal state
2581                                 break;
2582                                 }
2583                         err = mStatus_MemFree;
2584                         InvokeCallback = mDNStrue;
2585                         if (srs->NATinfo.clientContext)
2586                                 {
2587                                 // deletion completed
2588                                 mDNS_StopNATOperation_internal(m, &srs->NATinfo);
2589                                 srs->NATinfo.clientContext = mDNSNULL;
2590                                 }
2591                         srs->state = regState_Unregistered;
2592                         break;
2593                 case regState_DeregDeferred:
2594                         if (err)
2595                                 {
2596                                 debugf("Error %d received prior to deferred deregistration of %##s", err, srs->RR_SRV.resrec.name->c);
2597                                 err = mStatus_MemFree;
2598                                 InvokeCallback = mDNStrue;
2599                                 srs->state = regState_Unregistered;
2600                                 break;
2601                                 }
2602                         else
2603                                 {
2604                                 debugf("Performing deferred deregistration of %##s", srs->RR_SRV.resrec.name->c);
2605                                 srs->state = regState_Registered;
2606                                 SendServiceDeregistration(m, srs);
2607                                 return;
2608                                 }
2609                 case regState_UpdatePending:
2610                         if (err)
2611                                 {
2612                                 LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs->RR_SRV.resrec.name->c);
2613                                 InvokeCallback = mDNStrue;
2614                                 }
2615                         else
2616                                 {
2617                                 srs->state = regState_Registered;
2618                                 // deallocate old RData
2619                                 if (txt->UpdateCallback) txt->UpdateCallback(m, txt, txt->OrigRData);
2620                                 SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen);
2621                                 txt->OrigRData = mDNSNULL;
2622                                 txt->InFlightRData = mDNSNULL;
2623                                 }
2624                         break;
2625                 case regState_NoTarget:
2626                         // This state is used when using SendServiceDeregistration() when going to sleep -- no further action required
2627                         return;
2628                 case regState_FetchingZoneData:
2629                 case regState_Registered:
2630                 case regState_Unregistered:
2631                 case regState_NATMap:
2632                 case regState_ExtraQueued:
2633                 case regState_NATError:
2634                         LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %d.  Unlinking.",
2635                                    srs->RR_SRV.resrec.name->c, srs->state, err);
2636                         err = mStatus_UnknownErr;
2637                 default: LogMsg("hndlServiceUpdateReply: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c);
2638                 }
2639
2640         if ((srs->SRVChanged || srs->SRVUpdateDeferred) && (srs->state == regState_NoTarget || srs->state == regState_Registered))
2641                 {
2642                 debugf("hndlServiceUpdateReply: SRVChanged %d SRVUpdateDeferred %d state %d", srs->SRVChanged, srs->SRVUpdateDeferred, srs->state);
2643                 if (InvokeCallback)
2644                         {
2645                         srs->ClientCallbackDeferred = mDNStrue;
2646                         srs->DeferredStatus = err;
2647                         }
2648                 srs->SRVChanged = srs->SRVUpdateDeferred = mDNSfalse;
2649                 UpdateSRV(m, srs);
2650                 return;
2651                 }
2652
2653         while (*e)
2654                 {
2655                 if ((*e)->r.state == regState_ExtraQueued)
2656                         {
2657                         if (srs->state == regState_Registered && !err)
2658                                 {
2659                                 // extra resource record queued for this service - copy zone srs and register
2660                                 (*e)->r.zone = &srs->zone;
2661                                 (*e)->r.UpdateServer    = srs->SRSUpdateServer;
2662                                 (*e)->r.UpdatePort  = srs->SRSUpdatePort;
2663                                 (*e)->r.uselease = srs->srs_uselease;
2664                                 SendRecordRegistration(m, &(*e)->r);
2665                                 e = &(*e)->next;
2666                                 }
2667                         else if (err && (*e)->r.state != regState_Unregistered)
2668                                 {
2669                                 // unlink extra from list
2670                                 (*e)->r.state = regState_Unregistered;
2671                                 *e = (*e)->next;
2672                                 }
2673                         else e = &(*e)->next;
2674                         }
2675                 else e = &(*e)->next;
2676                 }
2677
2678         if (srs->state == regState_Unregistered)
2679                 {
2680                 if (err != mStatus_MemFree)
2681                         LogMsg("hndlServiceUpdateReply ERROR! state == regState_Unregistered but err != mStatus_MemFree. Permanently abandoning service registration %##s",
2682                                 srs->RR_SRV.resrec.name->c);
2683                 unlinkSRS(m, srs);
2684                 }
2685         else if (txt->QueuedRData && srs->state == regState_Registered)
2686                 {
2687                 if (InvokeCallback)
2688                         {
2689                         // if we were supposed to give a client callback, we'll do it after we update the primary txt record
2690                         srs->ClientCallbackDeferred = mDNStrue;
2691                         srs->DeferredStatus = err;
2692                         }
2693                 srs->state = regState_UpdatePending;
2694                 txt->InFlightRData = txt->QueuedRData;
2695                 txt->InFlightRDLen = txt->QueuedRDLen;
2696                 txt->OrigRData = txt->resrec.rdata;
2697                 txt->OrigRDLen = txt->resrec.rdlength;
2698                 txt->QueuedRData = mDNSNULL;
2699                 SendServiceRegistration(m, srs);
2700                 return;
2701                 }
2702
2703         mDNS_DropLockBeforeCallback();
2704         if (InvokeCallback)
2705                 srs->ServiceCallback(m, srs, err);
2706         else if (srs->ClientCallbackDeferred)
2707                 {
2708                 srs->ClientCallbackDeferred = mDNSfalse;
2709                 srs->ServiceCallback(m, srs, srs->DeferredStatus);
2710                 }
2711         mDNS_ReclaimLockAfterCallback();
2712         // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
2713         // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
2714         }
2715
2716 // Called with lock held
2717 mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
2718         {
2719         mDNSBool InvokeCallback = mDNStrue;
2720
2721         if (m->mDNS_busy != m->mDNS_reentrancy+1)
2722                 LogMsg("hndlRecordUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
2723
2724         LogInfo("hndlRecordUpdateReply: err %d state %d %s", err, rr->state, ARDisplayString(m, rr));
2725
2726         if (m->SleepState) return;              // If we just sent a deregister on going to sleep, no further action required
2727
2728         SetRecordRetry(m, rr, mStatus_NoError);
2729
2730         if (rr->state == regState_UpdatePending)
2731                 {
2732                 if (err) LogMsg("Update record failed for %##s (err %d)", rr->resrec.name->c, err);
2733                 rr->state = regState_Registered;
2734                 // deallocate old RData
2735                 if (rr->UpdateCallback) rr->UpdateCallback(m, rr, rr->OrigRData);
2736                 SetNewRData(&rr->resrec, rr->InFlightRData, rr->InFlightRDLen);
2737                 rr->OrigRData = mDNSNULL;
2738                 rr->InFlightRData = mDNSNULL;
2739                 }
2740
2741         if (rr->state == regState_DeregPending)
2742                 {
2743                 debugf("Received reply for deregister record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype);
2744                 if (err) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %d",
2745                                                 rr->resrec.name->c, rr->resrec.rrtype, err);
2746                 err = mStatus_MemFree;
2747                 rr->state = regState_Unregistered;
2748                 }
2749
2750         if (rr->state == regState_DeregDeferred)
2751                 {
2752                 if (err)
2753                         {
2754                         LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %d",
2755                                    rr->resrec.name->c, rr->resrec.rrtype, err);
2756                         rr->state = regState_Unregistered;
2757                         }
2758                 debugf("Calling deferred deregistration of record %##s type %d",  rr->resrec.name->c, rr->resrec.rrtype);
2759                 rr->state = regState_Registered;
2760                 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
2761                 return;
2762                 }
2763
2764         if (rr->state == regState_Pending || rr->state == regState_Refresh)
2765                 {
2766                 if (!err)
2767                         {
2768                         if (rr->state == regState_Refresh) InvokeCallback = mDNSfalse;
2769                         rr->state = regState_Registered;
2770                         }
2771                 else
2772                         {
2773                         if (rr->uselease && err == mStatus_UnknownErr && mDNSSameIPPort(rr->UpdatePort, UnicastDNSPort))
2774                                 {
2775                                 LogMsg("Re-trying update of record %##s without lease option", rr->resrec.name->c);
2776                                 rr->uselease = mDNSfalse;
2777                                 SendRecordRegistration(m, rr);
2778                                 return;
2779                                 }
2780                         LogMsg("hndlRecordUpdateReply: Registration of record %##s type %d failed with error %d", rr->resrec.name->c, rr->resrec.rrtype, err);
2781                         return;
2782                         }
2783                 }
2784
2785         if (rr->state == regState_Unregistered)         // Should never happen
2786                 {
2787                 LogMsg("hndlRecordUpdateReply rr->state == regState_Unregistered %s", ARDisplayString(m, rr));
2788                 return;
2789                 }
2790
2791         if (rr->QueuedRData && rr->state == regState_Registered)
2792                 {
2793                 rr->state = regState_UpdatePending;
2794                 rr->InFlightRData = rr->QueuedRData;
2795                 rr->InFlightRDLen = rr->QueuedRDLen;
2796                 rr->OrigRData = rr->resrec.rdata;
2797                 rr->OrigRDLen = rr->resrec.rdlength;
2798                 rr->QueuedRData = mDNSNULL;
2799                 SendRecordRegistration(m, rr);
2800                 return;
2801                 }
2802
2803         if (InvokeCallback && rr->RecordCallback)
2804                 {
2805                 mDNS_DropLockBeforeCallback();
2806                 rr->RecordCallback(m, rr, err);
2807                 mDNS_ReclaimLockAfterCallback();
2808                 }
2809         // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
2810         // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
2811         }
2812
2813 mDNSexport void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 *pkt, mDNSu16 len)
2814         {
2815         NATTraversalInfo *ptr;
2816         NATAddrReply     *AddrReply    = (NATAddrReply    *)pkt;
2817         NATPortMapReply  *PortMapReply = (NATPortMapReply *)pkt;
2818         mDNSu32 nat_elapsed, our_elapsed;
2819
2820         // Minimum packet is vers (1) opcode (1) err (2) upseconds (4) = 8 bytes
2821         if (!AddrReply->err && len < 8) { LogMsg("NAT Traversal message too short (%d bytes)", len); return; }
2822         if (AddrReply->vers != NATMAP_VERS) { LogMsg("Received NAT Traversal response with version %d (expected %d)", pkt[0], NATMAP_VERS); return; }
2823
2824         // Read multi-byte numeric values (fields are identical in a NATPortMapReply)
2825         AddrReply->err       = (mDNSu16) (                                                (mDNSu16)pkt[2] << 8 | pkt[3]);
2826         AddrReply->upseconds = (mDNSs32) ((mDNSs32)pkt[4] << 24 | (mDNSs32)pkt[5] << 16 | (mDNSs32)pkt[6] << 8 | pkt[7]);
2827
2828         nat_elapsed = AddrReply->upseconds - m->LastNATupseconds;
2829         our_elapsed = (m->timenow - m->LastNATReplyLocalTime) / mDNSPlatformOneSecond;
2830         debugf("uDNS_ReceiveNATPMPPacket %X upseconds %u nat_elapsed %d our_elapsed %d", AddrReply->opcode, AddrReply->upseconds, nat_elapsed, our_elapsed);
2831
2832         // We compute a conservative estimate of how much the NAT gateways's clock should have advanced
2833         // 1. We subtract 12.5% from our own measured elapsed time, to allow for NAT gateways that have an inacurate clock that runs slowly
2834         // 2. We add a two-second safety margin to allow for rounding errors: e.g.
2835         //    -- if NAT gateway sends a packet at t=2.000 seconds, then one at t=7.999, that's approximately 6 real seconds,
2836         //       but based on the values in the packet (2,7) the apparent difference according to the packet is only 5 seconds
2837         //    -- if we're slow handling packets and/or we have coarse clock granularity,
2838         //       we could receive the t=2 packet at our t=1.999 seconds, which we round down to 1
2839         //       and the t=7.999 packet at our t=8.000 seconds, which we record as 8,
2840         //       giving an apparent local time difference of 7 seconds
2841         //    The two-second safety margin coves this possible calculation discrepancy
2842         if (AddrReply->upseconds < m->LastNATupseconds || nat_elapsed + 2 < our_elapsed - our_elapsed/8)
2843                 { LogMsg("NAT gateway %#a rebooted", &m->Router); RecreateNATMappings(m); }
2844
2845         m->LastNATupseconds      = AddrReply->upseconds;
2846         m->LastNATReplyLocalTime = m->timenow;
2847 #ifdef _LEGACY_NAT_TRAVERSAL_
2848         LNT_ClearState(m);
2849 #endif // _LEGACY_NAT_TRAVERSAL_
2850
2851         if (AddrReply->opcode == NATOp_AddrResponse)
2852                 {
2853 #if APPLE_OSX_mDNSResponder
2854                 static char msgbuf[16];
2855                 mDNS_snprintf(msgbuf, sizeof(msgbuf), "%d", AddrReply->err);
2856                 mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.natpmp.AddressRequest", AddrReply->err ? "failure" : "success", msgbuf, "");
2857 #endif
2858                 if (!AddrReply->err && len < sizeof(NATAddrReply)) { LogMsg("NAT Traversal AddrResponse message too short (%d bytes)", len); return; }
2859                 natTraversalHandleAddressReply(m, AddrReply->err, AddrReply->ExtAddr);
2860                 }
2861         else if (AddrReply->opcode == NATOp_MapUDPResponse || AddrReply->opcode == NATOp_MapTCPResponse)
2862                 {
2863                 mDNSu8 Protocol = AddrReply->opcode & 0x7F;
2864 #if APPLE_OSX_mDNSResponder
2865                 static char msgbuf[16];
2866                 mDNS_snprintf(msgbuf, sizeof(msgbuf), "%s - %d", AddrReply->opcode == NATOp_MapUDPResponse ? "UDP" : "TCP", PortMapReply->err);
2867                 mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.natpmp.PortMapRequest", PortMapReply->err ? "failure" : "success", msgbuf, "");
2868 #endif
2869                 if (!PortMapReply->err)
2870                         {
2871                         if (len < sizeof(NATPortMapReply)) { LogMsg("NAT Traversal PortMapReply message too short (%d bytes)", len); return; }
2872                         PortMapReply->NATRep_lease = (mDNSu32) ((mDNSu32)pkt[12] << 24 | (mDNSu32)pkt[13] << 16 | (mDNSu32)pkt[14] << 8 | pkt[15]);
2873                         }
2874
2875                 // Since some NAT-PMP server implementations don't return the requested internal port in
2876                 // the reply, we can't associate this reply with a particular NATTraversalInfo structure.
2877                 // We globally keep track of the most recent error code for mappings.
2878                 m->LastNATMapResultCode = PortMapReply->err;
2879                 
2880                 for (ptr = m->NATTraversals; ptr; ptr=ptr->next)
2881                         if (ptr->Protocol == Protocol && mDNSSameIPPort(ptr->IntPort, PortMapReply->intport))
2882                                 natTraversalHandlePortMapReply(m, ptr, InterfaceID, PortMapReply->err, PortMapReply->extport, PortMapReply->NATRep_lease);
2883                 }
2884         else { LogMsg("Received NAT Traversal response with version unknown opcode 0x%X", AddrReply->opcode); return; }
2885
2886         // Don't need an SSDP socket if we get a NAT-PMP packet
2887         if (m->SSDPSocket) { debugf("uDNS_ReceiveNATPMPPacket destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
2888         }
2889
2890 // <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
2891 // <rdar://problem/4288449> Add check to avoid crashing NAT gateways that have buggy DNS relay code
2892 //
2893 // We know of bugs in home NAT gateways that cause them to crash if they receive certain DNS queries.
2894 // The DNS queries that make them crash are perfectly legal DNS queries, but even if they weren't,
2895 // the gateway shouldn't crash -- in today's world of viruses and network attacks, software has to
2896 // be written assuming that a malicious attacker could send them any packet, properly-formed or not.
2897 // Still, we don't want to be crashing people's home gateways, so we go out of our way to avoid
2898 // the queries that crash them.
2899 //
2900 // Some examples:
2901 //
2902 // 1. Any query where the name ends in ".in-addr.arpa." and the text before this is 32 or more bytes.
2903 //    The query type does not need to be PTR -- the gateway will crash for any query type.
2904 //    e.g. "ping long-name-crashes-the-buggy-router.in-addr.arpa" will crash one of these.
2905 //
2906 // 2. Any query that results in a large response with the TC bit set.
2907 //
2908 // 3. Any PTR query that doesn't begin with four decimal numbers.
2909 //    These gateways appear to assume that the only possible PTR query is a reverse-mapping query
2910 //    (e.g. "1.0.168.192.in-addr.arpa") and if they ever get a PTR query where the first four
2911 //    labels are not all decimal numbers in the range 0-255, they handle that by crashing.
2912 //    These gateways also ignore the remainder of the name following the four decimal numbers
2913 //    -- whether or not it actually says in-addr.arpa, they just make up an answer anyway.
2914 //
2915 // The challenge therefore is to craft a query that will discern whether the DNS server
2916 // is one of these buggy ones, without crashing it. Furthermore we don't want our test
2917 // queries making it all the way to the root name servers, putting extra load on those
2918 // name servers and giving Apple a bad reputation. To this end we send this query:
2919 //     dig -t ptr 1.0.0.127.dnsbugtest.1.0.0.127.in-addr.arpa.
2920 //
2921 // The text preceding the ".in-addr.arpa." is under 32 bytes, so it won't cause crash (1).
2922 // It will not yield a large response with the TC bit set, so it won't cause crash (2).
2923 // It starts with four decimal numbers, so it won't cause crash (3).
2924 // The name falls within the "1.0.0.127.in-addr.arpa." domain, the reverse-mapping name for the local
2925 // loopback address, and therefore the query will black-hole at the first properly-configured DNS server
2926 // it reaches, making it highly unlikely that this query will make it all the way to the root.
2927 //
2928 // Finally, the correct response to this query is NXDOMAIN or a similar error, but the
2929 // gateways that ignore the remainder of the name following the four decimal numbers
2930 // give themselves away by actually returning a result for this nonsense query.
2931
2932 mDNSlocal const domainname *DNSRelayTestQuestion = (const domainname*)
2933         "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\xa" "dnsbugtest"
2934         "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\x7" "in-addr" "\x4" "arpa";
2935
2936 // See comments above for DNSRelayTestQuestion
2937 // If this is the kind of query that has the risk of crashing buggy DNS servers, we do a test question first
2938 mDNSlocal mDNSBool NoTestQuery(DNSQuestion *q)
2939         {
2940         int i;
2941         mDNSu8 *p = q->qname.c;
2942         if (q->AuthInfo) return(mDNStrue);              // Don't need a test query for private queries sent directly to authoritative server over TLS/TCP
2943         if (q->qtype != kDNSType_PTR) return(mDNStrue);         // Don't need a test query for any non-PTR queries
2944         for (i=0; i<4; i++)             // If qname does not begin with num.num.num.num, can't skip the test query
2945                 {
2946                 if (p[0] < 1 || p[0] > 3) return(mDNSfalse);
2947                 if (              p[1] < '0' || p[1] > '9' ) return(mDNSfalse);
2948                 if (p[0] >= 2 && (p[2] < '0' || p[2] > '9')) return(mDNSfalse);
2949                 if (p[0] >= 3 && (p[3] < '0' || p[3] > '9')) return(mDNSfalse);
2950                 p += 1 + p[0];
2951                 }
2952         // If remainder of qname is ".in-addr.arpa.", this is a vanilla reverse-mapping query and
2953         // we can safely do it without needing a test query first, otherwise we need the test query.
2954         return(SameDomainName((domainname*)p, (const domainname*)"\x7" "in-addr" "\x4" "arpa"));
2955         }
2956
2957 // Returns mDNStrue if response was handled
2958 mDNSlocal mDNSBool uDNS_ReceiveTestQuestionResponse(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
2959         const mDNSAddr *const srcaddr, const mDNSIPPort srcport)
2960         {
2961         const mDNSu8 *ptr = msg->data;
2962         DNSQuestion pktq;
2963         DNSServer *s;
2964         mDNSu32 result = 0;
2965
2966         // 1. Find out if this is an answer to one of our test questions
2967         if (msg->h.numQuestions != 1) return(mDNSfalse);
2968         ptr = getQuestion(msg, ptr, end, mDNSInterface_Any, &pktq);
2969         if (!ptr) return(mDNSfalse);
2970         if (pktq.qtype != kDNSType_PTR || pktq.qclass != kDNSClass_IN) return(mDNSfalse);
2971         if (!SameDomainName(&pktq.qname, DNSRelayTestQuestion)) return(mDNSfalse);
2972
2973         // 2. If the DNS relay gave us a positive response, then it's got buggy firmware
2974         // else, if the DNS relay gave us an error or no-answer response, it passed our test
2975         if ((msg->h.flags.b[1] & kDNSFlag1_RC_Mask) == kDNSFlag1_RC_NoErr && msg->h.numAnswers > 0)
2976                 result = DNSServer_Failed;
2977         else
2978                 result = DNSServer_Passed;
2979
2980         // 3. Find occurrences of this server in our list, and mark them appropriately
2981         for (s = m->DNSServers; s; s = s->next)
2982                 {
2983                 mDNSBool matchaddr = (s->teststate != result && mDNSSameAddress(srcaddr, &s->addr) && mDNSSameIPPort(srcport, s->port));
2984                 mDNSBool matchid   = (s->teststate == DNSServer_Untested && mDNSSameOpaque16(msg->h.id, s->testid));
2985                 if (matchaddr || matchid)
2986                         {
2987                         DNSQuestion *q;
2988                         s->teststate = result;
2989                         if (result == DNSServer_Passed)
2990                                 {
2991                                 LogInfo("DNS Server %#a:%d (%#a:%d) %d passed%s",
2992                                         &s->addr, mDNSVal16(s->port), srcaddr, mDNSVal16(srcport), mDNSVal16(s->testid),
2993                                         matchaddr ? "" : " NOTE: Reply did not come from address to which query was sent");
2994                                 }
2995                         else
2996                                 {
2997                                 LogMsg("NOTE: Wide-Area Service Discovery disabled to avoid crashing defective DNS relay %#a:%d (%#a:%d) %d%s",
2998                                         &s->addr, mDNSVal16(s->port), srcaddr, mDNSVal16(srcport), mDNSVal16(s->testid),
2999                                         matchaddr ? "" : " NOTE: Reply did not come from address to which query was sent");
3000                                 }
3001
3002                         // If this server has just changed state from DNSServer_Untested to DNSServer_Passed, then retrigger any waiting questions.
3003                         // We use the NoTestQuery() test so that we only retrigger questions that were actually blocked waiting for this test to complete.
3004                         if (result == DNSServer_Passed)         // Unblock any questions that were waiting for this result
3005                                 for (q = m->Questions; q; q=q->next)
3006                                         if (q->qDNSServer == s && !NoTestQuery(q))
3007                                                 {
3008                                                 q->ThisQInterval = INIT_UCAST_POLL_INTERVAL / QuestionIntervalStep;
3009                                                 q->unansweredQueries = 0;
3010                                                 q->LastQTime = m->timenow - q->ThisQInterval;
3011                                                 m->NextScheduledQuery = m->timenow;
3012                                                 }
3013                         }
3014                 }
3015
3016         return(mDNStrue); // Return mDNStrue to tell uDNS_ReceiveMsg it doesn't need to process this packet further
3017         }
3018
3019 // Called from mDNSCoreReceive with the lock held
3020 mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport)
3021         {
3022         DNSQuestion *qptr;
3023         mStatus err = mStatus_NoError;
3024