]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnspcap.cc
Support LOOP link type
[thirdparty/pdns.git] / pdns / dnspcap.cc
CommitLineData
12471842
PL
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 */
0b86fb59 22#define __FAVOR_BSD
870a0fe4
AT
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
ab06937b 26#include "dnspcap.hh"
11212b81 27#include <boost/format.hpp>
0b86fb59 28#include <fcntl.h>
ab06937b 29
61b26744 30#include "namespaces.hh"
ab06937b
BH
31PcapPacketReader::PcapPacketReader(const string& fname) : d_fname(fname)
32{
33 d_fp=fopen(fname.c_str(),"r");
34 if(!d_fp)
27789bef 35 unixDie("Unable to open file " + fname);
ab06937b 36
0b86fb59
BH
37 int flags=fcntl(fileno(d_fp),F_GETFL,0);
38 fcntl(fileno(d_fp), F_SETFL,flags&(~O_NONBLOCK)); // bsd needs this in stdin (??)
ab06937b
BH
39
40 checkedFread(&d_pfh);
41
42 if(d_pfh.magic != 2712847316UL)
43 throw runtime_error((format("PCAP file %s has bad magic %x, should be %x") % fname % d_pfh.magic % 2712847316UL).str());
44
2acf3098
BH
45 if( d_pfh.linktype==1) {
46 d_skipMediaHeader=sizeof(struct ether_header);
8bfd2560 47 }
70e6f59d
OM
48 else if( d_pfh.linktype==12) { // LOOP
49 d_skipMediaHeader=4;
50 }
8bfd2560 51 else if(d_pfh.linktype==101) {
52 d_skipMediaHeader=0;
53 }
54 else if(d_pfh.linktype==113) {
2acf3098
BH
55 d_skipMediaHeader=16;
56 }
57 else throw runtime_error((format("Unsupported link type %d") % d_pfh.linktype).str());
ab06937b 58
11212b81 59 d_runts = d_oversized = d_correctpackets = d_nonetheripudp = 0;
ab06937b
BH
60}
61
11212b81 62PcapPacketReader::~PcapPacketReader()
ab06937b
BH
63{
64 fclose(d_fp);
65}
66
67
68void PcapPacketReader::checkedFreadSize(void* ptr, size_t size)
69{
70 int ret=fread(ptr, 1, size, d_fp);
71 if(ret < 0)
72 unixDie( (format("Error reading %d bytes from %s") % size % d_fname).str());
73
74 if(!ret)
75 throw EofException();
76
77 if((size_t)ret != size)
78 throw EofException((format("Incomplete read from '%s', got only %d bytes") % d_fname % ret).str());
79}
80
81bool PcapPacketReader::getUDPPacket()
82try
83{
84 for(;;) {
85 checkedFread(&d_pheader);
d2d8cafd 86 if(!d_pheader.caplen) {
87 d_runts++;
e0333255 88 continue;
d2d8cafd 89 }
3042f1ba 90
ab06937b
BH
91 if(d_pheader.caplen > sizeof(d_buffer)) {
92 d_oversized++;
3042f1ba 93 throw runtime_error((format("Can't handle a %d byte packet, have space for %d") % d_pheader.caplen % sizeof(d_buffer)).str());
ab06937b 94 }
3042f1ba 95
ab06937b 96 checkedFreadSize(d_buffer, d_pheader.caplen);
3042f1ba 97
173dcfb0 98 if(d_pheader.caplen < d_pheader.len) {
3042f1ba
BH
99 d_runts++;
100 continue;
101 }
102
fe92c902
RG
103 if (d_pheader.caplen < d_skipMediaHeader) {
104 d_runts++;
105 continue;
106 }
2acf3098
BH
107
108 d_ip=reinterpret_cast<struct ip*>(d_buffer + d_skipMediaHeader);
bf32bff8 109 d_ip6=reinterpret_cast<struct ip6_hdr*>(d_buffer + d_skipMediaHeader);
49f61cba 110 uint16_t contentCode=0;
fe92c902
RG
111
112 if(d_pfh.linktype==1) {
113 if (d_pheader.caplen < sizeof(*d_ether)) {
114 d_runts++;
115 continue;
116 }
117 d_ether=reinterpret_cast<struct ether_header*>(d_buffer);
2acf3098 118 contentCode=ntohs(d_ether->ether_type);
fe92c902 119 }
70e6f59d
OM
120 else if(d_pfh.linktype == 12) { // LOOP
121 if (d_pheader.caplen < (d_skipMediaHeader + sizeof(*d_ip))) {
122 d_runts++;
123 continue;
124 }
125 if(d_ip->ip_v == 4)
126 contentCode = 0x0800;
127 else
128 contentCode = 0x86dd;
129 }
8bfd2560 130 else if(d_pfh.linktype==101) {
fe92c902
RG
131 if (d_pheader.caplen < (d_skipMediaHeader + sizeof(*d_ip))) {
132 d_runts++;
133 continue;
134 }
8bfd2560 135 if(d_ip->ip_v==4)
136 contentCode = 0x0800;
137 else
3ae047fe 138 contentCode = 0x86dd;
8bfd2560 139 }
fe92c902
RG
140 else if(d_pfh.linktype==113) {
141 if (d_pheader.caplen < sizeof(*d_lcc)) {
142 d_runts++;
143 continue;
144 }
145 d_lcc=reinterpret_cast<struct pdns_lcc_header*>(d_buffer);
2acf3098 146 contentCode=ntohs(d_lcc->lcc_protocol);
fe92c902 147 }
3042f1ba 148
b7a969f2 149 if(contentCode==0x0800 && (d_pheader.caplen >= (d_skipMediaHeader + sizeof(*d_ip))) && d_ip->ip_p==17) { // udp
fe92c902
RG
150 if (d_pheader.caplen < (d_skipMediaHeader + (4 * d_ip->ip_hl) + sizeof(*d_udp))) {
151 d_runts++;
152 continue;
153 }
2acf3098 154 d_udp=reinterpret_cast<const struct udphdr*>(d_buffer + d_skipMediaHeader + 4 * d_ip->ip_hl);
ab06937b 155 d_payload = (unsigned char*)d_udp + sizeof(struct udphdr);
0b86fb59 156 d_len = ntohs(d_udp->uh_ulen) - sizeof(struct udphdr);
fe92c902
RG
157 if (d_pheader.caplen < (d_skipMediaHeader + (4 * d_ip->ip_hl) + sizeof(*d_udp) + d_len)) {
158 d_runts++;
159 continue;
160 }
66afeb44 161 if((const char*)d_payload + d_len > d_buffer + d_pheader.caplen) {
162 d_runts++;
163 continue;
164 }
11212b81 165 d_correctpackets++;
ab06937b
BH
166 return true;
167 }
b7a969f2 168 else if(contentCode==0x86dd && (d_pheader.caplen >= (d_skipMediaHeader + sizeof(*d_ip6))) && d_ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt==17) { // udpv6, we ignore anything with extension hdr
fe92c902
RG
169 if (d_pheader.caplen < (d_skipMediaHeader + sizeof(struct ip6_hdr) + sizeof(struct udphdr))) {
170 d_runts++;
171 continue;
172 }
bf32bff8 173 d_udp=reinterpret_cast<const struct udphdr*>(d_buffer + d_skipMediaHeader + sizeof(struct ip6_hdr));
174 d_payload = (unsigned char*)d_udp + sizeof(struct udphdr);
175 d_len = ntohs(d_udp->uh_ulen) - sizeof(struct udphdr);
fe92c902
RG
176 if (d_pheader.caplen < (d_skipMediaHeader + sizeof(struct ip6_hdr) + sizeof(struct udphdr) + d_len)) {
177 d_runts++;
178 continue;
179 }
66afeb44 180 if((const char*)d_payload + d_len > d_buffer + d_pheader.caplen) {
181 d_runts++;
182 continue;
183 }
184
bf32bff8 185 d_correctpackets++;
186 return true;
187 }
11212b81
BH
188 else {
189 d_nonetheripudp++;
190 }
ab06937b
BH
191 }
192}
819861fa 193catch(const EofException&) {
ab06937b
BH
194 return false;
195}
196
a5d9353e 197ComboAddress PcapPacketReader::getSource() const
198{
199 ComboAddress ret;
200 if(d_ip->ip_v == 4) {
201 ret.sin4.sin_family = AF_INET;
202 ret.sin4.sin_addr = d_ip->ip_src;
203 ret.sin4.sin_port = d_udp->uh_sport; // should deal with TCP too!
204 } else {
205 ret.sin6.sin6_family = AF_INET6;
206 ret.sin6.sin6_addr = d_ip6->ip6_src;
207 ret.sin6.sin6_port = d_udp->uh_sport; // should deal with TCP too!
208 }
209 return ret;
210}
211
212ComboAddress PcapPacketReader::getDest() const
213{
214 ComboAddress ret;
215 if(d_ip->ip_v == 4) {
216 ret.sin4.sin_family = AF_INET;
217 ret.sin4.sin_addr = d_ip->ip_dst;
218 ret.sin4.sin_port = d_udp->uh_dport; // should deal with TCP too!
219 } else {
220 ret.sin6.sin6_family = AF_INET6;
221 ret.sin6.sin6_addr = d_ip6->ip6_dst;
222 ret.sin6.sin6_port = d_udp->uh_dport; // should deal with TCP too!
223 }
224 return ret;
225}
226
e795f590 227PcapPacketWriter::PcapPacketWriter(const string& fname, const PcapPacketReader& ppr) : PcapPacketWriter(fname)
228{
229 setPPR(ppr);
230}
231
232PcapPacketWriter::PcapPacketWriter(const string& fname) : d_fname(fname)
ab06937b
BH
233{
234 d_fp=fopen(fname.c_str(),"w");
235 if(!d_fp)
236 unixDie("Unable to open file");
237
0419f7af
BH
238 int flags=fcntl(fileno(d_fp),F_GETFL,0);
239 fcntl(fileno(d_fp), F_SETFL,flags&(~O_NONBLOCK)); // bsd needs this in stdin (??)
ab06937b
BH
240}
241
242void PcapPacketWriter::write()
243{
d7729968
RG
244 if (!d_ppr) {
245 return;
246 }
247
e795f590 248 if(d_first) {
249 fwrite(&d_ppr->d_pfh, 1, sizeof(d_ppr->d_pfh), d_fp);
250 d_first=false;
251 }
252 fwrite(&d_ppr->d_pheader, 1, sizeof(d_ppr->d_pheader), d_fp);
253 fwrite(d_ppr->d_buffer, 1, d_ppr->d_pheader.caplen, d_fp);
ab06937b
BH
254}
255
11212b81 256PcapPacketWriter::~PcapPacketWriter()
ab06937b
BH
257{
258 fclose(d_fp);
259}