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