blob: fc85a83ab3934c989d0e79b956f34f6ec3b04efe [file] [log] [blame]
//
// DNSFrame.cpp
// TestTB
//
// Created by Terrin Eager on 9/26/12.
//
//
#include "DNSFrame.h"
#define DNS_LABEL_MAX_LENGTH 63
#define DNS_NAME_MAX_LENGTH 255
void CDNSRecord::GetDnsRecordName(BJString& ReturnString,int nLabelToSkip,int nMaxLabel)
{
GetDnsRecordNameFromBuffer(m_pStartofRec, ReturnString, nLabelToSkip, nMaxLabel);
}
void CDNSRecord::GetDnsRecordNameFromBuffer(BJ_UINT8* pBuffer,BJString& ReturnString,int nLabelToSkip,int nMaxLabel)
{
BJ_UINT8* pNameBuffer = NULL;
int nOffset = 0;
// char* pTemp = pReturnBuffer;
int nCharCount = 0;
int nSkippedLabels = 0;
int nLabelProcessed = 0;
ReturnString.Set(NULL,255);
if (ReturnString.GetBuffer() == NULL)
return;
pNameBuffer = pBuffer;
if (pNameBuffer == NULL)
{
return;
}
while (ReturnString.GetBufferLength() < 1024)
{
nCharCount = *pNameBuffer++;
if (nCharCount == 0)
break;
if ((nCharCount&(DNS_NAME_OFFSET_MASK)) == DNS_NAME_OFFSET_MASK)
{
nOffset = *pNameBuffer++;
nOffset |= (nCharCount&(~DNS_NAME_OFFSET_MASK)) << 8;
pNameBuffer = m_pDNSFrame->GetBuffer() + nOffset;
continue;
}
if (nCharCount > DNS_LABEL_MAX_LENGTH)
{
printf("label too long %d\n",nCharCount);
break;
}
if (ReturnString.GetLength() + nCharCount + 1 > DNS_NAME_MAX_LENGTH) // + 1 is for the '.' added later on
{
printf("Name exceeded limit allowed for DNS: %d\n", ReturnString.GetLength() + nCharCount + 1);
break;
}
if (nLabelToSkip > nSkippedLabels)
{
nSkippedLabels++;
pNameBuffer += nCharCount;
continue;
}
ReturnString.Append((char*)pNameBuffer, nCharCount);
pNameBuffer+= nCharCount;
nLabelProcessed++;
if (nLabelProcessed >= nMaxLabel)
return;
ReturnString += ".";
}
}
CDNSFrame::CDNSFrame()
{
for(int nIndex=0; nIndex < MAX_DNS_RECORDS_PER_FRAME; nIndex++)
m_dnsItems[nIndex].m_pDNSFrame = this;
}
CDNSRecord* CDNSFrame::GetDnsRecord(int nIndex)
{
if (nIndex > m_nMaxItems)
return NULL;
return &m_dnsItems[nIndex];
}
bool CDNSFrame::ParseDNSFrame(BJ_UINT8* pBuffer,BJ_INT32 nLength, BJ_UINT64 frameTime)
{
if (pBuffer == NULL)
return false;
int nIndex = 0;
m_Servicev4Address.Empty();
m_Servicev6Address.Empty();
m_pStartBuffer = pBuffer;
m_nFrameLen = (BJ_UINT32) nLength;
m_pCurrentBuffer = m_pStartBuffer;
m_pEndBuffer = m_pStartBuffer + m_nFrameLen;
m_Time = frameTime;
m_nId = PF_GET_UINT16(m_pStartBuffer,0);
m_nFlags = PF_GET_UINT16(m_pStartBuffer,2);
m_nQuestionCount = PF_GET_UINT16(m_pStartBuffer,4);
m_nAnswersCount = PF_GET_UINT16(m_pStartBuffer,6);
m_NSCOUNT = PF_GET_UINT16(m_pStartBuffer,8);
m_ARCOUNT = PF_GET_UINT16(m_pStartBuffer,10);
m_nMaxItems = 0;
// printf("FrameNum= %d,nQuestionCount= %d nAnswersCount= %d NSCOUNT= %d ARCOUNT= %d\n",nFrameCount++,m_nQuestionCount, m_nAnswersCount,m_NSCOUNT, m_ARCOUNT);
m_pCurrentBuffer = m_pStartBuffer + 12;
for (nIndex =0; nIndex < m_nQuestionCount;nIndex++)
{
// printf("FramePosition= %ld ",m_pCurrentBuffer);
ParseDnsRecord(CDNSRecord::Question);
}
for (nIndex =0; nIndex < m_nAnswersCount;nIndex++)
{
// printf("FramePosition= %ld ",m_pCurrentBuffer);
ParseDnsRecord(CDNSRecord::Answer);
}
for (nIndex =0; nIndex < m_NSCOUNT;nIndex++)
{
// printf("FramePosition= %ld ",m_pCurrentBuffer);
ParseDnsRecord(CDNSRecord::Answer);
}
for (nIndex =0; nIndex < m_ARCOUNT;nIndex++)
{
// printf("FramePosition= %ld ",m_pCurrentBuffer);
ParseDnsRecord(CDNSRecord::Answer);
CDNSRecord* pRecord = &m_dnsItems[m_nMaxItems-1];
if (pRecord->m_RecType == DNS_TYPE_AAAA && m_Servicev6Address.IsEmpty())
{
m_Servicev6Address.Setv6Raw(pRecord->GetStartofRdata());
}
if (pRecord->m_RecType == DNS_TYPE_A && m_Servicev4Address.IsEmpty())
{
m_Servicev4Address.Setv4Raw(pRecord->GetStartofRdata());
}
}
//
/// for (dnsItemsIndex =0; dnsItemsIndex < m_nQuestionCount+m_nAnswersCount;dnsItemsIndex++)
/// {
/// printf("Name = %s\n", GetDnsRecordName(&Frame,dnsItemsIndex,tempBuffer,sizeof(tempBuffer)));
// }
return true;
}
BJ_BOOL CDNSFrame::ParseDnsRecord(CDNSRecord::dnsItemType eItemType)
{
unsigned char nCharCount = 0;
BJ_UINT8* pTemp = m_pCurrentBuffer;
CDNSRecord* pRecord = &m_dnsItems[m_nMaxItems++];
//temp
BJ_UINT16 nRdataLen = 0;
if (pTemp > m_pEndBuffer)
{
printf("Error in ParseDnsRecord pBuffer > pEndBuffer\n");
pRecord->m_pStartofRec = NULL;
pRecord->m_nNameLength = 0;
return false;
}
pRecord->m_pStartofRec = pTemp;
pRecord->m_nNameLength = 0;
pRecord->m_nRdataLen = 0;
// Skip over Name;
while (pTemp < m_pEndBuffer)
{
nCharCount = *pTemp;
pTemp++;
if (nCharCount == 0)
break;
if ((nCharCount&(DNS_NAME_OFFSET_MASK)) == DNS_NAME_OFFSET_MASK)
{ // offset string
pTemp++;
break;
}
if (nCharCount > DNS_LABEL_MAX_LENGTH)
{
printf("%d. label too long %d\n",m_nMaxItems-1,nCharCount);
}
if (pTemp + nCharCount < m_pEndBuffer)
pTemp += nCharCount;
else
pTemp = m_pEndBuffer;
}
pRecord->m_nNameLength = (BJ_UINT32)(pTemp - pRecord->m_pStartofRec);
if (eItemType == CDNSRecord::Question)
{
pRecord->m_RecType = PF_GET_UINT16(pTemp,0);
pRecord->m_RecClass = PF_GET_UINT16(pTemp,2);
pRecord->m_nTTL = PF_GET_UINT16(pTemp,4);
// printf("Namelen=%u, Type=%u, class=%u, TTL=%u, RDLength=%u\n", m_dnsItems[ndnsIndex].nNameLength,nType,nClass,nTTL,nRdataLen);
pTemp += 4;
}
else
{
pRecord->m_RecType = PF_GET_UINT16(pTemp,0);
pRecord->m_RecClass = PF_GET_UINT16(pTemp,2);
pRecord->m_nTTL = PF_GET_UINT32(pTemp,4);
pRecord->m_nRdataLen = PF_GET_UINT16(pTemp,8);
if (nRdataLen > 1024*10)
{
printf("large Rdata ??");
}
// 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);
pTemp += 10 + pRecord->m_nRdataLen;
}
m_pCurrentBuffer = pTemp;
return true;
}
BJ_BOOL CDNSFrame::IsQueryFrame()
{
return !(m_nFlags&0x8000);
}
#define UNICAST_RESPONDS_REQUESTED 0x8000
BJ_BOOL CDNSFrame::IsWakeFrame()
{
for (int i=0; i < m_nQuestionCount; i++)
{
if (m_dnsItems[i].m_RecType == DNS_TYPE_PTR && m_dnsItems[i].m_RecClass & UNICAST_RESPONDS_REQUESTED)
return true;
}
return false;
}
#define DNS_HEADER_TRUNCATEED 0x0200
BJ_BOOL CDNSFrame::IsTruncatedFrame()
{
return (m_nFlags&DNS_HEADER_TRUNCATEED);
}
BJ_BOOL CDNSFrame::HasOnlyService(BJString sName, BJ_INT16 nRecType)
{
/* if (IsQueryFrame())
{
for (int i=0; i < m_nQuestionCount; i++)
{
CBJString sRecordName;
m_dnsItems[i].GetDnsRecordName(sRecordName, 0);
if (m_dnsItems[i].m_RecType != nRecType && nRecType != -1)
return false;
if (!sRecordName.Contains(sName.GetBuffer()))
return false;
}
}
else*/
{
for (int i=0; i < m_nQuestionCount+m_nAnswersCount; i++)
{
BJString sRecordName;
m_dnsItems[i].GetDnsRecordName(sRecordName, 0,99);
if (m_dnsItems[i].m_RecType != nRecType && nRecType != -1)
return false;
if (!sRecordName.Contains(sName.GetBuffer()))
return false;
}
}
return true;
}
CDNSRecord* CDNSFrame::FindAdditionRecord(BJString& sName,BJ_INT16 nRecType)
{
for (int i = 0; i < m_nMaxItems; i++)
{
if (m_dnsItems[i].m_RecType != nRecType && nRecType != -1)
continue;
BJString sRecordName;
m_dnsItems[i].GetDnsRecordName(sRecordName, 0,99);
if (sRecordName == sName)
return &m_dnsItems[i];
}
return NULL;
}
void CDNSFrame::SetAddress(BJIPAddr *pSourceIPAddress,BJMACAddr *pSourceMACAddress)
{
m_SourceIPAddress = *pSourceIPAddress;
m_SourceMACAddress = *pSourceMACAddress;
}
bool CDNSFrame::GetTracingInfo(BJ_UINT8 &platform, BJ_UINT32 &version, BJMACAddr &)
{
// Find OPT record
for (int i = m_nQuestionCount + m_nAnswersCount + m_NSCOUNT; i < m_nMaxItems; i++)
{
if (m_dnsItems[i].m_RecType == DNS_TYPE_OPT)
{
BJ_UINT8* rdata = m_dnsItems[i].GetStartofRdata();
BJ_UINT8* rdataEnd = rdata + m_dnsItems[i].m_nRdataLen;
while (rdata < rdataEnd)
{
BJ_UINT16 type = PF_GET_UINT16(rdata,0);
BJ_UINT16 len = PF_GET_UINT16(rdata,2);
if (type == DNS_EDNS0_TRACE)
{
platform = PF_GET_UINT8(rdata,4);
if (len == 3) // EDNS field of length 3 <rdar://15101783>
{
version = static_cast<BJ_UINT32>(PF_GET_UINT16(rdata,5));
}
else if (len == 5) // EDNS field of length 5 <rdar://15235603>
{
version = static_cast<BJ_UINT32>(PF_GET_UINT32(rdata, 5));
}
else
{
return false;
}
return true;
}
rdata += sizeof(BJ_UINT16)*2 + len;
}
}
}
return false;
}