]> granicus.if.org Git - pdns/commitdiff
Correctly parse ECS with a source prefix-length value of 0
authorRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 9 Feb 2017 13:50:11 +0000 (14:50 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 31 May 2017 14:13:13 +0000 (16:13 +0200)
It means there is no address there, but the family and source
prefix-length values are still relevant. rfc7871 explicitly says
that the family SHOULD be set to the transport over which the query
is sent if source prefix-length is 0.
It also states that a source prefix-length means the client is
asking that no ECS value be sent.

(cherry picked from commit 53221eafae3fe410586daf98cca0df3d81ea344c)

pdns/ednssubnet.cc

index d87f26c9e254eb304effc623c55a8f7f82a4a82d..d6b9f8e0069ac4caae585da9e627391370769674 100644 (file)
@@ -37,20 +37,20 @@ namespace {
 
 bool getEDNSSubnetOptsFromString(const string& options, EDNSSubnetOpts* eso)
 {
+  //cerr<<"options.size:"<<options.size()<<endl;
   return getEDNSSubnetOptsFromString(options.c_str(), options.length(), eso);
 }
 bool getEDNSSubnetOptsFromString(const char* options, unsigned int len, EDNSSubnetOpts* eso)
 {
-  //cerr<<"options.size:"<<options.size()<<endl;
   EDNSSubnetOptsWire esow;
   static_assert (sizeof(esow) == 4, "sizeof(EDNSSubnetOptsWire) must be 4 bytes");
-  if(len <= sizeof(esow))
+  if(len < sizeof(esow))
     return false;
   memcpy(&esow, options, sizeof(esow));
   esow.family = ntohs(esow.family);
   //cerr<<"Family when parsing from string: "<<esow.family<<endl;
   ComboAddress address;
-  unsigned int octetsin = ((esow.sourceMask - 1)>> 3)+1;
+  unsigned int octetsin = esow.sourceMask > 0 ? (((esow.sourceMask - 1)>> 3)+1) : 0;
   //cerr<<"octetsin:"<<octetsin<<endl;
   if(esow.family == 1) {
     if(len != sizeof(esow)+octetsin)
@@ -59,7 +59,8 @@ bool getEDNSSubnetOptsFromString(const char* options, unsigned int len, EDNSSubn
       return false;
     memset(&address, 0, sizeof(address));
     address.sin4.sin_family = AF_INET;
-    memcpy(&address.sin4.sin_addr.s_addr, options+sizeof(esow), octetsin);
+    if(octetsin > 0)
+      memcpy(&address.sin4.sin_addr.s_addr, options+sizeof(esow), octetsin);
   } else if(esow.family == 2) {
     if(len != sizeof(esow)+octetsin)
       return false;
@@ -67,11 +68,12 @@ bool getEDNSSubnetOptsFromString(const char* options, unsigned int len, EDNSSubn
       return false;
     memset(&address, 0, sizeof(address));
     address.sin4.sin_family = AF_INET6;
-    memcpy(&address.sin6.sin6_addr.s6_addr, options+sizeof(esow), octetsin);
+    if(octetsin > 0)
+      memcpy(&address.sin6.sin6_addr.s6_addr, options+sizeof(esow), octetsin);
   }
   else
     return false;
// cerr<<"Source address: "<<address.toString()<<", mask: "<<(int)esow.sourceMask<<endl;
 //cerr<<"Source address: "<<address.toString()<<", mask: "<<(int)esow.sourceMask<<endl;
   eso->source = Netmask(address, esow.sourceMask);
   /* 'address' has more bits set (potentially) than scopeMask. This leads to odd looking netmasks that promise
      more precision than they have. For this reason we truncate the address to scopeMask bits */