]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnspcap2protobuf.cc
Meson: Separate test files from common files
[thirdparty/pdns.git] / pdns / dnspcap2protobuf.cc
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 */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include <boost/uuid/uuid.hpp>
26
27 #include "iputils.hh"
28 #include "misc.hh"
29 #include "dns.hh"
30 #include "dnspcap.hh"
31 #include "dnsparser.hh"
32 #include "protozero.hh"
33 #include "uuid-utils.hh"
34
35 #include "statbag.hh"
36 StatBag S;
37
38 static void usage()
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
44 int main(int argc, char **argv)
45 try {
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
58 if(argc < 3) {
59 usage();
60 exit(EXIT_FAILURE);
61 }
62
63
64 PcapPacketReader pr(argv[1]);
65
66 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): it's argv..
67 auto filePtr = pdns::openFileForWriting(argv[2], 0600, true, false);
68 if (!filePtr) {
69 auto error = errno;
70 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): it's argv..
71 cerr<<"Error opening output file "<<argv[2]<<": "<<stringerror(error)<<endl;
72 exit(EXIT_FAILURE);
73 }
74
75 int ind=0;
76 if(argc==4)
77 ind=atoi(argv[3]);
78
79 std::map<uint16_t,std::pair<boost::uuids::uuid,struct timeval> > ids;
80 std::string pbBuffer;
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 }
102
103 boost::uuids::uuid uniqueId;
104 struct timeval queryTime = { 0, 0 };
105 bool hasQueryTime = false;
106 if (!dh->qr) {
107 queryTime.tv_sec = pr.d_pheader.ts.tv_sec;
108 queryTime.tv_usec = pr.d_pheader.ts.tv_usec;
109 uniqueId = getUniqueID();
110 ids[dh->id] = {uniqueId, queryTime};
111 }
112 else {
113 const auto& it = ids.find(dh->id);
114 if (it != ids.end()) {
115 uniqueId = it->second.first;
116 queryTime = it->second.second;
117 hasQueryTime = true;
118 }
119 else {
120 uniqueId = getUniqueID();
121 }
122 }
123
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
129 pbBuffer.clear();
130 pdns::ProtoZero::Message pbMessage(pbBuffer);
131 pbMessage.setType(dh->qr ? pdns::ProtoZero::Message::MessageType::DNSResponseType : pdns::ProtoZero::Message::MessageType::DNSQueryType);
132 pbMessage.setRequest(uniqueId, requestor, responder, qname, qtype, qclass, dh->id, pdns::ProtoZero::Message::TransportProtocol::UDP, pr.d_len);
133 pbMessage.setTime(pr.d_pheader.ts.tv_sec, pr.d_pheader.ts.tv_usec);
134
135 if (dh->qr) {
136 pbMessage.startResponse();
137 pbMessage.setResponseCode(dh->rcode);
138 if (hasQueryTime) {
139 pbMessage.setQueryTime(queryTime.tv_sec, queryTime.tv_usec);
140 }
141
142 try {
143 pbMessage.addRRsFromPacket((const char*) dh, pr.d_len, true);
144 }
145 catch (const std::exception& e)
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 }
154
155 uint16_t mlen = htons(pbBuffer.length());
156 fwrite(&mlen, 1, sizeof(mlen), filePtr.get());
157 fwrite(pbBuffer.c_str(), 1, pbBuffer.length(), filePtr.get());
158 }
159 }
160 catch (const std::exception& e) {
161 cerr<<"Error while parsing the PCAP file: "<<e.what()<<endl;
162 exit(EXIT_FAILURE);
163 }
164 }
165 catch(const std::exception& e) {
166 cerr<<"Error opening PCAP file: "<<e.what()<<endl;
167 exit(EXIT_FAILURE);
168 }