1 /*
2 * SpanDSP - a series of DSP components for telephony
3 *
4 * pcap_parse.c
5 *
6 * Written by Steve Underwood <steveu@coppice.org>
7 *
8 * Copyright (C) 2009 Steve Underwood
9 *
10 * All rights reserved.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2, as
14 * published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 * Some code from SIPP (http://sf.net/projects/sipp) was used as a model
26 * for how to work with PCAP files. That code was authored by Guillaume
27 * TEISSIER from FTR&D 02/02/2006, and released under the GPL2 licence.
28 */
29
30 #if defined(HAVE_CONFIG_H)
31 #include "config.h"
32 #endif
33
34 #include <inttypes.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37
38 #if defined(HAVE_PCAP_H)
39 #include <pcap.h>
40 #include <pcap/sll.h>
41 #endif
42 #include <netinet/in.h>
43 #include <netinet/udp.h>
44 #if defined(__HPUX) || defined(__CYGWIN__) || defined(__FreeBSD__)
45 #include <netinet/in_systm.h>
46 #endif
47 #include <netinet/ip.h>
48 #if !defined(__CYGWIN__)
49 #include <netinet/ip6.h>
50 #endif
51 #include <string.h>
52
53 #include <netinet/in.h>
54 #include <netinet/udp.h>
55 #include <time.h>
56
57 #include "udptl.h"
58 #include "spandsp.h"
59 #include "pcap_parse.h"
60
61 #if defined(__HPUX) || defined(__DARWIN) || defined(__CYGWIN__) || defined(__FreeBSD__)
62
63 struct iphdr
64 {
65 #if defined(_HPUX_LI)
66 unsigned int ihl:4;
67 unsigned int version:4;
68 #else
69 unsigned int version:4;
70 unsigned int ihl:4;
71 #endif
72 uint8_t tos;
73 uint16_t tot_len;
74 uint16_t id;
75 uint16_t frag_off;
76 uint8_t ttl;
77 uint8_t protocol;
78 uint16_t check;
79 uint32_t saddr;
80 uint32_t daddr;
81 /*The options start here. */
82 };
83
84 #endif
85
86 /* We define our own structures for Ethernet Header and IPv6 Header as they are not available on CYGWIN.
87 * We only need the fields, which are necessary to determine the type of the next header.
88 * we could also define our own structures for UDP and IPv4. We currently use the structures
89 * made available by the platform, as we had no problems to get them on all supported platforms.
90 */
91
92 typedef struct _ether_hdr
93 {
94 char ether_dst[6];
95 char ether_src[6];
96 uint16_t ether_type;
97 } ether_hdr;
98
99 typedef struct _null_hdr
100 {
101 uint32_t pf_type;
102 } null_hdr;
103
104 #if !defined(__CYGWIN__)
105 typedef struct _ipv6_hdr
106 {
107 char dontcare[6];
108 u_int8_t nxt_header; /* we only need the next header, so we can determine, if the next header is UDP or not */
109 char dontcare2[33];
110 } ipv6_hdr;
111 #endif
112
113 char errbuf[PCAP_ERRBUF_SIZE];
114
pcap_scan_pkts(const char * file,uint32_t src_addr,uint16_t src_port,uint32_t dest_addr,uint16_t dest_port,pcap_timing_update_handler_t * timing_update_handler,pcap_packet_handler_t * packet_handler,void * user_data)115 int pcap_scan_pkts(const char *file,
116 uint32_t src_addr,
117 uint16_t src_port,
118 uint32_t dest_addr,
119 uint16_t dest_port,
120 pcap_timing_update_handler_t *timing_update_handler,
121 pcap_packet_handler_t *packet_handler,
122 void *user_data)
123 {
124 pcap_t *pcap;
125 struct pcap_pkthdr *pkthdr;
126 uint8_t *pktdata;
127 uint8_t *pktptr;
128 const uint8_t *body;
129 int body_len;
130 int total_pkts;
131 uint32_t pktlen;
132 ether_hdr *ethhdr;
133 struct sll_header *sllhdr;
134 null_hdr *nullhdr;
135 struct iphdr *iphdr;
136 #if !defined(__CYGWIN__)
137 ipv6_hdr *ip6hdr;
138 #endif
139 struct udphdr *udphdr;
140 int datalink;
141 int packet_type;
142
143 total_pkts = 0;
144 if ((pcap = pcap_open_offline(file, errbuf)) == NULL)
145 {
146 fprintf(stderr, "Can't open PCAP file: %s\n", errbuf);
147 return -1;
148 }
149 //printf("PCAP file version %d.%d\n", pcap_major_version(pcap), pcap_minor_version(pcap));
150 datalink = pcap_datalink(pcap);
151 /* DLT_EN10MB seems to apply to all forms of ethernet, not just the 10MB kind. */
152 switch (datalink)
153 {
154 case DLT_EN10MB:
155 printf("Datalink type ethernet\n");
156 break;
157 case DLT_LINUX_SLL:
158 printf("Datalink type cooked Linux socket\n");
159 break;
160 case DLT_NULL:
161 printf("Datalink type NULL\n");
162 break;
163 default:
164 fprintf(stderr, "Unsupported data link type %d\n", datalink);
165 return -1;
166 }
167
168 pkthdr = NULL;
169 pktdata = NULL;
170 #if defined(HAVE_PCAP_NEXT_EX)
171 while (pcap_next_ex(pcap, &pkthdr, (const uint8_t **) &pktdata) == 1)
172 {
173 #else
174 if ((pkthdr = (struct pcap_pkthdr *) malloc(sizeof(*pkthdr))) == NULL)
175 {
176 fprintf(stderr, "Can't allocate memory for pcap pkthdr\n");
177 return -1;
178 }
179 while ((pktdata = (uint8_t *) pcap_next(pcap, pkthdr)) != NULL)
180 {
181 #endif
182 pktptr = pktdata;
183 switch (datalink)
184 {
185 case DLT_EN10MB:
186 ethhdr = (ether_hdr *) pktptr;
187 packet_type = ntohs(ethhdr->ether_type);
188 pktptr += sizeof(*ethhdr);
189 /* Check for a 802.1Q Virtual LAN entry we might need to step over */
190 if (packet_type == 0x8100)
191 {
192 /* Step over the 802.1Q stuff, to get to the next packet type */
193 pktptr += sizeof(uint16_t);
194 packet_type = ntohs(*((uint16_t *) pktptr));
195 pktptr += sizeof(uint16_t);
196 }
197 #if !defined(__CYGWIN__)
198 if (packet_type != 0x0800 /* IPv4 */
199 &&
200 packet_type != 0x86DD) /* IPv6 */
201 #else
202 if (packet_type != 0x0800) /* IPv4 */
203 #endif
204 {
205 continue;
206 }
207 iphdr = (struct iphdr *) pktptr;
208 break;
209 case DLT_LINUX_SLL:
210 sllhdr = (struct sll_header *) pktptr;
211 packet_type = ntohs(sllhdr->sll_protocol);
212 pktptr += sizeof(*sllhdr);
213 #if !defined(__CYGWIN__)
214 if (packet_type != 0x0800 /* IPv4 */
215 &&
216 packet_type != 0x86DD) /* IPv6 */
217 #else
218 if (packet_type != 0x0800) /* IPv4 */
219 #endif
220 {
221 continue;
222 }
223 iphdr = (struct iphdr *) pktptr;
224 break;
225 case DLT_NULL:
226 nullhdr = (null_hdr *) pktptr;
227 pktptr += sizeof(*nullhdr);
228 if (nullhdr->pf_type != PF_INET && nullhdr->pf_type != PF_INET6)
229 continue;
230 iphdr = (struct iphdr *) pktptr;
231 break;
232 default:
233 continue;
234 }
235 #if 0
236 {
237 int i;
238 printf("--- %d -", pkthdr->caplen);
239 for (i = 0; i < pkthdr->caplen; i++)
240 printf(" %02x", pktdata[i]);
241 printf("\n");
242 }
243 #endif
244 #if !defined(__CYGWIN__)
245 if (iphdr && iphdr->version == 6)
246 {
247 /* ipv6 */
248 ip6hdr = (ipv6_hdr *) (void *) iphdr;
249 if (ip6hdr->nxt_header != IPPROTO_UDP)
250 continue;
251 pktlen = (uint32_t) pkthdr->len - (pktptr - pktdata) - sizeof(*ip6hdr);
252 udphdr = (struct udphdr *) ((uint8_t *) ip6hdr + sizeof(*ip6hdr));
253 }
254 else
255 #endif
256 {
257 /* ipv4 */
258 if (iphdr->protocol != IPPROTO_UDP)
259 continue;
260 #if defined(__DARWIN) || defined(__CYGWIN__) || defined(__FreeBSD__)
261 udphdr = (struct udphdr *) ((uint8_t *) iphdr + (iphdr->ihl << 2) + 4);
262 pktlen = (uint32_t) ntohs(udphdr->uh_ulen);
263 #elif defined ( __HPUX)
264 udphdr = (struct udphdr *) ((uint8_t *) iphdr + (iphdr->ihl << 2));
265 pktlen = (uint32_t) pkthdr->len - (pktptr - pktdata) - sizeof(*iphdr);
266 #else
267 udphdr = (struct udphdr *) ((uint8_t *) iphdr + (iphdr->ihl << 2));
268 pktlen = (uint32_t) ntohs(udphdr->len);
269 #endif
270 }
271
272 timing_update_handler(user_data, &pkthdr->ts);
273
274 if (src_addr && ntohl(iphdr->saddr) != src_addr)
275 continue;
276 #if defined(__DARWIN) || defined(__CYGWIN__) || defined(__FreeBSD__)
277 if (src_port && ntohs(udphdr->uh_sport) != src_port)
278 #else
279 if (src_port && ntohs(udphdr->source) != src_port)
280 #endif
281 continue;
282 if (dest_addr && ntohl(iphdr->daddr) != dest_addr)
283 continue;
284 #if defined(__DARWIN) || defined(__CYGWIN__) || defined(__FreeBSD__)
285 if (dest_port && ntohs(udphdr->uh_dport) != dest_port)
286 #else
287 if (dest_port && ntohs(udphdr->dest) != dest_port)
288 #endif
289 continue;
290
291 if (pkthdr->len != pkthdr->caplen)
292 {
293 fprintf(stderr, "Truncated packet - total len = %d, captured len = %d\n", pkthdr->len, pkthdr->caplen);
294 exit(2);
295 }
296 #if 0
297 printf("%d:%d -> %d:%d\n", ntohl(iphdr->saddr), ntohs(udphdr->source), ntohl(iphdr->daddr), ntohs(udphdr->dest));
298 #endif
299 body = (const uint8_t *) udphdr;
300 body += sizeof(struct udphdr);
301 body_len = pktlen - sizeof(struct udphdr);
302 packet_handler(user_data, body, body_len);
303
304 total_pkts++;
305 }
306 fprintf(stderr, "In pcap %s there were %d accepted packets\n", file, total_pkts);
307 pcap_close(pcap);
308
309 return 0;
310 }
311 /*- End of function --------------------------------------------------------*/
312 /*- End of file ------------------------------------------------------------*/
313