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