Anope IRC Services  Version 2.0
m_dns.cpp
Go to the documentation of this file.
1 /*
2  *
3  * (C) 2003-2014 Anope Team
4  * Contact us at team@anope.org
5  *
6  * Please read COPYING and README for further details.
7  *
8  * Based on the original code of Epona by Lara.
9  * Based on the original code of Services by Andy Church.
10  *
11  */
12 
13 #include "module.h"
14 #include "modules/dns.h"
15 
16 using namespace DNS;
17 
18 namespace
19 {
20  Anope::string admin, nameservers;
21  int refresh;
22  time_t timeout;
23 }
24 
27 class Packet : public Query
28 {
29  void PackName(unsigned char *output, unsigned short output_size, unsigned short &pos, const Anope::string &name)
30  {
31  if (pos + name.length() + 2 > output_size)
32  throw SocketException("Unable to pack name");
33 
34  Log(LOG_DEBUG_2) << "Resolver: PackName packing " << name;
35 
36  sepstream sep(name, '.');
37  Anope::string token;
38 
39  while (sep.GetToken(token))
40  {
41  output[pos++] = token.length();
42  memcpy(&output[pos], token.c_str(), token.length());
43  pos += token.length();
44  }
45 
46  output[pos++] = 0;
47  }
48 
49  Anope::string UnpackName(const unsigned char *input, unsigned short input_size, unsigned short &pos)
50  {
52  unsigned short pos_ptr = pos, lowest_ptr = input_size;
53  bool compressed = false;
54 
55  if (pos_ptr >= input_size)
56  throw SocketException("Unable to unpack name - no input");
57 
58  while (input[pos_ptr] > 0)
59  {
60  unsigned short offset = input[pos_ptr];
61 
62  if (offset & POINTER)
63  {
64  if ((offset & POINTER) != POINTER)
65  throw SocketException("Unable to unpack name - bogus compression header");
66  if (pos_ptr + 1 >= input_size)
67  throw SocketException("Unable to unpack name - bogus compression header");
68 
69  /* Place pos at the second byte of the first (farthest) compression pointer */
70  if (compressed == false)
71  {
72  ++pos;
73  compressed = true;
74  }
75 
76  pos_ptr = (offset & LABEL) << 8 | input[pos_ptr + 1];
77 
78  /* Pointers can only go back */
79  if (pos_ptr >= lowest_ptr)
80  throw SocketException("Unable to unpack name - bogus compression pointer");
81  lowest_ptr = pos_ptr;
82  }
83  else
84  {
85  if (pos_ptr + offset + 1 >= input_size)
86  throw SocketException("Unable to unpack name - offset too large");
87  if (!name.empty())
88  name += ".";
89  for (unsigned i = 1; i <= offset; ++i)
90  name += input[pos_ptr + i];
91 
92  pos_ptr += offset + 1;
93  if (compressed == false)
94  /* Move up pos */
95  pos = pos_ptr;
96  }
97  }
98 
99  /* +1 pos either to one byte after the compression pointer or one byte after the ending \0 */
100  ++pos;
101 
102  if (name.empty())
103  throw SocketException("Unable to unpack name - no name");
104 
105  Log(LOG_DEBUG_2) << "Resolver: UnpackName successfully unpacked " << name;
106 
107  return name;
108  }
109 
110  Question UnpackQuestion(const unsigned char *input, unsigned short input_size, unsigned short &pos)
111  {
112  Question question;
113 
114  question.name = this->UnpackName(input, input_size, pos);
115 
116  if (pos + 4 > input_size)
117  throw SocketException("Unable to unpack question");
118 
119  question.type = static_cast<QueryType>(input[pos] << 8 | input[pos + 1]);
120  pos += 2;
121 
122  question.qclass = input[pos] << 8 | input[pos + 1];
123  pos += 2;
124 
125  return question;
126  }
127 
128  ResourceRecord UnpackResourceRecord(const unsigned char *input, unsigned short input_size, unsigned short &pos)
129  {
130  ResourceRecord record = static_cast<ResourceRecord>(this->UnpackQuestion(input, input_size, pos));
131 
132  if (pos + 6 > input_size)
133  throw SocketException("Unable to unpack resource record");
134 
135  record.ttl = (input[pos] << 24) | (input[pos + 1] << 16) | (input[pos + 2] << 8) | input[pos + 3];
136  pos += 4;
137 
138  //record.rdlength = input[pos] << 8 | input[pos + 1];
139  pos += 2;
140 
141  switch (record.type)
142  {
143  case QUERY_A:
144  {
145  if (pos + 4 > input_size)
146  throw SocketException("Unable to unpack resource record");
147 
148  in_addr a;
149  a.s_addr = input[pos] | (input[pos + 1] << 8) | (input[pos + 2] << 16) | (input[pos + 3] << 24);
150  pos += 4;
151 
152  sockaddrs addrs;
153  addrs.ntop(AF_INET, &a);
154  if (!addrs.valid())
155  throw SocketException("Invalid IP");
156 
157  record.rdata = addrs.addr();
158  break;
159  }
160  case QUERY_AAAA:
161  {
162  if (pos + 16 > input_size)
163  throw SocketException("Unable to unpack resource record");
164 
165  in6_addr a;
166  for (int j = 0; j < 16; ++j)
167  a.s6_addr[j] = input[pos + j];
168  pos += 16;
169 
170  sockaddrs addrs;
171  addrs.ntop(AF_INET6, &a);
172  if (!addrs.valid())
173  throw SocketException("Invalid IP");
174 
175  record.rdata = addrs.addr();
176  break;
177  }
178  case QUERY_CNAME:
179  case QUERY_PTR:
180  {
181  record.rdata = this->UnpackName(input, input_size, pos);
182  break;
183  }
184  default:
185  break;
186  }
187 
188  Log(LOG_DEBUG_2) << "Resolver: " << record.name << " -> " << record.rdata;
189 
190  return record;
191  }
192 
193  public:
194  static const int POINTER = 0xC0;
195  static const int LABEL = 0x3F;
196  static const int HEADER_LENGTH = 12;
197 
199  /* Source or destination of the packet */
201  /* ID for this packet */
202  unsigned short id;
203  /* Flags on the packet */
204  unsigned short flags;
205 
206  Packet(Manager *m, sockaddrs *a) : manager(m), id(0), flags(0)
207  {
208  if (a)
209  addr = *a;
210  }
211 
212  void Fill(const unsigned char *input, const unsigned short len)
213  {
214  if (len < HEADER_LENGTH)
215  throw SocketException("Unable to fill packet");
216 
217  unsigned short packet_pos = 0;
218 
219  this->id = (input[packet_pos] << 8) | input[packet_pos + 1];
220  packet_pos += 2;
221 
222  this->flags = (input[packet_pos] << 8) | input[packet_pos + 1];
223  packet_pos += 2;
224 
225  unsigned short qdcount = (input[packet_pos] << 8) | input[packet_pos + 1];
226  packet_pos += 2;
227 
228  unsigned short ancount = (input[packet_pos] << 8) | input[packet_pos + 1];
229  packet_pos += 2;
230 
231  unsigned short nscount = (input[packet_pos] << 8) | input[packet_pos + 1];
232  packet_pos += 2;
233 
234  unsigned short arcount = (input[packet_pos] << 8) | input[packet_pos + 1];
235  packet_pos += 2;
236 
237  Log(LOG_DEBUG_2) << "Resolver: qdcount: " << qdcount << " ancount: " << ancount << " nscount: " << nscount << " arcount: " << arcount;
238 
239  for (unsigned i = 0; i < qdcount; ++i)
240  this->questions.push_back(this->UnpackQuestion(input, len, packet_pos));
241 
242  for (unsigned i = 0; i < ancount; ++i)
243  this->answers.push_back(this->UnpackResourceRecord(input, len, packet_pos));
244 
245  for (unsigned i = 0; i < nscount; ++i)
246  this->authorities.push_back(this->UnpackResourceRecord(input, len, packet_pos));
247 
248  for (unsigned i = 0; i < arcount; ++i)
249  this->additional.push_back(this->UnpackResourceRecord(input, len, packet_pos));
250  }
251 
252  unsigned short Pack(unsigned char *output, unsigned short output_size)
253  {
254  if (output_size < HEADER_LENGTH)
255  throw SocketException("Unable to pack packet");
256 
257  unsigned short pos = 0;
258 
259  output[pos++] = this->id >> 8;
260  output[pos++] = this->id & 0xFF;
261  output[pos++] = this->flags >> 8;
262  output[pos++] = this->flags & 0xFF;
263  output[pos++] = this->questions.size() >> 8;
264  output[pos++] = this->questions.size() & 0xFF;
265  output[pos++] = this->answers.size() >> 8;
266  output[pos++] = this->answers.size() & 0xFF;
267  output[pos++] = this->authorities.size() >> 8;
268  output[pos++] = this->authorities.size() & 0xFF;
269  output[pos++] = this->additional.size() >> 8;
270  output[pos++] = this->additional.size() & 0xFF;
271 
272  for (unsigned i = 0; i < this->questions.size(); ++i)
273  {
274  Question &q = this->questions[i];
275 
276  if (q.type == QUERY_PTR)
277  {
278  sockaddrs ip(q.name);
279  if (!ip.valid())
280  throw SocketException("Invalid IP");
281 
282  if (q.name.find(':') != Anope::string::npos)
283  {
284  const char *const hex = "0123456789abcdef";
285  char reverse_ip[128];
286  unsigned reverse_ip_count = 0;
287  for (int j = 15; j >= 0; --j)
288  {
289  reverse_ip[reverse_ip_count++] = hex[ip.sa6.sin6_addr.s6_addr[j] & 0xF];
290  reverse_ip[reverse_ip_count++] = '.';
291  reverse_ip[reverse_ip_count++] = hex[ip.sa6.sin6_addr.s6_addr[j] >> 4];
292  reverse_ip[reverse_ip_count++] = '.';
293  }
294  reverse_ip[reverse_ip_count++] = 0;
295 
296  q.name = reverse_ip;
297  q.name += "ip6.arpa";
298  }
299  else
300  {
301  unsigned long forward = ip.sa4.sin_addr.s_addr;
302  in_addr reverse;
303  reverse.s_addr = forward << 24 | (forward & 0xFF00) << 8 | (forward & 0xFF0000) >> 8 | forward >> 24;
304 
305  ip.ntop(AF_INET, &reverse);
306 
307  q.name = ip.addr() + ".in-addr.arpa";
308  }
309  }
310 
311  this->PackName(output, output_size, pos, q.name);
312 
313  if (pos + 4 >= output_size)
314  throw SocketException("Unable to pack packet");
315 
316  short s = htons(q.type);
317  memcpy(&output[pos], &s, 2);
318  pos += 2;
319 
320  s = htons(q.qclass);
321  memcpy(&output[pos], &s, 2);
322  pos += 2;
323  }
324 
325  std::vector<ResourceRecord> types[] = { this->answers, this->authorities, this->additional };
326  for (int i = 0; i < 3; ++i)
327  for (unsigned j = 0; j < types[i].size(); ++j)
328  {
329  ResourceRecord &rr = types[i][j];
330 
331  this->PackName(output, output_size, pos, rr.name);
332 
333  if (pos + 8 >= output_size)
334  throw SocketException("Unable to pack packet");
335 
336  short s = htons(rr.type);
337  memcpy(&output[pos], &s, 2);
338  pos += 2;
339 
340  s = htons(rr.qclass);
341  memcpy(&output[pos], &s, 2);
342  pos += 2;
343 
344  long l = htonl(rr.ttl);
345  memcpy(&output[pos], &l, 4);
346  pos += 4;
347 
348  switch (rr.type)
349  {
350  case QUERY_A:
351  {
352  if (pos + 6 > output_size)
353  throw SocketException("Unable to pack packet");
354 
355  sockaddrs a(rr.rdata);
356  if (!a.valid())
357  throw SocketException("Invalid IP");
358 
359  s = htons(4);
360  memcpy(&output[pos], &s, 2);
361  pos += 2;
362 
363  memcpy(&output[pos], &a.sa4.sin_addr, 4);
364  pos += 4;
365  break;
366  }
367  case QUERY_AAAA:
368  {
369  if (pos + 18 > output_size)
370  throw SocketException("Unable to pack packet");
371 
372  sockaddrs a(rr.rdata);
373  if (!a.valid())
374  throw SocketException("Invalid IP");
375 
376  s = htons(16);
377  memcpy(&output[pos], &s, 2);
378  pos += 2;
379 
380  memcpy(&output[pos], &a.sa6.sin6_addr, 16);
381  pos += 16;
382  break;
383  }
384  case QUERY_NS:
385  case QUERY_CNAME:
386  case QUERY_PTR:
387  {
388  if (pos + 2 >= output_size)
389  throw SocketException("Unable to pack packet");
390 
391  unsigned short packet_pos_save = pos;
392  pos += 2;
393 
394  this->PackName(output, output_size, pos, rr.rdata);
395 
396  s = htons(pos - packet_pos_save - 2);
397  memcpy(&output[packet_pos_save], &s, 2);
398  break;
399  }
400  case QUERY_SOA:
401  {
402  if (pos + 2 >= output_size)
403  throw SocketException("Unable to pack packet");
404 
405  unsigned short packet_pos_save = pos;
406  pos += 2;
407 
408  std::vector<Anope::string> ns;
409  spacesepstream(nameservers).GetTokens(ns);
410  this->PackName(output, output_size, pos, !ns.empty() ? ns[0] : "");
411  this->PackName(output, output_size, pos, admin.replace_all_cs('@', '.'));
412 
413  if (pos + 20 >= output_size)
414  throw SocketException("Unable to pack SOA");
415 
416  l = htonl(manager->GetSerial());
417  memcpy(&output[pos], &l, 4);
418  pos += 4;
419 
420  l = htonl(refresh); // Refresh
421  memcpy(&output[pos], &l, 4);
422  pos += 4;
423 
424  l = htonl(refresh); // Retry
425  memcpy(&output[pos], &l, 4);
426  pos += 4;
427 
428  l = htonl(604800); // Expire
429  memcpy(&output[pos], &l, 4);
430  pos += 4;
431 
432  l = htonl(0); // Minimum
433  memcpy(&output[pos], &l, 4);
434  pos += 4;
435 
436  s = htons(pos - packet_pos_save - 2);
437  memcpy(&output[packet_pos_save], &s, 2);
438 
439  break;
440  }
441  default:
442  break;
443  }
444  }
445 
446  return pos;
447  }
448 };
449 
450 namespace DNS
451 {
452  class ReplySocket : public virtual Socket
453  {
454  public:
455  virtual ~ReplySocket() { }
456  virtual void Reply(Packet *p) = 0;
457  };
458 }
459 
460 /* Listens for TCP requests */
461 class TCPSocket : public ListenSocket
462 {
464 
465  public:
466  /* A TCP client */
467  class Client : public ClientSocket, public Timer, public ReplySocket
468  {
471  unsigned char packet_buffer[524];
472  int length;
473 
474  public:
475  Client(Manager *m, TCPSocket *l, int fd, const sockaddrs &addr) : Socket(fd, l->IsIPv6()), ClientSocket(l, addr), Timer(5),
476  manager(m), packet(NULL), length(0)
477  {
478  Log(LOG_DEBUG_2) << "Resolver: New client from " << addr.addr();
479  }
480 
482  {
483  Log(LOG_DEBUG_2) << "Resolver: Exiting client from " << clientaddr.addr();
484  delete packet;
485  }
486 
487  /* Times out after a few seconds */
488  void Tick(time_t) anope_override { }
489 
491  {
492  delete packet;
493  packet = p;
494  SocketEngine::Change(this, true, SF_WRITABLE);
495  }
496 
498  {
499  Log(LOG_DEBUG_2) << "Resolver: Reading from DNS TCP socket";
500 
501  int i = recv(this->GetFD(), reinterpret_cast<char *>(packet_buffer) + length, sizeof(packet_buffer) - length, 0);
502  if (i <= 0)
503  return false;
504 
505  length += i;
506 
507  unsigned short want_len = packet_buffer[0] << 8 | packet_buffer[1];
508  if (length >= want_len + 2)
509  {
510  int len = length - 2;
511  length -= want_len + 2;
512  return this->manager->HandlePacket(this, packet_buffer + 2, len, NULL);
513  }
514  return true;
515  }
516 
518  {
519  Log(LOG_DEBUG_2) << "Resolver: Writing to DNS TCP socket";
520 
521  if (packet != NULL)
522  {
523  try
524  {
525  unsigned char buffer[65535];
526  unsigned short len = packet->Pack(buffer + 2, sizeof(buffer) - 2);
527 
528  short s = htons(len);
529  memcpy(buffer, &s, 2);
530  len += 2;
531 
532  send(this->GetFD(), reinterpret_cast<char *>(buffer), len, 0);
533  }
534  catch (const SocketException &) { }
535 
536  delete packet;
537  packet = NULL;
538  }
539 
540  SocketEngine::Change(this, false, SF_WRITABLE);
541  return true; /* Do not return false here, bind is unhappy we close the connection so soon after sending */
542  }
543  };
544 
545  TCPSocket(Manager *m, const Anope::string &ip, int port) : Socket(-1, ip.find(':') != Anope::string::npos), ListenSocket(ip, port, ip.find(':') != Anope::string::npos), manager(m) { }
546 
548  {
549  return new Client(this->manager, this, fd, addr);
550  }
551 };
552 
553 /* Listens for UDP requests */
554 class UDPSocket : public ReplySocket
555 {
557  std::deque<Packet *> packets;
558 
559  public:
560  UDPSocket(Manager *m, const Anope::string &ip, int port) : Socket(-1, ip.find(':') != Anope::string::npos, SOCK_DGRAM), manager(m) { }
561 
563  {
564  for (unsigned i = 0; i < packets.size(); ++i)
565  delete packets[i];
566  }
567 
569  {
570  packets.push_back(p);
571  SocketEngine::Change(this, true, SF_WRITABLE);
572  }
573 
574  std::deque<Packet *>& GetPackets() { return packets; }
575 
577  {
578  Log(LOG_DEBUG_2) << "Resolver: Reading from DNS UDP socket";
579 
580  unsigned char packet_buffer[524];
581  sockaddrs from_server;
582  socklen_t x = sizeof(from_server);
583  int length = recvfrom(this->GetFD(), reinterpret_cast<char *>(&packet_buffer), sizeof(packet_buffer), 0, &from_server.sa, &x);
584  return this->manager->HandlePacket(this, packet_buffer, length, &from_server);
585  }
586 
588  {
589  Log(LOG_DEBUG_2) << "Resolver: Writing to DNS UDP socket";
590 
591  Packet *r = !packets.empty() ? packets.front() : NULL;
592  if (r != NULL)
593  {
594  try
595  {
596  unsigned char buffer[524];
597  unsigned short len = r->Pack(buffer, sizeof(buffer));
598 
599  sendto(this->GetFD(), reinterpret_cast<char *>(buffer), len, 0, &r->addr.sa, r->addr.size());
600  }
601  catch (const SocketException &) { }
602 
603  delete r;
604  packets.pop_front();
605  }
606 
607  if (packets.empty())
608  SocketEngine::Change(this, false, SF_WRITABLE);
609 
610  return true;
611  }
612 };
613 
614 class NotifySocket : public Socket
615 {
617  public:
618  NotifySocket(bool v6, Packet *p) : Socket(-1, v6, SOCK_DGRAM), packet(p)
619  {
620  SocketEngine::Change(this, false, SF_READABLE);
621  SocketEngine::Change(this, true, SF_WRITABLE);
622  }
623 
625  {
626  if (!packet)
627  return false;
628 
629  Log(LOG_DEBUG_2) << "Resolver: Notifying slave " << packet->addr.addr();
630 
631  try
632  {
633  unsigned char buffer[524];
634  unsigned short len = packet->Pack(buffer, sizeof(buffer));
635 
636  sendto(this->GetFD(), reinterpret_cast<char *>(buffer), len, 0, &packet->addr.sa, packet->addr.size());
637  }
638  catch (const SocketException &) { }
639 
640  delete packet;
641  packet = NULL;
642 
643  return false;
644  }
645 };
646 
647 class MyManager : public Manager, public Timer
648 {
649  uint32_t serial;
650 
651  typedef TR1NS::unordered_map<Question, Query, Question::hash> cache_map;
652  cache_map cache;
653 
656 
657  bool listen;
659 
660  std::vector<std::pair<Anope::string, short> > notify;
661  public:
662  std::map<unsigned short, Request *> requests;
663 
664  MyManager(Module *creator) : Manager(creator), Timer(300, Anope::CurTime, true), serial(Anope::CurTime), tcpsock(NULL), udpsock(NULL),
665  listen(false), cur_id(rand())
666  {
667  }
668 
670  {
671  delete udpsock;
672  delete tcpsock;
673 
674  for (std::map<unsigned short, Request *>::iterator it = this->requests.begin(), it_end = this->requests.end(); it != it_end;)
675  {
676  Request *request = it->second;
677  ++it;
678 
679  Query rr(*request);
680  rr.error = ERROR_UNKNOWN;
681  request->OnError(&rr);
682 
683  delete request;
684  }
685  this->requests.clear();
686 
687  this->cache.clear();
688  }
689 
690  void SetIPPort(const Anope::string &nameserver, const Anope::string &ip, unsigned short port, std::vector<std::pair<Anope::string, short> > n)
691  {
692  delete udpsock;
693  delete tcpsock;
694 
695  udpsock = NULL;
696  tcpsock = NULL;
697 
698  try
699  {
700  this->addrs.pton(nameserver.find(':') != Anope::string::npos ? AF_INET6 : AF_INET, nameserver, 53);
701 
702  udpsock = new UDPSocket(this, ip, port);
703 
704  if (!ip.empty())
705  {
706  udpsock->Bind(ip, port);
707  tcpsock = new TCPSocket(this, ip, port);
708  listen = true;
709  }
710  }
711  catch (const SocketException &ex)
712  {
713  Log() << "Unable to bind dns to " << ip << ":" << port << ": " << ex.GetReason();
714  }
715 
716  notify = n;
717  }
718 
719  private:
720  unsigned short cur_id;
721 
722  unsigned short GetID()
723  {
724  if (this->udpsock->GetPackets().size() == 65535)
725  throw SocketException("DNS queue full");
726 
727  do
728  cur_id = (cur_id + 1) & 0xFFFF;
729  while (!cur_id || this->requests.count(cur_id));
730 
731  return cur_id;
732  }
733 
734  public:
736  {
737  Log(LOG_DEBUG_2) << "Resolver: Processing request to lookup " << req->name << ", of type " << req->type;
738 
739  if (req->use_cache && this->CheckCache(req))
740  {
741  Log(LOG_DEBUG_2) << "Resolver: Using cached result";
742  delete req;
743  return;
744  }
745 
746  if (!this->udpsock)
747  throw SocketException("No dns socket");
748 
749  req->id = GetID();
750  this->requests[req->id] = req;
751 
752  req->SetSecs(timeout);
753 
754  Packet *p = new Packet(this, &this->addrs);
755  p->flags = QUERYFLAGS_RD;
756  p->id = req->id;
757  p->questions.push_back(*req);
758 
759  this->udpsock->Reply(p);
760  }
761 
763  {
764  this->requests.erase(req->id);
765  }
766 
767  bool HandlePacket(ReplySocket *s, const unsigned char *const packet_buffer, int length, sockaddrs *from) anope_override
768  {
769  if (length < Packet::HEADER_LENGTH)
770  return true;
771 
772  Packet recv_packet(this, from);
773 
774  try
775  {
776  recv_packet.Fill(packet_buffer, length);
777  }
778  catch (const SocketException &ex)
779  {
780  Log(LOG_DEBUG_2) << ex.GetReason();
781  return true;
782  }
783 
784  if (!(recv_packet.flags & QUERYFLAGS_QR))
785  {
786  if (!listen)
787  return true;
788  else if (recv_packet.questions.empty())
789  {
790  Log(LOG_DEBUG_2) << "Resolver: Received a question with no questions?";
791  return true;
792  }
793 
794  Packet *packet = new Packet(recv_packet);
795  packet->flags |= QUERYFLAGS_QR; /* This is a reponse */
796  packet->flags |= QUERYFLAGS_AA; /* And we are authoritative */
797 
798  packet->answers.clear();
799  packet->authorities.clear();
800  packet->additional.clear();
801 
802  for (unsigned i = 0; i < recv_packet.questions.size(); ++i)
803  {
804  const Question& q = recv_packet.questions[i];
805 
806  if (q.type == QUERY_AXFR || q.type == QUERY_SOA)
807  {
809  packet->answers.push_back(rr);
810 
811  if (q.type == QUERY_AXFR)
812  {
813  Anope::string token;
814  spacesepstream sep(nameservers);
815  while (sep.GetToken(token))
816  {
817  ResourceRecord rr2(q.name, QUERY_NS);
818  rr2.rdata = token;
819  packet->answers.push_back(rr2);
820  }
821  }
822  break;
823  }
824  }
825 
826  FOREACH_MOD(OnDnsRequest, (recv_packet, packet));
827 
828  for (unsigned i = 0; i < recv_packet.questions.size(); ++i)
829  {
830  const Question& q = recv_packet.questions[i];
831 
832  if (q.type == QUERY_AXFR)
833  {
835  packet->answers.push_back(rr);
836  break;
837  }
838  }
839 
840  s->Reply(packet);
841  return true;
842  }
843 
844  if (from == NULL)
845  {
846  Log(LOG_DEBUG_2) << "Resolver: Received an answer over TCP. This is not supported.";
847  return true;
848  }
849  else if (this->addrs != *from)
850  {
851  Log(LOG_DEBUG_2) << "Resolver: Received an answer from the wrong nameserver, Bad NAT or DNS forging attempt? '" << this->addrs.addr() << "' != '" << from->addr() << "'";
852  return true;
853  }
854 
855  std::map<unsigned short, Request *>::iterator it = this->requests.find(recv_packet.id);
856  if (it == this->requests.end())
857  {
858  Log(LOG_DEBUG_2) << "Resolver: Received an answer for something we didn't request";
859  return true;
860  }
861  Request *request = it->second;
862 
863  if (recv_packet.flags & QUERYFLAGS_OPCODE)
864  {
865  Log(LOG_DEBUG_2) << "Resolver: Received a nonstandard query";
866  recv_packet.error = ERROR_NONSTANDARD_QUERY;
867  request->OnError(&recv_packet);
868  }
869  else if (recv_packet.flags & QUERYFLAGS_RCODE)
870  {
871  Error error = ERROR_UNKNOWN;
872 
873  switch (recv_packet.flags & QUERYFLAGS_RCODE)
874  {
875  case 1:
876  Log(LOG_DEBUG_2) << "Resolver: format error";
877  error = ERROR_FORMAT_ERROR;
878  break;
879  case 2:
880  Log(LOG_DEBUG_2) << "Resolver: server error";
881  error = ERROR_SERVER_FAILURE;
882  break;
883  case 3:
884  Log(LOG_DEBUG_2) << "Resolver: domain not found";
885  error = ERROR_DOMAIN_NOT_FOUND;
886  break;
887  case 4:
888  Log(LOG_DEBUG_2) << "Resolver: not implemented";
889  error = ERROR_NOT_IMPLEMENTED;
890  break;
891  case 5:
892  Log(LOG_DEBUG_2) << "Resolver: refused";
893  error = ERROR_REFUSED;
894  break;
895  default:
896  break;
897  }
898 
899  recv_packet.error = error;
900  request->OnError(&recv_packet);
901  }
902  else if (recv_packet.questions.empty() || recv_packet.answers.empty())
903  {
904  Log(LOG_DEBUG_2) << "Resolver: No resource records returned";
905  recv_packet.error = ERROR_NO_RECORDS;
906  request->OnError(&recv_packet);
907  }
908  else
909  {
910  Log(LOG_DEBUG_2) << "Resolver: Lookup complete for " << request->name;
911  request->OnLookupComplete(&recv_packet);
912  this->AddCache(recv_packet);
913  }
914 
915  delete request;
916  return true;
917  }
918 
920  {
921  serial = Anope::CurTime;
922  }
923 
925  {
926  /* notify slaves of the update */
927  for (unsigned i = 0; i < notify.size(); ++i)
928  {
929  const Anope::string &ip = notify[i].first;
930  short port = notify[i].second;
931 
932  sockaddrs addr;
933  addr.pton(ip.find(':') != Anope::string::npos ? AF_INET6 : AF_INET, ip, port);
934  if (!addr.valid())
935  return;
936 
937  Packet *packet = new Packet(this, &addr);
939  try
940  {
941  packet->id = GetID();
942  }
943  catch (const SocketException &)
944  {
945  delete packet;
946  continue;
947  }
948 
949  packet->questions.push_back(Question(zone, QUERY_SOA));
950 
951  new NotifySocket(ip.find(':') != Anope::string::npos ? AF_INET6 : AF_INET, packet);
952  }
953  }
954 
955  uint32_t GetSerial() const anope_override
956  {
957  return serial;
958  }
959 
960  void Tick(time_t now) anope_override
961  {
962  Log(LOG_DEBUG_2) << "Resolver: Purging DNS cache";
963 
964  for (cache_map::iterator it = this->cache.begin(), it_next; it != this->cache.end(); it = it_next)
965  {
966  const Query &q = it->second;
967  const ResourceRecord &req = q.answers[0];
968  it_next = it;
969  ++it_next;
970 
971  if (req.created + static_cast<time_t>(req.ttl) < now)
972  this->cache.erase(it);
973  }
974  }
975 
976  private:
980  void AddCache(Query &r)
981  {
982  const ResourceRecord &rr = r.answers[0];
983  Log(LOG_DEBUG_3) << "Resolver cache: added cache for " << rr.name << " -> " << rr.rdata << ", ttl: " << rr.ttl;
984  this->cache[r.questions[0]] = r;
985  }
986 
990  bool CheckCache(Request *request)
991  {
992  cache_map::iterator it = this->cache.find(*request);
993  if (it != this->cache.end())
994  {
995  Query &record = it->second;
996  Log(LOG_DEBUG_3) << "Resolver: Using cached result for " << request->name;
997  request->OnLookupComplete(&record);
998  return true;
999  }
1000 
1001  return false;
1002  }
1003 
1004 };
1005 
1006 class ModuleDNS : public Module
1007 {
1009 
1012  int port;
1013 
1014  std::vector<std::pair<Anope::string, short> > notify;
1015 
1016  public:
1017  ModuleDNS(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR), manager(this)
1018  {
1019 
1020  }
1021 
1023  {
1024  for (std::map<int, Socket *>::const_iterator it = SocketEngine::Sockets.begin(), it_end = SocketEngine::Sockets.end(); it != it_end;)
1025  {
1026  Socket *s = it->second;
1027  ++it;
1028 
1029  if (dynamic_cast<NotifySocket *>(s) || dynamic_cast<TCPSocket::Client *>(s))
1030  delete s;
1031  }
1032  }
1033 
1035  {
1036  Configuration::Block *block = conf->GetModule(this);
1037 
1038  nameserver = block->Get<const Anope::string>("nameserver", "127.0.0.1");
1039  timeout = block->Get<time_t>("timeout", "5");
1040  ip = block->Get<const Anope::string>("ip", "0.0.0.0");
1041  port = block->Get<int>("port", "53");
1042  admin = block->Get<const Anope::string>("admin", "admin@example.com");
1043  nameservers = block->Get<const Anope::string>("nameservers", "ns1.example.com");
1044  refresh = block->Get<int>("refresh", "3600");
1045 
1046  for (int i = 0; i < block->CountBlock("notify"); ++i)
1047  {
1048  Configuration::Block *n = block->GetBlock("notify", i);
1049  Anope::string nip = n->Get<Anope::string>("ip");
1050  short nport = n->Get<short>("port");
1051 
1052  notify.push_back(std::make_pair(nip, nport));
1053  }
1054 
1055  if (Anope::IsFile(nameserver))
1056  {
1057  std::ifstream f(nameserver.c_str());
1058  bool success = false;
1059 
1060  if (f.is_open())
1061  {
1062  for (Anope::string server; std::getline(f, server.str());)
1063  {
1064  if (server.find("nameserver") == 0)
1065  {
1066  size_t i = server.find_first_of("123456789");
1067  if (i != Anope::string::npos)
1068  {
1069  if (server.substr(i).is_pos_number_only())
1070  {
1071  nameserver = server.substr(i);
1072  Log(LOG_DEBUG) << "Nameserver set to " << nameserver;
1073  success = true;
1074  break;
1075  }
1076  }
1077  }
1078  }
1079 
1080  f.close();
1081  }
1082 
1083  if (!success)
1084  {
1085  Log() << "Unable to find nameserver, defaulting to 127.0.0.1";
1086  nameserver = "127.0.0.1";
1087  }
1088  }
1089 
1090  try
1091  {
1092  this->manager.SetIPPort(nameserver, ip, port, notify);
1093  }
1094  catch (const SocketException &ex)
1095  {
1096  throw ModuleException(ex.GetReason());
1097  }
1098  }
1099 
1101  {
1102  for (std::map<unsigned short, Request *>::iterator it = this->manager.requests.begin(), it_end = this->manager.requests.end(); it != it_end;)
1103  {
1104  unsigned short id = it->first;
1105  Request *req = it->second;
1106  ++it;
1107 
1108  if (req->creator == m)
1109  {
1110  Query rr(*req);
1111  rr.error = ERROR_UNLOADED;
1112  req->OnError(&rr);
1113 
1114  delete req;
1115  this->manager.requests.erase(id);
1116  }
1117  }
1118  }
1119 };
1120 
1122 
Error error
Definition: dns.h:107
TR1NS::unordered_map< Question, Query, Question::hash > cache_map
Definition: m_dns.cpp:651
MyManager manager
Definition: m_dns.cpp:1008
ResourceRecord UnpackResourceRecord(const unsigned char *input, unsigned short input_size, unsigned short &pos)
Definition: m_dns.cpp:128
int CountBlock(const Anope::string &name)
Definition: config.cpp:35
void pton(int type, const Anope::string &address, int pport=0)
Definition: sockets.cpp:121
void Process(Request *req) anope_override
Definition: m_dns.cpp:735
UDPSocket * udpsock
Definition: m_dns.cpp:655
size_t size() const
Definition: sockets.cpp:43
void Fill(const unsigned char *input, const unsigned short len)
Definition: m_dns.cpp:212
Definition: timers.h:18
~ModuleDNS()
Definition: m_dns.cpp:1022
static const int HEADER_LENGTH
Definition: m_dns.cpp:196
bool ProcessRead() anope_override
Definition: m_dns.cpp:576
std::map< unsigned short, Request * > requests
Definition: m_dns.cpp:662
bool listen
Definition: m_dns.cpp:657
sockaddr sa
Definition: sockets.h:30
void OnModuleUnload(User *u, Module *m) anope_override
Definition: m_dns.cpp:1100
Packet * packet
Definition: m_dns.cpp:470
sockaddr_in sa4
Definition: sockets.h:31
unsigned short flags
Definition: m_dns.cpp:204
CoreExport bool IsFile(const Anope::string &file)
Definition: misc.cpp:266
void UpdateSerial() anope_override
Definition: m_dns.cpp:919
Anope::string addr() const
Definition: sockets.cpp:73
virtual uint32_t GetSerial() const =0
std::deque< Packet * > & GetPackets()
Definition: m_dns.cpp:574
~MyManager()
Definition: m_dns.cpp:669
void AddCache(Query &r)
Definition: m_dns.cpp:980
void GetTokens(T &token)
Definition: anope.h:587
time_t created
Definition: dns.h:97
void Reply(Packet *p) anope_override
Definition: m_dns.cpp:568
Definition: users.h:34
virtual bool HandlePacket(ReplySocket *s, const unsigned char *const data, int len, sockaddrs *from)=0
Anope::string rdata
Definition: dns.h:96
NotifySocket(bool v6, Packet *p)
Definition: m_dns.cpp:618
static std::map< int, Socket * > Sockets
Definition: socketengine.h:24
TCPSocket * tcpsock
Definition: m_dns.cpp:654
TCPSocket(Manager *m, const Anope::string &ip, int port)
Definition: m_dns.cpp:545
std::vector< ResourceRecord > authorities
Definition: dns.h:106
Manager * manager
Definition: m_dns.cpp:556
void RemoveRequest(Request *req) anope_override
Definition: m_dns.cpp:762
unsigned int ttl
Definition: dns.h:95
sockaddrs addr
Definition: m_dns.cpp:200
static void Change(Socket *s, bool set, SocketFlag flag)
void Notify(const Anope::string &zone) anope_override
Definition: m_dns.cpp:924
Question UnpackQuestion(const unsigned char *input, unsigned short input_size, unsigned short &pos)
Definition: m_dns.cpp:110
std::vector< Question > questions
Definition: dns.h:105
CoreExport time_t CurTime
Definition: main.cpp:41
Error
Definition: dns.h:57
Manager * manager
Definition: m_dns.cpp:198
#define FOREACH_MOD(ename, args)
Definition: modules.h:62
sockaddrs addrs
Definition: m_dns.cpp:658
Client(Manager *m, TCPSocket *l, int fd, const sockaddrs &addr)
Definition: m_dns.cpp:475
MyManager(Module *creator)
Definition: m_dns.cpp:664
string substr(size_type pos=0, size_type n=npos) const
Definition: anope.h:277
Packet(Manager *m, sockaddrs *a)
Definition: m_dns.cpp:206
Manager * manager
Definition: m_dns.cpp:469
std::vector< ResourceRecord > additional
Definition: dns.h:106
bool ProcessRead() anope_override
Definition: m_dns.cpp:497
size_type length() const
Definition: anope.h:131
virtual void Reply(Packet *p)=0
std::vector< std::pair< Anope::string, short > > notify
Definition: m_dns.cpp:660
Block * GetBlock(const Anope::string &name, int num=0)
Definition: config.cpp:43
virtual void OnError(const Query *r)
Definition: dns.h:163
bool valid() const
Definition: sockets.cpp:99
unsigned short qclass
Definition: dns.h:78
static const size_type npos
Definition: anope.h:44
void Reply(Packet *p) anope_override
Definition: m_dns.cpp:490
void ntop(int type, const void *src)
Definition: sockets.cpp:156
void Tick(time_t) anope_override
Definition: m_dns.cpp:488
bool HandlePacket(ReplySocket *s, const unsigned char *const packet_buffer, int length, sockaddrs *from) anope_override
Definition: m_dns.cpp:767
Anope::string ip
Definition: m_dns.cpp:1011
Packet * packet
Definition: m_dns.cpp:616
bool ProcessWrite() anope_override
Definition: m_dns.cpp:624
#define anope_override
Definition: services.h:56
bool empty() const
Definition: anope.h:126
UDPSocket(Manager *m, const Anope::string &ip, int port)
Definition: m_dns.cpp:560
int port
Definition: m_dns.cpp:1012
bool ProcessWrite() anope_override
Definition: m_dns.cpp:587
Anope::string nameserver
Definition: m_dns.cpp:1010
void PackName(unsigned char *output, unsigned short output_size, unsigned short &pos, const Anope::string &name)
Definition: m_dns.cpp:29
std::deque< Packet * > packets
Definition: m_dns.cpp:557
std::basic_string< char, ci_char_traits, std::allocator< char > > string
Definition: hashcomp.h:133
#define MODULE_INIT(x)
Definition: modules.h:45
static Timer * timeout
Definition: os_defcon.cpp:106
virtual ~ReplySocket()
Definition: m_dns.cpp:455
bool CheckCache(Request *request)
Definition: m_dns.cpp:990
std::vector< std::pair< Anope::string, short > > notify
Definition: m_dns.cpp:1014
Definition: defs.h:28
uint32_t GetSerial() const anope_override
Definition: m_dns.cpp:955
unsigned short id
Definition: m_dns.cpp:202
~UDPSocket()
Definition: m_dns.cpp:562
unsigned short Pack(unsigned char *output, unsigned short output_size)
Definition: m_dns.cpp:252
QueryType
Definition: dns.h:20
QueryType type
Definition: dns.h:77
void Bind(const Anope::string &ip, int port=0)
Definition: sockets.cpp:493
bool GetToken(Anope::string &token)
Definition: hashcomp.cpp:99
Module * creator
Definition: dns.h:145
void SetIPPort(const Anope::string &nameserver, const Anope::string &ip, unsigned short port, std::vector< std::pair< Anope::string, short > > n)
Definition: m_dns.cpp:690
bool ProcessWrite() anope_override
Definition: m_dns.cpp:517
Anope::string name
Definition: access.cpp:22
cache_map cache
Definition: m_dns.cpp:652
virtual const Anope::string & GetReason() const
Definition: anope.h:672
virtual void OnLookupComplete(const Query *r)=0
Manager * manager
Definition: m_dns.cpp:463
Anope::string UnpackName(const unsigned char *input, unsigned short input_size, unsigned short &pos)
Definition: m_dns.cpp:49
Anope::string name
Definition: dns.h:76
uint32_t serial
Definition: m_dns.cpp:649
const char * c_str() const
Definition: anope.h:117
Definition: logger.h:53
unsigned short GetID()
Definition: m_dns.cpp:722
T Get(const Anope::string &tag)
Definition: config.h:44
Definition: m_dns.cpp:27
ModuleDNS(const Anope::string &modname, const Anope::string &creator)
Definition: m_dns.cpp:1017
void Tick(time_t now) anope_override
Definition: m_dns.cpp:960
LogType type
Definition: logger.h:74
std::vector< ResourceRecord > answers
Definition: dns.h:106
ClientSocket * OnAccept(int fd, const sockaddrs &addr) anope_override
Definition: m_dns.cpp:547
size_type find(const string &_str, size_type pos=0) const
Definition: anope.h:192
Definition: anope.h:20
unsigned short cur_id
Definition: m_dns.cpp:720
Definition: modules.h:163
void OnReload(Configuration::Conf *conf) anope_override
Definition: m_dns.cpp:1034
sockaddr_in6 sa6
Definition: sockets.h:32