1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
7 * <brain@chatspike.net>
8 * <Craig@chatspike.net>
10 * Written by Craig Edwards, Craig McLure, and others.
11 * This program is free but copyrighted software; see
12 * the file COPYING for details.
14 * ---------------------------------------------------
18 dns.cpp - Nonblocking DNS functions.
19 Very loosely based on the firedns library,
20 Copyright (C) 2002 Ian Gulliver.
22 There have been so many modifications to this file
23 to make it fit into InspIRCd and make it object
24 orientated that you should not take this code as
25 being what firedns really looks like. It used to
26 look very different to this! :-P
33 #include <sys/types.h>
34 #include <sys/socket.h>
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
43 #include "helperfuncs.h"
44 #include "inspircd_config.h"
45 #include "socketengine.h"
46 #include "configreader.h"
48 extern InspIRCd* ServerInstance;
49 extern ServerConfig* Config;
51 extern userrec* fd_ref_table[MAX_DESCRIPTORS];
64 FLAGS_MASK_OPCODE = 0x78,
66 FLAGS_MASK_RCODE = 0x0F,
72 typedef std::map<int,dns_connection*> connlist;
73 typedef connlist::iterator connlist_iter;
78 int master_socket = -1;
79 Resolver* dns_classes[65536];
86 unsigned int rr_class;
88 unsigned int rdlength;
100 unsigned int arcount;
101 unsigned char payload[512];
109 unsigned int rr_class;
114 res = new unsigned char[512];
123 unsigned char* result_ready(dns_header &h, int length);
124 int send_requests(const dns_header *h, const int l, QueryType qt);
128 * Optimized by brain, these were using integer division and modulus.
129 * We can use logic shifts and logic AND to replace these even divisions
130 * and multiplications, it should be a bit faster (probably not noticably,
131 * but of course, more impressive). Also made these inline.
134 inline void dns_fill_rr(dns_rr_middle* rr, const unsigned char *input)
136 rr->type = (QueryType)((input[0] << 8) + input[1]);
137 rr->rr_class = (input[2] << 8) + input[3];
138 rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
139 rr->rdlength = (input[8] << 8) + input[9];
142 inline void dns_fill_header(dns_header *header, const unsigned char *input, const int length)
144 header->id[0] = input[0];
145 header->id[1] = input[1];
146 header->flags1 = input[2];
147 header->flags2 = input[3];
148 header->qdcount = (input[4] << 8) + input[5];
149 header->ancount = (input[6] << 8) + input[7];
150 header->nscount = (input[8] << 8) + input[9];
151 header->arcount = (input[10] << 8) + input[11];
152 memcpy(header->payload,&input[12],length);
155 inline void dns_empty_header(unsigned char *output, const dns_header *header, const int length)
157 output[0] = header->id[0];
158 output[1] = header->id[1];
159 output[2] = header->flags1;
160 output[3] = header->flags2;
161 output[4] = header->qdcount >> 8;
162 output[5] = header->qdcount & 0xFF;
163 output[6] = header->ancount >> 8;
164 output[7] = header->ancount & 0xFF;
165 output[8] = header->nscount >> 8;
166 output[9] = header->nscount & 0xFF;
167 output[10] = header->arcount >> 8;
168 output[11] = header->arcount & 0xFF;
169 memcpy(&output[12],header->payload,length);
173 int dns_connection::send_requests(const dns_header *h, const int length, QueryType qt)
176 unsigned char payload[sizeof(dns_header)];
181 dns_empty_header(payload,h,length);
183 memset(&addr,0,sizeof(addr));
185 memcpy(&addr.sin6_addr,&myserver,sizeof(addr.sin6_addr));
186 addr.sin6_family = AF_FAMILY;
187 addr.sin6_port = htons(53);
189 memcpy(&addr.sin_addr.s_addr,&myserver,sizeof(addr.sin_addr));
190 addr.sin_family = AF_FAMILY;
191 addr.sin_port = htons(53);
193 if (sendto(master_socket, payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1)
195 log(DEBUG,"Error in sendto!");
202 dns_connection* dns_add_query(dns_header *h, int &id)
206 dns_connection * s = new dns_connection();
208 h->id[0] = s->id[0] = id >> 8;
209 h->id[1] = s->id[1] = id & 0xFF;
210 h->flags1 = FLAGS_MASK_RD;
217 if (connections.find(id) == connections.end())
224 log(DEBUG,"---- BEGIN DNS INITIALIZATION, SERVER=%s ---",Config->DNSServer);
226 srand((unsigned int) TIME);
227 memset(&myserver,0,sizeof(insp_inaddr));
228 if (insp_aton(Config->DNSServer,&addr) > 0)
229 memcpy(&myserver,&addr,sizeof(insp_inaddr));
231 master_socket = socket(PF_PROTOCOL, SOCK_DGRAM, 0);
232 if (master_socket != -1)
234 log(DEBUG,"Set query socket nonblock");
235 if (fcntl(master_socket, F_SETFL, O_NONBLOCK) != 0)
237 shutdown(master_socket,2);
238 close(master_socket);
242 if (master_socket != -1)
246 memset(&addr,0,sizeof(addr));
247 addr.sin6_family = AF_FAMILY;
249 memset(&addr.sin6_addr,255,sizeof(in6_addr));
252 memset(&addr,0,sizeof(addr));
253 addr.sin_family = AF_FAMILY;
255 addr.sin_addr.s_addr = INADDR_ANY;
257 log(DEBUG,"Binding query port");
258 if (bind(master_socket,(sockaddr *)&addr,sizeof(addr)) != 0)
260 log(DEBUG,"Cant bind with source port = 0");
261 shutdown(master_socket,2);
262 close(master_socket);
266 if (master_socket >= 0)
268 log(DEBUG,"Attach query port to socket engine");
269 if (ServerInstance && ServerInstance->SE)
270 ServerInstance->SE->AddFd(master_socket,true,X_ESTAB_DNS);
275 int dns_build_query_payload(const char * const name, const unsigned short rr, const unsigned short rr_class, unsigned char * const payload)
278 const char * tempchr, * tempchr2;
284 /* split name up into labels, create query */
285 while ((tempchr = strchr(tempchr2,'.')) != NULL)
287 l = tempchr - tempchr2;
288 if (payloadpos + l + 1 > 507)
290 payload[payloadpos++] = l;
291 memcpy(&payload[payloadpos],tempchr2,l);
293 tempchr2 = &tempchr[1];
295 l = strlen(tempchr2);
298 if (payloadpos + l + 2 > 507)
300 payload[payloadpos++] = l;
301 memcpy(&payload[payloadpos],tempchr2,l);
303 payload[payloadpos++] = '\0';
305 if (payloadpos > 508)
308 memcpy(&payload[payloadpos],&l,2);
310 memcpy(&payload[payloadpos + 2],&l,2);
311 return payloadpos + 4;
314 int DNS::dns_getip4(const char *name)
321 if ((length = dns_build_query_payload(name,DNS_QRY_A,1,(unsigned char*)&h.payload)) == -1)
324 if ((req = dns_add_query(&h, id)) == NULL)
327 if (req->send_requests(&h,length,DNS_QRY_A) == -1)
333 int DNS::dns_getname4(const insp_inaddr *ip)
344 unsigned char* c = (unsigned char*)&ip->s_addr;
346 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
348 if ((length = dns_build_query_payload(query,DNS_QRY_PTR,1,(unsigned char*)&h.payload)) == -1)
351 if ((req = dns_add_query(&h, id)) == NULL)
354 if (req->send_requests(&h,length,DNS_QRY_PTR) == -1)
361 /* Return the next id which is ready, and the result attached to it
363 DNSResult DNS::dns_getresult()
365 /* retrieve result of DNS query (buffered) */
369 unsigned char buffer[sizeof(dns_header)];
371 length = recv(master_socket,buffer,sizeof(dns_header),0);
374 return std::make_pair(-1,"");
376 dns_fill_header(&h,buffer,length - 12);
378 // Get the id of this request
379 unsigned long this_id = h.id[1] + (h.id[0] << 8);
381 // Do we have a pending request for it?
383 connlist_iter n_iter = connections.find(this_id);
384 if (n_iter == connections.end())
386 log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",master_socket,this_id);
387 return std::make_pair(-1,"");
391 /* Remove the query from the list */
392 c = (dns_connection*)n_iter->second;
393 /* We don't delete c here, because its done later when needed */
394 connections.erase(n_iter);
396 unsigned char* a = c->result_ready(h, length);
397 std::string resultstr;
405 if (c->type == DNS_QRY_A)
407 char formatted[1024];
408 snprintf(formatted,1024,"%u.%u.%u.%u",a[0],a[1],a[2],a[3]);
409 resultstr = std::string(formatted);
413 resultstr = std::string((const char*)a);
418 return std::make_pair(this_id,resultstr);
421 /** A result is ready, process it
423 unsigned char* dns_connection::result_ready(dns_header &h, int length)
425 int i, q, curanswer, o;
429 if ((h.flags1 & FLAGS_MASK_QR) == 0)
431 log(DEBUG,"DNS: didnt get a query result");
434 if ((h.flags1 & FLAGS_MASK_OPCODE) != 0)
436 log(DEBUG,"DNS: got an OPCODE and didnt want one");
439 if ((h.flags2 & FLAGS_MASK_RCODE) != 0)
441 log(DEBUG,"DNS lookup failed due to SERVFAIL");
446 log(DEBUG,"DNS: no answers!");
452 while ((unsigned)q < h.qdcount && i < length)
454 if (h.payload[i] > 63)
461 if (h.payload[i] == 0)
466 else i += h.payload[i] + 1;
470 while ((unsigned)curanswer < h.ancount)
473 while (q == 0 && i < length)
475 if (h.payload[i] > 63)
482 if (h.payload[i] == 0)
487 else i += h.payload[i] + 1; /* skip length and label */
494 dns_fill_rr(&rr,&h.payload[i]);
496 if (rr.type != this->type)
502 if (rr.rr_class != this->rr_class)
510 if ((unsigned int)curanswer == h.ancount)
512 if (i + rr.rdlength > (unsigned int)length)
514 if (rr.rdlength > 1023)
520 log(DEBUG,"DNS: got a result of type DNS_QRY_PTR");
523 while (q == 0 && i < length && o + 256 < 1023)
525 if (h.payload[i] > 63)
527 log(DEBUG,"DNS: h.payload[i] > 63");
528 memcpy(&p,&h.payload[i],2);
529 i = ntohs(p) - 0xC000 - 12;
533 if (h.payload[i] == 0)
542 memcpy(&res[o],&h.payload[i + 1],h.payload[i]);
544 i += h.payload[i] + 1;
551 log(DEBUG,"DNS: got a result of type DNS_QRY_A");
552 memcpy(res,&h.payload[i],rr.rdlength);
553 res[rr.rdlength] = '\0';
556 memcpy(res,&h.payload[i],rr.rdlength);
557 res[rr.rdlength] = '\0';
565 log(DEBUG,"Create blank DNS");
572 Resolver::Resolver(const std::string &source, bool forward) : input(source), fwd(forward)
576 log(DEBUG,"Resolver: Forward lookup on %s",source.c_str());
577 this->myid = Res->dns_getip4(source.c_str());
581 log(DEBUG,"Resolver: Reverse lookup on %s",source.c_str());
583 if (insp_aton(source.c_str(), &binip) > 0)
585 /* Valid ip address */
586 this->myid = Res->dns_getname4(&binip);
589 if (this->myid == -1)
591 log(DEBUG,"Resolver::Resolver: Could not get an id!");
592 this->OnError(RESOLVER_NSDOWN);
593 throw ModuleException("Resolver: Couldnt get an id to make a request");
594 /* We shouldnt get here really */
598 log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid);
601 void Resolver::OnLookupComplete(const std::string &result)
605 void Resolver::OnError(ResolverError e)
609 Resolver::~Resolver()
611 log(DEBUG,"Resolver::~Resolver");
614 int Resolver::GetId()
619 bool Resolver::ProcessResult(const std::string &result)
621 log(DEBUG,"Resolver::ProcessResult");
623 if (!result.length())
625 log(DEBUG,"Resolver::OnError(RESOLVER_NXDOMAIN)");
626 this->OnError(RESOLVER_NXDOMAIN);
632 log(DEBUG,"Resolver::OnLookupComplete(%s)",result.c_str());
633 this->OnLookupComplete(result);
638 void dns_deal_with_classes(int fd)
640 log(DEBUG,"dns_deal_with_classes(%d)",fd);
641 if (fd == master_socket)
643 DNSResult res = Res->dns_getresult();
646 log(DEBUG,"Result available, id=%d",res.first);
647 if (dns_classes[res.first])
649 dns_classes[res.first]->ProcessResult(res.second);
650 delete dns_classes[res.first];
651 dns_classes[res.first] = NULL;
657 bool dns_add_class(Resolver* r)
659 log(DEBUG,"dns_add_class");
660 if ((r) && (r->GetId() > -1))
662 if (!dns_classes[r->GetId()])
664 log(DEBUG,"dns_add_class: added class");
665 dns_classes[r->GetId()] = r;
670 log(DEBUG,"Space occupied!");
676 log(DEBUG,"Bad class");
685 memset(dns_classes,0,sizeof(dns_classes));