]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnspcap.cc
Merge pull request #3797 from pieterlexis/issue-270-Version-for-tools
[thirdparty/pdns.git] / pdns / dnspcap.cc
1 #define __FAVOR_BSD
2 #ifdef HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5 #include "dnspcap.hh"
6 #include <boost/format.hpp>
7 #include <fcntl.h>
8
9 #include "namespaces.hh"
10 PcapPacketReader::PcapPacketReader(const string& fname) : d_fname(fname)
11 {
12 d_fp=fopen(fname.c_str(),"r");
13 if(!d_fp)
14 unixDie("Unable to open file " + fname);
15
16 int flags=fcntl(fileno(d_fp),F_GETFL,0);
17 fcntl(fileno(d_fp), F_SETFL,flags&(~O_NONBLOCK)); // bsd needs this in stdin (??)
18
19 checkedFread(&d_pfh);
20
21 if(d_pfh.magic != 2712847316UL)
22 throw runtime_error((format("PCAP file %s has bad magic %x, should be %x") % fname % d_pfh.magic % 2712847316UL).str());
23
24 if( d_pfh.linktype==1) {
25 d_skipMediaHeader=sizeof(struct ether_header);
26 }
27 else if(d_pfh.linktype==101) {
28 d_skipMediaHeader=0;
29 }
30 else if(d_pfh.linktype==113) {
31 d_skipMediaHeader=16;
32 }
33 else throw runtime_error((format("Unsupported link type %d") % d_pfh.linktype).str());
34
35 d_runts = d_oversized = d_correctpackets = d_nonetheripudp = 0;
36 }
37
38 PcapPacketReader::~PcapPacketReader()
39 {
40 fclose(d_fp);
41 }
42
43
44 void PcapPacketReader::checkedFreadSize(void* ptr, size_t size)
45 {
46 int ret=fread(ptr, 1, size, d_fp);
47 if(ret < 0)
48 unixDie( (format("Error reading %d bytes from %s") % size % d_fname).str());
49
50 if(!ret)
51 throw EofException();
52
53 if((size_t)ret != size)
54 throw EofException((format("Incomplete read from '%s', got only %d bytes") % d_fname % ret).str());
55 }
56
57 bool PcapPacketReader::getUDPPacket()
58 try
59 {
60 for(;;) {
61 checkedFread(&d_pheader);
62 if(!d_pheader.caplen) {
63 d_runts++;
64 continue;
65 }
66
67 if(d_pheader.caplen > sizeof(d_buffer)) {
68 d_oversized++;
69 throw runtime_error((format("Can't handle a %d byte packet, have space for %d") % d_pheader.caplen % sizeof(d_buffer)).str());
70 }
71
72 checkedFreadSize(d_buffer, d_pheader.caplen);
73
74 if(d_pheader.caplen!=d_pheader.len) {
75 d_runts++;
76 continue;
77 }
78
79 d_ether=reinterpret_cast<struct ether_header*>(d_buffer);
80 d_lcc=reinterpret_cast<struct pdns_lcc_header*>(d_buffer);
81
82 d_ip=reinterpret_cast<struct ip*>(d_buffer + d_skipMediaHeader);
83 d_ip6=reinterpret_cast<struct ip6_hdr*>(d_buffer + d_skipMediaHeader);
84 uint16_t contentCode=0;
85 if(d_pfh.linktype==1)
86 contentCode=ntohs(d_ether->ether_type);
87 else if(d_pfh.linktype==101) {
88 if(d_ip->ip_v==4)
89 contentCode = 0x0800;
90 else
91 contentCode = 0x86dd;
92 }
93 else if(d_pfh.linktype==113)
94 contentCode=ntohs(d_lcc->lcc_protocol);
95
96 if(contentCode==0x0800 && d_ip->ip_p==17) { // udp
97 d_udp=reinterpret_cast<const struct udphdr*>(d_buffer + d_skipMediaHeader + 4 * d_ip->ip_hl);
98 d_payload = (unsigned char*)d_udp + sizeof(struct udphdr);
99 d_len = ntohs(d_udp->uh_ulen) - sizeof(struct udphdr);
100 if((const char*)d_payload + d_len > d_buffer + d_pheader.caplen) {
101 d_runts++;
102 continue;
103 }
104 d_correctpackets++;
105 return true;
106 }
107 if(contentCode==0x86dd && d_ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt==17) { // udpv6, we ignore anything with extension hdr
108 d_udp=reinterpret_cast<const struct udphdr*>(d_buffer + d_skipMediaHeader + sizeof(struct ip6_hdr));
109 d_payload = (unsigned char*)d_udp + sizeof(struct udphdr);
110 d_len = ntohs(d_udp->uh_ulen) - sizeof(struct udphdr);
111 if((const char*)d_payload + d_len > d_buffer + d_pheader.caplen) {
112 d_runts++;
113 continue;
114 }
115
116 d_correctpackets++;
117 return true;
118 }
119 else {
120 d_nonetheripudp++;
121 }
122 }
123 }
124 catch(EofException) {
125 return false;
126 }
127
128 ComboAddress PcapPacketReader::getSource() const
129 {
130 ComboAddress ret;
131 if(d_ip->ip_v == 4) {
132 ret.sin4.sin_family = AF_INET;
133 ret.sin4.sin_addr = d_ip->ip_src;
134 ret.sin4.sin_port = d_udp->uh_sport; // should deal with TCP too!
135 } else {
136 ret.sin6.sin6_family = AF_INET6;
137 ret.sin6.sin6_addr = d_ip6->ip6_src;
138 ret.sin6.sin6_port = d_udp->uh_sport; // should deal with TCP too!
139 }
140 return ret;
141 }
142
143 ComboAddress PcapPacketReader::getDest() const
144 {
145 ComboAddress ret;
146 if(d_ip->ip_v == 4) {
147 ret.sin4.sin_family = AF_INET;
148 ret.sin4.sin_addr = d_ip->ip_dst;
149 ret.sin4.sin_port = d_udp->uh_dport; // should deal with TCP too!
150 } else {
151 ret.sin6.sin6_family = AF_INET6;
152 ret.sin6.sin6_addr = d_ip6->ip6_dst;
153 ret.sin6.sin6_port = d_udp->uh_dport; // should deal with TCP too!
154 }
155 return ret;
156 }
157
158 PcapPacketWriter::PcapPacketWriter(const string& fname, PcapPacketReader& ppr) : d_fname(fname), d_ppr(ppr)
159 {
160 d_fp=fopen(fname.c_str(),"w");
161 if(!d_fp)
162 unixDie("Unable to open file");
163
164 int flags=fcntl(fileno(d_fp),F_GETFL,0);
165 fcntl(fileno(d_fp), F_SETFL,flags&(~O_NONBLOCK)); // bsd needs this in stdin (??)
166
167 fwrite(&ppr.d_pfh, 1, sizeof(ppr.d_pfh), d_fp);
168 }
169
170 void PcapPacketWriter::write()
171 {
172 fwrite(&d_ppr.d_pheader, 1, sizeof(d_ppr.d_pheader), d_fp);
173 fwrite(d_ppr.d_buffer, 1, d_ppr.d_pheader.caplen, d_fp);
174 }
175
176 PcapPacketWriter::~PcapPacketWriter()
177 {
178 fclose(d_fp);
179 }