@@ -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 */
4345enum 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 */
162164DNSRequest::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