Include <string.h> and <ctype.h> to get the appropriate functions
[obnox/wireshark/wip.git] / tap-iousers.c
1 /* tap-iousers.c
2  * iostat   2003 Ronnie Sahlberg
3  *
4  * $Id$
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  * 
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  * 
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <stdio.h>
30
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34
35 #include <string.h>
36 #include <epan/packet_info.h>
37 #include <epan/packet.h>
38 #include <epan/addr_resolv.h>
39 #include <epan/tap.h>
40 #include "register.h"
41 #include <epan/dissectors/packet-ip.h>
42 #include <epan/dissectors/packet-ipx.h>
43 #include <epan/dissectors/packet-tcp.h>
44 #include <epan/dissectors/packet-udp.h>
45 #include <epan/dissectors/packet-eth.h>
46 #include <epan/dissectors/packet-tr.h>
47 #include <epan/dissectors/packet-fc.h>
48 #include <epan/dissectors/packet-fddi.h>
49 #include <string.h>
50
51 typedef struct _io_users_t {
52         char *type;
53         char *filter;
54         struct _io_users_item_t *items;
55 } io_users_t;
56
57 typedef struct _io_users_item_t {
58         struct _io_users_item_t *next;
59         char *name1;
60         char *name2;
61         address addr1;
62         address addr2; 
63         guint32 frames1;
64         guint32 frames2;
65         guint32 bytes1;
66         guint32 bytes2;
67 } io_users_item_t;
68
69
70 static int
71 iousers_udpip_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vudph)
72 {
73         io_users_t *iu=arg;
74         const e_udphdr *udph=vudph;
75         char name1[256],name2[256];
76         io_users_item_t *iui;
77         int direction=0;
78
79         if(udph->uh_sport>udph->uh_dport){
80                 direction=0;
81                 snprintf(name1,256,"%s:%s",address_to_str(&udph->ip_src),get_udp_port(udph->uh_sport));
82                 snprintf(name2,256,"%s:%s",address_to_str(&udph->ip_dst),get_udp_port(udph->uh_dport));
83         } else if(udph->uh_sport<udph->uh_dport){
84                 direction=1;
85                 snprintf(name2,256,"%s:%s",address_to_str(&udph->ip_src),get_udp_port(udph->uh_sport));
86                 snprintf(name1,256,"%s:%s",address_to_str(&udph->ip_dst),get_udp_port(udph->uh_dport));
87         } else if(CMP_ADDRESS(&udph->ip_src, &udph->ip_dst)>0){
88                 direction=0;
89                 snprintf(name1,256,"%s:%s",address_to_str(&udph->ip_src),get_udp_port(udph->uh_sport));
90                 snprintf(name2,256,"%s:%s",address_to_str(&udph->ip_dst),get_udp_port(udph->uh_dport));
91         } else {
92                 direction=1;
93                 snprintf(name2,256,"%s:%s",address_to_str(&udph->ip_src),get_udp_port(udph->uh_sport));
94                 snprintf(name1,256,"%s:%s",address_to_str(&udph->ip_dst),get_udp_port(udph->uh_dport));
95         }
96
97         for(iui=iu->items;iui;iui=iui->next){
98                 if((!strcmp(iui->name1, name1))
99                 && (!strcmp(iui->name2, name2)) ){
100                         break;
101                 }
102         }
103
104         if(!iui){
105                 iui=g_malloc(sizeof(io_users_item_t));
106                 iui->next=iu->items;
107                 iu->items=iui;
108 /*              iui->addr1=NULL;*/
109                 iui->name1=strdup(name1);
110 /*              iui->addr2=NULL;*/
111                 iui->name2=strdup(name2);
112                 iui->frames1=0;
113                 iui->frames2=0;
114                 iui->bytes1=0;
115                 iui->bytes2=0;
116         }
117
118         if(direction){
119                 iui->frames1++;
120                 iui->bytes1+=pinfo->fd->pkt_len;
121         } else {
122                 iui->frames2++;
123                 iui->bytes2+=pinfo->fd->pkt_len;
124         }
125
126         return 1;
127 }
128
129
130 static int
131 iousers_tcpip_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vtcph)
132 {
133         io_users_t *iu=arg;
134         const struct tcpheader *tcph=vtcph;
135         char name1[256],name2[256];
136         io_users_item_t *iui;
137         int direction=0;
138
139         if(tcph->th_sport>tcph->th_dport){
140                 direction=0;
141                 snprintf(name1,256,"%s:%s",address_to_str(&tcph->ip_src),get_tcp_port(tcph->th_sport));
142                 snprintf(name2,256,"%s:%s",address_to_str(&tcph->ip_dst),get_tcp_port(tcph->th_dport));
143         } else if(tcph->th_sport<tcph->th_dport){
144                 direction=1;
145                 snprintf(name2,256,"%s:%s",address_to_str(&tcph->ip_src),get_tcp_port(tcph->th_sport));
146                 snprintf(name1,256,"%s:%s",address_to_str(&tcph->ip_dst),get_tcp_port(tcph->th_dport));
147         } else if(CMP_ADDRESS(&tcph->ip_src, &tcph->ip_dst)>0){
148                 direction=0;
149                 snprintf(name1,256,"%s:%s",address_to_str(&tcph->ip_src),get_tcp_port(tcph->th_sport));
150                 snprintf(name2,256,"%s:%s",address_to_str(&tcph->ip_dst),get_tcp_port(tcph->th_dport));
151         } else {
152                 direction=1;
153                 snprintf(name2,256,"%s:%s",address_to_str(&tcph->ip_src),get_tcp_port(tcph->th_sport));
154                 snprintf(name1,256,"%s:%s",address_to_str(&tcph->ip_dst),get_tcp_port(tcph->th_dport));
155         }
156
157         for(iui=iu->items;iui;iui=iui->next){
158                 if((!strcmp(iui->name1, name1))
159                 && (!strcmp(iui->name2, name2)) ){
160                         break;
161                 }
162         }
163
164         if(!iui){
165                 iui=g_malloc(sizeof(io_users_item_t));
166                 iui->next=iu->items;
167                 iu->items=iui;
168 /*              iui->addr1=NULL;*/
169                 iui->name1=strdup(name1);
170 /*              iui->addr2=NULL;*/
171                 iui->name2=strdup(name2);
172                 iui->frames1=0;
173                 iui->frames2=0;
174                 iui->bytes1=0;
175                 iui->bytes2=0;
176         }
177
178         if(direction){
179                 iui->frames1++;
180                 iui->bytes1+=pinfo->fd->pkt_len;
181         } else {
182                 iui->frames2++;
183                 iui->bytes2+=pinfo->fd->pkt_len;
184         }
185
186         return 1;
187 }
188
189
190 static int
191 iousers_ip_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip)
192 {
193         io_users_t *iu=arg;
194         const e_ip *iph=vip;
195         const address *addr1, *addr2;
196         io_users_item_t *iui;
197
198         if(CMP_ADDRESS(&iph->ip_src, &iph->ip_dst)>0){
199                 addr1=&iph->ip_src;
200                 addr2=&iph->ip_dst;
201         } else {
202                 addr2=&iph->ip_src;
203                 addr1=&iph->ip_dst;
204         }
205
206         for(iui=iu->items;iui;iui=iui->next){
207                 if((!CMP_ADDRESS(&iui->addr1, addr1))
208                 &&(!CMP_ADDRESS(&iui->addr2, addr2)) ){
209                         break;
210                 }
211         }
212
213         if(!iui){
214                 iui=g_malloc(sizeof(io_users_item_t));
215                 iui->next=iu->items;
216                 iu->items=iui;
217                 COPY_ADDRESS(&iui->addr1, addr1);
218                 iui->name1=strdup(address_to_str(addr1));
219                 COPY_ADDRESS(&iui->addr2, addr2);
220                 iui->name2=strdup(address_to_str(addr2));
221                 iui->frames1=0;
222                 iui->frames2=0;
223                 iui->bytes1=0;
224                 iui->bytes2=0;
225         }
226
227         if(!CMP_ADDRESS(&iph->ip_dst, &iui->addr1)){
228                 iui->frames1++;
229                 iui->bytes1+=pinfo->fd->pkt_len;
230         } else {
231                 iui->frames2++;
232                 iui->bytes2+=pinfo->fd->pkt_len;
233         }
234
235         return 1;
236 }
237
238 static int
239 iousers_ipx_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vipx)
240 {
241         io_users_t *iu=arg;
242         const ipxhdr_t *ipxh=vipx;
243         const address *addr1, *addr2;
244         io_users_item_t *iui;
245
246         if(CMP_ADDRESS(&ipxh->ipx_src, &ipxh->ipx_dst)>0){
247                 addr1=&ipxh->ipx_src;
248                 addr2=&ipxh->ipx_dst;
249         } else {
250                 addr2=&ipxh->ipx_src;
251                 addr1=&ipxh->ipx_dst;
252         }
253
254         for(iui=iu->items;iui;iui=iui->next){
255                 if((!CMP_ADDRESS(&iui->addr1, addr1))
256                 &&(!CMP_ADDRESS(&iui->addr2, addr2)) ){
257                         break;
258                 }
259         }
260
261         if(!iui){
262                 iui=g_malloc(sizeof(io_users_item_t));
263                 iui->next=iu->items;
264                 iu->items=iui;
265                 COPY_ADDRESS(&iui->addr1, addr1);
266                 iui->name1=strdup(address_to_str(addr1));
267                 COPY_ADDRESS(&iui->addr2, addr2);
268                 iui->name2=strdup(address_to_str(addr2));
269                 iui->frames1=0;
270                 iui->frames2=0;
271                 iui->bytes1=0;
272                 iui->bytes2=0;
273         }
274
275         if(!CMP_ADDRESS(&ipxh->ipx_dst, &iui->addr1)){
276                 iui->frames1++;
277                 iui->bytes1+=pinfo->fd->pkt_len;
278         } else {
279                 iui->frames2++;
280                 iui->bytes2+=pinfo->fd->pkt_len;
281         }
282
283         return 1;
284 }
285
286 static int
287 iousers_fc_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vfc)
288 {
289         io_users_t *iu=arg;
290         const fc_hdr *fchdr=vfc;
291         const address *addr1, *addr2;
292         io_users_item_t *iui;
293
294         if(CMP_ADDRESS(&fchdr->s_id, &fchdr->d_id)<0){
295                 addr1=&fchdr->s_id;
296                 addr2=&fchdr->d_id;
297         } else {
298                 addr2=&fchdr->s_id;
299                 addr1=&fchdr->d_id;
300         }
301
302         for(iui=iu->items;iui;iui=iui->next){
303                 if((!CMP_ADDRESS(&iui->addr1, addr1))
304                 &&(!CMP_ADDRESS(&iui->addr2, addr2)) ){
305                         break;
306                 }
307         }
308
309         if(!iui){
310                 iui=g_malloc(sizeof(io_users_item_t));
311                 iui->next=iu->items;
312                 iu->items=iui;
313                 COPY_ADDRESS(&iui->addr1, addr1);
314                 iui->name1=strdup(address_to_str(addr1));
315                 COPY_ADDRESS(&iui->addr2, addr2);
316                 iui->name2=strdup(address_to_str(addr2));
317                 iui->frames1=0;
318                 iui->frames2=0;
319                 iui->bytes1=0;
320                 iui->bytes2=0;
321         }
322
323         if(!CMP_ADDRESS(&fchdr->d_id,&iui->addr1)){
324                 iui->frames1++;
325                 iui->bytes1+=pinfo->fd->pkt_len;
326         } else {
327                 iui->frames2++;
328                 iui->bytes2+=pinfo->fd->pkt_len;
329         }
330
331         return 1;
332 }
333
334 static int
335 iousers_eth_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *veth)
336 {
337         io_users_t *iu=arg;
338         const eth_hdr *ehdr=veth;
339         const address *addr1, *addr2;
340         io_users_item_t *iui;
341
342         if(CMP_ADDRESS(&ehdr->src, &ehdr->dst)<0){
343                 addr1=&ehdr->src;
344                 addr2=&ehdr->dst;
345         } else {
346                 addr2=&ehdr->src;
347                 addr1=&ehdr->dst;
348         }
349
350         for(iui=iu->items;iui;iui=iui->next){
351                 if((!CMP_ADDRESS(&iui->addr1, addr1))
352                 &&(!CMP_ADDRESS(&iui->addr2, addr2)) ){
353                         break;
354                 }
355         }
356
357         if(!iui){
358                 iui=g_malloc(sizeof(io_users_item_t));
359                 iui->next=iu->items;
360                 iu->items=iui;
361                 COPY_ADDRESS(&iui->addr1, addr1);
362                 iui->name1=strdup(address_to_str(addr1));
363                 COPY_ADDRESS(&iui->addr2, addr2);
364                 iui->name2=strdup(address_to_str(addr2));
365                 iui->frames1=0;
366                 iui->frames2=0;
367                 iui->bytes1=0;
368                 iui->bytes2=0;
369         }
370
371         if(!CMP_ADDRESS(&ehdr->dst,&iui->addr1)){
372                 iui->frames1++;
373                 iui->bytes1+=pinfo->fd->pkt_len;
374         } else {
375                 iui->frames2++;
376                 iui->bytes2+=pinfo->fd->pkt_len;
377         }
378
379         return 1;
380 }
381
382 static int
383 iousers_fddi_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *veth)
384 {
385         io_users_t *iu=arg;
386         const fddi_hdr *ehdr=veth;
387         const address *addr1, *addr2;
388         io_users_item_t *iui;
389
390         if(CMP_ADDRESS(&ehdr->src, &ehdr->dst)<0){
391                 addr1=&ehdr->src;
392                 addr2=&ehdr->dst;
393         } else {
394                 addr2=&ehdr->src;
395                 addr1=&ehdr->dst;
396         }
397
398         for(iui=iu->items;iui;iui=iui->next){
399                 if((!CMP_ADDRESS(&iui->addr1, addr1))
400                 &&(!CMP_ADDRESS(&iui->addr2, addr2)) ){
401                         break;
402                 }
403         }
404
405         if(!iui){
406                 iui=g_malloc(sizeof(io_users_item_t));
407                 iui->next=iu->items;
408                 iu->items=iui;
409                 COPY_ADDRESS(&iui->addr1, addr1);
410                 iui->name1=strdup(address_to_str(addr1));
411                 COPY_ADDRESS(&iui->addr2, addr2);
412                 iui->name2=strdup(address_to_str(addr2));
413                 iui->frames1=0;
414                 iui->frames2=0;
415                 iui->bytes1=0;
416                 iui->bytes2=0;
417         }
418
419         if(!CMP_ADDRESS(&ehdr->dst,&iui->addr1)){
420                 iui->frames1++;
421                 iui->bytes1+=pinfo->fd->pkt_len;
422         } else {
423                 iui->frames2++;
424                 iui->bytes2+=pinfo->fd->pkt_len;
425         }
426
427         return 1;
428 }
429
430 static int
431 iousers_tr_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vtr)
432 {
433         io_users_t *iu=arg;
434         const tr_hdr *trhdr=vtr;
435         const address *addr1, *addr2;
436         io_users_item_t *iui;
437
438         if(CMP_ADDRESS(&trhdr->src, &trhdr->dst)<0){
439                 addr1=&trhdr->src;
440                 addr2=&trhdr->dst;
441         } else {
442                 addr2=&trhdr->src;
443                 addr1=&trhdr->dst;
444         }
445
446         for(iui=iu->items;iui;iui=iui->next){
447                 if((!CMP_ADDRESS(&iui->addr1, addr1))
448                 &&(!CMP_ADDRESS(&iui->addr2, addr2)) ){
449                         break;
450                 }
451         }
452
453         if(!iui){
454                 iui=g_malloc(sizeof(io_users_item_t));
455                 iui->next=iu->items;
456                 iu->items=iui;
457                 COPY_ADDRESS(&iui->addr1, addr1);
458                 iui->name1=strdup(address_to_str(addr1));
459                 COPY_ADDRESS(&iui->addr2, addr2);
460                 iui->name2=strdup(address_to_str(addr2));
461                 iui->frames1=0;
462                 iui->frames2=0;
463                 iui->bytes1=0;
464                 iui->bytes2=0;
465         }
466
467         if(!CMP_ADDRESS(&trhdr->dst,&iui->addr1)){
468                 iui->frames1++;
469                 iui->bytes1+=pinfo->fd->pkt_len;
470         } else {
471                 iui->frames2++;
472                 iui->bytes2+=pinfo->fd->pkt_len;
473         }
474
475         return 1;
476 }
477
478 static void
479 iousers_draw(void *arg)
480 {
481         io_users_t *iu = arg;
482         io_users_item_t *iui;
483         guint32 last_frames, max_frames;
484
485         printf("================================================================================\n");
486         printf("%s Conversations\n",iu->type);
487         printf("Filter:%s\n",iu->filter?iu->filter:"<No Filter>");
488         printf("                                               |       <-      | |       ->      | |     Total     |\n");
489         printf("                                               | Frames  Bytes | | Frames  Bytes | | Frames  Bytes |\n");
490         max_frames=0xffffffff;
491         do {
492                 last_frames=0;
493                 for(iui=iu->items;iui;iui=iui->next){
494                         guint32 tot_frames;
495                         tot_frames=iui->frames1+iui->frames2;
496
497                         if((tot_frames>last_frames)
498                         &&(tot_frames<max_frames)){
499                                 last_frames=tot_frames;
500                         }
501                 }
502                 for(iui=iu->items;iui;iui=iui->next){
503                         guint32 tot_frames;
504                         tot_frames=iui->frames1+iui->frames2;
505
506                         if(tot_frames==last_frames){
507                                 printf("%-20s <-> %-20s  %6d %9d  %6d %9d  %6d %9d\n",
508                                         iui->name1, iui->name2,
509                                         iui->frames1, iui->bytes1,
510                                         iui->frames2, iui->bytes2,
511                                         iui->frames1+iui->frames2,
512                                         iui->bytes1+iui->bytes2
513                                 );
514                         }
515                 }
516                 max_frames=last_frames;
517         } while(last_frames);
518         printf("================================================================================\n");
519 }
520
521 void
522 iousers_init(char *optarg)
523 {
524         char *filter=NULL;
525         char *tap_type, *tap_type_name;
526         tap_packet_cb packet_func;
527         io_users_t *iu=NULL;
528         GString *error_string;
529
530         if(!strncmp(optarg,"conv,eth",8)){
531                 if(optarg[8]==','){
532                         filter=optarg+9;
533                 } else {
534                         filter=NULL;
535                 }
536                 tap_type="eth";
537                 tap_type_name="Ethernet";
538                 packet_func=iousers_eth_packet;
539         } else if(!strncmp(optarg,"conv,fc",7)){
540                 if(optarg[7]==','){
541                         filter=optarg+8;
542                 } else {
543                         filter=NULL;
544                 }
545                 tap_type="fc";
546                 tap_type_name="Fibre Channel";
547                 packet_func=iousers_fc_packet;
548         } else if(!strncmp(optarg,"conv,fddi",9)){
549                 if(optarg[9]==','){
550                         filter=optarg+10;
551                 } else {
552                         filter=NULL;
553                 }
554                 tap_type="fddi";
555                 tap_type_name="FDDI";
556                 packet_func=iousers_fddi_packet;
557         } else if(!strncmp(optarg,"conv,tcp",8)){
558                 if(optarg[8]==','){
559                         filter=optarg+9;
560                 } else {
561                         filter=NULL;
562                 }
563                 tap_type="tcp";
564                 tap_type_name="TCP";
565                 packet_func=iousers_tcpip_packet;
566         } else if(!strncmp(optarg,"conv,udp",8)){
567                 if(optarg[8]==','){
568                         filter=optarg+9;
569                 } else {
570                         filter=NULL;
571                 }
572                 tap_type="udp";
573                 tap_type_name="UDP";
574                 packet_func=iousers_udpip_packet;
575         } else if(!strncmp(optarg,"conv,tr",7)){
576                 if(optarg[7]==','){
577                         filter=optarg+8;
578                 } else {
579                         filter=NULL;
580                 }
581                 tap_type="tr";
582                 tap_type_name="Token Ring";
583                 packet_func=iousers_tr_packet;
584         } else if(!strncmp(optarg,"conv,ipx",8)){
585                 if(optarg[8]==','){
586                         filter=optarg+9;
587                 } else {
588                         filter=NULL;
589                 }
590                 tap_type="ipx";
591                 tap_type_name="IPX";
592                 packet_func=iousers_ipx_packet;
593         } else if(!strncmp(optarg,"conv,ip",7)){
594                 if(optarg[7]==','){
595                         filter=optarg+8;
596                 } else {
597                         filter=NULL;
598                 }
599                 tap_type="ip";
600                 tap_type_name="IPv4";
601                 packet_func=iousers_ip_packet;
602         } else {
603                 fprintf(stderr, "tethereal: invalid \"-z conv,<type>[,<filter>]\" argument\n");
604                 fprintf(stderr,"   <type> must be one of\n");
605                 fprintf(stderr,"      \"eth\"\n");
606                 fprintf(stderr,"      \"fc\"\n");
607                 fprintf(stderr,"      \"fddi\"\n");
608                 fprintf(stderr,"      \"ip\"\n");
609                 fprintf(stderr,"      \"ipx\"\n");
610                 fprintf(stderr,"      \"tcp\"\n");
611                 fprintf(stderr,"      \"tr\"\n");
612                 fprintf(stderr,"      \"udp\"\n");
613                 exit(1);
614         }
615
616
617         iu=g_malloc(sizeof(io_users_t));
618         iu->items=NULL;
619         iu->type=tap_type_name;
620         if(filter){
621                 iu->filter=strdup(filter);
622         } else {
623                 iu->filter=NULL;
624         }
625
626         error_string=register_tap_listener(tap_type, iu, filter, NULL, packet_func, iousers_draw);
627         if(error_string){
628                 if(iu->items){
629                         g_free(iu->items);
630                 }
631                 g_free(iu);
632                 fprintf(stderr, "tethereal: Couldn't register conversations tap: %s\n",
633                     error_string->str);
634                 g_string_free(error_string, TRUE);
635                 exit(1);
636         }
637
638 }
639
640 void
641 register_tap_listener_iousers(void)
642 {
643         register_ethereal_tap("conv,", iousers_init);
644 }