diff -ru pdns-recursor-4.0.8.orig/pdns_recursor.cc pdns-recursor-4.0.8/pdns_recursor.cc
--- pdns-recursor-4.0.8.orig/pdns_recursor.cc	2017-12-11 11:38:52.000000000 +0100
+++ pdns-recursor-4.0.8/pdns_recursor.cc	2018-10-09 17:14:58.052450425 +0200
@@ -1134,7 +1134,7 @@
       if(sendmsg(dc->d_socket, &msgh, 0) < 0 && g_logCommonErrors) 
         L<<Logger::Warning<<"Sending UDP reply to client "<<dc->d_remote.toStringWithPort()<<" failed with: "<<strerror(errno)<<endl;
       if(!SyncRes::s_nopacketcache && !variableAnswer && !sr.wasVariable() ) {
-        t_packetCache->insertResponsePacket(dc->d_tag, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_query,
+        t_packetCache->insertResponsePacket(dc->d_tag, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass, dc->d_query,
                                             string((const char*)&*packet.begin(), packet.size()),
                                             g_now.tv_sec,
                                             pw.getHeader()->rcode == RCode::ServFail ? SyncRes::s_packetcacheservfailttl :
diff -ru pdns-recursor-4.0.8.orig/recpacketcache.cc pdns-recursor-4.0.8/recpacketcache.cc
--- pdns-recursor-4.0.8.orig/recpacketcache.cc	2017-12-11 11:38:52.000000000 +0100
+++ pdns-recursor-4.0.8/recpacketcache.cc	2018-10-09 17:08:20.176479437 +0200
@@ -42,17 +42,59 @@
   return count;
 }
 
+static bool queryHeaderMatches(const std::string& cachedQuery, const std::string& query)
+{
+  if (cachedQuery.size() != query.size()) {
+    return false;
+  }
+
+  return (cachedQuery.compare(/* skip the ID */ 2, sizeof(dnsheader) - 2, query, 2, sizeof(dnsheader) - 2) == 0);
+}
+
+bool RecursorPacketCache::queryMatches(const std::string& cachedQuery, const std::string& query, const DNSName& qname, uint16_t ecsBegin, uint16_t ecsEnd)
+{
+  if (!queryHeaderMatches(cachedQuery, query)) {
+    return false;
+  }
+
+  size_t pos = sizeof(dnsheader) + qname.wirelength();
+
+  if (ecsBegin != 0 && ecsBegin >= pos && ecsEnd > ecsBegin) {
+    if (cachedQuery.compare(pos, ecsBegin - pos, query, pos, ecsBegin - pos) != 0) {
+      return false;
+    }
+
+    if (cachedQuery.compare(ecsEnd, cachedQuery.size() - ecsEnd, query, ecsEnd, query.size() - ecsEnd) != 0) {
+      return false;
+    }
+  }
+  else {
+    if (cachedQuery.compare(pos, cachedQuery.size() - pos, query, pos, query.size() - pos) != 0) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
 // one day this function could be really fast by doing only a case insensitive compare
-static bool qrMatch(const std::string& query, const std::string& response)
+bool RecursorPacketCache::qrMatch(const packetCache_t::index<HashTag>::type::iterator& iter, const std::string& queryPacket, uint16_t ecsBegin, uint16_t ecsEnd)
 {
-  uint16_t rqtype, rqclass, qqtype, qqclass;
-  DNSName queryname(query.c_str(), query.length(), sizeof(dnsheader), false, &qqtype, &qqclass, 0);
-  DNSName respname(response.c_str(), response.length(), sizeof(dnsheader), false, &rqtype, &rqclass, 0);
-  // this ignores checking on the EDNS subnet flags! 
-  return queryname==respname && rqtype == qqtype && rqclass == qqclass;
+  uint16_t qqtype, qqclass;
+  DNSName queryname(queryPacket.c_str(), queryPacket.length(), sizeof(dnsheader), false, &qqtype, &qqclass, 0);
+   // this ignores checking on the EDNS subnet flags!
+  if (qqtype != iter->d_type || qqclass != iter->d_class || queryname != iter->d_name) {
+    return false;
+  }
+
+  if (iter->d_ecsBegin != ecsBegin || iter->d_ecsEnd != ecsEnd) {
+    return false;
+  }
+
+  return queryMatches(iter->d_query, queryPacket, queryname, ecsBegin, ecsEnd);
 }
 
-uint32_t RecursorPacketCache::canHashPacket(const std::string& origPacket)
+uint32_t RecursorPacketCache::canHashPacket(const std::string& origPacket, uint16_t* ecsBegin, uint16_t* ecsEnd)
 {
   //  return 42; // should still work if you do this!
   uint32_t ret=0;
@@ -68,6 +110,10 @@
   struct dnsheader* dh = (struct dnsheader*)origPacket.c_str();
   const char* skipBegin = p;
   const char* skipEnd = p;
+  if (ecsBegin != nullptr && ecsEnd != nullptr) {
+    *ecsBegin = 0;
+    *ecsEnd = 0;
+  }
   /* we need at least 1 (final empty label) + 2 (QTYPE) + 2 (QCLASS)
      + OPT root label (1), type (2), class (2) and ttl (4)
      + the OPT RR rdlen (2)
@@ -82,6 +128,10 @@
     if (res == 0) {
       skipBegin = optionBegin;
       skipEnd = optionBegin + optionLen;
+      if (ecsBegin != nullptr && ecsEnd != nullptr) {
+        *ecsBegin = optionBegin - origPacket.c_str();
+        *ecsEnd = *ecsBegin + optionLen;
+      }
     }
   }
   if (skipBegin > p) {
@@ -96,15 +146,11 @@
 }
 
 bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now,
-                                            std::string* responsePacket, uint32_t* age)
-{
-  return getResponsePacket(tag, queryPacket, now, responsePacket, age, nullptr);
-}
-
-bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now,
                                             std::string* responsePacket, uint32_t* age, RecProtoBufMessage* protobufMessage)
 {
-  uint32_t h = canHashPacket(queryPacket);
+  uint16_t ecsBegin = 0;
+  uint16_t ecsEnd = 0;
+  uint32_t h = canHashPacket(queryPacket, &ecsBegin, &ecsEnd);
   auto& idx = d_packetCache.get<HashTag>();
   auto range = idx.equal_range(tie(tag,h)); 
 
@@ -115,8 +161,9 @@
     
   for(auto iter = range.first ; iter != range.second ; ++ iter) {
     // the possibility is VERY real that we get hits that are not right - birthday paradox
-    if(!qrMatch(queryPacket, iter->d_packet))
+    if(!qrMatch(iter, queryPacket, ecsBegin, ecsEnd)) {
       continue;
+    }
     if((uint32_t)now < iter->d_ttd) { // it is right, it is fresh!
       *age = now - iter->d_creation;
       *responsePacket = iter->d_packet;
@@ -153,27 +200,28 @@
 }
 
 
-void RecursorPacketCache::insertResponsePacket(unsigned int tag, const DNSName& qname, uint16_t qtype, const std::string& queryPacket, const std::string& responsePacket, time_t now, uint32_t ttl)
+void RecursorPacketCache::insertResponsePacket(unsigned int tag, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& queryPacket, const std::string& responsePacket, time_t now, uint32_t ttl, const RecProtoBufMessage* protobufMessage)
 {
-  insertResponsePacket(tag, qname, qtype, queryPacket, responsePacket, now, ttl, nullptr);
-}
-
-void RecursorPacketCache::insertResponsePacket(unsigned int tag, const DNSName& qname, uint16_t qtype, const std::string& queryPacket, const std::string& responsePacket, time_t now, uint32_t ttl, const RecProtoBufMessage* protobufMessage)
-{
-  auto qhash = canHashPacket(queryPacket);
+  uint16_t ecsBegin = 0;
+  uint16_t ecsEnd = 0;
+  auto qhash = canHashPacket(queryPacket, &ecsBegin, &ecsEnd);
   auto& idx = d_packetCache.get<HashTag>();
   auto range = idx.equal_range(tie(tag,qhash));
   auto iter = range.first;
 
   for( ; iter != range.second ; ++iter)  {
-    if(iter->d_type != qtype)
+    if(iter->d_type != qtype || iter->d_class != qclass) {
       continue;
+    }
     // this only happens on insert which is relatively rare and does not need to be super fast
     DNSName respname(iter->d_packet.c_str(), iter->d_packet.length(), sizeof(dnsheader), false, 0, 0, 0);
     if(qname != respname)
       continue;
     moveCacheItemToBack(d_packetCache, iter);
     iter->d_packet = responsePacket;
+    iter->d_query = queryPacket;
+    iter->d_ecsBegin = ecsBegin;
+    iter->d_ecsEnd = ecsEnd;
     iter->d_ttd = now + ttl;
     iter->d_creation = now;
 #ifdef HAVE_PROTOBUF
@@ -188,9 +236,13 @@
   if(iter == range.second) { // nothing to refresh
     struct Entry e;
     e.d_packet = responsePacket;
+    e.d_query = queryPacket;
     e.d_name = qname;
     e.d_qhash = qhash;
     e.d_type = qtype;
+    e.d_class = qclass;
+    e.d_ecsBegin = ecsBegin;
+    e.d_ecsEnd = ecsEnd;
     e.d_ttd = now+ttl;
     e.d_creation = now;
     e.d_tag = tag;
diff -ru pdns-recursor-4.0.8.orig/recpacketcache.hh pdns-recursor-4.0.8/recpacketcache.hh
--- pdns-recursor-4.0.8.orig/recpacketcache.hh	2017-12-11 11:38:52.000000000 +0100
+++ pdns-recursor-4.0.8/recpacketcache.hh	2018-10-09 17:14:58.052450425 +0200
@@ -50,10 +50,8 @@
 {
 public:
   RecursorPacketCache();
-  bool getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now, std::string* responsePacket, uint32_t* age);
-  void insertResponsePacket(unsigned int tag, const DNSName& qname, uint16_t qtype, const std::string& queryPacket, const std::string& responsePacket, time_t now, uint32_t ttd);
   bool getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now, std::string* responsePacket, uint32_t* age, RecProtoBufMessage* protobufMessage);
-  void insertResponsePacket(unsigned int tag, const DNSName& qname, uint16_t qtype, const std::string& queryPacket, const std::string& responsePacket, time_t now, uint32_t ttd, const RecProtoBufMessage* protobufMessage);
+  void insertResponsePacket(unsigned int tag, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& queryPacket, const std::string& responsePacket, time_t now, uint32_t ttd, const RecProtoBufMessage* protobufMessage);
   void doPruneTo(unsigned int maxSize=250000);
   uint64_t doDump(int fd);
   int doWipePacketCache(const DNSName& name, uint16_t qtype=0xffff, bool subtree=false);
@@ -72,12 +70,16 @@
     mutable uint32_t d_creation; // so we can 'age' our packets
     DNSName d_name;
     uint16_t d_type;
+    uint16_t d_class;
     mutable std::string d_packet; // "I know what I am doing"
+    mutable std::string d_query;
 #ifdef HAVE_PROTOBUF
     mutable RecProtoBufMessage d_protobufMessage;
 #endif
     uint32_t d_qhash;
     uint32_t d_tag;
+    mutable uint16_t d_ecsBegin;
+    mutable uint16_t d_ecsEnd;
     inline bool operator<(const struct Entry& rhs) const;
     
     uint32_t getTTD() const
@@ -85,7 +87,7 @@
       return d_ttd;
     }
   };
-  uint32_t canHashPacket(const std::string& origPacket);
+
   typedef multi_index_container<
     Entry,
     indexed_by  <
@@ -96,6 +98,11 @@
   > packetCache_t;
   
   packetCache_t d_packetCache;
+
+public:
+  static bool queryMatches(const std::string& cachedQuery, const std::string& query, const DNSName& qname, uint16_t ecsBegin, uint16_t ecsEnd);
+  static bool qrMatch(const packetCache_t::index<HashTag>::type::iterator& iter, const std::string& queryPacket, uint16_t ecsBegin, uint16_t ecsEnd);
+  static uint32_t canHashPacket(const std::string& origPacket, uint16_t* ecsBegin, uint16_t* ecsEnd);
 };
 
 #endif
diff -ru pdns-recursor-4.0.8.orig/test-recpacketcache_cc.cc pdns-recursor-4.0.8/test-recpacketcache_cc.cc
--- pdns-recursor-4.0.8.orig/test-recpacketcache_cc.cc	2017-12-11 11:38:52.000000000 +0100
+++ pdns-recursor-4.0.8/test-recpacketcache_cc.cc	2018-10-09 17:14:58.052450425 +0200
@@ -33,19 +33,19 @@
   pw.commit();
   string rpacket((const char*)&packet[0], packet.size());
 
-  rpc.insertResponsePacket(0,qname, QType::A, qpacket, rpacket, time(0), 3600);
+  rpc.insertResponsePacket(0,qname, QType::A, QClass::IN, qpacket, rpacket, time(0), 3600, nullptr);
   BOOST_CHECK_EQUAL(rpc.size(), 1);
   rpc.doPruneTo(0);
   BOOST_CHECK_EQUAL(rpc.size(), 0);
-  rpc.insertResponsePacket(0,qname, QType::A, qpacket, rpacket, time(0), 3600);
+  rpc.insertResponsePacket(0,qname, QType::A, QClass::IN, qpacket, rpacket, time(0), 3600, nullptr);
   BOOST_CHECK_EQUAL(rpc.size(), 1);
   rpc.doWipePacketCache(qname);
   BOOST_CHECK_EQUAL(rpc.size(), 0);
 
-  rpc.insertResponsePacket(0,qname, QType::A, qpacket, rpacket, time(0), 3600);
+  rpc.insertResponsePacket(0,qname, QType::A, QClass::IN, qpacket, rpacket, time(0), 3600, nullptr);
   uint32_t age=0;
   string fpacket;
-  bool found = rpc.getResponsePacket(0, qpacket, time(0), &fpacket, &age);
+  bool found = rpc.getResponsePacket(0, qpacket, time(0), &fpacket, &age, nullptr);
   BOOST_CHECK_EQUAL(found, 1);
   BOOST_CHECK_EQUAL(fpacket, rpacket);
 
@@ -57,7 +57,7 @@
   pw2.getHeader()->qr=false;
   pw2.getHeader()->id=random();
   qpacket.assign((const char*)&packet[0], packet.size());
-  found = rpc.getResponsePacket(0, qpacket, time(0), &fpacket, &age);
+  found = rpc.getResponsePacket(0, qpacket, time(0), &fpacket, &age, nullptr);
   BOOST_CHECK_EQUAL(found, 0);
 
   rpc.doWipePacketCache(DNSName("com"), 0xffff, true);
