#include <limits.h>
+/* d_content: <---- d_stuff ---->
+ v d_truncatemarker
+ dnsheader | qname | qtype | qclass | {recordname| dnsrecordheader | record }
+ ^ d_rollbackmarker ^ d_sor
+
+
+*/
+
+
DNSPacketWriter::DNSPacketWriter(vector<uint8_t>& content, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint8_t opcode)
: d_content(content), d_qname(qname), d_canonic(false), d_lowerCase(false)
{
uint8_t* dptr=(&*d_content.begin()) + len;
memcpy(dptr, ptr, sizeof(dnsheader));
- d_stuff=0;
d_namepositions.reserve(16);
xfrName(qname, false);
+ xfr16BitInt(qtype);
+ xfr16BitInt(qclass);
- len=d_content.size();
- d_content.resize(len + d_record.size() + 4);
-
- ptr=&*d_record.begin();
- dptr=(&*d_content.begin()) + len;
-
- memcpy(dptr, ptr, d_record.size());
-
- len+=d_record.size();
- d_record.clear();
-
- qtype=htons(qtype);
- qclass=htons(qclass);
-
- vector<uint8_t>::iterator i=d_content.begin()+len; // this works around a gcc 3.4 bug
- memcpy(&*i, &qtype, 2);
- i+=2;
- memcpy(&*i, &qclass, 2);
-
- d_stuff=0xffff;
d_truncatemarker=d_content.size();
d_sor = 0;
d_rollbackmarker = 0;
- d_recordttl = 0;
- d_recordqtype = 0;
- d_recordqclass = QClass::IN;
- d_recordplace = DNSResourceRecord::ANSWER;
}
dnsheader* DNSPacketWriter::getHeader()
return reinterpret_cast<dnsheader*>(&*d_content.begin());
}
+
void DNSPacketWriter::startRecord(const DNSName& name, uint16_t qtype, uint32_t ttl, uint16_t qclass, DNSResourceRecord::Place place, bool compress)
{
- if(!d_record.empty())
- commit();
-
- d_recordqname=name;
- d_recordqtype=qtype;
- d_recordqclass=qclass;
- d_recordttl=ttl;
- d_recordplace=place;
-
- d_stuff = 0;
+ commit();
d_rollbackmarker=d_content.size();
- if(compress && d_recordqname.countLabels() && d_qname==d_recordqname) { // don't do the whole label compression thing if we *know* we can get away with "see question" - except when compressing the root
+ if(compress && !name.empty() && d_qname==name) { // don't do the whole label compression thing if we *know* we can get away with "see question" - except when compressing the root
static unsigned char marker[2]={0xc0, 0x0c};
d_content.insert(d_content.end(), (const char *) &marker[0], (const char *) &marker[2]);
}
else {
- xfrName(d_recordqname, compress);
- d_content.insert(d_content.end(), d_record.begin(), d_record.end());
- d_record.clear();
+ xfrName(name, compress);
}
-
- d_stuff = sizeof(dnsrecordheader); // this is needed to get compressed label offsets right, the dnsrecordheader will be interspersed
- d_sor=d_content.size() + d_stuff; // start of real record
+ xfr16BitInt(qtype);
+ xfr16BitInt(qclass);
+ xfr32BitInt(ttl);
+ xfr16BitInt(0); // this will be the record size
+ d_recordplace = place;
+ d_sor=d_content.size(); // this will remind us where to stuff the record size
}
void DNSPacketWriter::addOpt(uint16_t udpsize, int extRCode, int Z, const vector<pair<uint16_t,string> >& options)
memcpy(bytes, (void*)&theLeft, sizeof(theLeft));
memcpy(bytes+2, (void*)&theRight, sizeof(theRight));
- d_record.insert(d_record.end(), bytes, bytes + sizeof(bytes));
+ d_content.insert(d_content.end(), bytes, bytes + sizeof(bytes));
}
{
int rval=htonl(val);
uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
- d_record.insert(d_record.end(), ptr, ptr+4);
+ d_content.insert(d_content.end(), ptr, ptr+4);
}
void DNSPacketWriter::xfr16BitInt(uint16_t val)
{
uint16_t rval=htons(val);
uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
- d_record.insert(d_record.end(), ptr, ptr+2);
+ d_content.insert(d_content.end(), ptr, ptr+2);
}
void DNSPacketWriter::xfr8BitInt(uint8_t val)
{
- d_record.push_back(val);
+ d_content.push_back(val);
}
void DNSPacketWriter::xfrText(const string& text, bool, bool lenField)
{
if(text.empty()) {
- d_record.push_back(0);
+ d_content.push_back(0);
return;
}
vector<string> segments = segmentDNSText(text);
for(const string& str : segments) {
if(lenField)
- d_record.push_back(str.length());
- d_record.insert(d_record.end(), str.c_str(), str.c_str() + str.length());
+ d_content.push_back(str.length());
+ d_content.insert(d_content.end(), str.c_str(), str.c_str() + str.length());
}
}
void DNSPacketWriter::xfrUnquotedText(const string& text, bool lenField)
{
if(text.empty()) {
- d_record.push_back(0);
+ d_content.push_back(0);
return;
}
if(lenField)
- d_record.push_back(text.length());
- d_record.insert(d_record.end(), text.c_str(), text.c_str() + text.length());
+ d_content.push_back(text.length());
+ d_content.insert(d_content.end(), text.c_str(), text.c_str() + text.length());
}
cout<<"Have "<<d_namepositions.size()<<" to ponder"<<endl;
int counter=1;
for(auto p : d_namepositions) {
- vector<uint8_t>* source=0;
- if(p < d_content.size())
- source = &d_content;
- else {
- source = &d_record;
- p-= (d_content.size() + d_stuff);
-
- }
if(l_verbose) {
- if(source == &d_content) {
- DNSName pname((const char*)&(*source)[0], (*source).size(), p, true); // only for debugging
- cout<<"Looking at '"<<pname<<"' in packet at position "<<p<<"/"<<(*source).size()<<", option "<<counter<<"/"<<d_namepositions.size()<<endl;
- }
- else
- {
- cout<<"Looking at *record* at position "<<p<<"/"<<(*source).size()<<", option "<<counter<<"/"<<d_namepositions.size()<<endl;
- }
+ cout<<"Pos: "<<p<<", "<<d_content.size()<<endl;
+ DNSName pname((const char*)&d_content[0], d_content.size(), p, true); // only for debugging
+ cout<<"Looking at '"<<pname<<"' in packet at position "<<p<<"/"<<d_content.size()<<", option "<<counter<<"/"<<d_namepositions.size()<<endl;
++counter;
}
// memcmp here makes things _slower_
pvect.clear();
- for(auto iter = (*source).cbegin() + p; iter < (*source).cend();) {
+ for(auto iter = d_content.cbegin() + p; iter < d_content.cend();) {
uint8_t c=*iter;
if(l_verbose)
if(c & 0xc0) {
uint16_t npos = 0x100*(c & (~0xc0)) + *++iter;
- iter = (*source).begin() + npos;
+ iter = d_content.begin() + npos;
if(l_verbose)
cout<<"Is compressed label to newpos "<<npos<<", going there"<<endl;
// check against going forward here
}
if(!c)
break;
- pvect.push_back(iter - (*source).cbegin());
+ pvect.push_back(iter - d_content.cbegin());
iter+=*iter+1;
}
if(l_verbose) {
unsigned int cmatchlen=1;
for(; niter != nvect.crend() && piter != pvect.crend(); ++niter, ++piter) {
// niter is an offset in raw, pvect an offset in packet
- uint8_t nlen = raw[*niter], plen=(*source)[*piter];
+ uint8_t nlen = raw[*niter], plen=d_content[*piter];
if(l_verbose)
cout<<"nlnen="<<(int)nlen<<", plen="<<(int)plen<<endl;
if(nlen != plen)
break;
- if(strncasecmp(raw.c_str()+*niter+1, (const char*)&(*source)[*piter]+1, nlen)) {
+ if(strncasecmp(raw.c_str()+*niter+1, (const char*)&d_content[*piter]+1, nlen)) {
if(l_verbose)
- cout<<"Mismatch: "<<string(raw.c_str()+*niter+1, raw.c_str()+*niter+nlen+1)<< " != "<<string((const char*)&(*source)[*piter]+1, (const char*)&(*source)[*piter]+nlen+1)<<endl;
+ cout<<"Mismatch: "<<string(raw.c_str()+*niter+1, raw.c_str()+*niter+nlen+1)<< " != "<<string((const char*)&d_content[*piter]+1, (const char*)&d_content[*piter]+nlen+1)<<endl;
break;
}
cmatchlen+=nlen+1;
compress=false;
if(name.empty() || name.isRoot()) { // for speed
- d_record.push_back(0);
+ d_content.push_back(0);
return;
}
cout<<"Found a substring of "<<matchlen<<" bytes from the back, offset: "<<li<<", dnslen: "<<dns.size()<<endl;
// found a substring, if www.powerdns.com matched powerdns.com, we get back matchlen = 13
- unsigned int pos=d_content.size() + d_record.size() + d_stuff;
+ unsigned int pos=d_content.size();
if(pos < 16384 && matchlen != dns.size()) {
if(l_verbose)
cout<<"Inserting pos "<<pos<<" for "<<name<<" for compressed case"<<endl;
if(l_verbose)
cout<<"Going to write unique part: '"<<makeHexDump(string(dns.c_str(), dns.c_str() + dns.size() - matchlen)) <<"'"<<endl;
- d_record.insert(d_record.end(), (const unsigned char*)dns.c_str(), (const unsigned char*)dns.c_str() + dns.size() - matchlen);
+ d_content.insert(d_content.end(), (const unsigned char*)dns.c_str(), (const unsigned char*)dns.c_str() + dns.size() - matchlen);
uint16_t offset=li;
offset|=0xc000;
- d_record.push_back((char)(offset >> 8));
- d_record.push_back((char)(offset & 0xff));
+ d_content.push_back((char)(offset >> 8));
+ d_content.push_back((char)(offset & 0xff));
}
else {
- unsigned int pos=d_content.size() + d_record.size() + d_stuff;
+ unsigned int pos=d_content.size();
if(l_verbose)
cout<<"Found nothing, we are at pos "<<pos<<", inserting whole name"<<endl;
if(pos < 16384) {
const DNSName::string_t& raw = (lc ? *lc : name).getStorage();
if(l_verbose)
cout<<"Writing out the whole thing "<<makeHexDump(string(raw.c_str(), raw.c_str() + raw.length()))<<endl;
- d_record.insert(d_record.end(), raw.c_str(), raw.c_str() + raw.size());
+ d_content.insert(d_content.end(), raw.c_str(), raw.c_str() + raw.size());
}
}
void DNSPacketWriter::xfrBlob(const string& blob, int )
{
const uint8_t* ptr=reinterpret_cast<const uint8_t*>(blob.c_str());
- d_record.insert(d_record.end(), ptr, ptr+blob.size());
+ d_content.insert(d_content.end(), ptr, ptr+blob.size());
}
void DNSPacketWriter::xfrBlobNoSpaces(const string& blob, int )
xfrBlob(blob);
}
-void DNSPacketWriter::getRecords(string& records)
+// call __before commit__
+void DNSPacketWriter::getRecordPayload(string& records)
{
records.assign(d_content.begin() + d_sor, d_content.end());
}
uint32_t DNSPacketWriter::size()
{
- return d_content.size() + d_stuff + d_record.size();
+ return d_content.size();
}
void DNSPacketWriter::rollback()
{
d_content.resize(d_rollbackmarker);
- d_record.clear();
- d_stuff=0;
}
void DNSPacketWriter::truncate()
{
d_content.resize(d_truncatemarker);
- d_record.clear();
- d_stuff=0;
dnsheader* dh=reinterpret_cast<dnsheader*>( &*d_content.begin());
dh->ancount = dh->nscount = dh->arcount = 0;
}
void DNSPacketWriter::commit()
{
- if(d_stuff==0xffff && (d_content.size()!=d_sor || !d_record.empty()))
- throw MOADNSException("DNSPacketWriter::commit() called without startRecord ever having been called, but a record was added");
- // build dnsrecordheader
- struct dnsrecordheader drh;
- drh.d_type=htons(d_recordqtype);
- drh.d_class=htons(d_recordqclass);
- drh.d_ttl=htonl(d_recordttl);
- drh.d_clen=htons(d_record.size());
-
- // and write out the header
- const uint8_t* ptr=(const uint8_t*)&drh;
- d_content.insert(d_content.end(), ptr, ptr+sizeof(drh));
-
- d_stuff=0;
-
- // write out pending d_record
- d_content.insert(d_content.end(), d_record.begin(), d_record.end());
-
+ if(!d_sor)
+ return;
+ uint16_t rlen = d_content.size() - d_sor;
+ d_content[d_sor-2]=rlen >> 8;
+ d_content[d_sor-1]=rlen & 0xff;
+ d_sor=0;
dnsheader* dh=reinterpret_cast<dnsheader*>( &*d_content.begin());
switch(d_recordplace) {
case DNSResourceRecord::QUESTION:
break;
}
- d_record.clear(); // clear d_record, ready for next record
}