1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 *
16 * Author : Guillaume TEISSIER from FTR&D 02/02/2006
17 */
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include <pcap.h>
23 #include <stdlib.h>
24 #include <netinet/in.h>
25 #include <netinet/udp.h>
26
27 #if defined(__HPUX) || defined(__CYGWIN) || defined(__FreeBSD__)
28 #include <netinet/in_systm.h>
29 #endif
30 #include <netinet/ip.h>
31 #ifndef __CYGWIN
32 #include <netinet/ip6.h>
33 #endif
34 #include <string.h>
35
36 #include "defines.h"
37 #include "endianshim.h"
38 #include "prepare_pcap.h"
39
40 /* We define our own structures for Ethernet Header and IPv6 Header as they are not available on CYGWIN.
41 * We only need the fields, which are necessary to determine the type of the next header.
42 * we could also define our own structures for UDP and IPv4. We currently use the structures
43 * made available by the platform, as we had no problems to get them on all supported platforms.
44 */
45
46 typedef struct _ether_type_hdr {
47 uint16_t ether_type; /* we only need the type, so we can determine, if the next header is IPv4 or IPv6 */
48 } ether_type_hdr;
49
50 typedef struct _ipv6_hdr {
51 char dontcare[6];
52 uint8_t nxt_header; /* we only need the next header, so we can determine, if the next header is UDP or not */
53 char dontcare2[33];
54 } ipv6_hdr;
55
56
57 #ifdef __HPUX
check(uint16_t * buffer,int len)58 int check(uint16_t *buffer, int len)
59 {
60 #else
61 inline int check(uint16_t *buffer, int len)
62 {
63 #endif
64 int sum;
65 int i;
66 sum = 0;
67
68 for (i=0; i<(len&~1); i+= 2)
69 sum += *buffer++;
70
71 if (len & 1) {
72 sum += htons((*(const uint8_t*)buffer) << 8);
73 }
74 return sum;
75 }
76
77 #ifdef __HPUX
78 uint16_t checksum_carry(int s)
79 {
80 #else
81 inline uint16_t checksum_carry(int s)
82 {
83 #endif
84 int s_c = (s >> 16) + (s & 0xffff);
85 return (~(s_c + (s_c >> 16)) & 0xffff);
86 }
87
88 char errbuf[PCAP_ERRBUF_SIZE];
89
90 /* get octet offset to EtherType block in 802.11 frame
91 */
92 size_t get_802_11_ethertype_offset(int link, const uint8_t* pktdata)
93 {
94 size_t offset = 0;
95 uint8_t frame_type = 0; /* 2 bits */
96 uint8_t frame_sub_type = 0; /* 4 bits */
97 uint16_t frame_ctl_fld; /* Frame Control Field */
98
99 /* get RadioTap header length */
100 if (link == DLT_IEEE802_11_RADIO) {
101 uint16_t rdtap_hdr_len = 0;
102 /* http://www.radiotap.org */
103 /* rdtap_version[1], pad[1], rdtap_hdr_len[2], rdtap_flds[4] */
104 memcpy(&rdtap_hdr_len, pktdata + 2, sizeof(rdtap_hdr_len));
105 /* http://radiotap.org */
106 /* all data fields in the radiotap header are to be specified
107 * in little-endian order */
108 rdtap_hdr_len = le16toh(rdtap_hdr_len);
109 offset += rdtap_hdr_len;
110 }
111
112 memcpy(&frame_ctl_fld, pktdata + offset, sizeof(frame_ctl_fld));
113 /* extract frame type and subtype from Frame Control Field */
114 frame_type = frame_sub_type = frame_ctl_fld>>8;
115 frame_type = frame_type>>2 & 0x03;
116 frame_sub_type >>= 4;
117 if (frame_type < 0x02) {
118 /* Control or Management frame, so ignore it and try to get
119 * EtherType from next one */
120 offset = 0;
121 } else if (frame_type == 0x02) {
122 /* only Data frames carry the relevant payload and EtherType */
123 if (frame_sub_type < 0x04
124 || (frame_sub_type > 0x07 && frame_sub_type < 0x0c)) {
125 /* MAC header of a Data frame is at least 24 and at most 36
126 * octets long */
127 size_t mac_hdr_len = 24;
128 uint8_t llc_hdr[8] = { 0x00 };
129 while (mac_hdr_len <= 36) {
130 /* attempt to get Logical-Link Control header */
131 /* dsap[1],ssap[1],ctrl_fld[1],org_code[3],ethertype[2] */
132 memcpy(llc_hdr, pktdata + offset + mac_hdr_len, sizeof(llc_hdr));
133 /* check if Logical-Link Control header */
134 if (llc_hdr[0] == 0xaa && llc_hdr[1] == 0xaa && llc_hdr[2] == 0x03) {
135 /* get EtherType and convert to host byte-order.
136 * (reduce by sizeof(eth_type)) */
137 offset += mac_hdr_len + (sizeof(llc_hdr) - sizeof(uint16_t));
138 break;
139 }
140 mac_hdr_len++;
141 }
142 } else {
143 /* could be Null Data frame, so ignore it and try to get
144 * EtherType from next one */
145 offset = 0;
146 }
147 } else {
148 ERROR("Unsupported frame type %d", frame_type);
149 }
150 return offset;
151 }
152
153 /* get octet offset to EtherType block
154 */
155 size_t get_ethertype_offset(int link, const uint8_t* pktdata)
156 {
157 int is_le_encoded = 0; /* little endian */
158 uint16_t eth_type = 0;
159 size_t offset = 0;
160
161 /* http://www.tcpdump.org/linktypes.html */
162 if (link == DLT_EN10MB) {
163 /* srcmac[6], dstmac[6], ethertype[2] */
164 offset = 12;
165 } else if (link == DLT_LINUX_SLL) {
166 /* http://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html */
167 /* pkttype[2], arphrd_type[2], lladdrlen[2], lladdr[8], ethertype[2] */
168 offset = 14;
169 } else if (link == DLT_IEEE802_11
170 || link == DLT_IEEE802_11_RADIO) {
171 offset = get_802_11_ethertype_offset(link, pktdata);
172 /* multi-octet fields in 802.11 frame are to be specified in
173 * little-endian order */
174 is_le_encoded = 1;
175 } else {
176 ERROR("Unsupported link-type %d", link);
177 }
178
179 if (offset) {
180 /* get EtherType and convert to host byte order */
181 memcpy(ð_type, pktdata + offset, sizeof(eth_type));
182 eth_type = (is_le_encoded) ? le16toh(eth_type) : ntohs(eth_type);
183 if (eth_type != 0x0800 && eth_type != 0x86dd) {
184 /* check if Ethernet 802.1Q VLAN */
185 if (eth_type == 0x8100) {
186 /* vlan_tag[4] */
187 offset += 4;
188 } else {
189 ERROR("Unsupported ethernet type %d", eth_type);
190 }
191 }
192 }
193 return offset;
194 }
195
196 /* prepare a pcap file
197 */
198 int prepare_pkts(char *file, pcap_pkts *pkts)
199 {
200 pcap_t* pcap;
201 #ifdef HAVE_PCAP_NEXT_EX
202 struct pcap_pkthdr* pkthdr = NULL;
203 #else
204 struct pcap_pkthdr pkthdr_storage;
205 struct pcap_pkthdr* pkthdr = &pkthdr_storage;
206 #endif
207 const uint8_t* pktdata = NULL;
208 int n_pkts = 0;
209 uint64_t max_length = 0;
210 size_t ether_type_offset = 0;
211 uint16_t base = 0xffff;
212 uint64_t pktlen;
213 pcap_pkt* pkt_index;
214 ether_type_hdr* ethhdr;
215
216 struct iphdr* iphdr;
217 ipv6_hdr* ip6hdr;
218 struct udphdr* udphdr;
219
220 pkts->pkts = NULL;
221
222 pcap = pcap_open_offline(file, errbuf);
223 if (!pcap)
224 ERROR_NO("Can't open PCAP file '%s'", file);
225 #ifdef HAVE_PCAP_NEXT_EX
226 while (pcap_next_ex(pcap, &pkthdr, &pktdata) == 1) {
227 #else
228 while ((pktdata = pcap_next(pcap, pkthdr)) != NULL) {
229 #endif
230 if (pkthdr->len != pkthdr->caplen) {
231 ERROR("You got truncated packets. Please create a new dump with -s0");
232 }
233
234 /* Determine offset from packet to ether type only once. */
235 if (!ether_type_offset) {
236 int datalink = pcap_datalink(pcap);
237 ether_type_offset = get_ethertype_offset(datalink, pktdata);
238 }
239
240 ethhdr = (ether_type_hdr *)(pktdata + ether_type_offset);
241 if (ntohs(ethhdr->ether_type) != 0x0800 /* IPv4 */
242 && ntohs(ethhdr->ether_type) != 0x86dd) { /* IPv6 */
243 fprintf(stderr, "Ignoring non IP{4,6} packet, got ether_type %hu!\n",
244 ntohs(ethhdr->ether_type));
245 continue;
246 }
247 iphdr = (struct iphdr*)((char*)ethhdr + sizeof(*ethhdr));
248 if (iphdr && iphdr->version == 6) {
249 /* ipv6 */
250 pktlen = (uint64_t)pkthdr->len - sizeof(*ethhdr) - sizeof(*ip6hdr);
251 ip6hdr = (ipv6_hdr*)(void*)iphdr;
252 if (ip6hdr->nxt_header != IPPROTO_UDP) {
253 fprintf(stderr, "prepare_pcap.c: Ignoring non UDP packet!\n");
254 continue;
255 }
256 udphdr = (struct udphdr*)((char*)ip6hdr + sizeof(*ip6hdr));
257 } else {
258 /* ipv4 */
259 if (iphdr->protocol != IPPROTO_UDP) {
260 fprintf(stderr, "prepare_pcap.c: Ignoring non UDP packet!\n");
261 continue;
262 }
263 #if defined(__DARWIN) || defined(__CYGWIN) || defined(__FreeBSD__)
264 udphdr = (struct udphdr*)((char*)iphdr + (iphdr->ihl << 2) + 4);
265 pktlen = (uint64_t)(ntohs(udphdr->uh_ulen));
266 #elif defined ( __HPUX)
267 udphdr = (struct udphdr*)((char*)iphdr + (iphdr->ihl << 2));
268 pktlen = (uint64_t) pkthdr->len - sizeof(*ethhdr) - sizeof(*iphdr);
269 #else
270 udphdr = (struct udphdr*)((char*)iphdr + (iphdr->ihl << 2));
271 pktlen = (uint64_t)(ntohs(udphdr->len));
272 #endif
273 }
274 if (pktlen > PCAP_MAXPACKET) {
275 ERROR("Packet size is too big! Recompile with bigger PCAP_MAXPACKET in prepare_pcap.h");
276 }
277 pkts->pkts = (pcap_pkt *)realloc(pkts->pkts, sizeof(*(pkts->pkts)) * (n_pkts + 1));
278 if (!pkts->pkts)
279 ERROR("Can't re-allocate memory for pcap pkt");
280 pkt_index = pkts->pkts + n_pkts;
281 pkt_index->pktlen = pktlen;
282 pkt_index->ts = pkthdr->ts;
283 pkt_index->data = (unsigned char *) malloc(pktlen);
284 if (!pkt_index->data)
285 ERROR("Can't allocate memory for pcap pkt data");
286 memcpy(pkt_index->data, udphdr, pktlen);
287
288 #if defined(__HPUX) || defined(__DARWIN) || (defined __CYGWIN) || defined(__FreeBSD__)
289 udphdr->uh_sum = 0 ;
290 #else
291 udphdr->check = 0;
292 #endif
293
294 /* compute a partial udp checksum */
295 /* not including port that will be changed */
296 /* when sending RTP */
297 #if defined(__HPUX) || defined(__DARWIN) || (defined __CYGWIN) || defined(__FreeBSD__)
298 pkt_index->partial_check = check((uint16_t*)&udphdr->uh_ulen, pktlen - 4) + ntohs(IPPROTO_UDP + pktlen);
299 #else
300 pkt_index->partial_check = check((uint16_t*)&udphdr->len, pktlen - 4) + ntohs(IPPROTO_UDP + pktlen);
301 #endif
302 if (max_length < pktlen)
303 max_length = pktlen;
304 #if defined(__HPUX) || defined(__DARWIN) || (defined __CYGWIN) || defined(__FreeBSD__)
305 if (base > ntohs(udphdr->uh_dport))
306 base = ntohs(udphdr->uh_dport);
307 #else
308 if (base > ntohs(udphdr->dest))
309 base = ntohs(udphdr->dest);
310 #endif
311 n_pkts++;
312 }
313 pkts->max = pkts->pkts + n_pkts;
314 pkts->max_length = max_length;
315 pkts->base = base;
316 fprintf(stderr, "In pcap %s, npkts %d\nmax pkt length %ld\nbase port %d\n", file, n_pkts, max_length, base);
317 pcap_close(pcap);
318
319 return 0;
320 }
321