| 1 | #include "dnswriter.hh" |
|---|
| 2 | #include "misc.hh" |
|---|
| 3 | #include "dnsparser.hh" |
|---|
| 4 | |
|---|
| 5 | DNSPacketWriter::DNSPacketWriter(vector<uint8_t>& content, const string& qname, uint16_t qtype, uint16_t qclass) |
|---|
| 6 | : d_pos(0), d_content(content), d_qname(qname), d_qtype(qtype), d_qclass(qclass) |
|---|
| 7 | { |
|---|
| 8 | d_content.clear(); |
|---|
| 9 | dnsheader dnsheader; |
|---|
| 10 | |
|---|
| 11 | memset(&dnsheader, 0, sizeof(dnsheader)); |
|---|
| 12 | dnsheader.id=0; |
|---|
| 13 | dnsheader.qdcount=htons(1); |
|---|
| 14 | |
|---|
| 15 | const uint8_t* ptr=(const uint8_t*)&dnsheader; |
|---|
| 16 | d_content.insert(d_content.end(), ptr, ptr + sizeof(dnsheader)); |
|---|
| 17 | |
|---|
| 18 | xfrLabel(qname, false); |
|---|
| 19 | d_content.insert(d_content.end(), d_record.begin(), d_record.end()); |
|---|
| 20 | d_record.clear(); |
|---|
| 21 | |
|---|
| 22 | qtype=htons(qtype); |
|---|
| 23 | ptr=(const uint8_t*)&qtype; |
|---|
| 24 | d_content.insert(d_content.end(), ptr, ptr+2); |
|---|
| 25 | |
|---|
| 26 | qclass=htons(qclass); |
|---|
| 27 | ptr=(const uint8_t*)&qclass; |
|---|
| 28 | d_content.insert(d_content.end(), ptr, ptr+2); |
|---|
| 29 | } |
|---|
| 30 | |
|---|
| 31 | DNSPacketWriter::dnsheader* DNSPacketWriter::getHeader() |
|---|
| 32 | { |
|---|
| 33 | return (dnsheader*)&*d_content.begin(); |
|---|
| 34 | } |
|---|
| 35 | |
|---|
| 36 | void DNSPacketWriter::setRD(bool rd) |
|---|
| 37 | { |
|---|
| 38 | dnsheader* dh=reinterpret_cast<dnsheader*>( &*d_content.begin()); |
|---|
| 39 | dh->rd=rd; |
|---|
| 40 | } |
|---|
| 41 | |
|---|
| 42 | void DNSPacketWriter::startRecord(const string& name, uint16_t qtype, uint32_t ttl, uint16_t qclass, Place place) |
|---|
| 43 | { |
|---|
| 44 | if(!d_record.empty()) |
|---|
| 45 | commit(); |
|---|
| 46 | |
|---|
| 47 | d_recordqname=name; |
|---|
| 48 | d_recordqtype=qtype; |
|---|
| 49 | d_recordqclass=qclass; |
|---|
| 50 | d_recordttl=ttl; |
|---|
| 51 | |
|---|
| 52 | d_stuff = 0; |
|---|
| 53 | |
|---|
| 54 | xfrLabel(d_recordqname, true); |
|---|
| 55 | d_content.insert(d_content.end(), d_record.begin(), d_record.end()); |
|---|
| 56 | d_record.clear(); |
|---|
| 57 | |
|---|
| 58 | d_stuff = sizeof(dnsrecordheader); // this is needed to get compressed label offsets right, the dnsrecordheader will be interspersed |
|---|
| 59 | |
|---|
| 60 | dnsheader* dh=reinterpret_cast<dnsheader*>( &*d_content.begin()); |
|---|
| 61 | switch(place) { |
|---|
| 62 | case ANSWER: |
|---|
| 63 | dh->ancount = htons(ntohs(dh->ancount) + 1); |
|---|
| 64 | break; |
|---|
| 65 | case AUTHORITY: |
|---|
| 66 | dh->nscount = htons(ntohs(dh->nscount) + 1); |
|---|
| 67 | break; |
|---|
| 68 | case ADDITIONAL: |
|---|
| 69 | dh->arcount = htons(ntohs(dh->arcount) + 1); |
|---|
| 70 | break; |
|---|
| 71 | } |
|---|
| 72 | } |
|---|
| 73 | |
|---|
| 74 | void DNSPacketWriter::addOpt(int udpsize, int extRCode, int Z) |
|---|
| 75 | { |
|---|
| 76 | uint32_t ttl=0; |
|---|
| 77 | struct Stuff { |
|---|
| 78 | uint8_t extRCode, version; |
|---|
| 79 | uint16_t Z; |
|---|
| 80 | } __attribute__((packed)); |
|---|
| 81 | |
|---|
| 82 | Stuff stuff; |
|---|
| 83 | |
|---|
| 84 | stuff.extRCode=extRCode; |
|---|
| 85 | stuff.version=0; |
|---|
| 86 | stuff.Z=htons(Z); |
|---|
| 87 | |
|---|
| 88 | memcpy(&ttl, &stuff, sizeof(stuff)); |
|---|
| 89 | cout<<sizeof(stuff)<<endl; |
|---|
| 90 | ttl=ntohl(ttl); // will be reversed later on |
|---|
| 91 | |
|---|
| 92 | startRecord("", ns_t_opt, ttl, udpsize, ADDITIONAL); |
|---|
| 93 | } |
|---|
| 94 | |
|---|
| 95 | void DNSPacketWriter::xfr32BitInt(uint32_t val) |
|---|
| 96 | { |
|---|
| 97 | uint8_t* ptr=reinterpret_cast<uint8_t*>(&val); |
|---|
| 98 | d_record.insert(d_record.end(), ptr, ptr+4); |
|---|
| 99 | } |
|---|
| 100 | |
|---|
| 101 | void DNSPacketWriter::xfr16BitInt(uint16_t val) |
|---|
| 102 | { |
|---|
| 103 | uint8_t* ptr=reinterpret_cast<uint8_t*>(&val); |
|---|
| 104 | d_record.insert(d_record.end(), ptr, ptr+2); |
|---|
| 105 | } |
|---|
| 106 | |
|---|
| 107 | void DNSPacketWriter::xfr8BitInt(uint8_t val) |
|---|
| 108 | { |
|---|
| 109 | d_record.push_back(val); |
|---|
| 110 | } |
|---|
| 111 | |
|---|
| 112 | void DNSPacketWriter::xfrText(const string& text) |
|---|
| 113 | { |
|---|
| 114 | d_record.push_back(text.length()); |
|---|
| 115 | const uint8_t* ptr=(uint8_t*)(text.c_str()); |
|---|
| 116 | d_record.insert(d_record.end(), ptr, ptr+text.size()); |
|---|
| 117 | } |
|---|
| 118 | |
|---|
| 119 | |
|---|
| 120 | void DNSPacketWriter::xfrLabel(const string& label, bool compress) |
|---|
| 121 | { |
|---|
| 122 | typedef vector<string> parts_t; |
|---|
| 123 | parts_t parts; |
|---|
| 124 | stringtok(parts, label, "."); |
|---|
| 125 | |
|---|
| 126 | string enc; |
|---|
| 127 | unsigned int pos=d_content.size() + d_record.size() + d_stuff; // d_stuff is amount of stuff that is yet to be written out - the dnsrecordheader for example |
|---|
| 128 | string chopped(label); |
|---|
| 129 | |
|---|
| 130 | for(parts_t::const_iterator i=parts.begin(); i!=parts.end(); ++i) { |
|---|
| 131 | map<string, uint16_t>::iterator li; |
|---|
| 132 | if(compress && (li=d_labelmap.find(chopped))!=d_labelmap.end()) { // see if we've written out this domain before |
|---|
| 133 | uint16_t offset=li->second; |
|---|
| 134 | offset|=0xc000; |
|---|
| 135 | enc.append(1, (char)(offset >> 8)); |
|---|
| 136 | enc.append(1, (char)(offset & 0xff)); |
|---|
| 137 | goto out; // skip trailing 0 in case of compression |
|---|
| 138 | } |
|---|
| 139 | else if(compress || d_labelmap.count(chopped)) { // if 'compress' is true, li will be equal to d_labelmap.end() |
|---|
| 140 | d_labelmap[chopped]=pos; // if untrue, we need to count |
|---|
| 141 | } |
|---|
| 142 | enc.append(1, (char)i->length()); |
|---|
| 143 | enc.append(*i); |
|---|
| 144 | pos+=i->length()+1; |
|---|
| 145 | chopOff(chopped); // www.powerdns.com -> powerdns.com -> com |
|---|
| 146 | } |
|---|
| 147 | enc.append(1,(char)0); |
|---|
| 148 | |
|---|
| 149 | out:; |
|---|
| 150 | |
|---|
| 151 | const uint8_t* ptr=reinterpret_cast<const uint8_t*>(enc.c_str()); |
|---|
| 152 | d_record.insert(d_record.end(), ptr, ptr+enc.size()); |
|---|
| 153 | } |
|---|
| 154 | |
|---|
| 155 | void DNSPacketWriter::xfrBlob(const string& blob) |
|---|
| 156 | { |
|---|
| 157 | const uint8_t* ptr=reinterpret_cast<const uint8_t*>(blob.c_str()); |
|---|
| 158 | |
|---|
| 159 | d_record.insert(d_record.end(), ptr, ptr+blob.size()); |
|---|
| 160 | } |
|---|
| 161 | |
|---|
| 162 | |
|---|
| 163 | void DNSPacketWriter::commit() |
|---|
| 164 | { |
|---|
| 165 | // build dnsrecordheader |
|---|
| 166 | struct dnsrecordheader drh; |
|---|
| 167 | drh.d_type=htons(d_recordqtype); |
|---|
| 168 | drh.d_class=htons(d_recordqclass); |
|---|
| 169 | drh.d_ttl=htonl(d_recordttl); |
|---|
| 170 | drh.d_clen=htons(d_record.size()); |
|---|
| 171 | |
|---|
| 172 | // and write out the header |
|---|
| 173 | const uint8_t* ptr=(const uint8_t*)&drh; |
|---|
| 174 | d_content.insert(d_content.end(), ptr, ptr+sizeof(drh)); |
|---|
| 175 | |
|---|
| 176 | // write out d_record |
|---|
| 177 | d_content.insert(d_content.end(), d_record.begin(), d_record.end()); |
|---|
| 178 | |
|---|
| 179 | d_record.clear(); // clear d_record, ready for next record |
|---|
| 180 | } |
|---|
| 181 | |
|---|
| 182 | |
|---|
| 183 | |
|---|
| 184 | |
|---|
| 185 | |
|---|
| 186 | |
|---|