1 /*
2  * Copyright (c) 2000 Paul Herman
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $Id: tcpprof.c,v 1.7 2002/01/19 04:31:37 pherman Exp $
28  */
29 
30 #include "tcpprof.h"
31 
32 char	numbers_only		= 0;
33 char	filterexpr[BUF_SIZ]	= "";
34 char	registered_only		= 0;
35 char	src_dest_split		= 0;
36 int	ports_to_show		= IPPORT_RESERVED;
37 int	lines_to_show		= -1;
38 
39 #define USAGE 								\
40 "Usage: %s [-?hnpR] [-f filter expr] [-i interface] [-P port]		\
41 \n		[-r file] [-s seconds] [-S letters] [-t lines]		\
42 \n	-?, -h 		- display this help				\
43 \n	-d		- show source/dest statistics			\
44 \n	-f filter expr	- tcpdump(1) filter expression			\
45 \n	-i interface	- do live capture on [interface], not from file \
46 \n	-n		- don't resolve network numbers			\
47 \n	-p		- non-promiscuous mode when doing live capture	\
48 \n	-P port		- ignore port numbers >= port			\
49 \n	-r file		- read tcpdump data from file			\
50 \n	-R		- display only registered ports			\
51 \n	-s seconds	- capture only [seconds] long			\
52 \n	-S letters	- collect stats					\
53 \n		a		- collect ALL stats			\
54 \n		l		- collect link stats			\
55 \n		i		- collect ip stats			\
56 \n		p		- collect port stats			\
57 \n		h		- collect host stats			\
58 \n		n		- collect network stats			\
59 \n	-t lines	- show at most [lines] lines for each stat	\
60 \n									\
61 \nExample: %s -S ph -r data.dump					\
62 \n	Displays port and host statistics from the file 'data.dump'	\
63 \n"
64 
my_hook(packet_data * pd,void ** args)65 void my_hook(packet_data *pd, void **args) {
66 	u_int		*types;
67 
68 	types = (u_int *) *args++;
69 	stats_insert(pd, *types);
70 }
71 
72 /*
73  * process_file() takes the output of tcpdump, saves packets, and creates
74  * statistics
75  */
process_file(char * fname,u_int s_types,int flags,Double capture_seconds)76 void process_file(char *fname, u_int s_types, int flags, Double capture_seconds) {
77 	void		*argv[1];
78 
79 	stats_initdb(s_types);
80 
81 	argv[0] = (void *) &s_types;
82 	if (get_dump_data(fname, filterexpr, flags, capture_seconds, my_hook, argv) == 0)
83 		show_results(s_types);
84 
85 	stats_closedb();
86 }
87 
parse_stats_types(char * in)88 u_int parse_stats_types(char *in) {
89 	u_int ret = 0;
90 	while (*in) {
91 		if (*in == 'l' || *in == 'a' ) ret |= TYPE_LINK;
92 		if (*in == 'i' || *in == 'a' ) ret |= TYPE_IP_PROTO;
93 		if (*in == 'p' || *in == 'a' ) ret |= TYPE_PORT;
94 		if (*in == 'h' || *in == 'a' ) ret |= TYPE_HOST;
95 		if (*in == 'n' || *in == 'a' ) ret |= TYPE_NET;
96 		in++;
97 		}
98 	return ret;
99 }
100 
Usage(int r,char * prog)101 int Usage(int r, char *prog) {
102 	fprintf(stderr, USAGE, my_basename(prog), prog);
103 	return r;
104 }
105 
error(char * s)106 void error(char *s) {
107 	fprintf(stderr, "error: %s\n", s);
108 	Usage(-1, "tcpprof"); exit(-1);
109 }
110 
main(int argc,char ** argv)111 int main(int argc, char **argv) {
112 	char	filename[BUF_SIZ];
113 	u_int	stats_types = TYPE_ALL;
114 	int	flags = GET_TCPD_COUNT_LINKSIZE | GET_TCPD_DO_LIVE_PROMISC;
115 	int	ch;
116 	Double	capture_seconds = -1.0;
117 
118 	filename[0] = 0;
119 	while ( (ch = getopt(argc, argv, "h?ndpP:Rf:i:s:S:r:t:")) != -1) {
120 		switch(ch) {
121 			case 'h':
122 			case '?':
123 				return Usage(1, argv[0]);
124 				break;
125 			case 'd':
126 				src_dest_split = 1;
127 				break;
128 			case 'f':
129 				strncpy(filterexpr, optarg, BUF_SIZ);
130 				break;
131 			case 'i':
132 				strncpy(filename, optarg, BUF_SIZ);
133 				flags |= GET_TCPD_DO_LIVE;
134 				break;
135 			case 'r':
136 				strncpy(filename, optarg, BUF_SIZ);
137 				flags &= ~GET_TCPD_DO_LIVE;
138 				break;
139 			case 'n':
140 				numbers_only = 1;
141 				break;
142 			case 'p':
143 				flags &= ~GET_TCPD_DO_LIVE_PROMISC;
144 				break;
145 			case 'P':
146 				ports_to_show = (int) strtol(optarg, NULL, 10);
147 				registered_only = 1;
148 				break;
149 			case 'R':
150 				registered_only = 1;
151 				break;
152 			case 's':
153 				capture_seconds = atof(optarg);
154 				if (capture_seconds <= 0.0 &&
155 				    capture_seconds != -1.0)
156 					return Usage(1, argv[0]);
157 				break;
158 			case 'S':
159 				stats_types |= parse_stats_types(optarg);
160 				break;
161 			case 't':
162 				lines_to_show = (int) strtol(optarg, NULL, 10);
163 				break;
164 			default:
165 				break;
166 			}
167 		}
168 
169 	if (filename == NULL || strlen(filename) < 1) {
170 		strncpy(filename, "auto", BUF_SIZ);
171 		flags |= GET_TCPD_DO_LIVE;
172 		}
173 
174 	process_file(filename, stats_types, flags, capture_seconds);
175 
176 	return 0;
177 }
178