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
26 #include "jprocessor.h"
27 #include "jresolver.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];
52 vsprintf(buffer
, format
, ap
);
58 fprintf(debugFile
, "%d - %d, %s\n", getpid(), priority
, buffer
);
63 syslog(priority
, "%d - %d, %s\n", getpid(), priority
, buffer
);
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
;
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");
90 if (!strcmp(argv
[a
], "-h") || !strcmp(argv
[a
], "--help")) {
91 printf( "Usage: jnettop [-hv] [-i interface] [-d filename]\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"
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"
113 "Report bugs to <j@kubs.cz>\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"
123 " jnettop --display text -t 5 --format CSV\n"
124 " jnettop --display text -t 5 --format '$srcname$,$srcport$,$dstname$,$dstport$,$totalbps$'\n"
129 if (!strcmp(argv
[a
], "-c") || !strcmp(argv
[a
], "--content-filter")) {
130 jconfig_Settings
.onoffContentFiltering
= FALSE
;
133 if (!strcmp(argv
[a
], "--display")) {
135 fprintf(stderr
, "%s switch requires argument\n", argv
[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
;
148 fprintf(stderr
, "display type %s is not supported.\n", argv
[a
]);
153 if (!strcmp(argv
[a
], "-i") || !strcmp(argv
[a
], "--interface")) {
155 fprintf(stderr
, "%s switch requires argument\n", argv
[a
]);
158 jconfig_Settings
.deviceName
= argv
[++a
];
161 if (!strcmp(argv
[a
], "-s") || !strcmp(argv
[a
], "--select-rule")) {
163 fprintf(stderr
, "%s switch requires argument\n", argv
[a
]);
166 selectRuleName
= argv
[++a
];
169 if (!strcmp(argv
[a
], "-d") || !strcmp(argv
[a
], "--debug")) {
171 fprintf(stderr
, "%s switch requires filename to debug to as an argument\n", argv
[a
]);
175 if (!strcmp(argv
[a
], "syslog")) {
176 #ifdef SUPPORT_SYSLOG
177 debugOut
= DEBUGOUT_SYSLOG
;
179 fprintf(stderr
, "Syslog output not enabled in compilation\n");
182 } else if (!strcmp(argv
[a
], "stderr")) {
183 debugOut
= DEBUGOUT_STDERR
;
186 debugFile
= fopen(argv
[a
], "w");
188 perror("Could not open debug file");
191 debugOut
= DEBUGOUT_FILE
;
195 if (!strcmp(argv
[a
], "-f") || !strcmp(argv
[a
], "--config-file")) {
197 fprintf(stderr
, "%s switch required argument\n", argv
[a
]);
200 configFileName
= argv
[++a
];
203 if (!strcmp(argv
[a
], "-x") || !strcmp(argv
[a
], "--filter")) {
205 char *commandLineRule
;
207 fprintf(stderr
, "%s switch requires argument\n", argv
[a
]);
210 commandLineRule
= argv
[++a
];
211 ret
= jutil_ValidateBPFFilter(commandLineRule
);
213 fprintf(stderr
, "Error compiling rule: %s\n", ret
);
216 JCONFIG_BPFFILTERS_SETSELECTEDFILTER(JCONFIG_BPFFILTERS_LEN
);
217 jconfig_AddBpfFilter("<commandline>", commandLineRule
);
220 if (!strcmp(argv
[a
], "-p") || !strcmp(argv
[a
], "--promiscuous")) {
221 jconfig_Settings
.onoffPromisc
= TRUE
;
224 if (!strcmp(argv
[a
], "-n") || !strcmp(argv
[a
], "--no-resolve")) {
225 jconfig_Settings
.onoffResolver
= FALSE
;
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
]);
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
]);
243 int consumed
= currentDisplay
->processargument((const gchar
**) argv
+a
, argc
-a
);
249 fprintf(stderr
, "Unknown argument: %s\n", argv
[a
]);
253 if (!jconfig_ParseFile(configFileName
)) {
257 jconfig_SetDefaults();
259 if (selectRuleName
) {
260 int i
= jconfig_FindBpfFilterByName(selectRuleName
);
262 fprintf(stderr
, "Rule '%s' specified on the command line is not defined.\n", selectRuleName
);
265 JCONFIG_BPFFILTERS_SETSELECTEDFILTER(i
);
269 void initializeDevices() {
270 if (!jdevice_LookupDevices()) {
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");
279 if (!(jconfig_Settings
.device
= jdevice_CreateSingleDevice(jconfig_Settings
.deviceName
))) {
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()) {
296 int main(int argc
, char ** argv
) {
303 if (jcursesdisplay_Functions
.supported
)
304 currentDisplay
= &jcursesdisplay_Functions
;
306 currentDisplay
= &jtxtdisplay_Functions
;
308 parseCommandLineAndConfig(argc
, argv
);
310 if (!currentDisplay
->presetup()) {
314 jconfig_ConfigureModules();
317 jresolver_Initialize();
318 currentDisplay
->setup();
322 jprocessor_ResetStats();
324 if (!currentDisplay
->prerunsetup()) {
328 jcapture_SetDevice(jconfig_Settings
.device
);
329 jcapture_SetBpfFilterText(jconfig_GetSelectedBpfFilterText());
331 currentDisplay
->prerun();
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())
344 while (threadCount
) {
353 currentDisplay
->shutdown();
355 jresolver_Shutdown();