diff options
-rw-r--r-- | include/dns.h | 48 | ||||
-rw-r--r-- | include/inspircd.h | 2 | ||||
-rw-r--r-- | src/dns.cpp | 207 | ||||
-rw-r--r-- | src/inspircd.cpp | 7 | ||||
-rw-r--r-- | src/modules.cpp | 2 |
5 files changed, 129 insertions, 137 deletions
diff --git a/include/dns.h b/include/dns.h index 1f520de33..50febef59 100644 --- a/include/dns.h +++ b/include/dns.h @@ -38,21 +38,8 @@ enum ResolverError RESOLVER_BADIP = 4 }; - -/** DNS is a singleton class used by the core to dispatch dns - * requests to the dns server, and route incoming dns replies - * back to Resolver objects, based upon the request ID. You - * should never use this class yourself. - */ -class DNS : public Extensible -{ - public: - int GetIP(const char* name); - int GetName(const insp_inaddr* ip); - DNSResult GetResult(); - DNS(); - ~DNS(); -}; +class DNSRequest; +class DNSHeader; /** * The Resolver class is a high-level abstraction for resolving DNS entries. @@ -132,19 +119,24 @@ class Resolver : public Extensible int GetId(); }; -/** - * Clear the pointer table used for Resolver classes, - * translate ServerConfig::DNSServer into an insp_inaddr, - * establish binding on UDP socket for DNS requests. - */ -void init_dns(); -/** - * Deal with a Resolver class which has become readable - */ -void dns_deal_with_classes(int fd); -/** - * Add a resolver class to our active table +/** DNS is a singleton class used by the core to dispatch dns + * requests to the dns server, and route incoming dns replies + * back to Resolver objects, based upon the request ID. You + * should never use this class yourself. */ -bool dns_add_class(Resolver* r); +class DNS : public Extensible +{ + private: + insp_inaddr myserver; + public: + int GetIP(const char* name); + int GetName(const insp_inaddr* ip); + DNSResult GetResult(); + void MarshallReads(int fd); + bool AddResolverClass(Resolver* r); + DNSRequest* DNSAddQuery(DNSHeader *header, int &id); + DNS(); + ~DNS(); +}; #endif diff --git a/include/inspircd.h b/include/inspircd.h index 8e75c256c..e698efe21 100644 --- a/include/inspircd.h +++ b/include/inspircd.h @@ -103,6 +103,7 @@ class InspIRCd : public classbase CommandParser* Parser; SocketEngine* SE; serverstats* stats; + DNS* Res; std::string GetRevision(); std::string GetVersionString(); @@ -113,7 +114,6 @@ class InspIRCd : public classbase InspIRCd(int argc, char** argv); void DoOneIteration(bool process_module_sockets); int Run(); - }; /* Miscellaneous stuff here, moved from inspircd_io.h */ diff --git a/src/dns.cpp b/src/dns.cpp index b9ecffa06..66e4edaed 100644 --- a/src/dns.cpp +++ b/src/dns.cpp @@ -43,89 +43,93 @@ using namespace std; #include "socketengine.h" #include "configreader.h" +/* We need these */ extern InspIRCd* ServerInstance; extern ServerConfig* Config; -extern time_t TIME; -extern userrec* fd_ref_table[MAX_DESCRIPTORS]; +/* Query and resource record types */ enum QueryType { - DNS_QRY_A = 1, - DNS_QRY_PTR = 12 + DNS_QRY_A = 1, /* 'A' record: an IP address */ + DNS_QRY_PTR = 12 /* 'PTR' record: a hostname */ }; +/* Masks to mask off the responses we get from the DNSRequest methods */ enum QueryInfo { - ERROR_MASK = 0x10000 + ERROR_MASK = 0x10000 /* Result is an error */ }; +/* Flags which can be ORed into a request or reply for different meanings */ enum QueryFlags { - FLAGS_MASK_RD = 0x01, + FLAGS_MASK_RD = 0x01, /* Recursive */ FLAGS_MASK_TC = 0x02, - FLAGS_MASK_AA = 0x04, + FLAGS_MASK_AA = 0x04, /* Authoritative */ FLAGS_MASK_OPCODE = 0x78, FLAGS_MASK_QR = 0x80, - FLAGS_MASK_RCODE = 0x0F, + FLAGS_MASK_RCODE = 0x0F, /* Request */ FLAGS_MASK_Z = 0x70, FLAGS_MASK_RA = 0x80 }; -class DNSRequest; -typedef std::map<int,DNSRequest*> connlist; -typedef connlist::iterator connlist_iter; - -DNS* Res = NULL; +/* Master file descriptor - all DNS requests go out over this socket. + */ +int MasterDNSSocket = -1; -connlist connections; -int master_socket = -1; +/* Lookup table of Resolver classes. Because the request ID can be between + * 0 and 65535 of these, we have 65536 of them. This could be a map, saving + * some ram, but that will also slow down DNS requests, and the DNS request + * mechanism needs to be pretty fast. + */ Resolver* dns_classes[65536]; -insp_inaddr myserver; /* Represents a dns resource record (rr) */ class ResourceRecord { public: - QueryType type; - unsigned int rr_class; - unsigned long ttl; - unsigned int rdlength; + QueryType type; /* Record type */ + unsigned int rr_class; /* Record class */ + unsigned long ttl; /* Time to live */ + unsigned int rdlength; /* Record length */ }; -/* Represents a dns request/reply header, - * and its payload as opaque data. +/* Represents a dns request/reply header, and its payload as opaque data. */ class DNSHeader { public: - unsigned char id[2]; - unsigned int flags1; - unsigned int flags2; + unsigned char id[2]; /* Request id */ + unsigned int flags1; /* Flags */ + unsigned int flags2; /* Flags */ unsigned int qdcount; - unsigned int ancount; - unsigned int nscount; + unsigned int ancount; /* Answer count */ + unsigned int nscount; /* Nameserver count */ unsigned int arcount; - unsigned char payload[512]; + unsigned char payload[512]; /* Packet payload */ }; -/* Represents a request 'on the wire' with - * routing information relating to where to - * call when we get a result +/* Represents a request 'on the wire' with routing information relating to + * where to call when we get a result */ class DNSRequest { public: - unsigned char id[2]; - unsigned char* res; - unsigned int rr_class; - QueryType type; - - DNSRequest() + unsigned char id[2]; /* Request id */ + unsigned char* res; /* Result processing buffer */ + unsigned int rr_class; /* Request class */ + QueryType type; /* Request type */ + insp_inaddr myserver; /* DNS server address*/ + + /* Allocate the processing buffer */ + DNSRequest(insp_inaddr server) { res = new unsigned char[512]; *res = 0; + memcpy(&myserver, &server, sizeof(insp_inaddr)); } + /* Deallocate the processing buffer */ ~DNSRequest() { delete[] res; @@ -138,6 +142,15 @@ class DNSRequest int SendRequests(const DNSHeader *header, const int length, QueryType qt); }; +/* A set of requests keyed by request id */ +typedef std::map<int,DNSRequest*> requestlist; + +/* An iterator into a set of requests */ +typedef requestlist::iterator requestlist_iter; + +/* Declare our map */ +requestlist requests; + /* * Optimized by brain, these were using integer division and modulus. * We can use logic shifts and logic AND to replace these even divisions @@ -145,7 +158,9 @@ class DNSRequest * but of course, more impressive). Also made these inline. */ -inline void dns_fill_rr(ResourceRecord* rr, const unsigned char *input) + +/* Fill a ResourceRecord class based on raw data input */ +inline void DNSFillResourceRecord(ResourceRecord* rr, const unsigned char *input) { rr->type = (QueryType)((input[0] << 8) + input[1]); rr->rr_class = (input[2] << 8) + input[3]; @@ -153,7 +168,8 @@ inline void dns_fill_rr(ResourceRecord* rr, const unsigned char *input) rr->rdlength = (input[8] << 8) + input[9]; } -inline void dns_fill_header(DNSHeader *header, const unsigned char *input, const int length) +/* Fill a DNSHeader class based on raw data input of a given length */ +inline void DNSFillHeader(DNSHeader *header, const unsigned char *input, const int length) { header->id[0] = input[0]; header->id[1] = input[1]; @@ -166,7 +182,8 @@ inline void dns_fill_header(DNSHeader *header, const unsigned char *input, const memcpy(header->payload,&input[12],length); } -inline void dns_empty_header(unsigned char *output, const DNSHeader *header, const int length) +/* Empty a DNSHeader class out into raw data, ready for transmission */ +inline void DNSEmptyHeader(unsigned char *output, const DNSHeader *header, const int length) { output[0] = header->id[0]; output[1] = header->id[1]; @@ -183,7 +200,7 @@ inline void dns_empty_header(unsigned char *output, const DNSHeader *header, con memcpy(&output[12],header->payload,length); } - +/* Send requests we have previously built down the UDP socket */ int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt) { insp_sockaddr addr; @@ -192,7 +209,7 @@ int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryTyp this->rr_class = 1; this->type = qt; - dns_empty_header(payload,header,length); + DNSEmptyHeader(payload,header,length); memset(&addr,0,sizeof(addr)); #ifdef IPV6 @@ -204,7 +221,7 @@ int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryTyp addr.sin_family = AF_FAMILY; addr.sin_port = htons(53); #endif - if (sendto(master_socket, payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1) + if (sendto(MasterDNSSocket, payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1) { log(DEBUG,"Error in sendto!"); return -1; @@ -213,11 +230,11 @@ int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryTyp return 0; } -DNSRequest* DNSAddQuery(DNSHeader *header, int &id) +/* Add a query with a predefined header, and allocate an ID for it. */ +DNSRequest* DNS::DNSAddQuery(DNSHeader *header, int &id) { - id = rand() % 65536; - DNSRequest* req = new DNSRequest(); + DNSRequest* req = new DNSRequest(this->myserver); header->id[0] = req->id[0] = id >> 8; header->id[1] = req->id[1] = id & 0xFF; @@ -228,34 +245,36 @@ DNSRequest* DNSAddQuery(DNSHeader *header, int &id) header->nscount = 0; header->arcount = 0; - if (connections.find(id) == connections.end()) - connections[id] = req; + if (requests.find(id) == requests.end()) + requests[id] = req; /* According to the C++ spec, new never returns NULL. */ return req; } -void DNSCreateSocket() +/* Initialise the DNS UDP socket so that we can send requests */ +DNS::DNS() { - log(DEBUG,"---- BEGIN DNS INITIALIZATION, SERVER=%s ---",Config->DNSServer); + log(DEBUG,"----- Initialize dns class ----- "); + memset(dns_classes,0,sizeof(dns_classes)); insp_inaddr addr; - srand((unsigned int) TIME); + srand((unsigned int)time(NULL)); 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) + MasterDNSSocket = socket(PF_PROTOCOL, SOCK_DGRAM, 0); + if (MasterDNSSocket != -1) { log(DEBUG,"Set query socket nonblock"); - if (fcntl(master_socket, F_SETFL, O_NONBLOCK) != 0) + if (fcntl(MasterDNSSocket, F_SETFL, O_NONBLOCK) != 0) { - shutdown(master_socket,2); - close(master_socket); - master_socket = -1; + shutdown(MasterDNSSocket,2); + close(MasterDNSSocket); + MasterDNSSocket = -1; } } - if (master_socket != -1) + if (MasterDNSSocket != -1) { #ifdef IPV6 insp_sockaddr addr; @@ -271,19 +290,19 @@ void DNSCreateSocket() addr.sin_addr.s_addr = INADDR_ANY; #endif log(DEBUG,"Binding query port"); - if (bind(master_socket,(sockaddr *)&addr,sizeof(addr)) != 0) + if (bind(MasterDNSSocket,(sockaddr *)&addr,sizeof(addr)) != 0) { log(DEBUG,"Cant bind with source port = 0"); - shutdown(master_socket,2); - close(master_socket); - master_socket = -1; + shutdown(MasterDNSSocket,2); + close(MasterDNSSocket); + MasterDNSSocket = -1; } - if (master_socket >= 0) + if (MasterDNSSocket >= 0) { log(DEBUG,"Attach query port to socket engine"); if (ServerInstance && ServerInstance->SE) - ServerInstance->SE->AddFd(master_socket,true,X_ESTAB_DNS); + ServerInstance->SE->AddFd(MasterDNSSocket,true,X_ESTAB_DNS); } } } @@ -383,7 +402,7 @@ DNSResult DNS::GetResult() unsigned char buffer[sizeof(DNSHeader)]; /* Attempt to read a header */ - length = recv(master_socket,buffer,sizeof(DNSHeader),0); + length = recv(MasterDNSSocket,buffer,sizeof(DNSHeader),0); /* Did we get the whole header? */ if (length < 12) @@ -391,7 +410,7 @@ DNSResult DNS::GetResult() return std::make_pair(-1,""); /* Put the read header info into a header class */ - dns_fill_header(&header,buffer,length - 12); + DNSFillHeader(&header,buffer,length - 12); /* Get the id of this request. * Its a 16 bit value stored in two char's, @@ -400,19 +419,19 @@ DNSResult DNS::GetResult() unsigned long this_id = header.id[1] + (header.id[0] << 8); /* Do we have a pending request matching this id? */ - connlist_iter n_iter = connections.find(this_id); - if (n_iter == connections.end()) - { + requestlist_iter n_iter = requests.find(this_id); + if (n_iter == requests.end()) + { /* Somehow we got a DNS response for a request we never made... */ - 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 - { + log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",MasterDNSSocket,this_id); + return std::make_pair(-1,""); + } + else + { /* Remove the query from the list of pending queries */ req = (DNSRequest*)n_iter->second; - connections.erase(n_iter); - } + requests.erase(n_iter); + } /* Inform the DNSRequest class that it has a result to be read. * When its finished it will return a DNSInfo which is a pair of @@ -519,7 +538,7 @@ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length) if (length - i < 10) return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply"); - dns_fill_rr(&rr,&header.payload[i]); + DNSFillResourceRecord(&rr,&header.payload[i]); i += 10; if (rr.type != this->type) { @@ -587,12 +606,10 @@ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length) return std::make_pair(res,"No error");; } -DNS::DNS() -{ -} - DNS::~DNS() { + shutdown(MasterDNSSocket, 2); + close(MasterDNSSocket); } Resolver::Resolver(const std::string &source, bool forward) : input(source), fwd(forward) @@ -600,7 +617,7 @@ Resolver::Resolver(const std::string &source, bool forward) : input(source), fwd if (forward) { log(DEBUG,"Resolver: Forward lookup on %s",source.c_str()); - this->myid = Res->GetIP(source.c_str()); + this->myid = ServerInstance->Res->GetIP(source.c_str()); } else { @@ -609,7 +626,7 @@ Resolver::Resolver(const std::string &source, bool forward) : input(source), fwd if (insp_aton(source.c_str(), &binip) > 0) { /* Valid ip address */ - this->myid = Res->GetName(&binip); + this->myid = ServerInstance->Res->GetName(&binip); } else { @@ -630,10 +647,6 @@ Resolver::Resolver(const std::string &source, bool forward) : input(source), fwd log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid); } -//void Resolver::OnLookupComplete(const std::string &result) -//{ -//} - void Resolver::OnError(ResolverError e, const std::string &errormessage) { } @@ -648,12 +661,12 @@ int Resolver::GetId() return this->myid; } -void dns_deal_with_classes(int fd) +void DNS::MarshallReads(int fd) { log(DEBUG,"dns_deal_with_classes(%d)",fd); - if (fd == master_socket) + if (fd == MasterDNSSocket) { - DNSResult res = Res->GetResult(); + DNSResult res = this->GetResult(); if (res.first != -1) { if (res.first & ERROR_MASK) @@ -682,35 +695,23 @@ void dns_deal_with_classes(int fd) } } -bool dns_add_class(Resolver* r) +bool DNS::AddResolverClass(Resolver* r) { - 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)); - DNSCreateSocket(); -} diff --git a/src/inspircd.cpp b/src/inspircd.cpp index 23a4bb496..bcd1614d3 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -817,11 +817,10 @@ void InspIRCd::DoOneIteration(bool process_module_sockets) case X_ESTAB_DNS: /* Handles instances of the Resolver class, - * a simple class extended by modules for + * a simple class extended by modules and the core for * nonblocking resolving of addresses. */ - - dns_deal_with_classes(activefds[activefd]); + this->Res->MarshallReads(activefds[activefd]); break; case X_LISTEN: @@ -895,7 +894,7 @@ int InspIRCd::Run() { /* Until THIS point, ServerInstance == NULL */ - init_dns(); + this->Res = new DNS(); LoadAllModules(this); diff --git a/src/modules.cpp b/src/modules.cpp index fbdac43d2..9bb8e9a05 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -632,7 +632,7 @@ bool Server::DelModeWatcher(ModeWatcher* mw) bool Server::AddResolver(Resolver* r) { - return dns_add_class(r); + return ServerInstance->Res->AddResolverClass(r); } int Server::CountUsers(chanrec* c) |