]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnspcap2protobuf.cc
hopefully fix build without protobuf on travis
[thirdparty/pdns.git] / pdns / dnspcap2protobuf.cc
CommitLineData
f9cad4da
RG
1#include <boost/uuid/uuid.hpp>
2#include <boost/uuid/uuid_generators.hpp>
3#include <boost/uuid/uuid_io.hpp>
4
f483cc6d
RG
5#include "dnsmessage.pb.h"
6#include "iputils.hh"
7#include "misc.hh"
8#include "dns.hh"
9#include "dnspcap.hh"
10#include "dnsparser.hh"
11
12#include "statbag.hh"
13StatBag S;
14
15static void addRRs(const char* packet, const size_t len, PBDNSMessage_DNSResponse& response)
1b448d84 16try
f483cc6d
RG
17{
18 if (len < sizeof(struct dnsheader))
19 return;
20
21 const struct dnsheader* dh = (const struct dnsheader*) packet;
22
23 if (ntohs(dh->ancount) == 0)
24 return;
25
26 if (ntohs(dh->qdcount) == 0)
27 return;
28
29 vector<uint8_t> content(len - sizeof(dnsheader));
30 copy(packet + sizeof(dnsheader), packet + len, content.begin());
31 PacketReader pr(content);
32
33 size_t idx = 0;
34 DNSName rrname;
35 uint16_t qdcount = ntohs(dh->qdcount);
36 uint16_t ancount = ntohs(dh->ancount);
37 uint16_t rrtype;
38 uint16_t rrclass;
39 string blob;
40 struct dnsrecordheader ah;
41
42 rrname = pr.getName();
43 rrtype = pr.get16BitInt();
44 rrclass = pr.get16BitInt();
45
46 /* consume remaining qd if any */
47 if (qdcount > 1) {
48 for(idx = 1; idx < qdcount; idx++) {
49 rrname = pr.getName();
50 rrtype = pr.get16BitInt();
51 rrclass = pr.get16BitInt();
52 (void) rrtype;
53 (void) rrclass;
54 }
55 }
56
57 /* parse AN */
58 for (idx = 0; idx < ancount; idx++) {
59 rrname = pr.getName();
60 pr.getDnsrecordheader(ah);
61
62 pr.xfrBlob(blob);
63 if (ah.d_type == QType::A || ah.d_type == QType::AAAA) {
64 PBDNSMessage_DNSResponse_DNSRR* rr = response.add_rrs();
65 if (rr) {
66 rr->set_name(rrname.toString());
67 rr->set_type(ah.d_type);
68 rr->set_class_(ah.d_class);
69 rr->set_ttl(ah.d_ttl);
70 rr->set_rdata(blob.c_str(), blob.length());
71 }
72 }
73 }
74}
1b448d84 75catch(std::exception& e)
76{
77 cerr<<"Error parsing response records: "<<e.what()<<endl;
78}
f483cc6d
RG
79int main(int argc, char **argv)
80{
81 if(argc != 3) {
82 cerr<<"This program reads DNS queries and responses from a PCAP file and stores them into our protobuf format."<<endl;
83 cerr<<"Usage: "<<argv[0]<<" <PCAP file> <out file>"<<endl;
84 exit(EXIT_FAILURE);
85 }
86
87 PcapPacketReader pr(argv[1]);
88
89 FILE* fp = fopen(argv[2], "w");
90 if (!fp) {
91 cerr<<"Error opening output file "<<argv[2]<<": "<<strerror(errno)<<endl;
92 exit(EXIT_FAILURE);
93 }
f9cad4da
RG
94 std::map<uint16_t,boost::uuids::uuid> ids;
95 boost::uuids::random_generator uuidGenerator;
f483cc6d
RG
96 while (pr.getUDPPacket()) {
97 const dnsheader* dh=(dnsheader*)pr.d_payload;
98 if (!dh->qdcount)
99 continue;
100
4c2862d4
RG
101 if (pr.d_len < sizeof(dnsheader))
102 continue;
103
f483cc6d
RG
104 uint16_t qtype, qclass;
105 DNSName qname;
106 try {
107 qname=DNSName((const char*)pr.d_payload, pr.d_len, sizeof(dnsheader), false, &qtype, &qclass);
108 }
109 catch(const std::exception& e) {
110 cerr<<"Error while parsing qname: "<<e.what()<<endl;
111 continue;
112 }
113
114 PBDNSMessage message;
115 message.set_timesec(pr.d_pheader.ts.tv_sec);
116 message.set_timeusec(pr.d_pheader.ts.tv_usec);
117 message.set_id(ntohs(dh->id));
118 message.set_type(dh->qr ? PBDNSMessage_Type_DNSResponseType : PBDNSMessage_Type_DNSQueryType);
119 const ComboAddress source = pr.getSource();
120 const ComboAddress dest = pr.getDest();
121 message.set_socketfamily(source.sin4.sin_family == AF_INET ? PBDNSMessage_SocketFamily_INET : PBDNSMessage_SocketFamily_INET6);
122 // we handle UDP packets only for now
123 message.set_socketprotocol(PBDNSMessage_SocketProtocol_UDP);
124 if (source.sin4.sin_family == AF_INET) {
125 message.set_from(&source.sin4.sin_addr.s_addr, sizeof(source.sin4.sin_addr.s_addr));
126 }
127 else if (source.sin4.sin_family == AF_INET6) {
128 message.set_from(&source.sin6.sin6_addr.s6_addr, sizeof(source.sin6.sin6_addr.s6_addr));
129 }
130 if (dest.sin4.sin_family == AF_INET) {
131 message.set_to(&dest.sin4.sin_addr.s_addr, sizeof(dest.sin4.sin_addr.s_addr));
132 }
133 else if (dest.sin4.sin_family == AF_INET6) {
134 message.set_to(&dest.sin6.sin6_addr.s6_addr, sizeof(dest.sin6.sin6_addr.s6_addr));
135 }
136 message.set_inbytes(pr.d_len);
137
138 PBDNSMessage_DNSQuestion question;
139 PBDNSMessage_DNSResponse response;
140 if (!dh->qr) {
f9cad4da
RG
141 boost::uuids::uuid uniqueId = uuidGenerator();
142 ids[dh->id] = uniqueId;
143 message.set_messageid(boost::uuids::to_string(uniqueId));
f483cc6d
RG
144 question.set_qname(qname.toString());
145 question.set_qtype(qtype);
146 question.set_qclass(qclass);
147 message.set_allocated_question(&question);
148 }
149 else {
f9cad4da
RG
150 const auto& it = ids.find(dh->id);
151 if (it != ids.end()) {
152 message.set_messageid(boost::uuids::to_string(it->second));
153 }
f483cc6d
RG
154 response.set_rcode(dh->rcode);
155 addRRs((const char*) dh, pr.d_len, response);
156 message.set_allocated_response(&response);
157 }
158
159 std::string str;
f9cad4da 160 //cerr<<message.DebugString()<<endl;
f483cc6d 161 message.SerializeToString(&str);
1b448d84 162 uint16_t mlen = htons(str.length());
f483cc6d
RG
163 fwrite(&mlen, 1, sizeof(mlen), fp);
164 fwrite(str.c_str(), 1, str.length(), fp);
165 if (!dh->qr) {
166 message.release_question();
167 }
168 else {
169 message.release_response();
170 }
171 }
172 fclose(fp);
173}