]>
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 | } |
48 | else if(d_pfh.linktype==101) { | |
49 | d_skipMediaHeader=0; | |
50 | } | |
51 | else if(d_pfh.linktype==113) { | |
2acf3098 BH |
52 | d_skipMediaHeader=16; |
53 | } | |
54 | else throw runtime_error((format("Unsupported link type %d") % d_pfh.linktype).str()); | |
ab06937b | 55 | |
11212b81 | 56 | d_runts = d_oversized = d_correctpackets = d_nonetheripudp = 0; |
ab06937b BH |
57 | } |
58 | ||
11212b81 | 59 | PcapPacketReader::~PcapPacketReader() |
ab06937b BH |
60 | { |
61 | fclose(d_fp); | |
62 | } | |
63 | ||
64 | ||
65 | void PcapPacketReader::checkedFreadSize(void* ptr, size_t size) | |
66 | { | |
67 | int ret=fread(ptr, 1, size, d_fp); | |
68 | if(ret < 0) | |
69 | unixDie( (format("Error reading %d bytes from %s") % size % d_fname).str()); | |
70 | ||
71 | if(!ret) | |
72 | throw EofException(); | |
73 | ||
74 | if((size_t)ret != size) | |
75 | throw EofException((format("Incomplete read from '%s', got only %d bytes") % d_fname % ret).str()); | |
76 | } | |
77 | ||
78 | bool PcapPacketReader::getUDPPacket() | |
79 | try | |
80 | { | |
81 | for(;;) { | |
82 | checkedFread(&d_pheader); | |
d2d8cafd | 83 | if(!d_pheader.caplen) { |
84 | d_runts++; | |
e0333255 | 85 | continue; |
d2d8cafd | 86 | } |
3042f1ba | 87 | |
ab06937b BH |
88 | if(d_pheader.caplen > sizeof(d_buffer)) { |
89 | d_oversized++; | |
3042f1ba | 90 | throw runtime_error((format("Can't handle a %d byte packet, have space for %d") % d_pheader.caplen % sizeof(d_buffer)).str()); |
ab06937b | 91 | } |
3042f1ba | 92 | |
ab06937b | 93 | checkedFreadSize(d_buffer, d_pheader.caplen); |
3042f1ba | 94 | |
173dcfb0 | 95 | if(d_pheader.caplen < d_pheader.len) { |
3042f1ba BH |
96 | d_runts++; |
97 | continue; | |
98 | } | |
99 | ||
11212b81 | 100 | d_ether=reinterpret_cast<struct ether_header*>(d_buffer); |
2acf3098 BH |
101 | d_lcc=reinterpret_cast<struct pdns_lcc_header*>(d_buffer); |
102 | ||
103 | d_ip=reinterpret_cast<struct ip*>(d_buffer + d_skipMediaHeader); | |
bf32bff8 | 104 | d_ip6=reinterpret_cast<struct ip6_hdr*>(d_buffer + d_skipMediaHeader); |
49f61cba | 105 | uint16_t contentCode=0; |
2acf3098 BH |
106 | if(d_pfh.linktype==1) |
107 | contentCode=ntohs(d_ether->ether_type); | |
8bfd2560 | 108 | else if(d_pfh.linktype==101) { |
109 | if(d_ip->ip_v==4) | |
110 | contentCode = 0x0800; | |
111 | else | |
3ae047fe | 112 | contentCode = 0x86dd; |
8bfd2560 | 113 | } |
2acf3098 BH |
114 | else if(d_pfh.linktype==113) |
115 | contentCode=ntohs(d_lcc->lcc_protocol); | |
3042f1ba | 116 | |
2acf3098 BH |
117 | if(contentCode==0x0800 && d_ip->ip_p==17) { // udp |
118 | d_udp=reinterpret_cast<const struct udphdr*>(d_buffer + d_skipMediaHeader + 4 * d_ip->ip_hl); | |
ab06937b | 119 | d_payload = (unsigned char*)d_udp + sizeof(struct udphdr); |
0b86fb59 | 120 | d_len = ntohs(d_udp->uh_ulen) - sizeof(struct udphdr); |
66afeb44 | 121 | if((const char*)d_payload + d_len > d_buffer + d_pheader.caplen) { |
122 | d_runts++; | |
123 | continue; | |
124 | } | |
11212b81 | 125 | d_correctpackets++; |
ab06937b BH |
126 | return true; |
127 | } | |
bf32bff8 | 128 | if(contentCode==0x86dd && d_ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt==17) { // udpv6, we ignore anything with extension hdr |
129 | d_udp=reinterpret_cast<const struct udphdr*>(d_buffer + d_skipMediaHeader + sizeof(struct ip6_hdr)); | |
130 | d_payload = (unsigned char*)d_udp + sizeof(struct udphdr); | |
131 | d_len = ntohs(d_udp->uh_ulen) - sizeof(struct udphdr); | |
66afeb44 | 132 | if((const char*)d_payload + d_len > d_buffer + d_pheader.caplen) { |
133 | d_runts++; | |
134 | continue; | |
135 | } | |
136 | ||
bf32bff8 | 137 | d_correctpackets++; |
138 | return true; | |
139 | } | |
11212b81 BH |
140 | else { |
141 | d_nonetheripudp++; | |
142 | } | |
ab06937b BH |
143 | } |
144 | } | |
145 | catch(EofException) { | |
146 | return false; | |
147 | } | |
148 | ||
a5d9353e | 149 | ComboAddress PcapPacketReader::getSource() const |
150 | { | |
151 | ComboAddress ret; | |
152 | if(d_ip->ip_v == 4) { | |
153 | ret.sin4.sin_family = AF_INET; | |
154 | ret.sin4.sin_addr = d_ip->ip_src; | |
155 | ret.sin4.sin_port = d_udp->uh_sport; // should deal with TCP too! | |
156 | } else { | |
157 | ret.sin6.sin6_family = AF_INET6; | |
158 | ret.sin6.sin6_addr = d_ip6->ip6_src; | |
159 | ret.sin6.sin6_port = d_udp->uh_sport; // should deal with TCP too! | |
160 | } | |
161 | return ret; | |
162 | } | |
163 | ||
164 | ComboAddress PcapPacketReader::getDest() const | |
165 | { | |
166 | ComboAddress ret; | |
167 | if(d_ip->ip_v == 4) { | |
168 | ret.sin4.sin_family = AF_INET; | |
169 | ret.sin4.sin_addr = d_ip->ip_dst; | |
170 | ret.sin4.sin_port = d_udp->uh_dport; // should deal with TCP too! | |
171 | } else { | |
172 | ret.sin6.sin6_family = AF_INET6; | |
173 | ret.sin6.sin6_addr = d_ip6->ip6_dst; | |
174 | ret.sin6.sin6_port = d_udp->uh_dport; // should deal with TCP too! | |
175 | } | |
176 | return ret; | |
177 | } | |
178 | ||
e795f590 | 179 | PcapPacketWriter::PcapPacketWriter(const string& fname, const PcapPacketReader& ppr) : PcapPacketWriter(fname) |
180 | { | |
181 | setPPR(ppr); | |
182 | } | |
183 | ||
184 | PcapPacketWriter::PcapPacketWriter(const string& fname) : d_fname(fname) | |
ab06937b BH |
185 | { |
186 | d_fp=fopen(fname.c_str(),"w"); | |
187 | if(!d_fp) | |
188 | unixDie("Unable to open file"); | |
189 | ||
0419f7af BH |
190 | int flags=fcntl(fileno(d_fp),F_GETFL,0); |
191 | fcntl(fileno(d_fp), F_SETFL,flags&(~O_NONBLOCK)); // bsd needs this in stdin (??) | |
ab06937b BH |
192 | } |
193 | ||
194 | void PcapPacketWriter::write() | |
195 | { | |
d7729968 RG |
196 | if (!d_ppr) { |
197 | return; | |
198 | } | |
199 | ||
e795f590 | 200 | if(d_first) { |
201 | fwrite(&d_ppr->d_pfh, 1, sizeof(d_ppr->d_pfh), d_fp); | |
202 | d_first=false; | |
203 | } | |
204 | fwrite(&d_ppr->d_pheader, 1, sizeof(d_ppr->d_pheader), d_fp); | |
205 | fwrite(d_ppr->d_buffer, 1, d_ppr->d_pheader.caplen, d_fp); | |
ab06937b BH |
206 | } |
207 | ||
11212b81 | 208 | PcapPacketWriter::~PcapPacketWriter() |
ab06937b BH |
209 | { |
210 | fclose(d_fp); | |
211 | } |