dns.cpp

Go to the documentation of this file.
00001 /*
00002  *
00003  * (C) 2003-2012 Anope Team
00004  * Contact us at team@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church.
00010  *
00011  */
00012 
00013 #include "services.h"
00014 #include "anope.h"
00015 #include "dns.h"
00016 #include "sockets.h"
00017 #include "socketengine.h"
00018 
00019 #ifndef _WIN32
00020 #include <sys/types.h>
00021 #include <sys/socket.h>
00022 #include <netdb.h>
00023 #endif
00024 
00025 using namespace DNS;
00026 
00027 Manager *DNS::Engine = NULL;
00028 
00029 Question::Question()
00030 {
00031         this->type = QUERY_NONE;
00032         this->qclass = 0;
00033 }
00034 
00035 Question::Question(const Anope::string &n, QueryType t, unsigned short q) : name(n), type(t), qclass(q)
00036 {
00037 }
00038 
00039 ResourceRecord::ResourceRecord(const Anope::string &n, QueryType t, unsigned short q) : Question(n, t, q)
00040 {
00041         this->ttl = 0;
00042         this->created = Anope::CurTime;
00043 }
00044 
00045 ResourceRecord::ResourceRecord(const Question &q) : Question(q)
00046 {
00047         this->ttl = 0;
00048         this->created = Anope::CurTime;
00049 }
00050 
00051 Query::Query()
00052 {
00053         this->error = ERROR_NONE;
00054 }
00055 
00056 Query::Query(const Question &q)
00057 {
00058         this->questions.push_back(q);
00059         this->error = ERROR_NONE;
00060 }
00061 
00062 Request::Request(const Anope::string &addr, QueryType qt, bool cache, Module *c) : Timer(Config->DNSTimeout), Question(addr, qt), use_cache(cache), id(0), creator(c)
00063 {
00064         if (!DNS::Engine || !DNS::Engine->udpsock)
00065                 throw SocketException("No DNS::Engine");
00066         if (DNS::Engine->udpsock->GetPackets().size() == 65535)
00067                 throw SocketException("DNS queue full");
00068 
00069         do
00070         {
00071                 static unsigned short cur_id = rand();
00072                 this->id = cur_id++;
00073         }
00074         while (DNS::Engine->requests.count(this->id));
00075 
00076         DNS::Engine->requests[this->id] = this;
00077 }
00078 
00079 Request::~Request()
00080 {
00081         DNS::Engine->requests.erase(this->id);
00082 }
00083 
00084 void Request::Process()
00085 {
00086         Log(LOG_DEBUG_2) << "Resolver: Processing request to lookup " << this->name << ", of type " << this->type;
00087 
00088         if (!DNS::Engine || !DNS::Engine->udpsock)
00089                 throw SocketException("DNS::Engine has not been initialized");
00090 
00091         if (this->use_cache && DNS::Engine->CheckCache(this))
00092         {
00093                 Log(LOG_DEBUG_2) << "Resolver: Using cached result";
00094                 delete this;
00095                 return;
00096         }
00097         
00098         Packet *p = new Packet(&DNS::Engine->addrs);
00099         p->flags = QUERYFLAGS_RD;
00100 
00101         p->id = this->id;
00102         p->questions.push_back(*this);
00103         DNS::Engine->udpsock->Reply(p);
00104 }
00105 
00106 void Request::OnError(const Query *r)
00107 {
00108 }
00109 
00110 void Request::Tick(time_t)
00111 {
00112         Log(LOG_DEBUG_2) << "Resolver: timeout for query " << this->name;
00113         Query rr(*this);
00114         rr.error = ERROR_TIMEOUT;
00115         this->OnError(&rr);
00116 } 
00117 
00118 void Packet::PackName(unsigned char *output, unsigned short output_size, unsigned short &pos, const Anope::string &name)
00119 {
00120         if (name.length() + 2 > output_size)
00121                 throw SocketException("Unable to pack name");
00122 
00123         Log(LOG_DEBUG_2) << "Resolver: PackName packing " << name;
00124 
00125         sepstream sep(name, '.');
00126         Anope::string token;
00127 
00128         while (sep.GetToken(token))
00129         {
00130                 output[pos++] = token.length();
00131                 memcpy(&output[pos], token.c_str(), token.length());
00132                 pos += token.length();
00133         }
00134 
00135         output[pos++] = 0;
00136 }
00137 
00138 Anope::string Packet::UnpackName(const unsigned char *input, unsigned short input_size, unsigned short &pos)
00139 {
00140         Anope::string name;
00141         unsigned short pos_ptr = pos, lowest_ptr = input_size;
00142         bool compressed = false;
00143 
00144         if (pos_ptr >= input_size)
00145                 throw SocketException("Unable to unpack name - no input");
00146 
00147         while (input[pos_ptr] > 0)
00148         {
00149                 unsigned short offset = input[pos_ptr];
00150 
00151                 if (offset & POINTER)
00152                 {
00153                         if ((offset & POINTER) != POINTER)
00154                                 throw SocketException("Unable to unpack name - bogus compression header");
00155                         if (pos_ptr + 1 >= input_size)
00156                                 throw SocketException("Unable to unpack name - bogus compression header");
00157 
00158                         /* Place pos at the second byte of the first (farthest) compression pointer */
00159                         if (compressed == false)
00160                         {
00161                                 ++pos;
00162                                 compressed = true;
00163                         }
00164 
00165                         pos_ptr = (offset & LABEL) << 8 | input[pos_ptr + 1];
00166 
00167                         /* Pointers can only go back */
00168                         if (pos_ptr >= lowest_ptr)
00169                                 throw SocketException("Unable to unpack name - bogus compression pointer");
00170                         lowest_ptr = pos_ptr;
00171                 }
00172                 else
00173                 {
00174                         if (pos_ptr + offset + 1 >= input_size)
00175                                 throw SocketException("Unable to unpack name - offset too large");
00176                         if (!name.empty())
00177                                 name += ".";
00178                         for (unsigned i = 1; i <= offset; ++i)
00179                                 name += input[pos_ptr + i];
00180 
00181                         pos_ptr += offset + 1;
00182                         if (compressed == false)
00183                                 /* Move up pos */
00184                                 pos = pos_ptr;
00185                 }
00186         }
00187 
00188         /* +1 pos either to one byte after the compression pointer or one byte after the ending \0 */
00189         ++pos;
00190 
00191         Log(LOG_DEBUG_2) << "Resolver: UnpackName successfully unpacked " << name;
00192 
00193         return name;
00194 }
00195 
00196 Question Packet::UnpackQuestion(const unsigned char *input, unsigned short input_size, unsigned short &pos)
00197 {
00198         Question question;
00199 
00200         question.name = this->UnpackName(input, input_size, pos);
00201 
00202         if (pos + 4 > input_size)
00203                 throw SocketException("Unable to unpack question");
00204 
00205         question.type = static_cast<QueryType>(input[pos] << 8 | input[pos + 1]);
00206         pos += 2;
00207 
00208         question.qclass = input[pos] << 8 | input[pos + 1];
00209         pos += 2;
00210 
00211         return question;
00212 }
00213 
00214 ResourceRecord Packet::UnpackResourceRecord(const unsigned char *input, unsigned short input_size, unsigned short &pos)
00215 {
00216         ResourceRecord record = static_cast<ResourceRecord>(this->UnpackQuestion(input, input_size, pos));
00217 
00218         if (pos + 6 > input_size)
00219                 throw SocketException("Unable to unpack resource record");
00220 
00221         record.ttl = (input[pos] << 24) | (input[pos + 1] << 16) | (input[pos + 2] << 8) | input[pos + 3];
00222         pos += 4;
00223 
00224         //record.rdlength = input[pos] << 8 | input[pos + 1];
00225         pos += 2;
00226 
00227         switch (record.type)
00228         {
00229                 case QUERY_A:
00230                 {
00231                         if (pos + 4 > input_size)
00232                                 throw SocketException("Unable to unpack resource record");
00233 
00234                         in_addr a;
00235                         a.s_addr = input[pos] | (input[pos + 1] << 8) | (input[pos + 2] << 16)  | (input[pos + 3] << 24);
00236                         pos += 4;
00237 
00238                         sockaddrs addrs;
00239                         addrs.ntop(AF_INET, &a);
00240 
00241                         record.rdata = addrs.addr();
00242                         break;
00243                 }
00244                 case QUERY_AAAA:
00245                 {
00246                         if (pos + 16 > input_size)
00247                                 throw SocketException("Unable to unpack resource record");
00248 
00249                         in6_addr a;
00250                         for (int j = 0; j < 16; ++j)
00251                                 a.s6_addr[j] = input[pos + j];
00252                         pos += 16;
00253 
00254                         sockaddrs addrs;
00255                         addrs.ntop(AF_INET6, &a);
00256 
00257                         record.rdata = addrs.addr();
00258                         break;
00259                 }
00260                 case QUERY_CNAME:
00261                 case QUERY_PTR:
00262                 {
00263                         record.rdata = this->UnpackName(input, input_size, pos);
00264                         break;
00265                 }
00266                 default:
00267                         break;
00268         }
00269 
00270         Log(LOG_DEBUG_2) << "Resolver: " << record.name << " -> " << record.rdata;
00271 
00272         return record;
00273 }
00274 
00275 Packet::Packet(sockaddrs *a) : Query(), id(0), flags(0)
00276 {
00277         if (a)
00278                 addr = *a;
00279 }
00280 
00281 void Packet::Fill(const unsigned char *input, const unsigned short len)
00282 {
00283         if (len < Packet::HEADER_LENGTH)
00284                 throw SocketException("Unable to fill packet");
00285 
00286         unsigned short packet_pos = 0;
00287 
00288         this->id = (input[packet_pos] << 8) | input[packet_pos + 1];
00289         packet_pos += 2;
00290 
00291         this->flags = (input[packet_pos] << 8) | input[packet_pos + 1];
00292         packet_pos += 2;
00293 
00294         unsigned short qdcount = (input[packet_pos] << 8) | input[packet_pos + 1];
00295         packet_pos += 2;
00296 
00297         unsigned short ancount = (input[packet_pos] << 8) | input[packet_pos + 1];
00298         packet_pos += 2;
00299 
00300         unsigned short nscount = (input[packet_pos] << 8) | input[packet_pos + 1];
00301         packet_pos += 2;
00302 
00303         unsigned short arcount = (input[packet_pos] << 8) | input[packet_pos + 1];
00304         packet_pos += 2;
00305 
00306         Log(LOG_DEBUG_2) << "Resolver: qdcount: " << qdcount << " ancount: " << ancount << " nscount: " << nscount << " arcount: " << arcount;
00307 
00308         for (unsigned i = 0; i < qdcount; ++i)
00309                 this->questions.push_back(this->UnpackQuestion(input, len, packet_pos));
00310         
00311         for (unsigned i = 0; i < ancount; ++i)
00312                 this->answers.push_back(this->UnpackResourceRecord(input, len, packet_pos));
00313 
00314         for (unsigned i = 0; i < nscount; ++i)
00315                 this->authorities.push_back(this->UnpackResourceRecord(input, len, packet_pos));
00316 
00317         for (unsigned i = 0; i < arcount; ++i)
00318                 this->additional.push_back(this->UnpackResourceRecord(input, len, packet_pos));
00319 }
00320 
00321 unsigned short Packet::Pack(unsigned char *output, unsigned short output_size)
00322 {
00323         if (output_size < Packet::HEADER_LENGTH)
00324                 throw SocketException("Unable to pack packet");
00325         
00326         unsigned short pos = 0;
00327 
00328         output[pos++] = this->id >> 8;
00329         output[pos++] = this->id & 0xFF;
00330         output[pos++] = this->flags >> 8;
00331         output[pos++] = this->flags & 0xFF;
00332         output[pos++] = this->questions.size() >> 8;
00333         output[pos++] = this->questions.size() & 0xFF;
00334         output[pos++] = this->answers.size() >> 8;
00335         output[pos++] = this->answers.size() & 0xFF;
00336         output[pos++] = this->authorities.size() >> 8;
00337         output[pos++] = this->authorities.size() & 0xFF;
00338         output[pos++] = this->additional.size() >> 8;
00339         output[pos++] = this->additional.size() & 0xFF;
00340 
00341         for (unsigned i = 0; i < this->questions.size(); ++i)
00342         {
00343                 Question &q = this->questions[i];
00344 
00345                 if (q.type == QUERY_PTR)
00346                 {
00347                         sockaddrs ip(q.name);
00348 
00349                         if (q.name.find(':') != Anope::string::npos)
00350                         {
00351                                 static const char *const hex = "0123456789abcdef";
00352                                 char reverse_ip[128];
00353                                 unsigned reverse_ip_count = 0;
00354                                 for (int j = 15; j >= 0; --j)
00355                                 {
00356                                         reverse_ip[reverse_ip_count++] = hex[ip.sa6.sin6_addr.s6_addr[j] & 0xF];
00357                                         reverse_ip[reverse_ip_count++] = '.';
00358                                         reverse_ip[reverse_ip_count++] = hex[ip.sa6.sin6_addr.s6_addr[j] >> 4];
00359                                         reverse_ip[reverse_ip_count++] = '.';
00360                                 }
00361                                 reverse_ip[reverse_ip_count++] = 0;
00362 
00363                                 q.name = reverse_ip;
00364                                 q.name += "ip6.arpa";
00365                         }
00366                         else
00367                         {
00368                                 unsigned long forward = ip.sa4.sin_addr.s_addr;
00369                                 in_addr reverse;
00370                                 reverse.s_addr = forward << 24 | (forward & 0xFF00) << 8 | (forward & 0xFF0000) >> 8 | forward >> 24;
00371 
00372                                 ip.ntop(AF_INET, &reverse);
00373 
00374                                 q.name = ip.addr() + ".in-addr.arpa";
00375                         }
00376                 }
00377 
00378                 this->PackName(output, output_size, pos, q.name);
00379 
00380                 if (pos + 4 >= output_size)
00381                         throw SocketException("Unable to pack packet");
00382 
00383                 short s = htons(q.type);
00384                 memcpy(&output[pos], &s, 2);
00385                 pos += 2;
00386 
00387                 s = htons(q.qclass);
00388                 memcpy(&output[pos], &s, 2);
00389                 pos += 2;
00390         }
00391 
00392         std::vector<ResourceRecord> types[] = { this->answers, this->authorities, this->additional };
00393         for (int i = 0; i < 3; ++i)
00394                 for (unsigned j = 0; j < types[i].size(); ++j)
00395                 {
00396                         ResourceRecord &rr = types[i][j];
00397 
00398                         this->PackName(output, output_size, pos, rr.name);
00399 
00400                         if (pos + 8 >= output_size)
00401                                 throw SocketException("Unable to pack packet");
00402 
00403                         short s = htons(rr.type);
00404                         memcpy(&output[pos], &s, 2);
00405                         pos += 2;
00406 
00407                         s = htons(rr.qclass);
00408                         memcpy(&output[pos], &s, 2);
00409                         pos += 2;
00410 
00411                         long l = htonl(rr.ttl);
00412                         memcpy(&output[pos], &l, 4);
00413                         pos += 4;
00414 
00415                         switch (rr.type)
00416                         {
00417                                 case QUERY_A:
00418                                 {
00419                                         if (pos + 6 > output_size)
00420                                                 throw SocketException("Unable to pack packet");
00421 
00422                                         sockaddrs a(rr.rdata);
00423 
00424                                         s = htons(4);
00425                                         memcpy(&output[pos], &s, 2);
00426                                         pos += 2;
00427 
00428                                         memcpy(&output[pos], &a.sa4.sin_addr, 4);
00429                                         pos += 4;
00430                                         break;
00431                                 }
00432                                 case QUERY_AAAA:
00433                                 {
00434                                         if (pos + 18 > output_size)
00435                                                 throw SocketException("Unable to pack packet");
00436 
00437                                         sockaddrs a(rr.rdata);
00438 
00439                                         s = htons(16);
00440                                         memcpy(&output[pos], &s, 2);
00441                                         pos += 2;
00442 
00443                                         memcpy(&output[pos], &a.sa6.sin6_addr, 16);
00444                                         pos += 16;
00445                                         break;
00446                                 }
00447                                 case QUERY_NS:
00448                                 case QUERY_CNAME:
00449                                 case QUERY_PTR:
00450                                 {
00451                                         if (pos + 2 >= output_size)
00452                                                 throw SocketException("Unable to pack packet");
00453 
00454                                         unsigned short packet_pos_save = pos;
00455                                         pos += 2;
00456 
00457                                         this->PackName(output, output_size, pos, rr.rdata);
00458 
00459                                         s = htons(pos - packet_pos_save - 2);
00460                                         memcpy(&output[packet_pos_save], &s, 2);
00461                                         break;
00462                                 }
00463                                 case QUERY_SOA:
00464                                 {
00465                                         if (pos + 2 >= output_size)
00466                                                 throw SocketException("Unable to pack packet");
00467 
00468                                         unsigned short packet_pos_save = pos;
00469                                         pos += 2;
00470 
00471                                         std::vector<Anope::string> nameservers;
00472                                         spacesepstream(Config->DNSSOANS).GetTokens(nameservers);
00473                                         this->PackName(output, output_size, pos, !nameservers.empty() ? nameservers[0] : "");
00474                                         this->PackName(output, output_size, pos, Config->DNSSOAAdmin.replace_all_cs('@', '.'));
00475 
00476                                         if (pos + 20 >= output_size)
00477                                                 throw SocketException("Unable to pack SOA");
00478 
00479                                         l = htonl(DNS::Engine->GetSerial());
00480                                         memcpy(&output[pos], &l, 4);
00481                                         pos += 4;
00482                                         
00483                                         l = htonl(Config->DNSSOARefresh); // Refresh
00484                                         memcpy(&output[pos], &l, 4);
00485                                         pos += 4;
00486 
00487                                         l = htonl(Config->DNSSOARefresh); // Retry
00488                                         memcpy(&output[pos], &l, 4);
00489                                         pos += 4;
00490 
00491                                         l = htonl(604800); // Expire
00492                                         memcpy(&output[pos], &l, 4);
00493                                         pos += 4;
00494 
00495                                         l = htonl(0); // Minimum
00496                                         memcpy(&output[pos], &l, 4);
00497                                         pos += 4;
00498 
00499                                         s = htons(pos - packet_pos_save - 2);
00500                                         memcpy(&output[packet_pos_save], &s, 2);
00501 
00502                                         break;
00503                                 }
00504                                 default:
00505                                         break;
00506                         }
00507                 }
00508         
00509         return pos;
00510 }
00511 
00512 Manager::TCPSocket::Client::Client(TCPSocket *l, int fd, const sockaddrs &addr) : Socket(fd, l->IsIPv6()), ClientSocket(l, addr), Timer(5), tcpsock(l), packet(NULL), length(0)
00513 {
00514         Log(LOG_DEBUG_2) << "Resolver: New client from " << addr.addr();
00515 }
00516 
00517 Manager::TCPSocket::Client::~Client()
00518 {
00519         Log(LOG_DEBUG_2) << "Resolver: Exiting client from " << clientaddr.addr();
00520         delete packet;
00521 }
00522 
00523 void Manager::TCPSocket::Client::Reply(Packet *p)
00524 {
00525         delete packet;
00526         packet = p;
00527         SocketEngine::Change(this, true, SF_WRITABLE);
00528 }
00529 
00530 bool Manager::TCPSocket::Client::ProcessRead()
00531 {
00532         Log(LOG_DEBUG_2) << "Resolver: Reading from DNS TCP socket";
00533 
00534         int i = recv(this->GetFD(), reinterpret_cast<char *>(packet_buffer) + length, sizeof(packet_buffer) - length, 0);
00535         if (i <= 0)
00536                 return false;
00537 
00538         length += i;
00539 
00540         unsigned short want_len = packet_buffer[0] << 8 | packet_buffer[1];
00541         if (length >= want_len + 2)
00542         {
00543                 int len = length - 2;
00544                 length -= want_len + 2;
00545                 return DNS::Engine->HandlePacket(this, packet_buffer + 2, len, NULL);
00546         }
00547         return true;
00548 }
00549 
00550 bool Manager::TCPSocket::Client::ProcessWrite()
00551 {
00552         Log(LOG_DEBUG_2) << "Resolver: Writing to DNS TCP socket";
00553 
00554         if (packet != NULL)
00555         {
00556                 try
00557                 {
00558                         unsigned char buffer[65535];
00559                         unsigned short len = packet->Pack(buffer + 2, sizeof(buffer) - 2);
00560 
00561                         short s = htons(len);
00562                         memcpy(buffer, &s, 2);
00563                         len += 2;
00564 
00565                         send(this->GetFD(), reinterpret_cast<char *>(buffer), len, 0);
00566                 }
00567                 catch (const SocketException &) { }
00568 
00569                 delete packet;
00570                 packet = NULL;
00571         }
00572 
00573         SocketEngine::Change(this, false, SF_WRITABLE);
00574         return true; /* Do not return false here, bind is unhappy we close the connection so soon after sending */
00575 }
00576 
00577 Manager::TCPSocket::TCPSocket(const Anope::string &ip, int port) : Socket(-1, ip.find(':') != Anope::string::npos), ListenSocket(ip, port, ip.find(':') != Anope::string::npos)
00578 {
00579 }
00580 
00581 ClientSocket *Manager::TCPSocket::OnAccept(int fd, const sockaddrs &addr)
00582 {
00583         return new Client(this, fd, addr);
00584 }
00585 
00586 Manager::UDPSocket::UDPSocket(const Anope::string &ip, int port) : Socket(-1, ip.find(':') != Anope::string::npos, SOCK_DGRAM)
00587 {
00588 }
00589 
00590 Manager::UDPSocket::~UDPSocket()
00591 {
00592         for (unsigned i = 0; i < packets.size(); ++i)
00593                 delete packets[i];
00594 }
00595 
00596 void Manager::UDPSocket::Reply(Packet *p)
00597 {
00598         packets.push_back(p);
00599         SocketEngine::Change(this, true, SF_WRITABLE);
00600 }
00601 
00602 bool Manager::UDPSocket::ProcessRead()
00603 {
00604         Log(LOG_DEBUG_2) << "Resolver: Reading from DNS UDP socket";
00605 
00606         unsigned char packet_buffer[524];
00607         sockaddrs from_server;
00608         socklen_t x = sizeof(from_server);
00609         int length = recvfrom(this->GetFD(), reinterpret_cast<char *>(&packet_buffer), sizeof(packet_buffer), 0, &from_server.sa, &x);
00610         return DNS::Engine->HandlePacket(this, packet_buffer, length, &from_server);
00611 }
00612 
00613 bool Manager::UDPSocket::ProcessWrite()
00614 {
00615         Log(LOG_DEBUG_2) << "Resolver: Writing to DNS UDP socket";
00616 
00617         Packet *r = !packets.empty() ? packets.front() : NULL;
00618         if (r != NULL)
00619         {
00620                 try
00621                 {
00622                         unsigned char buffer[524];
00623                         unsigned short len = r->Pack(buffer, sizeof(buffer));
00624 
00625                         sendto(this->GetFD(), reinterpret_cast<char *>(buffer), len, 0, &r->addr.sa, r->addr.size());
00626                 }
00627                 catch (const SocketException &) { }
00628 
00629                 delete r;
00630                 packets.pop_front();
00631         }
00632 
00633         if (packets.empty())
00634                 SocketEngine::Change(this, false, SF_WRITABLE);
00635         
00636         return true;
00637 }
00638 
00639 Manager::Manager(const Anope::string &nameserver, const Anope::string &ip, int port) : Timer(300, Anope::CurTime, true), listen(false), serial(0), tcpsock(NULL), udpsock(NULL)
00640 {
00641         this->addrs.pton(nameserver.find(':') != Anope::string::npos ? AF_INET6 : AF_INET, nameserver, port);
00642 
00643         try
00644         {
00645                 udpsock = new UDPSocket(ip, port);
00646         }
00647         catch (const SocketException &ex)
00648         {
00649                 Log() << "Unable to create socket for Manager: " << ex.GetReason();
00650         }
00651 
00652         try
00653         {
00654                 udpsock->Bind(ip, port);
00655                 tcpsock = new TCPSocket(ip, port);
00656                 listen = true;
00657         }
00658         catch (const SocketException &ex)
00659         {
00660                 /* This error can be from normal operation as most people don't use services to handle DNS queries, so put it in debug log */
00661                 Log(LOG_DEBUG) << "Unable to bind Manager to port " << port << ": " << ex.GetReason();
00662         }
00663 
00664         this->UpdateSerial();
00665 }
00666 
00667 Manager::~Manager()
00668 {
00669         delete udpsock;
00670         delete tcpsock;
00671 
00672         for (std::map<unsigned short, Request *>::iterator it = this->requests.begin(), it_end = this->requests.end(); it != it_end; ++it)
00673         {       
00674                 Request *request = it->second;
00675 
00676                 Query rr(*request);
00677                 rr.error = ERROR_UNKNOWN;
00678                 request->OnError(&rr);
00679 
00680                 delete request;
00681         }
00682         this->requests.clear();
00683 
00684         this->cache.clear();
00685 
00686         DNS::Engine = NULL;
00687 }
00688 
00689 bool Manager::HandlePacket(ReplySocket *s, const unsigned char *const packet_buffer, int length, sockaddrs *from)
00690 {
00691         if (length < Packet::HEADER_LENGTH)
00692                 return true;
00693 
00694         Packet recv_packet(from);
00695 
00696         try
00697         {
00698                 recv_packet.Fill(packet_buffer, length);
00699         }
00700         catch (const SocketException &ex)
00701         {
00702                 Log(LOG_DEBUG_2) << ex.GetReason();
00703                 return true;
00704         }
00705 
00706         if (!(recv_packet.flags & QUERYFLAGS_QR))
00707         {
00708                 if (!listen)
00709                         return true;
00710                 else if (recv_packet.questions.empty())
00711                 {
00712                         Log(LOG_DEBUG_2) << "Resolver: Received a question with no questions?";
00713                         return true;
00714                 }
00715 
00716                 Packet *packet = new Packet(recv_packet);
00717                 packet->flags |= QUERYFLAGS_QR; /* This is a reponse */
00718                 packet->flags |= QUERYFLAGS_AA; /* And we are authoritative */
00719 
00720                 packet->answers.clear();
00721                 packet->authorities.clear();
00722                 packet->additional.clear();
00723 
00724                 for (unsigned i = 0; i < recv_packet.questions.size(); ++i)
00725                 {
00726                         const Question& q = recv_packet.questions[i];
00727 
00728                         if (q.type == QUERY_AXFR || q.type == QUERY_SOA)
00729                         {
00730                                 ResourceRecord rr(q.name, QUERY_SOA);
00731                                 packet->answers.push_back(rr);
00732 
00733                                 if (q.type == QUERY_AXFR)
00734                                 {
00735                                         Anope::string token;
00736                                         spacesepstream sep(Config->DNSSOANS);
00737                                         while (sep.GetToken(token))
00738                                         {
00739                                                 ResourceRecord rr2(q.name, QUERY_NS);
00740                                                 rr2.rdata = token;
00741                                                 packet->answers.push_back(rr2);
00742                                         }
00743                                 }
00744                                 break;
00745                         }
00746                 }
00747 
00748                 FOREACH_MOD(I_OnDnsRequest, OnDnsRequest(recv_packet, packet));
00749 
00750                 for (unsigned i = 0; i < recv_packet.questions.size(); ++i)
00751                 {
00752                         const Question& q = recv_packet.questions[i];
00753 
00754                         if (q.type == QUERY_AXFR)
00755                         {
00756                                 ResourceRecord rr(q.name, QUERY_SOA);
00757                                 packet->answers.push_back(rr);
00758                                 break;
00759                         }
00760                 }
00761 
00762                 s->Reply(packet);
00763                 return true;
00764         }
00765 
00766         if (from == NULL)
00767         {
00768                 Log(LOG_DEBUG_2) << "Resolver: Received an answer over TCP. This is not supported.";
00769                 return true;
00770         }
00771         else if (this->addrs != *from)
00772         {
00773                 Log(LOG_DEBUG_2) << "Resolver: Received an answer from the wrong nameserver, Bad NAT or DNS forging attempt? '" << this->addrs.addr() << "' != '" << from->addr() << "'";
00774                 return true;
00775         }
00776 
00777         std::map<unsigned short, Request *>::iterator it = DNS::Engine->requests.find(recv_packet.id);
00778         if (it == DNS::Engine->requests.end())
00779         {
00780                 Log(LOG_DEBUG_2) << "Resolver: Received an answer for something we didn't request";
00781                 return true;
00782         }
00783         Request *request = it->second;
00784 
00785         if (recv_packet.flags & QUERYFLAGS_OPCODE)
00786         {
00787                 Log(LOG_DEBUG_2) << "Resolver: Received a nonstandard query";
00788                 recv_packet.error = ERROR_NONSTANDARD_QUERY;
00789                 request->OnError(&recv_packet);
00790         }
00791         else if (recv_packet.flags & QUERYFLAGS_RCODE)
00792         {
00793                 Error error = ERROR_UNKNOWN;
00794 
00795                 switch (recv_packet.flags & QUERYFLAGS_RCODE)
00796                 {
00797                         case 1:
00798                                 Log(LOG_DEBUG_2) << "Resolver: format error";
00799                                 error = ERROR_FORMAT_ERROR;
00800                                 break;
00801                         case 2:
00802                                 Log(LOG_DEBUG_2) << "Resolver: server error";
00803                                 error = ERROR_SERVER_FAILURE;
00804                                 break;
00805                         case 3:
00806                                 Log(LOG_DEBUG_2) << "Resolver: domain not found";
00807                                 error = ERROR_DOMAIN_NOT_FOUND;
00808                                 break;
00809                         case 4:
00810                                 Log(LOG_DEBUG_2) << "Resolver: not implemented";
00811                                 error = ERROR_NOT_IMPLEMENTED;
00812                                 break;
00813                         case 5:
00814                                 Log(LOG_DEBUG_2) << "Resolver: refused";
00815                                 error = ERROR_REFUSED;
00816                                 break;
00817                         default:
00818                                 break;
00819                 }
00820 
00821                 recv_packet.error = error;
00822                 request->OnError(&recv_packet);
00823         }
00824         else if (recv_packet.answers.empty())
00825         {
00826                 Log(LOG_DEBUG_2) << "Resolver: No resource records returned";
00827                 recv_packet.error = ERROR_NO_RECORDS;
00828                 request->OnError(&recv_packet);
00829         }
00830         else
00831         {
00832                 Log(LOG_DEBUG_2) << "Resolver: Lookup complete for " << request->name;
00833                 request->OnLookupComplete(&recv_packet);
00834                 DNS::Engine->AddCache(recv_packet);
00835         }
00836         
00837         delete request;
00838         return true;
00839 }
00840 
00841 void Manager::AddCache(Query &r)
00842 {
00843         for (unsigned i = 0; i < r.answers.size(); ++i)
00844         {
00845                 ResourceRecord &rr = r.answers[i];
00846                 Log(LOG_DEBUG_3) << "Resolver cache: added cache for " << rr.name << " -> " << rr.rdata << ", ttl: " << rr.ttl;
00847                 this->cache.insert(std::make_pair(rr.name, rr));
00848         }
00849 }
00850 
00851 bool Manager::CheckCache(Request *request)
00852 {
00853         cache_map::iterator it = this->cache.find(request->name);
00854         if (it != this->cache.end())
00855         {
00856                 Query record(*request);
00857                 
00858                 for (cache_map::iterator it_end = this->cache.upper_bound(request->name); it != it_end; ++it)
00859                 {
00860                         ResourceRecord &rec = it->second;
00861                         if (rec.created + static_cast<time_t>(rec.ttl) >= Anope::CurTime)
00862                                 record.answers.push_back(rec);
00863                 }
00864 
00865                 if (!record.answers.empty())
00866                 {
00867                         Log(LOG_DEBUG_3) << "Resolver: Using cached result for " << request->name;
00868                         request->OnLookupComplete(&record);
00869                         return true;
00870                 }
00871         }
00872 
00873         return false;
00874 }
00875 
00876 void Manager::Tick(time_t now)
00877 {
00878         Log(LOG_DEBUG_2) << "Resolver: Purging DNS cache";
00879 
00880         for (cache_map::iterator it = this->cache.begin(), it_next; it != this->cache.end(); it = it_next)
00881         {
00882                 ResourceRecord &req = it->second;
00883                 it_next = it;
00884                 ++it_next;
00885 
00886                 if (req.created + static_cast<time_t>(req.ttl) < now)
00887                         this->cache.erase(it);
00888         }
00889 }
00890 
00891 void Manager::Cleanup(Module *mod)
00892 {
00893         for (std::map<unsigned short, Request *>::iterator it = this->requests.begin(), it_end = this->requests.end(); it != it_end;)
00894         {
00895                 unsigned short id = it->first;
00896                 Request *req = it->second;
00897                 ++it;
00898 
00899                 if (req->creator && req->creator == mod)
00900                 {
00901                         Query rr(*req);
00902                         rr.error = ERROR_UNLOADED;
00903                         req->OnError(&rr);
00904 
00905                         delete req;
00906                         this->requests.erase(id);
00907                 }
00908         }
00909 }
00910 
00911 void Manager::UpdateSerial()
00912 {
00913         serial = Anope::CurTime;
00914 }
00915 
00916 uint32_t Manager::GetSerial() const
00917 {
00918         return serial;
00919 }
00920 
00921 Query Manager::BlockingQuery(const Anope::string &mask, QueryType qt)
00922 {
00923         Question question(mask, qt);
00924         Query result(question);
00925 
00926         int type = AF_UNSPEC;
00927         if (qt == QUERY_A)
00928                 type = AF_INET;
00929         else if (qt == QUERY_AAAA)
00930                 type = AF_INET6;
00931 
00932         addrinfo hints;
00933         memset(&hints, 0, sizeof(hints));
00934         hints.ai_family = type;
00935 
00936         Log(LOG_DEBUG_2) << "Resolver: BlockingQuery: Looking up " << mask;
00937 
00938         addrinfo *addrresult;
00939         if (getaddrinfo(mask.c_str(), NULL, &hints, &addrresult) == 0)
00940         {
00941                 for (addrinfo *cur = addrresult; cur; cur = cur->ai_next)
00942                 {
00943                         sockaddrs addr;
00944                         memcpy(&addr, addrresult->ai_addr, addrresult->ai_addrlen);
00945                         try
00946                         {
00947                                 ResourceRecord rr(mask, qt);
00948                                 rr.rdata = addr.addr();
00949                                 result.answers.push_back(rr);
00950 
00951                                 Log(LOG_DEBUG_2) << "Resolver: BlockingQuery: " << mask << " -> " << rr.rdata;
00952                         }
00953                         catch (const SocketException &) { }
00954                 }
00955 
00956                 freeaddrinfo(addrresult);
00957         }
00958 
00959         return result;
00960 }
00961 
00962 
00963