/*
* 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";
static char const GCC_UNUSED rcsid[] =
"@(#)$Header: /usr/local/cvs/tcptrace/udp.c,v 5.9 2003/11/19 14:38:06 sdo Exp $";
#include "gcache.h"
/* locally global variables */
static int packet_count = 0;
static int search_count = 0;
static Bool *ignore_pairs = NULL;/* which ones will we ignore */
static Bool more_conns_ignored = FALSE;
/* provided globals */
int num_udp_pairs = -1; /* how many pairs we've allocated */
udp_pair **utp = NULL; /* array of pointers to allocated pairs */
int max_udp_pairs = 64; /* initial value, automatically increases */
u_long udp_trace_count = 0;
/* local routine definitions */
static udp_pair *NewUTP(struct ip *, struct udphdr *);
static udp_pair *FindUTP(struct ip *, struct udphdr *, int *);
static void MoreUdpPairs(int num_needed);
static udp_pair *
NewUTP(
struct ip *pip,
struct udphdr *pudp)
{
udp_pair *pup;
if (0) {
printf("trace.c:NewUTP() calling MakeUdpPair()\n");
}
pup = MakeUdpPair();
++num_udp_pairs;
/* make a new one, if possible */
if ((num_udp_pairs+1) >= max_udp_pairs) {
MoreUdpPairs(num_udp_pairs+1);
}
/* create a new UDP pair record and remember where you put it */
utp[num_udp_pairs] = pup;
pup->ignore_pair=ignore_pairs[num_udp_pairs];
/* grab the address from this packet */
CopyAddr(&pup->addr_pair,
pip, ntohs(pudp->uh_sport), ntohs(pudp->uh_dport));
/* data structure setup */
pup->a2b.pup = pup;
pup->b2a.pup = pup;
pup->a2b.ptwin = &pup->b2a;
pup->b2a.ptwin = &pup->a2b;
/* fill in connection name fields */
pup->a2b.host_letter = strdup(NextHostLetter());
pup->b2a.host_letter = strdup(NextHostLetter());
pup->a_hostname = strdup(HostName(pup->addr_pair.a_address));
pup->a_portname = strdup(ServiceName(pup->addr_pair.a_port));
pup->a_endpoint =
strdup(EndpointName(pup->addr_pair.a_address,
pup->addr_pair.a_port));
pup->b_hostname = strdup(HostName(pup->addr_pair.b_address));
pup->b_portname = strdup(ServiceName(pup->addr_pair.b_port));
pup->b_endpoint =
strdup(EndpointName(pup->addr_pair.b_address,
pup->addr_pair.b_port));
pup->filename = cur_filename;
return(pup);
}
/* connection records are stored in a hash table. Buckets are linked */
/* lists sorted by most recent access. */
#define HASH_TABLE_SIZE 1021 /* oughta be prime */
static udp_pair *
FindUTP(
struct ip *pip,
struct udphdr *pudp,
int *pdir)
{
static udp_pair *pup_hashtable[HASH_TABLE_SIZE] = {NULL};
udp_pair **ppup_head = NULL;
udp_pair *pup;
udp_pair *pup_last;
udp_pair tp_in;
int dir;
hash hval;
/* grab the address from this packet */
CopyAddr(&tp_in.addr_pair, pip,
ntohs(pudp->uh_sport), ntohs(pudp->uh_dport));
/* grab the hash value (already computed by CopyAddr) */
hval = tp_in.addr_pair.hash % HASH_TABLE_SIZE;
pup_last = NULL;
ppup_head = &pup_hashtable[hval];
for (pup = *ppup_head; pup; pup=pup->next) {
++search_count;
if (SameConn(&tp_in.addr_pair,&pup->addr_pair,&dir)) {
/* move to head of access list (unless already there) */
if (pup != *ppup_head) {
pup_last->next = pup->next; /* unlink */
pup->next = *ppup_head; /* move to head */
*ppup_head = pup;
}
*pdir = dir;
return(pup);
}
pup_last = pup;
}
/* Didn't find it, make a new one, if possible */
pup = NewUTP(pip,pudp);
/* put at the head of the access list */
if (pup) {
pup->next = *ppup_head;
*ppup_head = pup;
}
*pdir = A2B;
return(pup);
}
void IgnoreUDPConn(
int ix)
{
if (debug)
fprintf(stderr,"ignoring conn %d\n", ix);
--ix;
MoreUdpPairs(ix);
more_conns_ignored=FALSE;
ignore_pairs[ix]=TRUE;
}
void
OnlyUDPConn(
int ix_only)
{
int ix;
static Bool cleared = FALSE;
if (debug) fprintf(stderr,"only printing conn %d\n", ix_only);
--ix_only;
MoreUdpPairs(ix_only);
if (!cleared) {
for (ix = 0; ix < max_udp_pairs; ++ix) {
ignore_pairs[ix] = TRUE;
}
cleared = TRUE;
}
more_conns_ignored = TRUE;
ignore_pairs[ix_only] = FALSE;
}
udp_pair *
udpdotrace(
struct ip *pip,
struct udphdr *pudp,
void *plast)
{
udp_pair *pup_save;
ucb *thisdir;
ucb *otherdir;
udp_pair tp_in;
int dir;
u_short uh_sport; /* source port */
u_short uh_dport; /* destination port */
u_short uh_ulen; /* data length */
/* make sure we have enough of the packet */
if ((char *)pudp + sizeof(struct udphdr)-1 > (char *)plast) {
if (warn_printtrunc)
fprintf(stderr,
"UDP packet %lu truncated too short to trace, ignored\n",
pnum);
++ctrunc;
return(NULL);
}
/* convert interesting fields to local byte order */
uh_sport = ntohs(pudp->uh_sport);
uh_dport = ntohs(pudp->uh_dport);
uh_ulen = ntohs(pudp->uh_ulen);
/* make sure this is one of the connections we want */
pup_save = FindUTP(pip,pudp,&dir);
++packet_count;
if (pup_save == NULL) {
return(NULL);
}
++udp_trace_count;
/* do time stats */
if (ZERO_TIME(&pup_save->first_time)) {
pup_save->first_time = current_time;
}
pup_save->last_time = current_time;
// Lets not waste any more CPU cycles if we are ignoring this connection.
if (pup_save->ignore_pair)
return (pup_save);
/* save to a file if requested */
if (output_filename) {
PcapSavePacket(output_filename,pip,plast);
}
/* now, print it if requested */
if (printem && !printallofem) {
printf("Packet %lu\n", pnum);
printpacket(0, /* original length not available */
(char *)plast - (char *)pip + 1,
NULL,0, /* physical stuff not known here */
pip,plast,NULL);
}
/* grab the address from this packet */
CopyAddr(&tp_in.addr_pair, pip,
uh_sport, uh_dport);
/* figure out which direction this packet is going */
if (dir == A2B) {
thisdir = &pup_save->a2b;
otherdir = &pup_save->b2a;
} else {
thisdir = &pup_save->b2a;
otherdir = &pup_save->a2b;
}
/* do data stats */
thisdir->packets += 1;
thisdir->data_bytes += uh_ulen;
/* total packets stats */
++pup_save->packets;
return(pup_save);
}
void
udptrace_done(void)
{
udp_pair *pup;
int ix;
double etime;
if(do_udp) { // Just a quick sanity check to make sure if we need to do
// anything at all..
if(!run_continuously) {
if (!printsuppress) {
if (udp_trace_count == 0) {
fprintf(stdout,"no traced UDP packets\n");
return;
} else {
if ((tcp_trace_count > 0) && (!printbrief))
printf("\n============================================================\n");
fprintf(stdout,"UDP connection info:\n");
}
}
if (!printbrief)
fprintf(stdout,"%d UDP %s traced:\n",
num_udp_pairs + 1,
num_udp_pairs==0?"connection":"connections");
}
/* elapsed time */
etime = elapsed(first_packet,last_packet);
if (ctrunc > 0) {
fprintf(stdout,
"*** %lu packets were too short to process at some point\n",
ctrunc);
if (!warn_printtrunc)
fprintf(stdout,"\t(use -w option to show details)\n");
}
if (debug>1)
fprintf(stdout,"average search length: %d\n",
search_count / packet_count);
/* print each connection */
if(!run_continuously) {
if (!printsuppress) {
for (ix = 0; ix <= num_udp_pairs; ++ix) {
pup = utp[ix];
if (!pup->ignore_pair) {
if (printbrief) {
fprintf(stdout,"%3d: ", ix+1);
UDPPrintBrief(pup);
} else {
if (ix > 0)
fprintf(stdout,
"================================\n");
fprintf(stdout,"UDP connection %d:\n", ix+1);
UDPPrintTrace(pup);
}
}
}
}
}
}
}
static void
MoreUdpPairs(
int num_needed)
{
int new_max_udp_pairs;
int i;
if (num_needed < max_udp_pairs)
return;
new_max_udp_pairs = max_udp_pairs * 4;
while (new_max_udp_pairs < num_needed)
new_max_udp_pairs *= 4;
if (debug)
printf("trace: making more space for %d total UDP pairs\n",
new_max_udp_pairs);
/* enlarge array to hold any pairs that we might create */
utp = ReallocZ(utp,
max_udp_pairs * sizeof(udp_pair *),
new_max_udp_pairs * sizeof(udp_pair *));
/* enlarge array to keep track of which ones to ignore */
ignore_pairs = ReallocZ(ignore_pairs,
max_udp_pairs * sizeof(Bool),
new_max_udp_pairs * sizeof(Bool));
if (more_conns_ignored)
for (i=max_udp_pairs; i < new_max_udp_pairs;++i)
ignore_pairs[i] = TRUE;
max_udp_pairs = new_max_udp_pairs;
}
void
udptrace_init(void)
{
static Bool initted = FALSE;
if (initted)
return;
initted = TRUE;
/* create an array to hold any pairs that we might create */
utp = (udp_pair **) MallocZ(max_udp_pairs * sizeof(udp_pair *));
/* create an array to keep track of which ones to ignore */
ignore_pairs = (Bool *) MallocZ(max_udp_pairs * sizeof(Bool));
}
syntax highlighted by Code2HTML, v. 0.9.1