]>
Commit | Line | Data |
---|---|---|
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 |
31 | PcapPacketReader::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 | 62 | PcapPacketReader::~PcapPacketReader() |
ab06937b BH |
63 | { |
64 | fclose(d_fp); | |
65 | } | |
66 | ||
67 | ||
68 | void 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 | ||
81 | bool PcapPacketReader::getUDPPacket() | |
82 | try | |
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 | 193 | catch(const EofException&) { |
ab06937b BH |
194 | return false; |
195 | } | |
196 | ||
a5d9353e | 197 | ComboAddress 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 | ||
212 | ComboAddress 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 | 227 | PcapPacketWriter::PcapPacketWriter(const string& fname, const PcapPacketReader& ppr) : PcapPacketWriter(fname) |
228 | { | |
229 | setPPR(ppr); | |
230 | } | |
231 | ||
232 | PcapPacketWriter::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 | ||
242 | void 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 | 256 | PcapPacketWriter::~PcapPacketWriter() |
ab06937b BH |
257 | { |
258 | fclose(d_fp); | |
259 | } |