From b7f823b059aa6f8133abf0a0d1895983ccd04590 Mon Sep 17 00:00:00 2001 From: brain Date: Fri, 1 Apr 2005 19:15:55 +0000 Subject: DNS timeout fixes! Docs to come git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@940 e03df62e-2008-0410-955e-edbf42e46eb7 --- src/dns.cpp | 50 +++++++----- src/dnsqueue.cpp | 28 +++++-- src/inspircd.cpp | 239 ++++++++++++++++++++++++++++++++----------------------- 3 files changed, 187 insertions(+), 130 deletions(-) (limited to 'src') diff --git a/src/dns.cpp b/src/dns.cpp index ffde3f2a1..a1287e499 100644 --- a/src/dns.cpp +++ b/src/dns.cpp @@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include +#include #include "dns.h" static const char tagstring[] = "$Id$"; @@ -255,7 +256,7 @@ static s_connection *dns_add_query(s_header *h) { /* build DNS query, add to lis } } if (s->fd == -1) { - free(s); + delete s; return NULL; } /* create new connection object, add to linked list */ @@ -315,7 +316,7 @@ in_addr* DNS::dns_aton4_r(const char *ipstring) { /* ascii to numeric (reentrant in_addr* ip; ip = new in_addr; if(dns_aton4_s(ipstring,ip) == NULL) { - free(ip); + delete ip; return NULL; } return ip; @@ -470,7 +471,7 @@ char* DNS::dns_getresult_r(const int fd) { /* retrieve result of DNS query (reen char *result; result = new char[RESULTSIZE]; if(dns_getresult_s(fd,result) == NULL) { - free(result); + delete result; return NULL; } return result; @@ -484,6 +485,11 @@ 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) + { + result[0] = 0; + } + prev = NULL; c = connection_head; while (c != NULL) { /* find query in list of open queries */ @@ -504,28 +510,28 @@ char* DNS::dns_getresult_s(const int fd, char *result) { /* retrieve result of D l = recv(c->fd,buffer,sizeof(s_header),0); dns_close(c->fd); if (l < 12) { - free(c); + delete c; return NULL; } dns_fill_header(&h,buffer,l - 12); if (c->id[0] != h.id[0] || c->id[1] != h.id[1]) { - free(c); + delete c; return NULL; /* ID mismatch */ } if ((h.flags1 & FLAGS1_MASK_QR) == 0) { - free(c); + delete c; return NULL; } if ((h.flags1 & FLAGS1_MASK_OPCODE) != 0) { - free(c); + delete c; return NULL; } if ((h.flags2 & FLAGS2_MASK_RCODE) != 0) { - free(c); + delete c; return NULL; } if (h.ancount < 1) { /* no sense going on if we don't have any answers */ - free(c); + delete c; return NULL; } /* skip queries */ @@ -561,7 +567,7 @@ char* DNS::dns_getresult_s(const int fd, char *result) { /* retrieve result of D } } if (l - i < 10) { - free(c); + delete c; return NULL; } dns_fill_rr(&rr,&h.payload[i]); @@ -617,7 +623,7 @@ char* DNS::dns_getresult_s(const int fd, char *result) { /* retrieve result of D if (rr._class != 1) break; if (rr.rdlength != 4) { - free(c); + delete c; return NULL; } memcpy(&alist->ip,&h.payload[i],4); @@ -641,7 +647,7 @@ char* DNS::dns_getresult_s(const int fd, char *result) { /* retrieve result of D } } if (l - i < 10) { - free(c); + delete c; return NULL; } dns_fill_rr(&rr,&h.payload[i]); @@ -661,7 +667,7 @@ char* DNS::dns_getresult_s(const int fd, char *result) { /* retrieve result of D result[rr.rdlength] = '\0'; break; } - free(c); + delete c; return result; } @@ -695,14 +701,16 @@ bool DNS::ForwardLookup(std::string host) bool DNS::HasResult() { - fd_set fds; - FD_ZERO(&fds); - FD_SET(this->fd,&fds); - timeval tvs; - tvs.tv_usec = 0; - tvs.tv_sec = 0; - int result = select(this->fd+1, &fds, NULL, NULL, &tvs); - return (result > 0); + pollfd polls; + polls.fd = this->fd; + polls.events = POLLIN; + int ret = poll(&polls,1,1); + return (ret > 0); +} + +int DNS::GetFD() +{ + return this->fd; } std::string DNS::GetResult() diff --git a/src/dnsqueue.cpp b/src/dnsqueue.cpp index ac521f091..4c328e71c 100644 --- a/src/dnsqueue.cpp +++ b/src/dnsqueue.cpp @@ -193,13 +193,26 @@ public: { if (resolver->HasResult()) { - log(DEBUG,"DNS Result available!"); - std::string hostname = resolver->GetResult(); - if (u) + log(DEBUG,"resolver says result available!"); + if (resolver->GetFD() != 0) + { + log(DEBUG,"Resolver FD is not 0"); + std::string hostname = resolver->GetResult(); + if (u) + { + log(DEBUG,"Applying hostname lookup to %s: %s",u->nick,hostname.c_str()); + if (hostname != "") + { + strlcpy(u->host,hostname.c_str(),MAXBUF); + WriteServ(u->fd,"NOTICE Auth :Resolved your hostname: %s",hostname.c_str()); + u->dns_done = true; + return true; + } + return false; + } + } + else { - log(DEBUG,"Applying hostname lookup to %s: %s",u->nick,hostname.c_str()); - if (hostname != "") - strlcpy(u->host,hostname.c_str(),MAXBUF); u->dns_done = true; return true; } @@ -225,6 +238,7 @@ bool lookup_dns(userrec* u) { // place a new user into the queue... log(DEBUG,"Queueing DNS lookup for %s",u->nick); + WriteServ(u->fd,"NOTICE Auth :Looking up your hostname..."); Lookup L(u); dnsq.push_back(L); return true; @@ -235,11 +249,9 @@ void dns_poll() // do we have items in the queue? if (dnsq.size()) { - log(DEBUG,"DNS items pending..."); // are any ready, or stale? if (dnsq[0].Done() || (!dnsq[0].GetFD())) { - // if they are take them out... log(DEBUG,"****** DNS lookup for fd %d is complete. ******",dnsq[0].GetFD()); dnsq.erase(dnsq.begin()); } diff --git a/src/inspircd.cpp b/src/inspircd.cpp index 491c67cd2..989e3e6b7 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -87,6 +87,7 @@ time_t startup_time = time(NULL); int NetBufferSize = 10240; // NetBufferSize used as the buffer size for all read() ops extern int MaxWhoResults; time_t nb_start = 0; +int dns_timeout = 5; bool AllowHalfop = true; bool AllowProtect = true; @@ -97,6 +98,8 @@ std::vector module_names; extern std::vector factory; std::vector fd_reap; +std::vector pending_connects; + extern int MODCOUNT; bool nofork = false; @@ -315,7 +318,7 @@ void readfile(file_cache &F, const char* fname) void ReadConfig(bool bail, userrec* user) { char dbg[MAXBUF],pauseval[MAXBUF],Value[MAXBUF],timeout[MAXBUF],NB[MAXBUF],flood[MAXBUF],MW[MAXBUF]; - char AH[MAXBUF],AP[MAXBUF],AF[MAXBUF]; + char AH[MAXBUF],AP[MAXBUF],AF[MAXBUF],DNT[MAXBUF]; ConnectClass c; std::stringstream errstr; @@ -372,8 +375,14 @@ void ReadConfig(bool bail, userrec* user) ConfValue("options","allowprotect",0,AP,&config_f); ConfValue("options","allowfounder",0,AF,&config_f); ConfValue("dns","server",0,DNSServer,&config_f); + ConfValue("dns","timeout",0,DNT,&config_f); NetBufferSize = atoi(NB); MaxWhoResults = atoi(MW); + dns_timeout = atoi(DNT); + if (!dns_timeout) + dns_timeout = 5; + if (!strcmp(DNSServer,"")) + strlcpy(DNSServer,"127.0.0.1",MAXBUF); AllowHalfop = ((!strcasecmp(AH,"true")) || (!strcasecmp(AH,"1")) || (!strcasecmp(AH,"yes"))); AllowProtect = ((!strcasecmp(AP,"true")) || (!strcasecmp(AP,"1")) || (!strcasecmp(AP,"yes"))); AllowFounder = ((!strcasecmp(AF,"true")) || (!strcasecmp(AF,"1")) || (!strcasecmp(AF,"yes"))); @@ -1110,7 +1119,7 @@ void purge_empty_chans(void) if (i != chanlist.end()) { log(DEBUG,"del_channel: destroyed: %s",i->second->name); - delete i->second; + if (i->second) delete i->second; chanlist.erase(i); go_again = 1; purge++; @@ -1619,7 +1628,7 @@ chanrec* del_channel(userrec *user, const char* cname, const char* reason, bool if (iter != chanlist.end()) { log(DEBUG,"del_channel: destroyed: %s",Ptr->name); - delete iter->second; + if (iter->second) delete iter->second; chanlist.erase(iter); } } @@ -1698,7 +1707,7 @@ void kick_channel(userrec *src,userrec *user, chanrec *Ptr, char* reason) if (iter != chanlist.end()) { log(DEBUG,"del_channel: destroyed: %s",Ptr->name); - delete iter->second; + if (iter->second) delete iter->second; chanlist.erase(iter); } } @@ -1916,7 +1925,7 @@ void kill_link(userrec *user,const char* r) { log(DEBUG,"deleting user hash value %d",iter->second); if ((iter->second) && (user->registered == 7)) { - delete iter->second; + if (iter->second) delete iter->second; } clientlist.erase(iter); } @@ -1966,7 +1975,7 @@ void kill_link_silent(userrec *user,const char* r) { log(DEBUG,"deleting user hash value %d",iter->second); if ((iter->second) && (user->registered == 7)) { - delete iter->second; + if (iter->second) delete iter->second; } clientlist.erase(iter); } @@ -2106,7 +2115,6 @@ userrec* ReHashNick(char* Old, char* New) clientlist[New] = new userrec(); clientlist[New] = oldnick->second; - /*delete oldnick->second; */ clientlist.erase(oldnick); log(DEBUG,"ReHashNick: Nick rehashed as %s",New); @@ -2141,7 +2149,7 @@ void AddWhoWas(userrec* u) // 3600 seconds in an hour ;) if ((i->second->signon)<(time(NULL)-(WHOWAS_STALE*3600))) { - delete i->second; + if (i->second) delete i->second; i->second = a; log(DEBUG,"added WHOWAS entry, purged an old record"); return; @@ -2157,7 +2165,7 @@ void AddWhoWas(userrec* u) else { log(DEBUG,"updated WHOWAS entry"); - delete iter->second; + if (iter->second) delete iter->second; iter->second = a; } } @@ -2205,15 +2213,6 @@ void AddClient(int socket, char* host, int port, bool iscached, char* ip) clientlist[tempnick]->port = port; strncpy(clientlist[tempnick]->ip,ip,32); - if (iscached) - { - WriteServ(socket,"NOTICE Auth :Found your hostname (cached)..."); - } - else - { - WriteServ(socket,"NOTICE Auth :Looking up your hostname..."); - } - lookup_dns(clientlist[tempnick]); // set the registration timeout for this user @@ -2362,81 +2361,131 @@ void ShowRULES(userrec *user) } /* shows the message of the day, and any other on-logon stuff */ -void ConnectUser(userrec *user) +void FullConnectUser(userrec* user) { - user->registered = 7; - user->idle_lastmsg = time(NULL); + user->registered = 7; + user->idle_lastmsg = time(NULL); log(DEBUG,"ConnectUser: %s",user->nick); - if (strcmp(Passwd(user),"") && (!user->haspassed)) - { - kill_link(user,"Invalid password"); - return; - } - if (IsDenied(user)) + if (strcmp(Passwd(user),"") && (!user->haspassed)) + { + kill_link(user,"Invalid password"); + return; + } + if (IsDenied(user)) + { + kill_link(user,"Unauthorised connection"); + return; + } + + char match_against[MAXBUF]; + snprintf(match_against,MAXBUF,"%s@%s",user->ident,user->host); + char* r = matches_gline(match_against); + if (r) + { + char reason[MAXBUF]; + snprintf(reason,MAXBUF,"G-Lined: %s",r); + kill_link_silent(user,reason); + return; + } + + r = matches_kline(user->host); + if (r) + { + char reason[MAXBUF]; + snprintf(reason,MAXBUF,"K-Lined: %s",r); + kill_link_silent(user,reason); + return; + } + + WriteServ(user->fd,"NOTICE Auth :Welcome to \002%s\002!",Network); + WriteServ(user->fd,"001 %s :Welcome to the %s IRC Network %s!%s@%s",user->nick,Network,user->nick,user->ident,user->host); + WriteServ(user->fd,"002 %s :Your host is %s, running version %s",user->nick,ServerName,VERSION); + WriteServ(user->fd,"003 %s :This server was created %s %s",user->nick,__TIME__,__DATE__); + WriteServ(user->fd,"004 %s %s %s iowghraAsORVSxNCWqBzvdHtGI lvhopsmntikrRcaqOALQbSeKVfHGCuzN",user->nick,ServerName,VERSION); + // the neatest way to construct the initial 005 numeric, considering the number of configure constants to go in it... + std::stringstream v; + v << "MESHED WALLCHOPS MODES=13 CHANTYPES=# PREFIX=(ohv)@%+ MAP SAFELIST MAXCHANNELS=" << MAXCHANS; + v << " MAXBANS=60 NICKLEN=" << NICKMAX; + v << " TOPICLEN=307 KICKLEN=307 MAXTARGETS=20 AWAYLEN=307 CHANMODES=ohvb,k,l,psmnti NETWORK="; + v << std::string(Network); + std::string data005 = v.str(); + FOREACH_MOD On005Numeric(data005); + // anfl @ #ratbox, efnet reminded me that according to the RFC this cant contain more than 13 tokens per line... + // so i'd better split it :) + std::stringstream out(data005); + std::string token = ""; + std::string line5 = ""; + int token_counter = 0; + while (!out.eof()) + { + out >> token; + line5 = line5 + token + " "; + token_counter++; + if ((token_counter >= 13) || (out.eof() == true)) + { + WriteServ(user->fd,"005 %s %s:are supported by this server",user->nick,line5.c_str()); + line5 = ""; + token_counter = 0; + } + } + ShowMOTD(user); + FOREACH_MOD OnUserConnect(user); + WriteOpers("*** Client connecting on port %d: %s!%s@%s [%s]",user->port,user->nick,user->ident,user->host,user->ip); + + char buffer[MAXBUF]; + snprintf(buffer,MAXBUF,"N %d %s %s %s %s +%s %s %s :%s",user->age,user->nick,user->host,user->dhost,user->ident,user->modes,user->ip,ServerName,user->fullname); + NetSendToAll(buffer); +} + +// handles any connects where DNS isnt done yet, times out stale dns queries on users, and lets completed queries connect. +void HandlePendingConnects() +{ + if (pending_connects.size()) { - kill_link(user,"Unauthorised connection"); - return; + for (std::vector::iterator i = pending_connects.begin(); i <= pending_connects.end(); i++) + { + userrec* a = *i; + if (a) + { + // this user's dns is done now. + if ((a->dns_done) && (a->registered == 3)) + { + FullConnectUser(a); // attack! attack!.... + pending_connects.erase(i); + return; // ...RUN AWAY! RUN AWAY! + } + // this users dns is NOT done, but its timed out. + if ((time(NULL) > a->signon+dns_timeout) && (a->registered == 3)) + { + WriteServ(a->fd,"NOTICE Auth :Failed to resolve your hostname, using your IP address instead."); + FullConnectUser(a); + pending_connects.erase(i); + return; + } + } + else + { + pending_connects.erase(i); + return; + } + } } +} - char match_against[MAXBUF]; - snprintf(match_against,MAXBUF,"%s@%s",user->ident,user->host); - char* r = matches_gline(match_against); - if (r) +/* shows the message of the day, and any other on-logon stuff */ +void ConnectUser(userrec *user) +{ + // dns is already done, things are fast. no need to wait for dns to complete just pass them straight on + if (user->dns_done) { - char reason[MAXBUF]; - snprintf(reason,MAXBUF,"G-Lined: %s",r); - kill_link_silent(user,reason); - return; + FullConnectUser(user); } - - r = matches_kline(user->host); - if (r) + else { - char reason[MAXBUF]; - snprintf(reason,MAXBUF,"K-Lined: %s",r); - kill_link_silent(user,reason); - return; + // add them to the pending queue + pending_connects.push_back(user); } - - WriteServ(user->fd,"NOTICE Auth :Welcome to \002%s\002!",Network); - WriteServ(user->fd,"001 %s :Welcome to the %s IRC Network %s!%s@%s",user->nick,Network,user->nick,user->ident,user->host); - WriteServ(user->fd,"002 %s :Your host is %s, running version %s",user->nick,ServerName,VERSION); - WriteServ(user->fd,"003 %s :This server was created %s %s",user->nick,__TIME__,__DATE__); - WriteServ(user->fd,"004 %s %s %s iowghraAsORVSxNCWqBzvdHtGI lvhopsmntikrRcaqOALQbSeKVfHGCuzN",user->nick,ServerName,VERSION); - // the neatest way to construct the initial 005 numeric, considering the number of configure constants to go in it... - std::stringstream v; - v << "MESHED WALLCHOPS MODES=13 CHANTYPES=# PREFIX=(ohv)@%+ MAP SAFELIST MAXCHANNELS=" << MAXCHANS; - v << " MAXBANS=60 NICKLEN=" << NICKMAX; - v << " TOPICLEN=307 KICKLEN=307 MAXTARGETS=20 AWAYLEN=307 CHANMODES=ohvb,k,l,psmnti NETWORK="; - v << std::string(Network); - std::string data005 = v.str(); - FOREACH_MOD On005Numeric(data005); - // anfl @ #ratbox, efnet reminded me that according to the RFC this cant contain more than 13 tokens per line... - // so i'd better split it :) - std::stringstream out(data005); - std::string token = ""; - std::string line5 = ""; - int token_counter = 0; - while (!out.eof()) - { - out >> token; - line5 = line5 + token + " "; - token_counter++; - if ((token_counter >= 13) || (out.eof() == true)) - { - WriteServ(user->fd,"005 %s %s:are supported by this server",user->nick,line5.c_str()); - line5 = ""; - token_counter = 0; - } - } - ShowMOTD(user); - FOREACH_MOD OnUserConnect(user); - WriteOpers("*** Client connecting on port %d: %s!%s@%s [%s]",user->port,user->nick,user->ident,user->host,user->ip); - - char buffer[MAXBUF]; - snprintf(buffer,MAXBUF,"N %d %s %s %s %s +%s %s %s :%s",user->age,user->nick,user->host,user->dhost,user->ident,user->modes,user->ip,ServerName,user->fullname); - NetSendToAll(buffer); } void handle_version(char **parameters, int pcnt, userrec *user) @@ -3409,6 +3458,9 @@ int InspIRCd(void) // poll dns queue dns_poll(); + // handle pending connects + HandlePendingConnects(); + user_hash::iterator count2 = clientlist.begin(); // *FIX* Instead of closing sockets in kill_link when they receive the ERROR :blah line, we should queue @@ -3698,23 +3750,8 @@ int InspIRCd(void) length = sizeof (client); incomingSockfd = accept (openSockfd[count], (struct sockaddr *) &client, &length); - //address_cache::iterator iter = IP.find(client.sin_addr); - bool iscached = false; - //if (iter == IP.end()) - //{ - /* ip isn't in cache, add it */ - strlcpy (target, (char *) inet_ntoa (client.sin_addr), MAXBUF); - strlcpy (resolved, target, MAXBUF); - /* hostname now in 'target' */ - //IP[client.sin_addr] = new string(resolved); - /* hostname in cache */ - //} - //else - //{ - // /* found ip (cached) */ - // strlcpy(resolved, iter->second->c_str(), MAXBUF); - // iscached = true; - //} + strlcpy (target, (char *) inet_ntoa (client.sin_addr), MAXBUF); + strlcpy (resolved, target, MAXBUF); if (incomingSockfd < 0) { @@ -3723,7 +3760,7 @@ int InspIRCd(void) } else { - AddClient(incomingSockfd, resolved, ports[count], iscached, inet_ntoa (client.sin_addr)); + AddClient(incomingSockfd, resolved, ports[count], false, inet_ntoa (client.sin_addr)); log(DEBUG,"InspIRCd: adding client on port %d fd=%d",ports[count],incomingSockfd); } goto label; -- cgit v1.2.3