root/trunk/pdns/pdns/dnspacket.hh @ 325

Revision 325, 13.0 KB (checked in by ahu, 8 years ago)

Based on request of Simon Kirby, added ability to listen on multiple addresses.
This commit also removes the last mentions of 'AhuDNS', the very old name of
PowerDNS. It also removes some old documentation. Furthermore, there are some
additional license version clarifications.

  • Property svn:eol-style set to native
  • Property svn:keywords set to author date id revision
Line 
1/*
2    PowerDNS Versatile Database Driven Nameserver
3    Copyright (C) 2005  PowerDNS.COM BV
4
5    This program is free software; you can redistribute it and/or modify it
6    under the terms of the GNU General Public License version 2 as published
7    by the Free Software Foundation
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
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
17*/
18#ifndef DNSPACKET_HH
19
20#if __GNUC__ == 2
21#if __GNUC_MINOR__ < 95
22        #error Your compiler is too old! Try g++ 3.3 or higher
23#else
24        #warning There are known problems with PowerDNS binaries compiled by gcc version 2.95 and 2.96!
25#endif
26#endif
27
28#define DNSPACKET_HH
29
30#include <cstdio>
31#include <cstring>
32#include <cstdlib>
33#include <sys/types.h>
34
35#ifndef WIN32
36#include <sys/socket.h>
37#include <netinet/in.h>
38#include <sys/time.h>
39#include <unistd.h>
40#include <arpa/inet.h>
41
42#endif // WIN32
43
44#include <iostream>
45#include <string>
46
47#include <vector>
48#include "qtype.hh"
49#include "dns.hh"
50#include "misc.hh"
51#include "utility.hh"
52#include "logger.hh"
53#include "ahuexception.hh"
54
55#ifdef HAVE_CONFIG_H
56#include "config.h"
57 #endif // HAVE_CONFIG_H
58
59
60#ifdef WIN32
61# ifdef BYTE_ORDER
62#   undef BYTE_ORDER
63# endif // BYTE_ORDER
64# define BYTE_ORDER LITTLE_ENDIAN
65#endif // WIN32
66
67class DNSBackend;
68
69//! This class represents DNS packets, either received or to be sent.
70class DNSPacket
71{
72public:
73  DNSPacket();
74  DNSPacket(const DNSPacket &orig);
75
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 getRemote() const;
120  u_int16_t getRemotePort() const;
121  void setA(bool); //!< make this packet authoritative
122  void setRA(bool); //!< set the Recursion Available flag
123  void setRD(bool); //!< set the Recursion Desired flag
124  void setAnswer(bool); //!< Make this packet an answer
125  void setID(u_int16_t); //!< set the DNS id of this packet
126  void setOpcode(u_int16_t);  //!< set the Opcode of this packet
127  void setRcode(int v); //!< set the Rcode of this packet
128
129
130  /** Add a DNSResourceRecord to this packet. A DNSPacket (as does a DNS Packet) has 4 kinds of resource records. Questions,
131      Answers, Authority and Additional. See RFC 1034 and 1035 for details. You can specify where a record needs to go in the
132      DNSResourceRecord d_place field */
133  void addRecord(const DNSResourceRecord &); 
134
135  /** helper function for both DNSPacket and addSOARecord() - converts a line into a struct, for easier parsing */
136  static void fillSOAData(const string &content, SOAData &data);
137
138  /** for use by DNSPacket, converts a SOAData class to a ascii line again */
139  static string serializeSOAData(const SOAData &data);
140  void setQuestion(int op, const string &qdomain, int qtype);
141  vector<DNSResourceRecord> getAnswers();
142private:
143  string compress(const string &qd);
144  void addARecord(const string&, u_int32_t, u_int32_t ttl, DNSResourceRecord::Place place); //!< add an A record to the packet
145  void addARecord(const DNSResourceRecord &); //!< add an A record to the packet
146
147  void addAAAARecord(const string &, unsigned char addr[16], u_int32_t ttl, DNSResourceRecord::Place place); //!< add an A record to the packet
148  void addAAAARecord(const DNSResourceRecord &); //!< add an A record to the packet
149
150
151  void addMXRecord(const string &domain, const string &mx, int priority, u_int32_t ttl); //!< add an MX record to the packet
152  void addMXRecord(const DNSResourceRecord &); //!< add an MX record to the packet
153
154  void addSRVRecord(const string &domain, const string &srv, int priority, u_int32_t ttl); //!< add an SRVMX record to the packet
155  void addSRVRecord(const DNSResourceRecord &); //!< add an SRV record to the packet
156
157  void addCNAMERecord(const string &domain, const string &alias, u_int32_t ttl); //!< add a CNAME record to the packet
158  void addCNAMERecord(const DNSResourceRecord &); //!< add a CNAME record to the packet
159
160  void addRPRecord(const string &domain, const string &content, u_int32_t ttl); //!< add a RP record to the packet
161  void addRPRecord(const DNSResourceRecord &); //!< add a RP record to the packet
162
163  void addNAPTRRecord(const string &domain, const string &content, u_int32_t ttl); //!< add a NAPTR record to the packet
164  void addNAPTRRecord(const DNSResourceRecord &); //!< add a NAPTR record to the packet
165
166
167  void addPTRRecord(const string &domain, const string &alias, u_int32_t ttl); //!< add a PTR record to the packet
168  void addPTRRecord(const DNSResourceRecord &); //!< add a PTR record to the packet
169
170  void addLOCRecord(const string &domain, const string &content, u_int32_t ttl); 
171  void addLOCRecord(const DNSResourceRecord &); //!< add a LOC record to the packet
172
173
174  /** Adds a SOA record to the packet. The SOA record is very special because we have a lot of default values,
175      that may be overridden by the contents of the database. Content can have a variety of content:
176     
177      (nothing)
178      hostmaster
179      hostmaster serial-number
180      hostmaster serial-number [refresh [retry [expire [ minimum] ] ] ]
181
182      Suggested values are:
183
184      10800           ;refresh every three hours
185      300             ;retry every 5 min
186      604800          ;expire after a week
187      86400           ;default ttl
188
189      An empty field means that we supply hostmaster+@+domain name as hostmaster. An empty serial number is replaced by the
190      number of seconds since 1 jan 1970 (unix timestamp). The other values are substituted as indicated
191
192  */
193  void addSOARecord(const string &domain, const string &content, u_int32_t ttl, DNSResourceRecord::Place place); 
194  void addSOARecord(const DNSResourceRecord &); //!< add a SOA record to the packet
195
196  void addTXTRecord(string domain, string, u_int32_t ttl); //!< add a TXT record to the packet
197  void addTXTRecord(const DNSResourceRecord &); //!< add a TXT record to the packet
198
199  void addHINFORecord(string domain, string, u_int32_t ttl); //!< add a HINFO record to the packet
200  void addHINFORecord(const DNSResourceRecord &); //!< add a HINFO record to the packet
201
202  void addNSRecord(string domain, string server, u_int32_t ttl, DNSResourceRecord::Place place); //!< add an NS record to the packet
203  void addNSRecord(const DNSResourceRecord &); //!< add an NS record to the packet
204  void addGenericRecord(const DNSResourceRecord& rr);
205  static string &attodot(string &str);  //!< for when you need to insert an email address in the SOA
206
207public:
208
209  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
210  void pasteQ(const char *question, int length); //!< set the question of this packet, useful for crafting replies
211  void trim();
212  void wrapup(void); 
213  inline const char *getData(void); //!< get binary representation of packet
214  void setRaw(char *mesg, int length);
215  const char *getRaw(void);
216  inline void spoofID(u_int16_t id); //!< change the ID of an existing packet. Useful for fixing up packets returned from the PacketCache
217  inline void spoofQuestion(const string &qd); //!< paste in the exact right case of the question. Useful for PacketCache
218  void truncate(int new_length); // has documentation in source
219
220  bool needAP(); //!< query this to find out if this packet needs additional processing
221  vector<DNSResourceRecord*> getAPRecords(); //!< get a vector with DNSResourceRecords that need additional processing
222  void setCompress(bool compress);
223
224  DNSPacket *replyPacket() const; //!< convenience function that creates a virgin answer packet to this question
225  Utility::sock_t getSocket() const
226  {
227    return d_socket;
228  }
229  inline void setSocket(Utility::sock_t sock);
230  inline void commitD();
231  static bool isRD(const string &buffer)
232  {
233    return ((struct dnsheader *)buffer.c_str())->rd;
234  }
235
236  //////// DATA !
237
238  char remote[sizeof(sockaddr_in6)];
239  Utility::socklen_t d_socklen; // 4
240  u_int16_t len; //!< length of the raw binary packet 2
241  u_int16_t qclass;  //!< class of the question - should always be INternet 2
242  struct dnsheader d; //!< dnsheader at the start of the databuffer 12
243
244  QType qtype;  //!< type of the question 8
245
246  string qdomain;  //!< qname of the question 4
247  bool d_tcp;
248private:
249  bool d_wrapped; // 1
250  bool d_compress; // 1
251  u_int16_t d_qlen; // length of the question (including class & type) in this packet 2
252 
253  int d_socket; // 4
254 
255  int findlabel(string &label);
256  int toqname(const char *name, string &qname, bool compress = true);
257  int toqname(const string &name, string &qname, bool compress = true);
258  int toqname(const string &name, string *qname, bool compress = true); 
259  const string makeSoaHostmasterPiece(const string &hostmaster);
260  static string parseLOC(const unsigned char *p, unsigned int length);
261  void makeHeader(char *p,u_int16_t qtype, u_int32_t ttl);
262  int domprint();
263  int getq();
264
265  // MORE DATA!
266
267  string stringbuffer; // this is where everything lives 4
268
269  vector<DNSResourceRecord> rrs; // 4
270};
271
272
273inline void DNSPacket::spoofQuestion(const string &qd)
274{
275  string label=compress(qd);
276  for(string::size_type i=0;i<label.size();++i)
277    stringbuffer[i+sizeof(d)]=label[i];
278  d_wrapped=true; // if we do this, don't later on wrapup
279}
280
281/** This function takes data from the network, possibly received with recvfrom, and parses
282    it into our class. Results of calling this function multiple times on one packet are
283    unknown. Returns -1 if the packet cannot be parsed.
284*/
285int DNSPacket::parse(const char *mesg, int length)
286{
287  stringbuffer.assign(mesg,length); 
288  len=length;
289  if(length < 12) { 
290    L << Logger::Warning << "Ignoring packet: too short from "
291      << getRemote() << endl;
292    return -1;
293  }
294
295  memcpy((void *)&d,(const void *)stringbuffer.c_str(),12);
296
297  int offset=0;
298  d_qlen=0;
299  if(ntohs(d.qdcount)) {
300    offset = getq(); // also sets this->qdomain!
301    if(offset < 0) {
302      //    L << Logger::Warning << "Ignoring packet: invalid label in question from "
303      //  << inet_ntoa(remote.sin_addr) << endl;
304      return -1;
305    }
306    d_qlen=offset+4; // this points to the start of any answers
307  }
308
309  if((unsigned int)(15+offset)>=stringbuffer.length()) {
310    L << Logger::Warning << "Ignoring packet: question too short from "<< getRemote()<<", offset "<<
311      15+offset<<">="<<stringbuffer.length()<<endl;
312    return -1;
313  }
314
315  qtype=((unsigned char)stringbuffer[12+offset])*256+(unsigned char)stringbuffer[13+offset];
316  qclass=((unsigned char)stringbuffer[14+offset]*256)+(unsigned char)stringbuffer[15+offset];
317  return 0;
318}
319
320//! Use this to set where this packet was received from or should be sent to
321inline void DNSPacket::setRemote(const struct sockaddr *s, Utility::socklen_t socklen)
322{
323  if(socklen>(Utility::socklen_t)sizeof(remote))
324    throw AhuException("Address too long for storage: "+itoa(socklen));
325
326  memcpy((void *)remote,(void *)s,socklen);
327  d_socklen=socklen;
328}
329
330inline void DNSPacket::spoofID(u_int16_t id)
331{
332  stringbuffer[1]=(id>>8)&0xff; 
333  stringbuffer[0]=id&0xff;
334  d.id=id;
335}
336
337inline void DNSPacket::setSocket(Utility::sock_t sock)
338{
339  d_socket=sock;
340}
341
342inline void DNSPacket::commitD()
343{
344  stringbuffer.replace(0,12,(char *)&d,12); // copy in d
345}
346
347inline const char *DNSPacket::getData(void)
348{
349  if(!d_wrapped)
350    wrapup();
351
352  return stringbuffer.data();
353}
354
355
356#endif
Note: See TracBrowser for help on using the browser.