]> granicus.if.org Git - pdns/commitdiff
rec: Log protobuf messages for cache hits. Add policy tags in gettag()
authorRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 21 Jun 2016 15:01:43 +0000 (17:01 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 21 Jun 2016 15:01:43 +0000 (17:01 +0200)
gettag()` can now return an optional policy tags table in addition to
the existing `tag` integer.
Question and response protobuf messages are now sent even on cache hits.
When protobuf logging is enabled, the protobuf response message is
added to the cache and retrieved together with the response.

docs/markdown/recursor/scripting.md
pdns/lua-recursor4.cc
pdns/lua-recursor4.hh
pdns/pdns_recursor.cc
pdns/recpacketcache.cc
pdns/recpacketcache.hh

index bdcc9eef8151fb190b6ef08052725e8ea9e6a0f5..9625b4ea85b86e14e38bde18639b447c70dd9d30 100644 (file)
@@ -138,6 +138,7 @@ would require packet parsing, which is what we are trying to prevent with `ipfil
 The `gettag` function is invoked when `dq.tag` is called on a dq object or when
 the Recursor attempts to discover in which packetcache an answer is available.
 This function must return an integer, which is the tag number of the packetcache.
+In addition to this integer, this function can return a table of policy tags.
 
 The tagged packetcache can e.g. be used to answer queries from cache that have
 e.g. been filtered for certain IPs (this logic should be implemented in the
index ec2076ef4a136d65ec3d52e91c148ea69f479964..0f1be6f806511784e5939efeeeb3af1e62912b8b 100644 (file)
@@ -44,7 +44,7 @@ bool RecursorLua4::ipfilter(const ComboAddress& remote, const ComboAddress& loca
   return false;
 }
 
-int RecursorLua4::gettag(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype)
+int RecursorLua4::gettag(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector<std::string>* policyTags)
 {
   return 0;
 }
@@ -480,10 +480,21 @@ bool RecursorLua4::ipfilter(const ComboAddress& remote, const ComboAddress& loca
   return false; // don't block
 }
 
-int RecursorLua4::gettag(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype)
+int RecursorLua4::gettag(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector<std::string>* policyTags)
 {
-  if(d_gettag)
-    return d_gettag(remote, ednssubnet, local, qname, qtype);
+  if(d_gettag) {
+    auto ret = d_gettag(remote, ednssubnet, local, qname, qtype);
+
+    if (policyTags) {
+      const auto& tags = std::get<1>(ret);
+      if (tags) {
+        for (const auto& tag : *tags) {
+          policyTags->push_back(tag.second);
+        }
+      }
+    }
+    return std::get<0>(ret);
+  }
   return 0;
 }
 
index cd2a6823d4a17390586b098be9bdbbd86d1e0144..f168cd8a0cd3e8b1eb37721033b54e37530a7b39 100644 (file)
@@ -30,9 +30,9 @@ public:
   bool preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret);
   bool ipfilter(const ComboAddress& remote, const ComboAddress& local, const struct dnsheader&);
 
-  int gettag(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& query, uint16_t qtype);
+  int gettag(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& query, uint16_t qtype, std::vector<std::string>* policyTags);
 
-  typedef std::function<int(ComboAddress, Netmask, ComboAddress, DNSName, uint16_t)> gettag_t;
+  typedef std::function<std::tuple<int,boost::optional<std::unordered_map<int,string> > >(ComboAddress, Netmask, ComboAddress, DNSName, uint16_t)> gettag_t;
   gettag_t d_gettag; // public so you can query if we have this hooked
 
 private:
index e04780092058b940ec2f7c067d6b80c55df29739..7a4265792fa767e9a11ff5d11513f8f8217cee71 100644 (file)
@@ -199,7 +199,7 @@ struct DNSComboWriter {
   ComboAddress d_remote, d_local;
 #ifdef HAVE_PROTOBUF
   boost::uuids::uuid d_uuid;
-  Netmask ednssubnet;
+  Netmask d_ednssubnet;
 #endif
   bool d_tcp;
   int d_socket;
@@ -207,6 +207,7 @@ struct DNSComboWriter {
   string d_query;
   shared_ptr<TCPConnection> d_tcpConnection;
   vector<pair<uint16_t, string> > d_ednsOpts;
+  std::vector<std::string> d_policyTags;
 };
 
 
@@ -613,28 +614,29 @@ catch(...)
 }
 
 #ifdef HAVE_PROTOBUF
-static void protobufFillMessageFromDC(PBDNSMessage& message, const DNSComboWriter* dc)
+static void protobufUpdateMessage(PBDNSMessage& message, const boost::uuids::uuid& uniqueId, const ComboAddress& remote, const ComboAddress& local, const Netmask& ednssubnet, bool tcp, uint16_t id)
 {
   std::string* messageId = message.mutable_messageid();
-  messageId->resize(dc->d_uuid.size());
-  std::copy(dc->d_uuid.begin(), dc->d_uuid.end(), messageId->begin());
+  messageId->resize(uniqueId.size());
+  std::copy(uniqueId.begin(), uniqueId.end(), messageId->begin());
 
-  message.set_socketfamily(dc->d_remote.sin4.sin_family == AF_INET ? PBDNSMessage_SocketFamily_INET : PBDNSMessage_SocketFamily_INET6);
-  message.set_socketprotocol(dc->d_tcp ? PBDNSMessage_SocketProtocol_TCP : PBDNSMessage_SocketProtocol_UDP);
-  if (dc->d_local.sin4.sin_family == AF_INET) {
-    message.set_to(&dc->d_local.sin4.sin_addr.s_addr, sizeof(dc->d_local.sin4.sin_addr.s_addr));
+  message.set_socketfamily(remote.sin4.sin_family == AF_INET ? PBDNSMessage_SocketFamily_INET : PBDNSMessage_SocketFamily_INET6);
+  message.set_socketprotocol(tcp ? PBDNSMessage_SocketProtocol_TCP : PBDNSMessage_SocketProtocol_UDP);
+
+  if (local.sin4.sin_family == AF_INET) {
+    message.set_to(&local.sin4.sin_addr.s_addr, sizeof(local.sin4.sin_addr.s_addr));
   }
-  else if (dc->d_local.sin4.sin_family == AF_INET6) {
-    message.set_to(&dc->d_local.sin6.sin6_addr.s6_addr, sizeof(dc->d_local.sin6.sin6_addr.s6_addr));
+  else if (local.sin4.sin_family == AF_INET6) {
+    message.set_to(&local.sin6.sin6_addr.s6_addr, sizeof(local.sin6.sin6_addr.s6_addr));
   }
-  if (dc->d_remote.sin4.sin_family == AF_INET) {
-    message.set_from(&dc->d_remote.sin4.sin_addr.s_addr, sizeof(dc->d_remote.sin4.sin_addr.s_addr));
+  if (remote.sin4.sin_family == AF_INET) {
+    message.set_from(&remote.sin4.sin_addr.s_addr, sizeof(remote.sin4.sin_addr.s_addr));
   }
-  else if (dc->d_remote.sin4.sin_family == AF_INET6) {
-    message.set_from(&dc->d_remote.sin6.sin6_addr.s6_addr, sizeof(dc->d_remote.sin6.sin6_addr.s6_addr));
+  else if (remote.sin4.sin_family == AF_INET6) {
+    message.set_from(&remote.sin6.sin6_addr.s6_addr, sizeof(remote.sin6.sin6_addr.s6_addr));
   }
-  if (!dc->ednssubnet.empty()) {
-    const ComboAddress ca = dc->ednssubnet.getNetwork();
+  if (!ednssubnet.empty()) {
+    const ComboAddress ca = ednssubnet.getNetwork();
     if (ca.sin4.sin_family == AF_INET) {
       message.set_originalrequestorsubnet(&ca.sin4.sin_addr.s_addr, sizeof(ca.sin4.sin_addr.s_addr));
     }
@@ -647,42 +649,62 @@ static void protobufFillMessageFromDC(PBDNSMessage& message, const DNSComboWrite
   gettime(&ts, true);
   message.set_timesec(ts.tv_sec);
   message.set_timeusec(ts.tv_nsec / 1000);
-  message.set_id(ntohs(dc->d_mdp.d_header.id));
+
+  message.set_id(ntohs(id));
+}
+
+static void protobufFillMessage(PBDNSMessage& message, const boost::uuids::uuid& uniqueId, const ComboAddress& remote, const ComboAddress& local, const Netmask& ednssubnet, bool tcp, uint16_t id, const DNSName& qname, uint16_t qtype, uint16_t qclass)
+{
+  protobufUpdateMessage(message, uniqueId, remote, local, ednssubnet, tcp, id);
 
   PBDNSMessage_DNSQuestion* question = message.mutable_question();
-  question->set_qname(dc->d_mdp.d_qname.toString());
-  question->set_qtype(dc->d_mdp.d_qtype);
-  question->set_qclass(dc->d_mdp.d_qclass);
+  question->set_qname(qname.toString());
+  question->set_qtype(qtype);
+  question->set_qclass(qclass);
 }
 
-static void protobufLogQuery(const std::shared_ptr<RemoteLogger>& logger, const DNSComboWriter* dc)
+static void protobufFillMessageFromDC(PBDNSMessage& message, const DNSComboWriter* dc)
+{
+  protobufFillMessage(message, dc->d_uuid, dc->d_remote, dc->d_local, dc->d_ednssubnet, dc->d_tcp, dc->d_mdp.d_header.id, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass);
+}
+
+static void protobufLogQuery(const std::shared_ptr<RemoteLogger>& logger, const boost::uuids::uuid& uniqueId, const ComboAddress& remote, const ComboAddress& local, const Netmask& ednssubnet, bool tcp, uint16_t id, size_t len, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string appliedPolicy, const std::vector<std::string>& policyTags)
 {
   PBDNSMessage message;
   message.set_type(PBDNSMessage_Type_DNSQueryType);
-  message.set_inbytes(dc->d_query.length());
-  protobufFillMessageFromDC(message, dc);
+  message.set_inbytes(len);
+  protobufFillMessage(message, uniqueId, remote, local, ednssubnet, tcp, id, qname, qtype, qclass);
+
+  /* just fake it up for now */
+  PBDNSMessage_DNSResponse* response = message.mutable_response();
+  if (!appliedPolicy.empty()) {
+    response->set_appliedpolicy(appliedPolicy);
+  }
+  if (!policyTags.empty()) {
+    for(const auto tag : policyTags) {
+      response->add_tags(tag);
+    }
+  }
 
 //  cerr <<message.DebugString()<<endl;
   std::string str;
   message.SerializeToString(&str);
   logger->queueData(str);
-  message.release_question();
 }
 
-static void protobufLogResponse(const std::shared_ptr<RemoteLogger>& logger, const DNSComboWriter* dc, size_t responseSize, PBDNSMessage_DNSResponse& protobufResponse)
+static void protobufFillResponseFromDC(PBDNSMessage& message, const DNSComboWriter* dc, size_t responseSize)
 {
-  PBDNSMessage message;
   message.set_type(PBDNSMessage_Type_DNSResponseType);
   message.set_inbytes(responseSize);
   protobufFillMessageFromDC(message, dc);
+}
 
-  message.set_allocated_response(&protobufResponse);
-
+static void protobufLogResponse(const std::shared_ptr<RemoteLogger>& logger, const PBDNSMessage& message)
+{
 //  cerr <<message.DebugString()<<endl;
   std::string str;
   message.SerializeToString(&str);
   logger->queueData(str);
-  message.release_response();
 }
 #endif
 
@@ -706,12 +728,9 @@ void startDoResolve(void *p)
 
     auto luaconfsLocal = g_luaconfs.getLocal();
     std::string appliedPolicy;
-    std::vector<std::string> policyTags;
 #ifdef HAVE_PROTOBUF
-    PBDNSMessage_DNSResponse protobufResponse;
-    if(luaconfsLocal->protobufServer) {
-      protobufLogQuery(luaconfsLocal->protobufServer, dc);
-    }
+    PBDNSMessage pbMessage;
+    PBDNSMessage_DNSResponse* protobufResponse = pbMessage.mutable_response();
 #endif
 
     DNSPacketWriter pw(packet, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass);
@@ -773,8 +792,8 @@ void startDoResolve(void *p)
       L<<Logger::Warning<<t_id<<" ["<<MT->getTid()<<"/"<<MT->numProcesses()<<"] " << (dc->d_tcp ? "TCP " : "") << "question for '"<<dc->d_mdp.d_qname<<"|"
        <<DNSRecordContent::NumberToType(dc->d_mdp.d_qtype)<<"' from "<<dc->getRemote();
 #ifdef HAVE_PROTOBUF
-      if(!dc->ednssubnet.empty()) {
-        L<<" (ecs "<<dc->ednssubnet.toString()<<")";
+      if(!dc->d_ednssubnet.empty()) {
+        L<<" (ecs "<<dc->d_ednssubnet.toString()<<")";
       }
 #endif
       L<<endl;
@@ -831,7 +850,7 @@ void startDoResolve(void *p)
     }
 
 
-    if(!t_pdl->get() || !(*t_pdl)->preresolve(dc->d_remote, dc->d_local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_tcp, ret, dc->d_ednsOpts.empty() ? 0 : &dc->d_ednsOpts, dc->d_tag, &appliedPolicy, &policyTags, res, &variableAnswer)) {
+    if(!t_pdl->get() || !(*t_pdl)->preresolve(dc->d_remote, dc->d_local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_tcp, ret, dc->d_ednsOpts.empty() ? 0 : &dc->d_ednsOpts, dc->d_tag, &appliedPolicy, &dc->d_policyTags, res, &variableAnswer)) {
       try {
         res = sr.beginResolve(dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_mdp.d_qclass, ret);
       }
@@ -899,8 +918,7 @@ void startDoResolve(void *p)
          (*t_pdl)->nxdomain(dc->d_remote, dc->d_local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_tcp, ret, res, &variableAnswer);
        
 
-       (*t_pdl)->postresolve(dc->d_remote, dc->d_local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_tcp, ret, &appliedPolicy, &policyTags, res, &variableAnswer);
-       
+       (*t_pdl)->postresolve(dc->d_remote, dc->d_local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_tcp, ret, &appliedPolicy, &dc->d_policyTags, res, &variableAnswer);
       }
     }
   haveAnswer:;
@@ -1003,8 +1021,8 @@ void startDoResolve(void *p)
          goto sendit; // need to jump over pw.commit
        }
 #ifdef HAVE_PROTOBUF
-        if(luaconfsLocal->protobufServer && (i->d_type == QType::A || i->d_type == QType::AAAA)) {
-          PBDNSMessage_DNSResponse_DNSRR* pbRR = protobufResponse.add_rrs();
+        if(luaconfsLocal->protobufServer && protobufResponse && (i->d_type == QType::A || i->d_type == QType::AAAA)) {
+          PBDNSMessage_DNSResponse_DNSRR* pbRR = protobufResponse->add_rrs();
           if(pbRR) {
             pbRR->set_name(i->d_name.toString());
             pbRR->set_type(i->d_type);
@@ -1033,16 +1051,19 @@ void startDoResolve(void *p)
     updateResponseStats(res, dc->d_remote, packet.size(), &dc->d_mdp.d_qname, dc->d_mdp.d_qtype);
 #ifdef HAVE_PROTOBUF
     if (luaconfsLocal->protobufServer) {
-      protobufResponse.set_rcode(pw.getHeader()->rcode);
-      if (!appliedPolicy.empty()) {
-        protobufResponse.set_appliedpolicy(appliedPolicy);
-      }
-      if (!policyTags.empty()) {
-        for(const auto tag : policyTags) {
-          protobufResponse.add_tags(tag);
+      if (protobufResponse) {
+        protobufResponse->set_rcode(pw.getHeader()->rcode);
+        if (!appliedPolicy.empty()) {
+          protobufResponse->set_appliedpolicy(appliedPolicy);
+        }
+        if (!dc->d_policyTags.empty()) {
+          for(const auto tag : dc->d_policyTags) {
+            protobufResponse->add_tags(tag);
+          }
         }
       }
-      protobufLogResponse(luaconfsLocal->protobufServer, dc, packet.size(), protobufResponse);
+      protobufFillResponseFromDC(pbMessage, dc, packet.size());
+      protobufLogResponse(luaconfsLocal->protobufServer, pbMessage);
     }
 #endif
     if(!dc->d_tcp) {
@@ -1057,12 +1078,25 @@ void startDoResolve(void *p)
       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() ) {
-
+#ifdef HAVE_PROTOBUF
+        if (luaconfsLocal->protobufServer) {
+          t_packetCache->insertResponsePacket(dc->d_tag, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_query,
+                                              string((const char*)&*packet.begin(), packet.size()),
+                                              g_now.tv_sec,
+                                              pw.getHeader()->rcode == RCode::ServFail ? SyncRes::s_packetcacheservfailttl :
+                                              min(minTTL,SyncRes::s_packetcachettl),
+                                              &pbMessage);
+        }
+        else {
+#endif
         t_packetCache->insertResponsePacket(dc->d_tag, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_query, 
                                             string((const char*)&*packet.begin(), packet.size()),
                                             g_now.tv_sec,
                                             pw.getHeader()->rcode == RCode::ServFail ? SyncRes::s_packetcacheservfailttl :
                                             min(minTTL,SyncRes::s_packetcachettl));
+#ifdef HAVE_PROTOBUF
+        }
+#endif
       }
       //      else cerr<<"Not putting in packet cache: "<<sr.wasVariable()<<endl;
     }
@@ -1180,6 +1214,32 @@ void makeControlChannelSocket(int processNum=-1)
   }
 }
 
+static void getQNameAndSubnet(const std::string& question, DNSName* dnsname, uint16_t* qtype, uint16_t* qclass, Netmask* ednssubnet)
+{
+  const struct dnsheader* dh = (struct dnsheader*)question.c_str();
+  size_t questionLen = question.length();
+  unsigned int consumed=0;
+  *dnsname=DNSName(question.c_str(), questionLen, sizeof(dnsheader), false, qtype, qclass, &consumed);
+
+  size_t pos= sizeof(dnsheader)+consumed+4;
+  /* at least OPT root label (1), type (2), class (2) and ttl (4) + OPT RR rdlen (2)
+     = 11 */
+  if(ntohs(dh->arcount) == 1 && questionLen > pos + 11) { // this code can extract one (1) EDNS Subnet option
+    /* OPT root label (1) followed by type (2) */
+    if(question.at(pos)==0 && question.at(pos+1)==0 && question.at(pos+2)==QType::OPT) {
+      char* ecsStart = nullptr;
+      size_t ecsLen = 0;
+      int res = getEDNSOption((char*)question.c_str()+pos+9, questionLen - pos - 9, EDNSOptionCode::ECS, &ecsStart, &ecsLen);
+      if (res == 0 && ecsLen > 4) {
+        EDNSSubnetOpts eso;
+        if(getEDNSSubnetOptsFromString(ecsStart + 4, ecsLen - 4, &eso)) {
+          *ednssubnet=eso.source;
+        }
+      }
+    }
+  }
+}
+
 void handleRunningTCPQuestion(int fd, FDMultiplexer::funcparam_t& var)
 {
   shared_ptr<TCPConnection> conn=any_cast<shared_ptr<TCPConnection> >(var);
@@ -1244,7 +1304,28 @@ void handleRunningTCPQuestion(int fd, FDMultiplexer::funcparam_t& var)
       getsockname(conn->getFD(), (sockaddr*)&dest, &len); // if this fails, we're ok with it
       dc->setLocal(dest);
 #ifdef HAVE_PROTOBUF
-      dc->d_uuid = (*t_uuidGenerator)();
+      auto luaconfsLocal = g_luaconfs.getLocal();
+
+      if(luaconfsLocal->protobufServer) {
+        dc->d_uuid = (*t_uuidGenerator)();
+
+        try {
+          DNSName qname;
+          uint16_t qtype;
+          uint16_t qclass;
+          Netmask ednssubnet;
+          const struct dnsheader* dh = (const struct dnsheader*) conn->data;
+
+          getQNameAndSubnet(std::string(conn->data, conn->qlen), &qname, &qtype, &qclass, &ednssubnet);
+          dc->d_ednssubnet = ednssubnet;
+
+          protobufLogQuery(luaconfsLocal->protobufServer, dc->d_uuid, dest, conn->d_remote, ednssubnet, true, dh->id, conn->qlen, qname, qtype, qclass, std::string(), std::vector<std::string>());
+        }
+        catch(std::exception& e) {
+          if(g_logCommonErrors)
+            L<<Logger::Warning<<"Error parsing a TCP query packet for edns subnet: "<<e.what()<<endl;
+        }
+      }
 #endif
       if(dc->d_mdp.d_header.qr) {
         delete dc;
@@ -1309,32 +1390,6 @@ void handleNewTCPQuestion(int fd, FDMultiplexer::funcparam_t& )
   }
 }
 
-void getQNameAndSubnet(const std::string& question, DNSName* dnsname, uint16_t* qtype, Netmask* ednssubnet)
-{
-  const struct dnsheader* dh = (struct dnsheader*)question.c_str();
-  size_t questionLen = question.length();
-  unsigned int consumed=0;
-  *dnsname=DNSName(question.c_str(), questionLen, sizeof(dnsheader), false, qtype, 0, &consumed);
-
-  size_t pos= sizeof(dnsheader)+consumed+4;
-  /* at least OPT root label (1), type (2), class (2) and ttl (4) + OPT RR rdlen (2)
-     = 11 */
-  if(ntohs(dh->arcount) == 1 && questionLen > pos + 11) { // this code can extract one (1) EDNS Subnet option
-    /* OPT root label (1) followed by type (2) */
-    if(question.at(pos)==0 && question.at(pos+1)==0 && question.at(pos+2)==QType::OPT) {
-      char* ecsStart = nullptr;
-      size_t ecsLen = 0;
-      int res = getEDNSOption((char*)question.c_str()+pos+9, questionLen - pos - 9, EDNSOptionCode::ECS, &ecsStart, &ecsLen);
-      if (res == 0 && ecsLen > 4) {
-        EDNSSubnetOpts eso;
-        if(getEDNSSubnetOptsFromString(ecsStart + 4, ecsLen - 4, &eso)) {
-          *ednssubnet=eso.source;
-        }
-      }
-    }
-  }
-}
-
 string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fromaddr, const ComboAddress& destaddr, struct timeval tv, int fd)
 {
   gettimeofday(&g_now, 0);
@@ -1354,11 +1409,21 @@ string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fr
   const struct dnsheader* dh = (struct dnsheader*)question.c_str();
   unsigned int ctag=0;
   bool needECS = false;
+  std::vector<std::string> policyTags;
 #ifdef HAVE_PROTOBUF
-  needECS = true;
+  boost::uuids::uuid uniqueId;
+  PBDNSMessage pbMessage;
+  auto luaconfsLocal = g_luaconfs.getLocal();
+  if (luaconfsLocal->protobufServer) {
+    needECS = true;
+    uniqueId = (*t_uuidGenerator)();
+  }
 #endif
   Netmask ednssubnet;
   try {
+    DNSName qname;
+    uint16_t qtype=0;
+    uint16_t qclass=0;
     uint32_t age;
 #ifdef MALLOC_TRACE
     /*
@@ -1373,14 +1438,12 @@ string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fr
 #endif
 
     if(needECS || (t_pdl->get() && (*t_pdl)->d_gettag)) {
-      uint16_t qtype=0;
       try {
-        DNSName qname;
-        getQNameAndSubnet(question, &qname, &qtype, &ednssubnet);
+        getQNameAndSubnet(question, &qname, &qtype, &qclass, &ednssubnet);
 
         if(t_pdl->get() && (*t_pdl)->d_gettag) {
           try {
-            ctag=(*t_pdl)->gettag(fromaddr, ednssubnet, destaddr, qname, qtype);
+            ctag=(*t_pdl)->gettag(fromaddr, ednssubnet, destaddr, qname, qtype, &policyTags);
           }
           catch(std::exception& e)  {
             if(g_logCommonErrors)
@@ -1395,7 +1458,24 @@ string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fr
       }
     }
 
-    if(!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, g_now.tv_sec, &response, &age)) {
+    bool cacheHit = false;
+#ifdef HAVE_PROTOBUF
+    if(luaconfsLocal->protobufServer) {
+      protobufLogQuery(luaconfsLocal->protobufServer, uniqueId, fromaddr, destaddr, ednssubnet, false, dh->id, question.size(), qname, qtype, qclass, std::string(), policyTags);
+
+      cacheHit = (!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, g_now.tv_sec, &response, &age, &pbMessage));
+      if (cacheHit) {
+        protobufUpdateMessage(pbMessage, uniqueId, fromaddr, destaddr, ednssubnet, false, dh->id);
+        protobufLogResponse(luaconfsLocal->protobufServer, pbMessage);
+      }
+    }
+    else {
+#endif
+    cacheHit = (!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, g_now.tv_sec, &response, &age));
+#ifdef HAVE_PROTOBUF
+    }
+#endif
+    if (cacheHit) {
       if(!g_quiet)
         L<<Logger::Notice<<t_id<< " question answered from packet cache tag="<<ctag<<" from "<<fromaddr.toString()<<endl;
 
@@ -1453,9 +1533,10 @@ string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fr
   dc->setRemote(&fromaddr);
   dc->setLocal(destaddr);
   dc->d_tcp=false;
+  dc->d_policyTags = policyTags;
 #ifdef HAVE_PROTOBUF
-  dc->d_uuid = (*t_uuidGenerator)();
-  dc->ednssubnet = ednssubnet;
+  dc->d_uuid = uniqueId;
+  dc->d_ednssubnet = ednssubnet;
 #endif
 
   MT->makeThread(startDoResolve, (void*) dc); // deletes dc
index 873e36962b6be74ffcb3f6e1977921e64c344d52..8b45f7041af8dbb89aac7f80487f04d0e1683ffb 100644 (file)
@@ -95,8 +95,19 @@ uint32_t RecursorPacketCache::canHashPacket(const std::string& origPacket)
   return ret;
 }
 
+#ifdef HAVE_PROTOBUF
+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, PBDNSMessage* protobufMessage)
+#else
 bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now, 
   std::string* responsePacket, uint32_t* age)
+#endif
 {
   uint32_t h = canHashPacket(queryPacket);
   auto& idx = d_packetCache.get<HashTag>();
@@ -128,6 +139,11 @@ bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string&
 
       d_hits++;
       moveCacheItemToBack(d_packetCache, iter);
+#ifdef HAVE_PROTOBUF
+      if (protobufMessage) {
+        *protobufMessage = iter->d_protobufMessage;
+      }
+#endif
       
       return true;
     }
@@ -142,7 +158,16 @@ bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string&
 }
 
 
+#ifdef HAVE_PROTOBUF
+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)
+{
+  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 PBDNSMessage* protobufMessage)
+#else
 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)
+#endif
 {
   auto qhash = canHashPacket(queryPacket);
   auto& idx = d_packetCache.get<HashTag>();
@@ -160,6 +185,12 @@ void RecursorPacketCache::insertResponsePacket(unsigned int tag, const DNSName&
     iter->d_packet = responsePacket;
     iter->d_ttd = now + ttl;
     iter->d_creation = now;
+#ifdef HAVE_PROTOBUF
+    if (protobufMessage) {
+      iter->d_protobufMessage = *protobufMessage;
+    }
+#endif
+
     break;
   }
   
@@ -172,6 +203,11 @@ void RecursorPacketCache::insertResponsePacket(unsigned int tag, const DNSName&
     e.d_ttd = now+ttl;
     e.d_creation = now;
     e.d_tag = tag;
+#ifdef HAVE_PROTOBUF
+    if (protobufMessage) {
+      e.d_protobufMessage = *protobufMessage;
+    }
+#endif
     d_packetCache.insert(e);
   }
 }
index 8cf7dd2d2518ca6f6a470ef1d10bb3aa60b3a7ae..e61dfefe3d872fe60ff8740f676412776dbd5bd8 100644 (file)
 #include <boost/tuple/tuple_comparison.hpp>
 #include <boost/multi_index/sequenced_index.hpp>
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#ifdef HAVE_PROTOBUF
+#include <boost/uuid/uuid.hpp>
+#include <boost/uuid/uuid_generators.hpp>
+#include "dnsmessage.pb.h"
+#endif
+
 
 using namespace ::boost::multi_index;
 
@@ -26,6 +35,10 @@ 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);
+#ifdef HAVE_PROTOBUF
+  bool getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now, std::string* responsePacket, uint32_t* age, PBDNSMessage* 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 PBDNSMessage* protobufMessage);
+#endif
   void doPruneTo(unsigned int maxSize=250000);
   uint64_t doDump(int fd);
   int doWipePacketCache(const DNSName& name, uint16_t qtype=0xffff, bool subtree=false);
@@ -45,6 +58,9 @@ private:
     DNSName d_name;
     uint16_t d_type;
     mutable std::string d_packet; // "I know what I am doing"
+#ifdef HAVE_PROTOBUF
+    mutable PBDNSMessage d_protobufMessage;
+#endif
     uint32_t d_qhash;
     uint32_t d_tag;
     inline bool operator<(const struct Entry& rhs) const;