+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <boost/uuid/uuid.hpp>
-#include <boost/uuid/uuid_generators.hpp>
-#include "dnsmessage.pb.h"
#include "iputils.hh"
#include "misc.hh"
+#include "protobuf.hh"
#include "dns.hh"
#include "dnspcap.hh"
#include "dnsparser.hh"
+#include "protobuf.hh"
+#include "uuid-utils.hh"
#include "statbag.hh"
StatBag S;
-static void addRRs(const char* packet, const size_t len, PBDNSMessage_DNSResponse* response)
-try
-{
- if (len < sizeof(struct dnsheader))
- return;
-
- const struct dnsheader* dh = (const struct dnsheader*) packet;
-
- if (ntohs(dh->ancount) == 0)
- return;
-
- if (ntohs(dh->qdcount) == 0)
- return;
-
- vector<uint8_t> content(len - sizeof(dnsheader));
- copy(packet + sizeof(dnsheader), packet + len, content.begin());
- PacketReader pr(content);
-
- size_t idx = 0;
- DNSName rrname;
- uint16_t qdcount = ntohs(dh->qdcount);
- uint16_t ancount = ntohs(dh->ancount);
- uint16_t rrtype;
- uint16_t rrclass;
- string blob;
- struct dnsrecordheader ah;
-
- rrname = pr.getName();
- rrtype = pr.get16BitInt();
- rrclass = pr.get16BitInt();
-
- /* consume remaining qd if any */
- if (qdcount > 1) {
- for(idx = 1; idx < qdcount; idx++) {
- rrname = pr.getName();
- rrtype = pr.get16BitInt();
- rrclass = pr.get16BitInt();
- (void) rrtype;
- (void) rrclass;
- }
- }
-
- /* parse AN */
- for (idx = 0; idx < ancount; idx++) {
- rrname = pr.getName();
- pr.getDnsrecordheader(ah);
-
- pr.xfrBlob(blob);
- if (ah.d_type == QType::A || ah.d_type == QType::AAAA) {
- PBDNSMessage_DNSResponse_DNSRR* rr = response->add_rrs();
- if (rr) {
- rr->set_name(rrname.toString());
- rr->set_type(ah.d_type);
- rr->set_class_(ah.d_class);
- rr->set_ttl(ah.d_ttl);
- rr->set_rdata(blob.c_str(), blob.length());
- }
- }
- }
-}
-catch(const std::exception& e)
-{
- cerr<<"Error parsing response records: "<<e.what()<<endl;
-}
-catch(const PDNSException& e)
-{
- cerr<<"Error parsing response records: "<<e.reason<<endl;
-}
-
-void usage()
+static void usage()
{
cerr<<"This program reads DNS queries and responses from a PCAP file and stores them into our protobuf format."<<endl;
cerr<<"Usage: dnspcap2protobuf PCAPFILE OUTFILE"<<endl;
if(argc==4)
ind=atoi(argv[3]);
- std::map<uint16_t,boost::uuids::uuid> ids;
- boost::uuids::random_generator uuidGenerator;
+ std::map<uint16_t,std::pair<boost::uuids::uuid,struct timeval> > ids;
try {
while (pr.getUDPPacket()) {
const dnsheader* dh=(dnsheader*)pr.d_payload;
continue;
}
- PBDNSMessage message;
- message.set_timesec(pr.d_pheader.ts.tv_sec);
- message.set_timeusec(pr.d_pheader.ts.tv_usec);
- message.set_id(ntohs(dh->id));
- message.set_type(dh->qr ? PBDNSMessage_Type_DNSResponseType : PBDNSMessage_Type_DNSQueryType);
+ boost::uuids::uuid uniqueId;
+ struct timeval queryTime = { 0, 0 };
+ bool hasQueryTime = false;
+ if (!dh->qr) {
+ queryTime.tv_sec = pr.d_pheader.ts.tv_sec;
+ queryTime.tv_usec = pr.d_pheader.ts.tv_usec;
+ uniqueId = getUniqueID();
+ ids[dh->id] = std::make_pair(uniqueId, queryTime);
+ }
+ else {
+ const auto& it = ids.find(dh->id);
+ if (it != ids.end()) {
+ uniqueId = it->second.first;
+ queryTime = it->second.second;
+ hasQueryTime = true;
+ }
+ else {
+ uniqueId = getUniqueID();
+ }
+ }
+
const ComboAddress requestor = dh->qr ? pr.getDest() : pr.getSource();
const ComboAddress responder = dh->qr ? pr.getSource() : pr.getDest();
-
*((char*)&requestor.sin4.sin_addr.s_addr)|=ind;
*((char*)&responder.sin4.sin_addr.s_addr)|=ind;
- message.set_socketfamily(requestor.sin4.sin_family == AF_INET ? PBDNSMessage_SocketFamily_INET : PBDNSMessage_SocketFamily_INET6);
- // we handle UDP packets only for now
- message.set_socketprotocol(PBDNSMessage_SocketProtocol_UDP);
- if (requestor.sin4.sin_family == AF_INET) {
- message.set_from(&requestor.sin4.sin_addr.s_addr, sizeof(requestor.sin4.sin_addr.s_addr));
- }
- else if (requestor.sin4.sin_family == AF_INET6) {
- message.set_from(&requestor.sin6.sin6_addr.s6_addr, sizeof(requestor.sin6.sin6_addr.s6_addr));
- }
- if (responder.sin4.sin_family == AF_INET) {
- message.set_to(&responder.sin4.sin_addr.s_addr, sizeof(responder.sin4.sin_addr.s_addr));
- }
- else if (responder.sin4.sin_family == AF_INET6) {
- message.set_to(&responder.sin6.sin6_addr.s6_addr, sizeof(responder.sin6.sin6_addr.s6_addr));
- }
- message.set_inbytes(pr.d_len);
- PBDNSMessage_DNSQuestion* question = message.mutable_question();
- PBDNSMessage_DNSResponse* response = message.mutable_response();
+ DNSProtoBufMessage message(dh->qr ? DNSProtoBufMessage::DNSProtoBufMessageType::Response : DNSProtoBufMessage::DNSProtoBufMessageType::Query, uniqueId, &requestor, &responder, qname, qtype, qclass, dh->id, false, pr.d_len);
+ message.setTime(pr.d_pheader.ts.tv_sec, pr.d_pheader.ts.tv_usec);
- if (!dh->qr) {
- boost::uuids::uuid uniqueId = uuidGenerator();
- ids[dh->id] = uniqueId;
- std::string* messageId = message.mutable_messageid();
- messageId->resize(uniqueId.size());
- std::copy(uniqueId.begin(), uniqueId.end(), messageId->begin());
- }
- else {
- const auto& it = ids.find(dh->id);
- if (it != ids.end()) {
- std::string* messageId = message.mutable_messageid();
- messageId->resize(it->second.size());
- std::copy(it->second.begin(), it->second.end(), messageId->begin());
+ if (dh->qr) {
+ message.setResponseCode(dh->rcode);
+ if (hasQueryTime) {
+ message.setQueryTime(queryTime.tv_sec, queryTime.tv_usec);
}
- response->set_rcode(dh->rcode);
- addRRs((const char*) dh, pr.d_len, response);
+ try {
+ message.addRRsFromPacket((const char*) dh, pr.d_len, true);
+ }
+ catch(std::exception& e)
+ {
+ cerr<<"Error parsing response records: "<<e.what()<<endl;
+ }
+ catch(const PDNSException& e)
+ {
+ cerr<<"Error parsing response records: "<<e.reason<<endl;
+ }
}
- question->set_qname(qname.toString());
- question->set_qtype(qtype);
- question->set_qclass(qclass);
-
std::string str;
- //cerr<<message.DebugString()<<endl;
- message.SerializeToString(&str);
+ message.serialize(str);
+
uint16_t mlen = htons(str.length());
fwrite(&mlen, 1, sizeof(mlen), fp);
fwrite(str.c_str(), 1, str.length(), fp);