The InspIRCd Project
Home | Developers | Wiki | Forums | Bug Tracker | SVN | Download
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

dns.cpp

Go to the documentation of this file.
00001 /*       +------------------------------------+
00002  *       | Inspire Internet Relay Chat Daemon |
00003  *       +------------------------------------+
00004  *
00005  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
00006  * See: http://www.inspircd.org/wiki/index.php/Credits
00007  *
00008  * This program is free but copyrighted software; see
00009  *            the file COPYING for details.
00010  *
00011  * ---------------------------------------------------
00012  */
00013 
00014 /* $Core */
00015 
00016 /*
00017 dns.cpp - Nonblocking DNS functions.
00018 Very very loosely based on the firedns library,
00019 Copyright (C) 2002 Ian Gulliver. This file is no
00020 longer anything like firedns, there are many major
00021 differences between this code and the original.
00022 Please do not assume that firedns works like this,
00023 looks like this, walks like this or tastes like this.
00024 */
00025 
00026 #ifndef WIN32
00027 #include <sys/types.h>
00028 #include <sys/socket.h>
00029 #include <errno.h>
00030 #include <netinet/in.h>
00031 #include <arpa/inet.h>
00032 #else
00033 #include "inspircd_win32wrapper.h"
00034 #include "inspircd_se_config.h"
00035 #endif
00036 
00037 #include "dns.h"
00038 #include "inspircd.h"
00039 #include "socketengine.h"
00040 #include "configreader.h"
00041 #include "socket.h"
00042 
00043 using irc::sockets::insp_inaddr;
00044 using irc::sockets::insp_ntoa;
00045 using irc::sockets::insp_aton;
00046 using irc::sockets::OpenTCPSocket;
00047 
00050 enum QueryInfo
00051 {
00052         ERROR_MASK      = 0x10000       /* Result is an error */
00053 };
00054 
00057 enum QueryFlags
00058 {
00059         FLAGS_MASK_RD           = 0x01, /* Recursive */
00060         FLAGS_MASK_TC           = 0x02,
00061         FLAGS_MASK_AA           = 0x04, /* Authoritative */
00062         FLAGS_MASK_OPCODE       = 0x78,
00063         FLAGS_MASK_QR           = 0x80,
00064         FLAGS_MASK_RCODE        = 0x0F, /* Request */
00065         FLAGS_MASK_Z            = 0x70,
00066         FLAGS_MASK_RA           = 0x80
00067 };
00068 
00069 
00072 struct ResourceRecord
00073 {
00074         QueryType       type;           /* Record type */
00075         unsigned int    rr_class;       /* Record class */
00076         unsigned long   ttl;            /* Time to live */
00077         unsigned int    rdlength;       /* Record length */
00078 };
00079 
00082 class DNSHeader
00083 {
00084  public:
00085         unsigned char   id[2];          /* Request id */
00086         unsigned int    flags1;         /* Flags */
00087         unsigned int    flags2;         /* Flags */
00088         unsigned int    qdcount;
00089         unsigned int    ancount;        /* Answer count */
00090         unsigned int    nscount;        /* Nameserver count */
00091         unsigned int    arcount;
00092         unsigned char   payload[512];   /* Packet payload */
00093 };
00094 
00095 class DNSRequest
00096 {
00097  public:
00098         unsigned char   id[2];          /* Request id */
00099         unsigned char*  res;            /* Result processing buffer */
00100         unsigned int    rr_class;       /* Request class */
00101         QueryType       type;           /* Request type */
00102         DNS*            dnsobj;         /* DNS caller (where we get our FD from) */
00103         unsigned long   ttl;            /* Time to live */
00104         std::string     orig;           /* Original requested name/ip */
00105         InspIRCd*       ServerInstance;
00106 
00107         DNSRequest(InspIRCd* Instance, DNS* dns, int id, const std::string &original);
00108         ~DNSRequest();
00109         DNSInfo ResultIsReady(DNSHeader &h, int length, int result_we_want);
00110         int SendRequests(const DNSHeader *header, const int length, QueryType qt);
00111 };
00112 
00113 class CacheTimer : public Timer
00114 {
00115  private:
00116         InspIRCd* ServerInstance;
00117         DNS* dns;
00118  public:
00119         CacheTimer(InspIRCd* Instance, DNS* thisdns)
00120                 : Timer(3600, Instance->Time(), true), ServerInstance(Instance), dns(thisdns) { }
00121 
00122         virtual void Tick(time_t)
00123         {
00124                 dns->PruneCache();
00125         }
00126 };
00127 
00128 class RequestTimeout : public Timer
00129 {
00130         InspIRCd* ServerInstance;
00131         DNSRequest* watch;
00132         int watchid;
00133  public:
00134         RequestTimeout(unsigned long n, InspIRCd* SI, DNSRequest* watching, int id) : Timer(n, time(NULL)), ServerInstance(SI), watch(watching), watchid(id)
00135         {
00136         }
00137 
00138         void Tick(time_t)
00139         {
00140                 if (ServerInstance->Res->requests[watchid] == watch)
00141                 {
00142                         /* Still exists, whack it */
00143                         if (ServerInstance->Res->Classes[watchid])
00144                         {
00145                                 ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out");
00146                                 delete ServerInstance->Res->Classes[watchid];
00147                                 ServerInstance->Res->Classes[watchid] = NULL;
00148                         }
00149                         ServerInstance->Res->requests[watchid] = NULL;
00150                         delete watch;
00151                         return;
00152                 }
00153         }
00154 };
00155 
00156 /* Allocate the processing buffer */
00157 DNSRequest::DNSRequest(InspIRCd* Instance, DNS* dns, int rid, const std::string &original) : dnsobj(dns), ServerInstance(Instance)
00158 {
00159         res = new unsigned char[512];
00160         *res = 0;
00161         orig = original;
00162         RequestTimeout* RT = new RequestTimeout(Instance->Config->dns_timeout ? Instance->Config->dns_timeout : 5, Instance, this, rid);
00163         Instance->Timers->AddTimer(RT); /* The timer manager frees this */
00164 }
00165 
00166 /* Deallocate the processing buffer */
00167 DNSRequest::~DNSRequest()
00168 {
00169         delete[] res;
00170 }
00171 
00173 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
00174 {
00175         rr->type = (QueryType)((input[0] << 8) + input[1]);
00176         rr->rr_class = (input[2] << 8) + input[3];
00177         rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
00178         rr->rdlength = (input[8] << 8) + input[9];
00179 }
00180 
00182 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
00183 {
00184         header->id[0] = input[0];
00185         header->id[1] = input[1];
00186         header->flags1 = input[2];
00187         header->flags2 = input[3];
00188         header->qdcount = (input[4] << 8) + input[5];
00189         header->ancount = (input[6] << 8) + input[7];
00190         header->nscount = (input[8] << 8) + input[9];
00191         header->arcount = (input[10] << 8) + input[11];
00192         memcpy(header->payload,&input[12],length);
00193 }
00194 
00196 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
00197 {
00198         output[0] = header->id[0];
00199         output[1] = header->id[1];
00200         output[2] = header->flags1;
00201         output[3] = header->flags2;
00202         output[4] = header->qdcount >> 8;
00203         output[5] = header->qdcount & 0xFF;
00204         output[6] = header->ancount >> 8;
00205         output[7] = header->ancount & 0xFF;
00206         output[8] = header->nscount >> 8;
00207         output[9] = header->nscount & 0xFF;
00208         output[10] = header->arcount >> 8;
00209         output[11] = header->arcount & 0xFF;
00210         memcpy(&output[12],header->payload,length);
00211 }
00212 
00214 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
00215 {
00216         ServerInstance->Logs->Log("RESOLVER", DEBUG,"DNSRequest::SendRequests");
00217 
00218         unsigned char payload[sizeof(DNSHeader)];
00219 
00220         this->rr_class = 1;
00221         this->type = qt;
00222                 
00223         DNS::EmptyHeader(payload,header,length);
00224 
00225 #ifdef IPV6
00226         if (this->dnsobj->socketfamily == AF_INET6)
00227         {
00228                 sockaddr_in6 addr;
00229                 memset(&addr,0,sizeof(addr));
00230                 memcpy(&addr.sin6_addr,&dnsobj->myserver6,sizeof(addr.sin6_addr));
00231                 addr.sin6_family = AF_INET6;
00232                 addr.sin6_port = htons(DNS::QUERY_PORT);
00233                 if (ServerInstance->SE->SendTo(dnsobj, payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) != length+12)
00234                         return -1;
00235         }
00236         else
00237 #endif
00238         {
00239                 sockaddr_in addr;
00240                 memset(&addr,0,sizeof(addr));
00241                 memcpy(&addr.sin_addr.s_addr,&dnsobj->myserver4,sizeof(addr.sin_addr));
00242                 addr.sin_family = AF_INET;
00243                 addr.sin_port = htons(DNS::QUERY_PORT);
00244                 if (ServerInstance->SE->SendTo(dnsobj, (const char*)payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) != length+12)
00245                         return -1;
00246         }
00247 
00248         ServerInstance->Logs->Log("RESOLVER",DEBUG,"Sent OK");
00249         return 0;
00250 }
00251 
00253 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id, const char* original)
00254 {
00255         /* Is the DNS connection down? */
00256         if (this->GetFd() == -1)
00257                 return NULL;
00258         
00259         /* Create an id */
00260         id = this->PRNG() & DNS::MAX_REQUEST_ID;
00261 
00262         /* If this id is already 'in flight', pick another. */
00263         while (requests[id])
00264                 id = this->PRNG() & DNS::MAX_REQUEST_ID;
00265 
00266         DNSRequest* req = new DNSRequest(ServerInstance, this, id, original);
00267 
00268         header->id[0] = req->id[0] = id >> 8;
00269         header->id[1] = req->id[1] = id & 0xFF;
00270         header->flags1 = FLAGS_MASK_RD;
00271         header->flags2 = 0;
00272         header->qdcount = 1;
00273         header->ancount = 0;
00274         header->nscount = 0;
00275         header->arcount = 0;
00276 
00277         /* At this point we already know the id doesnt exist,
00278          * so there needs to be no second check for the ::end()
00279          */
00280         requests[id] = req;
00281 
00282         /* According to the C++ spec, new never returns NULL. */
00283         return req;
00284 }
00285 
00286 int DNS::ClearCache()
00287 {
00288         /* This ensures the buckets are reset to sane levels */
00289         int rv = this->cache->size();
00290         delete this->cache;
00291         this->cache = new dnscache();
00292         return rv;
00293 }
00294 
00295 int DNS::PruneCache()
00296 {
00297         int n = 0;
00298         dnscache* newcache = new dnscache();
00299         for (dnscache::iterator i = this->cache->begin(); i != this->cache->end(); i++)
00300                 /* Dont include expired items (theres no point) */
00301                 if (i->second.CalcTTLRemaining())
00302                         newcache->insert(*i);
00303                 else
00304                         n++;
00305 
00306         delete this->cache;
00307         this->cache = newcache;
00308         return n;
00309 }
00310 
00311 void DNS::Rehash()
00312 {
00313         ip6munge = false;
00314         int portpass = 0;
00315 
00316         if (this->GetFd() > -1)
00317         {
00318                 if (ServerInstance && ServerInstance->SE)
00319                         ServerInstance->SE->DelFd(this);
00320                 ServerInstance->SE->Shutdown(this, 2);
00321                 ServerInstance->SE->Close(this);
00322                 this->SetFd(-1);
00323 
00324                 /* Rehash the cache */
00325                 this->PruneCache();
00326         }
00327         else
00328         {
00329                 /* Create initial dns cache */
00330                 this->cache = new dnscache();
00331         }
00332 
00333         if ((strstr(ServerInstance->Config->DNSServer,"::ffff:") == (char*)&ServerInstance->Config->DNSServer) ||  (strstr(ServerInstance->Config->DNSServer,"::FFFF:") == (char*)&ServerInstance->Config->DNSServer))
00334         {
00335                 ServerInstance->Logs->Log("RESOLVER",DEFAULT,"WARNING: Using IPv4 addresses over IPv6 forces some DNS checks to be disabled.");
00336                 ServerInstance->Logs->Log("RESOLVER",DEFAULT,"         This should not cause a problem, however it is recommended you migrate");
00337                 ServerInstance->Logs->Log("RESOLVER",DEFAULT,"         to a true IPv6 environment.");
00338                 this->ip6munge = true;
00339         }
00340 
00341         this->socketfamily = AF_INET;
00342 #ifdef IPV6
00343         if (strchr(ServerInstance->Config->DNSServer,':'))
00344         {
00345                 this->socketfamily = AF_INET6;
00346                 inet_pton(AF_INET6, ServerInstance->Config->DNSServer, &this->myserver6);
00347         }
00348         else
00349         {
00350                 inet_aton(ServerInstance->Config->DNSServer, &this->myserver4);
00351                 portpass = -1;
00352         }
00353 #else
00354         inet_aton(ServerInstance->Config->DNSServer, &this->myserver4);
00355 #endif
00356 
00357         /* Initialize mastersocket */
00358         int s = OpenTCPSocket(ServerInstance->Config->DNSServer, SOCK_DGRAM);
00359         this->SetFd(s);
00360         ServerInstance->SE->NonBlocking(this->GetFd());
00361 
00362         /* Have we got a socket and is it nonblocking? */
00363         if (this->GetFd() != -1)
00364         {
00365                 /* Bind the port - port 0 INADDR_ANY */
00366                 if (!ServerInstance->BindSocket(this->GetFd(), portpass, "", false))
00367                 {
00368                         /* Failed to bind */
00369                         ServerInstance->Logs->Log("RESOLVER",DEBUG,"Error binding dns socket");
00370                         ServerInstance->SE->Shutdown(this, 2);
00371                         ServerInstance->SE->Close(this);
00372                         this->SetFd(-1);
00373                 }
00374 
00375                 if (this->GetFd() >= 0)
00376                 {
00377                         /* Hook the descriptor into the socket engine */
00378                         if (ServerInstance && ServerInstance->SE)
00379                         {
00380                                 if (!ServerInstance->SE->AddFd(this))
00381                                 {
00382                                         ServerInstance->Logs->Log("RESOLVER",DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
00383                                         ServerInstance->SE->Shutdown(this, 2);
00384                                         ServerInstance->SE->Close(this);
00385                                         this->SetFd(-1);
00386                                 }
00387                         }
00388                 }
00389         }
00390         else
00391         {
00392                 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Error creating dns socket");
00393         }
00394 }
00395 
00397 DNS::DNS(InspIRCd* Instance) : ServerInstance(Instance)
00398 {
00399         ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::DNS");
00400         /* Clear the Resolver class table */
00401         memset(Classes,0,sizeof(Classes));
00402 
00403         /* Clear the requests class table */
00404         memset(requests,0,sizeof(requests));
00405 
00406         /* Set the id of the next request to 0
00407          */
00408         currid = 0;
00409 
00410         /* DNS::Rehash() sets this to a valid ptr
00411          */
00412         this->cache = NULL;
00413         
00414         /* Again, DNS::Rehash() sets this to a
00415          * valid value
00416          */
00417         this->SetFd(-1);
00418 
00419         /* Actually read the settings
00420          */
00421         this->Rehash();
00422 
00423         this->PruneTimer = new CacheTimer(ServerInstance, this);
00424 
00425         ServerInstance->Timers->AddTimer(this->PruneTimer);
00426 }
00427 
00429 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
00430 {
00431         short payloadpos = 0;
00432         const char* tempchr, *tempchr2 = name;
00433         unsigned short length;
00434 
00435         /* split name up into labels, create query */
00436         while ((tempchr = strchr(tempchr2,'.')) != NULL)
00437         {
00438                 length = tempchr - tempchr2;
00439                 if (payloadpos + length + 1 > 507)
00440                         return -1;
00441                 payload[payloadpos++] = length;
00442                 memcpy(&payload[payloadpos],tempchr2,length);
00443                 payloadpos += length;
00444                 tempchr2 = &tempchr[1];
00445         }
00446         length = strlen(tempchr2);
00447         if (length)
00448         {
00449                 if (payloadpos + length + 2 > 507)
00450                         return -1;
00451                 payload[payloadpos++] = length;
00452                 memcpy(&payload[payloadpos],tempchr2,length);
00453                 payloadpos += length;
00454                 payload[payloadpos++] = 0;
00455         }
00456         if (payloadpos > 508)
00457                 return -1;
00458         length = htons(rr);
00459         memcpy(&payload[payloadpos],&length,2);
00460         length = htons(rr_class);
00461         memcpy(&payload[payloadpos + 2],&length,2);
00462         return payloadpos + 4;
00463 }
00464 
00466 int DNS::GetIP(const char *name)
00467 {
00468         DNSHeader h;
00469         int id;
00470         int length;
00471         
00472         if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
00473                 return -1;
00474 
00475         DNSRequest* req = this->AddQuery(&h, id, name);
00476 
00477         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
00478                 return -1;
00479 
00480         return id;
00481 }
00482 
00484 int DNS::GetIP6(const char *name)
00485 {
00486         DNSHeader h;
00487         int id;
00488         int length;
00489 
00490         if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
00491                 return -1;
00492 
00493         DNSRequest* req = this->AddQuery(&h, id, name);
00494 
00495         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
00496                 return -1;
00497 
00498         return id;
00499 }
00500 
00502 int DNS::GetCName(const char *alias)
00503 {
00504         DNSHeader h;
00505         int id;
00506         int length;
00507 
00508         if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
00509                 return -1;
00510 
00511         DNSRequest* req = this->AddQuery(&h, id, alias);
00512 
00513         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
00514                 return -1;
00515 
00516         return id;
00517 }
00518 
00520 int DNS::GetName(const insp_inaddr *ip)
00521 {
00522         char query[128];
00523         DNSHeader h;
00524         int id;
00525         int length;
00526 
00527 #ifdef IPV6
00528         unsigned char* c = (unsigned char*)&ip->s6_addr;
00529         if (c[0] == 0 && c[1] == 0 && c[2] == 0 && c[3] == 0 &&
00530             c[4] == 0 && c[5] == 0 && c[6] == 0 && c[7] == 0 &&
00531             c[8] == 0 && c[9] == 0 && c[10] == 0xFF && c[11] == 0xFF)
00532                 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[15],c[14],c[13],c[12]);
00533         else
00534                 DNS::MakeIP6Int(query, (in6_addr*)ip);
00535 #else
00536         unsigned char* c = (unsigned char*)&ip->s_addr;
00537         sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
00538 #endif
00539 
00540         if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
00541                 return -1;
00542 
00543         DNSRequest* req = this->AddQuery(&h, id, insp_ntoa(*ip));
00544 
00545         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
00546                 return -1;
00547 
00548         return id;
00549 }
00550 
00552 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
00553 {
00554         char query[128];
00555         DNSHeader h;
00556         int id;
00557         int length;
00558 #ifdef SUPPORT_IP6LINKS
00559         if (fp == PROTOCOL_IPV6)
00560         {
00561                 in6_addr i;
00562                 if (inet_pton(AF_INET6, ip, &i) > 0)
00563                 {
00564                         DNS::MakeIP6Int(query, &i);
00565                 }
00566                 else
00567                         /* Invalid IP address */
00568                         return -1;
00569         }
00570         else
00571 #endif
00572         {
00573                 in_addr i;
00574                 if (inet_aton(ip, &i))
00575                 {
00576                         unsigned char* c = (unsigned char*)&i.s_addr;
00577                         sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
00578                 }
00579                 else
00580                         /* Invalid IP address */
00581                         return -1;
00582         }
00583 
00584         if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
00585                 return -1;
00586 
00587         DNSRequest* req = this->AddQuery(&h, id, ip);
00588 
00589         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
00590                 return -1;
00591 
00592         return id;
00593 }
00594 
00597 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
00598 {
00599 #ifdef SUPPORT_IP6LINKS
00600         const char* hex = "0123456789abcdef";
00601         for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
00602         {
00603                 if (index % 2)
00604                         /* low nibble */
00605                         *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
00606                 else
00607                         /* high nibble */
00608                         *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
00609                 *query++ = '.'; /* Seperator */
00610         }
00611         strcpy(query,"ip6.arpa"); /* Suffix the string */
00612 #else
00613         *query = 0;
00614 #endif
00615 }
00616 
00618 DNSResult DNS::GetResult(int resultnum)
00619 {
00620         /* Fetch dns query response and decide where it belongs */
00621         DNSHeader header;
00622         DNSRequest *req;
00623         unsigned char buffer[sizeof(DNSHeader)];
00624         sockaddr* from = new sockaddr[2];
00625 #ifdef IPV6
00626         socklen_t x = this->socketfamily == AF_INET ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
00627 #else
00628         socklen_t x = sizeof(sockaddr_in);
00629 #endif
00630         const char* ipaddr_from;
00631         unsigned short int port_from = 0;
00632 
00633         int length = ServerInstance->SE->RecvFrom(this, (char*)buffer, sizeof(DNSHeader), 0, from, &x);
00634 
00635         /* Did we get the whole header? */
00636         if (length < 12)
00637         {
00638                 /* Nope - something screwed up. */
00639                 delete[] from;
00640                 return DNSResult(-1,"",0,"");
00641         }
00642 
00643         /* Check wether the reply came from a different DNS
00644          * server to the one we sent it to, or the source-port
00645          * is not 53.
00646          * A user could in theory still spoof dns packets anyway
00647          * but this is less trivial than just sending garbage
00648          * to the client, which is possible without this check.
00649          *
00650          * -- Thanks jilles for pointing this one out.
00651          */
00652 #ifdef IPV6
00653         char nbuf[MAXBUF];
00654         if (this->socketfamily == AF_INET6)
00655         {
00656                 ipaddr_from = inet_ntop(AF_INET6, &((sockaddr_in6*)from)->sin6_addr, nbuf, sizeof(nbuf));
00657                 port_from = ntohs(((sockaddr_in6*)from)->sin6_port);
00658         }
00659         else
00660 #endif
00661         {
00662                 ipaddr_from = inet_ntoa(((sockaddr_in*)from)->sin_addr);
00663                 port_from = ntohs(((sockaddr_in*)from)->sin_port);
00664         }
00665 
00666         delete[] from;
00667 
00668         /* We cant perform this security check if you're using 4in6.
00669          * Tough luck to you, choose one or't other!
00670          */
00671         if (!ip6munge)
00672         {
00673                 if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, ServerInstance->Config->DNSServer)))
00674                 {
00675                         return DNSResult(-1,"",0,"");
00676                 }
00677         }
00678 
00679         /* Put the read header info into a header class */
00680         DNS::FillHeader(&header,buffer,length - 12);
00681 
00682         /* Get the id of this request.
00683          * Its a 16 bit value stored in two char's,
00684          * so we use logic shifts to create the value.
00685          */
00686         unsigned long this_id = header.id[1] + (header.id[0] << 8);
00687 
00688         /* Do we have a pending request matching this id? */
00689         if (!requests[this_id])
00690         {
00691                 /* Somehow we got a DNS response for a request we never made... */
00692                 return DNSResult(-1,"",0,"");
00693         }
00694         else
00695         {
00696                 /* Remove the query from the list of pending queries */
00697                 req = requests[this_id];
00698                 requests[this_id] = NULL;
00699         }
00700 
00701         /* Inform the DNSRequest class that it has a result to be read.
00702          * When its finished it will return a DNSInfo which is a pair of
00703          * unsigned char* resource record data, and an error message.
00704          */
00705         DNSInfo data = req->ResultIsReady(header, length, resultnum);
00706         std::string resultstr;
00707 
00708         /* Check if we got a result, if we didnt, its an error */
00709         if (data.first == NULL)
00710         {
00711                 /* An error.
00712                  * Mask the ID with the value of ERROR_MASK, so that
00713                  * the dns_deal_with_classes() function knows that its
00714                  * an error response and needs to be treated uniquely.
00715                  * Put the error message in the second field.
00716                  */
00717                 std::string ro = req->orig;
00718                 delete req;
00719                 return DNSResult(this_id | ERROR_MASK, data.second, 0, ro);
00720         }
00721         else
00722         {
00723                 unsigned long ttl = req->ttl;
00724                 char formatted[128];
00725 
00726                 /* Forward lookups come back as binary data. We must format them into ascii */
00727                 switch (req->type)
00728                 {
00729                         case DNS_QUERY_A:
00730                                 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
00731                                 resultstr = formatted;
00732                         break;
00733 
00734                         case DNS_QUERY_AAAA:
00735                         {
00736                                 inet_ntop(AF_INET6, data.first, formatted, sizeof(formatted));
00737                                 char* c = strstr(formatted,":0:");
00738                                 if (c != NULL)
00739                                 {
00740                                         memmove(c+1,c+2,strlen(c+2) + 1);
00741                                         c += 2;
00742                                         while (memcmp(c,"0:",2) == 0)
00743                                                 memmove(c,c+2,strlen(c+2) + 1);
00744                                         if (memcmp(c,"0",2) == 0)
00745                                                 *c = 0;
00746                                         if (memcmp(formatted,"0::",3) == 0)
00747                                                 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
00748                                 }
00749                                 resultstr = formatted;
00750 
00751                                 /* Special case. Sending ::1 around between servers
00752                                  * and to clients is dangerous, because the : on the
00753                                  * start makes the client or server interpret the IP
00754                                  * as the last parameter on the line with a value ":1".
00755                                  */
00756                                 if (*formatted == ':')
00757                                         resultstr.insert(0, "0");
00758                         }
00759                         break;
00760 
00761                         case DNS_QUERY_CNAME:
00762                                 /* Identical handling to PTR */
00763 
00764                         case DNS_QUERY_PTR:
00765                                 /* Reverse lookups just come back as char* */
00766                                 resultstr = std::string((const char*)data.first);
00767                         break;
00768 
00769                         default:
00770                         break;
00771                         
00772                 }
00773 
00774                 /* Build the reply with the id and hostname/ip in it */
00775                 std::string ro = req->orig;
00776                 delete req;
00777                 return DNSResult(this_id,resultstr,ttl,ro);
00778         }
00779 }
00780 
00782 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length, int result_we_want)
00783 {
00784         int i = 0;
00785         int q = 0;
00786         int curanswer, o;
00787         ResourceRecord rr;
00788         unsigned short ptr;
00789 
00790         /* This is just to keep _FORTIFY_SOURCE happy */
00791         rr.type = DNS_QUERY_NONE;
00792         rr.rdlength = 0;
00793         rr.ttl = 1;     /* GCC is a whiney bastard -- see the XXX below. */
00794         rr.rr_class = 0; /* Same for VC++ */
00795 
00796         if (!(header.flags1 & FLAGS_MASK_QR))
00797                 return std::make_pair((unsigned char*)NULL,"Not a query result");
00798 
00799         if (header.flags1 & FLAGS_MASK_OPCODE)
00800                 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
00801 
00802         if (header.flags2 & FLAGS_MASK_RCODE)
00803                 return std::make_pair((unsigned char*)NULL,"Domain name not found");
00804 
00805         if (header.ancount < 1)
00806                 return std::make_pair((unsigned char*)NULL,"No resource records returned");
00807 
00808         /* Subtract the length of the header from the length of the packet */
00809         length -= 12;
00810 
00811         while ((unsigned int)q < header.qdcount && i < length)
00812         {
00813                 if (header.payload[i] > 63)
00814                 {
00815                         i += 6;
00816                         q++;
00817                 }
00818                 else
00819                 {
00820                         if (header.payload[i] == 0)
00821                         {
00822                                 q++;
00823                                 i += 5;
00824                         }
00825                         else i += header.payload[i] + 1;
00826                 }
00827         }
00828         curanswer = 0;
00829         while ((unsigned)curanswer < header.ancount)
00830         {
00831                 q = 0;
00832                 while (q == 0 && i < length)
00833                 {
00834                         if (header.payload[i] > 63)
00835                         {
00836                                 i += 2;
00837                                 q = 1;
00838                         }
00839                         else
00840                         {
00841                                 if (header.payload[i] == 0)
00842                                 {
00843                                         i++;
00844                                         q = 1;
00845                                 }
00846                                 else i += header.payload[i] + 1; /* skip length and label */
00847                         }
00848                 }
00849                 if (length - i < 10)
00850                         return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
00851 
00852                 /* XXX: We actually initialise 'rr' here including its ttl field */
00853                 if (curanswer == result_we_want)
00854                         DNS::FillResourceRecord(&rr,&header.payload[i]);
00855         
00856                 i += 10;
00857                 if (rr.type != this->type)
00858                 {
00859                         curanswer++;
00860                         i += rr.rdlength;
00861                         continue;
00862                 }
00863                 if (rr.rr_class != this->rr_class)
00864                 {
00865                         curanswer++;
00866                         i += rr.rdlength;
00867                         continue;
00868                 }
00869                 break;
00870         }
00871         if ((unsigned int)curanswer == header.ancount)
00872                 return std::make_pair((unsigned char*)NULL,"No more answers (" + ConvToStr(header.ancount) + " answers, wanted #" + ConvToStr(result_we_want) + ")");
00873 
00874         if (i + rr.rdlength > (unsigned int)length)
00875                 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
00876 
00877         if (rr.rdlength > 1023)
00878                 return std::make_pair((unsigned char*)NULL,"Resource record too large");
00879 
00880         this->ttl = rr.ttl;
00881 
00882         switch (rr.type)
00883         {
00884                 case DNS_QUERY_CNAME:
00885                         /* CNAME and PTR have the same processing code */
00886                 case DNS_QUERY_PTR:
00887                         o = 0;
00888                         q = 0;
00889                         while (q == 0 && i < length && o + 256 < 1023)
00890                         {
00891                                 if (header.payload[i] > 63)
00892                                 {
00893                                         memcpy(&ptr,&header.payload[i],2);
00894                                         i = ntohs(ptr) - 0xC000 - 12;
00895                                 }
00896                                 else
00897                                 {
00898                                         if (header.payload[i] == 0)
00899                                         {
00900                                                 q = 1;
00901                                         }
00902                                         else
00903                                         {
00904                                                 res[o] = 0;
00905                                                 if (o != 0)
00906                                                         res[o++] = '.';
00907                                                 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
00908                                                 o += header.payload[i];
00909                                                 i += header.payload[i] + 1;
00910                                         }
00911                                 }
00912                         }
00913                         res[o] = 0;
00914                 break;
00915                 case DNS_QUERY_AAAA:
00916                         memcpy(res,&header.payload[i],rr.rdlength);
00917                         res[rr.rdlength] = 0;
00918                 break;
00919                 case DNS_QUERY_A:
00920                         memcpy(res,&header.payload[i],rr.rdlength);
00921                         res[rr.rdlength] = 0;
00922                 break;
00923                 default:
00924                         memcpy(res,&header.payload[i],rr.rdlength);
00925                         res[rr.rdlength] = 0;
00926                 break;
00927         }
00928         return std::make_pair(res,"No error");
00929 }
00930 
00932 DNS::~DNS()
00933 {
00934         ServerInstance->SE->Shutdown(this, 2);
00935         ServerInstance->SE->Close(this);
00936         ServerInstance->Timers->DelTimer(this->PruneTimer);
00937 }
00938 
00939 CachedQuery* DNS::GetCache(const std::string &source)
00940 {
00941         dnscache::iterator x = cache->find(source.c_str());
00942         if (x != cache->end())
00943                 return &(x->second);
00944         else
00945                 return NULL;
00946 }
00947                 
00948 void DNS::DelCache(const std::string &source)
00949 {
00950         cache->erase(source.c_str());
00951 }
00952 
00953 void Resolver::TriggerCachedResult()
00954 {
00955         if (CQ)
00956                 OnLookupComplete(CQ->data, time_left, true, 0);
00957 }
00958 
00960 Resolver::Resolver(InspIRCd* Instance, const std::string &source, QueryType qt, bool &cached, Module* creator) : ServerInstance(Instance), Creator(creator), input(source), querytype(qt)
00961 {
00962         ServerInstance->Logs->Log("RESOLVER",DEBUG,"Resolver::Resolver");
00963         cached = false;
00964 
00965         CQ = ServerInstance->Res->GetCache(source);
00966         if (CQ)
00967         {
00968                 time_left = CQ->CalcTTLRemaining();
00969                 if (!time_left)
00970                 {
00971                         ServerInstance->Res->DelCache(source);
00972                 }
00973                 else
00974                 {
00975                         cached = true;
00976                         return;
00977                 }
00978         }
00979 
00980         insp_inaddr binip;
00981 
00982         switch (querytype)
00983         {
00984                 case DNS_QUERY_A:
00985                         this->myid = ServerInstance->Res->GetIP(source.c_str());
00986                 break;
00987 
00988                 case DNS_QUERY_PTR:
00989                         if (insp_aton(source.c_str(), &binip) > 0)
00990                         {
00991                                 /* Valid ip address */
00992                                 this->myid = ServerInstance->Res->GetName(&binip);
00993                         }
00994                         else
00995                         {
00996                                 this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
00997                                 throw ModuleException("Resolver: Bad IP address");
00998                                 return;
00999                         }
01000                 break;
01001 
01002                 case DNS_QUERY_PTR4:
01003                         querytype = DNS_QUERY_PTR;
01004                         this->myid = ServerInstance->Res->