]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnspcap2protobuf.cc
Merge pull request #14021 from Habbie/auth-lua-join-whitespace
[thirdparty/pdns.git] / pdns / dnspcap2protobuf.cc
CommitLineData
12471842
PL
1/*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
a4a74820
PL
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
f9cad4da 25#include <boost/uuid/uuid.hpp>
f9cad4da 26
f483cc6d
RG
27#include "iputils.hh"
28#include "misc.hh"
29#include "dns.hh"
30#include "dnspcap.hh"
31#include "dnsparser.hh"
471c63d0 32#include "protozero.hh"
d61aa945 33#include "uuid-utils.hh"
f483cc6d
RG
34
35#include "statbag.hh"
36StatBag S;
37
d9d3f9c1 38static void usage()
a4a74820
PL
39{
40 cerr<<"This program reads DNS queries and responses from a PCAP file and stores them into our protobuf format."<<endl;
41 cerr<<"Usage: dnspcap2protobuf PCAPFILE OUTFILE"<<endl;
42}
43
f483cc6d 44int main(int argc, char **argv)
d7729968 45try {
a4a74820
PL
46 for(int n=1 ; n < argc; ++n) {
47 if ((string) argv[n] == "--help") {
48 usage();
49 return EXIT_SUCCESS;
50 }
51
52 if ((string) argv[n] == "--version") {
53 cerr<<"dnspcap2protobuf "<<VERSION<<endl;
54 return EXIT_SUCCESS;
55 }
56 }
57
2718cbf4 58 if(argc < 3) {
a4a74820 59 usage();
f483cc6d
RG
60 exit(EXIT_FAILURE);
61 }
62
a4a74820 63
f483cc6d
RG
64 PcapPacketReader pr(argv[1]);
65
6e58535e 66 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): it's argv..
b1564d45 67 auto filePtr = pdns::openFileForWriting(argv[2], 0600, true, false);
114b8796 68 if (!filePtr) {
b1564d45 69 auto error = errno;
6e58535e 70 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): it's argv..
b1564d45 71 cerr<<"Error opening output file "<<argv[2]<<": "<<stringerror(error)<<endl;
f483cc6d
RG
72 exit(EXIT_FAILURE);
73 }
2718cbf4 74
75 int ind=0;
76 if(argc==4)
77 ind=atoi(argv[3]);
78
58307a85 79 std::map<uint16_t,std::pair<boost::uuids::uuid,struct timeval> > ids;
471c63d0 80 std::string pbBuffer;
d7729968
RG
81 try {
82 while (pr.getUDPPacket()) {
83 const dnsheader* dh=(dnsheader*)pr.d_payload;
84 if (!dh->qdcount)
85 continue;
86
87 if (pr.d_len < sizeof(dnsheader))
88 continue;
89
90 if(!dh->rd)
91 continue;
92
93 uint16_t qtype, qclass;
94 DNSName qname;
95 try {
96 qname=DNSName((const char*)pr.d_payload, pr.d_len, sizeof(dnsheader), false, &qtype, &qclass);
97 }
98 catch(const std::exception& e) {
99 cerr<<"Error while parsing qname: "<<e.what()<<endl;
100 continue;
101 }
f483cc6d 102
d9d3f9c1 103 boost::uuids::uuid uniqueId;
58307a85
RG
104 struct timeval queryTime = { 0, 0 };
105 bool hasQueryTime = false;
d7729968 106 if (!dh->qr) {
58307a85
RG
107 queryTime.tv_sec = pr.d_pheader.ts.tv_sec;
108 queryTime.tv_usec = pr.d_pheader.ts.tv_usec;
d61aa945 109 uniqueId = getUniqueID();
e32a8d46 110 ids[dh->id] = {uniqueId, queryTime};
d7729968
RG
111 }
112 else {
113 const auto& it = ids.find(dh->id);
114 if (it != ids.end()) {
58307a85
RG
115 uniqueId = it->second.first;
116 queryTime = it->second.second;
117 hasQueryTime = true;
d9d3f9c1
RG
118 }
119 else {
d61aa945 120 uniqueId = getUniqueID();
d7729968 121 }
f9cad4da 122 }
ec469dd7 123
d9d3f9c1
RG
124 const ComboAddress requestor = dh->qr ? pr.getDest() : pr.getSource();
125 const ComboAddress responder = dh->qr ? pr.getSource() : pr.getDest();
126 *((char*)&requestor.sin4.sin_addr.s_addr)|=ind;
127 *((char*)&responder.sin4.sin_addr.s_addr)|=ind;
128
471c63d0
RG
129 pbBuffer.clear();
130 pdns::ProtoZero::Message pbMessage(pbBuffer);
89addb82 131 pbMessage.setType(dh->qr ? pdns::ProtoZero::Message::MessageType::DNSResponseType : pdns::ProtoZero::Message::MessageType::DNSQueryType);
cffd3a17 132 pbMessage.setRequest(uniqueId, requestor, responder, qname, qtype, qclass, dh->id, pdns::ProtoZero::Message::TransportProtocol::UDP, pr.d_len);
471c63d0 133 pbMessage.setTime(pr.d_pheader.ts.tv_sec, pr.d_pheader.ts.tv_usec);
d9d3f9c1
RG
134
135 if (dh->qr) {
471c63d0
RG
136 pbMessage.startResponse();
137 pbMessage.setResponseCode(dh->rcode);
58307a85 138 if (hasQueryTime) {
471c63d0 139 pbMessage.setQueryTime(queryTime.tv_sec, queryTime.tv_usec);
58307a85
RG
140 }
141
d9d3f9c1 142 try {
471c63d0 143 pbMessage.addRRsFromPacket((const char*) dh, pr.d_len, true);
d9d3f9c1 144 }
471c63d0 145 catch (const std::exception& e)
d9d3f9c1
RG
146 {
147 cerr<<"Error parsing response records: "<<e.what()<<endl;
148 }
149 catch(const PDNSException& e)
150 {
151 cerr<<"Error parsing response records: "<<e.reason<<endl;
152 }
153 }
3bde188c 154
471c63d0 155 uint16_t mlen = htons(pbBuffer.length());
114b8796
RG
156 fwrite(&mlen, 1, sizeof(mlen), filePtr.get());
157 fwrite(pbBuffer.c_str(), 1, pbBuffer.length(), filePtr.get());
d7729968
RG
158 }
159 }
160 catch (const std::exception& e) {
161 cerr<<"Error while parsing the PCAP file: "<<e.what()<<endl;
d7729968 162 exit(EXIT_FAILURE);
f483cc6d 163 }
f483cc6d 164}
d7729968
RG
165catch(const std::exception& e) {
166 cerr<<"Error opening PCAP file: "<<e.what()<<endl;
167 exit(EXIT_FAILURE);
168}