"SfR Fresh" - the SfR Freeware/Shareware Archive 
Member "trafshow-3.1/display.c" of archive trafshow-3.1.tgz:
As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers.
Alternatively you can here view or download the uninterpreted source code file.
That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
1 /*
2 * Copyright (c) 1993-1997 JSC Rinet, Novosibirsk, Russia
3 *
4 * Redistribution and use in source forms, with and without modification,
5 * are permitted provided that this entire comment appears intact.
6 * Redistribution in binary form may occur without any restrictions.
7 *
8 * THIS SOFTWARE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND.
9 */
10
11 /* display.c -- collect and display network traffic */
12
13 char copyright[] = "Copyright (c) 1993-1997 JSC Rinet, Novosibirsk, Russia";
14
15 #ifdef HAVE_CONFIG_H
16 #include <config.h>
17 #endif
18
19 #ifdef HAVE_SLCURSES
20 #include <slcurses.h>
21 #endif
22 #ifdef HAVE_NCURSES
23 #include <ncurses.h>
24 #endif
25 #ifdef HAVE_CURSES
26 #include <curses.h>
27 #endif
28
29 #include <sys/types.h>
30 #include <sys/time.h>
31 #include <netinet/in.h>
32 #include <netinet/in_systm.h>
33 #include <netinet/ip.h>
34 #include <netinet/ip_icmp.h>
35 #include <netinet/udp.h>
36 #include <netinet/tcp.h>
37 #include <stdlib.h>
38 #include <signal.h>
39 #include <string.h>
40 #include <unistd.h>
41 #ifdef TIME_WITH_SYS_TIME
42 #include <time.h>
43 #endif
44
45 #include "trafshow.h"
46
47 typedef struct t_entry *p_entry;
48 struct t_entry *entries;
49 int n_entry = 0;
50 u_long bytes_total = 0;
51 u_long packets_total = 0;
52 int page = 0;
53 int page_size;
54 static int l_nflag, l_eflag;
55 static int n_entries;
56 static int err_pos;
57
58 void
59 init_display(reinit)
60 int reinit;
61 {
62 if (!reinit) {
63 n_entries = LINES * MAX_PAGES;
64 entries = (struct t_entry *)calloc(n_entries, sizeof(struct t_entry));
65 if (!entries) error(1, "init_display: calloc");
66 l_nflag = nflag;
67 l_eflag = eflag;
68 alarm(scr_interval);
69 } else {
70 int i = LINES * MAX_PAGES;
71 if (i > n_entries) {
72 n_entries = i;
73 entries = (struct t_entry *)realloc(entries, i * sizeof(struct t_entry));
74 if (!entries) error(1, "init_display: realloc");
75 }
76 page = 0;
77 }
78 err_pos = strlen(device_name) + count_size + 15;
79 }
80
81 void
82 header_line()
83 {
84 int i;
85
86 mvprintw(0, 0, "%-*.*s %-*.*s %-*.*s %*.*s %-*.*s",
87 addr_size, addr_size, "From Address",
88 addr_size, addr_size, "To Address",
89 proto_size, proto_size, "Proto",
90 bytes_size, bytes_size, "Bytes",
91 cps_size, cps_size, "CPS");
92 for (i = 0; i < COLS; i++) mvaddch(1, i, '=');
93 }
94
95 void
96 status_line(reinit)
97 int reinit;
98 {
99 static time_t tp = 0;
100 static u_long bytes_prev = 0, packets_prev = 0;
101
102 if (reinit) {
103 time_t tn = time(NULL);
104 register sec = tn - tp;
105 if (sec < 1) sec = 1;
106 mvprintw(LINES-1, 0, "(%.5s) %*ld kb/total %*d pkts/sec %*d bytes/sec",
107 device_name, count_size, bytes_total/1024,
108 count_size, (packets_total-packets_prev)/sec,
109 count_size, (bytes_total-bytes_prev)/sec);
110 packets_prev = packets_total;
111 bytes_prev = bytes_total;
112 tp = tn;
113 } else mvprintw(LINES-1, 0, "(%.5s) %*ld kb/total",
114 device_name, count_size, bytes_total/1024);
115 mvprintw(LINES-1, COLS-13, " Page %2d/%-2d", page+1, n_entry/page_size+1);
116 clrtoeol();
117 }
118
119 /*
120 * Pretty print an Internet address (net address + port).
121 */
122 static char *
123 inet_print(in, port, proto)
124 struct in_addr in;
125 u_short port, proto;
126 {
127 register char *cp;
128 char pline[20];
129 int alen, plen;
130 static char aline[1024];
131 static char *icmp_type[ICMP_MAXTYPE+1] = {
132 "echoreply", "unknown", "unknown", "dstunreach", "srcquench",
133 "redirect", "unknown", "unknown", "echoreqst", "rtradvert",
134 "rtrsolicit", "timeexceed", "paramprobl", "stampreqst",
135 "stampreply", "inforeqst", "inforeply", "maskreqst",
136 "maskreply" };
137
138 if (l_nflag) cp = intoa(in.s_addr);
139 else cp = ipaddr_string(&in);
140 (void) sprintf(aline, "%-*.*s", addr_size, addr_size, cp);
141
142 if (port) {
143 if (proto == IPPROTO_TCP)
144 cp = tcpport_string(port);
145 else if (proto == IPPROTO_UDP)
146 cp = udpport_string(port);
147 else if (proto == IPPROTO_ICMP && port <= ICMP_MAXTYPE)
148 cp = icmp_type[port];
149 else cp = "unknown";
150
151 plen = sprintf(pline, "..%.10s", cp);
152
153 if ((cp = strchr(aline, ' ')) != NULL)
154 alen = cp - aline;
155 else alen = addr_size;
156 if ((alen + plen) >= addr_size)
157 memcpy(&aline[addr_size - plen], pline, plen);
158 else memcpy(&aline[alen], pline, plen);
159 }
160 return aline;
161 }
162
163 static void
164 main_print(line, i)
165 int line;
166 register i;
167 {
168 char *proto;
169 int normal = TRUE;
170
171 move(SCR_OFFS+line, 0);
172 #ifdef HAVE_HAS_COLORS
173 if (use_colors) normal = !color_on(&entries[i]);
174 #endif
175 if (l_eflag) {
176 printw("%-*.*s", addr_size, addr_size,
177 l_nflag ? entoa(entries[i].eh.ether_shost) :
178 etheraddr_string(entries[i].eh.ether_shost));
179 addch(' ');
180 printw("%-*.*s", addr_size, addr_size,
181 l_nflag ? entoa(entries[i].eh.ether_dhost) :
182 etheraddr_string(entries[i].eh.ether_dhost));
183
184 proto = etherproto_string(entries[i].eh.ether_type);
185 } else {
186 addstr(inet_print(entries[i].src, entries[i].sport, entries[i].proto));
187 addch(' ');
188 addstr(inet_print(entries[i].dst, entries[i].dport, entries[i].proto));
189
190 proto = getprotoname(entries[i].proto);
191 if (proto == NULL) proto = "unknown";
192 }
193
194 printw(" %-*.*s", proto_size, proto_size, proto);
195 #ifdef HAVE_HAS_COLORS
196 if (!normal) attrset(A_NORMAL);
197 #endif
198 printw(" %*ld", bytes_size, entries[i].bytes);
199 if (entries[i].cps) printw(" %-*d", cps_size, entries[i].cps);
200 clrtoeol();
201 }
202
203 static int
204 sortbybytes(e1, e2)
205 register p_entry e1, e2;
206 {
207 if (e1->bytes > e2->bytes) return -1;
208 if (e1->bytes < e2->bytes) return 1;
209 return 0;
210 }
211
212 /*
213 * If scr_interval time any entry wasn't changed then purge it
214 * and redraw whole screen.
215 */
216 void
217 scr_redraw(del_old)
218 int del_old;
219 {
220 register i, j;
221
222 if (del_old) {
223 alarm(0);
224 for (i = j = 0; i < n_entry; i++) {
225 if (entries[i].bytes != entries[i].obytes)
226 entries[i].cps = (entries[i].bytes - entries[i].obytes)/scr_interval;
227 else entries[i].bytes = 0, j++;
228 entries[i].obytes = entries[i].bytes;
229 }
230 qsort(entries, n_entry, sizeof(struct t_entry), sortbybytes);
231 n_entry -= j;
232 }
233 j = n_entry/page_size;
234 if (page > j) page = j;
235
236 move(SCR_OFFS, 0);
237 if (n_entry) {
238 for (i = 0, j = page * page_size;
239 i < page_size && j < n_entry; i++, j++)
240 main_print(i, j);
241 } else {
242 clrtoeol();
243 switch (alarm_flag) {
244 case 1:
245 addstr("Where is the tcp or udp packets contained data? It is exactly what I want! Now!");
246 break;
247 case 2:
248 addstr("Nothing to show, this interface sleeping or broken. blah-blah-gluk-gluk-wait...");
249 break;
250 default:
251 i = COLS/2 - strlen(copyright)/2;
252 if (i < 0) i = 0;
253 mvaddstr(SCR_OFFS, i, copyright);
254 alarm_flag = 1;
255 }
256 }
257 clrtobot();
258 status_line(del_old);
259 if (del_old) alarm(scr_interval);
260 }
261
262 void
263 scr_update()
264 {
265 #ifdef HAVE_HAS_COLORS
266 move(LINES-1, COLS-1);
267 #else
268 move(0, COLS-1);
269 #endif
270 refresh();
271 }
272
273 /*
274 * Add new entry or add bytes to existed record.
275 */
276 static void
277 collect(e)
278 register p_entry e;
279 {
280 register i, j;
281
282 packets_total++;
283 bytes_total += e->bytes;
284 j = page * page_size;
285 for (i = 0; i < n_entry; i++) {
286 if (memcmp(&e->eh, &entries[i].eh, sizeof(e->eh)) == 0 &&
287 e->src.s_addr == entries[i].src.s_addr &&
288 e->sport == entries[i].sport &&
289 e->dst.s_addr == entries[i].dst.s_addr &&
290 e->dport == entries[i].dport &&
291 e->proto == entries[i].proto) {
292 entries[i].bytes += e->bytes;
293 if (i >= j && i < j + page_size)
294 mvprintw(i-j+SCR_OFFS, addr_size*2+proto_size+3,
295 "%*ld", bytes_size, entries[i].bytes);
296 return;
297 }
298 }
299 if (i >= LINES * MAX_PAGES) {
300 mvaddstr(LINES-1, COLS-13, " Overflow");
301 clrtoeol();
302 return;
303 }
304 /* add new entry */
305 entries[i] = *e;
306 entries[i].obytes = entries[i].cps = 0;
307 if (i >= j && i < j + page_size) main_print(i-j, i);
308 n_entry++;
309 status_line(0);
310 }
311
312 void
313 display(eh, ip, length)
314 struct ether_header *eh;
315 register struct ip *ip;
316 int length;
317 {
318 register iplen;
319 int hlen, not_ip = 0;
320 register u_char *cp;
321 struct t_entry te;
322
323 if ((u_char *)(ip + 1) > snapend) {
324 if (!eflag) return; /* not ip proto? discard silently */
325 not_ip++;
326 } else if (length < sizeof(*ip)) {
327 if (!eflag) {
328 mvprintw(LINES-1, err_pos, "\
329 truncated-ip: discard %d bytes", length);
330 clrtoeol();
331 goto refresh_screen;
332 }
333 not_ip++;
334 } else if (ip->ip_v != IPVERSION) {
335 if (!eflag) {
336 mvprintw(LINES-1, err_pos, "\
337 ip ver != %d: discard %d bytes", IPVERSION, length);
338 clrtoeol();
339 goto refresh_screen;
340 }
341 not_ip++;
342 } else if ((iplen = ntohs(ip->ip_len)) < 1) {
343 if (!eflag) return; /* empty ip packet? discard silently */
344 not_ip++;
345 } else if (length < iplen) {
346 if (!eflag) {
347 mvprintw(LINES-1, err_pos, "\
348 truncated-ip: %d bytes missing", iplen - length);
349 clrtoeol();
350 goto refresh_screen;
351 }
352 not_ip++;
353 }
354
355 if (eh) te.eh = *eh;
356 else memset(&te.eh, 0, sizeof(te.eh));
357
358 te.sport = te.dport = 0;
359
360 if (!not_ip) { /* parse ip packet */
361
362 /*
363 * If this is fragment zero, hand it to the next higher level
364 * protocol to fetch ports or icmp type else it is fragmented
365 * ip datagram.
366 */
367 if ((ntohs(ip->ip_off) & 0x1fff) == 0) {
368 /* advance to high level protocol header */
369 hlen = ip->ip_hl * 4;
370 cp = (u_char *)ip + hlen;
371 if (ip->ip_p == IPPROTO_TCP) {
372 if (cp + sizeof(struct tcphdr) > snapend ||
373 iplen - hlen < sizeof(struct tcphdr)) {
374 mvprintw(LINES-1, err_pos, "\
375 truncated-tcp: wrong ip hdrlen");
376 clrtoeol();
377 goto refresh_screen;
378 }
379 te.sport = ntohs(((struct tcphdr *)cp)->th_sport);
380 te.dport = ntohs(((struct tcphdr *)cp)->th_dport);
381 } else if (ip->ip_p == IPPROTO_UDP) {
382 if (cp + sizeof(struct udphdr) > snapend ||
383 iplen - hlen < sizeof(struct udphdr)) {
384 mvprintw(LINES-1, err_pos, "\
385 truncated-udp: wrong ip hdrlen");
386 clrtoeol();
387 goto refresh_screen;
388 }
389 te.sport = ntohs(((struct udphdr *)cp)->uh_sport);
390 te.dport = ntohs(((struct udphdr *)cp)->uh_dport);
391 } else if (ip->ip_p == IPPROTO_ICMP) {
392 if (cp + sizeof(struct icmp) > snapend ||
393 iplen - hlen < sizeof(struct icmp)) {
394 mvprintw(LINES-1, err_pos, "\
395 truncated-icmp: wrong ip hdrlen");
396 clrtoeol();
397 goto refresh_screen;
398 }
399 te.sport = ((struct icmp *)cp)->icmp_type;
400 }
401 }
402 te.src.s_addr = ip->ip_src.s_addr;
403 te.dst.s_addr = ip->ip_dst.s_addr;
404 te.proto = ip->ip_p;
405 te.bytes = iplen;
406 } else { /* other than ip protocol packets */
407 te.src.s_addr = te.dst.s_addr = 0;
408 te.proto = 0;
409 te.bytes = length;
410 }
411
412 collect(&te);
413
414 if (alarm_flag) {
415 alarm_flag = 0;
416 if (resize_flag) {
417 resize_flag = 0;
418 init_term(TRUE);
419 }
420 scr_redraw(TRUE);
421 }
422
423 refresh_screen:
424 if (kflag && kbhit(0) && get_keyb()) scr_redraw(FALSE);
425
426 scr_update();
427 return;
428 }
429
430 int
431 inputchar()
432 {
433 return getch();
434 }
435
436 int
437 get_keyb()
438 {
439 int ch;
440
441 if ((ch = getch()) == ERR) error(1, "get_keyb: getch");
442 switch(ch) {
443 case ESC:
444 switch(get_arrowkey(inputchar)) {
445 case KEYMAP_UP:
446 case KEYMAP_PAGE_UP:
447 goto page_up;
448 case KEYMAP_DOWN:
449 case KEYMAP_PAGE_DOWN:
450 goto page_down;
451 case KEYMAP_LEFT:
452 case KEYMAP_HOME:
453 goto home_list;
454 case KEYMAP_RIGHT:
455 case KEYMAP_END:
456 goto end_list;
457 default:
458 mvaddstr(LINES-1, COLS-13, " Bad command");
459 return 0;
460 }
461 break;
462
463 case 'k': /* line up */
464 case ctrl('P'):
465 case '\b': /* page up */
466 case 'b':
467 case ctrl('U'):
468 case ctrl('B'):
469 page_up:
470 if (page > 0) page--;
471 break;
472
473 case 'j':
474 case ctrl('N'): /* line down */
475 case ' ': /* page down */
476 case ctrl('D'):
477 case ctrl('F'):
478 page_down:
479 if (page < n_entry/page_size) page++;
480 break;
481
482 case ctrl('A'): /* home */
483 home_list:
484 page = 0;
485 break;
486
487 case ctrl('E'): /* end */
488 end_list:
489 page = n_entry/page_size;
490 break;
491
492 case '\r': /* enter */
493 case '\n':
494 l_eflag ^= 1;
495 break;
496
497 case '\t': /* tab */
498 l_nflag ^= 1;
499 break;
500
501 case 'q': /* quit */
502 cleanup(SIGINT);
503
504 case ctrl('L'): /* refresh screen */
505 clear();
506 header_line();
507 scr_redraw(FALSE);
508 scr_update();
509 break;
510
511 default:
512 mvaddstr(LINES-1, COLS-13, " Bad command");
513 return 0;
514 }
515 return 1;
516 }