]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnspcap2protobuf.cc
Merge pull request #4079 from rgacogne/dnsdist-remotelog-no-protobuf
[thirdparty/pdns.git] / pdns / dnspcap2protobuf.cc
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 #include <boost/uuid/uuid.hpp>
5 #include <boost/uuid/uuid_generators.hpp>
6
7 #include "iputils.hh"
8 #include "misc.hh"
9 #include "dns.hh"
10 #include "dnspcap.hh"
11 #include "dnsparser.hh"
12 #include "protobuf.hh"
13
14 #include "statbag.hh"
15 StatBag S;
16
17 static void usage()
18 {
19 cerr<<"This program reads DNS queries and responses from a PCAP file and stores them into our protobuf format."<<endl;
20 cerr<<"Usage: dnspcap2protobuf PCAPFILE OUTFILE"<<endl;
21 }
22
23 int main(int argc, char **argv)
24 try {
25 for(int n=1 ; n < argc; ++n) {
26 if ((string) argv[n] == "--help") {
27 usage();
28 return EXIT_SUCCESS;
29 }
30
31 if ((string) argv[n] == "--version") {
32 cerr<<"dnspcap2protobuf "<<VERSION<<endl;
33 return EXIT_SUCCESS;
34 }
35 }
36
37 if(argc < 3) {
38 usage();
39 exit(EXIT_FAILURE);
40 }
41
42
43 PcapPacketReader pr(argv[1]);
44
45 FILE* fp = fopen(argv[2], "w");
46 if (!fp) {
47 cerr<<"Error opening output file "<<argv[2]<<": "<<strerror(errno)<<endl;
48 exit(EXIT_FAILURE);
49 }
50
51 int ind=0;
52 if(argc==4)
53 ind=atoi(argv[3]);
54
55 std::map<uint16_t,std::pair<boost::uuids::uuid,struct timeval> > ids;
56 boost::uuids::random_generator uuidGenerator;
57 try {
58 while (pr.getUDPPacket()) {
59 const dnsheader* dh=(dnsheader*)pr.d_payload;
60 if (!dh->qdcount)
61 continue;
62
63 if (pr.d_len < sizeof(dnsheader))
64 continue;
65
66 if(!dh->rd)
67 continue;
68
69 uint16_t qtype, qclass;
70 DNSName qname;
71 try {
72 qname=DNSName((const char*)pr.d_payload, pr.d_len, sizeof(dnsheader), false, &qtype, &qclass);
73 }
74 catch(const std::exception& e) {
75 cerr<<"Error while parsing qname: "<<e.what()<<endl;
76 continue;
77 }
78
79 boost::uuids::uuid uniqueId;
80 struct timeval queryTime = { 0, 0 };
81 bool hasQueryTime = false;
82 if (!dh->qr) {
83 queryTime.tv_sec = pr.d_pheader.ts.tv_sec;
84 queryTime.tv_usec = pr.d_pheader.ts.tv_usec;
85 uniqueId = uuidGenerator();
86 ids[dh->id] = std::make_pair(uniqueId, queryTime);
87 }
88 else {
89 const auto& it = ids.find(dh->id);
90 if (it != ids.end()) {
91 uniqueId = it->second.first;
92 queryTime = it->second.second;
93 hasQueryTime = true;
94 }
95 else {
96 uniqueId = uuidGenerator();
97 }
98 }
99
100 const ComboAddress requestor = dh->qr ? pr.getDest() : pr.getSource();
101 const ComboAddress responder = dh->qr ? pr.getSource() : pr.getDest();
102 *((char*)&requestor.sin4.sin_addr.s_addr)|=ind;
103 *((char*)&responder.sin4.sin_addr.s_addr)|=ind;
104
105 DNSProtoBufMessage message(dh->qr ? DNSProtoBufMessage::DNSProtoBufMessageType::Response : DNSProtoBufMessage::DNSProtoBufMessageType::Query, uniqueId, &requestor, &responder, qname, qtype, qclass, dh->id, false, pr.d_len);
106 message.setTime(pr.d_pheader.ts.tv_sec, pr.d_pheader.ts.tv_usec);
107
108 if (dh->qr) {
109 message.setResponseCode(dh->rcode);
110 if (hasQueryTime) {
111 message.setQueryTime(queryTime.tv_sec, queryTime.tv_usec);
112 }
113
114 try {
115 message.addRRsFromPacket((const char*) dh, pr.d_len);
116 }
117 catch(std::exception& e)
118 {
119 cerr<<"Error parsing response records: "<<e.what()<<endl;
120 }
121 catch(const PDNSException& e)
122 {
123 cerr<<"Error parsing response records: "<<e.reason<<endl;
124 }
125 }
126
127 std::string str;
128 message.serialize(str);
129
130 uint16_t mlen = htons(str.length());
131 fwrite(&mlen, 1, sizeof(mlen), fp);
132 fwrite(str.c_str(), 1, str.length(), fp);
133 }
134 }
135 catch (const std::exception& e) {
136 cerr<<"Error while parsing the PCAP file: "<<e.what()<<endl;
137 fclose(fp);
138 exit(EXIT_FAILURE);
139 }
140
141 fclose(fp);
142 }
143 catch(const std::exception& e) {
144 cerr<<"Error opening PCAP file: "<<e.what()<<endl;
145 exit(EXIT_FAILURE);
146 }