Skip to content

Commit fe7dbd2

Browse files
author
Sir Pogsalot
committed
Merge pull request #1 from nenolod/insp20
DNS resolver hardening (insp20 branch)
2 parents eba7e66 + eac05f8 commit fe7dbd2

File tree

1 file changed

+38
-10
lines changed

1 file changed

+38
-10
lines changed

Diff for: src/dns.cpp

+38-10
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ looks like this, walks like this or tastes like this.
3838
#include "configreader.h"
3939
#include "socket.h"
4040

41+
#define DN_COMP_BITMASK 0xC000 /* highest 6 bits in a DN label header */
42+
4143
/** Masks to mask off the responses we get from the DNSRequest methods
4244
*/
4345
enum QueryInfo
@@ -98,7 +100,7 @@ class DNSRequest
98100

99101
DNSRequest(DNS* dns, int id, const std::string &original);
100102
~DNSRequest();
101-
DNSInfo ResultIsReady(DNSHeader &h, int length);
103+
DNSInfo ResultIsReady(DNSHeader &h, unsigned length);
102104
int SendRequests(const DNSHeader *header, const int length, QueryType qt);
103105
};
104106

@@ -161,7 +163,10 @@ int CachedQuery::CalcTTLRemaining()
161163
/* Allocate the processing buffer */
162164
DNSRequest::DNSRequest(DNS* dns, int rid, const std::string &original) : dnsobj(dns)
163165
{
164-
res = new unsigned char[512];
166+
/* hardening against overflow here: make our work buffer twice the theoretical
167+
* maximum size so that hostile input doesn't screw us over.
168+
*/
169+
res = new unsigned char[sizeof(DNSHeader) * 2];
165170
*res = 0;
166171
orig = original;
167172
RequestTimeout* RT = new RequestTimeout(ServerInstance->Config->dns_timeout ? ServerInstance->Config->dns_timeout : 5, this, rid);
@@ -688,11 +693,11 @@ DNSResult DNS::GetResult()
688693
}
689694

690695
/** A result is ready, process it */
691-
DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
696+
DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, unsigned length)
692697
{
693-
int i = 0;
698+
unsigned i = 0, o;
694699
int q = 0;
695-
int curanswer, o;
700+
int curanswer;
696701
ResourceRecord rr;
697702
unsigned short ptr;
698703

@@ -790,17 +795,31 @@ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
790795

791796
switch (rr.type)
792797
{
798+
/*
799+
* CNAME and PTR are compressed. We need to decompress them.
800+
*/
793801
case DNS_QUERY_CNAME:
794-
/* CNAME and PTR have the same processing code */
795802
case DNS_QUERY_PTR:
796803
o = 0;
797804
q = 0;
798805
while (q == 0 && i < length && o + 256 < 1023)
799806
{
807+
/* DN label found (byte over 63) */
800808
if (header.payload[i] > 63)
801809
{
802810
memcpy(&ptr,&header.payload[i],2);
803-
i = ntohs(ptr) - 0xC000 - 12;
811+
812+
i = ntohs(ptr);
813+
814+
/* check that highest two bits are set. if not, we've been had */
815+
if (!(i & DN_COMP_BITMASK))
816+
return std::make_pair((unsigned char *) NULL, "DN label decompression header is bogus");
817+
818+
/* mask away the two highest bits. */
819+
i &= ~DN_COMP_BITMASK;
820+
821+
/* and decrease length by 12 bytes. */
822+
i =- 12;
804823
}
805824
else
806825
{
@@ -813,7 +832,11 @@ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
813832
res[o] = 0;
814833
if (o != 0)
815834
res[o++] = '.';
816-
memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
835+
836+
if (o + header.payload[i] > sizeof(DNSHeader))
837+
return std::make_pair((unsigned char *) NULL, "DN label decompression is impossible -- malformed/hostile packet?");
838+
839+
memcpy(&res[o], &header.payload[i + 1], header.payload[i]);
817840
o += header.payload[i];
818841
i += header.payload[i] + 1;
819842
}
@@ -822,16 +845,21 @@ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
822845
res[o] = 0;
823846
break;
824847
case DNS_QUERY_AAAA:
848+
if (rr.rdlength != sizeof(struct in6_addr))
849+
return std::make_pair((unsigned char *) NULL, "rr.rdlength is larger than 16 bytes for an ipv6 entry -- malformed/hostile packet?");
850+
825851
memcpy(res,&header.payload[i],rr.rdlength);
826852
res[rr.rdlength] = 0;
827853
break;
828854
case DNS_QUERY_A:
855+
if (rr.rdlength != sizeof(struct in_addr))
856+
return std::make_pair((unsigned char *) NULL, "rr.rdlength is larger than 4 bytes for an ipv4 entry -- malformed/hostile packet?");
857+
829858
memcpy(res,&header.payload[i],rr.rdlength);
830859
res[rr.rdlength] = 0;
831860
break;
832861
default:
833-
memcpy(res,&header.payload[i],rr.rdlength);
834-
res[rr.rdlength] = 0;
862+
return std::make_pair((unsigned char *) NULL, "don't know how to handle undefined type (" + ConvToStr(rr.type) + ") -- rejecting");
835863
break;
836864
}
837865
return std::make_pair(res,"No error");

0 commit comments

Comments
 (0)