1.1.3
by ARAKI Yasuhiro
Import upstream version 2.0.1 |
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 |
#include <pcap.h> |
|
19 |
#include <stdlib.h> |
|
20 |
#include <netinet/in.h> |
|
21 |
#include <netinet/udp.h> |
|
22 |
#if defined(__HPUX) || defined(__CYGWIN)
|
|
23 |
#include <netinet/in_systm.h> |
|
24 |
#endif
|
|
25 |
#include <netinet/ip.h> |
|
26 |
#ifndef __CYGWIN
|
|
27 |
#include <netinet/ip6.h> |
|
28 |
#endif
|
|
29 |
#include <string.h> |
|
30 |
||
31 |
#include "prepare_pcap.h" |
|
32 |
#include "screen.hpp" |
|
33 |
||
34 |
/* We define our own structures for Ethernet Header and IPv6 Header as they are not available on CYGWIN.
|
|
35 |
* We only need the fields, which are necessary to determine the type of the next header.
|
|
36 |
* we could also define our own structures for UDP and IPv4. We currently use the structures
|
|
37 |
* made available by the platform, as we had no problems to get them on all supported platforms.
|
|
38 |
*/
|
|
39 |
||
40 |
typedef struct _ether_hdr { |
|
41 |
char ether_dst[6]; |
|
42 |
char ether_src[6]; |
|
43 |
u_int16_t ether_type; /* we only need the type, so we can determine, if the next header is IPv4 or IPv6 */ |
|
44 |
} ether_hdr; |
|
45 |
||
46 |
typedef struct _ipv6_hdr { |
|
47 |
char dontcare[6]; |
|
48 |
u_int8_t nxt_header; /* we only need the next header, so we can determine, if the next header is UDP or not */ |
|
49 |
char dontcare2[33]; |
|
50 |
} ipv6_hdr; |
|
51 |
||
52 |
||
53 |
#ifdef __HPUX
|
|
54 |
int check(u_int16_t *buffer, int len){ |
|
55 |
#else
|
|
56 |
inline int check(u_int16_t *buffer, int len){ |
|
57 |
#endif
|
|
58 |
int sum; |
|
59 |
int i; |
|
60 |
sum = 0; |
|
61 |
||
62 |
for (i=0; i<(len&~1); i+= 2) |
|
63 |
sum += *buffer++; |
|
64 |
||
65 |
if (len & 1) { |
|
66 |
sum += htons( (*(const u_int8_t *)buffer) << 8); |
|
67 |
}
|
|
68 |
return sum; |
|
69 |
}
|
|
70 |
||
71 |
#ifdef __HPUX
|
|
72 |
u_int16_t checksum_carry(int s) { |
|
73 |
#else
|
|
74 |
inline u_int16_t checksum_carry(int s) { |
|
75 |
#endif
|
|
76 |
int s_c = (s >> 16) + (s & 0xffff); |
|
77 |
return (~(s_c + (s_c >> 16)) & 0xffff); |
|
78 |
}
|
|
79 |
||
80 |
char errbuf[PCAP_ERRBUF_SIZE]; |
|
81 |
||
82 |
/* prepare a pcap file
|
|
83 |
*/
|
|
84 |
int prepare_pkts(char *file, pcap_pkts *pkts) { |
|
85 |
pcap_t *pcap; |
|
86 |
struct pcap_pkthdr *pkthdr = NULL; |
|
87 |
u_char *pktdata = NULL; |
|
88 |
int n_pkts = 0; |
|
89 |
u_long max_length = 0; |
|
90 |
u_int16_t base = 0xffff; |
|
91 |
u_long pktlen; |
|
92 |
pcap_pkt *pkt_index; |
|
93 |
ether_hdr *ethhdr; |
|
94 |
struct iphdr *iphdr; |
|
95 |
ipv6_hdr *ip6hdr; |
|
96 |
struct udphdr *udphdr; |
|
97 |
||
98 |
pkts->pkts = NULL; |
|
99 |
||
100 |
pcap = pcap_open_offline(file, errbuf); |
|
101 |
if (!pcap) |
|
102 |
ERROR_P1("Can't open PCAP file '%s'", file); |
|
103 |
||
104 |
#if HAVE_PCAP_NEXT_EX
|
|
105 |
while (pcap_next_ex (pcap, &pkthdr, (const u_char **) &pktdata) == 1) |
|
106 |
{
|
|
107 |
#else
|
|
108 |
#ifdef __HPUX
|
|
109 |
pkthdr = (pcap_pkthdr *) malloc (sizeof (*pkthdr)); |
|
110 |
#else
|
|
111 |
pkthdr = malloc (sizeof (*pkthdr)); |
|
112 |
#endif
|
|
113 |
if (!pkthdr) |
|
114 |
ERROR("Can't allocate memory for pcap pkthdr"); |
|
115 |
while ((pktdata = (u_char *) pcap_next (pcap, pkthdr)) != NULL) |
|
116 |
{
|
|
117 |
#endif
|
|
118 |
ethhdr = (ether_hdr *)pktdata; |
|
119 |
if (ntohs(ethhdr->ether_type) != 0x0800 /* IPv4 */ |
|
120 |
&& ntohs(ethhdr->ether_type) != 0x86dd) /* IPv6 */ { |
|
121 |
fprintf(stderr, "Ignoring non IP{4,6} packet!\n"); |
|
122 |
continue; |
|
123 |
}
|
|
124 |
iphdr = (struct iphdr *)((char *)ethhdr + sizeof(*ethhdr)); |
|
125 |
if (iphdr && iphdr->version == 6) { |
|
126 |
//ipv6
|
|
127 |
pktlen = (u_long) pkthdr->len - sizeof(*ethhdr) - sizeof(*ip6hdr); |
|
128 |
ip6hdr = (ipv6_hdr *)(void *) iphdr; |
|
129 |
if (ip6hdr->nxt_header != IPPROTO_UDP) { |
|
130 |
fprintf(stderr, "prepare_pcap.c: Ignoring non UDP packet!\n"); |
|
131 |
continue; |
|
132 |
}
|
|
133 |
udphdr = (struct udphdr *)((char *)ip6hdr + sizeof(*ip6hdr)); |
|
134 |
} else { |
|
135 |
//ipv4
|
|
136 |
if (iphdr->protocol != IPPROTO_UDP) { |
|
137 |
fprintf(stderr, "prepare_pcap.c: Ignoring non UDP packet!\n"); |
|
138 |
continue; |
|
139 |
}
|
|
140 |
#if defined(__DARWIN) || defined(__CYGWIN)
|
|
141 |
udphdr = (struct udphdr *)((char *)iphdr + (iphdr->ihl << 2) + 4); |
|
142 |
pktlen = (u_long)(ntohs(udphdr->uh_ulen)); |
|
143 |
#elif defined ( __HPUX)
|
|
144 |
udphdr = (struct udphdr *)((char *)iphdr + (iphdr->ihl << 2)); |
|
145 |
pktlen = (u_long) pkthdr->len - sizeof(*ethhdr) - sizeof(*iphdr); |
|
146 |
#else
|
|
147 |
udphdr = (struct udphdr *)((char *)iphdr + (iphdr->ihl << 2)); |
|
148 |
pktlen = (u_long)(ntohs(udphdr->len)); |
|
149 |
#endif
|
|
150 |
}
|
|
151 |
if (pktlen > PCAP_MAXPACKET) { |
|
152 |
ERROR("Packet size is too big! Recompile with bigger PCAP_MAXPACKET in prepare_pcap.h"); |
|
153 |
}
|
|
154 |
pkts->pkts = (pcap_pkt *) realloc(pkts->pkts, sizeof(*(pkts->pkts)) * (n_pkts + 1)); |
|
155 |
if (!pkts->pkts) |
|
156 |
ERROR("Can't re-allocate memory for pcap pkt"); |
|
157 |
pkt_index = pkts->pkts + n_pkts; |
|
158 |
pkt_index->pktlen = pktlen; |
|
159 |
pkt_index->ts = pkthdr->ts; |
|
160 |
pkt_index->data = (unsigned char *) malloc(pktlen); |
|
161 |
if (!pkt_index->data) |
|
162 |
ERROR("Can't allocate memory for pcap pkt data"); |
|
163 |
memcpy(pkt_index->data, udphdr, pktlen); |
|
164 |
||
165 |
#if defined(__HPUX) || defined(__DARWIN) || (defined __CYGWIN)
|
|
166 |
udphdr->uh_sum = 0 ; |
|
167 |
#else
|
|
168 |
udphdr->check = 0; |
|
169 |
#endif
|
|
170 |
||
171 |
// compute a partial udp checksum
|
|
172 |
// not including port that will be changed
|
|
173 |
// when sending RTP
|
|
174 |
#if defined(__HPUX) || defined(__DARWIN) || (defined __CYGWIN)
|
|
175 |
pkt_index->partial_check = check((u_int16_t *) &udphdr->uh_ulen, pktlen - 4) + ntohs(IPPROTO_UDP + pktlen); |
|
176 |
#else
|
|
177 |
pkt_index->partial_check = check((u_int16_t *) &udphdr->len, pktlen - 4) + ntohs(IPPROTO_UDP + pktlen); |
|
178 |
#endif
|
|
179 |
if (max_length < pktlen) |
|
180 |
max_length = pktlen; |
|
181 |
#if defined(__HPUX) || defined(__DARWIN) || (defined __CYGWIN)
|
|
182 |
if (base > ntohs(udphdr->uh_dport)) |
|
183 |
base = ntohs(udphdr->uh_dport); |
|
184 |
#else
|
|
185 |
if (base > ntohs(udphdr->dest)) |
|
186 |
base = ntohs(udphdr->dest); |
|
187 |
#endif
|
|
188 |
n_pkts++; |
|
189 |
}
|
|
190 |
pkts->max = pkts->pkts + n_pkts; |
|
191 |
pkts->max_length = max_length; |
|
192 |
pkts->base = base; |
|
193 |
fprintf(stderr, "In pcap %s, npkts %d\nmax pkt length %ld\nbase port %d\n", file, n_pkts, max_length, base); |
|
194 |
pcap_close(pcap); |
|
195 |
||
196 |
return 0; |
|
197 |
}
|
|
198 |
||
199 |
void free_pkts(pcap_pkts *pkts) { |
|
200 |
pcap_pkt *pkt_index; |
|
201 |
while (pkt_index < pkts->max) { |
|
202 |
free(pkt_index->data); |
|
203 |
}
|
|
204 |
free(pkts->pkts); |
|
205 |
}
|