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