| 1 | #ifndef PDNS_DNSWRITER_HH |
|---|
| 2 | #define PDNS_DNSWRITER_HH |
|---|
| 3 | |
|---|
| 4 | #include <string> |
|---|
| 5 | #include <vector> |
|---|
| 6 | #include <map> |
|---|
| 7 | #if !defined SOLARIS8 && !defined WIN32 |
|---|
| 8 | #include <stdint.h> |
|---|
| 9 | #elif defined WIN32 |
|---|
| 10 | #include "utility.hh" |
|---|
| 11 | #endif |
|---|
| 12 | #include "dns.hh" |
|---|
| 13 | using namespace std; |
|---|
| 14 | |
|---|
| 15 | /** this class can be used to write DNS packets. It knows about DNS in the sense that it makes |
|---|
| 16 | the packet header and record headers. |
|---|
| 17 | |
|---|
| 18 | The model is: |
|---|
| 19 | |
|---|
| 20 | packetheader (recordheader recordcontent)* |
|---|
| 21 | |
|---|
| 22 | The packetheader needs to be updated with the amount of packets of each kind (answer, auth, additional) |
|---|
| 23 | |
|---|
| 24 | Each recordheader contains the length of a dns record. |
|---|
| 25 | |
|---|
| 26 | Calling convention: |
|---|
| 27 | |
|---|
| 28 | vector<uint8_t> content; |
|---|
| 29 | DNSPacketWriter dpw(content, const string& qname, uint16_t qtype, uint16_t qclass=1); // sets the question |
|---|
| 30 | dpw.startrecord("this.is.an.ip.address.", ns_t_a); // does nothing, except store qname and qtype |
|---|
| 31 | dpw.xfr32BitInt(0x01020304); // adds 4 bytes (0x01020304) to the record buffer |
|---|
| 32 | dpw.startrecord("this.is.an.ip.address.", ns_t_a); // aha! writes out dnsrecord header containing qname and qtype and length 4, plus the recordbuffer, which gets emptied |
|---|
| 33 | // new qname and qtype are stored |
|---|
| 34 | dpw.xfr32BitInt(0x04030201); // adds 4 bytes (0x04030201) to the record buffer |
|---|
| 35 | dpw.commit(); // writes out dnsrecord header containing qname and qtype and length 4, plus the recordbuffer |
|---|
| 36 | |
|---|
| 37 | // content now contains the ready packet, with 1 question and 2 answers |
|---|
| 38 | |
|---|
| 39 | */ |
|---|
| 40 | |
|---|
| 41 | class DNSPacketWriter |
|---|
| 42 | { |
|---|
| 43 | |
|---|
| 44 | public: |
|---|
| 45 | typedef vector<pair<string, uint16_t> > lmap_t; |
|---|
| 46 | enum Place {ANSWER=1, AUTHORITY=2, ADDITIONAL=3}; |
|---|
| 47 | |
|---|
| 48 | //! Start a DNS Packet in the vector passed, with question qname, qtype and qclass |
|---|
| 49 | DNSPacketWriter(vector<uint8_t>& content, const string& qname, uint16_t qtype, uint16_t qclass=1, uint8_t opcode=0); |
|---|
| 50 | |
|---|
| 51 | /** Start a new DNS record within this packet for namq, qtype, ttl, class and in the requested place. Note that packets can only be written in natural order - |
|---|
| 52 | ANSWER, AUTHORITY, ADDITIONAL */ |
|---|
| 53 | void startRecord(const string& name, uint16_t qtype, uint32_t ttl=3600, uint16_t qclass=1, Place place=ANSWER); |
|---|
| 54 | |
|---|
| 55 | /** Shorthand way to add an Opt-record, for example for EDNS0 purposes */ |
|---|
| 56 | typedef vector<pair<uint16_t,std::string> > optvect_t; |
|---|
| 57 | void addOpt(int udpsize, int extRCode, int Z, const optvect_t& options=optvect_t()); |
|---|
| 58 | |
|---|
| 59 | /** needs to be called after the last record is added, but can be called again and again later on. Is called internally by startRecord too. |
|---|
| 60 | The content of the vector<> passed to the constructor is inconsistent until commit is called. |
|---|
| 61 | */ |
|---|
| 62 | void commit(); |
|---|
| 63 | |
|---|
| 64 | uint16_t size(); |
|---|
| 65 | |
|---|
| 66 | /** Should the packet have grown too big for the writer's liking, rollback removes the record currently being written */ |
|---|
| 67 | void rollback(); |
|---|
| 68 | |
|---|
| 69 | void xfr48BitInt(uint64_t val); |
|---|
| 70 | void xfr32BitInt(uint32_t val); |
|---|
| 71 | void xfr16BitInt(uint16_t val); |
|---|
| 72 | void xfrType(uint16_t val) |
|---|
| 73 | { |
|---|
| 74 | xfr16BitInt(val); |
|---|
| 75 | } |
|---|
| 76 | void xfrIP(const uint32_t& val) |
|---|
| 77 | { |
|---|
| 78 | xfr32BitInt(htonl(val)); |
|---|
| 79 | } |
|---|
| 80 | void xfrTime(const uint32_t& val) |
|---|
| 81 | { |
|---|
| 82 | xfr32BitInt(val); |
|---|
| 83 | } |
|---|
| 84 | |
|---|
| 85 | void xfr8BitInt(uint8_t val); |
|---|
| 86 | |
|---|
| 87 | void xfrLabel(const string& label, bool compress=false); |
|---|
| 88 | void xfrText(const string& text, bool multi=false); |
|---|
| 89 | void xfrBlob(const string& blob, int len=-1); |
|---|
| 90 | void xfrHexBlob(const string& blob); |
|---|
| 91 | |
|---|
| 92 | uint16_t d_pos; |
|---|
| 93 | |
|---|
| 94 | dnsheader* getHeader(); |
|---|
| 95 | void getRecords(string& records); |
|---|
| 96 | const vector<uint8_t>& getRecordBeingWritten() { return d_record; } |
|---|
| 97 | |
|---|
| 98 | private: |
|---|
| 99 | vector <uint8_t>& d_content; |
|---|
| 100 | vector <uint8_t> d_record; |
|---|
| 101 | string d_qname; |
|---|
| 102 | uint16_t d_qtype, d_qclass; |
|---|
| 103 | string d_recordqname; |
|---|
| 104 | uint16_t d_recordqtype, d_recordqclass; |
|---|
| 105 | uint32_t d_recordttl; |
|---|
| 106 | lmap_t d_labelmap; |
|---|
| 107 | uint16_t d_stuff; |
|---|
| 108 | uint16_t d_sor; |
|---|
| 109 | uint16_t d_rollbackmarker; // start of last complete packet, for rollback |
|---|
| 110 | Place d_recordplace; |
|---|
| 111 | }; |
|---|
| 112 | #endif |
|---|