diff options
author | brain <brain@e03df62e-2008-0410-955e-edbf42e46eb7> | 2006-08-03 14:25:49 +0000 |
---|---|---|
committer | brain <brain@e03df62e-2008-0410-955e-edbf42e46eb7> | 2006-08-03 14:25:49 +0000 |
commit | 43759fd180caf1894e10e8adc2df86f029aa63b1 (patch) | |
tree | ad2c530e324266a08b1a39f98b1e6120889b9d47 | |
parent | bcc3c8566cc5fcff6c39c94ac823941ad1e60b83 (diff) |
Check for spoofed DNS replies where the source-port is invalid, or the ip is not that of the nameserver we're configured to use
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@4668 e03df62e-2008-0410-955e-edbf42e46eb7
-rw-r--r-- | include/dns.h | 7 | ||||
-rw-r--r-- | src/dns.cpp | 35 |
2 files changed, 35 insertions, 7 deletions
diff --git a/include/dns.h b/include/dns.h index 41f42f46a..9d6f161df 100644 --- a/include/dns.h +++ b/include/dns.h @@ -190,7 +190,7 @@ class DNS : public Extensible static const int MAX_REQUEST_ID = 0xFFFF; /** - * Requests that are currently 'in flight + * Requests that are currently 'in flight' */ requestlist requests; @@ -220,6 +220,11 @@ class DNS : public Extensible int MakePayload(const char* name, const QueryType rr, const unsigned short rr_class, unsigned char* payload); public: + /** + * The port number DNS requests are made on, + * and replies have as a source-port number. + */ + static const int QUERY_PORT = 53; /** * Fill an rr (resource record) with data from input diff --git a/src/dns.cpp b/src/dns.cpp index 648e8f4a4..0329ea712 100644 --- a/src/dns.cpp +++ b/src/dns.cpp @@ -184,11 +184,11 @@ int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryTyp #ifdef IPV6 memcpy(&addr.sin6_addr,&myserver,sizeof(addr.sin6_addr)); addr.sin6_family = AF_FAMILY; - addr.sin6_port = htons(53); + addr.sin6_port = htons(DNS::QUERY_PORT); #else memcpy(&addr.sin_addr.s_addr,&myserver,sizeof(addr.sin_addr)); addr.sin_family = AF_FAMILY; - addr.sin_port = htons(53); + addr.sin_port = htons(DNS::QUERY_PORT); #endif if (sendto(DNS::GetMasterSocket(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1) { @@ -202,13 +202,13 @@ int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryTyp /* Add a query with a predefined header, and allocate an ID for it. */ DNSRequest* DNS::AddQuery(DNSHeader *header, int &id) { - id = this->PRNG() & 0xFFFF; + id = this->PRNG() & DNS::MAX_REQUEST_ID; /* This id is already 'in flight', pick another. * -- Thanks jilles */ while (requests.find(id) != requests.end()) - id = this->PRNG() & 0xFFFF; + id = this->PRNG() & DNS::MAX_REQUEST_ID; DNSRequest* req = new DNSRequest(this->myserver); @@ -391,15 +391,38 @@ DNSResult DNS::GetResult() DNSHeader header; DNSRequest *req; unsigned char buffer[sizeof(DNSHeader)]; + sockaddr from; + socklen_t x = sizeof(from); + const char* ipaddr_from = ""; + unsigned short int port_from = 0; - /* Attempt to read a header */ - int length = recv(MasterSocket,buffer,sizeof(DNSHeader),0); + int length = recvfrom(MasterSocket,buffer,sizeof(DNSHeader),0,&from,&x); /* Did we get the whole header? */ if (length < 12) /* Nope - something screwed up. */ return std::make_pair(-1,""); + /* Check wether the reply came from a different DNS + * server to the one we sent it to, or the source-port + * is not 53. + * A user could in theory still spoof dns packets anyway + * but this is less trivial than just sending garbage + * to the client, which is possible without this check. + * + * -- Thanks jilles for pointing this one out. + */ +#ifdef IPV6 + ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin6_addr); + port_from = ntohs(((sockaddr_in*)&from)->sin6_port); +#else + ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr); + port_from = ntohs(((sockaddr_in*)&from)->sin_port); +#endif + + if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, Config->DNSServer))) + return std::make_pair(-1,""); + /* Put the read header info into a header class */ DNS::FillHeader(&header,buffer,length - 12); |