1 /*
2 * jnettop, network online traffic visualiser
3 * Copyright (C) 2002-2006 Jakub Skopal
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * $Header: /cvsroot/jnettop/jnettop/jnettop.c,v 1.38 2006/04/12 07:47:01 merunka Exp $
20 *
21 */
22
23 #include "jbase.h"
24 #include "jdevice.h"
25 #include "jcapture.h"
26 #include "jprocessor.h"
27 #include "jresolver.h"
28 #include "jresolv.h"
29 #include "jfilter.h"
30 #include "jutil.h"
31 #include "jconfig.h"
32 #include "jcursesdisplay.h"
33 #include "jtxtdisplay.h"
34 #include "juiadisplay.h"
35 #include "jnetdisplay.h"
36
37 #define DEBUGOUT_NONE 0
38 #define DEBUGOUT_SYSLOG 1
39 #define DEBUGOUT_FILE 2
40 int debugOut = DEBUGOUT_NONE;
41 FILE * debugFile = NULL;
42
43 volatile int threadCount;
44
45 jbase_display * currentDisplay;
46
debug(int priority,const char * format,...)47 void debug(int priority, const char *format, ...) {
48 static char buffer[32768];
49 va_list ap;
50 va_start(ap, format);
51 vsprintf(buffer, format, ap);
52 va_end(ap);
53
54 switch (debugOut) {
55 case DEBUGOUT_FILE:
56 fprintf(debugFile, "%d - %d, %s\n", getpid(), priority, buffer);
57 fflush(debugFile);
58 break;
59 #ifdef SUPPORT_SYSLOG
60 case DEBUGOUT_SYSLOG:
61 syslog(priority, "%d - %d, %s\n", getpid(), priority, buffer);
62 #endif
63 }
64 }
65
jbase_cb_DrawStatus(const gchar * msg)66 void jbase_cb_DrawStatus(const gchar *msg) {
67 currentDisplay->drawstatus(msg);
68 }
69
parseCommandLineAndConfig(int argc,char ** argv)70 void parseCommandLineAndConfig(int argc, char ** argv) {
71 char * configFileName = NULL;
72 char * selectRuleName = NULL;
73 int a;
74
75 jconfig_Setup();
76
77 for (a=1; a<argc; a++) {
78 if (!strcmp(argv[a], "-v") || !strcmp(argv[a], "--version")) {
79 printf(PACKAGE_STRING "\nWritten by Jakub Skopal <j@kubs.cz>\n\nSee copyright in the COPYING file.\n");
80 exit(0);
81 }
82 if (!strcmp(argv[a], "-h") || !strcmp(argv[a], "--help")) {
83 printf( "Usage: jnettop [-hv] [-i interface] [-d filename]\n"
84 "\n"
85 " -h, --help display this help message\n"
86 " -v, --version display version information\n\n"
87 " -b, --bit-units show BPS in bits per second, not bytes per second\n"
88 " -c, --content-filter disable content filtering\n"
89 " -d, --debug filename write debug information into file (or syslog)\n"
90 " --display type type of display (curses, text, uia)\n"
91 " -f, --config-file name reads configuration from file. defaults to ~/.jnettop\n"
92 " --format format list of fields to list in text output\n"
93 " -i, --interface name capture packets on specified interface\n"
94 " --local-aggr arg set local aggregation to none/host/port\n"
95 " -n, --no-resolver disable resolving of addresses\n"
96 " -p, --promiscuous enable promisc mode on the devices\n"
97 " --remote-aggr arg set remote aggregation to none/host/port\n"
98 " -s, --select-rule rule selects one of the rules defined in config file\n"
99 " by it's name\n"
100 " -t, --timeout sec timeout in seconds after which jnettop ends (text display)\n"
101 " -x, --filter rule allows for specification of custom filtering rule\n"
102 " this follows tcpdump(1) syntax. don't forget to\n"
103 " enclose the filter into quotes when running from shell\n"
104 "\n"
105 "Report bugs to <j@kubs.cz>\n"
106 "\n"
107 " Format variable can be CSV (comma separated values), TSV (tab separated values)\n"
108 " or completelly custom format string, where the following identifiers are subst-\n"
109 " ituted when surrounded by '$':\n"
110 " src, srcname, srcport, srcbytes, srcpackets, srcbps, srcpps,\n"
111 " dst, dstname, dstport, dstbytes, dstpackets, dstbps, dstpps,\n"
112 " proto, totalbytes, totalpackets, totalbps, totalpps, filterdata\n"
113 "\n"
114 " example:\n"
115 " jnettop --display text -t 5 --format CSV\n"
116 " jnettop --display text -t 5 --format '$srcname$,$srcport$,$dstname$,$dstport$,$totalbps$'\n"
117 "\n"
118 );
119 exit(0);
120 }
121 if (!strcmp(argv[a], "-c") || !strcmp(argv[a], "--content-filter")) {
122 jconfig_Settings.onoffContentFiltering = FALSE;
123 continue;
124 }
125 if (!strcmp(argv[a], "--display")) {
126 if (a+1>=argc) {
127 fprintf(stderr, "%s switch requires argument\n", argv[a]);
128 exit(255);
129 }
130 ++a;
131 if (jcursesdisplay_Functions.supported && !strcmp(argv[a], "curses")) {
132 currentDisplay = &jcursesdisplay_Functions;
133 } else if (jtxtdisplay_Functions.supported && !strcmp(argv[a], "text")) {
134 currentDisplay = &jtxtdisplay_Functions;
135 } else if (jnetdisplay_Functions.supported && !strcmp(argv[a], "jnet")) {
136 currentDisplay = &jnetdisplay_Functions;
137 } else if (juiadisplay_Functions.supported && !strcmp(argv[a], "uia")) {
138 currentDisplay = &juiadisplay_Functions;
139 } else {
140 fprintf(stderr, "display type %s is not supported.\n", argv[a]);
141 exit(255);
142 }
143 continue;
144 }
145 if (!strcmp(argv[a], "-i") || !strcmp(argv[a], "--interface")) {
146 if (a+1>=argc) {
147 fprintf(stderr, "%s switch requires argument\n", argv[a]);
148 exit(255);
149 }
150 jconfig_Settings.deviceName = argv[++a];
151 continue;
152 }
153 if (!strcmp(argv[a], "-s") || !strcmp(argv[a], "--select-rule")) {
154 if (a+1>=argc) {
155 fprintf(stderr, "%s switch requires argument\n", argv[a]);
156 exit(255);
157 }
158 selectRuleName = argv[++a];
159 continue;
160 }
161 if (!strcmp(argv[a], "-d") || !strcmp(argv[a], "--debug")) {
162 if (a+1>=argc) {
163 fprintf(stderr, "%s switch requires filename to debug to as an argument\n", argv[a]);
164 exit(255);
165 }
166 ++a;
167 if (!strcmp(argv[a], "syslog")) {
168 #ifdef SUPPORT_SYSLOG
169 debugOut = DEBUGOUT_SYSLOG;
170 #else
171 fprintf(stderr, "Syslog output not enabled in compilation\n");
172 exit(255);
173 #endif
174 } else {
175 debugFile = fopen(argv[a], "w");
176 if (!debugFile) {
177 perror("Could not open debug file");
178 exit(255);
179 }
180 debugOut = DEBUGOUT_FILE;
181 }
182 continue;
183 }
184 if (!strcmp(argv[a], "-f") || !strcmp(argv[a], "--config-file")) {
185 if (a+1>=argc) {
186 fprintf(stderr, "%s switch required argument\n", argv[a]);
187 exit(255);
188 }
189 configFileName = argv[++a];
190 continue;
191 }
192 if (!strcmp(argv[a], "-x") || !strcmp(argv[a], "--filter")) {
193 const char *ret;
194 char *commandLineRule;
195 if (a+1>=argc) {
196 fprintf(stderr, "%s switch requires argument\n", argv[a]);
197 exit(255);
198 }
199 commandLineRule = argv[++a];
200 ret = jutil_ValidateBPFFilter(commandLineRule);
201 if (ret) {
202 fprintf(stderr, "Error compiling rule: %s\n", ret);
203 exit(255);
204 }
205 JCONFIG_BPFFILTERS_SETSELECTEDFILTER(JCONFIG_BPFFILTERS_LEN);
206 jconfig_AddBpfFilter("<commandline>", commandLineRule);
207 continue;
208 }
209 if (!strcmp(argv[a], "-p") || !strcmp(argv[a], "--promiscuous")) {
210 jconfig_Settings.onoffPromisc = TRUE;
211 continue;
212 }
213 if (!strcmp(argv[a], "-n") || !strcmp(argv[a], "--no-resolve")) {
214 jconfig_Settings.onoffResolver = FALSE;
215 continue;
216 }
217 if (!strcmp(argv[a], "--local-aggr")) {
218 if (a+1>=argc || (jconfig_Settings.localAggregation = jutil_ParseAggregation(argv[++a]))==-1) {
219 fprintf(stderr, "%s switch requires none, host or port as an argument\n", argv[a]);
220 exit(255);
221 }
222 continue;
223 }
224 if (!strcmp(argv[a], "--remote-aggr")) {
225 if (a+1>=argc || (jconfig_Settings.remoteAggregation = jutil_ParseAggregation(argv[++a]))==-1) {
226 fprintf(stderr, "%s switch requires none, host or port as an argument\n", argv[a]);
227 exit(255);
228 }
229 continue;
230 }
231 {
232 int consumed = currentDisplay->processargument((const gchar **) argv+a, argc-a);
233 if (consumed) {
234 a += consumed - 1;
235 continue;
236 }
237 }
238 fprintf(stderr, "Unknown argument: %s\n", argv[a]);
239 exit(255);
240 }
241
242 if (!jconfig_ParseFile(configFileName)) {
243 exit(255);
244 }
245
246 jconfig_SetDefaults();
247
248 if (selectRuleName) {
249 int i = jconfig_FindBpfFilterByName(selectRuleName);
250 if (i == -1) {
251 fprintf(stderr, "Rule '%s' specified on the command line is not defined.\n", selectRuleName);
252 exit(255);
253 }
254 JCONFIG_BPFFILTERS_SETSELECTEDFILTER(i);
255 }
256 }
257
initializeDevices()258 void initializeDevices() {
259 if (!jdevice_LookupDevices()) {
260 exit(255);
261 }
262
263 if (!jdevice_DevicesCount) {
264 if (!jconfig_Settings.deviceName) {
265 fprintf(stderr, "Autodiscovery found no devices. Specify device you want to watch with -i parameter\n");
266 exit(255);
267 }
268 if (!(jconfig_Settings.device = jdevice_CreateSingleDevice(jconfig_Settings.deviceName))) {
269 exit(255);
270 }
271 } else if (jconfig_Settings.deviceName) {
272 jconfig_SelectDevice(jconfig_Settings.deviceName);
273 }
274
275 if (!jconfig_Settings.device) {
276 jconfig_Settings.deviceName = jdevice_Devices[0].name;
277 jconfig_Settings.device = jdevice_Devices;
278 }
279
280 if (!jdevice_CheckDevices()) {
281 exit(255);
282 }
283 }
284
main(int argc,char ** argv)285 int main(int argc, char ** argv) {
286 g_thread_init(NULL);
287
288 jcapture_Setup();
289 jprocessor_Setup();
290 jresolver_Setup();
291
292 if (jcursesdisplay_Functions.supported)
293 currentDisplay = &jcursesdisplay_Functions;
294 else
295 currentDisplay = &jtxtdisplay_Functions;
296
297 parseCommandLineAndConfig(argc, argv);
298
299 if (!currentDisplay->presetup()) {
300 return 0;
301 }
302
303 jconfig_ConfigureModules();
304 initializeDevices();
305
306 jresolver_Initialize();
307 currentDisplay->setup();
308
309 while (TRUE) {
310
311 jprocessor_ResetStats();
312
313 if (!currentDisplay->prerunsetup()) {
314 break;
315 }
316
317 jcapture_SetDevice(jconfig_Settings.device);
318 jcapture_SetBpfFilterText(jconfig_GetSelectedBpfFilterText());
319
320 currentDisplay->prerun();
321
322 jcapture_Start();
323 jprocessor_Start();
324
325 if (!currentDisplay->run()) {
326 // In case we're not switching to another device, we can happily finish
327 // after our display thread dies. (mind the endwin())
328 break;
329 }
330
331 jcapture_Kill();
332
333 while (threadCount) {
334 g_thread_yield();
335 }
336 }
337
338 if (debugFile) {
339 fclose(debugFile);
340 }
341
342 currentDisplay->shutdown();
343
344 jresolver_Shutdown();
345
346 return 0;
347 }
348