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

Revision 477, 13.4 KB (checked in by ahu, 8 years ago)

Move from u_intxx_t to uintxx_t typedefs, which are preferred:
 http://lists.freedesktop.org/pipermail/release-wranglers/2004-August/000926.html
 http://www.oreillynet.com/pub/a/network/2003/10/07/michael_barr.html

massive removal of windows style line-endings

  • 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 getLocal() const;
120  string getRemote() const;
121  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
130
131  /** Add a DNSResourceRecord to this packet. A DNSPacket (as does a DNS Packet) has 4 kinds of resource records. Questions,
132      Answers, Authority and Additional. See RFC 1034 and 1035 for details. You can specify where a record needs to go in the
133      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();
143private:
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
210public:
211
212  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
221  void truncate(int new_length); // has documentation in source
222
223  bool needAP(); //!< query this to find out if this packet needs additional processing
224  vector<DNSResourceRecord*> getAPRecords(); //!< get a vector with DNSResourceRecords that need additional processing
225  void setCompress(bool compress);
226
227  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  }
238
239  //////// DATA !
240
241  char remote[sizeof(sockaddr_in6)];
242  Utility::socklen_t d_socklen; // 4
243  uint16_t len; //!< length of the raw binary packet 2
244  uint16_t qclass;  //!< class of the question - should always be INternet 2
245  struct dnsheader d; //!< dnsheader at the start of the databuffer 12
246
247  QType qtype;  //!< type of the question 8
248
249  string qdomain;  //!< qname of the question 4
250  bool d_tcp;
251private:
252  bool d_wrapped; // 1
253  bool d_compress; // 1
254  uint16_t d_qlen; // length of the question (including class & type) in this packet 2
255 
256  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
270  string stringbuffer; // this is where everything lives 4
271
272  vector<DNSResourceRecord> rrs; // 4
273};
274
275
276inline 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*/
288int 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
336inline 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
345inline void DNSPacket::spoofID(uint16_t id)
346{
347  stringbuffer[1]=(id>>8)&0xff; 
348  stringbuffer[0]=id&0xff;
349  d.id=id;
350}
351
352inline void DNSPacket::setSocket(Utility::sock_t sock)
353{
354  d_socket=sock;
355}
356
357inline void DNSPacket::commitD()
358{
359  stringbuffer.replace(0,12,(char *)&d,12); // copy in d
360}
361
362inline const char *DNSPacket::getData(void)
363{
364  if(!d_wrapped)
365    wrapup();
366
367  return stringbuffer.data();
368}
369
370
371#endif
Note: See TracBrowser for help on using the browser.