/* * 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)); }