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