]>
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
=fopen(fname
.c_str(),"r");
35 unixDie("Unable to open file " + fname
);
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 (??)
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());
45 if( d_pfh
.linktype
==1) {
46 d_skipMediaHeader
=sizeof(struct ether_header
);
48 else if(d_pfh
.linktype
==101) {
51 else if(d_pfh
.linktype
==113) {
54 else throw runtime_error((format("Unsupported link type %d") % d_pfh
.linktype
).str());
56 d_runts
= d_oversized
= d_correctpackets
= d_nonetheripudp
= 0;
59 PcapPacketReader::~PcapPacketReader()
65 void PcapPacketReader::checkedFreadSize(void* ptr
, size_t size
)
67 int ret
=fread(ptr
, 1, size
, d_fp
);
69 unixDie( (format("Error reading %d bytes from %s") % size
% d_fname
).str());
74 if((size_t)ret
!= size
)
75 throw EofException((format("Incomplete read from '%s', got only %d bytes") % d_fname
% ret
).str());
78 bool PcapPacketReader::getUDPPacket()
82 checkedFread(&d_pheader
);
83 if(!d_pheader
.caplen
) {
88 if(d_pheader
.caplen
> sizeof(d_buffer
)) {
90 throw runtime_error((format("Can't handle a %d byte packet, have space for %d") % d_pheader
.caplen
% sizeof(d_buffer
)).str());
93 checkedFreadSize(d_buffer
, d_pheader
.caplen
);
95 if(d_pheader
.caplen
!=d_pheader
.len
) {
100 d_ether
=reinterpret_cast<struct ether_header
*>(d_buffer
);
101 d_lcc
=reinterpret_cast<struct pdns_lcc_header
*>(d_buffer
);
103 d_ip
=reinterpret_cast<struct ip
*>(d_buffer
+ d_skipMediaHeader
);
104 d_ip6
=reinterpret_cast<struct ip6_hdr
*>(d_buffer
+ d_skipMediaHeader
);
105 uint16_t contentCode
=0;
106 if(d_pfh
.linktype
==1)
107 contentCode
=ntohs(d_ether
->ether_type
);
108 else if(d_pfh
.linktype
==101) {
110 contentCode
= 0x0800;
112 contentCode
= 0x86dd;
114 else if(d_pfh
.linktype
==113)
115 contentCode
=ntohs(d_lcc
->lcc_protocol
);
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
);
119 d_payload
= (unsigned char*)d_udp
+ sizeof(struct udphdr
);
120 d_len
= ntohs(d_udp
->uh_ulen
) - sizeof(struct udphdr
);
121 if((const char*)d_payload
+ d_len
> d_buffer
+ d_pheader
.caplen
) {
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
);
132 if((const char*)d_payload
+ d_len
> d_buffer
+ d_pheader
.caplen
) {
145 catch(EofException
) {
149 ComboAddress
PcapPacketReader::getSource() const
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!
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!
164 ComboAddress
PcapPacketReader::getDest() const
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!
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!
179 PcapPacketWriter::PcapPacketWriter(const string
& fname
, const PcapPacketReader
& ppr
) : PcapPacketWriter(fname
)
184 PcapPacketWriter::PcapPacketWriter(const string
& fname
) : d_fname(fname
)
186 d_fp
=fopen(fname
.c_str(),"w");
188 unixDie("Unable to open file");
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 (??)
194 void PcapPacketWriter::write()
201 fwrite(&d_ppr
->d_pfh
, 1, sizeof(d_ppr
->d_pfh
), d_fp
);
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
);
208 PcapPacketWriter::~PcapPacketWriter()