#include <cassert>
#include "dnsutil.h"
#include "dnspacket.h"
#include "rrfactory.h"
DNSPacket::DNSPacket() : Buffer(scm_szPacketMax) {
m_sipRemote = new SockAddrIn;
}
DNSPacket::DNSPacket(SockAddrIn* &i_siprRemote, unsigned short i_usID, RequestConstPtr ci_rqp, ResponseConstPtr ci_rsp) : Buffer(scm_szPacketMax) {
m_sipRemote = i_siprRemote;
i_siprRemote = NULL;
this->Format(i_usID,ci_rqp,ci_rsp);
}
DNSPacket::DNSPacket(SockAddrIn* &i_siprRemote, unsigned short i_usID, QuestionConstPtr ci_qnp) : Buffer(scm_szPacketMax) {
RequestPtr rqp;
QuestionPtr qnp;
m_sipRemote = i_siprRemote;
i_siprRemote = NULL;
qnp = new Question(*ci_qnp);
rqp = new Request(false,OPCODE_QUERY,qnp);
this->Format(i_usID,rqp,NULL);
SoftDelete(rqp);
}
#define XBIT(XXX,YYY) ((XXX>>YYY)&1)
#define NULL0(XXX,YYY) (((XXX)==NULL) ? 0 : (XXX)->YYY)
#define NULLF(XXX,YYY) (((XXX)==NULL) ? false : (XXX)->YYY)
void DNSPacket::Format(unsigned short i_usID, RequestConstPtr ci_rqp, ResponseConstPtr ci_rsp) {
bool bTCFatal = true;
unsigned short usRRs;
try {
m_ofPos = 0;
m_ofRollBack = 0;
this->WriteNBO(i_usID);
this->WriteBits( (ci_rsp!=NULL),
XBIT(ci_rqp->GetOpcode(),3),
XBIT(ci_rqp->GetOpcode(),2),
XBIT(ci_rqp->GetOpcode(),1),
XBIT(ci_rqp->GetOpcode(),0),
(ci_rsp==NULL)?false:(ci_rsp->GetAA()),
(ci_rsp==NULL)?false:(ci_rsp->GetTC()),
(ci_rqp->GetRD()) );
this->WriteBits( (ci_rsp==NULL)?false:true,
false, false, false,
(ci_rsp==NULL)?false:(XBIT(ci_rsp->GetRCode(),3)),
(ci_rsp==NULL)?false:(XBIT(ci_rsp->GetRCode(),2)),
(ci_rsp==NULL)?false:(XBIT(ci_rsp->GetRCode(),1)),
(ci_rsp==NULL)?false:(XBIT(ci_rsp->GetRCode(),0)) );
this->WriteNBO(ci_rqp->GetQuestionCount());
this->WriteNBO((unsigned short)0);
this->WriteNBO((unsigned short)0);
this->WriteNBO((unsigned short)0);
m_ofRollBack = m_ofPos;
this->WriteQuestion(ci_rqp->GetQuestion());
m_ofRollBack = m_ofPos;
if (ci_rsp!=NULL) {
usRRs = this->WriteRRList(ci_rsp->GetANList());
this->PWriteNBO(usRRs,6);
m_ofRollBack = m_ofPos;
bTCFatal = false;
usRRs = this->WriteRRList(ci_rsp->GetNSList());
this->PWriteNBO(usRRs,8);
m_ofRollBack = m_ofPos;
usRRs = this->WriteRRList(ci_rsp->GetARList());
this->PWriteNBO(usRRs,10);
}
this->Truncate();
} catch (BufferEx &exr) {
LogHandle lh(LF_PACKETFORMAT,LY_ERROR);
lh << "Format exception: " << exr.what();
if (bTCFatal) lh << " (required packet will be truncated; TC set)";
else lh << " (only optional data will be lost; no TC)";
lh << LY_DEBUG << "rollback from " << m_ofPos << " to " << m_ofRollBack; lh();
m_ofPos = (size_t)m_ofRollBack;
this->Truncate();
assert(m_szBuffer>=12);
if (bTCFatal) this->WriteBit(true,2,1);
}
}
void DNSPacket::Parse(unsigned short &io_usrID, RequestPtr &o_rqpr, ResponsePtr &o_rspr) const {
bool bQR, bOp3, bOp2, bOp1, bOp0, bAA, bTC, bRD;
bool bRA, bZ2, bZ1, bZ0, bRC3, bRC2, bRC1, bRC0;
unsigned short usQDCount, usANCount, usNSCount, usARCount;
QuestionPtr qnp = NULL;
RRListPtr rlpAN = NULL;
RRListPtr rlpNS = NULL;
RRListPtr rlpAR = NULL;
o_rqpr = NULL;
o_rspr = NULL;
m_ofPos = 0;
try {
this->ReadNBO(io_usrID);
this->ReadBits(bQR,bOp3,bOp2,bOp1,bOp0,bAA,bTC,bRD);
this->ReadBits(bRA,bZ2,bZ1,bZ0,bRC3,bRC2,bRC1,bRC0);
this->ReadNBO(usQDCount);
assert(usQDCount==1);
this->ReadNBO(usANCount);
this->ReadNBO(usNSCount);
this->ReadNBO(usARCount);
this->ReadQuestion(qnp);
if (bQR==true) {
this->ReadRRList(rlpAN,usANCount);
this->ReadRRList(rlpNS,usNSCount);
this->ReadRRList(rlpAR,usARCount);
}
} catch (BufferEx &exr) {
LogHandle lh(LF_PACKETFORMAT,LY_ERROR);
lh << "Read exception:" << exr.what() << " (packet will be discarded)";
lh << LY_DEBUG;
this->DumpRange(lh,0,this->GetSize());
lh();
return;
}
o_rqpr = new Request(bRD,(Opcode)FromBits(bOp3,bOp2,bOp1,bOp0),qnp);
if (bQR)
o_rspr = new Response(bAA,bTC,(RCode)FromBits(bRC3,bRC2,bRC1,bRC0),rlpAN,rlpNS,rlpAR);
assert(qnp==NULL);
assert(rlpAN==NULL);
assert(rlpNS==NULL);
assert(rlpAR==NULL);
}
void DNSPacket::ReadQuestion(QuestionPtr &o_qnpr) const {
LabelListPtr llp = NULL;
unsigned short us;
RRType ty;
RRClass cl;
this->ReadLabelList(llp,true);
this->ReadNBO(us); ty = (RRType)us;
this->ReadNBO(us); cl = (RRClass)us;
o_qnpr = new Question(llp,ty,cl);
}
void DNSPacket::ReadRR(RRPtr &o_rrpr) const {
LabelListPtr llpName;
unsigned short us;
RRType ty;
RRClass cl;
unsigned uTTL;
RDataPtr rdp;
this->ReadLabelList(llpName,true);
this->ReadNBO(us); ty = (RRType)us;
this->ReadNBO(us); cl = (RRClass)us;
this->ReadNBO(uTTL);
rdp = RData::New(ty,cl);
rdp->ReadRData(this);
o_rrpr = RRFactory::NewRR(llpName,ty,cl,uTTL,rdp);
}
void DNSPacket::ReadRRList(RRListPtr &o_rlpr, unsigned short i_usCount) const {
unsigned short us;
RRPtr rrp;
o_rlpr = new RRList;
for(us=0;us<i_usCount;us++) {
this->ReadRR(rrp);
o_rlpr->push_back(rrp);
}
}
void DNSPacket::WriteQuestion(QuestionConstPtr ci_qnp) {
if (ci_qnp==NULL) return;
this->WriteLabelList(ci_qnp->GetName(),true);
this->WriteNBO((unsigned short)ci_qnp->GetType());
this->WriteNBO((unsigned short)ci_qnp->GetClass());
}
void DNSPacket::WriteRR(RRConstPtr ci_rrp) {
this->WriteLabelList(ci_rrp->GetName(),true);
this->WriteNBO((unsigned short)ci_rrp->GetType());
this->WriteNBO((unsigned short)ci_rrp->GetClass());
this->WriteNBO((unsigned)ci_rrp->GetTTL());
ci_rrp->GetRData()->WriteRData(this);
}
unsigned short DNSPacket::WriteRRList(RRListConstPtr ci_rlp) {
RRList::const_iterator c_rrpi;
unsigned short usCount = 0;
if (ci_rlp==NULL) return 0;
for(c_rrpi=ci_rlp->begin();c_rrpi!=ci_rlp->end();++c_rrpi) {
this->WriteRR(*c_rrpi);
usCount++;
}
return usCount;
}
DNSPacket::~DNSPacket() {
SoftDelete(m_sipRemote);
}
ostream& operator<<(ostream& io_smr, const DNSPacket &ci_dpr) {
io_smr << (const Buffer&)ci_dpr;
return io_smr;
}
ostream& operator<<(ostream& io_smr, DNSPacketConstPtr ci_dpp) {
io_smr << *ci_dpp;
return io_smr;
}