1 /* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
2 *
3 * Copyright (c) 2002-2020 Apple 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 * This code is completely 100% portable C. It does not depend on any external header files
18 * from outside the mDNS project -- all the types it expects to find are defined right here.
19 *
20 * The previous point is very important: This file does not depend on any external
21 * header files. It should compile on *any* platform that has a C compiler, without
22 * making *any* assumptions about availability of so-called "standard" C functions,
23 * routines, or types (which may or may not be present on any given platform).
24 */
25
26 #include "DNSCommon.h" // Defines general DNS utility routines
27 #include "uDNS.h" // Defines entry points into unicast-specific routines
28
29 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
30 #include "D2D.h"
31 #endif
32
33 #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
34 #include <bsm/libbsm.h>
35 #endif
36
37 #if MDNSRESPONDER_SUPPORTS(APPLE, CACHE_ANALYTICS)
38 #include "dnssd_analytics.h"
39 #endif
40
41 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
42 #include "QuerierSupport.h"
43 #endif
44
45 // Disable certain benign warnings with Microsoft compilers
46 #if (defined(_MSC_VER))
47 // Disable "conditional expression is constant" warning for debug macros.
48 // Otherwise, this generates warnings for the perfectly natural construct "while(1)"
49 // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know
50 #pragma warning(disable:4127)
51
52 // Disable "assignment within conditional expression".
53 // Other compilers understand the convention that if you place the assignment expression within an extra pair
54 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
55 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
56 // to the compiler that the assignment is intentional, we have to just turn this warning off completely.
57 #pragma warning(disable:4706)
58 #endif
59
60 #include "dns_sd.h" // for kDNSServiceFlags* definitions
61 #include "dns_sd_internal.h"
62
63 #if APPLE_OSX_mDNSResponder
64 // Delay in seconds before disabling multicast after there are no active queries or registrations.
65 #define BONJOUR_DISABLE_DELAY 60
66 #endif
67
68 #if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
69 #include <WebFilterDNS/WebFilterDNS.h>
70
71 WCFConnection *WCFConnectionNew(void) __attribute__((weak_import));
72 void WCFConnectionDealloc(WCFConnection* c) __attribute__((weak_import));
73 #endif
74
75 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
76 #include "Metrics.h"
77 #endif
78
79 #if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
80 #include "DNS64.h"
81 #endif
82
83 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
84 #include "dnssec_v2.h"
85 #endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
86
87 // Forward declarations
88 mDNSlocal void BeginSleepProcessing(mDNS *const m);
89 mDNSlocal void RetrySPSRegistrations(mDNS *const m);
90 mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password, mDNSBool unicastOnly);
91 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
92 mDNSlocal mDNSBool LocalRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q);
93 #endif
94 mDNSlocal void mDNS_PurgeBeforeResolve(mDNS *const m, DNSQuestion *q);
95 mDNSlocal void mDNS_SendKeepalives(mDNS *const m);
96 mDNSlocal void mDNS_ExtractKeepaliveInfo(AuthRecord *ar, mDNSu32 *timeout, mDNSAddr *laddr, mDNSAddr *raddr, mDNSEthAddr *eth,
97 mDNSu32 *seq, mDNSu32 *ack, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu16 *win);
98
99 typedef mDNSu32 DeadvertiseFlags;
100 #define kDeadvertiseFlag_NormalHostname (1U << 0)
101 #define kDeadvertiseFlag_RandHostname (1U << 1)
102 #define kDeadvertiseFlag_All (kDeadvertiseFlag_NormalHostname | kDeadvertiseFlag_RandHostname)
103
104 mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set, DeadvertiseFlags flags);
105 mDNSlocal void AdvertiseInterfaceIfNeeded(mDNS *const m, NetworkInterfaceInfo *set);
106 mDNSlocal mDNSu8 *GetValueForMACAddr(mDNSu8 *ptr, mDNSu8 *limit, mDNSEthAddr *eth);
107
108 // ***************************************************************************
109 #if COMPILER_LIKES_PRAGMA_MARK
110 #pragma mark - Program Constants
111 #endif
112
113 // To Turn OFF mDNS_Tracer set MDNS_TRACER to 0 or undef it
114 #define MDNS_TRACER 1
115
116 // Any records bigger than this are considered 'large' records
117 #define SmallRecordLimit 1024
118
119 #define kMaxUpdateCredits 10
120 #define kUpdateCreditRefreshInterval (mDNSPlatformOneSecond * 6)
121
122 // define special NR_AnswerTo values
123 #define NR_AnswerMulticast (mDNSu8*)~0
124 #define NR_AnswerUnicast (mDNSu8*)~1
125
126 // Question default timeout values
127 #define DEFAULT_MCAST_TIMEOUT 5
128 #define DEFAULT_LO_OR_P2P_TIMEOUT 5
129
130 // The code (see SendQueries() and BuildQuestion()) needs to have the
131 // RequestUnicast value set to a value one greater than the number of times you want the query
132 // sent with the "request unicast response" (QU) bit set.
133 #define SET_QU_IN_FIRST_QUERY 2
134 #define kDefaultRequestUnicastCount SET_QU_IN_FIRST_QUERY
135
136 // The time needed to offload records to a sleep proxy after powerd sends the kIOMessageSystemWillSleep notification
137 #define DARK_WAKE_DELAY_SLEEP 5
138 #define kDarkWakeDelaySleep (mDNSPlatformOneSecond * DARK_WAKE_DELAY_SLEEP)
139
140 // The maximum number of times we delay probing to prevent spurious conflicts due to stale packets
141 #define MAX_CONFLICT_PROCESSING_DELAYS 3
142
143 // RFC 6762 defines Passive Observation Of Failures (POOF)
144 //
145 // A host observes the multicast queries issued by the other hosts on
146 // the network. One of the major benefits of also sending responses
147 // using multicast is that it allows all hosts to see the responses
148 // (or lack thereof) to those queries.
149 //
150 // If a host sees queries, for which a record in its cache would be
151 // expected to be given as an answer in a multicast response, but no
152 // such answer is seen, then the host may take this as an indication
153 // that the record may no longer be valid.
154 //
155 // After seeing two or more of these queries, and seeing no multicast
156 // response containing the expected answer within ten seconds, then even
157 // though its TTL may indicate that it is not yet due to expire, that
158 // record SHOULD be flushed from the cache.
159 //
160 // <https://tools.ietf.org/html/rfc6762#section-10.5>
161
162 #define POOF_ENABLED 1
163
164 mDNSexport const char *const mDNS_DomainTypeNames[] =
165 {
166 "b._dns-sd._udp.", // Browse
167 "db._dns-sd._udp.", // Default Browse
168 "lb._dns-sd._udp.", // Automatic Browse
169 "r._dns-sd._udp.", // Registration
170 "dr._dns-sd._udp." // Default Registration
171 };
172
173 #ifdef UNICAST_DISABLED
174 #define uDNS_IsActiveQuery(q, u) mDNSfalse
175 #endif
176
177 // ***************************************************************************
178 #if COMPILER_LIKES_PRAGMA_MARK
179 #pragma mark -
180 #pragma mark - General Utility Functions
181 #endif
182
183 #if MDNS_MALLOC_DEBUGGING
184 // When doing memory allocation debugging, this function traverses all lists in the mDNS query
185 // structures and caches and checks each entry in the list to make sure it's still good.
mDNS_ValidateLists(void * context)186 mDNSlocal void mDNS_ValidateLists(void *context)
187 {
188 mDNS *m = context;
189 #if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
190 mDNSu32 NumAllInterfaceRecords = 0;
191 mDNSu32 NumAllInterfaceQuestions = 0;
192 #endif
193
194 // Check core mDNS lists
195 AuthRecord *rr;
196 for (rr = m->ResourceRecords; rr; rr=rr->next)
197 {
198 if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
199 LogMemCorruption("ResourceRecords list: %p is garbage (%X)", rr, rr->resrec.RecordType);
200 if (rr->resrec.name != &rr->namestorage)
201 LogMemCorruption("ResourceRecords list: %p name %p does not point to namestorage %p %##s",
202 rr, rr->resrec.name->c, rr->namestorage.c, rr->namestorage.c);
203 #if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
204 if (!AuthRecord_uDNS(rr) && !RRLocalOnly(rr)) NumAllInterfaceRecords++;
205 #endif
206 }
207
208 for (rr = m->DuplicateRecords; rr; rr=rr->next)
209 {
210 if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
211 LogMemCorruption("DuplicateRecords list: %p is garbage (%X)", rr, rr->resrec.RecordType);
212 #if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
213 if (!AuthRecord_uDNS(rr) && !RRLocalOnly(rr)) NumAllInterfaceRecords++;
214 #endif
215 }
216
217 rr = m->NewLocalRecords;
218 if (rr)
219 if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
220 LogMemCorruption("NewLocalRecords: %p is garbage (%X)", rr, rr->resrec.RecordType);
221
222 rr = m->CurrentRecord;
223 if (rr)
224 if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
225 LogMemCorruption("CurrentRecord: %p is garbage (%X)", rr, rr->resrec.RecordType);
226
227 DNSQuestion *q;
228 for (q = m->Questions; q; q=q->next)
229 {
230 if (q->next == (DNSQuestion*)~0 || q->ThisQInterval == (mDNSs32) ~0)
231 LogMemCorruption("Questions list: %p is garbage (%lX %p)", q, q->ThisQInterval, q->next);
232 if (q->DuplicateOf && q->LocalSocket)
233 LogMemCorruption("Questions list: Duplicate Question %p should not have LocalSocket set %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
234 #if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
235 if (!LocalOnlyOrP2PInterface(q->InterfaceID) && mDNSOpaque16IsZero(q->TargetQID))
236 NumAllInterfaceQuestions++;
237 #endif
238 }
239
240 CacheGroup *cg;
241 CacheRecord *cr;
242 mDNSu32 slot;
243 FORALL_CACHERECORDS(slot, cg, cr)
244 {
245 if (cr->resrec.RecordType == 0 || cr->resrec.RecordType == 0xFF)
246 LogMemCorruption("Cache slot %lu: %p is garbage (%X)", slot, cr, cr->resrec.RecordType);
247 if (cr->CRActiveQuestion)
248 {
249 for (q = m->Questions; q; q=q->next) if (q == cr->CRActiveQuestion) break;
250 if (!q) LogMemCorruption("Cache slot %lu: CRActiveQuestion %p not in m->Questions list %s", slot, cr->CRActiveQuestion, CRDisplayString(m, cr));
251 }
252 }
253
254 #if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
255 if (m->NumAllInterfaceRecords != NumAllInterfaceRecords)
256 LogMemCorruption("NumAllInterfaceRecords is %d should be %d", m->NumAllInterfaceRecords, NumAllInterfaceRecords);
257
258 if (m->NumAllInterfaceQuestions != NumAllInterfaceQuestions)
259 LogMemCorruption("NumAllInterfaceQuestions is %d should be %d", m->NumAllInterfaceQuestions, NumAllInterfaceQuestions);
260 #endif // MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
261 }
262 #endif // MDNS_MALLOC_DEBUGGING
263
264 // Returns true if this is a unique, authoritative LocalOnly record that answers questions of type
265 // A, AAAA , CNAME, or PTR. The caller should answer the question with this record and not send out
266 // the question on the wire if LocalOnlyRecordAnswersQuestion() also returns true.
267 // Main use is to handle /etc/hosts records and the LocalOnly PTR records created for localhost.
268 #define UniqueLocalOnlyRecord(rr) ((rr)->ARType == AuthRecordLocalOnly && \
269 (rr)->resrec.RecordType & kDNSRecordTypeUniqueMask && \
270 ((rr)->resrec.rrtype == kDNSType_A || (rr)->resrec.rrtype == kDNSType_AAAA || \
271 (rr)->resrec.rrtype == kDNSType_CNAME || \
272 (rr)->resrec.rrtype == kDNSType_PTR))
273
SetNextQueryStopTime(mDNS * const m,const DNSQuestion * const q)274 mDNSlocal void SetNextQueryStopTime(mDNS *const m, const DNSQuestion *const q)
275 {
276 mDNS_CheckLock(m);
277
278 if (m->NextScheduledStopTime - q->StopTime > 0)
279 m->NextScheduledStopTime = q->StopTime;
280 }
281
SetNextQueryTime(mDNS * const m,const DNSQuestion * const q)282 mDNSexport void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q)
283 {
284 mDNS_CheckLock(m);
285
286 if (ActiveQuestion(q))
287 {
288 // Depending on whether this is a multicast or unicast question we want to set either:
289 // m->NextScheduledQuery = NextQSendTime(q) or
290 // m->NextuDNSEvent = NextQSendTime(q)
291 mDNSs32 *const timer = mDNSOpaque16IsZero(q->TargetQID) ? &m->NextScheduledQuery : &m->NextuDNSEvent;
292 if (*timer - NextQSendTime(q) > 0)
293 *timer = NextQSendTime(q);
294 }
295 }
296
ReleaseAuthEntity(AuthHash * r,AuthEntity * e)297 mDNSlocal void ReleaseAuthEntity(AuthHash *r, AuthEntity *e)
298 {
299 #if MDNS_MALLOC_DEBUGGING >= 1
300 unsigned int i;
301 for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF;
302 #endif
303 e->next = r->rrauth_free;
304 r->rrauth_free = e;
305 r->rrauth_totalused--;
306 }
307
ReleaseAuthGroup(AuthHash * r,AuthGroup ** cp)308 mDNSlocal void ReleaseAuthGroup(AuthHash *r, AuthGroup **cp)
309 {
310 AuthEntity *e = (AuthEntity *)(*cp);
311 LogMsg("ReleaseAuthGroup: Releasing AuthGroup %##s", (*cp)->name->c);
312 if ((*cp)->rrauth_tail != &(*cp)->members)
313 LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrauth_tail != &(*cp)->members)");
314 if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name);
315 (*cp)->name = mDNSNULL;
316 *cp = (*cp)->next; // Cut record from list
317 ReleaseAuthEntity(r, e);
318 }
319
GetAuthEntity(AuthHash * r,const AuthGroup * const PreserveAG)320 mDNSlocal AuthEntity *GetAuthEntity(AuthHash *r, const AuthGroup *const PreserveAG)
321 {
322 AuthEntity *e = mDNSNULL;
323
324 if (r->rrauth_lock) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL); }
325 r->rrauth_lock = 1;
326
327 if (!r->rrauth_free)
328 {
329 // We allocate just one AuthEntity at a time because we need to be able
330 // free them all individually which normally happens when we parse /etc/hosts into
331 // AuthHash where we add the "new" entries and discard (free) the already added
332 // entries. If we allocate as chunks, we can't free them individually.
333 AuthEntity *storage = (AuthEntity *) mDNSPlatformMemAllocateClear(sizeof(*storage));
334 storage->next = mDNSNULL;
335 r->rrauth_free = storage;
336 }
337
338 // If we still have no free records, recycle all the records we can.
339 // Enumerating the entire auth is moderately expensive, so when we do it, we reclaim all the records we can in one pass.
340 if (!r->rrauth_free)
341 {
342 mDNSu32 oldtotalused = r->rrauth_totalused;
343 mDNSu32 slot;
344 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
345 {
346 AuthGroup **cp = &r->rrauth_hash[slot];
347 while (*cp)
348 {
349 if ((*cp)->members || (*cp)==PreserveAG) cp=&(*cp)->next;
350 else ReleaseAuthGroup(r, cp);
351 }
352 }
353 LogInfo("GetAuthEntity: Recycled %d records to reduce auth cache from %d to %d",
354 oldtotalused - r->rrauth_totalused, oldtotalused, r->rrauth_totalused);
355 }
356
357 if (r->rrauth_free) // If there are records in the free list, take one
358 {
359 e = r->rrauth_free;
360 r->rrauth_free = e->next;
361 if (++r->rrauth_totalused >= r->rrauth_report)
362 {
363 LogInfo("RR Auth now using %ld objects", r->rrauth_totalused);
364 if (r->rrauth_report < 100) r->rrauth_report += 10;
365 else if (r->rrauth_report < 1000) r->rrauth_report += 100;
366 else r->rrauth_report += 1000;
367 }
368 mDNSPlatformMemZero(e, sizeof(*e));
369 }
370
371 r->rrauth_lock = 0;
372
373 return(e);
374 }
375
AuthGroupForName(AuthHash * r,const mDNSu32 namehash,const domainname * const name)376 mDNSexport AuthGroup *AuthGroupForName(AuthHash *r, const mDNSu32 namehash, const domainname *const name)
377 {
378 AuthGroup *ag;
379 const mDNSu32 slot = namehash % AUTH_HASH_SLOTS;
380
381 for (ag = r->rrauth_hash[slot]; ag; ag=ag->next)
382 if (ag->namehash == namehash && SameDomainName(ag->name, name))
383 break;
384 return(ag);
385 }
386
AuthGroupForRecord(AuthHash * r,const ResourceRecord * const rr)387 mDNSexport AuthGroup *AuthGroupForRecord(AuthHash *r, const ResourceRecord *const rr)
388 {
389 return(AuthGroupForName(r, rr->namehash, rr->name));
390 }
391
GetAuthGroup(AuthHash * r,const ResourceRecord * const rr)392 mDNSlocal AuthGroup *GetAuthGroup(AuthHash *r, const ResourceRecord *const rr)
393 {
394 mDNSu16 namelen = DomainNameLength(rr->name);
395 AuthGroup *ag = (AuthGroup*)GetAuthEntity(r, mDNSNULL);
396 const mDNSu32 slot = rr->namehash % AUTH_HASH_SLOTS;
397 if (!ag) { LogMsg("GetAuthGroup: Failed to allocate memory for %##s", rr->name->c); return(mDNSNULL); }
398 ag->next = r->rrauth_hash[slot];
399 ag->namehash = rr->namehash;
400 ag->members = mDNSNULL;
401 ag->rrauth_tail = &ag->members;
402 ag->NewLocalOnlyRecords = mDNSNULL;
403 if (namelen > sizeof(ag->namestorage))
404 ag->name = (domainname *) mDNSPlatformMemAllocate(namelen);
405 else
406 ag->name = (domainname*)ag->namestorage;
407 if (!ag->name)
408 {
409 LogMsg("GetAuthGroup: Failed to allocate name storage for %##s", rr->name->c);
410 ReleaseAuthEntity(r, (AuthEntity*)ag);
411 return(mDNSNULL);
412 }
413 AssignDomainName(ag->name, rr->name);
414
415 if (AuthGroupForRecord(r, rr)) LogMsg("GetAuthGroup: Already have AuthGroup for %##s", rr->name->c);
416 r->rrauth_hash[slot] = ag;
417 if (AuthGroupForRecord(r, rr) != ag) LogMsg("GetAuthGroup: Not finding AuthGroup for %##s", rr->name->c);
418
419 return(ag);
420 }
421
422 // Returns the AuthGroup in which the AuthRecord was inserted
InsertAuthRecord(mDNS * const m,AuthHash * r,AuthRecord * rr)423 mDNSexport AuthGroup *InsertAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr)
424 {
425 AuthGroup *ag;
426
427 (void)m;
428 ag = AuthGroupForRecord(r, &rr->resrec);
429 if (!ag) ag = GetAuthGroup(r, &rr->resrec); // If we don't have a AuthGroup for this name, make one now
430 if (ag)
431 {
432 *(ag->rrauth_tail) = rr; // Append this record to tail of cache slot list
433 ag->rrauth_tail = &(rr->next); // Advance tail pointer
434 }
435 return ag;
436 }
437
RemoveAuthRecord(mDNS * const m,AuthHash * r,AuthRecord * rr)438 mDNSexport AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr)
439 {
440 AuthGroup *a;
441 AuthRecord **rp;
442
443 a = AuthGroupForRecord(r, &rr->resrec);
444 if (!a) { LogMsg("RemoveAuthRecord: ERROR!! AuthGroup not found for %s", ARDisplayString(m, rr)); return mDNSNULL; }
445 rp = &a->members;
446 while (*rp)
447 {
448 if (*rp != rr)
449 rp=&(*rp)->next;
450 else
451 {
452 // We don't break here, so that we can set the tail below without tracking "prev" pointers
453
454 LogInfo("RemoveAuthRecord: removing auth record %s from table", ARDisplayString(m, rr));
455 *rp = (*rp)->next; // Cut record from list
456 }
457 }
458 // TBD: If there are no more members, release authgroup ?
459 a->rrauth_tail = rp;
460 return a;
461 }
462
CacheGroupForName(const mDNS * const m,const mDNSu32 namehash,const domainname * const name)463 mDNSexport CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 namehash, const domainname *const name)
464 {
465 CacheGroup *cg;
466 mDNSu32 slot = HashSlotFromNameHash(namehash);
467 for (cg = m->rrcache_hash[slot]; cg; cg=cg->next)
468 if (cg->namehash == namehash && SameDomainName(cg->name, name))
469 break;
470 return(cg);
471 }
472
CacheGroupForRecord(const mDNS * const m,const ResourceRecord * const rr)473 mDNSlocal CacheGroup *CacheGroupForRecord(const mDNS *const m, const ResourceRecord *const rr)
474 {
475 return(CacheGroupForName(m, rr->namehash, rr->name));
476 }
477
mDNS_AddressIsLocalSubnet(mDNS * const m,const mDNSInterfaceID InterfaceID,const mDNSAddr * addr)478 mDNSexport mDNSBool mDNS_AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr)
479 {
480 NetworkInterfaceInfo *intf;
481
482 if (addr->type == mDNSAddrType_IPv4)
483 {
484 // Normally we resist touching the NotAnInteger fields, but here we're doing tricky bitwise masking so we make an exception
485 if (mDNSv4AddressIsLinkLocal(&addr->ip.v4)) return(mDNStrue);
486 for (intf = m->HostInterfaces; intf; intf = intf->next)
487 if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
488 if (((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) & intf->mask.ip.v4.NotAnInteger) == 0)
489 return(mDNStrue);
490 }
491
492 if (addr->type == mDNSAddrType_IPv6)
493 {
494 if (mDNSv6AddressIsLinkLocal(&addr->ip.v6)) return(mDNStrue);
495 for (intf = m->HostInterfaces; intf; intf = intf->next)
496 if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
497 if ((((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) &&
498 (((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) & intf->mask.ip.v6.l[1]) == 0) &&
499 (((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) & intf->mask.ip.v6.l[2]) == 0) &&
500 (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) & intf->mask.ip.v6.l[3]) == 0))
501 return(mDNStrue);
502 }
503
504 return(mDNSfalse);
505 }
506
FirstInterfaceForID(mDNS * const m,const mDNSInterfaceID InterfaceID)507 mDNSlocal NetworkInterfaceInfo *FirstInterfaceForID(mDNS *const m, const mDNSInterfaceID InterfaceID)
508 {
509 NetworkInterfaceInfo *intf = m->HostInterfaces;
510 while (intf && intf->InterfaceID != InterfaceID) intf = intf->next;
511 return(intf);
512 }
513
FirstIPv4LLInterfaceForID(mDNS * const m,const mDNSInterfaceID InterfaceID)514 mDNSlocal NetworkInterfaceInfo *FirstIPv4LLInterfaceForID(mDNS *const m, const mDNSInterfaceID InterfaceID)
515 {
516 NetworkInterfaceInfo *intf;
517
518 if (!InterfaceID)
519 return mDNSNULL;
520
521 // Note: We don't check for InterfaceActive, as the active interface could be IPv6 and
522 // we still want to find the first IPv4 Link-Local interface
523 for (intf = m->HostInterfaces; intf; intf = intf->next)
524 {
525 if (intf->InterfaceID == InterfaceID &&
526 intf->ip.type == mDNSAddrType_IPv4 && mDNSv4AddressIsLinkLocal(&intf->ip.ip.v4))
527 {
528 debugf("FirstIPv4LLInterfaceForID: found LL interface with address %.4a", &intf->ip.ip.v4);
529 return intf;
530 }
531 }
532 return (mDNSNULL);
533 }
534
InterfaceNameForID(mDNS * const m,const mDNSInterfaceID InterfaceID)535 mDNSexport char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID)
536 {
537 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
538 return(intf ? intf->ifname : mDNSNULL);
539 }
540
541 // Caller should hold the lock
GenerateNegativeResponseEx(mDNS * const m,mDNSInterfaceID InterfaceID,QC_result qc,mDNSBool noData)542 mDNSlocal void GenerateNegativeResponseEx(mDNS *const m, mDNSInterfaceID InterfaceID, QC_result qc, mDNSBool noData)
543 {
544 DNSQuestion *q;
545 if (!m->CurrentQuestion) { LogMsg("GenerateNegativeResponse: ERROR!! CurrentQuestion not set"); return; }
546 q = m->CurrentQuestion;
547 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
548 "[R%d->Q%d] GenerateNegativeResponse: Generating negative response for question " PRI_DM_NAME " (" PUB_S ")",
549 q->request_id, mDNSVal16(q->TargetQID), DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype));
550
551 MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, InterfaceID, mDNSNULL);
552 m->rec.r.resrec.negativeRecordType = noData ? kNegativeRecordType_NoData : kNegativeRecordType_Unspecified;
553
554 // We need to force the response through in the following cases
555 //
556 // a) SuppressUnusable questions that are suppressed
557 // b) Append search domains and retry the question
558 //
559 // The question may not have set Intermediates in which case we don't deliver negative responses. So, to force
560 // through we use "QC_forceresponse".
561 AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, qc);
562 if (m->CurrentQuestion == q) { q->ThisQInterval = 0; } // Deactivate this question
563 // Don't touch the question after this
564 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
565 }
566 #define GenerateNegativeResponse(M, INTERFACE_ID, QC) GenerateNegativeResponseEx(M, INTERFACE_ID, QC, mDNSfalse)
567
AnswerQuestionByFollowingCNAME(mDNS * const m,DNSQuestion * q,ResourceRecord * rr)568 mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, ResourceRecord *rr)
569 {
570 const mDNSBool selfref = SameDomainName(&q->qname, &rr->rdata->u.name);
571 if (q->CNAMEReferrals >= 10 || selfref)
572 {
573 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
574 "[R%d->Q%d] AnswerQuestionByFollowingCNAME: %p " PRI_DM_NAME " (" PUB_S ") NOT following CNAME referral %d" PUB_S " for " PRI_S,
575 q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype),
576 q->CNAMEReferrals, selfref ? " (Self-Referential)" : "", RRDisplayString(m, rr));
577
578 }
579 else
580 {
581 UDPSocket *sock = q->LocalSocket;
582 mDNSOpaque16 id = q->TargetQID;
583 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
584 uDNSMetrics metrics;
585 #endif
586
587 q->LocalSocket = mDNSNULL;
588
589 // The SameDomainName check above is to ignore bogus CNAME records that point right back at
590 // themselves. Without that check we can get into a case where we have two duplicate questions,
591 // A and B, and when we stop question A, UpdateQuestionDuplicates copies the value of CNAMEReferrals
592 // from A to B, and then A is re-appended to the end of the list as a duplicate of B (because
593 // the target name is still the same), and then when we stop question B, UpdateQuestionDuplicates
594 // copies the B's value of CNAMEReferrals back to A, and we end up not incrementing CNAMEReferrals
595 // for either of them. This is not a problem for CNAME loops of two or more records because in
596 // those cases the newly re-appended question A has a different target name and therefore cannot be
597 // a duplicate of any other question ('B') which was itself a duplicate of the previous question A.
598
599 // Right now we just stop and re-use the existing query. If we really wanted to be 100% perfect,
600 // and track CNAMEs coming and going, we should really create a subordinate query here,
601 // which we would subsequently cancel and retract if the CNAME referral record were removed.
602 // In reality this is such a corner case we'll ignore it until someone actually needs it.
603
604 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
605 "[R%d->Q%d] AnswerQuestionByFollowingCNAME: %p " PRI_DM_NAME " (" PUB_S ") following CNAME referral %d for " PRI_S,
606 q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype),
607 q->CNAMEReferrals, RRDisplayString(m, rr));
608
609 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
610 if (!mDNSOpaque16IsZero(q->TargetQID))
611 {
612 // Must be called before zeroing out q->metrics below.
613 Querier_PrepareQuestionForCNAMERestart(q);
614 }
615 #endif
616 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
617 if ((q->CNAMEReferrals == 0) && !q->metrics.originalQName)
618 {
619 domainname * qName;
620 mDNSu16 qNameLen;
621
622 qNameLen = DomainNameLength(&q->qname);
623 if ((qNameLen > 0) && (qNameLen <= MAX_DOMAIN_NAME))
624 {
625 qName = (domainname *) mDNSPlatformMemAllocate(qNameLen);
626 if (qName)
627 {
628 mDNSPlatformMemCopy(qName->c, q->qname.c, qNameLen);
629 q->metrics.originalQName = qName;
630 }
631 }
632 }
633 metrics = q->metrics;
634 // The metrics will be transplanted to the restarted question, so zero out the old copy instead of using
635 // uDNSMetricsClear(), which will free any pointers to allocated memory.
636 mDNSPlatformMemZero(&q->metrics, sizeof(q->metrics));
637 #endif
638 mDNS_StopQuery_internal(m, q); // Stop old query
639 AssignDomainName(&q->qname, &rr->rdata->u.name); // Update qname
640 q->qnamehash = DomainNameHashValue(&q->qname); // and namehash
641 // If a unicast query results in a CNAME that points to a .local, we need to re-try
642 // this as unicast. Setting the mDNSInterface_Unicast tells mDNS_StartQuery_internal
643 // to try this as unicast query even though it is a .local name
644 if (!mDNSOpaque16IsZero(q->TargetQID) && IsLocalDomain(&q->qname))
645 {
646 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
647 "[R%d->Q%d] AnswerQuestionByFollowingCNAME: Resolving a .local CNAME %p " PRI_DM_NAME " (" PUB_S ") Record " PRI_S,
648 q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype), RRDisplayString(m, rr));
649 q->IsUnicastDotLocal = mDNStrue;
650 }
651 q->CNAMEReferrals += 1; // Increment value before calling mDNS_StartQuery_internal
652 const mDNSu32 c = q->CNAMEReferrals; // Stash a copy of the new q->CNAMEReferrals value
653 mDNS_StartQuery_internal(m, q); // start new query
654 // Record how many times we've done this. We need to do this *after* mDNS_StartQuery_internal,
655 // because mDNS_StartQuery_internal re-initializes CNAMEReferrals to zero
656 q->CNAMEReferrals = c;
657 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
658 metrics.expiredAnswerState = q->metrics.expiredAnswerState; // We want the newly initialized state for this value
659 metrics.dnsOverTCPState = q->metrics.dnsOverTCPState; // We want the newly initialized state for this value
660 q->metrics = metrics;
661 #endif
662 if (sock)
663 {
664 // If our new query is a duplicate, then it can't have a socket of its own, so we have to close the one we saved.
665 if (q->DuplicateOf) mDNSPlatformUDPClose(sock);
666 else
667 {
668 // Transplant the old socket into the new question, and copy the query ID across too.
669 // No need to close the old q->LocalSocket value because it won't have been created yet (they're made lazily on-demand).
670 q->LocalSocket = sock;
671 q->TargetQID = id;
672 }
673 }
674 }
675 }
676
677 #ifdef USE_LIBIDN
678
679 #include <unicode/uidna.h>
680
681 // #define DEBUG_PUNYCODE 1
682
PunycodeConvert(const mDNSu8 * const src,mDNSu8 * const dst,const mDNSu8 * const end)683 mDNSlocal mDNSu8 *PunycodeConvert(const mDNSu8 *const src, mDNSu8 *const dst, const mDNSu8 *const end)
684 {
685 UErrorCode errorCode = U_ZERO_ERROR;
686 UIDNAInfo info = UIDNA_INFO_INITIALIZER;
687 UIDNA *uts46 = uidna_openUTS46(UIDNA_USE_STD3_RULES|UIDNA_NONTRANSITIONAL_TO_UNICODE, &errorCode);
688 int32_t len = uidna_nameToASCII_UTF8(uts46, (const char *)src+1, src[0], (char *)dst+1, (int32_t)(end-(dst+1)), &info, &errorCode);
689 uidna_close(uts46);
690 #if DEBUG_PUNYCODE
691 if (errorCode) LogMsg("uidna_nameToASCII_UTF8(%##s) failed errorCode %d", src, errorCode);
692 if (info.errors) LogMsg("uidna_nameToASCII_UTF8(%##s) failed info.errors 0x%08X", src, info.errors);
693 if (len > MAX_DOMAIN_LABEL) LogMsg("uidna_nameToASCII_UTF8(%##s) result too long %d", src, len);
694 #endif
695 if (errorCode || info.errors || len > MAX_DOMAIN_LABEL) return mDNSNULL;
696 *dst = len;
697 return(dst + 1 + len);
698 }
699
IsHighASCIILabel(const mDNSu8 * d)700 mDNSlocal mDNSBool IsHighASCIILabel(const mDNSu8 *d)
701 {
702 int i;
703 for (i=1; i<=d[0]; i++) if (d[i] & 0x80) return mDNStrue;
704 return mDNSfalse;
705 }
706
FindLastHighASCIILabel(const domainname * const d)707 mDNSlocal const mDNSu8 *FindLastHighASCIILabel(const domainname *const d)
708 {
709 const mDNSu8 *ptr = d->c;
710 const mDNSu8 *ans = mDNSNULL;
711 while (ptr[0])
712 {
713 const mDNSu8 *const next = ptr + 1 + ptr[0];
714 if (ptr[0] > MAX_DOMAIN_LABEL || next >= d->c + MAX_DOMAIN_NAME) return mDNSNULL;
715 if (IsHighASCIILabel(ptr)) ans = ptr;
716 ptr = next;
717 }
718 return ans;
719 }
720
PerformNextPunycodeConversion(const DNSQuestion * const q,domainname * const newname)721 mDNSlocal mDNSBool PerformNextPunycodeConversion(const DNSQuestion *const q, domainname *const newname)
722 {
723 const mDNSu8 *h = FindLastHighASCIILabel(&q->qname);
724 #if DEBUG_PUNYCODE
725 LogMsg("PerformNextPunycodeConversion: %##s (%s) Last High-ASCII Label %##s", q->qname.c, DNSTypeName(q->qtype), h);
726 #endif
727 if (!h) return mDNSfalse; // There are no high-ascii labels to convert
728
729 mDNSu8 *const dst = PunycodeConvert(h, newname->c + (h - q->qname.c), newname->c + MAX_DOMAIN_NAME);
730 if (!dst)
731 return mDNSfalse; // The label was not convertible to Punycode
732 else
733 {
734 // If Punycode conversion of final eligible label was successful, copy the rest of the domainname
735 const mDNSu8 *const src = h + 1 + h[0];
736 const mDNSu8 remainder = DomainNameLength((domainname*)src);
737 if (dst + remainder > newname->c + MAX_DOMAIN_NAME) return mDNSfalse; // Name too long -- cannot be converted to Punycode
738
739 mDNSPlatformMemCopy(newname->c, q->qname.c, (mDNSu32)(h - q->qname.c)); // Fill in the leading part
740 mDNSPlatformMemCopy(dst, src, remainder); // Fill in the trailing part
741 #if DEBUG_PUNYCODE
742 LogMsg("PerformNextPunycodeConversion: %##s converted to %##s", q->qname.c, newname->c);
743 #endif
744 return mDNStrue;
745 }
746 }
747
748 #endif // USE_LIBIDN
749
750 // For a single given DNSQuestion pointed to by CurrentQuestion, deliver an add/remove result for the single given AuthRecord
751 // Note: All the callers should use the m->CurrentQuestion to see if the question is still valid or not
AnswerLocalQuestionWithLocalAuthRecord(mDNS * const m,AuthRecord * rr,QC_result AddRecord)752 mDNSlocal void AnswerLocalQuestionWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord)
753 {
754 DNSQuestion *q = m->CurrentQuestion;
755 mDNSBool followcname;
756
757 if (!q)
758 {
759 LogMsg("AnswerLocalQuestionWithLocalAuthRecord: ERROR!! CurrentQuestion NULL while answering with %s", ARDisplayString(m, rr));
760 return;
761 }
762
763 followcname = FollowCNAME(q, &rr->resrec, AddRecord);
764
765 // We should not be delivering results for record types Unregistered, Deregistering, and (unverified) Unique
766 if (!(rr->resrec.RecordType & kDNSRecordTypeActiveMask))
767 {
768 LogMsg("AnswerLocalQuestionWithLocalAuthRecord: *NOT* delivering %s event for local record type %X %s",
769 AddRecord ? "Add" : "Rmv", rr->resrec.RecordType, ARDisplayString(m, rr));
770 return;
771 }
772
773 // Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it
774 if (AddRecord) rr->AnsweredLocalQ = mDNStrue;
775 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
776 if (q->QuestionCallback && !q->NoAnswer)
777 {
778 q->CurrentAnswers += AddRecord ? 1 : -1;
779 if (UniqueLocalOnlyRecord(rr))
780 {
781 if (!followcname || q->ReturnIntermed)
782 {
783 // Don't send this packet on the wire as we answered from /etc/hosts
784 q->ThisQInterval = 0;
785 q->LOAddressAnswers += AddRecord ? 1 : -1;
786 q->QuestionCallback(m, q, &rr->resrec, AddRecord);
787 }
788 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
789 // The callback above could have caused the question to stop. Detect that
790 // using m->CurrentQuestion
791 if (followcname && m->CurrentQuestion == q)
792 AnswerQuestionByFollowingCNAME(m, q, &rr->resrec);
793 return;
794 }
795 else
796 {
797 q->QuestionCallback(m, q, &rr->resrec, AddRecord);
798 }
799 }
800 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
801 }
802
AnswerInterfaceAnyQuestionsWithLocalAuthRecord(mDNS * const m,AuthRecord * ar,QC_result AddRecord)803 mDNSlocal void AnswerInterfaceAnyQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *ar, QC_result AddRecord)
804 {
805 if (m->CurrentQuestion)
806 LogMsg("AnswerInterfaceAnyQuestionsWithLocalAuthRecord: ERROR m->CurrentQuestion already set: %##s (%s)",
807 m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
808 m->CurrentQuestion = m->Questions;
809 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
810 {
811 mDNSBool answered;
812 DNSQuestion *q = m->CurrentQuestion;
813 if (RRAny(ar))
814 answered = AuthRecordAnswersQuestion(ar, q);
815 else
816 answered = LocalOnlyRecordAnswersQuestion(ar, q);
817 if (answered)
818 AnswerLocalQuestionWithLocalAuthRecord(m, ar, AddRecord); // MUST NOT dereference q again
819 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
820 m->CurrentQuestion = q->next;
821 }
822 m->CurrentQuestion = mDNSNULL;
823 }
824
825 // When a new local AuthRecord is created or deleted, AnswerAllLocalQuestionsWithLocalAuthRecord()
826 // delivers the appropriate add/remove events to listening questions:
827 // 1. It runs though all our LocalOnlyQuestions delivering answers as appropriate,
828 // stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion().
829 // 2. If the AuthRecord is marked mDNSInterface_LocalOnly or mDNSInterface_P2P, then it also runs though
830 // our main question list, delivering answers to mDNSInterface_Any questions as appropriate,
831 // stopping if it reaches a NewQuestion -- brand-new questions are handled by AnswerNewQuestion().
832 //
833 // AnswerAllLocalQuestionsWithLocalAuthRecord is used by the m->NewLocalRecords loop in mDNS_Execute(),
834 // and by mDNS_Deregister_internal()
835
AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS * const m,AuthRecord * ar,QC_result AddRecord)836 mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *ar, QC_result AddRecord)
837 {
838 if (m->CurrentQuestion)
839 LogMsg("AnswerAllLocalQuestionsWithLocalAuthRecord ERROR m->CurrentQuestion already set: %##s (%s)",
840 m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
841
842 m->CurrentQuestion = m->LocalOnlyQuestions;
843 while (m->CurrentQuestion && m->CurrentQuestion != m->NewLocalOnlyQuestions)
844 {
845 mDNSBool answered;
846 DNSQuestion *q = m->CurrentQuestion;
847 // We are called with both LocalOnly/P2P record or a regular AuthRecord
848 if (RRAny(ar))
849 answered = AuthRecordAnswersQuestion(ar, q);
850 else
851 answered = LocalOnlyRecordAnswersQuestion(ar, q);
852 if (answered)
853 AnswerLocalQuestionWithLocalAuthRecord(m, ar, AddRecord); // MUST NOT dereference q again
854 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
855 m->CurrentQuestion = q->next;
856 }
857
858 m->CurrentQuestion = mDNSNULL;
859
860 // If this AuthRecord is marked LocalOnly or P2P, then we want to deliver it to all local 'mDNSInterface_Any' questions
861 if (ar->ARType == AuthRecordLocalOnly || ar->ARType == AuthRecordP2P)
862 AnswerInterfaceAnyQuestionsWithLocalAuthRecord(m, ar, AddRecord);
863
864 }
865
866 // ***************************************************************************
867 #if COMPILER_LIKES_PRAGMA_MARK
868 #pragma mark -
869 #pragma mark - Resource Record Utility Functions
870 #endif
871
872 #define RRTypeIsAddressType(T) ((T) == kDNSType_A || (T) == kDNSType_AAAA)
873
ResourceRecordIsValidAnswer(const AuthRecord * const rr)874 mDNSlocal mDNSBool ResourceRecordIsValidAnswer(const AuthRecord *const rr)
875 {
876 if ((rr->resrec.RecordType & kDNSRecordTypeActiveMask) &&
877 ((rr->Additional1 == mDNSNULL) || (rr->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) &&
878 ((rr->Additional2 == mDNSNULL) || (rr->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) &&
879 ((rr->DependentOn == mDNSNULL) || (rr->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask)))
880 {
881 return mDNStrue;
882 }
883 else
884 {
885 return mDNSfalse;
886 }
887 }
888
IsInterfaceValidForAuthRecord(const AuthRecord * const rr,const mDNSInterfaceID InterfaceID)889 mDNSlocal mDNSBool IsInterfaceValidForAuthRecord(const AuthRecord *const rr, const mDNSInterfaceID InterfaceID)
890 {
891 if (rr->resrec.InterfaceID == mDNSInterface_Any)
892 {
893 return mDNSPlatformValidRecordForInterface(rr, InterfaceID);
894 }
895 else
896 {
897 return ((rr->resrec.InterfaceID == InterfaceID) ? mDNStrue : mDNSfalse);
898 }
899 }
900
ResourceRecordIsValidInterfaceAnswer(const AuthRecord * const rr,const mDNSInterfaceID interfaceID)901 mDNSlocal mDNSBool ResourceRecordIsValidInterfaceAnswer(const AuthRecord *const rr, const mDNSInterfaceID interfaceID)
902 {
903 return ((IsInterfaceValidForAuthRecord(rr, interfaceID) && ResourceRecordIsValidAnswer(rr)) ? mDNStrue : mDNSfalse);
904 }
905
906 #define DefaultProbeCountForTypeUnique ((mDNSu8)3)
907 #define DefaultProbeCountForRecordType(X) ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0)
908
909 // Parameters for handling probing conflicts
910 #define kMaxAllowedMCastProbingConflicts 1 // Maximum number of conflicts to allow from mcast messages.
911 #define kProbingConflictPauseDuration mDNSPlatformOneSecond // Duration of probing pause after an allowed mcast conflict.
912
913 // See RFC 6762: "8.3 Announcing"
914 // "The Multicast DNS responder MUST send at least two unsolicited responses, one second apart."
915 // Send 4, which is really 8 since we send on both IPv4 and IPv6.
916 #define InitialAnnounceCount ((mDNSu8)4)
917
918 // For goodbye packets we set the count to 3, and for wakeups we set it to 18
919 // (which will be up to 15 wakeup attempts over the course of 30 seconds,
920 // and then if the machine fails to wake, 3 goodbye packets).
921 #define GoodbyeCount ((mDNSu8)3)
922 #define WakeupCount ((mDNSu8)18)
923 #define MAX_PROBE_RESTARTS ((mDNSu8)20)
924 #define MAX_GHOST_TIME ((mDNSs32)((60*60*24*7)*mDNSPlatformOneSecond)) // One week
925
926 // Number of wakeups we send if WakeOnResolve is set in the question
927 #define InitialWakeOnResolveCount ((mDNSu8)3)
928
929 // Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not.
930 // This means that because the announce interval is doubled after sending the first packet, the first
931 // observed on-the-wire inter-packet interval between announcements is actually one second.
932 // The half-second value here may be thought of as a conceptual (non-existent) half-second delay *before* the first packet is sent.
933 #define DefaultProbeIntervalForTypeUnique (mDNSPlatformOneSecond/4)
934 #define DefaultAnnounceIntervalForTypeShared (mDNSPlatformOneSecond/2)
935 #define DefaultAnnounceIntervalForTypeUnique (mDNSPlatformOneSecond/2)
936
937 #define DefaultAPIntervalForRecordType(X) ((X) &kDNSRecordTypeActiveSharedMask ? DefaultAnnounceIntervalForTypeShared : \
938 (X) &kDNSRecordTypeUnique ? DefaultProbeIntervalForTypeUnique : \
939 (X) &kDNSRecordTypeActiveUniqueMask ? DefaultAnnounceIntervalForTypeUnique : 0)
940
941 #define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0)
942 #define TicksTTL(RR) ((mDNSs32)(RR)->resrec.rroriginalttl * mDNSPlatformOneSecond)
943 #define RRExpireTime(RR) ((RR)->TimeRcvd + TicksTTL(RR))
944
945 // Adjustment factor to avoid race condition (used for unicast cache entries) :
946 // Suppose real record has TTL of 3600, and our local caching server has held it for 3500 seconds, so it returns an aged TTL of 100.
947 // If we do our normal refresh at 80% of the TTL, our local caching server will return 20 seconds, so we'll do another
948 // 80% refresh after 16 seconds, and then the server will return 4 seconds, and so on, in the fashion of Zeno's paradox.
949 // To avoid this, we extend the record's effective TTL to give it a little extra grace period.
950 // We adjust the 100 second TTL to 127. This means that when we do our 80% query after 102 seconds,
951 // the cached copy at our local caching server will already have expired, so the server will be forced
952 // to fetch a fresh copy from the authoritative server, and then return a fresh record with the full TTL of 3600 seconds.
953
954 #define RRAdjustTTL(ttl) ((ttl) + ((ttl)/4) + 2)
955 #define RRUnadjustedTTL(ttl) ((((ttl) - 2) * 4) / 5)
956
957 #define MaxUnansweredQueries 4
958
959 // SameResourceRecordSignature returns true if two resources records have the same name, type, and class, and may be sent
960 // (or were received) on the same interface (i.e. if *both* records specify an interface, then it has to match).
961 // TTL and rdata may differ.
962 // This is used for cache flush management:
963 // When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent
964 // When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed
965
966 // SameResourceRecordNameClassInterface is functionally the same as SameResourceRecordSignature, except rrtype does not have to match
967
968 #define SameResourceRecordSignature(A,B) (A)->resrec.rrtype == (B)->resrec.rrtype && SameResourceRecordNameClassInterface((A),(B))
969
SameResourceRecordNameClassInterface(const AuthRecord * const r1,const AuthRecord * const r2)970 mDNSlocal mDNSBool SameResourceRecordNameClassInterface(const AuthRecord *const r1, const AuthRecord *const r2)
971 {
972 if (!r1) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse); }
973 if (!r2) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse); }
974 if (r1->resrec.InterfaceID &&
975 r2->resrec.InterfaceID &&
976 r1->resrec.InterfaceID != r2->resrec.InterfaceID) return(mDNSfalse);
977 return (mDNSBool)(
978 r1->resrec.rrclass == r2->resrec.rrclass &&
979 r1->resrec.namehash == r2->resrec.namehash &&
980 SameDomainName(r1->resrec.name, r2->resrec.name));
981 }
982
983 // PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our
984 // authoratative record is unique (as opposed to shared). For unique records, we are supposed to have
985 // complete ownership of *all* types for this name, so *any* record type with the same name is a conflict.
986 // In addition, when probing we send our questions with the wildcard type kDNSQType_ANY,
987 // so a response of any type should match, even if it is not actually the type the client plans to use.
988
989 // For now, to make it easier to avoid false conflicts, we treat SPS Proxy records like shared records,
990 // and require the rrtypes to match for the rdata to be considered potentially conflicting
PacketRRMatchesSignature(const CacheRecord * const pktrr,const AuthRecord * const authrr)991 mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, const AuthRecord *const authrr)
992 {
993 if (!pktrr) { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse); }
994 if (!authrr) { LogMsg("PacketRRMatchesSignature ERROR: authrr is NULL"); return(mDNSfalse); }
995 if (pktrr->resrec.InterfaceID &&
996 authrr->resrec.InterfaceID &&
997 pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse);
998 if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) || authrr->WakeUp.HMAC.l[0])
999 if (pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse);
1000 if ((authrr->resrec.InterfaceID == mDNSInterface_Any) &&
1001 !mDNSPlatformValidRecordForInterface(authrr, pktrr->resrec.InterfaceID)) return(mDNSfalse);
1002 return (mDNSBool)(
1003 pktrr->resrec.rrclass == authrr->resrec.rrclass &&
1004 pktrr->resrec.namehash == authrr->resrec.namehash &&
1005 SameDomainName(pktrr->resrec.name, authrr->resrec.name));
1006 }
1007
1008 // CacheRecord *ka is the CacheRecord from the known answer list in the query.
1009 // This is the information that the requester believes to be correct.
1010 // AuthRecord *rr is the answer we are proposing to give, if not suppressed.
1011 // This is the information that we believe to be correct.
1012 // We've already determined that we plan to give this answer on this interface
1013 // (either the record is non-specific, or it is specific to this interface)
1014 // so now we just need to check the name, type, class, rdata and TTL.
ShouldSuppressKnownAnswer(const CacheRecord * const ka,const AuthRecord * const rr)1015 mDNSlocal mDNSBool ShouldSuppressKnownAnswer(const CacheRecord *const ka, const AuthRecord *const rr)
1016 {
1017 // If RR signature is different, or data is different, then don't suppress our answer
1018 if (!IdenticalResourceRecord(&ka->resrec, &rr->resrec)) return(mDNSfalse);
1019
1020 // If the requester's indicated TTL is less than half the real TTL,
1021 // we need to give our answer before the requester's copy expires.
1022 // If the requester's indicated TTL is at least half the real TTL,
1023 // then we can suppress our answer this time.
1024 // If the requester's indicated TTL is greater than the TTL we believe,
1025 // then that's okay, and we don't need to do anything about it.
1026 // (If two responders on the network are offering the same information,
1027 // that's okay, and if they are offering the information with different TTLs,
1028 // the one offering the lower TTL should defer to the one offering the higher TTL.)
1029 return (mDNSBool)(ka->resrec.rroriginalttl >= rr->resrec.rroriginalttl / 2);
1030 }
1031
SetNextAnnounceProbeTime(mDNS * const m,const AuthRecord * const rr)1032 mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const rr)
1033 {
1034 if (rr->resrec.RecordType == kDNSRecordTypeUnique)
1035 {
1036 if ((rr->LastAPTime + rr->ThisAPInterval) - m->timenow > mDNSPlatformOneSecond * 10)
1037 {
1038 LogMsg("SetNextAnnounceProbeTime: ProbeCount %d Next in %d %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr));
1039 LogMsg("SetNextAnnounceProbeTime: m->SuppressProbes %d m->timenow %d diff %d", m->SuppressProbes, m->timenow, m->SuppressProbes - m->timenow);
1040 }
1041 if (m->NextScheduledProbe - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
1042 m->NextScheduledProbe = (rr->LastAPTime + rr->ThisAPInterval);
1043 // Some defensive code:
1044 // If (rr->LastAPTime + rr->ThisAPInterval) happens to be far in the past, we don't want to allow
1045 // NextScheduledProbe to be set excessively in the past, because that can cause bad things to happen.
1046 // See: <rdar://problem/7795434> mDNS: Sometimes advertising stops working and record interval is set to zero
1047 if (m->NextScheduledProbe - m->timenow < 0)
1048 m->NextScheduledProbe = m->timenow;
1049 }
1050 else if (rr->AnnounceCount && (ResourceRecordIsValidAnswer(rr) || rr->resrec.RecordType == kDNSRecordTypeDeregistering))
1051 {
1052 if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
1053 m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval);
1054 }
1055 }
1056
InitializeLastAPTime(mDNS * const m,AuthRecord * const rr)1057 mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
1058 {
1059 // For reverse-mapping Sleep Proxy PTR records, probe interval is one second
1060 rr->ThisAPInterval = rr->AddressProxy.type ? mDNSPlatformOneSecond : DefaultAPIntervalForRecordType(rr->resrec.RecordType);
1061
1062 // * If this is a record type that's going to probe, then we use the m->SuppressProbes time.
1063 // * Otherwise, if it's not going to probe, but m->SuppressProbes is set because we have other
1064 // records that are going to probe, then we delay its first announcement so that it will
1065 // go out synchronized with the first announcement for the other records that *are* probing.
1066 // This is a minor performance tweak that helps keep groups of related records synchronized together.
1067 // The addition of "interval / 2" is to make sure that, in the event that any of the probes are
1068 // delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete.
1069 // When the probing is complete and those records begin to announce, these records will also be picked up and accelerated,
1070 // because they will meet the criterion of being at least half-way to their scheduled announcement time.
1071 // * If it's not going to probe and m->SuppressProbes is not already set then we should announce immediately.
1072
1073 if (rr->ProbeCount)
1074 {
1075 rr->ProbingConflictCount = 0;
1076 // If we have no probe suppression time set, or it is in the past, set it now
1077 if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0)
1078 {
1079 // To allow us to aggregate probes when a group of services are registered together,
1080 // the first probe is delayed by a random delay in the range 1/8 to 1/4 second.
1081 // This means the common-case behaviour is:
1082 // randomized wait; probe
1083 // 1/4 second wait; probe
1084 // 1/4 second wait; probe
1085 // 1/4 second wait; announce (i.e. service is normally announced 7/8 to 1 second after being registered)
1086 m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique/2 + mDNSRandom(DefaultProbeIntervalForTypeUnique/2));
1087
1088 // If we already have a *probe* scheduled to go out sooner, then use that time to get better aggregation
1089 if (m->SuppressProbes - m->NextScheduledProbe >= 0)
1090 m->SuppressProbes = NonZeroTime(m->NextScheduledProbe);
1091 if (m->SuppressProbes - m->timenow < 0) // Make sure we don't set m->SuppressProbes excessively in the past
1092 m->SuppressProbes = m->timenow;
1093
1094 // If we already have a *query* scheduled to go out sooner, then use that time to get better aggregation
1095 if (m->SuppressProbes - m->NextScheduledQuery >= 0)
1096 m->SuppressProbes = NonZeroTime(m->NextScheduledQuery);
1097 if (m->SuppressProbes - m->timenow < 0) // Make sure we don't set m->SuppressProbes excessively in the past
1098 m->SuppressProbes = m->timenow;
1099
1100 // except... don't expect to be able to send before the m->SuppressSending timer fires
1101 if (m->SuppressSending && m->SuppressProbes - m->SuppressSending < 0)
1102 m->SuppressProbes = NonZeroTime(m->SuppressSending);
1103
1104 if (m->SuppressProbes - m->timenow > mDNSPlatformOneSecond * 8)
1105 {
1106 LogMsg("InitializeLastAPTime ERROR m->SuppressProbes %d m->NextScheduledProbe %d m->NextScheduledQuery %d m->SuppressSending %d %d",
1107 m->SuppressProbes - m->timenow,
1108 m->NextScheduledProbe - m->timenow,
1109 m->NextScheduledQuery - m->timenow,
1110 m->SuppressSending,
1111 m->SuppressSending - m->timenow);
1112 m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique/2 + mDNSRandom(DefaultProbeIntervalForTypeUnique/2));
1113 }
1114 }
1115 rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval;
1116 }
1117 // Skip kDNSRecordTypeKnownUnique and kDNSRecordTypeShared records here and set their LastAPTime in the "else" block below so
1118 // that they get announced immediately, otherwise, their announcement would be delayed until the based on the SuppressProbes value.
1119 else if ((rr->resrec.RecordType != kDNSRecordTypeKnownUnique) && (rr->resrec.RecordType != kDNSRecordTypeShared) && m->SuppressProbes && (m->SuppressProbes - m->timenow >= 0))
1120 rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval + DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2;
1121 else
1122 rr->LastAPTime = m->timenow - rr->ThisAPInterval;
1123
1124 // For reverse-mapping Sleep Proxy PTR records we don't want to start probing instantly -- we
1125 // wait one second to give the client a chance to go to sleep, and then start our ARP/NDP probing.
1126 // After three probes one second apart with no answer, we conclude the client is now sleeping
1127 // and we can begin broadcasting our announcements to take over ownership of that IP address.
1128 // If we don't wait for the client to go to sleep, then when the client sees our ARP Announcements there's a risk
1129 // (depending on the OS and networking stack it's using) that it might interpret it as a conflict and change its IP address.
1130 if (rr->AddressProxy.type)
1131 rr->LastAPTime = m->timenow;
1132
1133 // Set LastMCTime to now, to inhibit multicast responses
1134 // (no need to send additional multicast responses when we're announcing anyway)
1135 rr->LastMCTime = m->timenow;
1136 rr->LastMCInterface = mDNSInterfaceMark;
1137
1138 SetNextAnnounceProbeTime(m, rr);
1139 }
1140
SetUnicastTargetToHostName(mDNS * const m,AuthRecord * rr)1141 mDNSlocal const domainname *SetUnicastTargetToHostName(mDNS *const m, AuthRecord *rr)
1142 {
1143 const domainname *target;
1144 if (rr->AutoTarget)
1145 {
1146 rr->AutoTarget = Target_AutoHostAndNATMAP;
1147 }
1148
1149 target = GetServiceTarget(m, rr);
1150 if (!target || target->c[0] == 0)
1151 {
1152 // defer registration until we've got a target
1153 LogInfo("SetUnicastTargetToHostName No target for %s", ARDisplayString(m, rr));
1154 rr->state = regState_NoTarget;
1155 return mDNSNULL;
1156 }
1157 else
1158 {
1159 LogInfo("SetUnicastTargetToHostName target %##s for resource record %s", target->c, ARDisplayString(m,rr));
1160 return target;
1161 }
1162 }
1163
1164 #if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
AuthRecordIncludesOrIsAWDL(const AuthRecord * const ar)1165 mDNSlocal mDNSBool AuthRecordIncludesOrIsAWDL(const AuthRecord *const ar)
1166 {
1167 return ((AuthRecordIncludesAWDL(ar) || mDNSPlatformInterfaceIsAWDL(ar->resrec.InterfaceID)) ? mDNStrue : mDNSfalse);
1168 }
1169 #endif
1170
1171 // Right now this only applies to mDNS (.local) services where the target host is always m->MulticastHostname
1172 // Eventually we should unify this with GetServiceTarget() in uDNS.c
SetTargetToHostName(mDNS * const m,AuthRecord * const rr)1173 mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
1174 {
1175 domainname *const target = GetRRDomainNameTarget(&rr->resrec);
1176 const domainname *newname;
1177
1178 #if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
1179 if (AuthRecordIncludesOrIsAWDL(rr))
1180 {
1181 newname = &m->RandomizedHostname;
1182 }
1183 else
1184 #endif
1185 {
1186 newname = &m->MulticastHostname;
1187 }
1188 if (!target) LogInfo("SetTargetToHostName: Don't know how to set the target of rrtype %s", DNSTypeName(rr->resrec.rrtype));
1189
1190 if (!(rr->ForceMCast || rr->ARType == AuthRecordLocalOnly || rr->ARType == AuthRecordP2P || IsLocalDomain(&rr->namestorage)))
1191 {
1192 const domainname *const n = SetUnicastTargetToHostName(m, rr);
1193 if (n) newname = n;
1194 else { if (target) target->c[0] = 0; SetNewRData(&rr->resrec, mDNSNULL, 0); return; }
1195 }
1196
1197 if (target && SameDomainName(target, newname))
1198 debugf("SetTargetToHostName: Target of %##s is already %##s", rr->resrec.name->c, target->c);
1199
1200 if (target && !SameDomainName(target, newname))
1201 {
1202 AssignDomainName(target, newname);
1203 SetNewRData(&rr->resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash
1204
1205 // If we're in the middle of probing this record, we need to start again,
1206 // because changing its rdata may change the outcome of the tie-breaker.
1207 // (If the record type is kDNSRecordTypeUnique (unconfirmed unique) then DefaultProbeCountForRecordType is non-zero.)
1208 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType);
1209
1210 // If we've announced this record, we really should send a goodbye packet for the old rdata before
1211 // changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records,
1212 // so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way.
1213 if (rr->RequireGoodbye && rr->resrec.RecordType == kDNSRecordTypeShared)
1214 debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating",
1215 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1216
1217 rr->AnnounceCount = InitialAnnounceCount;
1218 rr->RequireGoodbye = mDNSfalse;
1219 rr->ProbeRestartCount = 0;
1220 InitializeLastAPTime(m, rr);
1221 }
1222 }
1223
AcknowledgeRecord(mDNS * const m,AuthRecord * const rr)1224 mDNSlocal void AcknowledgeRecord(mDNS *const m, AuthRecord *const rr)
1225 {
1226 if (rr->RecordCallback)
1227 {
1228 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
1229 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
1230 rr->Acknowledged = mDNStrue;
1231 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
1232 rr->RecordCallback(m, rr, mStatus_NoError);
1233 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
1234 }
1235 }
1236
ActivateUnicastRegistration(mDNS * const m,AuthRecord * const rr)1237 mDNSexport void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr)
1238 {
1239 // Make sure that we don't activate the SRV record and associated service records, if it is in
1240 // NoTarget state. First time when a service is being instantiated, SRV record may be in NoTarget state.
1241 // We should not activate any of the other reords (PTR, TXT) that are part of the service. When
1242 // the target becomes available, the records will be reregistered.
1243 if (rr->resrec.rrtype != kDNSType_SRV)
1244 {
1245 AuthRecord *srvRR = mDNSNULL;
1246 if (rr->resrec.rrtype == kDNSType_PTR)
1247 srvRR = rr->Additional1;
1248 else if (rr->resrec.rrtype == kDNSType_TXT)
1249 srvRR = rr->DependentOn;
1250 if (srvRR)
1251 {
1252 if (srvRR->resrec.rrtype != kDNSType_SRV)
1253 {
1254 LogMsg("ActivateUnicastRegistration: ERROR!! Resource record %s wrong, expecting SRV type", ARDisplayString(m, srvRR));
1255 }
1256 else
1257 {
1258 LogInfo("ActivateUnicastRegistration: Found Service Record %s in state %d for %##s (%s)",
1259 ARDisplayString(m, srvRR), srvRR->state, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1260 rr->state = srvRR->state;
1261 }
1262 }
1263 }
1264
1265 if (rr->state == regState_NoTarget)
1266 {
1267 LogInfo("ActivateUnicastRegistration record %s in regState_NoTarget, not activating", ARDisplayString(m, rr));
1268 return;
1269 }
1270 // When we wake up from sleep, we call ActivateUnicastRegistration. It is possible that just before we went to sleep,
1271 // the service/record was being deregistered. In that case, we should not try to register again. For the cases where
1272 // the records are deregistered due to e.g., no target for the SRV record, we would have returned from above if it
1273 // was already in NoTarget state. If it was in the process of deregistration but did not complete fully before we went
1274 // to sleep, then it is okay to start in Pending state as we will go back to NoTarget state if we don't have a target.
1275 if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
1276 {
1277 LogInfo("ActivateUnicastRegistration: Resource record %s, current state %d, moving to DeregPending", ARDisplayString(m, rr), rr->state);
1278 rr->state = regState_DeregPending;
1279 }
1280 else
1281 {
1282 LogInfo("ActivateUnicastRegistration: Resource record %s, current state %d, moving to Pending", ARDisplayString(m, rr), rr->state);
1283 rr->state = regState_Pending;
1284 }
1285 rr->ProbingConflictCount = 0;
1286 rr->LastConflictPktNum = 0;
1287 rr->ProbeRestartCount = 0;
1288 rr->ProbeCount = 0;
1289 rr->AnnounceCount = 0;
1290 rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL;
1291 rr->LastAPTime = m->timenow - rr->ThisAPInterval;
1292 rr->expire = 0; // Forget about all the leases, start fresh
1293 rr->uselease = mDNStrue;
1294 rr->updateid = zeroID;
1295 rr->SRVChanged = mDNSfalse;
1296 rr->updateError = mStatus_NoError;
1297 // RestartRecordGetZoneData calls this function whenever a new interface gets registered with core.
1298 // The records might already be registered with the server and hence could have NAT state.
1299 if (rr->NATinfo.clientContext)
1300 {
1301 mDNS_StopNATOperation_internal(m, &rr->NATinfo);
1302 rr->NATinfo.clientContext = mDNSNULL;
1303 }
1304 if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; }
1305 if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
1306 if (m->NextuDNSEvent - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
1307 m->NextuDNSEvent = (rr->LastAPTime + rr->ThisAPInterval);
1308 }
1309
1310 // Two records qualify to be local duplicates if:
1311 // (a) the RecordTypes are the same, or
1312 // (b) one is Unique and the other Verified
1313 // (c) either is in the process of deregistering
1314 #define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \
1315 ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified) || \
1316 ((A)->resrec.RecordType == kDNSRecordTypeDeregistering || (B)->resrec.RecordType == kDNSRecordTypeDeregistering))
1317
1318 #define RecordIsLocalDuplicate(A,B) \
1319 ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(& (A)->resrec, & (B)->resrec))
1320
CheckAuthIdenticalRecord(AuthHash * r,AuthRecord * rr)1321 mDNSlocal AuthRecord *CheckAuthIdenticalRecord(AuthHash *r, AuthRecord *rr)
1322 {
1323 const AuthGroup *a;
1324 AuthRecord *rp;
1325
1326 a = AuthGroupForRecord(r, &rr->resrec);
1327 if (!a) return mDNSNULL;
1328 rp = a->members;
1329 while (rp)
1330 {
1331 if (!RecordIsLocalDuplicate(rp, rr))
1332 rp = rp->next;
1333 else
1334 {
1335 if (rp->resrec.RecordType == kDNSRecordTypeDeregistering)
1336 {
1337 rp->AnnounceCount = 0;
1338 rp = rp->next;
1339 }
1340 else return rp;
1341 }
1342 }
1343 return (mDNSNULL);
1344 }
1345
CheckAuthRecordConflict(AuthHash * r,AuthRecord * rr)1346 mDNSlocal mDNSBool CheckAuthRecordConflict(AuthHash *r, AuthRecord *rr)
1347 {
1348 const AuthGroup *a;
1349 const AuthRecord *rp;
1350
1351 a = AuthGroupForRecord(r, &rr->resrec);
1352 if (!a) return mDNSfalse;
1353 rp = a->members;
1354 while (rp)
1355 {
1356 const AuthRecord *s1 = rr->RRSet ? rr->RRSet : rr;
1357 const AuthRecord *s2 = rp->RRSet ? rp->RRSet : rp;
1358 if (s1 != s2 && SameResourceRecordSignature(rp, rr) && !IdenticalSameNameRecord(&rp->resrec, &rr->resrec))
1359 return mDNStrue;
1360 else
1361 rp = rp->next;
1362 }
1363 return (mDNSfalse);
1364 }
1365
1366 // checks to see if "rr" is already present
CheckAuthSameRecord(AuthHash * r,AuthRecord * rr)1367 mDNSlocal AuthRecord *CheckAuthSameRecord(AuthHash *r, AuthRecord *rr)
1368 {
1369 const AuthGroup *a;
1370 AuthRecord *rp;
1371
1372 a = AuthGroupForRecord(r, &rr->resrec);
1373 if (!a) return mDNSNULL;
1374 rp = a->members;
1375 while (rp)
1376 {
1377 if (rp != rr)
1378 rp = rp->next;
1379 else
1380 {
1381 return rp;
1382 }
1383 }
1384 return (mDNSNULL);
1385 }
1386
DecrementAutoTargetServices(mDNS * const m,AuthRecord * const rr)1387 mDNSlocal void DecrementAutoTargetServices(mDNS *const m, AuthRecord *const rr)
1388 {
1389 if (RRLocalOnly(rr))
1390 {
1391 // A sanity check, this should be prevented in calling code.
1392 LogInfo("DecrementAutoTargetServices: called for RRLocalOnly() record: %s", ARDisplayString(m, rr));
1393 return;
1394 }
1395
1396 if (!AuthRecord_uDNS(rr) && (rr->resrec.rrtype == kDNSType_SRV) && (rr->AutoTarget == Target_AutoHost))
1397 {
1398 NetworkInterfaceInfo *intf;
1399 #if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
1400 DeadvertiseFlags flags = 0; // DeadvertiseFlags for non-AWDL interfaces.
1401 DeadvertiseFlags flagsAWDL = 0; // DeadvertiseFlags for AWDL interfaces.
1402 if (AuthRecordIncludesOrIsAWDL(rr))
1403 {
1404 if (AuthRecordIncludesAWDL(rr))
1405 {
1406 m->AutoTargetAWDLIncludedCount--;
1407 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
1408 "DecrementAutoTargetServices: AutoTargetAWDLIncludedCount %u Record " PRI_S,
1409 m->AutoTargetAWDLIncludedCount, ARDisplayString(m, rr));
1410 if (m->AutoTargetAWDLIncludedCount == 0)
1411 {
1412 flags |= kDeadvertiseFlag_RandHostname;
1413 if (m->AutoTargetAWDLOnlyCount == 0) flagsAWDL |= kDeadvertiseFlag_RandHostname;
1414 }
1415 }
1416 else
1417 {
1418 m->AutoTargetAWDLOnlyCount--;
1419 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
1420 "DecrementAutoTargetServices: AutoTargetAWDLOnlyCount %u Record " PRI_S,
1421 m->AutoTargetAWDLOnlyCount, ARDisplayString(m, rr));
1422 if ((m->AutoTargetAWDLIncludedCount == 0) && (m->AutoTargetAWDLOnlyCount == 0))
1423 {
1424 flagsAWDL |= kDeadvertiseFlag_RandHostname;
1425 }
1426 }
1427 if (flags || flagsAWDL)
1428 {
1429 for (intf = m->HostInterfaces; intf; intf = intf->next)
1430 {
1431 if (!intf->Advertise) continue;
1432 if (mDNSPlatformInterfaceIsAWDL(intf->InterfaceID))
1433 {
1434 if (flagsAWDL) DeadvertiseInterface(m, intf, flagsAWDL);
1435 }
1436 else
1437 {
1438 if (flags) DeadvertiseInterface(m, intf, flags);
1439 }
1440 }
1441 }
1442 if ((m->AutoTargetAWDLIncludedCount == 0) && (m->AutoTargetAWDLOnlyCount == 0))
1443 {
1444 GetRandomUUIDLocalHostname(&m->RandomizedHostname);
1445 }
1446 }
1447 else
1448 #endif
1449 {
1450 m->AutoTargetServices--;
1451 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
1452 "DecrementAutoTargetServices: AutoTargetServices %u Record " PRI_S,
1453 m->AutoTargetServices, ARDisplayString(m, rr));
1454 if (m->AutoTargetServices == 0)
1455 {
1456 for (intf = m->HostInterfaces; intf; intf = intf->next)
1457 {
1458 if (intf->Advertise) DeadvertiseInterface(m, intf, kDeadvertiseFlag_NormalHostname);
1459 }
1460 }
1461 }
1462 }
1463
1464 #if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
1465 if (!AuthRecord_uDNS(rr))
1466 {
1467 if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1)
1468 m->NextBonjourDisableTime = NonZeroTime(m->timenow + (BONJOUR_DISABLE_DELAY * mDNSPlatformOneSecond));
1469 m->NumAllInterfaceRecords--;
1470 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
1471 "DecrementAutoTargetServices: NumAllInterfaceRecords %u NumAllInterfaceQuestions %u " PRI_S,
1472 m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, ARDisplayString(m, rr));
1473 }
1474 #endif
1475 }
1476
AdvertiseNecessaryInterfaceRecords(mDNS * const m)1477 mDNSlocal void AdvertiseNecessaryInterfaceRecords(mDNS *const m)
1478 {
1479 NetworkInterfaceInfo *intf;
1480 for (intf = m->HostInterfaces; intf; intf = intf->next)
1481 {
1482 if (intf->Advertise) AdvertiseInterfaceIfNeeded(m, intf);
1483 }
1484 }
1485
IncrementAutoTargetServices(mDNS * const m,AuthRecord * const rr)1486 mDNSlocal void IncrementAutoTargetServices(mDNS *const m, AuthRecord *const rr)
1487 {
1488 mDNSBool enablingBonjour = mDNSfalse;
1489
1490 if (RRLocalOnly(rr))
1491 {
1492 // A sanity check, this should be prevented in calling code.
1493 LogInfo("IncrementAutoTargetServices: called for RRLocalOnly() record: %s", ARDisplayString(m, rr));
1494 return;
1495 }
1496
1497 #if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
1498 if (!AuthRecord_uDNS(rr))
1499 {
1500 m->NumAllInterfaceRecords++;
1501 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
1502 "IncrementAutoTargetServices: NumAllInterfaceRecords %u NumAllInterfaceQuestions %u " PRI_S,
1503 m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, ARDisplayString(m, rr));
1504 if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1)
1505 {
1506 m->NextBonjourDisableTime = 0;
1507 if (m->BonjourEnabled == 0)
1508 {
1509 // Enable Bonjour immediately by scheduling network changed processing where
1510 // we will join the multicast group on each active interface.
1511 m->BonjourEnabled = 1;
1512 enablingBonjour = mDNStrue;
1513 m->NetworkChanged = m->timenow;
1514 }
1515 }
1516 }
1517 #endif
1518
1519 if (!AuthRecord_uDNS(rr) && (rr->resrec.rrtype == kDNSType_SRV) && (rr->AutoTarget == Target_AutoHost))
1520 {
1521 #if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
1522 if (AuthRecordIncludesAWDL(rr))
1523 {
1524 m->AutoTargetAWDLIncludedCount++;
1525 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
1526 "IncrementAutoTargetServices: AutoTargetAWDLIncludedCount %u Record " PRI_S,
1527 m->AutoTargetAWDLIncludedCount, ARDisplayString(m, rr));
1528 }
1529 else if (mDNSPlatformInterfaceIsAWDL(rr->resrec.InterfaceID))
1530 {
1531 m->AutoTargetAWDLOnlyCount++;
1532 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
1533 "IncrementAutoTargetServices: AutoTargetAWDLOnlyCount %u Record " PRI_S,
1534 m->AutoTargetAWDLOnlyCount, ARDisplayString(m, rr));
1535 }
1536 else
1537 #endif
1538 {
1539 m->AutoTargetServices++;
1540 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
1541 "IncrementAutoTargetServices: AutoTargetServices %u Record " PRI_S,
1542 m->AutoTargetServices, ARDisplayString(m, rr));
1543 }
1544 // If this is the first advertised service and we did not just enable Bonjour above, then
1545 // advertise all the interface records. If we did enable Bonjour above, the interface records will
1546 // be advertised during the network changed processing scheduled above, so no need
1547 // to do it here.
1548 if (!enablingBonjour) AdvertiseNecessaryInterfaceRecords(m);
1549 }
1550 }
1551
getKeepaliveRaddr(mDNS * const m,AuthRecord * rr,mDNSAddr * raddr)1552 mDNSlocal void getKeepaliveRaddr(mDNS *const m, AuthRecord *rr, mDNSAddr *raddr)
1553 {
1554 mDNSAddr laddr = zeroAddr;
1555 mDNSEthAddr eth = zeroEthAddr;
1556 mDNSIPPort lport = zeroIPPort;
1557 mDNSIPPort rport = zeroIPPort;
1558 mDNSu32 timeout = 0;
1559 mDNSu32 seq = 0;
1560 mDNSu32 ack = 0;
1561 mDNSu16 win = 0;
1562
1563 if (mDNS_KeepaliveRecord(&rr->resrec))
1564 {
1565 mDNS_ExtractKeepaliveInfo(rr, &timeout, &laddr, raddr, ð, &seq, &ack, &lport, &rport, &win);
1566 if (!timeout || mDNSAddressIsZero(&laddr) || mDNSAddressIsZero(raddr) || mDNSIPPortIsZero(lport) || mDNSIPPortIsZero(rport))
1567 {
1568 LogMsg("getKeepaliveRaddr: not a valid record %s for keepalive %#a:%d %#a:%d", ARDisplayString(m, rr), &laddr, lport.NotAnInteger, raddr, rport.NotAnInteger);
1569 return;
1570 }
1571 }
1572 }
1573
1574 // Exported so uDNS.c can call this
mDNS_Register_internal(mDNS * const m,AuthRecord * const rr)1575 mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
1576 {
1577 domainname *target = GetRRDomainNameTarget(&rr->resrec);
1578 AuthRecord *r;
1579 AuthRecord **p = &m->ResourceRecords;
1580 AuthRecord **d = &m->DuplicateRecords;
1581
1582 if ((mDNSs32)rr->resrec.rroriginalttl <= 0)
1583 { LogMsg("mDNS_Register_internal: TTL %X should be 1 - 0x7FFFFFFF %s", rr->resrec.rroriginalttl, ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
1584
1585 if (!rr->resrec.RecordType)
1586 { LogMsg("mDNS_Register_internal: RecordType must be non-zero %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
1587
1588 if (m->ShutdownTime)
1589 { LogMsg("mDNS_Register_internal: Shutting down, can't register %s", ARDisplayString(m, rr)); return(mStatus_ServiceNotRunning); }
1590
1591 if (m->DivertMulticastAdvertisements && !AuthRecord_uDNS(rr))
1592 {
1593 mDNSInterfaceID previousID = rr->resrec.InterfaceID;
1594 if (rr->resrec.InterfaceID == mDNSInterface_Any || rr->resrec.InterfaceID == mDNSInterface_P2P)
1595 {
1596 rr->resrec.InterfaceID = mDNSInterface_LocalOnly;
1597 rr->ARType = AuthRecordLocalOnly;
1598 }
1599 if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
1600 {
1601 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID);
1602 if (intf && !intf->Advertise) { rr->resrec.InterfaceID = mDNSInterface_LocalOnly; rr->ARType = AuthRecordLocalOnly; }
1603 }
1604 if (rr->resrec.InterfaceID != previousID)
1605 LogInfo("mDNS_Register_internal: Diverting record to local-only %s", ARDisplayString(m, rr));
1606 }
1607
1608 if (RRLocalOnly(rr))
1609 {
1610 if (CheckAuthSameRecord(&m->rrauth, rr))
1611 {
1612 LogMsg("mDNS_Register_internal: ERROR!! Tried to register LocalOnly AuthRecord %p %##s (%s) that's already in the list",
1613 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1614 return(mStatus_AlreadyRegistered);
1615 }
1616 }
1617 else
1618 {
1619 while (*p && *p != rr) p=&(*p)->next;
1620 if (*p)
1621 {
1622 LogMsg("mDNS_Register_internal: ERROR!! Tried to register AuthRecord %p %##s (%s) that's already in the list",
1623 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1624 return(mStatus_AlreadyRegistered);
1625 }
1626 }
1627
1628 while (*d && *d != rr) d=&(*d)->next;
1629 if (*d)
1630 {
1631 LogMsg("mDNS_Register_internal: ERROR!! Tried to register AuthRecord %p %##s (%s) that's already in the Duplicate list",
1632 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1633 return(mStatus_AlreadyRegistered);
1634 }
1635
1636 if (rr->DependentOn)
1637 {
1638 if (rr->resrec.RecordType == kDNSRecordTypeUnique)
1639 rr->resrec.RecordType = kDNSRecordTypeVerified;
1640 else if (rr->resrec.RecordType != kDNSRecordTypeKnownUnique)
1641 {
1642 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique or kDNSRecordTypeKnownUnique",
1643 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1644 return(mStatus_Invalid);
1645 }
1646 if (!(rr->DependentOn->resrec.RecordType & (kDNSRecordTypeUnique | kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique)))
1647 {
1648 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn->RecordType bad type %X",
1649 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->DependentOn->resrec.RecordType);
1650 return(mStatus_Invalid);
1651 }
1652 }
1653
1654 rr->next = mDNSNULL;
1655
1656 // Field Group 1: The actual information pertaining to this resource record
1657 // Set up by client prior to call
1658
1659 // Field Group 2: Persistent metadata for Authoritative Records
1660 // rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
1661 // rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
1662 // rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
1663 // rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
1664 // rr->Callback = already set in mDNS_SetupResourceRecord
1665 // rr->Context = already set in mDNS_SetupResourceRecord
1666 // rr->RecordType = already set in mDNS_SetupResourceRecord
1667 // rr->HostTarget = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
1668 // rr->AllowRemoteQuery = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
1669 // Make sure target is not uninitialized data, or we may crash writing debugging log messages
1670 if (rr->AutoTarget && target) target->c[0] = 0;
1671
1672 // Field Group 3: Transient state for Authoritative Records
1673 rr->Acknowledged = mDNSfalse;
1674 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType);
1675 rr->ProbeRestartCount = 0;
1676 rr->AnnounceCount = InitialAnnounceCount;
1677 rr->RequireGoodbye = mDNSfalse;
1678 rr->AnsweredLocalQ = mDNSfalse;
1679 rr->IncludeInProbe = mDNSfalse;
1680 rr->ImmedUnicast = mDNSfalse;
1681 rr->SendNSECNow = mDNSNULL;
1682 rr->ImmedAnswer = mDNSNULL;
1683 rr->ImmedAdditional = mDNSNULL;
1684 rr->SendRNow = mDNSNULL;
1685 rr->v4Requester = zerov4Addr;
1686 rr->v6Requester = zerov6Addr;
1687 rr->NextResponse = mDNSNULL;
1688 rr->NR_AnswerTo = mDNSNULL;
1689 rr->NR_AdditionalTo = mDNSNULL;
1690 if (!rr->AutoTarget) InitializeLastAPTime(m, rr);
1691 // rr->LastAPTime = Set for us in InitializeLastAPTime()
1692 // rr->LastMCTime = Set for us in InitializeLastAPTime()
1693 // rr->LastMCInterface = Set for us in InitializeLastAPTime()
1694 rr->NewRData = mDNSNULL;
1695 rr->newrdlength = 0;
1696 rr->UpdateCallback = mDNSNULL;
1697 rr->UpdateCredits = kMaxUpdateCredits;
1698 rr->NextUpdateCredit = 0;
1699 rr->UpdateBlocked = 0;
1700
1701 // For records we're holding as proxy (except reverse-mapping PTR records) two announcements is sufficient
1702 if (rr->WakeUp.HMAC.l[0] && !rr->AddressProxy.type) rr->AnnounceCount = 2;
1703
1704 // Field Group 4: Transient uDNS state for Authoritative Records
1705 rr->state = regState_Zero;
1706 rr->uselease = 0;
1707 rr->expire = 0;
1708 rr->Private = 0;
1709 rr->updateid = zeroID;
1710 rr->updateIntID = zeroOpaque64;
1711 rr->zone = rr->resrec.name;
1712 rr->nta = mDNSNULL;
1713 rr->tcp = mDNSNULL;
1714 rr->OrigRData = 0;
1715 rr->OrigRDLen = 0;
1716 rr->InFlightRData = 0;
1717 rr->InFlightRDLen = 0;
1718 rr->QueuedRData = 0;
1719 rr->QueuedRDLen = 0;
1720 //mDNSPlatformMemZero(&rr->NATinfo, sizeof(rr->NATinfo));
1721 // We should be recording the actual internal port for this service record here. Once we initiate our NAT mapping
1722 // request we'll subsequently overwrite srv.port with the allocated external NAT port -- potentially multiple
1723 // times with different values if the external NAT port changes during the lifetime of the service registration.
1724 //if (rr->resrec.rrtype == kDNSType_SRV) rr->NATinfo.IntPort = rr->resrec.rdata->u.srv.port;
1725
1726 // rr->resrec.interface = already set in mDNS_SetupResourceRecord
1727 // rr->resrec.name->c = MUST be set by client
1728 // rr->resrec.rrtype = already set in mDNS_SetupResourceRecord
1729 // rr->resrec.rrclass = already set in mDNS_SetupResourceRecord
1730 // rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord
1731 // rr->resrec.rdata = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set
1732
1733 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
1734 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
1735 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
1736 if (rr->resrec.rrtype == kDNSType_TXT && rr->resrec.rdlength == 0) { rr->resrec.rdlength = 1; rr->resrec.rdata->u.txt.c[0] = 0; }
1737
1738 if (rr->AutoTarget)
1739 {
1740 SetTargetToHostName(m, rr); // Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime();
1741 #ifndef UNICAST_DISABLED
1742 // If we have no target record yet, SetTargetToHostName will set rr->state == regState_NoTarget
1743 // In this case we leave the record half-formed in the list, and later we'll remove it from the list and re-add it properly.
1744 if (rr->state == regState_NoTarget)
1745 {
1746 // Initialize the target so that we don't crash while logging etc.
1747 domainname *tar = GetRRDomainNameTarget(&rr->resrec);
1748 if (tar) tar->c[0] = 0;
1749 LogInfo("mDNS_Register_internal: record %s in NoTarget state", ARDisplayString(m, rr));
1750 }
1751 #endif
1752 }
1753 else
1754 {
1755 rr->resrec.rdlength = GetRDLength(&rr->resrec, mDNSfalse);
1756 rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue);
1757 }
1758
1759 if (!ValidateDomainName(rr->resrec.name))
1760 { LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
1761
1762 // Don't do this until *after* we've set rr->resrec.rdlength
1763 if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata))
1764 { LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
1765
1766 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
1767 rr->resrec.rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(&rr->resrec);
1768
1769 if (RRLocalOnly(rr))
1770 {
1771 // If this is supposed to be unique, make sure we don't have any name conflicts.
1772 // If we found a conflict, we may still want to insert the record in the list but mark it appropriately
1773 // (kDNSRecordTypeDeregistering) so that we deliver RMV events to the application. But this causes more
1774 // complications and not clear whether there are any benefits. See rdar:9304275 for details.
1775 // Hence, just bail out.
1776 // This comment is doesn’t make any sense. -- SC
1777 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
1778 {
1779 if (CheckAuthRecordConflict(&m->rrauth, rr))
1780 {
1781 LogInfo("mDNS_Register_internal: Name conflict %s (%p), InterfaceID %p", ARDisplayString(m, rr), rr, rr->resrec.InterfaceID);
1782 return mStatus_NameConflict;
1783 }
1784 }
1785 }
1786
1787 // For uDNS records, we don't support duplicate checks at this time.
1788 #ifndef UNICAST_DISABLED
1789 if (AuthRecord_uDNS(rr))
1790 {
1791 if (!m->NewLocalRecords) m->NewLocalRecords = rr;
1792 // When we called SetTargetToHostName, it may have caused mDNS_Register_internal to be re-entered, appending new
1793 // records to the list, so we now need to update p to advance to the new end to the list before appending our new record.
1794 while (*p) p=&(*p)->next;
1795 *p = rr;
1796 if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified;
1797 rr->ProbeCount = 0;
1798 rr->ProbeRestartCount = 0;
1799 rr->AnnounceCount = 0;
1800 if (rr->state != regState_NoTarget) ActivateUnicastRegistration(m, rr);
1801 return(mStatus_NoError); // <--- Note: For unicast records, code currently bails out at this point
1802 }
1803 #endif
1804
1805 // Now that we've finished building our new record, make sure it's not identical to one we already have
1806 if (RRLocalOnly(rr))
1807 {
1808 rr->ProbeCount = 0;
1809 rr->ProbeRestartCount = 0;
1810 rr->AnnounceCount = 0;
1811 r = CheckAuthIdenticalRecord(&m->rrauth, rr);
1812 }
1813 else
1814 {
1815 for (r = m->ResourceRecords; r; r=r->next)
1816 if (RecordIsLocalDuplicate(r, rr))
1817 {
1818 if (r->resrec.RecordType == kDNSRecordTypeDeregistering) r->AnnounceCount = 0;
1819 else break;
1820 }
1821 }
1822
1823 if (r)
1824 {
1825 LogInfo("mDNS_Register_internal: Adding to duplicate list %s", ARDisplayString(m,rr));
1826 *d = rr;
1827 // If the previous copy of this record is already verified unique,
1828 // then indicate that we should move this record promptly to kDNSRecordTypeUnique state.
1829 // Setting ProbeCount to zero will cause SendQueries() to advance this record to
1830 // kDNSRecordTypeVerified state and call the client callback at the next appropriate time.
1831 if (rr->resrec.RecordType == kDNSRecordTypeUnique && r->resrec.RecordType == kDNSRecordTypeVerified)
1832 rr->ProbeCount = 0;
1833 }
1834 else
1835 {
1836 LogInfo("mDNS_Register_internal: Adding to active record list %s", ARDisplayString(m,rr));
1837 if (RRLocalOnly(rr))
1838 {
1839 AuthGroup *ag;
1840 ag = InsertAuthRecord(m, &m->rrauth, rr);
1841 if (ag && !ag->NewLocalOnlyRecords)
1842 {
1843 m->NewLocalOnlyRecords = mDNStrue;
1844 ag->NewLocalOnlyRecords = rr;
1845 }
1846 // No probing for LocalOnly records; acknowledge them right away
1847 if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified;
1848 AcknowledgeRecord(m, rr);
1849 return(mStatus_NoError);
1850 }
1851 else
1852 {
1853 if (!m->NewLocalRecords) m->NewLocalRecords = rr;
1854 *p = rr;
1855 }
1856 }
1857
1858 if (!AuthRecord_uDNS(rr)) // This check is superfluous, given that for unicast records we (currently) bail out above
1859 {
1860 // We have inserted the record in the list. See if we have to advertise the A/AAAA, HINFO, PTR records.
1861 IncrementAutoTargetServices(m, rr);
1862
1863 // For records that are not going to probe, acknowledge them right away
1864 if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering)
1865 AcknowledgeRecord(m, rr);
1866
1867 // Adding a record may affect whether or not we should sleep
1868 mDNS_UpdateAllowSleep(m);
1869 }
1870
1871 // If this is a non-sleep proxy keepalive record, fetch the MAC address of the remote host.
1872 // This is used by the in-NIC proxy to send the keepalive packets.
1873 if (!rr->WakeUp.HMAC.l[0] && mDNS_KeepaliveRecord(&rr->resrec))
1874 {
1875 mDNSAddr raddr;
1876 // Set the record type to known unique to prevent probing keep alive records.
1877 // Also make sure we do not announce the keepalive records.
1878 rr->resrec.RecordType = kDNSRecordTypeKnownUnique;
1879 rr->AnnounceCount = 0;
1880 getKeepaliveRaddr(m, rr, &raddr);
1881 // This is an asynchronous call. Once the remote MAC address is available, helper will schedule an
1882 // asynchronous task to update the resource record
1883 mDNSPlatformGetRemoteMacAddr(&raddr);
1884 }
1885
1886 return(mStatus_NoError);
1887 }
1888
RecordProbeFailure(mDNS * const m,const AuthRecord * const rr)1889 mDNSlocal void RecordProbeFailure(mDNS *const m, const AuthRecord *const rr)
1890 {
1891 m->ProbeFailTime = m->timenow;
1892 m->NumFailedProbes++;
1893 // If we've had fifteen or more probe failures, rate-limit to one every five seconds.
1894 // If a bunch of hosts have all been configured with the same name, then they'll all
1895 // conflict and run through the same series of names: name-2, name-3, name-4, etc.,
1896 // up to name-10. After that they'll start adding random increments in the range 1-100,
1897 // so they're more likely to branch out in the available namespace and settle on a set of
1898 // unique names quickly. If after five more tries the host is still conflicting, then we
1899 // may have a serious problem, so we start rate-limiting so we don't melt down the network.
1900 if (m->NumFailedProbes >= 15)
1901 {
1902 m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5);
1903 LogMsg("Excessive name conflicts (%lu) for %##s (%s); rate limiting in effect",
1904 m->NumFailedProbes, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1905 }
1906 }
1907
CompleteRDataUpdate(mDNS * const m,AuthRecord * const rr)1908 mDNSlocal void CompleteRDataUpdate(mDNS *const m, AuthRecord *const rr)
1909 {
1910 RData *OldRData = rr->resrec.rdata;
1911 mDNSu16 OldRDLen = rr->resrec.rdlength;
1912 SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength); // Update our rdata
1913 rr->NewRData = mDNSNULL; // Clear the NewRData pointer ...
1914 if (rr->UpdateCallback)
1915 rr->UpdateCallback(m, rr, OldRData, OldRDLen); // ... and let the client know
1916 }
1917
1918 // Note: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list.
1919 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
1920 // Exported so uDNS.c can call this
mDNS_Deregister_internal(mDNS * const m,AuthRecord * const rr,mDNS_Dereg_type drt)1921 mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt)
1922 {
1923 AuthRecord *r2;
1924 mDNSu8 RecordType = rr->resrec.RecordType;
1925 AuthRecord **p = &m->ResourceRecords; // Find this record in our list of active records
1926 mDNSBool dupList = mDNSfalse;
1927
1928 if (RRLocalOnly(rr))
1929 {
1930 AuthGroup *a;
1931 AuthRecord **rp;
1932
1933 a = AuthGroupForRecord(&m->rrauth, &rr->resrec);
1934 if (!a) return mDNSfalse;
1935 rp = &a->members;
1936 while (*rp && *rp != rr) rp=&(*rp)->next;
1937 p = rp;
1938 }
1939 else
1940 {
1941 while (*p && *p != rr) p=&(*p)->next;
1942 }
1943
1944 if (*p)
1945 {
1946 // We found our record on the main list. See if there are any duplicates that need special handling.
1947 if (drt == mDNS_Dereg_conflict) // If this was a conflict, see that all duplicates get the same treatment
1948 {
1949 // Scan for duplicates of rr, and mark them for deregistration at the end of this routine, after we've finished
1950 // deregistering rr. We need to do this scan *before* we give the client the chance to free and reuse the rr memory.
1951 for (r2 = m->DuplicateRecords; r2; r2=r2->next) if (RecordIsLocalDuplicate(r2, rr)) r2->ProbeCount = 0xFF;
1952 }
1953 else
1954 {
1955 // Before we delete the record (and potentially send a goodbye packet)
1956 // first see if we have a record on the duplicate list ready to take over from it.
1957 AuthRecord **d = &m->DuplicateRecords;
1958 while (*d && !RecordIsLocalDuplicate(*d, rr)) d=&(*d)->next;
1959 if (*d)
1960 {
1961 AuthRecord *dup = *d;
1962 debugf("mDNS_Register_internal: Duplicate record %p taking over from %p %##s (%s)",
1963 dup, rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1964 *d = dup->next; // Cut replacement record from DuplicateRecords list
1965 if (RRLocalOnly(rr))
1966 {
1967 dup->next = mDNSNULL;
1968 if (!InsertAuthRecord(m, &m->rrauth, dup)) LogMsg("mDNS_Deregister_internal: ERROR!! cannot insert %s", ARDisplayString(m, dup));
1969 }
1970 else
1971 {
1972 dup->next = rr->next; // And then...
1973 rr->next = dup; // ... splice it in right after the record we're about to delete
1974 }
1975 dup->resrec.RecordType = rr->resrec.RecordType;
1976 dup->ProbeCount = rr->ProbeCount;
1977 dup->ProbeRestartCount = rr->ProbeRestartCount;
1978 dup->AnnounceCount = rr->AnnounceCount;
1979 dup->RequireGoodbye = rr->RequireGoodbye;
1980 dup->AnsweredLocalQ = rr->AnsweredLocalQ;
1981 dup->ImmedAnswer = rr->ImmedAnswer;
1982 dup->ImmedUnicast = rr->ImmedUnicast;
1983 dup->ImmedAdditional = rr->ImmedAdditional;
1984 dup->v4Requester = rr->v4Requester;
1985 dup->v6Requester = rr->v6Requester;
1986 dup->ThisAPInterval = rr->ThisAPInterval;
1987 dup->LastAPTime = rr->LastAPTime;
1988 dup->LastMCTime = rr->LastMCTime;
1989 dup->LastMCInterface = rr->LastMCInterface;
1990 dup->Private = rr->Private;
1991 dup->state = rr->state;
1992 rr->RequireGoodbye = mDNSfalse;
1993 rr->AnsweredLocalQ = mDNSfalse;
1994 }
1995 }
1996 }
1997 else
1998 {
1999 // We didn't find our record on the main list; try the DuplicateRecords list instead.
2000 p = &m->DuplicateRecords;
2001 while (*p && *p != rr) p=&(*p)->next;
2002 // If we found our record on the duplicate list, then make sure we don't send a goodbye for it
2003 if (*p)
2004 {
2005 // Duplicate records are not used for sending wakeups or goodbyes. Hence, deregister them
2006 // immediately. When there is a conflict, we deregister all the conflicting duplicate records
2007 // also that have been marked above in this function. In that case, we come here and if we don't
2008 // deregister (unilink from the DuplicateRecords list), we will be recursing infinitely. Hence,
2009 // clear the HMAC which will cause it to deregister. See <rdar://problem/10380988> for
2010 // details.
2011 rr->WakeUp.HMAC = zeroEthAddr;
2012 rr->RequireGoodbye = mDNSfalse;
2013 rr->resrec.RecordType = kDNSRecordTypeDeregistering;
2014 dupList = mDNStrue;
2015 }
2016 if (*p) debugf("mDNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)",
2017 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2018 }
2019
2020 if (!*p)
2021 {
2022 // No need to log an error message if we already know this is a potentially repeated deregistration
2023 if (drt != mDNS_Dereg_repeat)
2024 LogMsg("mDNS_Deregister_internal: Record %p not found in list %s", rr, ARDisplayString(m,rr));
2025 return(mStatus_BadReferenceErr);
2026 }
2027
2028 // If this is a shared record and we've announced it at least once,
2029 // we need to retract that announcement before we delete the record
2030
2031 // If this is a record (including mDNSInterface_LocalOnly records) for which we've given local-only answers then
2032 // it's tempting to just do "AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, QC_rmv)" here, but that would not not be safe.
2033 // The AnswerAllLocalQuestionsWithLocalAuthRecord routine walks the question list invoking client callbacks, using the "m->CurrentQuestion"
2034 // mechanism to cope with the client callback modifying the question list while that's happening.
2035 // However, mDNS_Deregister could have been called from a client callback (e.g. from the domain enumeration callback FoundDomain)
2036 // which means that the "m->CurrentQuestion" mechanism is already in use to protect that list, so we can't use it twice.
2037 // More generally, if we invoke callbacks from within a client callback, then those callbacks could deregister other
2038 // records, thereby invoking yet more callbacks, without limit.
2039 // The solution is to defer delivering the "Remove" events until mDNS_Execute time, just like we do for sending
2040 // actual goodbye packets.
2041
2042 #ifndef UNICAST_DISABLED
2043 if (AuthRecord_uDNS(rr))
2044 {
2045 if (rr->RequireGoodbye)
2046 {
2047 if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
2048 rr->resrec.RecordType = kDNSRecordTypeDeregistering;
2049 m->LocalRemoveEvents = mDNStrue;
2050 uDNS_DeregisterRecord(m, rr);
2051 // At this point unconditionally we bail out
2052 // Either uDNS_DeregisterRecord will have completed synchronously, and called CompleteDeregistration,
2053 // which calls us back here with RequireGoodbye set to false, or it will have initiated the deregistration
2054 // process and will complete asynchronously. Either way we don't need to do anything more here.
2055 return(mStatus_NoError);
2056 }
2057 // Sometimes the records don't complete proper deregistration i.e., don't wait for a response
2058 // from the server. In that case, if the records have been part of a group update, clear the
2059 // state here.
2060 rr->updateid = zeroID;
2061
2062 // We defer cleaning up NAT state only after sending goodbyes. This is important because
2063 // RecordRegistrationGotZoneData guards against creating NAT state if clientContext is non-NULL.
2064 // This happens today when we turn on/off interface where we get multiple network transitions
2065 // and RestartRecordGetZoneData triggers re-registration of the resource records even though
2066 // they may be in Registered state which causes NAT information to be setup multiple times. Defering
2067 // the cleanup here keeps clientContext non-NULL and hence prevents that. Note that cleaning up
2068 // NAT state here takes care of the case where we did not send goodbyes at all.
2069 if (rr->NATinfo.clientContext)
2070 {
2071 mDNS_StopNATOperation_internal(m, &rr->NATinfo);
2072 rr->NATinfo.clientContext = mDNSNULL;
2073 }
2074 if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; }
2075 if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
2076 }
2077 #endif // UNICAST_DISABLED
2078
2079 if (RecordType == kDNSRecordTypeUnregistered)
2080 LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeUnregistered", ARDisplayString(m, rr));
2081 else if (RecordType == kDNSRecordTypeDeregistering)
2082 {
2083 LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeDeregistering", ARDisplayString(m, rr));
2084 return(mStatus_BadReferenceErr);
2085 }
2086
2087 if (rr->WakeUp.HMAC.l[0] ||
2088 (((RecordType == kDNSRecordTypeShared) || (rr->ARType == AuthRecordLocalOnly)) &&
2089 (rr->RequireGoodbye || rr->AnsweredLocalQ)))
2090 {
2091 verbosedebugf("mDNS_Deregister_internal: Starting deregistration for %s", ARDisplayString(m, rr));
2092 rr->resrec.RecordType = kDNSRecordTypeDeregistering;
2093 rr->resrec.rroriginalttl = 0;
2094 rr->AnnounceCount = rr->WakeUp.HMAC.l[0] ? WakeupCount : (drt == mDNS_Dereg_rapid) ? 1 : GoodbyeCount;
2095 rr->ThisAPInterval = mDNSPlatformOneSecond * 2;
2096 rr->LastAPTime = m->timenow - rr->ThisAPInterval;
2097 m->LocalRemoveEvents = mDNStrue;
2098 if (m->NextScheduledResponse - (m->timenow + mDNSPlatformOneSecond/10) >= 0)
2099 m->NextScheduledResponse = (m->timenow + mDNSPlatformOneSecond/10);
2100 }
2101 else
2102 {
2103 if (!dupList && RRLocalOnly(rr))
2104 {
2105 AuthGroup *ag = RemoveAuthRecord(m, &m->rrauth, rr);
2106 if (ag->NewLocalOnlyRecords == rr) ag->NewLocalOnlyRecords = rr->next;
2107 }
2108 else
2109 {
2110 *p = rr->next; // Cut this record from the list
2111 if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next;
2112 DecrementAutoTargetServices(m, rr);
2113 }
2114 // If someone is about to look at this, bump the pointer forward
2115 if (m->CurrentRecord == rr) m->CurrentRecord = rr->next;
2116 rr->next = mDNSNULL;
2117
2118 verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m, rr));
2119 rr->resrec.RecordType = kDNSRecordTypeUnregistered;
2120
2121 if ((drt == mDNS_Dereg_conflict || drt == mDNS_Dereg_repeat) && RecordType == kDNSRecordTypeShared)
2122 debugf("mDNS_Deregister_internal: Cannot have a conflict on a shared record! %##s (%s)",
2123 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2124
2125 // If we have an update queued up which never executed, give the client a chance to free that memory
2126 if (rr->NewRData) CompleteRDataUpdate(m, rr); // Update our rdata, clear the NewRData pointer, and return memory to the client
2127
2128
2129 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
2130 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
2131 // In this case the likely client action to the mStatus_MemFree message is to free the memory,
2132 // so any attempt to touch rr after this is likely to lead to a crash.
2133 if (drt != mDNS_Dereg_conflict)
2134 {
2135 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
2136 LogInfo("mDNS_Deregister_internal: callback with mStatus_MemFree for %s", ARDisplayString(m, rr));
2137 if (rr->RecordCallback)
2138 rr->RecordCallback(m, rr, mStatus_MemFree); // MUST NOT touch rr after this
2139 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
2140 }
2141 else
2142 {
2143 RecordProbeFailure(m, rr);
2144 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
2145 if (rr->RecordCallback)
2146 rr->RecordCallback(m, rr, mStatus_NameConflict); // MUST NOT touch rr after this
2147 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
2148 // Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously.
2149 // Note that with all the client callbacks going on, by the time we get here all the
2150 // records we marked may have been explicitly deregistered by the client anyway.
2151 r2 = m->DuplicateRecords;
2152 while (r2)
2153 {
2154 if (r2->ProbeCount != 0xFF)
2155 {
2156 r2 = r2->next;
2157 }
2158 else
2159 {
2160 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
2161 // See if this record was also registered with any D2D plugins.
2162 D2D_stop_advertising_record(r2);
2163 #endif
2164 mDNS_Deregister_internal(m, r2, mDNS_Dereg_conflict);
2165 // As this is a duplicate record, it will be unlinked from the list
2166 // immediately
2167 r2 = m->DuplicateRecords;
2168 }
2169 }
2170 }
2171 }
2172 mDNS_UpdateAllowSleep(m);
2173 return(mStatus_NoError);
2174 }
2175
2176 // ***************************************************************************
2177 #if COMPILER_LIKES_PRAGMA_MARK
2178 #pragma mark -
2179 #pragma mark - Packet Sending Functions
2180 #endif
2181
AddRecordToResponseList(AuthRecord *** nrpp,AuthRecord * rr,AuthRecord * add)2182 mDNSlocal void AddRecordToResponseList(AuthRecord ***nrpp, AuthRecord *rr, AuthRecord *add)
2183 {
2184 if (rr->NextResponse == mDNSNULL && *nrpp != &rr->NextResponse)
2185 {
2186 **nrpp = rr;
2187 // NR_AdditionalTo must point to a record with NR_AnswerTo set (and not NR_AdditionalTo)
2188 // If 'add' does not meet this requirement, then follow its NR_AdditionalTo pointer to a record that does
2189 // The referenced record will definitely be acceptable (by recursive application of this rule)
2190 if (add && add->NR_AdditionalTo) add = add->NR_AdditionalTo;
2191 rr->NR_AdditionalTo = add;
2192 *nrpp = &rr->NextResponse;
2193 }
2194 debugf("AddRecordToResponseList: %##s (%s) already in list", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2195 }
2196
AddRRSetAdditionalsToResponseList(mDNS * const m,AuthRecord *** nrpp,AuthRecord * rr,AuthRecord * additional,const mDNSInterfaceID InterfaceID)2197 mDNSlocal void AddRRSetAdditionalsToResponseList(mDNS *const m, AuthRecord ***nrpp, AuthRecord *rr, AuthRecord *additional, const mDNSInterfaceID InterfaceID)
2198 {
2199 AuthRecord *rr2;
2200 if (additional->resrec.RecordType & kDNSRecordTypeUniqueMask)
2201 {
2202 for (rr2 = m->ResourceRecords; rr2; rr2 = rr2->next)
2203 {
2204 if ((rr2->resrec.namehash == additional->resrec.namehash) &&
2205 (rr2->resrec.rrtype == additional->resrec.rrtype) &&
2206 (rr2 != additional) &&
2207 (rr2->resrec.RecordType & kDNSRecordTypeUniqueMask) &&
2208 (rr2->resrec.rrclass == additional->resrec.rrclass) &&
2209 ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) &&
2210 SameDomainName(rr2->resrec.name, additional->resrec.name))
2211 {
2212 AddRecordToResponseList(nrpp, rr2, rr);
2213 }
2214 }
2215 }
2216 }
2217
AddAdditionalsToResponseList(mDNS * const m,AuthRecord * ResponseRecords,AuthRecord *** nrpp,const mDNSInterfaceID InterfaceID)2218 mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseRecords, AuthRecord ***nrpp, const mDNSInterfaceID InterfaceID)
2219 {
2220 AuthRecord *rr, *rr2;
2221 for (rr=ResponseRecords; rr; rr=rr->NextResponse) // For each record we plan to put
2222 {
2223 // (Note: This is an "if", not a "while". If we add a record, we'll find it again
2224 // later in the "for" loop, and we will follow further "additional" links then.)
2225 if (rr->Additional1 && ResourceRecordIsValidInterfaceAnswer(rr->Additional1, InterfaceID))
2226 {
2227 AddRecordToResponseList(nrpp, rr->Additional1, rr);
2228 AddRRSetAdditionalsToResponseList(m, nrpp, rr, rr->Additional1, InterfaceID);
2229 }
2230
2231 if (rr->Additional2 && ResourceRecordIsValidInterfaceAnswer(rr->Additional2, InterfaceID))
2232 {
2233 AddRecordToResponseList(nrpp, rr->Additional2, rr);
2234 AddRRSetAdditionalsToResponseList(m, nrpp, rr, rr->Additional2, InterfaceID);
2235 }
2236
2237 // For SRV records, automatically add the Address record(s) for the target host
2238 if (rr->resrec.rrtype == kDNSType_SRV)
2239 {
2240 for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records
2241 if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ...
2242 ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ...
2243 rr->resrec.rdatahash == rr2->resrec.namehash && // ... whose name is the name of the SRV target
2244 SameDomainName(&rr->resrec.rdata->u.srv.target, rr2->resrec.name))
2245 AddRecordToResponseList(nrpp, rr2, rr);
2246 }
2247 else if (RRTypeIsAddressType(rr->resrec.rrtype)) // For A or AAAA, put counterpart as additional
2248 {
2249 for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records
2250 if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ...
2251 ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ...
2252 rr->resrec.namehash == rr2->resrec.namehash && // ... and have the same name
2253 SameDomainName(rr->resrec.name, rr2->resrec.name))
2254 AddRecordToResponseList(nrpp, rr2, rr);
2255 }
2256 else if (rr->resrec.rrtype == kDNSType_PTR) // For service PTR, see if we want to add DeviceInfo record
2257 {
2258 if (ResourceRecordIsValidInterfaceAnswer(&m->DeviceInfo, InterfaceID) &&
2259 SameDomainLabel(rr->resrec.rdata->u.name.c, m->DeviceInfo.resrec.name->c))
2260 AddRecordToResponseList(nrpp, &m->DeviceInfo, rr);
2261 }
2262 }
2263 }
2264
SendDelayedUnicastResponse(mDNS * const m,const mDNSAddr * const dest,const mDNSInterfaceID InterfaceID)2265 mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const dest, const mDNSInterfaceID InterfaceID)
2266 {
2267 AuthRecord *rr;
2268 AuthRecord *ResponseRecords = mDNSNULL;
2269 AuthRecord **nrp = &ResponseRecords;
2270 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
2271
2272 // Make a list of all our records that need to be unicast to this destination
2273 for (rr = m->ResourceRecords; rr; rr=rr->next)
2274 {
2275 // If we find we can no longer unicast this answer, clear ImmedUnicast
2276 if (rr->ImmedAnswer == mDNSInterfaceMark ||
2277 mDNSSameIPv4Address(rr->v4Requester, onesIPv4Addr) ||
2278 mDNSSameIPv6Address(rr->v6Requester, onesIPv6Addr) )
2279 rr->ImmedUnicast = mDNSfalse;
2280
2281 if (rr->ImmedUnicast && rr->ImmedAnswer == InterfaceID)
2282 {
2283 if ((dest->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->v4Requester, dest->ip.v4)) ||
2284 (dest->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address(rr->v6Requester, dest->ip.v6)))
2285 {
2286 rr->ImmedAnswer = mDNSNULL; // Clear the state fields
2287 rr->ImmedUnicast = mDNSfalse;
2288 rr->v4Requester = zerov4Addr;
2289 rr->v6Requester = zerov6Addr;
2290
2291 // Only sent records registered for P2P over P2P interfaces
2292 if (intf && !mDNSPlatformValidRecordForInterface(rr, intf->InterfaceID))
2293 {
2294 continue;
2295 }
2296
2297 if (rr->NextResponse == mDNSNULL && nrp != &rr->NextResponse) // rr->NR_AnswerTo
2298 {
2299 rr->NR_AnswerTo = NR_AnswerMulticast;
2300 *nrp = rr;
2301 nrp = &rr->NextResponse;
2302 }
2303 }
2304 }
2305 }
2306
2307 AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID);
2308
2309 while (ResponseRecords)
2310 {
2311 mDNSu8 *responseptr = m->omsg.data;
2312 mDNSu8 *newptr;
2313 InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags);
2314
2315 // Put answers in the packet
2316 while (ResponseRecords && ResponseRecords->NR_AnswerTo)
2317 {
2318 rr = ResponseRecords;
2319 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2320 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
2321
2322 newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec);
2323
2324 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
2325 if (!newptr && m->omsg.h.numAnswers)
2326 {
2327 break; // If packet full, send it now
2328 }
2329 if (newptr) responseptr = newptr;
2330 ResponseRecords = rr->NextResponse;
2331 rr->NextResponse = mDNSNULL;
2332 rr->NR_AnswerTo = mDNSNULL;
2333 rr->NR_AdditionalTo = mDNSNULL;
2334 rr->RequireGoodbye = mDNStrue;
2335 }
2336
2337 // Add additionals, if there's space
2338 while (ResponseRecords && !ResponseRecords->NR_AnswerTo)
2339 {
2340 rr = ResponseRecords;
2341 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2342 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
2343 newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &rr->resrec);
2344 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
2345
2346 if (newptr) responseptr = newptr;
2347 if (newptr && m->omsg.h.numAnswers) rr->RequireGoodbye = mDNStrue;
2348 else if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) rr->ImmedAnswer = mDNSInterfaceMark;
2349 ResponseRecords = rr->NextResponse;
2350 rr->NextResponse = mDNSNULL;
2351 rr->NR_AnswerTo = mDNSNULL;
2352 rr->NR_AdditionalTo = mDNSNULL;
2353 }
2354
2355 if (m->omsg.h.numAnswers)
2356 mDNSSendDNSMessage(m, &m->omsg, responseptr, InterfaceID, mDNSNULL, mDNSNULL, dest, MulticastDNSPort, mDNSNULL, mDNSfalse);
2357 }
2358 }
2359
2360 // CompleteDeregistration guarantees that on exit the record will have been cut from the m->ResourceRecords list
2361 // and the client's mStatus_MemFree callback will have been invoked
CompleteDeregistration(mDNS * const m,AuthRecord * rr)2362 mDNSexport void CompleteDeregistration(mDNS *const m, AuthRecord *rr)
2363 {
2364 LogInfo("CompleteDeregistration: called for Resource record %s", ARDisplayString(m, rr));
2365 // Clearing rr->RequireGoodbye signals mDNS_Deregister_internal() that
2366 // it should go ahead and immediately dispose of this registration
2367 rr->resrec.RecordType = kDNSRecordTypeShared;
2368 rr->RequireGoodbye = mDNSfalse;
2369 rr->WakeUp.HMAC = zeroEthAddr;
2370 if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, QC_rmv); rr->AnsweredLocalQ = mDNSfalse; }
2371 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); // Don't touch rr after this
2372 }
2373
2374 // DiscardDeregistrations is used on shutdown and sleep to discard (forcibly and immediately)
2375 // any deregistering records that remain in the m->ResourceRecords list.
2376 // DiscardDeregistrations calls mDNS_Deregister_internal which can call a user callback,
2377 // which may change the record list and/or question list.
2378 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
DiscardDeregistrations(mDNS * const m)2379 mDNSlocal void DiscardDeregistrations(mDNS *const m)
2380 {
2381 if (m->CurrentRecord)
2382 LogMsg("DiscardDeregistrations ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
2383 m->CurrentRecord = m->ResourceRecords;
2384
2385 while (m->CurrentRecord)
2386 {
2387 AuthRecord *rr = m->CurrentRecord;
2388 if (!AuthRecord_uDNS(rr) && rr->resrec.RecordType == kDNSRecordTypeDeregistering)
2389 CompleteDeregistration(m, rr); // Don't touch rr after this
2390 else
2391 m->CurrentRecord = rr->next;
2392 }
2393 }
2394
GetLabelDecimalValue(const mDNSu8 * const src,mDNSu8 * dst)2395 mDNSlocal mStatus GetLabelDecimalValue(const mDNSu8 *const src, mDNSu8 *dst)
2396 {
2397 int i, val = 0;
2398 if (src[0] < 1 || src[0] > 3) return(mStatus_Invalid);
2399 for (i=1; i<=src[0]; i++)
2400 {
2401 if (src[i] < '0' || src[i] > '9') return(mStatus_Invalid);
2402 val = val * 10 + src[i] - '0';
2403 }
2404 if (val > 255) return(mStatus_Invalid);
2405 *dst = (mDNSu8)val;
2406 return(mStatus_NoError);
2407 }
2408
GetIPv4FromName(mDNSAddr * const a,const domainname * const name)2409 mDNSlocal mStatus GetIPv4FromName(mDNSAddr *const a, const domainname *const name)
2410 {
2411 int skip = CountLabels(name) - 6;
2412 if (skip < 0) { LogMsg("GetIPFromName: Need six labels in IPv4 reverse mapping name %##s", name); return mStatus_Invalid; }
2413 if (GetLabelDecimalValue(SkipLeadingLabels(name, skip+3)->c, &a->ip.v4.b[0]) ||
2414 GetLabelDecimalValue(SkipLeadingLabels(name, skip+2)->c, &a->ip.v4.b[1]) ||
2415 GetLabelDecimalValue(SkipLeadingLabels(name, skip+1)->c, &a->ip.v4.b[2]) ||
2416 GetLabelDecimalValue(SkipLeadingLabels(name, skip+0)->c, &a->ip.v4.b[3])) return mStatus_Invalid;
2417 a->type = mDNSAddrType_IPv4;
2418 return(mStatus_NoError);
2419 }
2420
2421 #define HexVal(X) ( ((X) >= '0' && (X) <= '9') ? ((X) - '0' ) : \
2422 ((X) >= 'A' && (X) <= 'F') ? ((X) - 'A' + 10) : \
2423 ((X) >= 'a' && (X) <= 'f') ? ((X) - 'a' + 10) : -1)
2424
GetIPv6FromName(mDNSAddr * const a,const domainname * const name)2425 mDNSlocal mStatus GetIPv6FromName(mDNSAddr *const a, const domainname *const name)
2426 {
2427 int i, h, l;
2428 const domainname *n;
2429