/* +------------------------------------+ * | 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. * * --------------------------------------------------- */ #include "inspircd_config.h" #include "inspircd.h" #include "configreader.h" #include #include #include #include #include #include "users.h" #include "globals.h" #include "inspstring.h" #include "dnsqueue.h" #include "dns.h" #include "helperfuncs.h" #include "hashcomp.h" #include "socketengine.h" #include "socket.h" extern ServerConfig* Config; extern InspIRCd* ServerInstance; class Lookup; Lookup* dnslist[MAX_DESCRIPTORS]; Lookup* user_fd_to_dns[MAX_DESCRIPTORS]; extern userrec* fd_ref_table[MAX_DESCRIPTORS]; //enum LookupState { reverse, forward }; class Lookup { private: char u[NICKMAX]; std::string hostname; public: DNS resolver1; DNS resolver2; Lookup() { *u = 0; hostname = ""; } void Reset() { *u = 0; hostname = ""; } ~Lookup() { } bool DoLookup(std::string nick) { hostname = ""; userrec* usr = Find(nick); if (usr) { resolver1.SetNS(std::string(Config->DNSServer)); if (!resolver1.ReverseLookup(std::string(usr->host), true)) { return false; } strlcpy(u,nick.c_str(),NICKMAX-1); /* ASSOCIATE WITH DNS LOOKUP LIST */ if (resolver1.GetFD() != -1) { dnslist[resolver1.GetFD()] = this; user_fd_to_dns[usr->fd] = this; return true; } } return false; } bool Done(int fdcheck) { if (hostname != "") { // doing forward lookup userrec* usr = NULL; if (resolver2.HasResult(fdcheck)) { if (resolver2.GetFD() != -1) { dnslist[resolver2.GetFD()] = NULL; std::string ip = resolver2.GetResultIP(); usr = Find(u); if (usr) { if (usr->registered > REG_NICKUSER) { usr->dns_done = true; return true; } if ((hostname != "") && (usr->registered != REG_ALL)) { if ((std::string(insp_ntoa(usr->ip4)) == ip) && (hostname.length() < 65)) { if ((hostname.find_last_of(".in-addr.arpa") == hostname.length() - 1) && (hostname.find_last_of(".in-addr.arpa") != std::string::npos)) { WriteServ(usr->fd,"NOTICE Auth :*** Your ISP are muppets -- reverse resolution resolves back to same reverse .arpa domain (!)"); } else { strlcpy(usr->host,hostname.c_str(),64); strlcpy(usr->dhost,hostname.c_str(),64); WriteServ(usr->fd,"NOTICE Auth :*** Found your hostname"); } } usr->dns_done = true; return true; } } } else { usr = Find(u); if (usr) { usr->dns_done = true; } return true; } } return false; } else { // doing reverse lookup userrec* usr = NULL; if (resolver1.HasResult(fdcheck)) { usr = Find(u); if ((usr) && (usr->dns_done)) { if (resolver1.GetFD() != -1) { dnslist[resolver1.GetFD()] = NULL; user_fd_to_dns[usr->fd] = NULL; } return true; } if (resolver1.GetFD() != -1) { dnslist[resolver1.GetFD()] = NULL; hostname = resolver1.GetResult(); if (usr) { user_fd_to_dns[usr->fd] = NULL; if ((usr->registered > REG_NICKUSER) || (hostname == "")) { WriteServ(usr->fd,"NOTICE Auth :*** Could not resolve your hostname -- Using your IP address instead"); usr->dns_done = true; return true; } if (hostname != "") { resolver2.ForwardLookup(hostname, true); if (resolver2.GetFD() != -1) { dnslist[resolver2.GetFD()] = this; if (usr) user_fd_to_dns[usr->fd] = this; } } } } } } return false; } int GetFD() { userrec* usr = Find(u); if (!usr) return 0; if (usr->dns_done) return 0; return usr->fd; } }; bool lookup_dns(const std::string &nick) { /* First attempt to find the nickname */ userrec* u = Find(nick); if (u) { /* Check the cache */ /*address_cache::iterator address = addrcache.find(u->ip4); if (address != addrcache.end()) { WriteServ(u->fd,"NOTICE Auth :*** Found your hostname (cached)"); log(DEBUG,"Found cached host"); strlcpy(u->host,address->second->c_str(),MAXBUF); strlcpy(u->dhost,address->second->c_str(),MAXBUF); u->dns_done = true; return true; }*/ /* If the user exists, create a new * lookup object, and associate it * with the user. The lookup object * will maintain the reference table * which we use for quickly finding * dns results. Please note that we * do not associate a lookup with a * userrec* pointer and we use the * nickname instead because, by the * time the DNS lookup has completed, * the nickname could have quit and * if we then try and access the * pointer we get a nice segfault. */ Lookup* L = new Lookup(); L->DoLookup(nick); return true; } return false; } void ZapThisDns(int fd) { #ifdef THREADED_DNS /* if (fd_ref_table[fd]) { if (fd_ref_table[fd]->registered >= REG_NICKUSER) { log(DEBUG,"Joining thread for user %d",fd); if (pthread_join(fd_ref_table[fd]->dnsthread, NULL)) { log(DEBUG,"Can't pthread_join(): %s", strerror(errno)); } } }*/ #else if ((fd < 0) || (fd > MAX_DESCRIPTORS)) return; Lookup *x = user_fd_to_dns[fd]; if (x) { if (x->resolver1.GetFD() > 0) { log(DEBUG,"Whacked resolver1"); dns_close(x->resolver1.GetFD()); } if (x->resolver2.GetFD() > 0) { log(DEBUG,"Whacked resolver2"); dns_close(x->resolver2.GetFD()); } } #endif } void dns_poll(int fdcheck) { /* Check the given file descriptor is in valid range */ if ((fdcheck < 0) || (fdcheck > MAX_DESCRIPTORS)) return; /* Try and find the file descriptor in our list of * active DNS lookups */ Lookup *x = dnslist[fdcheck]; if (x) { /* If it exists check if its a valid fd still */ if (x->GetFD() != -1) { /* Check if its done, if it is delete it */ if (x->Done(fdcheck)) { /* We don't need to delete the file descriptor * from the socket engine, as dns.cpp tracks it * for us if we are in single-threaded country. */ DELETE(x); } } else { /* its fd is dodgy, the dns code probably * bashed it due to error. Free the class. */ DELETE(x); } /* If we got down here, the dns lookup was valid, BUT, * its still in progress. Be patient, and wait for * more socketengine events to complete the lookups. */ return; } /* This FD doesnt belong here, lets be rid of it, * just to be safe so we dont get any more events * about it. */ if (ServerInstance && ServerInstance->SE) ServerInstance->SE->DelFd(fdcheck); }