1 /*
2 * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
3 * 2002, 2003, 2004
4 * Ohio University.
5 *
6 * ---
7 *
8 * Starting with the release of tcptrace version 6 in 2001, tcptrace
9 * is licensed under the GNU General Public License (GPL). We believe
10 * that, among the available licenses, the GPL will do the best job of
11 * allowing tcptrace to continue to be a valuable, freely-available
12 * and well-maintained tool for the networking community.
13 *
14 * Previous versions of tcptrace were released under a license that
15 * was much less restrictive with respect to how tcptrace could be
16 * used in commercial products. Because of this, I am willing to
17 * consider alternate license arrangements as allowed in Section 10 of
18 * the GNU GPL. Before I would consider licensing tcptrace under an
19 * alternate agreement with a particular individual or company,
20 * however, I would have to be convinced that such an alternative
21 * would be to the greater benefit of the networking community.
22 *
23 * ---
24 *
25 * This file is part of Tcptrace.
26 *
27 * Tcptrace was originally written and continues to be maintained by
28 * Shawn Ostermann with the help of a group of devoted students and
29 * users (see the file 'THANKS'). The work on tcptrace has been made
30 * possible over the years through the generous support of NASA GRC,
31 * the National Science Foundation, and Sun Microsystems.
32 *
33 * Tcptrace is free software; you can redistribute it and/or modify it
34 * under the terms of the GNU General Public License as published by
35 * the Free Software Foundation; either version 2 of the License, or
36 * (at your option) any later version.
37 *
38 * Tcptrace is distributed in the hope that it will be useful, but
39 * WITHOUT ANY WARRANTY; without even the implied warranty of
40 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41 * General Public License for more details.
42 *
43 * You should have received a copy of the GNU General Public License
44 * along with Tcptrace (in the file 'COPYING'); if not, write to the
45 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
46 * MA 02111-1307 USA
47 *
48 * Author: Shawn Ostermann
49 * School of Electrical Engineering and Computer Science
50 * Ohio University
51 * Athens, OH
52 * ostermann@cs.ohiou.edu
53 * http://www.tcptrace.org/
54 */
55 #include "tcptrace.h"
56 static char const GCC_UNUSED copyright[] =
57 "@(#)Copyright (c) 2004 -- Ohio University.\n";
58 static char const GCC_UNUSED rcsid[] =
59 "@(#)$Header$";
60
61
62 /*
63 * snoop.c - SNOOP specific file reading stuff
64 * ipv6 addition by Nasseef Abukamail
65 */
66
67
68
69
70 #ifdef GROK_SNOOP
71
72 /* Defining SYS_STDIN which is fp for Windows and stdin for all other systems */
73 #ifdef __WIN32
74 static FILE *fp;
75 #define SYS_STDIN fp
76 #else
77 #define SYS_STDIN stdin
78 #endif /* __WIN32 */
79
80 /* information necessary to understand Solaris Snoop output */
81 struct snoop_file_header {
82 char format_name[8]; /* should be "snoop\0\0\0" */
83 tt_uint32 snoop_version; /* current version is "2" */
84 tt_uint32 mac_type; /* hardware type */
85 };
86 /* snoop hardware types that we understand */
87 /* from sys/dlpi.h */
88 /* -- added prefix SNOOP_ to avoid name clash */
89 #define SNOOP_DL_ETHER 0x4 /* Ethernet Bus */
90 #define SNOOP_DL_FDDI 0x08 /* Fiber Distributed data interface */
91 #define SNOOP_DL_ATM 0x12 /* from Sun's "atmsnoop" */
92
93 struct snoop_packet_header {
94 tt_uint32 len;
95 tt_uint32 tlen;
96 tt_uint32 blen;
97 tt_uint32 unused3;
98 tt_uint32 secs;
99 tt_uint32 usecs;
100 };
101
102
103
104 /* static buffers for reading */
105 static struct ether_header *pep;
106 static int *pip_buf;
107 static int snoop_mac_type;
108
109 /* (Courtesy Jeffrey Semke, Pittsburgh Supercomputing Center) */
110 /* locate ip within FDDI according to RFC 1188 */
find_ip_fddi(char * buf,int iplen)111 static int find_ip_fddi(char* buf, int iplen) {
112 char* ptr, *ptr2;
113 int i;
114 u_char pattern[] = {0xAA, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00};
115 #define FDDIPATTERNLEN 7
116
117 ptr = ptr2 = buf;
118
119 for (i=0; i < FDDIPATTERNLEN; i++) {
120 ptr2 = memchr(ptr,pattern[i],(iplen - (int)(ptr - buf)));
121 if (!ptr2)
122 return (-1);
123 if (i && (ptr2 != ptr)) {
124 ptr2 = ptr2 - i - 1;
125 i = -1;
126 }
127 ptr = ptr2 + 1;
128 }
129 return (ptr2 - buf + 1);
130
131 }
132
133
134 /* return the next packet header */
135 /* currently only works for ETHERNET and FDDI */
136 static int
pread_snoop(struct timeval * ptime,int * plen,int * ptlen,void ** pphys,int * pphystype,struct ip ** ppip,void ** pplast)137 pread_snoop(
138 struct timeval *ptime,
139 int *plen,
140 int *ptlen,
141 void **pphys,
142 int *pphystype,
143 struct ip **ppip,
144 void **pplast)
145 {
146 int packlen;
147 int rlen;
148 int len;
149 struct snoop_packet_header hdr;
150 int hlen;
151
152 while (1) {
153 hlen = sizeof(struct snoop_packet_header);
154
155 /* read the packet header */
156 if ((rlen=fread(&hdr,1,hlen,SYS_STDIN)) != hlen) {
157 if (rlen != 0)
158 fprintf(stderr,"Bad snoop packet header\n");
159 return(0);
160 }
161
162 /* convert some stuff to host byte order */
163 hdr.tlen = ntohl(hdr.tlen);
164 hdr.len = ntohl(hdr.len);
165 hdr.blen = ntohl(hdr.blen);
166 hdr.secs = ntohl(hdr.secs);
167 hdr.usecs = ntohl(hdr.usecs);
168
169 /* truncated packet length */
170 packlen = hdr.tlen;
171
172 /* bug fix from Brian Utterback */
173 /* "blen" is the "total length of the packet", header+data+padding */
174 len = hdr.blen - hlen;
175
176 if (snoop_mac_type == SNOOP_DL_ETHER) {
177 /* read the ethernet header */
178 rlen=fread(pep,1,sizeof(struct ether_header),SYS_STDIN);
179 if (rlen != sizeof(struct ether_header)) {
180 fprintf(stderr,"Couldn't read ether header\n");
181 return(0);
182 }
183
184 /* read the rest of the packet */
185 len -= sizeof(struct ether_header);
186 if (len >= IP_MAXPACKET) {
187 /* sanity check */
188 fprintf(stderr,
189 "pread_snoop: invalid next packet, IP len is %d, return EOF\n", len);
190
191 return(0);
192 }
193
194 /* add VLAN support for John Tysko */
195 if ((ntohs(pep->ether_type) == ETHERTYPE_VLAN) && (len >= 4)){
196 struct {
197 tt_uint16 vlan_num;
198 tt_uint16 vlan_proto;
199 } vlanh;
200
201 /* adjust packet length */
202 len -= 4;
203
204 /* read the vlan header */
205 if ((rlen=fread(&vlanh,1,sizeof(vlanh),SYS_STDIN)) != sizeof(vlanh)) {
206 perror("pread_snoop: seek past vlan header");
207 }
208
209 if ((ntohs(vlanh.vlan_proto) == ETHERTYPE_IP) ||
210 (ntohs(vlanh.vlan_proto) == ETHERTYPE_IPV6)) {
211 /* make it appear to have been IP all along */
212 /* (note that both fields are still in N.B.O. */
213 pep->ether_type = vlanh.vlan_proto;
214 if (debug > 2)
215 printf("Removing VLAN header (vlan:%x)\n",
216 vlanh.vlan_num);
217 } else {
218 if (debug > 2)
219 printf("Skipping a VLAN packet (num:%x proto:%x)\n",
220 vlanh.vlan_num, vlanh.vlan_proto);
221 }
222
223 }
224
225
226 /* if it's not IP, then skip it */
227 if ((ntohs(pep->ether_type) != ETHERTYPE_IP) &&
228 (ntohs(pep->ether_type) != ETHERTYPE_IPV6)) {
229
230
231 if (debug > 2)
232 fprintf(stderr,
233 "pread_snoop: not an IP packet (ethertype 0x%x)\n",
234 ntohs(pep->ether_type));
235 /* discard the remainder */
236 /* N.B. fseek won't work - it could be a pipe! */
237 if ((rlen=fread(pip_buf,1,len,SYS_STDIN)) != len) {
238 perror("pread_snoop: seek past non-IP");
239 }
240
241 continue;
242 }
243
244 if ((rlen=fread(pip_buf,1,len,SYS_STDIN)) != len) {
245 if (rlen != 0 && debug)
246 fprintf(stderr,
247 "Couldn't read %d more bytes, skipping last packet\n",
248 len);
249 return(0);
250 }
251
252 *ppip = (struct ip *) pip_buf;
253 /* last byte in the IP packet */
254 *pplast = (char *)pip_buf+packlen-sizeof(struct ether_header)-1;
255
256 } else if (snoop_mac_type == SNOOP_DL_FDDI) {
257 /* FDDI is different */
258 int offset;
259
260 /* read in the whole frame and search for IP header */
261 /* (assumes sizeof(fddi frame) < IP_MAXPACKET, should be true) */
262 if ((rlen=fread(pip_buf,1,len,SYS_STDIN)) != len) {
263 if (debug && rlen != 0)
264 fprintf(stderr,
265 "Couldn't read %d more bytes, skipping last packet\n",
266 len);
267 return(0);
268 }
269
270 /* find the offset of the IP header inside the FDDI frame */
271 if ((offset = find_ip_fddi((void *)pip_buf,len)) == -1) {
272 /* not found */
273 if (debug)
274 printf("snoop.c: couldn't find next IP within FDDI\n");
275 return(-1);
276 }
277
278 /* copy to avoid alignment problems later (yucc) */
279 /* (we use memmove to make overlaps work) */
280 memmove(pip_buf,(char *)pip_buf+offset,len-offset);
281
282 /* point to first and last char in IP packet */
283 *ppip = (struct ip *) ((void *)pip_buf);
284 *pplast = (char *)pip_buf+len-offset-1;
285
286 /* assume it's IP (else find_ip_fddi would have failed) */
287 pep->ether_type = htons(ETHERTYPE_IP);
288 } else if (snoop_mac_type == SNOOP_DL_ATM) {
289 /* there's a 12 byte header that we don't care about */
290 /* the last 2 of those 12 bytes are the packet type */
291 /* we don't care about hardware header, so we just discard */
292 struct atm_header {
293 u_char junk[10];
294 u_short type;
295 } atm_header;
296
297 /* grab the 12-byte header */
298 rlen=fread(&atm_header,1,sizeof(struct atm_header),SYS_STDIN);
299 if (rlen != sizeof(struct atm_header)) {
300 fprintf(stderr,"Couldn't read ATM header\n");
301 return(0);
302 }
303
304 /* fill in the ethernet type */
305 /* we'll just assume that they're both in the same network
306 byte order */
307 pep->ether_type = atm_header.type;
308
309 /* read the rest of the packet */
310 len -= sizeof(struct atm_header);
311 if (len >= IP_MAXPACKET) {
312 /* sanity check */
313 fprintf(stderr,
314 "pread_snoop: invalid next packet, IP len is %d, return EOF\n", len);
315
316 return(0);
317 }
318
319 /* if it's not IP, then skip it */
320 if ((ntohs(pep->ether_type) != ETHERTYPE_IP) &&
321 (ntohs(pep->ether_type) != ETHERTYPE_IPV6)) {
322 if (debug > 2)
323 fprintf(stderr,
324 "pread_snoop: not an IP packet (ethertype 0x%x)\n",
325 ntohs(pep->ether_type));
326 /* discard the remainder */
327 /* N.B. fseek won't work - it could be a pipe! */
328 if ((rlen=fread(pip_buf,1,len,SYS_STDIN)) != len) {
329 perror("pread_snoop: seek past non-IP");
330 }
331
332 continue;
333 }
334
335 if ((rlen=fread(pip_buf,1,len,SYS_STDIN)) != len) {
336 if (rlen != 0 && debug)
337 fprintf(stderr,
338 "Couldn't read %d more bytes, skipping last packet\n",
339 len);
340 return(0);
341 }
342
343 *ppip = (struct ip *) pip_buf;
344 /* last byte in the IP packet */
345 *pplast = (char *)pip_buf+packlen-sizeof(struct ether_header)-1;
346 } else {
347 printf("snoop hardware type %d not understood\n",
348 snoop_mac_type);
349
350 exit(-1);
351 }
352
353
354 /* save pointer to physical header (always ethernet) */
355 *pphys = pep;
356 *pphystype = PHYS_ETHER;
357
358
359 ptime->tv_sec = hdr.secs;
360 ptime->tv_usec = hdr.usecs;
361 *plen = hdr.len;
362 *ptlen = hdr.tlen;
363
364
365 return(1);
366 }
367 }
368
369
370
371 /*
372 * is_snoop() is the input file in snoop format??
373 */
is_snoop(char * filename)374 pread_f *is_snoop(char *filename)
375 {
376 struct snoop_file_header buf;
377 int rlen;
378
379 #ifdef __WIN32
380 if((fp = fopen(filename, "r")) == NULL) {
381 perror(filename);
382 exit(-1);
383 }
384 #endif /* __WIN32 */
385
386 /* read the snoop file header */
387 if ((rlen=fread(&buf,1,sizeof(buf),SYS_STDIN)) != sizeof(buf)) {
388 rewind(SYS_STDIN);
389 return(NULL);
390 }
391
392 /* first 8 characters should be "snoop\0\0\0" */
393 if (strcmp(buf.format_name,"snoop") != 0)
394 return(NULL);
395
396 /* OK, it's a snoop file */
397
398
399 /* convert some stuff to host byte order */
400 buf.snoop_version = ntohl(buf.snoop_version);
401 buf.mac_type = ntohl(buf.mac_type);
402
403 /* sanity check on snoop version */
404 if (debug) {
405 printf("Snoop version: %ld\n", buf.snoop_version);
406 }
407 if (buf.snoop_version != 2) {
408 printf("\
409 Warning! snoop file is version %ld.\n\
410 Tcptrace is only known to work with version 2\n",
411 buf.snoop_version);
412 }
413
414 /* sanity check on hardware type */
415 snoop_mac_type = buf.mac_type;
416 switch (buf.mac_type) {
417 case SNOOP_DL_ETHER:
418 if (debug)
419 printf("Snoop hw type: %ld (Ethernet)\n", buf.mac_type);
420 break;
421 case SNOOP_DL_FDDI:
422 if (debug)
423 printf("Snoop hw type: %ld (FDDI)\n", buf.mac_type);
424 break;
425 case SNOOP_DL_ATM:
426 if (debug)
427 printf("Snoop hw type: %ld (ATM)\n", buf.mac_type);
428 break;
429 default:
430 if (debug)
431 printf("Snoop hw type: %ld (unknown)\n", buf.mac_type);
432 printf("snoop hardware type %ld not understood\n", buf.mac_type);
433
434 exit(-1);
435 }
436
437
438 /* OK, it's mine. Init some stuff */
439 pep = MallocZ(sizeof(struct ether_header));
440 pip_buf = MallocZ(IP_MAXPACKET);
441
442
443 return(pread_snoop);
444 }
445 #endif /* GROK_SNOOP */
446