]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnswriter.hh
the all new label compression code that is 40% faster even on fast malloc. This commi...
[thirdparty/pdns.git] / pdns / dnswriter.hh
1 /*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22 #ifndef PDNS_DNSWRITER_HH
23 #define PDNS_DNSWRITER_HH
24
25 #include <string>
26 #include <vector>
27 #include <map>
28 #include "dns.hh"
29 #include "dnsname.hh"
30 #include "namespaces.hh"
31 #include <arpa/inet.h>
32
33
34 /** this class can be used to write DNS packets. It knows about DNS in the sense that it makes
35 the packet header and record headers.
36
37 The model is:
38
39 packetheader (recordheader recordcontent)*
40
41 The packetheader needs to be updated with the amount of packets of each kind (answer, auth, additional)
42
43 Each recordheader contains the length of a dns record.
44
45 Calling convention:
46
47 vector<uint8_t> content;
48 DNSPacketWriter dpw(content, const string& qname, uint16_t qtype, uint16_t qclass=QClass:IN); // sets the question
49 dpw.startrecord("this.is.an.ip.address.", ns_t_a); // does nothing, except store qname and qtype
50 dpw.xfr32BitInt(0x01020304); // adds 4 bytes (0x01020304) to the record buffer
51 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
52 // new qname and qtype are stored
53 dpw.xfr32BitInt(0x04030201); // adds 4 bytes (0x04030201) to the record buffer
54 dpw.commit(); // writes out dnsrecord header containing qname and qtype and length 4, plus the recordbuffer
55
56 // content now contains the ready packet, with 1 question and 2 answers
57
58 */
59
60 class DNSPacketWriter : public boost::noncopyable
61 {
62
63 public:
64 //! Start a DNS Packet in the vector passed, with question qname, qtype and qclass
65 DNSPacketWriter(vector<uint8_t>& content, const DNSName& qname, uint16_t qtype, uint16_t qclass=QClass::IN, uint8_t opcode=0);
66
67 /** 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 -
68 ANSWER, AUTHORITY, ADDITIONAL */
69 void startRecord(const DNSName& name, uint16_t qtype, uint32_t ttl=3600, uint16_t qclass=QClass::IN, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, bool compress=true);
70
71 /** Shorthand way to add an Opt-record, for example for EDNS0 purposes */
72 typedef vector<pair<uint16_t,std::string> > optvect_t;
73 void addOpt(uint16_t udpsize, int extRCode, int Z, const optvect_t& options=optvect_t());
74
75 /** 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.
76 The content of the vector<> passed to the constructor is inconsistent until commit is called.
77 */
78 void commit();
79
80 uint32_t size(); // needs to be 32 bit because otherwise we don't see the wrap coming when it happened!
81
82 /** Should the packet have grown too big for the writer's liking, rollback removes the record currently being written */
83 void rollback();
84
85 /** Discard all content except the question section */
86 void truncate();
87
88 void xfr48BitInt(uint64_t val);
89 void xfr32BitInt(uint32_t val);
90 void xfr16BitInt(uint16_t val);
91 void xfrType(uint16_t val)
92 {
93 xfr16BitInt(val);
94 }
95 void xfrIP(const uint32_t& val)
96 {
97 xfr32BitInt(htonl(val));
98 }
99 void xfrIP6(const std::string& val)
100 {
101 xfrBlob(val,16);
102 }
103 void xfrTime(const uint32_t& val)
104 {
105 xfr32BitInt(val);
106 }
107
108 void xfr8BitInt(uint8_t val);
109
110 void xfrName(const DNSName& label, bool compress=false, bool noDot=false);
111 void xfrText(const string& text, bool multi=false, bool lenField=true);
112 void xfrUnquotedText(const string& text, bool lenField);
113 void xfrBlob(const string& blob, int len=-1);
114 void xfrBlobNoSpaces(const string& blob, int len=-1);
115 void xfrHexBlob(const string& blob, bool keepReading=false);
116
117 uint16_t d_pos;
118
119 dnsheader* getHeader();
120 void getRecords(string& records);
121 const vector<uint8_t>& getRecordBeingWritten() { return d_record; }
122
123 void setCanonic(bool val)
124 {
125 d_canonic=val;
126 }
127
128 void setLowercase(bool val)
129 {
130 d_lowerCase=val;
131 }
132 vector <uint8_t>& getContent()
133 {
134 return d_content;
135 }
136 bool eof() { return true; } // we don't know how long the record should be
137
138 private:
139 uint16_t lookupName(const DNSName& name, uint16_t* matchlen);
140 vector<uint16_t> d_positions;
141 // We declare 1 uint_16 in the public section, these 3 align on a 8-byte boundry
142 uint16_t d_stuff;
143 uint16_t d_sor;
144 uint16_t d_rollbackmarker; // start of last complete packet, for rollback
145
146 vector <uint8_t>& d_content;
147 vector <uint8_t> d_record;
148 DNSName d_qname;
149 DNSName d_recordqname;
150
151 uint32_t d_recordttl;
152 uint16_t d_recordqtype, d_recordqclass;
153
154 uint16_t d_truncatemarker; // end of header, for truncate
155 DNSResourceRecord::Place d_recordplace;
156 bool d_canonic, d_lowerCase;
157 };
158
159 typedef vector<pair<string::size_type, string::size_type> > labelparts_t;
160 // bool labeltokUnescape(labelparts_t& parts, const DNSName& label);
161 std::vector<string> segmentDNSText(const string& text); // from dnslabeltext.rl
162 std::deque<string> segmentDNSName(const string& input ); // from dnslabeltext.rl
163 #endif