1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2012 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include "mDNSEmbeddedAPI.h"
19 #include "CryptoAlg.h"
20 #include "anonymous.h"
21 #include "DNSCommon.h"
22
23 // Define ANONYMOUS_DISABLED to remove all the anonymous functionality
24 // and use the stub functions implemented later in this file.
25
26 #ifndef ANONYMOUS_DISABLED
27
28 #define ANON_NSEC3_ITERATIONS 1
29
InitializeNSEC3Record(ResourceRecord * rr,const mDNSu8 * AnonData,int len,mDNSu32 salt)30 mDNSlocal mDNSBool InitializeNSEC3Record(ResourceRecord *rr, const mDNSu8 *AnonData, int len, mDNSu32 salt)
31 {
32 const mDNSu8 *ptr;
33 rdataNSEC3 *nsec3 = (rdataNSEC3 *)rr->rdata->u.data;
34 mDNSu8 *tmp, *nxt;
35 unsigned short iter = ANON_NSEC3_ITERATIONS;
36 int hlen;
37 const mDNSu8 hashName[NSEC3_MAX_HASH_LEN];
38
39 // Construct the RDATA first and construct the owner name based on that.
40 ptr = (const mDNSu8 *)&salt;
41 debugf("InitializeNSEC3Record: %x%x%x%x, name %##s", ptr[0], ptr[1], ptr[2], ptr[3], rr->name->c);
42
43 // Set the RDATA
44 nsec3->alg = SHA1_DIGEST_TYPE;
45 nsec3->flags = 0;
46 nsec3->iterations = swap16(iter);
47 nsec3->saltLength = 4;
48 tmp = (mDNSu8 *)&nsec3->salt;
49 *tmp++ = ptr[0];
50 *tmp++ = ptr[1];
51 *tmp++ = ptr[2];
52 *tmp++ = ptr[3];
53
54 // hashLength, nxt, bitmap
55 *tmp++ = SHA1_HASH_LENGTH; // hash length
56 nxt = tmp;
57 tmp += SHA1_HASH_LENGTH;
58 *tmp++ = 0; // window number
59 *tmp++ = NSEC_MCAST_WINDOW_SIZE; // window length
60 mDNSPlatformMemZero(tmp, NSEC_MCAST_WINDOW_SIZE);
61 tmp[kDNSType_PTR >> 3] |= 128 >> (kDNSType_PTR & 7);
62
63 // Hash the base service name + salt + AnonData
64 if (!NSEC3HashName(rr->name, nsec3, AnonData, len, hashName, &hlen))
65 {
66 LogMsg("InitializeNSEC3Record: NSEC3HashName failed for ##s", rr->name->c);
67 return mDNSfalse;
68 }
69 if (hlen != SHA1_HASH_LENGTH)
70 {
71 LogMsg("InitializeNSEC3Record: hlen wrong %d", hlen);
72 return mDNSfalse;
73 }
74 mDNSPlatformMemCopy(nxt, hashName, hlen);
75
76 return mDNStrue;
77 }
78
ConstructNSEC3Record(const domainname * service,const mDNSu8 * AnonData,int len,mDNSu32 salt)79 mDNSlocal ResourceRecord *ConstructNSEC3Record(const domainname *service, const mDNSu8 *AnonData, int len, mDNSu32 salt)
80 {
81 ResourceRecord *rr;
82 int dlen;
83 domainname *name;
84
85 // We are just allocating an RData which has StandardAuthRDSize
86 if (StandardAuthRDSize < MCAST_NSEC3_RDLENGTH)
87 {
88 LogMsg("ConstructNSEC3Record: StandardAuthRDSize %d smaller than MCAST_NSEC3_RDLENGTH %d", StandardAuthRDSize, MCAST_NSEC3_RDLENGTH);
89 return mDNSNULL;
90 }
91
92 dlen = DomainNameLength(service);
93
94 // Allocate space for the name and RData.
95 rr = mDNSPlatformMemAllocate(sizeof(ResourceRecord) + dlen + sizeof(RData));
96 if (!rr)
97 return mDNSNULL;
98 name = (domainname *)((mDNSu8 *)rr + sizeof(ResourceRecord));
99 rr->RecordType = kDNSRecordTypePacketAuth;
100 rr->InterfaceID = mDNSInterface_Any;
101 rr->name = (const domainname *)name;
102 rr->rrtype = kDNSType_NSEC3;
103 rr->rrclass = kDNSClass_IN;
104 rr->rroriginalttl = kStandardTTL;
105 rr->rDNSServer = mDNSNULL;
106 rr->rdlength = MCAST_NSEC3_RDLENGTH;
107 rr->rdestimate = MCAST_NSEC3_RDLENGTH;
108 rr->rdata = (RData *)((mDNSu8 *)rr->name + dlen);
109
110 AssignDomainName(name, service);
111 if (!InitializeNSEC3Record(rr, AnonData, len, salt))
112 {
113 mDNSPlatformMemFree(rr);
114 return mDNSNULL;
115 }
116 return rr;
117 }
118
CopyNSEC3ResourceRecord(AnonymousInfo * si,const ResourceRecord * rr)119 mDNSlocal ResourceRecord *CopyNSEC3ResourceRecord(AnonymousInfo *si, const ResourceRecord *rr)
120 {
121 int len;
122 domainname *name;
123 ResourceRecord *nsec3rr;
124
125 if (rr->rdlength < MCAST_NSEC3_RDLENGTH)
126 {
127 LogMsg("CopyNSEC3ResourceRecord: rdlength %d smaller than MCAST_NSEC3_RDLENGTH %d", rr->rdlength, MCAST_NSEC3_RDLENGTH);
128 return mDNSNULL;
129 }
130 // Allocate space for the name and the rdata along with the ResourceRecord
131 len = DomainNameLength(rr->name);
132 nsec3rr = mDNSPlatformMemAllocate(sizeof(ResourceRecord) + len + sizeof(RData));
133 if (!nsec3rr)
134 return mDNSNULL;
135
136 *nsec3rr = *rr;
137 name = (domainname *)((mDNSu8 *)nsec3rr + sizeof(ResourceRecord));
138 nsec3rr->name = (const domainname *)name;
139 AssignDomainName(name, rr->name);
140
141 nsec3rr->rdata = (RData *)((mDNSu8 *)nsec3rr->name + len);
142 mDNSPlatformMemCopy(nsec3rr->rdata->u.data, rr->rdata->u.data, rr->rdlength);
143
144 si->nsec3RR = nsec3rr;
145
146 return nsec3rr;
147 }
148
149 // When a service is started or a browse is started with the Anonymous data, we allocate a new random
150 // number and based on that allocate a new NSEC3 resource record whose hash is a function of random number (salt) and
151 // the anonymous data.
152 //
153 // If we receive a packet with the NSEC3 option, we need to cache that along with the resource record so that we can
154 // check against the question to see whether it answers them or not. In that case, we pass the "rr" that we received.
AllocateAnonInfo(const domainname * service,const mDNSu8 * data,int len,const ResourceRecord * rr)155 mDNSexport AnonymousInfo *AllocateAnonInfo(const domainname *service, const mDNSu8 *data, int len, const ResourceRecord *rr)
156 {
157 AnonymousInfo *ai;
158 ai = (AnonymousInfo *)mDNSPlatformMemAllocate(sizeof(AnonymousInfo));
159 if (!ai)
160 {
161 return mDNSNULL;
162 }
163 mDNSPlatformMemZero(ai, sizeof(AnonymousInfo));
164 if (rr)
165 {
166 if (!CopyNSEC3ResourceRecord(ai, rr))
167 {
168 mDNSPlatformMemFree(ai);
169 return mDNSNULL;
170 }
171 return ai;
172 }
173 ai->salt = mDNSRandom(0xFFFFFFFF);
174 ai->AnonData = mDNSPlatformMemAllocate(len);
175 if (!ai->AnonData)
176 {
177 mDNSPlatformMemFree(ai);
178 return mDNSNULL;
179 }
180 ai->AnonDataLen = len;
181 mDNSPlatformMemCopy(ai->AnonData, data, len);
182 ai->nsec3RR = ConstructNSEC3Record(service, data, len, ai->salt);
183 if (!ai->nsec3RR)
184 {
185 mDNSPlatformMemFree(ai);
186 return mDNSNULL;
187 }
188 return ai;
189 }
190
FreeAnonInfo(AnonymousInfo * ai)191 mDNSexport void FreeAnonInfo(AnonymousInfo *ai)
192 {
193 if (ai->nsec3RR)
194 mDNSPlatformMemFree(ai->nsec3RR);
195 if (ai->AnonData)
196 mDNSPlatformMemFree(ai->AnonData);
197 mDNSPlatformMemFree(ai);
198 }
199
ReInitAnonInfo(AnonymousInfo ** AnonInfo,const domainname * name)200 mDNSexport void ReInitAnonInfo(AnonymousInfo **AnonInfo, const domainname *name)
201 {
202 if (*AnonInfo)
203 {
204 AnonymousInfo *ai = *AnonInfo;
205 *AnonInfo = AllocateAnonInfo(name, ai->AnonData, ai->AnonDataLen, mDNSNULL);
206 if (!(*AnonInfo))
207 *AnonInfo = ai;
208 else
209 FreeAnonInfo(ai);
210 }
211 }
212
213 // This function should be used only if you know that the question and
214 // the resource record belongs to the same set. The main usage is
215 // in ProcessQuery where we find the question to be part of the same
216 // set as the resource record, but it needs the AnonData to be
217 // initialized so that it can walk the cache records to see if they
218 // answer the question.
SetAnonData(DNSQuestion * q,ResourceRecord * rr,mDNSBool ForQuestion)219 mDNSexport void SetAnonData(DNSQuestion *q, ResourceRecord *rr, mDNSBool ForQuestion)
220 {
221 if (!q->AnonInfo || !rr->AnonInfo)
222 {
223 LogMsg("SetAnonData: question %##s(%p), rr %##s(%p), NULL", q->qname.c, q->AnonInfo, rr->name->c, rr->AnonInfo);
224 return;
225 }
226
227 debugf("SetAnonData: question %##s(%p), rr %##s(%p)", q->qname.c, q->AnonInfo, rr->name->c, rr->AnonInfo);
228 if (ForQuestion)
229 {
230 if (!q->AnonInfo->AnonData)
231 {
232 q->AnonInfo->AnonData = mDNSPlatformMemAllocate(rr->AnonInfo->AnonDataLen);
233 if (!q->AnonInfo->AnonData)
234 return;
235 }
236 mDNSPlatformMemCopy(q->AnonInfo->AnonData, rr->AnonInfo->AnonData, rr->AnonInfo->AnonDataLen);
237 q->AnonInfo->AnonDataLen = rr->AnonInfo->AnonDataLen;
238 }
239 else
240 {
241 if (!rr->AnonInfo->AnonData)
242 {
243 rr->AnonInfo->AnonData = mDNSPlatformMemAllocate(q->AnonInfo->AnonDataLen);
244 if (!rr->AnonInfo->AnonData)
245 return;
246 }
247 mDNSPlatformMemCopy(rr->AnonInfo->AnonData, q->AnonInfo->AnonData, q->AnonInfo->AnonDataLen);
248 rr->AnonInfo->AnonDataLen = q->AnonInfo->AnonDataLen;
249 }
250 }
251
252 // returns -1 if the caller should ignore the result
253 // returns 1 if the record answers the question
254 // returns 0 if the record does not answer the question
AnonInfoAnswersQuestion(const ResourceRecord * const rr,const DNSQuestion * const q)255 mDNSexport int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
256 {
257 mDNSexport mDNS mDNSStorage;
258 ResourceRecord *nsec3RR;
259 int i;
260 AnonymousInfo *qai, *rai;
261 mDNSu8 *AnonData;
262 int AnonDataLen;
263 rdataNSEC3 *nsec3;
264 int hlen;
265 const mDNSu8 hashName[NSEC3_MAX_HASH_LEN];
266 int nxtLength;
267 mDNSu8 *nxtName;
268
269 debugf("AnonInfoAnswersQuestion: question qname %##s", q->qname.c);
270
271 // Currently only PTR records can have anonymous information
272 if (q->qtype != kDNSType_PTR)
273 {
274 return -1;
275 }
276
277 // We allow anonymous questions to be answered by both normal services (without the
278 // anonymous information) and anonymous services that are part of the same set. And
279 // normal questions discover normal services and all anonymous services.
280 //
281 // The three cases have been enumerated clearly even though they all behave the
282 // same way.
283 if (!q->AnonInfo)
284 {
285 debugf("AnonInfoAnswersQuestion: not a anonymous type question");
286 if (!rr->AnonInfo)
287 {
288 // case 1
289 return -1;
290 }
291 else
292 {
293 // case 2
294 debugf("AnonInfoAnswersQuestion: Question %##s not answered using anonymous record %##s", q->qname.c, rr->name->c);
295 return -1;
296 }
297 }
298 else
299 {
300 // case 3
301 if (!rr->AnonInfo)
302 {
303 debugf("AnonInfoAnswersQuestion: not a anonymous type record");
304 return -1;
305 }
306 }
307
308 // case 4: We have the anonymous information both in the question and the record. We need
309 // two sets of information to validate.
310 //
311 // 1) Anonymous data that identifies the set/group
312 // 2) NSEC3 record that contains the hash and the salt
313 //
314 // If the question is a remote one, it does not have the anonymous information to validate (just
315 // the NSEC3 record) and hence the anonymous data should come from the local resource record. If the
316 // question is local, it can come from either of them and if there is a mismatch between the
317 // question and record, it won't validate.
318
319 qai = q->AnonInfo;
320 rai = rr->AnonInfo;
321
322 if (qai->AnonData && rai->AnonData)
323 {
324 // Before a cache record is created, if there is a matching question i.e., part
325 // of the same set, then when the cache is created we also set the anonymous
326 // information. Otherwise, the cache record contains just the NSEC3 record and we
327 // won't be here for that case.
328 //
329 // It is also possible that a local question is matched against the local AuthRecord
330 // as that is also the case for which the AnonData would be non-NULL for both.
331 // We match questions against AuthRecords (rather than the cache) for LocalOnly case and
332 // to see whether a .local query should be suppressed or not. The latter never happens
333 // because PTR queries are never suppressed.
334
335 // If they don't belong to the same anonymous set, then no point in validating.
336 if ((qai->AnonDataLen != rai->AnonDataLen) ||
337 mDNSPlatformMemCmp(qai->AnonData, rai->AnonData, qai->AnonDataLen) != 0)
338 {
339 debugf("AnonInfoAnswersQuestion: AnonData mis-match for record %s question %##s ",
340 RRDisplayString(&mDNSStorage, rr), q->qname.c);
341 return 0;
342 }
343 // AnonData matches i.e they belong to the same group and the same service.
344 LogInfo("AnonInfoAnswersQuestion: Answering qname %##s, rname %##s, without validation", q->qname.c,
345 rr->name->c);
346 return 1;
347 }
348 else
349 {
350 debugf("AnonInfoAnswersQuestion: question %p, record %p", qai->AnonData, rai->AnonData);
351 }
352
353 if (qai->AnonData)
354 {
355 // If there is AnonData, then this is a local question. The
356 // NSEC3 RR comes from the resource record which could be part
357 // of the cache or local auth record. The cache entry could
358 // be from a remote host or created when we heard our own
359 // announcements. In any case, we use that to see if it matches
360 // the question.
361 AnonData = qai->AnonData;
362 AnonDataLen = qai->AnonDataLen;
363 nsec3RR = rai->nsec3RR;
364 }
365 else
366 {
367 // Remote question or hearing our own question back
368 AnonData = rai->AnonData;
369 AnonDataLen = rai->AnonDataLen;
370 nsec3RR = qai->nsec3RR;
371 }
372
373 if (!AnonData || !nsec3RR)
374 {
375 // AnonData can be NULL for the cache entry and if we are hearing our own question back, AnonData is NULL for
376 // that too and we can end up here for that case.
377 debugf("AnonInfoAnswersQuestion: AnonData %p or nsec3RR %p, NULL for question %##s, record %s", AnonData, nsec3RR,
378 q->qname.c, RRDisplayString(&mDNSStorage, rr));
379 return 0;
380 }
381 debugf("AnonInfoAnswersQuestion: Validating question %##s, ResourceRecord %s", q->qname.c, RRDisplayString(&mDNSStorage, nsec3RR));
382
383
384 nsec3 = (rdataNSEC3 *)nsec3RR->rdata->u.data;
385
386 if (!NSEC3HashName(nsec3RR->name, nsec3, AnonData, AnonDataLen, hashName, &hlen))
387 {
388 LogMsg("AnonInfoAnswersQuestion: NSEC3HashName failed for ##s", nsec3RR->name->c);
389 return mDNSfalse;
390 }
391 if (hlen != SHA1_HASH_LENGTH)
392 {
393 LogMsg("AnonInfoAnswersQuestion: hlen wrong %d", hlen);
394 return mDNSfalse;
395 }
396
397 NSEC3Parse(nsec3RR, mDNSNULL, &nxtLength, &nxtName, mDNSNULL, mDNSNULL);
398
399 if (hlen != nxtLength)
400 {
401 LogMsg("AnonInfoAnswersQuestion: ERROR!! hlen %d not same as nxtLength %d", hlen, nxtLength);
402 return mDNSfalse;
403 }
404
405 for (i = 0; i < nxtLength; i++)
406 {
407 if (nxtName[i] != hashName[i])
408 {
409 debugf("AnonInfoAnswersQuestion: mismatch output %x, digest %x, i %d", nxtName[i+1], hashName[i], i);
410 return 0;
411 }
412 }
413 LogInfo("AnonInfoAnswersQuestion: ResourceRecord %s matched question %##s (%s)", RRDisplayString(&mDNSStorage, nsec3RR), q->qname.c, DNSTypeName(q->qtype));
414 return 1;
415 }
416
417 // Find a matching NSEC3 record for the name. We parse the questions and the records in the packet in order.
418 // Similarly we also parse the NSEC3 records in order and this mapping to the questions and records
419 // respectively.
FindMatchingNSEC3ForName(mDNS * const m,CacheRecord ** nsec3,const domainname * name)420 mDNSlocal CacheRecord *FindMatchingNSEC3ForName(mDNS *const m, CacheRecord **nsec3, const domainname *name)
421 {
422 CacheRecord *cr;
423 CacheRecord **prev = nsec3;
424
425 (void) m;
426
427 for (cr = *nsec3; cr; cr = cr->next)
428 {
429 if (SameDomainName(cr->resrec.name, name))
430 {
431 debugf("FindMatchingNSEC3ForName: NSEC3 record %s matched %##s", CRDisplayString(m, cr), name->c);
432 *prev = cr->next;
433 cr->next = mDNSNULL;
434 return cr;
435 }
436 prev = &cr->next;
437 }
438 return mDNSNULL;
439 }
440
InitializeAnonInfoForQuestion(mDNS * const m,CacheRecord ** McastNSEC3Records,DNSQuestion * q)441 mDNSexport void InitializeAnonInfoForQuestion(mDNS *const m, CacheRecord **McastNSEC3Records, DNSQuestion *q)
442 {
443 CacheRecord *nsec3CR;
444
445 if (q->qtype != kDNSType_PTR)
446 return;
447
448 nsec3CR = FindMatchingNSEC3ForName(m, McastNSEC3Records, &q->qname);
449 if (nsec3CR)
450 {
451 q->AnonInfo = AllocateAnonInfo(mDNSNULL, mDNSNULL, 0, &nsec3CR->resrec);
452 if (q->AnonInfo)
453 {
454 debugf("InitializeAnonInfoForQuestion: Found a matching NSEC3 record %s, for %##s (%s)",
455 RRDisplayString(m, q->AnonInfo->nsec3RR), q->qname.c, DNSTypeName(q->qtype));
456 }
457 ReleaseCacheRecord(m, nsec3CR);
458 }
459 }
460
InitializeAnonInfoForCR(mDNS * const m,CacheRecord ** McastNSEC3Records,CacheRecord * cr)461 mDNSexport void InitializeAnonInfoForCR(mDNS *const m, CacheRecord **McastNSEC3Records, CacheRecord *cr)
462 {
463 CacheRecord *nsec3CR;
464
465 if (!(*McastNSEC3Records))
466 return;
467
468 // If already initialized or not a PTR type, we don't have to do anything
469 if (cr->resrec.AnonInfo || cr->resrec.rrtype != kDNSType_PTR)
470 return;
471
472 nsec3CR = FindMatchingNSEC3ForName(m, McastNSEC3Records, cr->resrec.name);
473 if (nsec3CR)
474 {
475 cr->resrec.AnonInfo = AllocateAnonInfo(mDNSNULL, mDNSNULL, 0, &nsec3CR->resrec);
476 if (cr->resrec.AnonInfo)
477 {
478 debugf("InitializeAnonInfoForCR: Found a matching NSEC3 record %s, for %##s (%s)",
479 RRDisplayString(m, cr->resrec.AnonInfo->nsec3RR), cr->resrec.name->c,
480 DNSTypeName(cr->resrec.rrtype));
481 }
482 ReleaseCacheRecord(m, nsec3CR);
483 }
484 }
485
IdenticalAnonInfo(AnonymousInfo * a1,AnonymousInfo * a2)486 mDNSexport mDNSBool IdenticalAnonInfo(AnonymousInfo *a1, AnonymousInfo *a2)
487 {
488 // if a1 is NULL and a2 is not NULL AND vice-versa
489 // return false as there is a change.
490 if ((a1 != mDNSNULL) != (a2 != mDNSNULL))
491 return mDNSfalse;
492
493 // Both could be NULL or non-NULL
494 if (a1 && a2)
495 {
496 // The caller already verified that the owner name is the same.
497 // Check whether the RData is same.
498 if (!IdenticalSameNameRecord(a1->nsec3RR, a2->nsec3RR))
499 {
500 debugf("IdenticalAnonInfo: nsec3RR mismatch");
501 return mDNSfalse;
502 }
503 }
504 return mDNStrue;
505 }
506
CopyAnonInfoForCR(mDNS * const m,CacheRecord * crto,CacheRecord * crfrom)507 mDNSexport void CopyAnonInfoForCR(mDNS *const m, CacheRecord *crto, CacheRecord *crfrom)
508 {
509 AnonymousInfo *aifrom = crfrom->resrec.AnonInfo;
510 AnonymousInfo *aito = crto->resrec.AnonInfo;
511
512 (void) m;
513
514 if (!aifrom)
515 return;
516
517 if (aito)
518 {
519 crto->resrec.AnonInfo = aifrom;
520 FreeAnonInfo(aito);
521 crfrom->resrec.AnonInfo = mDNSNULL;
522 }
523 else
524 {
525 FreeAnonInfo(aifrom);
526 crfrom->resrec.AnonInfo = mDNSNULL;
527 }
528 }
529
530 #else // !ANONYMOUS_DISABLED
531
ReInitAnonInfo(AnonymousInfo ** si,const domainname * name)532 mDNSexport void ReInitAnonInfo(AnonymousInfo **si, const domainname *name)
533 {
534 (void)si;
535 (void)name;
536 }
537
AllocateAnonInfo(const domainname * service,const mDNSu8 * AnonData,int len,const ResourceRecord * rr)538 mDNSexport AnonymousInfo * AllocateAnonInfo(const domainname *service, const mDNSu8 *AnonData, int len, const ResourceRecord *rr)
539 {
540 (void)service;
541 (void)AnonData;
542 (void)len;
543 (void)rr;
544
545 return mDNSNULL;
546 }
547
FreeAnonInfo(AnonymousInfo * ai)548 mDNSexport void FreeAnonInfo(AnonymousInfo *ai)
549 {
550 (void)ai;
551 }
552
SetAnonData(DNSQuestion * q,ResourceRecord * rr,mDNSBool ForQuestion)553 mDNSexport void SetAnonData(DNSQuestion *q, ResourceRecord *rr, mDNSBool ForQuestion)
554 {
555 (void)q;
556 (void)rr;
557 (void)ForQuestion;
558 }
559
AnonInfoAnswersQuestion(const ResourceRecord * const rr,const DNSQuestion * const q)560 mDNSexport int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
561 {
562 (void)rr;
563 (void)q;
564
565 return mDNSfalse;
566 }
567
InitializeAnonInfoForQuestion(mDNS * const m,CacheRecord ** McastNSEC3Records,DNSQuestion * q)568 mDNSexport void InitializeAnonInfoForQuestion(mDNS *const m, CacheRecord **McastNSEC3Records, DNSQuestion *q)
569 {
570 (void)m;
571 (void)McastNSEC3Records;
572 (void)q;
573 }
574
InitializeAnonInfoForCR(mDNS * const m,CacheRecord ** McastNSEC3Records,CacheRecord * cr)575 mDNSexport void InitializeAnonInfoForCR(mDNS *const m, CacheRecord **McastNSEC3Records, CacheRecord *cr)
576 {
577 (void)m;
578 (void)McastNSEC3Records;
579 (void)cr;
580 }
581
CopyAnonInfoForCR(mDNS * const m,CacheRecord * crto,CacheRecord * crfrom)582 mDNSexport void CopyAnonInfoForCR(mDNS *const m, CacheRecord *crto, CacheRecord *crfrom)
583 {
584 (void)m;
585 (void)crto;
586 (void)crfrom;
587 }
588
IdenticalAnonInfo(AnonymousInfo * a1,AnonymousInfo * a2)589 mDNSexport mDNSBool IdenticalAnonInfo(AnonymousInfo *a1, AnonymousInfo *a2)
590 {
591 (void)a1;
592 (void)a2;
593
594 return mDNStrue;
595 }
596
597 #endif // !ANONYMOUS_DISABLED
598