/* * 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: Marina Bykova * School of Electrical Engineering and Computer Science * Ohio University * Athens, OH * http://www.tcptrace.org/ */ #include "tcptrace.h" static char const GCC_UNUSED rcsid[] = "@(#)$Header: /usr/local/cvs/tcptrace/mod_realtime.c,v 5.7 2003/11/19 14:38:03 sdo Exp $"; #ifdef LOAD_MODULE_REALTIME #include #include "mod_realtime.h" /* info kept for all traced packets */ struct realtime_conn_info { timeval first_time; /* time of the connection's first packet */ timeval last_time; /* time of the connection's last packet */ Bool is_closed; /* is the connection has been closed? */ Bool is_new; /* is the connection new? */ tcp_pair_addrblock addr_pair; tcp_pair *ptp; struct realtime_conn_info *prev; /* pointer to the prev connection */ struct realtime_conn_info *next; /* pointer to the next connection */ }; typedef struct realtime_conn_info rtconn; struct realtime_info { timeval last_scheduled_time; /* time of the last network statistics */ /* as it would appear in the ideal case */ timeval last_actual_time; /* time of the last network statistics */ /* when it actually happened */ rtconn *conn_head; /* head of the list of tcp connections */ rtconn *conn_tail; /* tail of the list of tcp connections */ u_long open_conns; /* number of new connections within the time interval */ u_long total_conns; /* number of currect active connections */ }; typedef struct realtime_info rtinfo; struct protocol { u_char ip_p; u_llong count; struct protocol *next; }; const static int realtime_update_interval = 60; /* global variables */ static rtinfo *mod_info; static u_llong tcp_packets = 0; static u_llong udp_packets = 0; static u_llong nontcpudp_packets = 0; static struct protocol *plist = NULL; /* declarations of memory management functions for the module */ static long rtconn_pool = -1; static rtconn * MakeRtconn( void) { rtconn *ptr = NULL; if (rtconn_pool < 0) { rtconn_pool = MakeMemPool(sizeof(rtconn), 0); } ptr = PoolMalloc(rtconn_pool, sizeof(rtconn)); return ptr; } static void FreeRtconn( rtconn *ptr) { PoolFree(rtconn_pool, ptr); } void realtime_usage(void) { printf("\t-xrealtime\tan example module showing how to use real-time tcptrace\n"); } int realtime_init( int argc, char *argv[]) { int i; int enable = 0; /* look for "-xrealtime" */ for (i = 1; i < argc; ++i) { if (!argv[i]) continue; /* argument already taken by another module... */ if (strncmp(argv[i],"-x", 2) == 0) { if (strncasecmp(argv[i] + 2, "realtime", 8) == 0) { /* I want to be called */ enable = 1; fprintf(stderr, "mod_realtime: Capturing traffic\n"); argv[i] = NULL; } } } if (!enable) return(0); /* don't call me again */ mod_info = (rtinfo *)malloc(sizeof(rtinfo)); mod_info->last_scheduled_time = current_time; mod_info->last_actual_time = current_time; mod_info->conn_head = NULL; mod_info->conn_tail = NULL; mod_info->open_conns = 0; mod_info->total_conns = 0; /* DNS lookups are time expensive, we want to disable them in real-time module */ resolve_ipaddresses = FALSE; resolve_ports = FALSE; /* we want to run the program in real-time mode */ run_continuously = TRUE; /* if you want to set a threshold on the number of connections the program * stores, uncomment this with and modify depending on your needs (must be * different for different monitoring points) */ /* conn_num_threshold = TRUE; update_interval = 60; max_conn_num = 20000; */ do_udp = TRUE; return(1); /* TRUE means call other realtime routines later */ } void realtime_done(void) { struct protocol *pp; fprintf(stdout, "\nrealtime: TCP packets - %" FS_ULL "\n", tcp_packets); fprintf(stdout, "realtime: UDP packets - %" FS_ULL "\n", udp_packets); fprintf(stdout, "realtime: other packets - %" FS_ULL "\n", nontcpudp_packets); for (pp = plist; pp; pp = pp->next) fprintf(stdout, "\tprotocol: %3u, number: %" FS_ULL "\n", pp->ip_p, pp->count); fprintf(stdout, "\n"); } void * realtime_newconn( tcp_pair *ptp) { rtconn *new_conn = MakeRtconn(); if (mod_info->last_scheduled_time.tv_sec == 0) { mod_info->last_scheduled_time = current_time; mod_info->last_actual_time = current_time; } new_conn->first_time = current_time; new_conn->last_time = current_time; new_conn->is_new = TRUE; new_conn->is_closed = FALSE; new_conn->addr_pair = ptp->addr_pair; new_conn->ptp = ptp; new_conn->next = NULL; new_conn->prev = NULL; if (mod_info->conn_head != NULL) { mod_info->conn_tail->next = new_conn; new_conn->prev = mod_info->conn_tail; mod_info->conn_tail = new_conn; } else { /* the list is empty */ mod_info->conn_head = new_conn; mod_info->conn_tail = new_conn; } mod_info->total_conns++; mod_info->open_conns++; return new_conn; } void realtime_deleteconn( tcp_pair *ptp, /* info I have about this connection */ void *mod_data) /* module specific info for this conn*/ { rtconn *conn = mod_data; Bool done = FALSE; if (!conn->is_closed) mod_info->open_conns--; if (conn == mod_info->conn_head) { mod_info->conn_head = mod_info->conn_head->next; if (mod_info->conn_head) { mod_info->conn_head->prev = NULL; } done = TRUE; } if (conn == mod_info->conn_tail) { mod_info->conn_tail = mod_info->conn_tail->prev; if (mod_info->conn_tail) { mod_info->conn_tail->next = NULL; } done = TRUE; } if (!done) { conn->prev->next = conn->next; conn->next->prev = conn->prev; } FreeRtconn(conn); return; } void realtime_read( struct ip *pip, /* the packet */ tcp_pair *ptp, /* info I have about this connection */ void *plast, /* past byte in the packet */ void *mod_data) /* module specific info for this connection */ { rtconn *conn = mod_data; double dtime = 0; ++tcp_packets; /* first, discard any connections that we aren't interested in. */ /* That means that pmodstruct is NULL */ if (conn == NULL) { return; } if (conn->is_new) { dtime = current_time.tv_sec + (current_time.tv_usec / 1000000.0); fprintf(stdout, "%.6f %s\t%s new connection\n", dtime, ptp->a_endpoint, ptp->b_endpoint); conn->is_new = FALSE; } conn->last_time = current_time; if (!conn->is_closed) { if ((FinCount(ptp) >= 1) || (ConnReset(ptp))) { if (dtime == 0) { dtime = current_time.tv_sec + (current_time.tv_usec / 1000000.0); } fprintf(stdout, "%.6f %s\t%s connection closes (had %" FS_ULL " packets)\n", dtime, ptp->a_endpoint, ptp->b_endpoint, ptp->packets); conn->is_closed = TRUE; mod_info->open_conns--; } } if ((elapsed(mod_info->last_scheduled_time, current_time) / 1000000.0) >= realtime_update_interval) { if (dtime == 0) { dtime = current_time.tv_sec + (current_time.tv_usec / 1000000.0); } fprintf(stdout, "%.6f number of open connections is %lu\n", dtime, mod_info->open_conns); mod_info->last_scheduled_time.tv_sec += realtime_update_interval; mod_info->last_actual_time = current_time; } } void realtime_udp_read( struct ip *pip, udp_pair *pup, void *plast, void *pmodstruct) { ++udp_packets; } void realtime_nontcpudp_read( struct ip *pip, void *plast) { struct protocol *last = NULL; struct protocol *current; ++nontcpudp_packets; if (plist == NULL) { plist = (struct protocol *)MallocZ(sizeof(struct protocol)); current = plist; current->count = 1; current->next = NULL; current->ip_p = pip->ip_p; last = current; } else { for (current = plist; current; current = current->next) { if (current->ip_p == pip->ip_p) { current->count++; break; } else { last = current; } } if (current == NULL) { /* protocol is not on our list yet */ current = (struct protocol *)MallocZ(sizeof(struct protocol)); current->ip_p = pip->ip_p; current->count = 1; current->next = NULL; last->next = current; last = current; } } } #endif /* LOAD_MODULE_REALTIME */