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