/*
* Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
* 2002, 2003, 2004
* Ohio University.
*
* ---
*
* Starting with the release of tcptrace version 6 in 2001, tcptrace
* is licensed under the GNU General Public License (GPL). We believe
* that, among the available licenses, the GPL will do the best job of
* allowing tcptrace to continue to be a valuable, freely-available
* and well-maintained tool for the networking community.
*
* Previous versions of tcptrace were released under a license that
* was much less restrictive with respect to how tcptrace could be
* used in commercial products. Because of this, I am willing to
* consider alternate license arrangements as allowed in Section 10 of
* the GNU GPL. Before I would consider licensing tcptrace under an
* alternate agreement with a particular individual or company,
* however, I would have to be convinced that such an alternative
* would be to the greater benefit of the networking community.
*
* ---
*
* This file is part of Tcptrace.
*
* Tcptrace was originally written and continues to be maintained by
* Shawn Ostermann with the help of a group of devoted students and
* users (see the file 'THANKS'). The work on tcptrace has been made
* possible over the years through the generous support of NASA GRC,
* the National Science Foundation, and Sun Microsystems.
*
* Tcptrace is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Tcptrace is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tcptrace (in the file 'COPYING'); if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Author: Shawn Ostermann
* School of Electrical Engineering and Computer Science
* Ohio University
* Athens, OH
* ostermann@cs.ohiou.edu
* http://www.tcptrace.org/
*/
#include "tcptrace.h"
static char const GCC_UNUSED copyright[] =
"@(#)Copyright (c) 2004 -- Ohio University.\n";
/*
* Kevin Lahey (kml@patheticgeek.net)
*/
static char const GCC_UNUSED rcsid[] =
"@(#)$Header: /usr/local/cvs/tcptrace/ns.c,v 1.18 2003/11/19 14:38:04 sdo Exp $";
/*
* ns.c - ns specific file reading stuff
*/
#ifdef GROK_NS
/* Defining SYS_STDIN which is fp for Windows and stdin for all other systems */
#ifdef __WIN32
static FILE *fp;
#define SYS_STDIN fp
#else
#define SYS_STDIN stdin
#endif /* __WIN32 */
/* static buffers for reading */
static struct ether_header *pep;
static int *pip_buf;
static struct ip *ipb;
static struct tcphdr *tcpb;
/* for debugging */
static unsigned linenum;
/* return the next packet header */
/* currently only works for ETHERNET */
static int
pread_ns(
struct timeval *ptime,
int *plen,
int *ptlen,
void **pphys,
int *pphystype,
struct ip **ppip,
void **pplast)
{
static int packlen = 0;
double c, d, e;
while (1) {
/* read the packet info */
char tt;
double timestamp;
int junk;
char type[16];
char flags[16];
int iteration;
int seq;
int is_ack;
int is_tcp;
int rlen;
char myline[128];
char *isend;
++linenum;
isend = fgets(myline, 128, SYS_STDIN);
if (isend == NULL) { // end of file
return(0);
}
/* correct NS output line would have 14 fields: */
rlen = sscanf(myline, "%c %lg %d %d %s %d %s %d %d.%hu %d.%hu %d %hu",
&tt,
×tamp,
&junk,
&junk,
type,
plen,
flags,
&iteration,
&ipb->ip_src.s_addr,
&tcpb->th_sport,
&ipb->ip_dst.s_addr,
&tcpb->th_dport,
&seq,
&ipb->ip_id);
/* if we can't match all 14 fields, we give up on the file */
if (rlen != 14 && rlen != 18) {
fprintf(stderr,"Bad NS packet header in line %u only [%d] arguments can be matched expected 14 or 18 \n", linenum, rlen);
return(0);
}
// find out who put in this line of code, because I'd love
// to know what their reasoning was
//tcpb->th_sport = tcpb->th_dport = iteration;
is_tcp = strcmp(type, "tcp") == 0;
is_ack = strcmp(type, "ack") == 0;
/* if it's not a TCP data segment or ACK, discard and try again */
if (!is_tcp && !is_ack)
continue;
if ((!ns_hdrs && is_tcp) || (ns_hdrs && packlen ==0))
*plen = *plen + sizeof(struct ip) + sizeof(struct tcphdr);
if (packlen == 0 && is_tcp)
packlen = *plen - sizeof(struct ip) - sizeof(struct tcphdr);
if (ns_hdrs && is_tcp)
packlen = *plen- sizeof(struct ip) - sizeof(struct tcphdr);
if (is_ack) /* this is explicitly for SACK that creates packets > 40 Bytes*/
*plen = 40;
ipb->ip_len = htons(*plen);
if (is_tcp) {
tcpb->th_seq = htonl(packlen * seq);
tcpb->th_ack = 0;
} else {
tcpb->th_seq = 0;
tcpb->th_ack = htonl(packlen * (seq + 1));
}
/* make up a reasonable IPv4 packet header */
#ifdef __VMS
ipb->ip_vhl = 0x0405; /* no options, normal length of 20 */
#else
ipb->ip_hl = 5; /* no options, normal length of 20 */
ipb->ip_v = 4; /* IPv4 */
#endif
ipb->ip_tos = 0;
ipb->ip_off = 0;
ipb->ip_ttl = 64; /* nice round number */
ipb->ip_p = 6; /* TCP */
ipb->ip_sum = 0; /* IP checksum, hope it doesn't get checked! */
ipb->ip_id = htons(ipb->ip_id);
/* is the transport "ECN-Capable"? */
if (strchr(flags, 'N') != NULL)
ipb->ip_tos |= IPTOS_ECT;
/* was the "Experienced Congestion" bit set? */
if (strchr(flags, 'E') != NULL)
ipb->ip_tos |= IPTOS_CE;
/* make up a reasonable TCP segment header */
#ifdef __VMS
tcpb->th_xoff = 0x50; /* no options, normal length of 20 */
#else
tcpb->th_off = 5; /* no options, normal length of 20 */
tcpb->th_x2 = 0;
#endif
tcpb->th_flags = TH_ACK; /* sdo: what about first SYN?? */
tcpb->th_sum = 0;
tcpb->th_urp = 0;
tcpb->th_win = htons(65535);
/* x2 *was* reserved, now used for ECN bits */
if (strchr(flags, 'C') != NULL)
#ifdef __VMS
tcpb->th_xoff |= TH_ECN_ECHO;
#else
tcpb->th_x2 |= TH_ECN_ECHO;
#endif
if (strchr(flags, 'A') != NULL)
#ifdef __VMS
tcpb->th_xoff |= TH_CWR;
#else
tcpb->th_x2 |= TH_CWR;
#endif
/* convert floating point timestamp to (tv_sec,tv_usec) */
c = floor(timestamp);
ptime->tv_sec = c;
d = timestamp - (double) ptime->tv_sec;
e = d * 1000000.0;
ptime->tv_usec = e;
*ptlen = *plen;
*ppip = (struct ip *) pip_buf;
*pplast = (char *)pip_buf + *plen;
*pphys = pep;
*pphystype = PHYS_ETHER;
/*
printf("timestamp %g, type %s, plen %d, seq %d, id %d\n",
timestamp, type, *plen, seq, ipb->ip_id);
*/
return(1);
}
}
int pread_ns_fulltcp(
struct timeval *ptime,
int *plen,
int *ptlen,
void **pphys,
int *pphystype,
struct ip **ppip,
void **pplast)
{
double c, d, e;
while (1) {
/* read the packet info */
char tt;
double timestamp;
int junk;
unsigned short junkshort;
char type[16];
char flags[16];
int iteration;
int seqno;
int ackno;
int hdrlen;
int is_ack;
int is_tcp;
int pflags;
int rlen;
char myline[128];
char *isend;
++linenum;
isend = fgets(myline, 128, SYS_STDIN);
if (isend == NULL) { // end of file
return 0;
}
/* correct NS output line would have 14 fields if show_tcphdr_ is 0: */
/* For Full TCP this changes to 18 fields when show_tcp is 1*/
rlen = sscanf(myline, "%c %lg %d %d %s %d %s %d %d.%hu %d.%hu %d %hu %d 0x%x %u %hu",
&tt,
×tamp,
&junk,
&junk,
type,
plen,
flags,
&iteration,
&ipb->ip_src.s_addr,
&tcpb->th_sport,
&ipb->ip_dst.s_addr,
&tcpb->th_dport,
&seqno,
&ipb->ip_id,
&ackno,
&pflags,
&hdrlen,
&junkshort);
/* if we can't match all 18 fields, we give up on the file */
if (rlen != 18) {
fprintf(stderr, "\"%s\"\n", myline);
fprintf(stderr,"Bad NS packet header in line %u only [%d] arguments can be matched expected 14 or 18 \n", linenum, rlen);
fprintf(stderr,"Is this a Full Tcp Header?\n");
return(0);
}
//tcpb->th_sport = tcpb->th_dport = iteration;
is_tcp = strcmp(type, "tcp") == 0;
is_ack = strcmp(type, "ack") == 0;
/* if it's not a TCP data segment or ACK, discard and try again */
if (!is_tcp && !is_ack)
continue;
/* we have biger header than 40 Bytes (SACK?) */
if (hdrlen > sizeof(struct ip) + sizeof(struct tcphdr)){
*plen -= (hdrlen - (sizeof(struct ip) + sizeof(struct tcphdr)));
}
ipb->ip_len = htons(*plen);
tcpb->th_seq = htonl(seqno);
tcpb->th_ack = htonl(ackno);
/* make up a reasonable IPv4 packet header */
ipb->ip_hl = 5; /* no options, normal length of 20 */
ipb->ip_v = 4; /* IPv4 */
ipb->ip_tos = 0;
ipb->ip_off = 0;
ipb->ip_ttl = 64; /* nice round number */
ipb->ip_p = 6; /* TCP */
ipb->ip_sum = 0; /* IP checksum, hope it doesn't get checked! */
ipb->ip_id = ipb->ip_id;
/* is the transport "ECN-Capable"? */
if (strchr(flags, 'N') != NULL)
ipb->ip_tos |= IPTOS_ECT;
/* was the "Experienced Congestion" bit set? */
if (strchr(flags, 'E') != NULL)
ipb->ip_tos |= IPTOS_CE;
/* make up a reasonable TCP segment header */
tcpb->th_off = 5; /* no options, normal length of 20 */
tcpb->th_flags = pflags; /* sdo: what about first SYN?? */
tcpb->th_x2 = 0;
tcpb->th_sum = 0;
tcpb->th_urp = 0;
tcpb->th_win = htons(65535);
/* x2 *was* reserved, now used for ECN bits */
if (strchr(flags, 'C') != NULL)
tcpb->th_x2 |= TH_ECN_ECHO;
if (strchr(flags, 'A') != NULL)
tcpb->th_x2 |= TH_CWR;
/* convert floating point timestamp to (tv_sec,tv_usec) */
c = floor(timestamp);
ptime->tv_sec = c;
d = timestamp - (double) ptime->tv_sec;
e = d * 1000000.0;
ptime->tv_usec = e;
*ptlen = *plen;
*ppip = (struct ip *) pip_buf;
*pplast = (char *)pip_buf + *plen;
*pphys = pep;
*pphystype = PHYS_ETHER;
/* printf("timestamp %g, type %s, plen %d, seq %d, id %d, ack %d, 0x%x %d \n",
timestamp, type, *plen, seqno, ipb->ip_id,ackno,pflags,hdrlen); */
return(1);
}
return(0);
}
/*
* is_ns() is the input file in ns format??
*/
pread_f *is_ns(char *filename)
{
int rlen;
char tt;
int junk;
double junkd;
char junks[20];
unsigned short junkshort;
int hdrlen = 0;
int pflags = 0;
char myline[128]; // read into this line and then parse for values
#ifdef __WIN32
if((fp = fopen(filename, "r")) == NULL) {
perror(filename);
exit(-1);
}
#endif /* __WIN32 */
fgets(myline, 128, SYS_STDIN);
rlen = sscanf(myline,
"%c %lg %d %d %s %d %s %d %d.%hu %d.%hu %d %hu %d 0x%x %u %hu",
&tt, &junkd, &junk, &junk, (char *)&junks, &junk,
(char *)&junks, &junk, &junk, &junkshort, &junk,
&junkshort, &junk, &junkshort, &junk, &pflags, &hdrlen,
&junkshort);
if ((rlen = getc(SYS_STDIN)) == EOF) {
return(NULL);
} else {
if (ungetc(rlen, SYS_STDIN) == EOF)
return NULL;
}
switch (tt) {
case '+':
case '-':
case 'h':
case 'r':
case 'd':
break;
default:
return(NULL);
}
/* OK, it's mine. Init some stuff */
pep = MallocZ(sizeof(struct ether_header));
pip_buf = MallocZ(IP_MAXPACKET);
ipb = (struct ip *) pip_buf;
tcpb = (struct tcphdr *) (ipb + 1);
/* Set up the stuff that shouldn't change */
pep->ether_type = ETHERTYPE_IP;
/* init line count (we might be called several times, must be done here) */
linenum = 0;
/* Lets check if it is FullTCP or not*/
if (hdrlen || pflags){ /*it is FullTCP */
/* printf("Full TCP \n"); */
rewind(SYS_STDIN);
return(pread_ns_fulltcp);
}
else{ /*Regular TCP (with or without tcpheaders activated */
return(pread_ns);
}
}
#endif /* GROK_NS */
syntax highlighted by Code2HTML, v. 0.9.1