~ubuntu-branches/ubuntu/maverick/pdns/maverick-updates

« back to all changes in this revision

Viewing changes to pdns/dnspacket.hh

  • Committer: Bazaar Package Importer
  • Author(s): Matthijs Mohlmann, Matthijs Mohlmann, Christoph Haas
  • Date: 2007-04-15 23:23:39 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070415232339-5x3scc8gx04e50um
Tags: 2.9.21-1
[ Matthijs Mohlmann ]
* New upstream release. (Closes: #420294)
* Remove meta pdns package.
* Added new sqlite3 backend package.
* Months and minutes where mixed up. (Closes: #406462)
* Case sensitivity in bind backend caused PowerDNS to not serve a certain
  zone. (Closes: #406461)
* Bind backend forgot about zones on a notify. (Closes: #398213)

[ Christoph Haas ]
* Documented incorporated backend bind. (Closes: #415471)

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
 
14
14
    You should have received a copy of the GNU General Public License
15
15
    along with this program; if not, write to the Free Software
16
 
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
17
*/
18
18
#ifndef DNSPACKET_HH
19
19
 
31
31
#include <cstring>
32
32
#include <cstdlib>
33
33
#include <sys/types.h>
 
34
#include "iputils.hh"
34
35
 
35
36
#ifndef WIN32
36
37
#include <sys/socket.h>
66
67
 
67
68
class DNSBackend;
68
69
 
 
70
/** helper function for both DNSPacket and addSOARecord() - converts a line into a struct, for easier parsing */
 
71
void fillSOAData(const string &content, SOAData &data);
 
72
 
 
73
/** for use by DNSPacket, converts a SOAData class to a ascii line again */
 
74
string serializeSOAData(const SOAData &data);
 
75
 
 
76
string &attodot(string &str);  //!< for when you need to insert an email address in the SOA
 
77
 
69
78
//! This class represents DNS packets, either received or to be sent.
70
79
class DNSPacket
71
80
{
73
82
  DNSPacket();
74
83
  DNSPacket(const DNSPacket &orig);
75
84
 
76
 
  int expand(const unsigned char *begin, const unsigned char *end, string &expanded, int depth=0);
77
 
  inline int parse(const char *mesg, int len); //!< parse a raw UDP or TCP packet and suck the data inward
78
 
  string getString();
79
 
 
80
 
  //! the raw DNS header
81
 
  struct dnsheader 
82
 
  {
83
 
    unsigned int id:16;  //!< id of this query/response
84
 
#ifdef WORDS_BIGENDIAN     // ultrasparc
85
 
    unsigned int qr:1;      //!< 1 if this is a query, 0 if response
86
 
    unsigned int opcode:4;  //!< the opcode
87
 
    unsigned int aa:1;   //!< packet contains authoritative data
88
 
    unsigned int tc:1;   //!< packet is truncated
89
 
    unsigned int rd:1;   //!< this packets wants us to recurse
90
 
    unsigned int ra:1;     //!< ??
91
 
    unsigned int unused:1; //!< 
92
 
    unsigned int ad:1;     //!< authentic data
93
 
    unsigned int cd:1;     //!< checking disabled by resolver
94
 
    unsigned int rcode:4;  //!< ??
95
 
#else
96
 
    unsigned int rd:1;   //!< this packets wants us to recurse
97
 
    unsigned int tc:1;   //!< packet is truncated
98
 
    unsigned int aa:1;   //!< packet contains authoritative data
99
 
    unsigned int opcode:4;  //!< the opcode
100
 
    unsigned int qr:1;      //!< 1 if this is a query, 0 if response
101
 
 
102
 
    /////////// 
103
 
 
104
 
    unsigned int rcode:4;  //!< ??
105
 
    unsigned int cd:1;     //!< checking disabled by resolver
106
 
    unsigned int ad:1;     //!< authentic data
107
 
    unsigned int unused:1; //!< 
108
 
    unsigned int ra:1;     //!< ??
109
 
#endif
110
 
    ////////////////
111
 
    
112
 
    unsigned int qdcount:16;  //!< number of questions
113
 
    unsigned int ancount:16;  //!< number of answers
114
 
    unsigned int nscount:16;  //!< number of authoritative nameservers included in answer
115
 
    unsigned int arcount:16;  //!< number of additional resource records
116
 
  };
117
 
 
118
 
  inline void setRemote(const struct sockaddr *a, Utility::socklen_t socklen);
119
 
  string getLocal() const;
 
85
  int parse(const char *mesg, int len); //!< parse a raw UDP or TCP packet and suck the data inward
 
86
  string getString(); //!< for serialization - just passes the whole packet
 
87
 
 
88
  // address & socket manipulation
 
89
  void setRemote(const ComboAddress*);
120
90
  string getRemote() const;
 
91
  string getLocal() const
 
92
  {
 
93
    ComboAddress ca;
 
94
    socklen_t len=sizeof(ca);
 
95
    getsockname(d_socket, (sockaddr*)&ca, &len);
 
96
    return ca.toString();
 
97
  }
121
98
  uint16_t getRemotePort() const;
122
 
  void setA(bool); //!< make this packet authoritative
123
 
  void setRA(bool); //!< set the Recursion Available flag
124
 
  void setRD(bool); //!< set the Recursion Desired flag
125
 
  void setAnswer(bool); //!< Make this packet an answer
126
 
  void setID(uint16_t); //!< set the DNS id of this packet
127
 
  void setOpcode(uint16_t);  //!< set the Opcode of this packet
128
 
  void setRcode(int v); //!< set the Rcode of this packet
129
 
 
 
99
 
 
100
  Utility::sock_t getSocket() const
 
101
  {
 
102
    return d_socket;
 
103
  }
 
104
  void setSocket(Utility::sock_t sock);
 
105
 
 
106
 
 
107
  // these manipulate 'd'
 
108
  void setA(bool); //!< make this packet authoritative - manipulates 'd'
 
109
  void setID(uint16_t); //!< set the DNS id of this packet - manipulates 'd'
 
110
  void setRA(bool); //!< set the Recursion Available flag - manipulates 'd'
 
111
  void setRD(bool); //!< set the Recursion Desired flag - manipulates 'd'
 
112
  void setAnswer(bool); //!< Make this packet an answer - clears the 'stringbuffer' first, if passed 'true', does nothing otherwise, manipulates 'd'
 
113
 
 
114
  void setOpcode(uint16_t);  //!< set the Opcode of this packet - manipulates 'd'
 
115
  void setRcode(int v); //!< set the Rcode of this packet - manipulates 'd'
 
116
 
 
117
  void clearRecords(); //!< when building a packet, wipe all previously added records (clears 'rrs')
130
118
 
131
119
  /** Add a DNSResourceRecord to this packet. A DNSPacket (as does a DNS Packet) has 4 kinds of resource records. Questions, 
132
120
      Answers, Authority and Additional. See RFC 1034 and 1035 for details. You can specify where a record needs to go in the
133
121
      DNSResourceRecord d_place field */
134
 
  void addRecord(const DNSResourceRecord &); 
135
 
 
136
 
  /** helper function for both DNSPacket and addSOARecord() - converts a line into a struct, for easier parsing */
137
 
  static void fillSOAData(const string &content, SOAData &data);
138
 
 
139
 
  /** for use by DNSPacket, converts a SOAData class to a ascii line again */
140
 
  static string serializeSOAData(const SOAData &data);
141
 
  void setQuestion(int op, const string &qdomain, int qtype);
142
 
  vector<DNSResourceRecord> getAnswers();
143
 
private:
144
 
  string compress(const string &qd);
145
 
  void addARecord(const string&, uint32_t, uint32_t ttl, DNSResourceRecord::Place place); //!< add an A record to the packet
146
 
  void addARecord(const DNSResourceRecord &); //!< add an A record to the packet
147
 
 
148
 
  void addAAAARecord(const string &, unsigned char addr[16], uint32_t ttl, DNSResourceRecord::Place place); //!< add an A record to the packet
149
 
  void addAAAARecord(const DNSResourceRecord &); //!< add an A record to the packet
150
 
 
151
 
 
152
 
  void addMXRecord(const string &domain, const string &mx, int priority, uint32_t ttl); //!< add an MX record to the packet
153
 
  void addMXRecord(const DNSResourceRecord &); //!< add an MX record to the packet
154
 
 
155
 
  void addSRVRecord(const string &domain, const string &srv, int priority, uint32_t ttl); //!< add an SRVMX record to the packet
156
 
  void addSRVRecord(const DNSResourceRecord &); //!< add an SRV record to the packet
157
 
 
158
 
  void addCNAMERecord(const string &domain, const string &alias, uint32_t ttl); //!< add a CNAME record to the packet
159
 
  void addCNAMERecord(const DNSResourceRecord &); //!< add a CNAME record to the packet
160
 
 
161
 
  void addRPRecord(const string &domain, const string &content, uint32_t ttl); //!< add a RP record to the packet
162
 
  void addRPRecord(const DNSResourceRecord &); //!< add a RP record to the packet
163
 
 
164
 
  void addNAPTRRecord(const string &domain, const string &content, uint32_t ttl); //!< add a NAPTR record to the packet
165
 
  void addNAPTRRecord(const DNSResourceRecord &); //!< add a NAPTR record to the packet
166
 
 
167
 
 
168
 
  void addPTRRecord(const string &domain, const string &alias, uint32_t ttl); //!< add a PTR record to the packet
169
 
  void addPTRRecord(const DNSResourceRecord &); //!< add a PTR record to the packet
170
 
 
171
 
  void addLOCRecord(const string &domain, const string &content, uint32_t ttl); 
172
 
  void addLOCRecord(const DNSResourceRecord &); //!< add a LOC record to the packet
173
 
 
174
 
 
175
 
  /** Adds a SOA record to the packet. The SOA record is very special because we have a lot of default values, 
176
 
      that may be overridden by the contents of the database. Content can have a variety of content:
177
 
      
178
 
      (nothing)
179
 
      hostmaster
180
 
      hostmaster serial-number
181
 
      hostmaster serial-number [refresh [retry [expire [ minimum] ] ] ]
182
 
 
183
 
      Suggested values are: 
184
 
 
185
 
      10800           ;refresh every three hours
186
 
      300             ;retry every 5 min
187
 
      604800          ;expire after a week
188
 
      86400           ;default ttl 
189
 
 
190
 
      An empty field means that we supply hostmaster+@+domain name as hostmaster. An empty serial number is replaced by the 
191
 
      number of seconds since 1 jan 1970 (unix timestamp). The other values are substituted as indicated
192
 
 
193
 
  */
194
 
  void addSOARecord(const string &domain, const string &content, uint32_t ttl, DNSResourceRecord::Place place); 
195
 
  void addSOARecord(const DNSResourceRecord &); //!< add a SOA record to the packet
196
 
 
197
 
  void addTXTorSPFRecord(uint16_t qtype, string domain, string, uint32_t ttl); //!< add a TXT or SPF record to the packet
198
 
 
199
 
  void addTXTRecord(const DNSResourceRecord &); //!< add a TXT record to the packet
200
 
  void addSPFRecord(const DNSResourceRecord &); //!< add a SPF record to the packet
201
 
 
202
 
  void addHINFORecord(string domain, string, uint32_t ttl); //!< add a HINFO record to the packet
203
 
  void addHINFORecord(const DNSResourceRecord &); //!< add a HINFO record to the packet
204
 
 
205
 
  void addNSRecord(string domain, string server, uint32_t ttl, DNSResourceRecord::Place place); //!< add an NS record to the packet
206
 
  void addNSRecord(const DNSResourceRecord &); //!< add an NS record to the packet
207
 
  void addGenericRecord(const DNSResourceRecord& rr);
208
 
  static string &attodot(string &str);  //!< for when you need to insert an email address in the SOA
209
 
 
210
 
public:
 
122
  void addRecord(const DNSResourceRecord &);  // adds to 'rrs'
 
123
 
 
124
  void setQuestion(int op, const string &qdomain, int qtype);  // wipes 'd', sets a random id, creates start of packet (label, type, class etc)
211
125
 
212
126
  DTime d_dt; //!< the time this packet was created. replyPacket() copies this in for you, so d_dt becomes the time spent processing the question+answer
213
 
  void pasteQ(const char *question, int length); //!< set the question of this packet, useful for crafting replies
214
 
  void trim();
215
 
  void wrapup(void); 
216
 
  inline const char *getData(void); //!< get binary representation of packet
217
 
  void setRaw(char *mesg, int length);
218
 
  const char *getRaw(void);
219
 
  inline void spoofID(uint16_t id); //!< change the ID of an existing packet. Useful for fixing up packets returned from the PacketCache
220
 
  inline void spoofQuestion(const string &qd); //!< paste in the exact right case of the question. Useful for PacketCache
 
127
  void wrapup(void);  // writes out queued rrs, and generates the binary packet. also shuffles. also rectifies dnsheader 'd', and copies it to the stringbuffer
 
128
  const char *getData(void); //!< get binary representation of packet, will call 'wrapup' for you
 
129
 
 
130
  const char *getRaw(void); //!< provides access to the raw packet, possibly on a packet that has never been 'wrapped'
 
131
  void spoofID(uint16_t id); //!< change the ID of an existing packet. Useful for fixing up packets returned from the PacketCache
 
132
  void spoofQuestion(const string &qd); //!< paste in the exact right case of the question. Useful for PacketCache
221
133
  void truncate(int new_length); // has documentation in source
222
134
 
223
 
  bool needAP(); //!< query this to find out if this packet needs additional processing
224
135
  vector<DNSResourceRecord*> getAPRecords(); //!< get a vector with DNSResourceRecords that need additional processing
225
136
  void setCompress(bool compress);
226
137
 
227
138
  DNSPacket *replyPacket() const; //!< convenience function that creates a virgin answer packet to this question
228
 
  Utility::sock_t getSocket() const
229
 
  {
230
 
    return d_socket;
231
 
  }
232
 
  inline void setSocket(Utility::sock_t sock);
233
 
  inline void commitD();
234
 
  static bool isRD(const string &buffer)
235
 
  {
236
 
    return ((struct dnsheader *)buffer.c_str())->rd;
237
 
  }
 
139
 
 
140
  void commitD(); //!< copies 'd' into the stringbuffer
238
141
 
239
142
  //////// DATA !
240
143
 
241
 
  char remote[sizeof(sockaddr_in6)];
242
 
  Utility::socklen_t d_socklen; // 4
 
144
  ComboAddress remote;
243
145
  uint16_t len; //!< length of the raw binary packet 2
244
146
  uint16_t qclass;  //!< class of the question - should always be INternet 2
245
147
  struct dnsheader d; //!< dnsheader at the start of the databuffer 12
246
148
 
247
149
  QType qtype;  //!< type of the question 8
248
150
 
249
 
  string qdomain;  //!< qname of the question 4
 
151
  string qdomain;  //!< qname of the question 4 - unsure how this is used
250
152
  bool d_tcp;
 
153
 
251
154
private:
 
155
  void pasteQ(const char *question, int length); //!< set the question of this packet, useful for crafting replies
 
156
 
252
157
  bool d_wrapped; // 1
253
158
  bool d_compress; // 1
254
159
  uint16_t d_qlen; // length of the question (including class & type) in this packet 2
255
160
  
256
161
  int d_socket; // 4
257
 
  
258
 
  int findlabel(string &label);
259
 
  int toqname(const char *name, string &qname, bool compress = true);
260
 
  int toqname(const string &name, string &qname, bool compress = true);
261
 
  int toqname(const string &name, string *qname, bool compress = true); 
262
 
  const string makeSoaHostmasterPiece(const string &hostmaster);
263
 
  static string parseLOC(const unsigned char *p, unsigned int length);
264
 
  void makeHeader(char *p,uint16_t qtype, uint32_t ttl);
265
 
  int domprint();
266
 
  int getq();
267
 
 
268
 
  // MORE DATA!
269
162
 
270
163
  string stringbuffer; // this is where everything lives 4
271
164
 
273
166
};
274
167
 
275
168
 
276
 
inline void DNSPacket::spoofQuestion(const string &qd)
277
 
{
278
 
  string label=compress(qd);
279
 
  for(string::size_type i=0;i<label.size();++i)
280
 
    stringbuffer[i+sizeof(d)]=label[i];
281
 
  d_wrapped=true; // if we do this, don't later on wrapup
282
 
}
283
 
 
284
 
/** This function takes data from the network, possibly received with recvfrom, and parses
285
 
    it into our class. Results of calling this function multiple times on one packet are
286
 
    unknown. Returns -1 if the packet cannot be parsed.
287
 
*/
288
 
int DNSPacket::parse(const char *mesg, int length)
289
 
{
290
 
  stringbuffer.assign(mesg,length); 
291
 
  len=length;
292
 
  if(length < 12) { 
293
 
    L << Logger::Warning << "Ignoring packet: too short from "
294
 
      << getRemote() << endl;
295
 
    return -1;
296
 
  }
297
 
 
298
 
  memcpy((void *)&d,(const void *)stringbuffer.c_str(),12);
299
 
 
300
 
  int offset=0;
301
 
  d_qlen=0;
302
 
 
303
 
  if(!ntohs(d.qdcount)) {
304
 
    if(!d_tcp) {
305
 
      L << Logger::Warning << "No question section in packet from " << getRemote() <<", rcode="<<(int)d.rcode<<endl;
306
 
      return -1;
307
 
    }
308
 
  }
309
 
  else {
310
 
    offset = getq(); // also sets this->qdomain!
311
 
    d_qlen=offset+4; // this points to the start of any answers
312
 
  }
313
 
  if(offset < 0) {
314
 
    //    L << Logger::Warning << "Ignoring packet: invalid label in question from "
315
 
    //  << inet_ntoa(remote.sin_addr) << endl;
316
 
    return -1;
317
 
  }
318
 
  if(qdomain.length() > 255) { // this prevents crap from the rootservers
319
 
    return -1;
320
 
  }
321
 
 
322
 
 
323
 
  
324
 
  if((unsigned int)(15+offset)>=stringbuffer.length()) {
325
 
    L << Logger::Warning << "Ignoring packet: question too short from "<< getRemote()<<", offset "<<
326
 
      15+offset<<">="<<stringbuffer.length()<<endl;
327
 
    return -1;
328
 
  }
329
 
 
330
 
  qtype=((unsigned char)stringbuffer[12+offset])*256+(unsigned char)stringbuffer[13+offset];
331
 
  qclass=((unsigned char)stringbuffer[14+offset]*256)+(unsigned char)stringbuffer[15+offset];
332
 
  return 0;
333
 
}
334
 
 
335
 
//! Use this to set where this packet was received from or should be sent to
336
 
inline void DNSPacket::setRemote(const struct sockaddr *s, Utility::socklen_t socklen)
337
 
{
338
 
  if(socklen>(Utility::socklen_t)sizeof(remote))
339
 
    throw AhuException("Address too long for storage: "+itoa(socklen));
340
 
 
341
 
  memcpy((void *)remote,(void *)s,socklen);
342
 
  d_socklen=socklen;
343
 
}
344
 
 
345
 
inline void DNSPacket::spoofID(uint16_t id)
346
 
{
347
 
  stringbuffer[1]=(id>>8)&0xff; 
348
 
  stringbuffer[0]=id&0xff;
349
 
  d.id=id;
350
 
}
351
 
 
352
 
inline void DNSPacket::setSocket(Utility::sock_t sock)
353
 
{
354
 
  d_socket=sock;
355
 
}
356
 
 
357
 
inline void DNSPacket::commitD()
358
 
{
359
 
  stringbuffer.replace(0,12,(char *)&d,12); // copy in d
360
 
}
361
 
 
362
 
inline const char *DNSPacket::getData(void)
363
 
{
364
 
  if(!d_wrapped)
365
 
    wrapup();
366
 
 
367
 
  return stringbuffer.data();
368
 
}
369
 
 
370
169
 
371
170
#endif