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 | |
---|
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 | |
---|
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 | |
---|
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. |
---|
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 | |
---|
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 | |
---|
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. |
---|
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 |
---|
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. |
---|
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 | |
---|
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 | |
---|
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 | |
---|
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 | |
---|
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 | |
---|
532 | mDNSexport void ReInitAnonInfo(AnonymousInfo **si, const domainname *name) |
---|
533 | { |
---|
534 | (void)si; |
---|
535 | (void)name; |
---|
536 | } |
---|
537 | |
---|
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 | |
---|
548 | mDNSexport void FreeAnonInfo(AnonymousInfo *ai) |
---|
549 | { |
---|
550 | (void)ai; |
---|
551 | } |
---|
552 | |
---|
553 | mDNSexport void SetAnonData(DNSQuestion *q, ResourceRecord *rr, mDNSBool ForQuestion) |
---|
554 | { |
---|
555 | (void)q; |
---|
556 | (void)rr; |
---|
557 | (void)ForQuestion; |
---|
558 | } |
---|
559 | |
---|
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 | |
---|
568 | mDNSexport void InitializeAnonInfoForQuestion(mDNS *const m, CacheRecord **McastNSEC3Records, DNSQuestion *q) |
---|
569 | { |
---|
570 | (void)m; |
---|
571 | (void)McastNSEC3Records; |
---|
572 | (void)q; |
---|
573 | } |
---|
574 | |
---|
575 | mDNSexport void InitializeAnonInfoForCR(mDNS *const m, CacheRecord **McastNSEC3Records, CacheRecord *cr) |
---|
576 | { |
---|
577 | (void)m; |
---|
578 | (void)McastNSEC3Records; |
---|
579 | (void)cr; |
---|
580 | } |
---|
581 | |
---|
582 | mDNSexport void CopyAnonInfoForCR(mDNS *const m, CacheRecord *crto, CacheRecord *crfrom) |
---|
583 | { |
---|
584 | (void)m; |
---|
585 | (void)crto; |
---|
586 | (void)crfrom; |
---|
587 | } |
---|
588 | |
---|
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 |
---|