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

Revision 947, 37.2 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) 2001 - 2005  PowerDNS.COM BV
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License version 2 as
7    published 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
19#include "utility.hh"
20#include <cstdio>
21
22#include <cstdlib>
23#include <sys/types.h>
24
25#include <iostream> 
26
27#include <string>
28#include <errno.h>
29#include<boost/tokenizer.hpp>
30#include <algorithm>
31
32#include "dns.hh"
33#include "dnsbackend.hh"
34#include "ahuexception.hh"
35#include "dnspacket.hh"
36#include "logger.hh"
37#include "arguments.hh"
38
39
40DNSPacket::DNSPacket() 
41{
42  d_wrapped=false;
43  d_compress=true;
44  d_tcp=false;
45}
46
47
48string DNSPacket::getString()
49{
50  return stringbuffer;
51}
52
53string DNSPacket::getLocal() const
54{
55  struct sockaddr_in6 sa;
56  int addrlen=sizeof(sa);
57
58  getsockname(d_socket, (struct sockaddr *)&sa, (socklen_t *)&addrlen);
59  return sockAddrToString((struct sockaddr_in*)&sa);
60}
61
62
63string DNSPacket::getRemote() const
64{
65  return remote.toString();
66}
67
68uint16_t DNSPacket::getRemotePort() const
69{
70  return remote.sin4.sin_port;
71}
72
73void DNSPacket::trim()
74{
75  rrs.clear();
76  qdomain=""; // .clear();
77  string(stringbuffer).swap(stringbuffer); // kudos Scott
78}
79
80DNSPacket::DNSPacket(const DNSPacket &orig)
81{
82  DLOG(L<<"DNSPacket copy constructor called!"<<endl);
83  d_socket=orig.d_socket;
84  remote=orig.remote;
85  len=orig.len;
86  d_qlen=orig.d_qlen;
87  d_dt=orig.d_dt;
88  d_compress=orig.d_compress;
89  d_tcp=orig.d_tcp;
90  qtype=orig.qtype;
91  qclass=orig.qclass;
92  qdomain=orig.qdomain;
93
94  rrs=orig.rrs;
95
96  d_wrapped=orig.d_wrapped;
97
98  stringbuffer=orig.stringbuffer;
99  d=orig.d;
100}
101
102int DNSPacket::expand(const unsigned char *begin, const unsigned char *end, string &expanded, int depth)
103{
104  if(depth>10)
105    throw AhuException("Looping label when parsing a packet");
106
107  unsigned int n;
108  const unsigned char *p=begin;
109
110  while((n=*(unsigned char *)p++)) {
111    char tmp[256];
112    if(n==0x41)
113       throw AhuException("unable to expand binary label, generally caused by deprecated IPv6 reverse lookups");
114
115    if((n & 0xc0) == 0xc0 ) { 
116       unsigned int labelOffset=(n&~0xc0)*256+ (int)*(unsigned char *)p;
117       expand((unsigned char *)stringbuffer.c_str()+labelOffset,end,expanded,++depth); // was cvstrac ticket #21
118       return 1+p-begin;
119    }
120
121    if(p+n>=end) { // this is a bogus packet, references beyond the end of the buffer
122       throw AhuException("Label claims to be longer than packet");
123    }
124    strncpy((char *)tmp,(const char *)p,n);
125   
126    if(*(p+n)) { // add a ., except at the end
127       tmp[n]='.';
128       tmp[n+1]=0;
129    }
130    else
131       tmp[n]=0;
132   
133    expanded+=tmp;
134   
135    p+=n;
136  }
137 
138  // lowercase(qdomain); (why was this?)
139 
140  return p-begin;
141
142}
143
144/** copies the question into our class
145 *  and returns offset of question type & class. Returns -1 in case of an error
146 */
147int DNSPacket::getq()
148{
149  const unsigned char *orig=(const unsigned char *)stringbuffer.c_str()+12;
150  const unsigned char *end=orig+(stringbuffer.length()-12);
151  qdomain="";
152  try {
153    return expand(orig,end,qdomain);
154  }
155  catch(AhuException &ae) {
156     L<<Logger::Error<<"On retrieving question of packet from "<<getRemote()<<", encountered error: "<<ae.reason<<endl;
157  }
158  return -1;
159}
160
161/*
162                                    1  1  1  1  1  1
163      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
164    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
165    |                      ID                       |
166    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
167    |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
168    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
169    |                    QDCOUNT                    |
170    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
171    |                    ANCOUNT                    |
172    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
173    |                    NSCOUNT                    |
174    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
175    |                    ARCOUNT                    |
176    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
177*/
178
179void DNSPacket::setRcode(int v)
180{
181  d.rcode=v;
182}
183
184void DNSPacket::setAnswer(bool b)
185{
186  if(b) {
187    stringbuffer.assign(12,(char)0);
188    memset((void *)&d,0,sizeof(d));
189   
190    d.qr=b;
191  }
192}
193
194void DNSPacket::setA(bool b)
195{
196  d.aa=b;
197}
198
199void DNSPacket::setID(uint16_t id)
200{
201  d.id=id;
202}
203
204void DNSPacket::setRA(bool b)
205{
206  d.ra=b;
207}
208
209void DNSPacket::setRD(bool b)
210{
211  d.rd=b;
212}
213
214
215void DNSPacket::setOpcode(uint16_t opcode)
216{
217  d.opcode=opcode;
218}
219
220const char *DNSPacket::getRaw(void)
221{
222  return stringbuffer.data();
223}
224
225void DNSPacket::setRaw(char *mesg, int length)
226{
227  stringbuffer.assign(mesg,length); 
228}
229
230void DNSPacket::addARecord(const DNSResourceRecord &rr)
231{
232  DLOG(L<<"Adding an A record to the packet!"<<endl);
233  addARecord(rr.qname, htonl(inet_addr(rr.content.c_str())), rr.ttl, rr.d_place);
234}
235
236void DNSPacket::clearRecords()
237{
238  rrs.clear();
239}
240
241void DNSPacket::addRecord(const DNSResourceRecord &rr)
242{
243  if(d_compress)
244    for(vector<DNSResourceRecord>::const_iterator i=rrs.begin();i!=rrs.end();++i) 
245      if(rr.qname==i->qname && rr.qtype==i->qtype && rr.content==i->content) {
246        if(rr.qtype.getCode()!=QType::MX && rr.qtype.getCode()!=QType::SRV)
247          return;
248        if(rr.priority==i->priority)
249          return;
250      }
251
252  rrs.push_back(rr);
253}
254
255void DNSPacket::addARecord(const string &name, uint32_t ip, uint32_t ttl, DNSResourceRecord::Place place)
256{
257  string piece1;
258  toqname(name, &piece1);
259
260  char p[14];
261  makeHeader(p,QType::A,ttl);
262  p[8]=0;
263  p[9]=4; // length of data
264
265  putLong(p+10,ip);
266  stringbuffer.append(piece1);
267  stringbuffer.append(p,14);
268
269  if(place==DNSResourceRecord::ADDITIONAL)
270    d.arcount++;
271  else
272    d.ancount++;
273}
274
275void DNSPacket::addAAAARecord(const DNSResourceRecord &rr)
276{
277  DLOG(L<<"Adding an AAAA record to the packet!"<<endl);
278  unsigned char addr[16];
279
280#ifdef HAVE_IPV6
281  if( Utility::inet_pton( AF_INET6, rr.content.c_str(), static_cast< void * >( addr )))
282    addAAAARecord(rr.qname, addr, rr.ttl,rr.d_place);
283  else
284#endif
285    L<<Logger::Error<<"Unable to convert IPv6 TEXT '"<<rr.content<<"' into binary for record '"<<rr.qname<<"': "
286     <<endl;
287}
288
289
290
291void DNSPacket::addAAAARecord(const string &name, unsigned char addr[16], uint32_t ttl,DNSResourceRecord::Place place)
292{
293  string piece1;
294  toqname(name.c_str(),&piece1);
295
296  char p[26];
297  makeHeader(p,QType::AAAA,ttl);
298  p[8]=0;
299  p[9]=16; // length of data
300
301  for(int n=0;n<16;n++)
302    p[10+n]=addr[n];
303
304  stringbuffer.append(piece1);
305  stringbuffer.append(p,26);
306  if(place==DNSResourceRecord::ADDITIONAL)
307    d.arcount++;
308  else
309    d.ancount++;
310}
311
312
313void DNSPacket::addMXRecord(const DNSResourceRecord &rr)
314{
315  addMXRecord(rr.qname, rr.content, rr.priority, rr.ttl);
316}
317
318void DNSPacket::addMXRecord(const string &domain, const string &mx, int priority, uint32_t ttl)
319{
320  string piece1;
321
322  toqname(domain,&piece1);
323
324  char piece2[12];
325  makeHeader(piece2,QType::MX,ttl);
326
327  // start of payload for which we need to specify the length in 8 & 9
328
329  piece2[10]=(priority>>8)&0xff;
330  piece2[11]=priority&0xff;
331 
332  string piece3;
333  toqname(mx,&piece3);
334  // end of payload
335
336  piece2[9]=piece3.length()+2; // fill in length
337
338  stringbuffer+=piece1;
339  stringbuffer.append(piece2,12);
340  stringbuffer+=piece3;
341
342  d.ancount++;
343}
344
345
346void DNSPacket::addSRVRecord(const DNSResourceRecord &rr)
347{
348  addSRVRecord(rr.qname, rr.content, rr.priority, rr.ttl);
349}
350
351void DNSPacket::addSRVRecord(const string &domain, const string &srv, int priority, uint32_t ttl)
352{
353  string piece1;
354  toqname(domain,&piece1);
355           
356  string target;
357  int weight=0;
358  int port=0;
359
360  vector<string>parts;
361  stringtok(parts,srv);
362  int pleft=parts.size();
363
364  // We need to have exactly 3 parts, so we have to check it!
365  if (pleft<2) {
366    throw AhuException("Missing data for type SRV "+domain);
367  }
368 
369  if(pleft) 
370    weight = atoi(parts[0].c_str());
371
372  if(pleft>1) 
373    port = atoi(parts[1].c_str());
374
375  if(pleft>2) 
376    toqname(parts[2],&target);
377
378 
379
380  char p[16];
381  makeHeader(p,QType::SRV,ttl);
382 
383  p[8]=0;
384  p[9]=0;  // need to fill this in
385
386  // start of payload for which we need to specify the length in 8 & 9
387
388  // priority aka preference
389  p[10]=(priority>>8)&0xff;
390  p[11]=priority&0xff;
391
392  // weight
393  p[12]=(weight>>8)&0xff;
394  p[13]=weight&0xff;
395 
396  // port
397  p[14]=(port>>8)&0xff;
398  p[15]=port&0xff;
399 
400  // target
401  // end of payload
402
403  p[9]=target.length()+6; // fill in length
404
405  stringbuffer+=piece1;
406  stringbuffer.append(p,16);
407  stringbuffer+=target;
408
409  d.ancount++;
410}
411
412string &DNSPacket::attodot(string &str)
413{
414   if(str.find_first_of("@")==string::npos)
415      return str;
416
417   for (unsigned int i = 0; i < str.length(); i++)
418   {
419      if (str[i] == '@') {
420         str[i] = '.';
421         break;
422      } else if (str[i] == '.') {
423         str.insert(i++, "\\");
424      }
425   }
426
427   return str;
428}
429
430void DNSPacket::fillSOAData(const string &content, SOAData &data)
431{
432  // content consists of fields separated by spaces:
433  //  nameservername hostmaster serial-number [refresh [retry [expire [ minimum] ] ] ]
434
435  // fill out data with some plausible defaults:
436  // 10800 3600 604800 3600
437  data.serial=0;
438  data.refresh=arg().asNum("soa-refresh-default");
439  data.retry=arg().asNum("soa-retry-default");
440  data.expire=arg().asNum("soa-expire-default");
441  data.default_ttl=arg().asNum("soa-minimum-ttl");
442
443  vector<string>parts;
444  stringtok(parts,content);
445  int pleft=parts.size();
446
447  //  cout<<"'"<<content<<"'"<<endl;
448
449  if(pleft)
450    data.nameserver=parts[0];
451
452  if(pleft>1) 
453    data.hostmaster=attodot(parts[1]); // ahu@ds9a.nl -> ahu.ds9a.nl, piet.puk@ds9a.nl -> piet\.puk.ds9a.nl
454
455  if(pleft>2)
456    data.serial=strtoul(parts[2].c_str(), NULL, 10);
457
458  if(pleft>3)
459    data.refresh=atoi(parts[3].c_str());
460
461  if(pleft>4)
462    data.retry=atoi(parts[4].c_str());
463
464
465  if(pleft>5)
466    data.expire=atoi(parts[5].c_str());
467
468  if(pleft>6)
469    data.default_ttl=atoi(parts[6].c_str());
470
471}
472
473
474string DNSPacket::serializeSOAData(const SOAData &d)
475{
476  ostringstream o;
477  //  nameservername hostmaster serial-number [refresh [retry [expire [ minimum] ] ] ]
478  o<<d.nameserver<<" "<< d.hostmaster <<" "<< d.serial <<" "<< d.refresh << " "<< d.retry << " "<< d.expire << " "<< d.default_ttl;
479
480  return o.str();
481}
482
483  /* the hostmaster is encoded as two parts - the bit UNTIL the first unescaped '.'
484     is encoded as a TXT string, the rest as a domain
485
486     we might encounter escaped dots in the first part though: bert\.hubert.powerdns.com for example should be
487     11bert.hubert7powerdns3com0 */
488
489/* Very ugly btw, this needs to be better */
490const string DNSPacket::makeSoaHostmasterPiece(const string &hostmaster)
491{
492  string ret;
493  string first;
494  string::size_type i;
495
496  for(i=0;i<hostmaster.length();++i) {
497    if(hostmaster[i]=='.') {
498      break;
499    }
500    if(hostmaster[i]=='\\' && i+1<hostmaster.length()) {
501      ++i;
502      first.append(1,hostmaster[i]);
503      continue;
504    }
505    first.append(1,hostmaster[i]);
506  }
507
508  ret.resize(1);
509  ret[0]=first.length();
510  ret+=first;
511 
512  string second;
513  if(i+1<hostmaster.length())
514     toqname(hostmaster.substr(i+1),&second); 
515  else {
516     second.resize(1);
517     second[0]=0;
518  }
519
520  return ret+second;
521}
522
523
524void DNSPacket::addSOARecord(const DNSResourceRecord &rr)
525{
526  addSOARecord(rr.qname, rr.content, rr.ttl, rr.d_place);
527}
528
529void DNSPacket::addSOARecord(const string &domain, const string & content, uint32_t ttl,DNSResourceRecord::Place place)
530{
531  SOAData soadata;
532  fillSOAData(content, soadata);
533
534  string piece1;
535  toqname(domain, &piece1);
536
537  char p[10];
538  makeHeader(p,QType::SOA,ttl);
539 
540  string piece3; 
541  toqname(soadata.nameserver,&piece3, false);
542 
543  string piece4=makeSoaHostmasterPiece(soadata.hostmaster);
544
545  uint32_t piece5[5];
546 
547  uint32_t *i_p=piece5;
548 
549  uint32_t soaoffset=0;
550  if(soadata.serial && (soaoffset=arg().asNum("soa-serial-offset")))
551    if(soadata.serial<soaoffset)
552      soadata.serial+=soaoffset; // thank you DENIC
553
554  *i_p++=htonl(soadata.serial ? soadata.serial : time(0));
555  *i_p++=htonl(soadata.refresh);
556  *i_p++=htonl(soadata.retry);
557  *i_p++=htonl(soadata.expire);
558  *i_p++=htonl(soadata.default_ttl);
559 
560  p[9]=piece3.length()+piece4.length()+20; 
561
562  stringbuffer+=piece1;
563  stringbuffer.append(p,10);
564  stringbuffer+=piece3;
565  stringbuffer+=piece4;
566  stringbuffer.append((char*)piece5,20);
567  if(place==DNSResourceRecord::ANSWER)
568    d.ancount++;
569  else
570    d.nscount++;
571}
572
573void DNSPacket::addCNAMERecord(const DNSResourceRecord &rr)
574{
575  addCNAMERecord(rr.qname, rr.content, rr.ttl);
576}
577
578
579void DNSPacket::addMRRecord(const DNSResourceRecord &rr)
580{
581  addMRRecord(rr.qname, rr.content, rr.ttl);
582}
583
584void DNSPacket::addMRRecord(const string& domain, const string& alias, uint32_t ttl)
585{
586  string piece1;
587
588  toqname(domain.c_str(),&piece1);
589  char p[10];
590 
591  p[0]=0;
592  p[1]=QType::MR; 
593  p[2]=0;
594  p[3]=1; // IN
595 
596  putLong(p+4,ttl);
597  p[8]=0;
598  p[9]=0;  // need to fill this in
599 
600  string piece3;
601  toqname(alias,&piece3);
602 
603  p[9]=piece3.length();
604 
605  stringbuffer+=piece1;
606  stringbuffer.append(p,10);
607  stringbuffer+=piece3;
608 
609  d.ancount++;
610}
611
612void DNSPacket::addCNAMERecord(const string &domain, const string &alias, uint32_t ttl)
613{
614 string piece1;
615
616 toqname(domain.c_str(),&piece1);
617 char p[10];
618 
619 p[0]=0;
620 p[1]=5; // CNAME
621 p[2]=0;
622 p[3]=1; // IN
623 
624 putLong(p+4,ttl);
625 p[8]=0;
626 p[9]=0;  // need to fill this in
627 
628 string piece3;
629 //xtoqname(alias,&piece3);
630 toqname(alias,&piece3);
631 
632 p[9]=piece3.length();
633
634 stringbuffer+=piece1;
635 stringbuffer.append(p,10);
636 stringbuffer+=piece3;
637
638 d.ancount++;
639}
640
641
642void DNSPacket::addRPRecord(const DNSResourceRecord &rr)
643{
644  addRPRecord(rr.qname, rr.content, rr.ttl);
645}
646
647void DNSPacket::addRPRecord(const string &domain, const string &content, uint32_t ttl)
648{
649 string piece1;
650
651 toqname(domain.c_str(),&piece1);
652 char p[11];
653 makeHeader(p,17,ttl);
654 
655 // content contains: mailbox-name more-info-domain (Separated by a space)
656 string::size_type pos;
657 if((pos=content.find(" "))==string::npos) {
658   L<<Logger::Warning<<"RP record for domain '"<<domain<<"' has malformed content field"<<endl;
659   return;
660 }
661
662 string mboxname=content.substr(0,pos);
663 string moreinfo=content.substr(pos+1);
664
665 string piece3;
666 toqname(mboxname,&piece3);
667
668 string piece4;
669 toqname(moreinfo,&piece4);
670 
671 p[9]=(piece3.length()+piece4.length())%256;
672 p[10]=(piece3.length()+piece4.length())/256;
673
674 stringbuffer+=piece1;
675 stringbuffer.append(p,10);
676 stringbuffer+=piece3;
677 stringbuffer+=piece4;
678
679 // done
680 d.ancount++;
681}
682
683
684
685
686void DNSPacket::addNAPTRRecord(const DNSResourceRecord &rr)
687{
688  addNAPTRRecord(rr.qname, rr.content, rr.ttl);
689}
690
691
692void DNSPacket::makeHeader(char *p,uint16_t qtype, uint32_t ttl)
693{
694  p[0]=0;
695  p[1]=qtype; 
696  p[2]=0;
697  p[3]=1; // IN
698  putLong(p+4,ttl);
699  p[8]=0;
700  p[9]=0;  // need to fill this in
701}
702
703void DNSPacket::addNAPTRRecord(const string &domain, const string &content, uint32_t ttl)
704{
705  string piece1;
706
707  //xtoqname(domain.c_str(),&piece1);
708  toqname(domain.c_str(),&piece1);
709  char p[11];
710  makeHeader(p,QType::NAPTR,ttl);
711 
712  // content contains: 100  100  "s"   "http+I2R"   ""    _http._tcp.foo.com.
713  //                   100   50  "u"   "e2u+sip"    "" testuser@domain.com
714 
715  using namespace boost;
716  escaped_list_separator<char> els("\\", " ", "\"");
717  tokenizer<escaped_list_separator<char> > tok(content, els);
718  tokenizer<escaped_list_separator<char> >::iterator iter=tok.begin();
719  int order, pref;
720  string flags, services, regex, replacement;
721  unsigned int n;
722  for(n=0; iter != tok.end(); ++iter, ++n) {
723    switch(n) {
724    case 0:
725        order=atoi(iter->c_str());
726        break;
727    case 1:
728      pref=atoi(iter->c_str());
729      break;
730    case 2:
731      flags=*iter;
732      break;
733    case 3:
734      services=*iter;
735      break;
736    case 4:
737      regex=*iter;
738      break;
739    case 5:
740      replacement=*iter;
741      break;
742    }
743  }
744  if(n!=6 || iter!=tok.end())
745    throw AhuException("Error parsing NAPTR content '"+content+"'");
746
747/*
748 The packet format for the NAPTR record is:
749
750                                          1  1  1  1  1  1
751            0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
752          +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
753          |                     ORDER                     |
754          +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
755          |                   PREFERENCE                  |
756          +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
757          /                     FLAGS                     /
758          +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
759          /                   SERVICES                    /
760          +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
761          /                    REGEXP                     /
762          +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
763          /                  REPLACEMENT                  /
764          /                                               /
765          +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
766          (jeez)
767*/
768
769
770  string piece3;
771  piece3.resize(4);
772 
773  piece3[0]=(order>>8)&0xff;
774  piece3[1]=(order)&0xff;
775
776  piece3[2]=(pref>>8)&0xff;
777  piece3[3]=(pref)&0xff;
778
779  piece3.append(1,flags.length());
780  piece3.append(flags);
781  piece3.append(1,services.length());
782  piece3.append(services);
783  piece3.append(1,regex.length());
784  piece3.append(regex);
785
786  string piece4;
787  toqname(replacement,&piece4, false); // don't compress
788 
789  p[9]=(piece3.length()+piece4.length())%256;
790  p[10]=(piece3.length()+piece4.length())/256;
791
792  stringbuffer+=piece1;
793  stringbuffer.append(p,10);
794  stringbuffer+=piece3;
795  stringbuffer+=piece4;
796 
797  // done
798  d.ancount++;
799}
800 
801void DNSPacket::addPTRRecord(const DNSResourceRecord &rr)
802{
803  addPTRRecord(rr.qname, rr.content, rr.ttl);
804}
805
806void DNSPacket::addPTRRecord(const string &domain, const string &alias, uint32_t ttl)
807{
808 string piece1;
809
810 toqname(domain,&piece1);
811 char p[10];
812 makeHeader(p,QType::PTR,ttl);
813
814 string piece3;
815 toqname(alias,&piece3);
816 
817 p[9]=piece3.length();
818 
819 stringbuffer+=piece1;
820 stringbuffer.append(p,10);
821 stringbuffer+=piece3;
822
823 d.ancount++;
824}
825
826void DNSPacket::addTXTRecord(const DNSResourceRecord& rr)
827{
828  addTXTorSPFRecord(QType::TXT, rr.qname, rr.content, rr.ttl);
829}
830
831void DNSPacket::addSPFRecord(const DNSResourceRecord& rr)
832{
833  addTXTorSPFRecord(QType::SPF, rr.qname, rr.content, rr.ttl);
834}
835
836
837void DNSPacket::addTXTorSPFRecord(uint16_t qtype, string domain, string txt, uint32_t ttl)
838{
839 string piece1;
840 //xtoqname(domain, &piece1);
841 toqname(domain, &piece1);
842 char p[10];
843 makeHeader(p, qtype, ttl);
844 string piece3;
845 piece3.reserve(txt.length()+1);
846 piece3.append(1,txt.length());
847 piece3.append(txt);
848
849 p[8]=piece3.length()/256;;
850 p[9]=piece3.length()%256;
851
852 stringbuffer+=piece1;
853 stringbuffer.append(p,10);
854 stringbuffer+=piece3;
855
856 d.ancount++;
857}
858void DNSPacket::addHINFORecord(const DNSResourceRecord& rr)
859{
860  addHINFORecord(rr.qname, rr.content, rr.ttl);
861}
862
863/** First word of content is the CPU */
864void DNSPacket::addHINFORecord(string domain, string content, uint32_t ttl)
865{
866  string piece1;
867  toqname(domain, &piece1);
868  char p[10];
869  makeHeader(p,QType::HINFO,ttl);
870 
871  string::size_type offset=content.find(" ");
872  string cpu, host;
873  if(offset==string::npos) {
874    cpu=content;
875  } else {
876    cpu=content.substr(0,offset);
877    host=content.substr(offset);
878  }
879 
880  string piece3;
881  piece3.reserve(cpu.length()+1);
882  piece3.append(1,cpu.length());
883  piece3.append(cpu);
884 
885  string piece4;
886  piece4.reserve(host.length()+1);
887  piece4.append(1,host.length());
888  piece4.append(host);
889   
890  p[8]=0;
891  p[9]=piece3.length()+piece4.length();
892 
893  stringbuffer+=piece1;
894  stringbuffer.append(p,10);
895  stringbuffer+=piece3;
896  stringbuffer+=piece4;
897 
898  d.ancount++;
899}
900
901void DNSPacket::addNSRecord(const DNSResourceRecord &rr)
902{
903  addNSRecord(rr.qname, rr.content, rr.ttl, rr.d_place);
904}
905
906void DNSPacket::addNSRecord(string domain, string server, uint32_t ttl, DNSResourceRecord::Place place)
907{
908  string piece1;
909  toqname(domain, &piece1);
910
911  char p[10];
912  makeHeader(p,QType::NS,ttl);
913
914  string piece3;
915  string::size_type pos=server.find('@'); // chop off @
916  if(pos!=string::npos)
917    server.resize(pos);
918
919  toqname(server,&piece3);
920
921  p[9]=piece3.length();;
922
923  stringbuffer.append(piece1);
924  stringbuffer.append(p,10);
925  stringbuffer.append(piece3);
926
927  if(place==DNSResourceRecord::AUTHORITY)
928    d.nscount++;
929  else
930    d.ancount++;
931
932}
933
934
935static int rrcomp(const DNSResourceRecord &A, const DNSResourceRecord &B)
936{
937  if(A.d_place<B.d_place)
938    return 1;
939
940  return 0;
941}
942
943/** You can call this function to find out if there are any records that need additional processing.
944    This holds for MX records and CNAME records, where information about the content may need further resolving. */
945bool DNSPacket::needAP()
946{
947  // if speed ever becomes an issue, this function might be implemented in the addRecord() method, which would set a flag
948  // whenever a record that needs additional processing is added
949
950  for(vector<DNSResourceRecord>::const_iterator i=rrs.begin();
951      i!=rrs.end();
952      ++i)
953    {
954      if(i->d_place!=DNSResourceRecord::ADDITIONAL && 
955         ( (i->qtype.getCode()==QType::NS && i->content.find('@')==string::npos) ||  // NS records with @ in them are processed
956          i->qtype.getCode()==QType::MX )) 
957        {
958          return true;
959        }
960    }
961  return false;
962}
963
964vector<DNSResourceRecord*> DNSPacket::getAPRecords()
965{
966  vector<DNSResourceRecord*> arrs;
967
968  for(vector<DNSResourceRecord>::iterator i=rrs.begin();
969      i!=rrs.end();
970      ++i)
971    {
972      if(i->d_place!=DNSResourceRecord::ADDITIONAL && 
973         (i->qtype.getCode()==15 || 
974          i->qtype.getCode()==2 )) // CNAME or MX or NS
975        {
976          arrs.push_back(&*i);
977        }
978    }
979
980  return arrs;
981
982}
983
984void DNSPacket::setCompress(bool compress)
985{
986  d_compress=compress;
987  stringbuffer.reserve(65000);
988  rrs.reserve(200);
989}
990
991/** Must be called before attempting to access getData(). This function stuffs all resource
992 *  records found in rrs into the data buffer. It also frees resource records queued for us.
993 */
994void DNSPacket::wrapup(void)
995{
996  if(d_wrapped) {
997    return;
998  }
999 
1000  // do embedded-additional processing decapsulation
1001  DNSResourceRecord rr;
1002  vector<DNSResourceRecord>::iterator pos;
1003
1004  vector<DNSResourceRecord> additional;
1005  for(pos=rrs.begin();pos<rrs.end();++pos) {
1006    if(pos->qtype.getCode()==QType::NS) {
1007      vector<string>pieces;
1008      stringtok(pieces,pos->content,"@");
1009     
1010      if(pieces.size() > 1) { // INSTANT ADDITIONAL PROCESSING!
1011        rr.qname=pieces[0];
1012        rr.qtype=QType::A;
1013        rr.ttl=pos->ttl;
1014        rr.content=pieces[1];
1015        rr.d_place=DNSResourceRecord::ADDITIONAL;
1016        additional.push_back(rr);
1017      }
1018    }
1019  }
1020  int ipos=rrs.size();
1021  rrs.resize(rrs.size()+additional.size());
1022  copy(additional.begin(), additional.end(), rrs.begin()+ipos);
1023
1024  // we now need to order rrs so that the different sections come at the right place
1025  // we want a stable sort, based on the d_place field
1026
1027  stable_sort(rrs.begin(),rrs.end(),rrcomp);
1028
1029  if(!d_tcp && !arg().mustDo("no-shuffle")) {
1030    shuffle(rrs);
1031  }
1032  d_wrapped=true;
1033
1034
1035  for(pos=rrs.begin();pos<rrs.end();++pos) {
1036    rr=*pos;
1037    DLOG(L<<"Added to data, RR: " << rr.qname);
1038    DLOG(L<<"(" << rr.qtype.getName() << ")" << " " << (int) rr.d_place<< endl);
1039
1040    switch(rr.qtype.getCode()) {
1041    case 1:  // A
1042      addARecord(rr);
1043      break;
1044    case 2:  // NS
1045      addNSRecord(rr);
1046      break;
1047
1048    case 5:  // CNAME
1049      addCNAMERecord(rr);
1050      break;
1051
1052    case 6:  // SOA
1053      addSOARecord(rr);
1054      break;
1055
1056    case QType::MR:
1057      addMRRecord(rr);
1058      break;
1059
1060    case 12:  // PTR
1061      addPTRRecord(rr);
1062      break;
1063
1064    case 13: // HINFO
1065      addHINFORecord(rr);
1066      break;
1067
1068    case 15: // MX
1069      addMXRecord(rr);
1070      break;
1071
1072    case QType::TXT: // TXT
1073
1074      addTXTRecord(rr);
1075      break;
1076
1077    case 17: // RP
1078      addRPRecord(rr);
1079      break;
1080
1081
1082    case 28: // AAAA
1083      addAAAARecord(rr);
1084      break;
1085
1086    case QType::SRV: 
1087      addSRVRecord(rr); 
1088      break;
1089
1090    case QType::LOC:
1091      addLOCRecord(rr);
1092      break;
1093
1094    case QType::NAPTR:
1095      addNAPTRRecord(rr);
1096      break;
1097
1098    case QType::SPF: // SPF
1099      addSPFRecord(rr);
1100      break;
1101
1102    case 258: // CURL
1103    case 256: // URL
1104      addARecord(rr.qname,htonl(inet_addr(arg()["urlredirector"].c_str())),rr.ttl,DNSResourceRecord::ANSWER);   
1105      break;
1106
1107    case 257: // MBOXFW
1108      string::size_type pos;
1109      pos=rr.qname.find("@");
1110      DLOG(L<<Logger::Warning<<"Adding rr.qname: '"<<rr.qname<<"'"<<endl);
1111      if(pos!=string::npos)
1112        {
1113          string substr=rr.qname.substr(pos+1);
1114
1115          addMXRecord(substr,arg()["smtpredirector"],25,rr.ttl);
1116        }
1117      break;
1118
1119    default:
1120      if(rr.qtype.getCode()>1024)
1121        addGenericRecord(rr);
1122      else
1123        L<<Logger::Warning<<"Unable to insert a record of type "<<rr.qtype.getName()<<" for '"<<rr.qname<<"'"<<endl;
1124    }
1125  }
1126  d.ancount=htons(d.ancount);
1127  d.qdcount=htons(d.qdcount);
1128  d.nscount=htons(d.nscount);
1129  d.arcount=htons(d.arcount);
1130
1131  commitD();
1132
1133  len=stringbuffer.length();
1134}
1135
1136void DNSPacket::addGenericRecord(const DNSResourceRecord& rr)
1137{
1138  string piece1;
1139 //xtoqname(domain, &piece1);
1140 toqname(rr.qname, &piece1);
1141 char p[10];
1142 
1143 p[0]=0;
1144 p[1]=rr.qtype.getCode()-1024; // TXT
1145 p[2]=0;
1146 p[3]=1; // IN
1147
1148 putLong(p+4,rr.ttl);
1149
1150 p[8]=rr.content.length()/256;
1151 p[9]=rr.content.length()%256; // need to fill this in
1152
1153 stringbuffer+=piece1;
1154 stringbuffer.append(p,10);
1155 stringbuffer+=rr.content;
1156 if(rr.d_place==DNSResourceRecord::ADDITIONAL)
1157   d.arcount++;
1158 else
1159   d.ancount++;
1160}
1161
1162/** Truncates a packet that has already been wrapup()-ed, possibly via a call to getData(). Do not call this function
1163    before having done this - it will possibly break your packet, or crash your program.
1164
1165    This method sets the 'TC' bit in the stringbuffer, and caps the len attributed to new_length.
1166*/ 
1167
1168void DNSPacket::truncate(int new_length)
1169{
1170  if(new_length>len || !d_wrapped)
1171    return;
1172
1173  DLOG(L<<Logger::Warning<<"Truncating a packet to "<< remote.toString() <<endl);
1174
1175  len=new_length;
1176  stringbuffer[2]|=2; // set TC
1177}
1178
1179string DNSPacket::compress(const string &qd)
1180{
1181  // input www.casema.net, output 3www6casema3net
1182  // input www.casema.net., output 3www6casema3net
1183  string qname = "";
1184
1185  // Convert the name to a qname
1186
1187  const char *p = qd.c_str();
1188  const char *q = strchr(p, '.');
1189 
1190  while (p <= (qd.c_str() + qd.length()))
1191    {
1192      int length = (q == NULL) ? strlen(p) : (q - p);
1193      if (length == 0) {
1194        break;
1195      }
1196      qname += (char) length;
1197      qname.append(p, length);
1198     
1199      if (q == NULL) {
1200        break;
1201      } else {
1202        p = q + 1;
1203        q = strchr(p, '.');
1204      }
1205    }
1206 
1207  qname += (char) 0x00;
1208  return qname;
1209}
1210
1211void DNSPacket::setQuestion(int op, const string &qd, int newqtype)
1212{
1213  memset(&d,0,sizeof(d));
1214  d.id=Utility::random();
1215  d.rd=d.tc=d.aa=false;
1216  d.qr=false;
1217  d.qdcount=1; // is htons'ed later on
1218  d.ancount=d.arcount=d.nscount=0;
1219  d.opcode=op;
1220  qdomain=qd;
1221  qtype=newqtype;
1222  string label=compress(qd);
1223  stringbuffer.assign((char *)&d,sizeof(d));
1224  stringbuffer.append(label);
1225  uint16_t tmp=htons(newqtype);
1226  stringbuffer.append((char *)&tmp,2);
1227  tmp=htons(1);
1228  stringbuffer.append((char *)&tmp,2);
1229}
1230
1231/** A DNS answer packets needs to include the original question. This function allows you to
1232    paste in a question */
1233
1234void DNSPacket::pasteQ(const char *question, int length)
1235{
1236  stringbuffer.replace(12,length,question,length);  // bytes 12 & onward need to become *question
1237}
1238
1239
1240vector<DNSResourceRecord> DNSPacket::getAnswers()
1241{
1242  // XXX FIXME a lot of this code happily touches bytes beyond your packet!
1243
1244  vector<DNSResourceRecord> rrs;
1245  if(!(d.ancount|d.arcount|d.nscount))
1246    return rrs;
1247
1248  const unsigned char *answerp=(const unsigned char *)stringbuffer.c_str()+d_qlen+12;
1249  const unsigned char *end=(const unsigned char *)stringbuffer.c_str()+len;
1250
1251  int numanswers=ntohs(d.ancount) + ntohs(d.nscount) + ntohs(d.arcount);
1252  int length;
1253  uint16_t pos=0;
1254  while(numanswers--) {
1255    string name; 
1256    int offset=0;
1257    offset=expand(answerp,end,name);
1258
1259    DNSResourceRecord rr;
1260    rr.qname=name;
1261    rr.qtype=answerp[offset]*256+answerp[offset+1];
1262    rr.ttl=answerp[offset+7]+256*(answerp[offset+6]+256*(answerp[offset+5]+256*answerp[offset+4]));
1263    rr.content="";
1264    length=256*(unsigned char)answerp[offset+8]+(unsigned char)answerp[offset+8+1];
1265
1266    const unsigned char *datapos=answerp+offset+10;
1267
1268    if(datapos+length  > end)
1269      throw AhuException("Record extends beyond end of packet");
1270
1271    string part;
1272    offset=0;
1273
1274    ostringstream o;
1275    int ip;
1276    int weight;
1277    int port;
1278
1279    switch(rr.qtype.getCode()) {
1280
1281    case QType::SOA:
1282      part=""; offset+=expand(datapos+offset,end,part); rr.content=part;      // mname
1283      part=""; offset+=expand(datapos+offset,end,part); rr.content+=" "+part;  // hostmaster
1284
1285      // explicitly copy the SOA values out of the packet to avoid
1286      // SPARC alignment issues.
1287     
1288      rr.content+=" ";rr.content+=uitoa(getLong( datapos+offset    ));
1289      rr.content+=" ";rr.content+=uitoa(getLong( datapos+offset+4  ));
1290      rr.content+=" ";rr.content+=uitoa(getLong( datapos+offset+8  ));
1291      rr.content+=" ";rr.content+=uitoa(getLong( datapos+offset+12 ));
1292      rr.content+=" ";rr.content+=uitoa(getLong( datapos+offset+16 ));
1293
1294      break;
1295
1296    case QType::A:
1297      ip = getLong(datapos);
1298
1299      o.clear();
1300      o<<((ip>>24)&0xff)<<".";
1301      o<<((ip>>16)&0xff)<<".";
1302      o<<((ip>>8)&0xff)<<".";
1303      o<<((ip>>0)&0xff);
1304     
1305      rr.content=o.str();
1306      break;
1307     
1308    case QType::MX:
1309      rr.priority=(datapos[0] << 8) + datapos[1];
1310      expand(datapos+2,end,rr.content);
1311
1312      break;
1313
1314    case QType::TXT:
1315      rr.content.assign((const char *)datapos+offset+1,(int)datapos[offset]);
1316      break;
1317
1318    case QType::HINFO:  // this code is way way way overdue for a redesign
1319      rr.content="\"";
1320      rr.content.append((const char *)datapos+offset+1,(int)datapos[offset]);
1321      rr.content+="\" \"";
1322      rr.content.append((const char *)datapos+offset+(int)datapos[offset]+2,
1323                        (int)datapos[offset+(int)datapos[offset]+1]);
1324      rr.content+="\"";
1325      break;
1326
1327
1328    case QType::LOC:
1329      rr.content=parseLOC(reinterpret_cast<const unsigned char *>(datapos+offset),length);
1330      break;
1331
1332
1333    case QType::SRV: // rfc 2052
1334      // priority goes into mx-priority
1335      rr.priority=(datapos[0] << 8) + datapos[1];
1336      // rest glue together 
1337      weight = (datapos[2] << 8) + datapos[3];
1338      port = (datapos[4] << 8) + datapos[5];
1339      expand(datapos+offset+6,end,part);
1340      rr.content.assign(itoa(weight));
1341      rr.content+=" "+itoa(port)+" "+part;
1342      break;
1343
1344    case QType::NAPTR: // rfc 2915
1345      {
1346        const string quote="\"";
1347        const string space=" ";
1348
1349        int order;
1350        int pref;
1351        string flags, services, regex, replacement, result;
1352
1353        order=(datapos[0] << 8) + datapos[1];
1354
1355        // "pref" should maybe be put into rr.priority, but that
1356        // might have unintended side effects that I cannot
1357        // evaluate at this time.
1358        //
1359        // Lorens Kockum 2004-10-12
1360
1361        pref=(datapos[2] << 8) + datapos[3];
1362
1363        // The following would be a good subject for a mini-
1364        // function with boundary checking, which could be
1365        // reused in a lot of places in this file (see FIXME
1366        // at beginning of function).
1367
1368        offset = 4 ;
1369        flags.assign((const char *)datapos+offset+1,(int)datapos[offset]);
1370        offset+=flags.size()+1;
1371        services.assign((const char *)datapos+offset+1,(int)datapos[offset]);
1372        offset+=services.size()+1;
1373        regex.assign((const char *)datapos+offset+1,(int)datapos[offset]);
1374        offset+=regex.size()+1;
1375
1376        expand(datapos+offset,end,replacement);
1377
1378        if (!replacement.size()) replacement = "." ;
1379
1380        rr.content = itoa(order) \
1381                     + " " + itoa(pref) \
1382                     + " " + quote + flags + quote \
1383                     + " " + quote + services + quote \
1384                     + " " + quote + regex + quote \
1385                     + " " + replacement;
1386      }
1387      break;
1388
1389    case QType::RP:
1390      offset+=expand(datapos+offset,end,rr.content);
1391      expand(datapos+offset,end,part);
1392      rr.content+=" "+part;
1393      break;
1394
1395
1396    case QType::CNAME:
1397    case QType::NS:
1398    case QType::PTR:
1399    case QType::MR:
1400      expand(datapos+offset,end,rr.content);
1401      break;
1402
1403    case QType::AAAA:
1404      if(length!=16)
1405        throw AhuException("Wrong length AAAA record returned from remote");
1406      char tmp[128];
1407#ifdef AF_INET6
1408      if(!Utility::inet_ntop(AF_INET6, (const char *)datapos, tmp, sizeof(tmp)-1))
1409#endif
1410        throw AhuException("Unable to translate record of type AAAA in resolver");
1411
1412      rr.content=tmp;
1413      break;
1414
1415    default:
1416      rr.qtype=rr.qtype.getCode()+1024;
1417      rr.content.assign((const char *)datapos,length);
1418      //      throw AhuException("Unknown type number "+itoa(rr.qtype.getCode())+" for: '"+rr.qname+"'");
1419    }
1420    if(pos<ntohs(d.ancount))
1421      rr.d_place=DNSResourceRecord::ANSWER;
1422    else if(pos<ntohs(d.ancount)+ntohs(d.nscount))
1423      rr.d_place=DNSResourceRecord::AUTHORITY;
1424    else
1425      rr.d_place=DNSResourceRecord::ADDITIONAL;
1426     
1427    rrs.push_back(rr);   
1428    pos++;
1429    //    cout<<"Added '"<<rr.qname<<"' '"<<rr.content<<"' "<<rr.qtype.getName()<<endl;
1430    //    cout<<"Advancing "<<length<<" bytes"<<endl;
1431    answerp=datapos+length; 
1432  }
1433  return rrs;
1434 
1435}
1436
1437/** convenience function for creating a reply packet from a question packet. Do not forget to delete it after use! */
1438DNSPacket *DNSPacket::replyPacket() const
1439{
1440  DNSPacket *r=new DNSPacket;
1441  r->setSocket(d_socket);
1442
1443  r->setRemote(&remote);
1444  r->setAnswer(true);  // this implies the allocation of the header
1445  r->setA(true); // and we are authoritative
1446  r->setRA(0); // no recursion available
1447  r->setRD(d.rd); // if you wanted to recurse, answer will say you wanted it (we don't do it)
1448  r->setID(d.id);
1449  r->setOpcode(d.opcode);
1450
1451  // reserve some space
1452  r->stringbuffer.reserve(d_qlen+12);
1453  // copy the question in
1454  r->pasteQ(stringbuffer.c_str()+12,d_qlen);
1455 
1456  r->d_dt=d_dt;
1457  r->d.qdcount=1;
1458  r->d_tcp = d_tcp;
1459  return r;
1460}
1461
1462int DNSPacket::findlabel(string &label)
1463{
1464  const char *data = stringbuffer.data();
1465  const char *p = data + 12;
1466
1467  // Look in the question section
1468   
1469  for (unsigned int i = 0; i < d.qdcount; i++) {
1470    while (*p != 0x00) {
1471      // Skip compressed labels
1472      if ((*p & 0xC0) == 0xC0) {
1473        p += 1;
1474        break;
1475      }
1476      else {
1477        if (strncmp(p, label.data(), label.size()) == 0)
1478          return (p - data);
1479        p += (*p + 1);
1480      }
1481    }
1482     
1483    // Skip the tailing zero
1484    p++;
1485   
1486    // Skip the header
1487    p += 4;
1488  }
1489
1490  // Look in the answer sections
1491
1492  for (unsigned int i = 0; i < d.ancount + d.nscount + d.arcount; i++) {
1493    while (*p != 0x00) {
1494      // Skip compressed labels - means the end
1495      if ((*p & 0xC0) == 0xC0)
1496        {
1497          p += 1;
1498          break;
1499        }
1500      else
1501        {
1502          if (strncmp(p, label.data(), label.size()) == 0)
1503            {
1504              return (p - data);
1505            }
1506         
1507          p += (*p + 1);
1508        }
1509    }
1510   
1511    // Skip the trailing zero or other half of the ptr
1512       
1513    p++;
1514
1515    // Skip the header and data
1516   
1517    uint16_t dataLength = getShort(p+8);
1518    uint16_t type = getShort(p); 
1519
1520    p += 10;
1521   
1522    // Check for NS, CNAME, PTR and MX records
1523   
1524    if (type == QType::NS || type == QType::CNAME || type == QType::PTR || type == QType::MX) {
1525      // For MX records, skip the preference field
1526      if (type == QType::MX){
1527        p += 2;
1528      }
1529
1530      while (*p != 0x00) {
1531        //
1532        // Skip compressed labels
1533        //
1534       
1535        if ((*p & 0xC0) == 0xC0) {
1536          p += 1;
1537          break;
1538        }
1539        else {
1540
1541          if (strncmp(p, label.data(), label.size()) == 0) {
1542            return (p - data);
1543          }
1544                   
1545          p += (*p + 1);
1546        }
1547      }
1548           
1549      // Skip the trailing zero or the last byte of a compresed label
1550      p++;       
1551    }
1552    else {
1553      p += dataLength;
1554    }
1555  }
1556 
1557  return -1;
1558}
1559
1560int DNSPacket::toqname(const char *name, string &qname, bool comp)
1561{
1562  qname = compress(name);
1563
1564  if (d_compress && comp) {
1565    // Now find a previous declared label. We work through the complete
1566    // name from left to right like this:
1567    //  ns1.norad.org
1568    //  norad.org
1569    //  org
1570   
1571    int i = 0;
1572    bool containsptr=false;
1573   
1574    while (qname[i] != 0x00 &&  /* qname[i] == 0x00 => i == qname.length */
1575        (qname[i] & 0xC0) != 0xC0) {    // no use to try to compress offsets
1576      // Get a portion of the name
1577     
1578      // qname must include an extra trailing '\0' if it's prefix
1579      // is not an offset ptr
1580      string s = qname.substr(i);       /* s == qname[i..N) */
1581      if (!containsptr) s = s + '\0';
1582
1583
1584      // Did we see this before?
1585      int offset = findlabel(s);
1586     
1587      if ( offset != -1) {
1588        qname[i + 0] = (char) (((offset | 0xC000) & 0x0000FF00) >> 8);
1589        qname[i + 1] = (char)  ((offset | 0xC000) & 0x000000FF);
1590        qname = qname.substr(0, i + 2); // XX setlength() ?
1591        containsptr=true;
1592        // qname now consists of unique prefix+known suffix (on location 'offset')
1593        // we managed to make qname shorter, maybe we can do that again
1594        i = 0;
1595       
1596      }
1597      else {                            /* offset == -1 */
1598        // Move to the next label
1599        i += (qname[i] + 1); // doesn't quite handle very long labels
1600      }
1601    }
1602  }
1603 
1604  return qname.length();
1605}
1606
1607int DNSPacket::toqname(const string &name, string &qname, bool compress)
1608{
1609   return toqname(name.c_str(), qname, compress);
1610}
1611
1612int DNSPacket::toqname(const string &name, string *qname, bool compress)
1613{
1614   return toqname(name.c_str(), *qname, compress);
1615}
1616
Note: See TracBrowser for help on using the browser.