X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fdns.cpp;h=efb690dc248cd90f6eb0860c298d25b8ee6e7e4c;hb=1f1258997c2d63eb54c5addece622af37f637a7b;hp=a1287e49937ab8078b7b702e360e4e9f6108564e;hpb=b7f823b059aa6f8133abf0a0d1895983ccd04590;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/dns.cpp b/src/dns.cpp index a1287e499..efb690dc2 100644 --- a/src/dns.cpp +++ b/src/dns.cpp @@ -1,5 +1,5 @@ /* -dns.cpp - based on the dns library Copyright (C) 2002 Ian Gulliver +dns.cpp - based on the firedns 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 @@ -17,6 +17,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define _DNS_C +using namespace std; + #include #include #include @@ -29,9 +31,17 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include +#include +#include +#include +#include #include "dns.h" +#include "inspircd.h" +#include "helperfuncs.h" +#include "socketengine.h" -static const char tagstring[] = "$Id$"; +extern InspIRCd* ServerInstance; +extern ServerConfig* Config; #define max(a,b) (a > b ? a : b) #define DNS_MAX 8 /* max number of nameservers used */ @@ -95,6 +105,8 @@ struct s_header { /* DNS query header */ unsigned char payload[512]; /* DNS question, populated by dns_build_query_payload() */ }; +extern time_t TIME; + void *dns_align(void *inp) { char *p = (char*)inp; int offby = ((char *)p - (char *)0) % DNS_ALIGN; @@ -143,10 +155,12 @@ void dns_empty_header(unsigned char *output, const s_header *header, const int l } void dns_close(int fd) { /* close query */ + log(DEBUG,"DNS: dns_close on fd %d",fd); if (fd == lastcreate) { wantclose = 1; return; } + shutdown(fd,2); close(fd); return; } @@ -161,7 +175,7 @@ void DNS::dns_init() { /* on first call only: populates servers4 struct with up i4 = 0; initdone = 1; - srand((unsigned int) time(NULL)); + srand((unsigned int) TIME); memset(servers4,'\0',sizeof(in_addr) * DNS_MAX); f = fopen(DNS_CONFIG_FBCK,"r"); if (f == NULL) @@ -178,27 +192,21 @@ void DNS::dns_init() { /* on first call only: populates servers4 struct with up } } fclose(f); - } -void DNS::dns_init_2(const char* dnsserver) { /* populates servers4 struct with address from the given parameter */ - FILE *f; - int i; +void DNS::dns_init_2(const char* dnsserver) +{ in_addr addr4; - char buf[1024]; - if (initdone == 1) - return; i4 = 0; - - initdone = 1; - srand((unsigned int) time(NULL)); + 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 */ +static int dns_send_requests(const s_header *h, const s_connection *s, const int l) +{ int i; sockaddr_in addr4; unsigned char payload[sizeof(s_header)]; @@ -206,13 +214,16 @@ static int dns_send_requests(const s_header *h, const s_connection *s, const int 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); - sendto(s->fd, payload, l + 12, 0, (sockaddr *) &addr4, sizeof(addr4)); + i = 0; + + /* 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; } return 0; @@ -240,6 +251,7 @@ static s_connection *dns_add_query(s_header *h) { /* build DNS query, add to lis s->fd = socket(PF_INET, SOCK_DGRAM, 0); if (s->fd != -1) { if (fcntl(s->fd, F_SETFL, O_NONBLOCK) != 0) { + shutdown(s->fd,2); close(s->fd); s->fd = -1; } @@ -251,6 +263,7 @@ static s_connection *dns_add_query(s_header *h) { /* build DNS query, add to lis addr.sin_port = 0; addr.sin_addr.s_addr = INADDR_ANY; if (bind(s->fd,(sockaddr *)&addr,sizeof(addr)) != 0) { + shutdown(s->fd,2); close(s->fd); s->fd = -1; } @@ -264,6 +277,7 @@ static s_connection *dns_add_query(s_header *h) { /* build DNS query, add to lis connection_head = s; if (wantclose == 1) { + shutdown(lastcreate,2); close(lastcreate); wantclose = 0; } @@ -275,7 +289,7 @@ static int dns_build_query_payload(const char * const name, const unsigned short short payloadpos; const char * tempchr, * tempchr2; unsigned short l; - + payloadpos = 0; tempchr2 = name; @@ -308,7 +322,7 @@ static int dns_build_query_payload(const char * const name, const unsigned short } in_addr* DNS::dns_aton4(const char * const ipstring) { /* ascii to numeric: convert string to static 4part IP addr struct */ - in_addr ip; + static in_addr ip; return dns_aton4_s(ipstring,&ip); } @@ -323,53 +337,8 @@ in_addr* DNS::dns_aton4_r(const char *ipstring) { /* ascii to numeric (reentrant } 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; + inet_aton(ipstring,ip); + return ip; } int DNS::dns_getip4(const char *name) { /* build, add and send A query; retrieve result with dns_getresult() */ @@ -424,8 +393,6 @@ int DNS::dns_getname4(const in_addr *ip) { /* build, add and send PTR query; ret unsigned char *c; int l; - dns_init(); - c = (unsigned char *)&ip->s_addr; sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]); @@ -445,39 +412,23 @@ int DNS::dns_getname4(const in_addr *ip) { /* build, add and send PTR query; ret } 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); -} - -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); + static char r[256]; + return dns_ntoa4_s(ip,r); } -char* DNS::dns_ntoa4_s(const in_addr *ip, char *result) { /* numeric to ascii (buffered): convert 4part IP addr struct to given string */ +char* DNS::dns_ntoa4_s(const in_addr *ip, char *r) { /* 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; -} - -char* DNS::dns_getresult(const int fd) { /* retrieve result of DNS query */ - static char result[RESULTSIZE]; - return dns_getresult_s(fd,result); + sprintf(r,"%d.%d.%d.%d",m[0],m[1],m[2],m[3]); + return r; } -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; +char* DNS::dns_getresult(const int cfd) { /* retrieve result of DNS query */ + log(DEBUG,"DNS: dns_getresult with cfd=%d",cfd); + return dns_getresult_s(cfd,this->localbuf); } -char* DNS::dns_getresult_s(const int fd, char *result) { /* retrieve result of DNS query (buffered) */ +char* DNS::dns_getresult_s(const int cfd, char *res) { /* retrieve result of DNS query (buffered) */ s_header h; s_connection *c, *prev; int l,i,q,curanswer,o; @@ -485,20 +436,21 @@ char* DNS::dns_getresult_s(const int fd, char *result) { /* retrieve result of D unsigned char buffer[sizeof(s_header)]; unsigned short p; - if (result) + if (res) { - result[0] = 0; + res[0] = 0; } prev = NULL; c = connection_head; while (c != NULL) { /* find query in list of open queries */ - if (c->fd == fd) + if (c->fd == cfd) break; prev = c; c = c->next; } if (c == NULL) { + log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d",cfd); return NULL; /* query not found */ } /* query found-- pull from list: */ @@ -515,22 +467,27 @@ char* DNS::dns_getresult_s(const int fd, char *result) { /* retrieve result of D } dns_fill_header(&h,buffer,l - 12); if (c->id[0] != h.id[0] || c->id[1] != h.id[1]) { + log(DEBUG,"DNS: id mismatch on query"); delete c; return NULL; /* ID mismatch */ } if ((h.flags1 & FLAGS1_MASK_QR) == 0) { + log(DEBUG,"DNS: didnt get a query result"); delete c; return NULL; } if ((h.flags1 & FLAGS1_MASK_OPCODE) != 0) { + log(DEBUG,"DNS: got an OPCODE and didnt want one"); delete c; return NULL; } if ((h.flags2 & FLAGS2_MASK_RCODE) != 0) { + log(DEBUG,"DNS lookup failed due to SERVFAIL"); delete c; return NULL; } if (h.ancount < 1) { /* no sense going on if we don't have any answers */ + log(DEBUG,"DNS: no answers!"); delete c; return NULL; } @@ -538,7 +495,7 @@ char* DNS::dns_getresult_s(const int fd, char *result) { /* retrieve result of D i = 0; q = 0; l -= 12; - while (q < h.qdcount && i < l) { + while ((unsigned)q < h.qdcount && i < l) { if (h.payload[i] > 63) { /* pointer */ i += 6; /* skip pointer, _class and type */ q++; @@ -552,7 +509,7 @@ char* DNS::dns_getresult_s(const int fd, char *result) { /* retrieve result of D } /* &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 */ @@ -584,15 +541,16 @@ char* DNS::dns_getresult_s(const int fd, char *result) { /* retrieve result of D } break; } - if (curanswer == h.ancount) + if ((unsigned)curanswer == h.ancount) return NULL; - if (i + rr.rdlength > l) + if ((unsigned)i + rr.rdlength > (unsigned)l) return NULL; if (rr.rdlength > 1023) return NULL; 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) { @@ -603,21 +561,22 @@ char* DNS::dns_getresult_s(const int fd, char *result) { /* retrieve result of D if (h.payload[i] == 0) q = 1; else { - result[o] = '\0'; + 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'; + res[o] = '\0'; break; case DNS_QRY_A: + log(DEBUG,"DNS: got a result of type 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) { + dns_ip4list *alist = (dns_ip4list *) res; /* we have to trust that this is aligned */ + while ((char *)alist - (char *)res < 700) { if (rr.type != DNS_QRY_A) break; if (rr._class != 1) @@ -627,7 +586,7 @@ char* DNS::dns_getresult_s(const int fd, char *result) { /* retrieve result of D return NULL; } memcpy(&alist->ip,&h.payload[i],4); - if (++curanswer >= h.ancount) + if ((unsigned)++curanswer >= h.ancount) break; i += rr.rdlength; { @@ -663,22 +622,31 @@ char* DNS::dns_getresult_s(const int fd, char *result) { /* retrieve result of D break; default: defaultcase: - memcpy(result,&h.payload[i],rr.rdlength); - result[rr.rdlength] = '\0'; + log(DEBUG,"DNS: doing something with result 'default'"); + 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_init_2(dnsserver.c_str()); + log(DEBUG,"Create DNS"); +} + +void DNS::SetNS(std::string dnsserver) +{ + dns_init_2(dnsserver.c_str()); + log(DEBUG,"Set NS"); } DNS::~DNS() @@ -687,38 +655,154 @@ DNS::~DNS() bool DNS::ReverseLookup(std::string ip) { + ServerInstance->stats->statsDns++; binip = dns_aton4(ip.c_str()); if (binip == NULL) { - fprintf(stderr,"invalid IP address.\n"); - return 2; + return false; } - this->fd = dns_getname4(binip); + + this->myfd = dns_getname4(binip); + if (this->myfd == -1) + { + return false; + } + log(DEBUG,"DNS: ReverseLookup, fd=%d",this->myfd); +#ifndef THREADED_DNS + ServerInstance->SE->AddFd(this->myfd,true,X_ESTAB_DNS); +#endif + return true; } bool DNS::ForwardLookup(std::string host) { + ServerInstance->stats->statsDns++; + this->myfd = dns_getip4(host.c_str()); + if (this->myfd == -1) + { + return false; + } + log(DEBUG,"DNS: ForwardLookup, fd=%d",this->myfd); +#ifndef THREADED_DNS + ServerInstance->SE->AddFd(this->myfd,true,X_ESTAB_DNS); +#endif + return true; +} + +bool DNS::HasResult(int fd) +{ + return (fd == this->myfd); } +/* Only the multithreaded dns uses this poll() based + * check now. As its in another thread we dont have + * to worry about its performance that much. + */ bool DNS::HasResult() { + log(DEBUG,"DNS: HasResult, fd=%d",this->myfd); pollfd polls; - polls.fd = this->fd; + polls.fd = this->myfd; polls.events = POLLIN; int ret = poll(&polls,1,1); + log(DEBUG,"DNS: Hasresult returning %d",ret); return (ret > 0); } int DNS::GetFD() { - return this->fd; + return this->myfd; } std::string DNS::GetResult() { - result = dns_getresult(this->fd); + log(DEBUG,"DNS: GetResult()"); + result = dns_getresult(this->myfd); +#ifndef THREADED_DNS + ServerInstance->SE->DelFd(this->myfd); +#endif if (result) { + ServerInstance->stats->statsDnsGood++; + dns_close(this->myfd); return result; } else { + ServerInstance->stats->statsDnsBad++; + if (this->myfd != -1) + { + dns_close(this->myfd); + } + return ""; + } +} + +std::string DNS::GetResultIP() +{ + char r[1024]; + log(DEBUG,"DNS: GetResultIP()"); + result = dns_getresult(this->myfd); + if (this->myfd != -1) + { +#ifndef THREADED_DNS + ServerInstance->SE->DelFd(this->myfd); +#endif + dns_close(this->myfd); + } + if (result) + { + ServerInstance->stats->statsDnsGood++; + unsigned char a = (unsigned)result[0]; + unsigned char b = (unsigned)result[1]; + unsigned char c = (unsigned)result[2]; + unsigned char d = (unsigned)result[3]; + snprintf(r,1024,"%u.%u.%u.%u",a,b,c,d); + return r; + } + else + { + ServerInstance->stats->statsDnsBad++; + log(DEBUG,"DANGER WILL ROBINSON! NXDOMAIN for forward lookup, but we got a reverse lookup!"); return ""; } } + + + +#ifdef THREADED_DNS +void* dns_task(void* arg) +{ + userrec* u = (userrec*)arg; + log(DEBUG,"DNS thread for user %s",u->nick); + DNS dns1; + DNS dns2; + std::string host; + std::string ip; + if (dns1.ReverseLookup(u->ip)) + { + while (!dns1.HasResult()) + { + usleep(100); + } + host = dns1.GetResult(); + if (host != "") + { + if (dns2.ForwardLookup(host)) + { + while (!dns2.HasResult()) + { + usleep(100); + } + ip = dns2.GetResultIP(); + if (ip == std::string(u->ip)) + { + if (host.length() < 160) + { + strcpy(u->host,host.c_str()); + strcpy(u->dhost,host.c_str()); + } + } + } + } + } + u->dns_done = true; + return NULL; +} +#endif