X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fdns.cpp;h=69df48cc65acdeba1d9e000b0ab6f9e275624adb;hb=a5c99b8dc6164ca3a9abed1c843627c1e817caaa;hp=6788937c60a0209f2f009882177a3760edddacda;hpb=1e4d37149c3c44a479dc3440a650e433c7f1b9c2;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/dns.cpp b/src/dns.cpp index 6788937c6..69df48cc6 100644 --- a/src/dns.cpp +++ b/src/dns.cpp @@ -1,21 +1,32 @@ -/* -dns.cpp - based on the dns library Copyright (C) 2002 Ian Gulliver - -This program is free software; you can redistribute it and/or modify -it under the terms of version 2 of the GNU General Public License as -published by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev. + * E-mail: + * + * + * + * Written by Craig Edwards, Craig McLure, and others. + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/* +dns.cpp - Nonblocking DNS functions. +Very loosely based on the firedns library, +Copyright (C) 2002 Ian Gulliver. + +There have been so many modifications to this file +to make it fit into InspIRCd and make it object +orientated that you should not take this code as +being what firedns really looks like. It used to +look very different to this! :-P */ -#define _DNS_C +using namespace std; #include #include @@ -29,203 +40,174 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include +#include +#include +#include +#include +#include +#include #include "dns.h" +#include "inspircd.h" +#include "helperfuncs.h" +#include "inspircd_config.h" +#include "socketengine.h" +#include "configreader.h" + +extern InspIRCd* ServerInstance; +extern ServerConfig* Config; +extern time_t TIME; +extern userrec* fd_ref_table[MAX_DESCRIPTORS]; + +enum QueryType { DNS_QRY_A = 1, DNS_QRY_PTR = 12 }; +enum QueryFlags1 { FLAGS1_MASK_RD = 0x01, FLAGS1_MASK_TC = 0x02, FLAGS1_MASK_AA = 0x04, FLAGS1_MASK_OPCODE = 0x78, FLAGS1_MASK_QR = 0x80 }; +enum QueryFlags2 { FLAGS2_MASK_RCODE = 0x0F, FLAGS2_MASK_Z = 0x70, FLAGS2_MASK_RA = 0x80 }; + +class s_connection; + +typedef std::map connlist; +typedef connlist::iterator connlist_iter; -static const char tagstring[] = "$Id$"; - -#define max(a,b) (a > b ? a : b) -#define DNS_MAX 8 /* max number of nameservers used */ -#define DNS_CONFIG_FBCK "/etc/resolv.conf" /* fallback config file */ -#define DNS_PORT 53 /* DNS well known port */ -#define DNS_QRY_A 1 /* name to IP address */ -#define DNS_QRY_AAAA 28 /* name to IP6 address */ -#define DNS_QRY_PTR 12 /* IP address to name */ -#define DNS_QRY_MX 15 /* name to MX */ -#define DNS_QRY_TXT 16 /* name to TXT */ -#define DNS_QRY_CNAME 5 - -#define DNS_ALIGN (sizeof(void *) > sizeof(long) ? sizeof(void *) : sizeof(long)) -#define DNS_TRIES 3 -#define RESULTSIZE 1024 -#define min(a,b) (a < b ? a : b) - -static struct in_addr servers4[DNS_MAX]; /* up to DNS_MAX nameservers; populated by dns_init() */ -static int i4; /* actual count of nameservers; set by dns_init() */ - -static int initdone = 0; /* to ensure dns_init() only runs once (on the first call) */ -static int wantclose = 0; -static int lastcreate = -1; - -struct s_connection { /* open DNS query */ - struct s_connection *next; /* next in list */ - unsigned char id[2]; - unsigned int _class; - unsigned int type; - int want_list; - int fd; /* file descriptor returned from sockets */ +DNS* Res = NULL; + +connlist connections; +int master_socket = -1; +Resolver* dns_classes[65536]; +insp_inaddr myserver; + +class s_rr_middle +{ + public: + QueryType type; + unsigned int _class; + unsigned long ttl; + unsigned int rdlength; }; -struct s_rr_middle { - unsigned int type; - unsigned int _class; - unsigned long ttl; - unsigned int rdlength; +class s_header +{ + public: + unsigned char id[2]; + unsigned int flags1; + unsigned int flags2; + unsigned int qdcount; + unsigned int ancount; + unsigned int nscount; + unsigned int arcount; + unsigned char payload[512]; }; -#define DNS_POINTER_VALUE 0xc000 - -static s_connection *connection_head = NULL; /* linked list of open DNS queries; populated by dns_add_query(), decimated by dns_getresult_s() */ - -struct s_header { /* DNS query header */ - unsigned char id[2]; - unsigned int flags1; -#define FLAGS1_MASK_QR 0x80 -#define FLAGS1_MASK_OPCODE 0x78 /* bitshift right 3 */ -#define FLAGS1_MASK_AA 0x04 -#define FLAGS1_MASK_TC 0x02 -#define FLAGS1_MASK_RD 0x01 - unsigned int flags2; -#define FLAGS2_MASK_RA 0x80 -#define FLAGS2_MASK_Z 0x70 -#define FLAGS2_MASK_RCODE 0x0f - unsigned int qdcount; - unsigned int ancount; - unsigned int nscount; - unsigned int arcount; - unsigned char payload[512]; /* DNS question, populated by dns_build_query_payload() */ +class s_connection +{ + public: + unsigned char id[2]; + unsigned char res[512]; + unsigned int _class; + QueryType type; + + s_connection() + { + *res = 0; + } + + unsigned char* result_ready(s_header &h, int length); + int send_requests(const s_header *h, const int l, QueryType qt); }; -extern time_t TIME; -void *dns_align(void *inp) { + +void *dns_align(void *inp) +{ char *p = (char*)inp; - int offby = ((char *)p - (char *)0) % DNS_ALIGN; + int offby = ((char *)p - (char *)0) % (sizeof(void *) > sizeof(long) ? sizeof(void *) : sizeof(long)); if (offby != 0) - return p + (DNS_ALIGN - offby); + return p + ((sizeof(void *) > sizeof(long) ? sizeof(void *) : sizeof(long)) - offby); else return p; } /* - * These little hacks are here to avoid alignment and type sizing issues completely by doing manual copies + * Optimized by brain, these were using integer division and modulus. + * We can use logic shifts and logic AND to replace these even divisions + * and multiplications, it should be a bit faster (probably not noticably, + * but of course, more impressive). Also made these inline. */ -void dns_fill_rr(s_rr_middle* rr, const unsigned char *input) { - rr->type = input[0] * 256 + input[1]; - rr->_class = input[2] * 256 + input[3]; - rr->ttl = input[4] * 16777216 + input[5] * 65536 + input[6] * 256 + input[7]; - rr->rdlength = input[8] * 256 + input[9]; + +inline void dns_fill_rr(s_rr_middle* rr, const unsigned char *input) +{ + rr->type = (QueryType)((input[0] << 8) + input[1]); + rr->_class = (input[2] << 8) + input[3]; + rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7]; + rr->rdlength = (input[8] << 8) + input[9]; } -void dns_fill_header(s_header *header, const unsigned char *input, const int l) { +inline void dns_fill_header(s_header *header, const unsigned char *input, const int l) +{ header->id[0] = input[0]; header->id[1] = input[1]; header->flags1 = input[2]; header->flags2 = input[3]; - header->qdcount = input[4] * 256 + input[5]; - header->ancount = input[6] * 256 + input[7]; - header->nscount = input[8] * 256 + input[9]; - header->arcount = input[10] * 256 + input[11]; + header->qdcount = (input[4] << 8) + input[5]; + header->ancount = (input[6] << 8) + input[7]; + header->nscount = (input[8] << 8) + input[9]; + header->arcount = (input[10] << 8) + input[11]; memcpy(header->payload,&input[12],l); } -void dns_empty_header(unsigned char *output, const s_header *header, const int l) { +inline void dns_empty_header(unsigned char *output, const s_header *header, const int l) +{ output[0] = header->id[0]; output[1] = header->id[1]; output[2] = header->flags1; output[3] = header->flags2; - output[4] = header->qdcount / 256; - output[5] = header->qdcount % 256; - output[6] = header->ancount / 256; - output[7] = header->ancount % 256; - output[8] = header->nscount / 256; - output[9] = header->nscount % 256; - output[10] = header->arcount / 256; - output[11] = header->arcount % 256; + output[4] = header->qdcount >> 8; + output[5] = header->qdcount & 0xFF; + output[6] = header->ancount >> 8; + output[7] = header->ancount & 0xFF; + output[8] = header->nscount >> 8; + output[9] = header->nscount & 0xFF; + output[10] = header->arcount >> 8; + output[11] = header->arcount & 0xFF; memcpy(&output[12],header->payload,l); } -void dns_close(int fd) { /* close query */ - if (fd == lastcreate) { - wantclose = 1; - return; - } - close(fd); - return; -} - -void DNS::dns_init() { /* on first call only: populates servers4 struct with up to DNS_MAX nameserver IP addresses from /etc/resolv.conf */ - FILE *f; - int i; - in_addr addr4; - char buf[1024]; - if (initdone == 1) - return; - i4 = 0; - - initdone = 1; - srand((unsigned int) TIME); - memset(servers4,'\0',sizeof(in_addr) * DNS_MAX); - f = fopen(DNS_CONFIG_FBCK,"r"); - if (f == NULL) - return; - while (fgets(buf,1024,f) != NULL) { - if (strncmp(buf,"nameserver",10) == 0) { - i = 10; - while (buf[i] == ' ' || buf[i] == '\t') - i++; - if (i4 < DNS_MAX) { - if (dns_aton4_s(&buf[i],&addr4) != NULL) - memcpy(&servers4[i4++],&addr4,sizeof(in_addr)); - } - } - } - fclose(f); -} - -void DNS::dns_init_2(const char* dnsserver) { /* populates servers4 struct with address from the given parameter */ - FILE *f; - int i; - in_addr addr4; - char buf[1024]; - i4 = 0; - srand((unsigned int) TIME); - memset(servers4,'\0',sizeof(in_addr) * DNS_MAX); - if (dns_aton4_s(dnsserver,&addr4) != NULL) - memcpy(&servers4[i4++],&addr4,sizeof(in_addr)); -} - -static int dns_send_requests(const s_header *h, const s_connection *s, const int l) { /* send DNS query */ - int i; - sockaddr_in addr4; +int s_connection::send_requests(const s_header *h, const int l, QueryType qt) +{ + insp_sockaddr addr; unsigned char payload[sizeof(s_header)]; + this->_class = 1; + this->type = qt; + dns_empty_header(payload,h,l); - - for (i = 0; i < i4; i++) { - /* otherwise send via standard ipv4 boringness */ - memset(&addr4,0,sizeof(addr4)); - memcpy(&addr4.sin_addr,&servers4[i],sizeof(addr4.sin_addr)); - addr4.sin_family = AF_INET; - addr4.sin_port = htons(DNS_PORT); - if (sendto(s->fd, payload, l + 12, 0, (sockaddr *) &addr4, sizeof(addr4)) == -1) - { - return -1; - } + memset(&addr,0,sizeof(addr)); +#ifdef IPV6 + memcpy(&addr.sin6_addr,&myserver,sizeof(addr.sin6_addr)); + addr.sin6_family = AF_FAMILY; + addr.sin6_port = htons(53); +#else + memcpy(&addr.sin_addr.s_addr,&myserver,sizeof(addr.sin_addr)); + addr.sin_family = AF_FAMILY; + addr.sin_port = htons(53); +#endif + if (sendto(master_socket, payload, l + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1) + { + log(DEBUG,"Error in sendto!"); + return -1; } return 0; } -static s_connection *dns_add_query(s_header *h) { /* build DNS query, add to list */ - s_connection * s; +s_connection* dns_add_query(s_header *h, int &id) +{ - s = new s_connection; + id = rand() % 65536; + s_connection * s = new s_connection(); - /* set header flags */ - h->id[0] = s->id[0] = rand() % 255; /* verified by dns_getresult_s() */ - h->id[1] = s->id[1] = rand() % 255; + h->id[0] = s->id[0] = id >> 8; + h->id[1] = s->id[1] = id & 0xFF; h->flags1 = 0 | FLAGS1_MASK_RD; h->flags2 = 0; h->qdcount = 1; @@ -233,54 +215,76 @@ static s_connection *dns_add_query(s_header *h) { /* build DNS query, add to lis h->nscount = 0; h->arcount = 0; - /* turn off want_list by default */ - s->want_list = 0; + if (connections.find(id) == connections.end()) + connections[id] = s; + return s; +} - /* try to create ipv6 or ipv4 socket */ - s->fd = socket(PF_INET, SOCK_DGRAM, 0); - if (s->fd != -1) { - if (fcntl(s->fd, F_SETFL, O_NONBLOCK) != 0) { - close(s->fd); - s->fd = -1; - } - } - if (s->fd != -1) { - sockaddr_in addr; - memset(&addr,0,sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = 0; - addr.sin_addr.s_addr = INADDR_ANY; - if (bind(s->fd,(sockaddr *)&addr,sizeof(addr)) != 0) { - close(s->fd); - s->fd = -1; - } +void create_socket() +{ + log(DEBUG,"---- BEGIN DNS INITIALIZATION, SERVER=%s ---",Config->DNSServer); + insp_inaddr addr; + srand((unsigned int) TIME); + memset(&myserver,0,sizeof(insp_inaddr)); + if (insp_aton(Config->DNSServer,&addr) > 0) + memcpy(&myserver,&addr,sizeof(insp_inaddr)); + + master_socket = socket(PF_PROTOCOL, SOCK_DGRAM, 0); + if (master_socket != -1) + { + log(DEBUG,"Set query socket nonblock"); + if (fcntl(master_socket, F_SETFL, O_NONBLOCK) != 0) + { + shutdown(master_socket,2); + close(master_socket); + master_socket = -1; } - if (s->fd == -1) { - delete s; - return NULL; + } + if (master_socket != -1) + { +#ifdef IPV6 + insp_sockaddr addr; + memset(&addr,0,sizeof(addr)); + addr.sin6_family = AF_FAMILY; + addr.sin6_port = 0; + memset(&addr.sin6_addr,255,sizeof(in6_addr)); +#else + insp_sockaddr addr; + memset(&addr,0,sizeof(addr)); + addr.sin_family = AF_FAMILY; + addr.sin_port = 0; + addr.sin_addr.s_addr = INADDR_ANY; +#endif + log(DEBUG,"Binding query port"); + if (bind(master_socket,(sockaddr *)&addr,sizeof(addr)) != 0) + { + log(DEBUG,"Cant bind with source port = 0"); + shutdown(master_socket,2); + close(master_socket); + master_socket = -1; } - /* create new connection object, add to linked list */ - s->next = connection_head; - connection_head = s; - if (wantclose == 1) { - close(lastcreate); - wantclose = 0; + if (master_socket >= 0) + { + log(DEBUG,"Attach query port to socket engine"); + if (ServerInstance && ServerInstance->SE) + ServerInstance->SE->AddFd(master_socket,true,X_ESTAB_DNS); + } } - lastcreate = s->fd; - return s; } -static int dns_build_query_payload(const char * const name, const unsigned short rr, const unsigned short _class, unsigned char * const payload) { +int dns_build_query_payload(const char * const name, const unsigned short rr, const unsigned short _class, unsigned char * const payload) +{ short payloadpos; const char * tempchr, * tempchr2; unsigned short l; - + payloadpos = 0; tempchr2 = name; /* split name up into labels, create query */ - while ((tempchr = strchr(tempchr2,'.')) != NULL) { + while ((tempchr = strchr(tempchr2,'.')) != NULL) + { l = tempchr - tempchr2; if (payloadpos + l + 1 > 507) return -1; @@ -290,7 +294,8 @@ static int dns_build_query_payload(const char * const name, const unsigned short tempchr2 = &tempchr[1]; } l = strlen(tempchr2); - if (l) { + if (l) + { if (payloadpos + l + 2 > 507) return -1; payload[payloadpos++] = l; @@ -307,426 +312,380 @@ static int dns_build_query_payload(const char * const name, const unsigned short return payloadpos + 4; } -in_addr* DNS::dns_aton4(const char * const ipstring) { /* ascii to numeric: convert string to static 4part IP addr struct */ - in_addr ip; - return dns_aton4_s(ipstring,&ip); -} - -in_addr* DNS::dns_aton4_r(const char *ipstring) { /* ascii to numeric (reentrant): convert string to new 4part IP addr struct */ - in_addr* ip; - ip = new in_addr; - if(dns_aton4_s(ipstring,ip) == NULL) { - delete ip; - return NULL; - } - return ip; -} - -in_addr* DNS::dns_aton4_s(const char *ipstring, in_addr *ip) { /* ascii to numeric (buffered): convert string to given 4part IP addr struct */ - unsigned char *myip; - int i,part = 0; - myip = (unsigned char *)ip; - - memset(myip,'\0',4); - for (i = 0; i < 16; i++) { - switch (ipstring[i]) { - case '\0': - if (part != 3) - return NULL; - return ip; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (myip[part] > 25) - return NULL; - myip[part] *= 10; - if (myip[part] == 250 && ipstring[i] - '0' > 6) - return NULL; - myip[part] += ipstring[i] - '0'; - break; - case '.': - if (part == 3) - return ip; - else - part++; - break; - default: - if (part == 3) - return ip; - else - return NULL; - break; - } - } - if (part == 3) - return ip; - else - return NULL; -} - -int DNS::dns_getip4(const char *name) { /* build, add and send A query; retrieve result with dns_getresult() */ +int DNS::dns_getip4(const char *name) +{ + /* build, add and send A query; retrieve result with dns_getresult() */ s_header h; - s_connection *s; - int l; - - dns_init(); + s_connection* req; + int id; - - l = dns_build_query_payload(name,DNS_QRY_A,1,(unsigned char *)&h.payload); - if (l == -1) + int length = dns_build_query_payload(name,DNS_QRY_A,1,(unsigned char*)&h.payload); + if (length == -1) return -1; - s = dns_add_query(&h); - if (s == NULL) + req = dns_add_query(&h, id); + if (req == NULL) return -1; - s->_class = 1; - s->type = DNS_QRY_A; - if (dns_send_requests(&h,s,l) == -1) - return -1; - - return s->fd; -} -int DNS::dns_getip4list(const char *name) { /* build, add and send A query; retrieve result with dns_getresult() */ - s_header h; - s_connection *s; - int l; - - dns_init(); - - - l = dns_build_query_payload(name,DNS_QRY_A,1,(unsigned char *)&h.payload); - if (l == -1) - return -1; - s = dns_add_query(&h); - if (s == NULL) - return -1; - s->_class = 1; - s->type = DNS_QRY_A; - s->want_list = 1; - if (dns_send_requests(&h,s,l) == -1) + if (req->send_requests(&h,length,DNS_QRY_A) == -1) return -1; - return s->fd; + return id; } -int DNS::dns_getname4(const in_addr *ip) { /* build, add and send PTR query; retrieve result with dns_getresult() */ +int DNS::dns_getname4(const insp_inaddr *ip) +{ /* build, add and send PTR query; retrieve result with dns_getresult() */ +#ifdef IPV6 + return -1; +#else + log(DEBUG,"DNS::dns_getname4"); char query[512]; s_header h; - s_connection * s; + s_connection* req; unsigned char *c; - int l; - - dns_init(); + int id; c = (unsigned char *)&ip->s_addr; sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]); - l = dns_build_query_payload(query,DNS_QRY_PTR,1,(unsigned char *)&h.payload); - if (l == -1) + int length = dns_build_query_payload(query,DNS_QRY_PTR,1,(unsigned char*)&h.payload); + if (length == -1) return -1; - s = dns_add_query(&h); - if (s == NULL) + req = dns_add_query(&h, id); + if (req == NULL) return -1; - s->_class = 1; - s->type = DNS_QRY_PTR; - if (dns_send_requests(&h,s,l) == -1) + if (req->send_requests(&h,length,DNS_QRY_PTR) == -1) return -1; - return s->fd; + return id; +#endif } -char* DNS::dns_ntoa4(const in_addr * const ip) { /* numeric to ascii: convert 4part IP addr struct to static string */ - static char result[256]; - return dns_ntoa4_s(ip,result); -} +/* Return the next id which is ready, and the result attached to it + */ +DNSResult DNS::dns_getresult() +{ + /* retrieve result of DNS query (buffered) */ + s_header h; + s_connection *c; + int length; + unsigned char buffer[sizeof(s_header)]; -char* DNS::dns_ntoa4_r(const in_addr *ip) { /* numeric to ascii (reentrant): convert 4part IP addr struct to new string */ - char *result; - result = new char[256]; - return dns_ntoa4_s(ip,result); -} + length = recv(master_socket,buffer,sizeof(s_header),0); -char* DNS::dns_ntoa4_s(const in_addr *ip, char *result) { /* numeric to ascii (buffered): convert 4part IP addr struct to given string */ - unsigned char *m; - m = (unsigned char *)&ip->s_addr; - sprintf(result,"%d.%d.%d.%d",m[0],m[1],m[2],m[3]); - return result; -} + if (length < 12) + return std::make_pair(-1,""); -char* DNS::dns_getresult(const int fd) { /* retrieve result of DNS query */ - static char result[RESULTSIZE]; - return dns_getresult_s(fd,result); -} + dns_fill_header(&h,buffer,length - 12); -char* DNS::dns_getresult_r(const int fd) { /* retrieve result of DNS query (reentrant) */ - char *result; - result = new char[RESULTSIZE]; - if(dns_getresult_s(fd,result) == NULL) { - delete result; - return NULL; - } - return result; -} + // Get the id of this request + unsigned long this_id = h.id[1] + (h.id[0] << 8); -char* DNS::dns_getresult_s(const int fd, char *result) { /* retrieve result of DNS query (buffered) */ - s_header h; - s_connection *c, *prev; - int l,i,q,curanswer,o; - s_rr_middle rr; - unsigned char buffer[sizeof(s_header)]; - unsigned short p; + // Do we have a pending request for it? - if (result) - { - result[0] = 0; - } + connlist_iter n_iter = connections.find(this_id); + if (n_iter == connections.end()) + { + log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",master_socket,this_id); + return std::make_pair(-1,""); + } + else + { + /* Remove the query from the list */ + c = (s_connection*)n_iter->second; + /* We don't delete c here, because its done later when needed */ + connections.erase(n_iter); + } + unsigned char* a = c->result_ready(h, length); + std::string resultstr; - prev = NULL; - c = connection_head; - while (c != NULL) { /* find query in list of open queries */ - if (c->fd == fd) - break; - prev = c; - c = c->next; - } - if (c == NULL) { - return NULL; /* query not found */ + if (a == NULL) + { + resultstr = ""; } - /* query found-- pull from list: */ - if (prev != NULL) - prev->next = c->next; else - connection_head = c->next; - - l = recv(c->fd,buffer,sizeof(s_header),0); - dns_close(c->fd); - if (l < 12) { - delete c; - return NULL; - } - dns_fill_header(&h,buffer,l - 12); - if (c->id[0] != h.id[0] || c->id[1] != h.id[1]) { - delete c; - return NULL; /* ID mismatch */ + { + if (c->type == DNS_QRY_A) + { + char formatted[1024]; + snprintf(formatted,1024,"%u.%u.%u.%u",a[0],a[1],a[2],a[3]); + resultstr = std::string(formatted); + } + else + { + resultstr = std::string((const char*)a); + } } - if ((h.flags1 & FLAGS1_MASK_QR) == 0) { - delete c; + + delete c; + return std::make_pair(this_id,resultstr); +} + +/** A result is ready, process it + */ +unsigned char* s_connection::result_ready(s_header &h, int length) +{ + int i, q, curanswer, o; + s_rr_middle rr; + unsigned short p; + + if ((h.flags1 & FLAGS1_MASK_QR) == 0) + { + log(DEBUG,"DNS: didnt get a query result"); return NULL; } - if ((h.flags1 & FLAGS1_MASK_OPCODE) != 0) { - delete c; + if ((h.flags1 & FLAGS1_MASK_OPCODE) != 0) + { + log(DEBUG,"DNS: got an OPCODE and didnt want one"); return NULL; } - if ((h.flags2 & FLAGS2_MASK_RCODE) != 0) { - delete c; + if ((h.flags2 & FLAGS2_MASK_RCODE) != 0) + { + log(DEBUG,"DNS lookup failed due to SERVFAIL"); return NULL; } - if (h.ancount < 1) { /* no sense going on if we don't have any answers */ - delete c; + if (h.ancount < 1) + { + log(DEBUG,"DNS: no answers!"); return NULL; } - /* skip queries */ i = 0; q = 0; - l -= 12; - while (q < h.qdcount && i < l) { - if (h.payload[i] > 63) { /* pointer */ - i += 6; /* skip pointer, _class and type */ + length -= 12; + while ((unsigned)q < h.qdcount && i < length) + { + if (h.payload[i] > 63) + { + i += 6; q++; - } else { /* label */ - if (h.payload[i] == 0) { + } + else + { + if (h.payload[i] == 0) + { q++; - i += 5; /* skip nil, _class and type */ - } else - i += h.payload[i] + 1; /* skip length and label */ + i += 5; + } + else i += h.payload[i] + 1; } } - /* &h.payload[i] should now be the start of the first response */ curanswer = 0; - while (curanswer < h.ancount) { + while ((unsigned)curanswer < h.ancount) + { q = 0; - while (q == 0 && i < l) { - if (h.payload[i] > 63) { /* pointer */ - i += 2; /* skip pointer */ + while (q == 0 && i < length) + { + if (h.payload[i] > 63) + { + i += 2; q = 1; - } else { /* label */ - if (h.payload[i] == 0) { + } + else + { + if (h.payload[i] == 0) + { i++; q = 1; - } else - i += h.payload[i] + 1; /* skip length and label */ + } + else i += h.payload[i] + 1; /* skip length and label */ } } - if (l - i < 10) { - delete c; + if (length - i < 10) + { return NULL; } dns_fill_rr(&rr,&h.payload[i]); i += 10; - if (rr.type != c->type) { + if (rr.type != this->type) + { curanswer++; i += rr.rdlength; continue; } - if (rr._class != c->_class) { + if (rr._class != this->_class) + { curanswer++; i += rr.rdlength; continue; } break; } - if (curanswer == h.ancount) + if ((unsigned int)curanswer == h.ancount) return NULL; - if (i + rr.rdlength > l) + if (i + rr.rdlength > (unsigned int)length) return NULL; if (rr.rdlength > 1023) return NULL; - switch (rr.type) { + switch (rr.type) + { case DNS_QRY_PTR: + log(DEBUG,"DNS: got a result of type DNS_QRY_PTR"); o = 0; q = 0; - while (q == 0 && i < l && o + 256 < 1023) { - if (h.payload[i] > 63) { /* pointer */ + while (q == 0 && i < length && o + 256 < 1023) + { + if (h.payload[i] > 63) + { + log(DEBUG,"DNS: h.payload[i] > 63"); memcpy(&p,&h.payload[i],2); - i = ntohs(p) - DNS_POINTER_VALUE - 12; - } else { /* label */ + i = ntohs(p) - 0xC000 - 12; + } + else + { if (h.payload[i] == 0) + { q = 1; - else { - result[o] = '\0'; + } + else + { + res[o] = '\0'; if (o != 0) - result[o++] = '.'; - memcpy(&result[o],&h.payload[i + 1],h.payload[i]); + res[o++] = '.'; + memcpy(&res[o],&h.payload[i + 1],h.payload[i]); o += h.payload[i]; i += h.payload[i] + 1; } } } - result[o] = '\0'; - break; + res[o] = '\0'; + break; case DNS_QRY_A: - if (c->want_list) { - dns_ip4list *alist = (dns_ip4list *) result; /* we have to trust that this is aligned */ - while ((char *)alist - (char *)result < 700) { - if (rr.type != DNS_QRY_A) - break; - if (rr._class != 1) - break; - if (rr.rdlength != 4) { - delete c; - return NULL; - } - memcpy(&alist->ip,&h.payload[i],4); - if (++curanswer >= h.ancount) - break; - i += rr.rdlength; - { - /* skip next name */ - q = 0; - while (q == 0 && i < l) { - if (h.payload[i] > 63) { /* pointer */ - i += 2; /* skip pointer */ - q = 1; - } else { /* label */ - if (h.payload[i] == 0) { - i++; - q = 1; - } else - i += h.payload[i] + 1; /* skip length and label */ - } - } - } - if (l - i < 10) { - delete c; - return NULL; - } - dns_fill_rr(&rr,&h.payload[i]); - i += 10; - alist->next = (dns_ip4list *) dns_align(((char *) alist) + sizeof(dns_ip4list)); - alist = alist->next; - alist->next = NULL; - } - alist->next = NULL; - break; - } - goto defaultcase; + log(DEBUG,"DNS: got a result of type DNS_QRY_A"); + memcpy(res,&h.payload[i],rr.rdlength); + res[rr.rdlength] = '\0'; break; default: - defaultcase: - memcpy(result,&h.payload[i],rr.rdlength); - result[rr.rdlength] = '\0'; + memcpy(res,&h.payload[i],rr.rdlength); + res[rr.rdlength] = '\0'; break; } - delete c; - return result; + return res; } DNS::DNS() { - dns_init(); + log(DEBUG,"Create blank DNS"); } -DNS::DNS(std::string dnsserver) +DNS::~DNS() { - dns_init_2(dnsserver.c_str()); } -void DNS::SetNS(std::string dnsserver) +Resolver::Resolver(const std::string &source, bool forward) : input(source), fwd(forward) { - dns_init_2(dnsserver.c_str()); + if (forward) + { + log(DEBUG,"Resolver: Forward lookup on %s",source.c_str()); + this->myid = Res->dns_getip4(source.c_str()); + } + else + { + log(DEBUG,"Resolver: Reverse lookup on %s",source.c_str()); + insp_inaddr binip; + if (insp_aton(source.c_str(), &binip) > 0) + { + /* Valid ip address */ + this->myid = Res->dns_getname4(&binip); + } + } + if (this->myid == -1) + { + log(DEBUG,"Resolver::Resolver: Could not get an id!"); + this->OnError(RESOLVER_NSDOWN); + throw ModuleException("Resolver: Couldnt get an id to make a request"); + /* We shouldnt get here really */ + return; + } + + log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid); } -DNS::~DNS() +void Resolver::OnLookupComplete(const std::string &result) { } -bool DNS::ReverseLookup(std::string ip) +void Resolver::OnError(ResolverError e) { - binip = dns_aton4(ip.c_str()); - if (binip == NULL) { - return false; - } - this->fd = dns_getname4(binip); - if (this->fd == -1) - return false; - return true; } -bool DNS::ForwardLookup(std::string host) +Resolver::~Resolver() +{ + log(DEBUG,"Resolver::~Resolver"); +} + +int Resolver::GetId() { + return this->myid; } -bool DNS::HasResult() +bool Resolver::ProcessResult(const std::string &result) { - pollfd polls; - polls.fd = this->fd; - polls.events = POLLIN; - int ret = poll(&polls,1,1); - return (ret > 0); + log(DEBUG,"Resolver::ProcessResult"); + + if (!result.length()) + { + log(DEBUG,"Resolver::OnError(RESOLVER_NXDOMAIN)"); + this->OnError(RESOLVER_NXDOMAIN); + return false; + } + else + { + + log(DEBUG,"Resolver::OnLookupComplete(%s)",result.c_str()); + this->OnLookupComplete(result); + return true; + } } -int DNS::GetFD() +void dns_deal_with_classes(int fd) { - return this->fd; + log(DEBUG,"dns_deal_with_classes(%d)",fd); + if (fd == master_socket) + { + DNSResult res = Res->dns_getresult(); + if (res.first != -1) + { + log(DEBUG,"Result available, id=%d",res.first); + if (dns_classes[res.first]) + { + dns_classes[res.first]->ProcessResult(res.second); + delete dns_classes[res.first]; + dns_classes[res.first] = NULL; + } + } + } } -std::string DNS::GetResult() +bool dns_add_class(Resolver* r) { - result = dns_getresult(this->fd); - if (result) { - dns_close(this->fd); - return result; - } else { - return ""; + log(DEBUG,"dns_add_class"); + if ((r) && (r->GetId() > -1)) + { + if (!dns_classes[r->GetId()]) + { + log(DEBUG,"dns_add_class: added class"); + dns_classes[r->GetId()] = r; + return true; + } + else + { + log(DEBUG,"Space occupied!"); + return false; + } } + else + { + log(DEBUG,"Bad class"); + delete r; + return true; + } +} + +void init_dns() +{ + Res = new DNS(); + memset(dns_classes,0,sizeof(dns_classes)); + create_socket(); } +