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