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

Revision 947, 13.4 KB (checked in by ahu, 6 years ago)

fix 'ns with identical glue' giving sort of NXRRSET, plus regression test. Should close Augie Schwer's issue.

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