]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnspcap.cc
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
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.
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.
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.
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.
27 #include <boost/format.hpp>
30 #include "namespaces.hh"
31 PcapPacketReader::PcapPacketReader(const string
& fname
) : d_fname(fname
)
33 d_fp
= pdns::UniqueFilePtr(fopen(fname
.c_str(), "r"));
35 unixDie("Unable to open file " + fname
);
38 int flags
= fcntl(fileno(d_fp
.get()), F_GETFL
, 0);
39 fcntl(fileno(d_fp
.get()), F_SETFL
, flags
& (~O_NONBLOCK
)); // bsd needs this in stdin (??)
43 if (d_pfh
.magic
!= 2712847316UL) {
44 throw runtime_error((boost::format("PCAP file %s has bad magic %x, should be %x") % fname
% d_pfh
.magic
% 2712847316UL).str());
47 if( d_pfh
.linktype
==1) {
48 d_skipMediaHeader
=sizeof(struct ether_header
);
50 else if( d_pfh
.linktype
==12) { // LOOP
53 else if(d_pfh
.linktype
==101) {
56 else if(d_pfh
.linktype
==113) {
59 else throw runtime_error((boost::format("Unsupported link type %d") % d_pfh
.linktype
).str());
61 d_runts
= d_oversized
= d_correctpackets
= d_nonetheripudp
= 0;
63 size_t alignmentCorrection
= d_skipMediaHeader
% alignof(struct ip
);
65 d_buffer
= d_readbuffer
+ alignmentCorrection
;
66 d_bufsize
= sizeof(d_readbuffer
) - alignmentCorrection
;
68 if (d_skipMediaHeader
> d_bufsize
) throw runtime_error("media header is too big");
71 void PcapPacketReader::checkedFreadSize(void* ptr
, size_t size
)
73 int ret
= fread(ptr
, 1, size
, d_fp
.get());
75 unixDie( (boost::format("Error reading %d bytes from %s") % size
% d_fname
).str());
81 if((size_t)ret
!= size
)
82 throw EofException((boost::format("Incomplete read from '%s', got only %d bytes") % d_fname
% ret
).str());
85 bool PcapPacketReader::getUDPPacket()
89 checkedFread(&d_pheader
);
90 if(!d_pheader
.caplen
) {
95 if(d_pheader
.caplen
> d_bufsize
) {
97 throw runtime_error((boost::format("Can't handle a %d byte packet, have space for %zu") % d_pheader
.caplen
% d_bufsize
).str());
100 checkedFreadSize(d_buffer
, d_pheader
.caplen
);
102 if(d_pheader
.caplen
< d_pheader
.len
) {
107 if (d_pheader
.caplen
< d_skipMediaHeader
) {
112 d_ip
=reinterpret_cast<struct ip
*>(d_buffer
+ d_skipMediaHeader
);
113 d_ip6
=reinterpret_cast<struct ip6_hdr
*>(d_buffer
+ d_skipMediaHeader
);
114 uint16_t contentCode
=0;
116 if(d_pfh
.linktype
==1) {
117 if (d_pheader
.caplen
< sizeof(*d_ether
)) {
121 d_ether
=reinterpret_cast<struct ether_header
*>(d_buffer
);
122 contentCode
=ntohs(d_ether
->ether_type
);
124 else if(d_pfh
.linktype
== 12) { // LOOP
125 if (d_pheader
.caplen
< (d_skipMediaHeader
+ sizeof(*d_ip
))) {
130 contentCode
= 0x0800;
132 contentCode
= 0x86dd;
134 else if(d_pfh
.linktype
==101) {
135 if (d_pheader
.caplen
< (d_skipMediaHeader
+ sizeof(*d_ip
))) {
140 contentCode
= 0x0800;
142 contentCode
= 0x86dd;
144 else if(d_pfh
.linktype
==113) {
145 if (d_pheader
.caplen
< sizeof(*d_lcc
)) {
149 d_lcc
=reinterpret_cast<struct pdns_lcc_header
*>(d_buffer
);
150 contentCode
=ntohs(d_lcc
->lcc_protocol
);
153 if(contentCode
==0x0800 && (d_pheader
.caplen
>= (d_skipMediaHeader
+ sizeof(*d_ip
))) && d_ip
->ip_p
==17) { // udp
154 if (d_pheader
.caplen
< (d_skipMediaHeader
+ (4 * d_ip
->ip_hl
) + sizeof(*d_udp
))) {
158 d_udp
=reinterpret_cast<const struct udphdr
*>(d_buffer
+ d_skipMediaHeader
+ 4 * d_ip
->ip_hl
);
159 d_payload
= (unsigned char*)d_udp
+ sizeof(struct udphdr
);
160 d_len
= ntohs(d_udp
->uh_ulen
) - sizeof(struct udphdr
);
161 if (d_pheader
.caplen
< (d_skipMediaHeader
+ (4 * d_ip
->ip_hl
) + sizeof(*d_udp
) + d_len
)) {
165 if((const char*)d_payload
+ d_len
> d_buffer
+ d_pheader
.caplen
) {
172 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
173 if (d_pheader
.caplen
< (d_skipMediaHeader
+ sizeof(struct ip6_hdr
) + sizeof(struct udphdr
))) {
177 d_udp
=reinterpret_cast<const struct udphdr
*>(d_buffer
+ d_skipMediaHeader
+ sizeof(struct ip6_hdr
));
178 d_payload
= (unsigned char*)d_udp
+ sizeof(struct udphdr
);
179 d_len
= ntohs(d_udp
->uh_ulen
) - sizeof(struct udphdr
);
180 if (d_pheader
.caplen
< (d_skipMediaHeader
+ sizeof(struct ip6_hdr
) + sizeof(struct udphdr
) + d_len
)) {
184 if((const char*)d_payload
+ d_len
> d_buffer
+ d_pheader
.caplen
) {
197 catch(const EofException
&) {
201 ComboAddress
PcapPacketReader::getSource() const
204 if(d_ip
->ip_v
== 4) {
205 ret
.sin4
.sin_family
= AF_INET
;
206 ret
.sin4
.sin_addr
= d_ip
->ip_src
;
207 ret
.sin4
.sin_port
= d_udp
->uh_sport
; // should deal with TCP too!
209 ret
.sin6
.sin6_family
= AF_INET6
;
210 ret
.sin6
.sin6_addr
= d_ip6
->ip6_src
;
211 ret
.sin6
.sin6_port
= d_udp
->uh_sport
; // should deal with TCP too!
216 ComboAddress
PcapPacketReader::getDest() const
219 if(d_ip
->ip_v
== 4) {
220 ret
.sin4
.sin_family
= AF_INET
;
221 ret
.sin4
.sin_addr
= d_ip
->ip_dst
;
222 ret
.sin4
.sin_port
= d_udp
->uh_dport
; // should deal with TCP too!
224 ret
.sin6
.sin6_family
= AF_INET6
;
225 ret
.sin6
.sin6_addr
= d_ip6
->ip6_dst
;
226 ret
.sin6
.sin6_port
= d_udp
->uh_dport
; // should deal with TCP too!
231 PcapPacketWriter::PcapPacketWriter(const string
& fname
, const PcapPacketReader
& ppr
) : PcapPacketWriter(fname
)
236 PcapPacketWriter::PcapPacketWriter(const string
& fname
) : d_fname(fname
)
238 d_fp
= pdns::openFileForWriting(fname
, 0600, true, false);
240 unixDie("Unable to open file");
243 int flags
= fcntl(fileno(d_fp
.get()), F_GETFL
, 0);
244 fcntl(fileno(d_fp
.get()), F_SETFL
,flags
& (~O_NONBLOCK
)); // bsd needs this in stdin (??)
247 void PcapPacketWriter::write()
254 fwrite(&d_ppr
->d_pfh
, 1, sizeof(d_ppr
->d_pfh
), d_fp
.get());
257 fwrite(&d_ppr
->d_pheader
, 1, sizeof(d_ppr
->d_pheader
), d_fp
.get());
258 fwrite(d_ppr
->d_buffer
, 1, d_ppr
->d_pheader
.caplen
, d_fp
.get());