setting svn:exports
[jnettop.git] / jnettop / jnettop.c
blob7a9e8723221fc6c23dd76eab80d0e9512223708f
1 /*
2 * jnettop, network online traffic visualiser
3 * Copyright (C) 2002-2006 Jakub Skopal
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.
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.
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
19 * $Header$
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"
37 #define DEBUGOUT_NONE 0
38 #define DEBUGOUT_SYSLOG 1
39 #define DEBUGOUT_FILE 2
40 #define DEBUGOUT_STDERR 3
41 int debugOut = DEBUGOUT_NONE;
42 FILE * debugFile = NULL;
44 volatile int threadCount;
46 jbase_display * currentDisplay;
48 void debug(int priority, const char *format, ...) {
49 static char buffer[32768];
50 va_list ap;
51 va_start(ap, format);
52 vsprintf(buffer, format, ap);
53 va_end(ap);
55 switch (debugOut) {
56 case DEBUGOUT_FILE:
57 case DEBUGOUT_STDERR:
58 fprintf(debugFile, "%d - %d, %s\n", getpid(), priority, buffer);
59 fflush(debugFile);
60 break;
61 #ifdef SUPPORT_SYSLOG
62 case DEBUGOUT_SYSLOG:
63 syslog(priority, "%d - %d, %s\n", getpid(), priority, buffer);
64 #endif
68 void debugip(int priority, int af, const jbase_mutableaddress *addr, const char *message) {
69 static char buffer[128];
70 jutil_Address2String(af, addr, buffer, sizeof(buffer));
71 debug(priority, "%s (ip address %s)", message, buffer);
74 void jbase_cb_DrawStatus(const gchar *msg) {
75 currentDisplay->drawstatus(msg);
78 void parseCommandLineAndConfig(int argc, char ** argv) {
79 char * configFileName = NULL;
80 char * selectRuleName = NULL;
81 int a;
83 jconfig_Setup();
85 for (a=1; a<argc; a++) {
86 if (!strcmp(argv[a], "-v") || !strcmp(argv[a], "--version")) {
87 printf(PACKAGE_STRING "\nWritten by Jakub Skopal <j@kubs.cz>\n\nSee copyright in the COPYING file.\n");
88 exit(0);
90 if (!strcmp(argv[a], "-h") || !strcmp(argv[a], "--help")) {
91 printf( "Usage: jnettop [-hv] [-i interface] [-d filename]\n"
92 "\n"
93 " -h, --help display this help message\n"
94 " -v, --version display version information\n\n"
95 " -b, --bit-units show BPS in bits per second, not bytes per second\n"
96 " -c, --content-filter disable content filtering\n"
97 " -d, --debug filename write debug information into file (or syslog)\n"
98 " --display type type of display (curses, text, uia)\n"
99 " -f, --config-file name reads configuration from file. defaults to ~/.jnettop\n"
100 " --format format list of fields to list in text output\n"
101 " -i, --interface name capture packets on specified interface\n"
102 " --local-aggr arg set local aggregation to none/host/port\n"
103 " -n, --no-resolver disable resolving of addresses\n"
104 " -p, --promiscuous enable promisc mode on the devices\n"
105 " --remote-aggr arg set remote aggregation to none/host/port\n"
106 " -s, --select-rule rule selects one of the rules defined in config file\n"
107 " by it's name\n"
108 " -t, --timeout sec timeout in seconds after which jnettop ends (text display)\n"
109 " -x, --filter rule allows for specification of custom filtering rule\n"
110 " this follows tcpdump(1) syntax. don't forget to\n"
111 " enclose the filter into quotes when running from shell\n"
112 "\n"
113 "Report bugs to <j@kubs.cz>\n"
114 "\n"
115 " Format variable can be CSV (comma separated values), TSV (tab separated values)\n"
116 " or completelly custom format string, where the following identifiers are subst-\n"
117 " ituted when surrounded by '$':\n"
118 " src, srcname, srcport, srcbytes, srcpackets, srcbps, srcpps,\n"
119 " dst, dstname, dstport, dstbytes, dstpackets, dstbps, dstpps,\n"
120 " proto, totalbytes, totalpackets, totalbps, totalpps, filterdata\n"
121 "\n"
122 " example:\n"
123 " jnettop --display text -t 5 --format CSV\n"
124 " jnettop --display text -t 5 --format '$srcname$,$srcport$,$dstname$,$dstport$,$totalbps$'\n"
125 "\n"
127 exit(0);
129 if (!strcmp(argv[a], "-c") || !strcmp(argv[a], "--content-filter")) {
130 jconfig_Settings.onoffContentFiltering = FALSE;
131 continue;
133 if (!strcmp(argv[a], "--display")) {
134 if (a+1>=argc) {
135 fprintf(stderr, "%s switch requires argument\n", argv[a]);
136 exit(255);
138 ++a;
139 if (jcursesdisplay_Functions.supported && !strcmp(argv[a], "curses")) {
140 currentDisplay = &jcursesdisplay_Functions;
141 } else if (jtxtdisplay_Functions.supported && !strcmp(argv[a], "text")) {
142 currentDisplay = &jtxtdisplay_Functions;
143 } else if (jnetdisplay_Functions.supported && !strcmp(argv[a], "jnet")) {
144 currentDisplay = &jnetdisplay_Functions;
145 } else if (juiadisplay_Functions.supported && !strcmp(argv[a], "uia")) {
146 currentDisplay = &juiadisplay_Functions;
147 } else {
148 fprintf(stderr, "display type %s is not supported.\n", argv[a]);
149 exit(255);
151 continue;
153 if (!strcmp(argv[a], "-i") || !strcmp(argv[a], "--interface")) {
154 if (a+1>=argc) {
155 fprintf(stderr, "%s switch requires argument\n", argv[a]);
156 exit(255);
158 jconfig_Settings.deviceName = argv[++a];
159 continue;
161 if (!strcmp(argv[a], "-s") || !strcmp(argv[a], "--select-rule")) {
162 if (a+1>=argc) {
163 fprintf(stderr, "%s switch requires argument\n", argv[a]);
164 exit(255);
166 selectRuleName = argv[++a];
167 continue;
169 if (!strcmp(argv[a], "-d") || !strcmp(argv[a], "--debug")) {
170 if (a+1>=argc) {
171 fprintf(stderr, "%s switch requires filename to debug to as an argument\n", argv[a]);
172 exit(255);
174 ++a;
175 if (!strcmp(argv[a], "syslog")) {
176 #ifdef SUPPORT_SYSLOG
177 debugOut = DEBUGOUT_SYSLOG;
178 #else
179 fprintf(stderr, "Syslog output not enabled in compilation\n");
180 exit(255);
181 #endif
182 } else if (!strcmp(argv[a], "stderr")) {
183 debugOut = DEBUGOUT_STDERR;
184 debugFile = stderr;
185 } else {
186 debugFile = fopen(argv[a], "w");
187 if (!debugFile) {
188 perror("Could not open debug file");
189 exit(255);
191 debugOut = DEBUGOUT_FILE;
193 continue;
195 if (!strcmp(argv[a], "-f") || !strcmp(argv[a], "--config-file")) {
196 if (a+1>=argc) {
197 fprintf(stderr, "%s switch required argument\n", argv[a]);
198 exit(255);
200 configFileName = argv[++a];
201 continue;
203 if (!strcmp(argv[a], "-x") || !strcmp(argv[a], "--filter")) {
204 const char *ret;
205 char *commandLineRule;
206 if (a+1>=argc) {
207 fprintf(stderr, "%s switch requires argument\n", argv[a]);
208 exit(255);
210 commandLineRule = argv[++a];
211 ret = jutil_ValidateBPFFilter(commandLineRule);
212 if (ret) {
213 fprintf(stderr, "Error compiling rule: %s\n", ret);
214 exit(255);
216 JCONFIG_BPFFILTERS_SETSELECTEDFILTER(JCONFIG_BPFFILTERS_LEN);
217 jconfig_AddBpfFilter("<commandline>", commandLineRule);
218 continue;
220 if (!strcmp(argv[a], "-p") || !strcmp(argv[a], "--promiscuous")) {
221 jconfig_Settings.onoffPromisc = TRUE;
222 continue;
224 if (!strcmp(argv[a], "-n") || !strcmp(argv[a], "--no-resolve")) {
225 jconfig_Settings.onoffResolver = FALSE;
226 continue;
228 if (!strcmp(argv[a], "--local-aggr")) {
229 if (a+1>=argc || (jconfig_Settings.localAggregation = jutil_ParseAggregation(argv[++a]))==-1) {
230 fprintf(stderr, "%s switch requires none, host or port as an argument\n", argv[a]);
231 exit(255);
233 continue;
235 if (!strcmp(argv[a], "--remote-aggr")) {
236 if (a+1>=argc || (jconfig_Settings.remoteAggregation = jutil_ParseAggregation(argv[++a]))==-1) {
237 fprintf(stderr, "%s switch requires none, host or port as an argument\n", argv[a]);
238 exit(255);
240 continue;
243 int consumed = currentDisplay->processargument((const gchar **) argv+a, argc-a);
244 if (consumed) {
245 a += consumed - 1;
246 continue;
249 fprintf(stderr, "Unknown argument: %s\n", argv[a]);
250 exit(255);
253 if (!jconfig_ParseFile(configFileName)) {
254 exit(255);
257 jconfig_SetDefaults();
259 if (selectRuleName) {
260 int i = jconfig_FindBpfFilterByName(selectRuleName);
261 if (i == -1) {
262 fprintf(stderr, "Rule '%s' specified on the command line is not defined.\n", selectRuleName);
263 exit(255);
265 JCONFIG_BPFFILTERS_SETSELECTEDFILTER(i);
269 void initializeDevices() {
270 if (!jdevice_LookupDevices()) {
271 exit(255);
274 if (!jdevice_DevicesCount) {
275 if (!jconfig_Settings.deviceName) {
276 fprintf(stderr, "Autodiscovery found no devices. Specify device you want to watch with -i parameter\n");
277 exit(255);
279 if (!(jconfig_Settings.device = jdevice_CreateSingleDevice(jconfig_Settings.deviceName))) {
280 exit(255);
282 } else if (jconfig_Settings.deviceName) {
283 jconfig_SelectDevice(jconfig_Settings.deviceName);
286 if (!jconfig_Settings.device) {
287 jconfig_Settings.deviceName = jdevice_Devices[0].name;
288 jconfig_Settings.device = jdevice_Devices;
291 if (!jdevice_CheckDevices()) {
292 exit(255);
296 int main(int argc, char ** argv) {
297 g_thread_init(NULL);
299 jcapture_Setup();
300 jprocessor_Setup();
301 jresolver_Setup();
303 if (jcursesdisplay_Functions.supported)
304 currentDisplay = &jcursesdisplay_Functions;
305 else
306 currentDisplay = &jtxtdisplay_Functions;
308 parseCommandLineAndConfig(argc, argv);
310 if (!currentDisplay->presetup()) {
311 return 0;
314 jconfig_ConfigureModules();
315 initializeDevices();
317 jresolver_Initialize();
318 currentDisplay->setup();
320 while (TRUE) {
322 jprocessor_ResetStats();
324 if (!currentDisplay->prerunsetup()) {
325 break;
328 jcapture_SetDevice(jconfig_Settings.device);
329 jcapture_SetBpfFilterText(jconfig_GetSelectedBpfFilterText());
331 currentDisplay->prerun();
333 jcapture_Start();
334 jprocessor_Start();
336 if (!currentDisplay->run()) {
337 // In case we're not switching to another device, we can happily finish
338 // after our display thread dies. (mind the endwin())
339 break;
342 jcapture_Kill();
344 while (threadCount) {
345 g_thread_yield();
349 if (debugFile) {
350 fclose(debugFile);
353 currentDisplay->shutdown();
355 jresolver_Shutdown();
357 return 0;