Imported Upstream version 878.70.2
[platform/upstream/mdnsresponder.git] / mDNSMacOSX / BonjourTop / source / DNSFrame.cpp
1 //
2 //  DNSFrame.cpp
3 //  TestTB
4 //
5 //  Created by Terrin Eager on 9/26/12.
6 //
7 //
8
9 #include "DNSFrame.h"
10
11 #define DNS_LABEL_MAX_LENGTH    63
12 #define DNS_NAME_MAX_LENGTH     255
13
14 void CDNSRecord::GetDnsRecordName(BJString& ReturnString,int nLabelToSkip,int nMaxLabel)
15 {
16     GetDnsRecordNameFromBuffer(m_pStartofRec, ReturnString, nLabelToSkip, nMaxLabel);
17 }
18
19 void CDNSRecord::GetDnsRecordNameFromBuffer(BJ_UINT8* pBuffer,BJString& ReturnString,int nLabelToSkip,int nMaxLabel)
20 {
21     BJ_UINT8* pNameBuffer = NULL;
22     int nOffset = 0;
23    // char* pTemp = pReturnBuffer;
24     int nCharCount  = 0;
25     int nSkippedLabels = 0;
26     int nLabelProcessed = 0;
27     ReturnString.Set(NULL,255);
28
29     if (ReturnString.GetBuffer() == NULL)
30         return;
31
32     pNameBuffer = pBuffer;
33     if (pNameBuffer == NULL)
34     {
35         return;
36     }
37
38     while (ReturnString.GetBufferLength() < 1024)
39     {
40         nCharCount = *pNameBuffer++;
41         if (nCharCount == 0)
42             break;
43
44         if ((nCharCount&(DNS_NAME_OFFSET_MASK)) == DNS_NAME_OFFSET_MASK)
45         {
46             nOffset = *pNameBuffer++;
47             nOffset |= (nCharCount&(~DNS_NAME_OFFSET_MASK)) << 8;
48             pNameBuffer = m_pDNSFrame->GetBuffer() + nOffset;
49             continue;
50         }
51
52         if (nCharCount > DNS_LABEL_MAX_LENGTH)
53         {
54             printf("label too long %d\n",nCharCount);
55             break;
56         }
57
58         if (ReturnString.GetLength() + nCharCount + 1 > DNS_NAME_MAX_LENGTH) // + 1 is for the '.' added later on
59         {
60             printf("Name exceeded limit allowed for DNS: %d\n", ReturnString.GetLength() + nCharCount + 1);
61             break;
62         }
63
64         if (nLabelToSkip > nSkippedLabels)
65         {
66             nSkippedLabels++;
67             pNameBuffer += nCharCount;
68             continue;
69         }
70         ReturnString.Append((char*)pNameBuffer, nCharCount);
71         pNameBuffer+= nCharCount;
72         nLabelProcessed++;
73
74         if (nLabelProcessed >= nMaxLabel)
75             return;
76
77         ReturnString += ".";
78     }
79 }
80
81
82
83
84 CDNSFrame::CDNSFrame()
85 {
86
87     for(int nIndex=0; nIndex < MAX_DNS_RECORDS_PER_FRAME; nIndex++)
88         m_dnsItems[nIndex].m_pDNSFrame = this;
89
90 }
91
92 CDNSRecord* CDNSFrame::GetDnsRecord(int nIndex)
93 {
94     if (nIndex > m_nMaxItems)
95         return NULL;
96     return &m_dnsItems[nIndex];
97 }
98
99 bool CDNSFrame::ParseDNSFrame(BJ_UINT8* pBuffer,BJ_INT32 nLength, BJ_UINT64 frameTime)
100 {
101     if (pBuffer == NULL)
102         return false;
103
104     int nIndex = 0;
105
106     m_Servicev4Address.Empty();
107     m_Servicev6Address.Empty();
108
109     m_pStartBuffer = pBuffer;
110     m_nFrameLen = (BJ_UINT32) nLength;
111
112     m_pCurrentBuffer = m_pStartBuffer;
113     m_pEndBuffer = m_pStartBuffer + m_nFrameLen;
114     m_Time = frameTime;
115
116     m_nId = PF_GET_UINT16(m_pStartBuffer,0);
117     m_nFlags = PF_GET_UINT16(m_pStartBuffer,2);
118     m_nQuestionCount = PF_GET_UINT16(m_pStartBuffer,4);
119     m_nAnswersCount = PF_GET_UINT16(m_pStartBuffer,6);
120     m_NSCOUNT = PF_GET_UINT16(m_pStartBuffer,8);
121     m_ARCOUNT = PF_GET_UINT16(m_pStartBuffer,10);
122
123     m_nMaxItems = 0;
124
125
126
127     // printf("FrameNum= %d,nQuestionCount= %d nAnswersCount= %d NSCOUNT= %d ARCOUNT= %d\n",nFrameCount++,m_nQuestionCount, m_nAnswersCount,m_NSCOUNT,  m_ARCOUNT);
128
129     m_pCurrentBuffer = m_pStartBuffer + 12;
130
131
132     for (nIndex =0; nIndex < m_nQuestionCount;nIndex++)
133     {
134         //      printf("FramePosition= %ld  ",m_pCurrentBuffer);
135         ParseDnsRecord(CDNSRecord::Question);
136
137     }
138     for (nIndex =0; nIndex < m_nAnswersCount;nIndex++)
139     {
140         //      printf("FramePosition= %ld  ",m_pCurrentBuffer);
141         ParseDnsRecord(CDNSRecord::Answer);
142     }
143     for (nIndex =0; nIndex < m_NSCOUNT;nIndex++)
144     {
145         //      printf("FramePosition= %ld  ",m_pCurrentBuffer);
146         ParseDnsRecord(CDNSRecord::Answer);
147     }
148     for (nIndex =0; nIndex < m_ARCOUNT;nIndex++)
149     {
150         //      printf("FramePosition= %ld  ",m_pCurrentBuffer);
151         ParseDnsRecord(CDNSRecord::Answer);
152         CDNSRecord* pRecord =  &m_dnsItems[m_nMaxItems-1];
153         if (pRecord->m_RecType == DNS_TYPE_AAAA && m_Servicev6Address.IsEmpty())
154         {
155             m_Servicev6Address.Setv6Raw(pRecord->GetStartofRdata());
156         }
157         if (pRecord->m_RecType == DNS_TYPE_A && m_Servicev4Address.IsEmpty())
158         {
159             m_Servicev4Address.Setv4Raw(pRecord->GetStartofRdata());
160         }
161     }
162     //
163     ///   for (dnsItemsIndex =0; dnsItemsIndex < m_nQuestionCount+m_nAnswersCount;dnsItemsIndex++)
164     ///   {
165     ///       printf("Name = %s\n", GetDnsRecordName(&Frame,dnsItemsIndex,tempBuffer,sizeof(tempBuffer)));
166     //   }
167     return true;
168 }
169
170 BJ_BOOL CDNSFrame::ParseDnsRecord(CDNSRecord::dnsItemType eItemType)
171 {
172     unsigned char nCharCount = 0;
173     BJ_UINT8* pTemp = m_pCurrentBuffer;
174     CDNSRecord* pRecord =  &m_dnsItems[m_nMaxItems++];
175
176     //temp
177     BJ_UINT16 nRdataLen = 0;
178     BJ_UINT16 nRdataLen2 = 0;
179
180     if (pTemp > m_pEndBuffer)
181     {
182         printf("Error in ParseDnsRecord pBuffer > pEndBuffer\n");
183         pRecord->m_pStartofRec = NULL;
184         pRecord->m_nNameLength = 0;
185         return false;
186     }
187
188
189     pRecord->m_pStartofRec = pTemp;
190     pRecord->m_nNameLength = 0;
191     pRecord->m_nRdataLen = 0;
192
193
194     // Skip over Name;
195     while (pTemp < m_pEndBuffer)
196     {
197         nCharCount = *pTemp;
198         pTemp++;
199
200         if (nCharCount == 0)
201             break;
202
203         if ((nCharCount&(DNS_NAME_OFFSET_MASK)) == DNS_NAME_OFFSET_MASK)
204         {  // offset string
205             pTemp++;
206             break;
207         }
208
209         if (nCharCount > DNS_LABEL_MAX_LENGTH)
210         {
211             printf("%d. label too long %d\n",m_nMaxItems-1,nCharCount);
212         }
213
214         if (pTemp + nCharCount < m_pEndBuffer)
215             pTemp += nCharCount;
216         else
217             pTemp = m_pEndBuffer;
218     }
219
220     pRecord->m_nNameLength = (BJ_UINT32)(pTemp - pRecord->m_pStartofRec);
221
222     if (eItemType == CDNSRecord::Question)
223     {
224         pRecord->m_RecType = PF_GET_UINT16(pTemp,0);
225         pRecord->m_RecClass = PF_GET_UINT16(pTemp,2);
226         pRecord->m_nTTL = PF_GET_UINT16(pTemp,4);
227
228         //   printf("Namelen=%u, Type=%u, class=%u, TTL=%u, RDLength=%u\n", m_dnsItems[ndnsIndex].nNameLength,nType,nClass,nTTL,nRdataLen);
229
230         pTemp += 4;
231     }
232     else
233     {
234
235         pRecord->m_RecType = PF_GET_UINT16(pTemp,0);
236         pRecord->m_RecClass = PF_GET_UINT16(pTemp,2);
237
238         pRecord->m_nTTL = PF_GET_UINT32(pTemp,4);
239         pRecord->m_nRdataLen = PF_GET_UINT16(pTemp,8);
240         if (nRdataLen > 1024*10)
241         {
242             printf("large Rdata ??");
243             nRdataLen2 = (pTemp[8] << 8) | pTemp[9];
244
245         }
246         //    printf("Namelen=%u, Type=%u, class=%u, TTL=%u, RDLength=%u\n", m_dnsItems[ndnsIndex].nNameLength,m_dnsItems[ndnsIndex].RecType,nClass,nTTL,m_dnsItems[ndnsIndex].nRdataLen);
247         pTemp += 10 + pRecord->m_nRdataLen;
248     }
249
250     m_pCurrentBuffer = pTemp;
251
252     return true;
253 }
254
255 BJ_BOOL CDNSFrame::IsQueryFrame()
256 {
257     return !(m_nFlags&0x8000);
258 }
259
260 #define UNICAST_RESPONDS_REQUESTED 0x8000
261 BJ_BOOL CDNSFrame::IsWakeFrame()
262 {
263
264     for (int i=0; i < m_nQuestionCount; i++)
265     {
266         if (m_dnsItems[i].m_RecType == DNS_TYPE_PTR &&  m_dnsItems[i].m_RecClass & UNICAST_RESPONDS_REQUESTED)
267             return true;
268     }
269
270     return false;
271 }
272 #define DNS_HEADER_TRUNCATEED 0x0200
273 BJ_BOOL  CDNSFrame::IsTruncatedFrame()
274 {
275        return (m_nFlags&DNS_HEADER_TRUNCATEED);
276 }
277
278
279 BJ_BOOL CDNSFrame::HasOnlyService(BJString sName, BJ_INT16 nRecType)
280 {
281  /*   if (IsQueryFrame())
282     {
283         for (int i=0; i < m_nQuestionCount; i++)
284         {
285             CBJString sRecordName;
286             m_dnsItems[i].GetDnsRecordName(sRecordName, 0);
287             if (m_dnsItems[i].m_RecType != nRecType && nRecType != -1)
288                 return false;
289
290             if (!sRecordName.Contains(sName.GetBuffer()))
291                 return false;
292         }
293     }
294     else*/
295     {
296         for (int i=0; i < m_nQuestionCount+m_nAnswersCount; i++)
297         {
298             BJString sRecordName;
299             m_dnsItems[i].GetDnsRecordName(sRecordName, 0,99);
300             if (m_dnsItems[i].m_RecType != nRecType && nRecType != -1)
301                 return false;
302
303             if (!sRecordName.Contains(sName.GetBuffer()))
304                 return false;
305         }
306
307
308     }
309
310
311     return true;
312 }
313
314 CDNSRecord* CDNSFrame::FindAdditionRecord(BJString& sName,BJ_INT16 nRecType)
315 {
316     for (int i = 0; i < m_nMaxItems; i++)
317     {
318         if (m_dnsItems[i].m_RecType != nRecType && nRecType != -1)
319             continue;
320         BJString sRecordName;
321         m_dnsItems[i].GetDnsRecordName(sRecordName, 0,99);
322         if (sRecordName == sName)
323             return &m_dnsItems[i];
324     }
325     return NULL;
326 }
327
328 void CDNSFrame::SetAddress(BJIPAddr *pSourceIPAddress,BJMACAddr *pSourceMACAddress)
329 {
330     m_SourceIPAddress = *pSourceIPAddress;
331     m_SourceMACAddress = *pSourceMACAddress;
332
333
334 }
335
336
337 bool CDNSFrame::GetTracingInfo(BJ_UINT8 &platform, BJ_UINT32 &version, BJMACAddr &)
338 {
339     // Find OPT record
340     for (int i = m_nQuestionCount + m_nAnswersCount + m_NSCOUNT; i < m_nMaxItems; i++)
341     {
342         if (m_dnsItems[i].m_RecType == DNS_TYPE_OPT)
343         {
344             BJ_UINT8* rdata = m_dnsItems[i].GetStartofRdata();
345
346             BJ_UINT8* rdataEnd = rdata +  m_dnsItems[i].m_nRdataLen;
347
348             while (rdata < rdataEnd)
349             {
350                 BJ_UINT16 type = PF_GET_UINT16(rdata,0);
351                 BJ_UINT16 len = PF_GET_UINT16(rdata,2);
352
353                 if (type == DNS_EDNS0_TRACE)
354                 {
355                     platform = PF_GET_UINT8(rdata,4);
356                     if (len == 3)   // EDNS field of length 3 <rdar://15101783>
357                     {
358                         version = static_cast<BJ_UINT32>(PF_GET_UINT16(rdata,5));
359                     }
360                     else if (len == 5) // EDNS field of length 5 <rdar://15235603>
361                     {
362                         version = static_cast<BJ_UINT32>(PF_GET_UINT32(rdata, 5));
363                     }
364                     else
365                     {
366                         return false;
367                     }
368                     return true;
369                 }
370
371
372                 rdata += sizeof(BJ_UINT16)*2 + len;
373             }
374
375         }
376     }
377     return false;
378
379 }
380
381
382
383
384