]>
Commit | Line | Data |
---|---|---|
0b86fb59 | 1 | #define __FAVOR_BSD |
ab06937b | 2 | #include "dnspcap.hh" |
11212b81 | 3 | #include <boost/format.hpp> |
0b86fb59 | 4 | #include <fcntl.h> |
ab06937b | 5 | |
61b26744 | 6 | #include "namespaces.hh" |
ab06937b BH |
7 | PcapPacketReader::PcapPacketReader(const string& fname) : d_fname(fname) |
8 | { | |
9 | d_fp=fopen(fname.c_str(),"r"); | |
10 | if(!d_fp) | |
11 | unixDie("Unable to open file"); | |
12 | ||
0b86fb59 BH |
13 | int flags=fcntl(fileno(d_fp),F_GETFL,0); |
14 | fcntl(fileno(d_fp), F_SETFL,flags&(~O_NONBLOCK)); // bsd needs this in stdin (??) | |
ab06937b BH |
15 | |
16 | checkedFread(&d_pfh); | |
17 | ||
18 | if(d_pfh.magic != 2712847316UL) | |
19 | throw runtime_error((format("PCAP file %s has bad magic %x, should be %x") % fname % d_pfh.magic % 2712847316UL).str()); | |
20 | ||
2acf3098 BH |
21 | if( d_pfh.linktype==1) { |
22 | d_skipMediaHeader=sizeof(struct ether_header); | |
23 | } else if(d_pfh.linktype==113) { | |
24 | d_skipMediaHeader=16; | |
25 | } | |
26 | else throw runtime_error((format("Unsupported link type %d") % d_pfh.linktype).str()); | |
ab06937b | 27 | |
11212b81 | 28 | d_runts = d_oversized = d_correctpackets = d_nonetheripudp = 0; |
ab06937b BH |
29 | } |
30 | ||
11212b81 | 31 | PcapPacketReader::~PcapPacketReader() |
ab06937b BH |
32 | { |
33 | fclose(d_fp); | |
34 | } | |
35 | ||
36 | ||
37 | void PcapPacketReader::checkedFreadSize(void* ptr, size_t size) | |
38 | { | |
39 | int ret=fread(ptr, 1, size, d_fp); | |
40 | if(ret < 0) | |
41 | unixDie( (format("Error reading %d bytes from %s") % size % d_fname).str()); | |
42 | ||
43 | if(!ret) | |
44 | throw EofException(); | |
45 | ||
46 | if((size_t)ret != size) | |
47 | throw EofException((format("Incomplete read from '%s', got only %d bytes") % d_fname % ret).str()); | |
48 | } | |
49 | ||
50 | bool PcapPacketReader::getUDPPacket() | |
51 | try | |
52 | { | |
53 | for(;;) { | |
54 | checkedFread(&d_pheader); | |
e0333255 BH |
55 | if(!d_pheader.caplen) |
56 | continue; | |
3042f1ba | 57 | |
ab06937b BH |
58 | if(d_pheader.caplen > sizeof(d_buffer)) { |
59 | d_oversized++; | |
3042f1ba | 60 | throw runtime_error((format("Can't handle a %d byte packet, have space for %d") % d_pheader.caplen % sizeof(d_buffer)).str()); |
ab06937b | 61 | } |
3042f1ba | 62 | |
ab06937b | 63 | checkedFreadSize(d_buffer, d_pheader.caplen); |
3042f1ba BH |
64 | |
65 | if(d_pheader.caplen!=d_pheader.len) { | |
66 | d_runts++; | |
67 | continue; | |
68 | } | |
69 | ||
11212b81 | 70 | d_ether=reinterpret_cast<struct ether_header*>(d_buffer); |
2acf3098 BH |
71 | d_lcc=reinterpret_cast<struct pdns_lcc_header*>(d_buffer); |
72 | ||
73 | d_ip=reinterpret_cast<struct ip*>(d_buffer + d_skipMediaHeader); | |
bf32bff8 | 74 | d_ip6=reinterpret_cast<struct ip6_hdr*>(d_buffer + d_skipMediaHeader); |
49f61cba | 75 | uint16_t contentCode=0; |
2acf3098 BH |
76 | if(d_pfh.linktype==1) |
77 | contentCode=ntohs(d_ether->ether_type); | |
78 | else if(d_pfh.linktype==113) | |
79 | contentCode=ntohs(d_lcc->lcc_protocol); | |
3042f1ba | 80 | |
2acf3098 BH |
81 | if(contentCode==0x0800 && d_ip->ip_p==17) { // udp |
82 | d_udp=reinterpret_cast<const struct udphdr*>(d_buffer + d_skipMediaHeader + 4 * d_ip->ip_hl); | |
ab06937b | 83 | d_payload = (unsigned char*)d_udp + sizeof(struct udphdr); |
0b86fb59 | 84 | d_len = ntohs(d_udp->uh_ulen) - sizeof(struct udphdr); |
11212b81 | 85 | d_correctpackets++; |
ab06937b BH |
86 | return true; |
87 | } | |
bf32bff8 | 88 | if(contentCode==0x86dd && d_ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt==17) { // udpv6, we ignore anything with extension hdr |
89 | d_udp=reinterpret_cast<const struct udphdr*>(d_buffer + d_skipMediaHeader + sizeof(struct ip6_hdr)); | |
90 | d_payload = (unsigned char*)d_udp + sizeof(struct udphdr); | |
91 | d_len = ntohs(d_udp->uh_ulen) - sizeof(struct udphdr); | |
92 | d_correctpackets++; | |
93 | return true; | |
94 | } | |
95 | ||
11212b81 BH |
96 | else { |
97 | d_nonetheripudp++; | |
98 | } | |
ab06937b BH |
99 | } |
100 | } | |
101 | catch(EofException) { | |
102 | return false; | |
103 | } | |
104 | ||
a5d9353e | 105 | ComboAddress PcapPacketReader::getSource() const |
106 | { | |
107 | ComboAddress ret; | |
108 | if(d_ip->ip_v == 4) { | |
109 | ret.sin4.sin_family = AF_INET; | |
110 | ret.sin4.sin_addr = d_ip->ip_src; | |
111 | ret.sin4.sin_port = d_udp->uh_sport; // should deal with TCP too! | |
112 | } else { | |
113 | ret.sin6.sin6_family = AF_INET6; | |
114 | ret.sin6.sin6_addr = d_ip6->ip6_src; | |
115 | ret.sin6.sin6_port = d_udp->uh_sport; // should deal with TCP too! | |
116 | } | |
117 | return ret; | |
118 | } | |
119 | ||
120 | ComboAddress PcapPacketReader::getDest() const | |
121 | { | |
122 | ComboAddress ret; | |
123 | if(d_ip->ip_v == 4) { | |
124 | ret.sin4.sin_family = AF_INET; | |
125 | ret.sin4.sin_addr = d_ip->ip_dst; | |
126 | ret.sin4.sin_port = d_udp->uh_dport; // should deal with TCP too! | |
127 | } else { | |
128 | ret.sin6.sin6_family = AF_INET6; | |
129 | ret.sin6.sin6_addr = d_ip6->ip6_dst; | |
130 | ret.sin6.sin6_port = d_udp->uh_dport; // should deal with TCP too! | |
131 | } | |
132 | return ret; | |
133 | } | |
134 | ||
ab06937b BH |
135 | PcapPacketWriter::PcapPacketWriter(const string& fname, PcapPacketReader& ppr) : d_fname(fname), d_ppr(ppr) |
136 | { | |
137 | d_fp=fopen(fname.c_str(),"w"); | |
138 | if(!d_fp) | |
139 | unixDie("Unable to open file"); | |
140 | ||
0419f7af BH |
141 | int flags=fcntl(fileno(d_fp),F_GETFL,0); |
142 | fcntl(fileno(d_fp), F_SETFL,flags&(~O_NONBLOCK)); // bsd needs this in stdin (??) | |
143 | ||
ab06937b | 144 | fwrite(&ppr.d_pfh, 1, sizeof(ppr.d_pfh), d_fp); |
ab06937b BH |
145 | } |
146 | ||
147 | void PcapPacketWriter::write() | |
148 | { | |
149 | fwrite(&d_ppr.d_pheader, 1, sizeof(d_ppr.d_pheader), d_fp); | |
150 | fwrite(d_ppr.d_buffer, 1, d_ppr.d_pheader.caplen, d_fp); | |
151 | } | |
152 | ||
11212b81 | 153 | PcapPacketWriter::~PcapPacketWriter() |
ab06937b BH |
154 | { |
155 | fclose(d_fp); | |
156 | } |