add packages_10.03.2 in preparation for the 10.03.2 interim release
[10.03/packages.git] / utils / pipacs / src / pipacs.c
1 // http://www.phj.hu/freesoft.asp
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include "parser.h"
5
6 #ifndef LINUX
7 #include <mstcpip.h>
8 #include <ws2tcpip.h>
9 #else
10 #include <termios.h>
11 struct promisc_device
12 {
13     char name[16]; /* name (e.g. eth0) */
14
15     int reset; /* do we have to reset it on exit ? */
16     struct ifreq oldifr; /* old settings */
17
18     struct promisc_device *next;
19 };
20
21 #endif
22
23 DWORD  dwIoControlCode=SIO_RCVALL;
24 DWORD   dwProtocol=IPPROTO_IP,  dwInterface=0;
25
26 #define MAXVER 2
27 #define MINVER 6
28 SOCKET        s;
29
30 //
31 // Filters (Globals)
32 //
33 unsigned int   uiSourceAddr=0,  uiDestAddr=0, uiXAddr=0;
34 unsigned short usSourcePort = 0, usDestPort = 0, usXPort = 0;
35 unsigned short usSourceNet = 32, usDestNet = 32, usXNet = 32;
36 unsigned long  ulDestNet=0xffffffff, ulSourceNet=0xffffffff, ulXNet=0xffffffff;
37 BOOL           bFilter=FALSE;
38 int            iline=25;
39 char myipname[64];
40 char pattern[1024];
41 int justheader=0;
42 int gre=0;
43 int sortbysize,fromip,toip;
44 int skipvlan=0;
45
46 extern char filename[128];
47
48 extern char intlist[128];
49
50 #ifndef LINUX
51 void PrintInterfaceList( void );
52 int  GetInterface(SOCKET , SOCKADDR_IN *, int );
53 #endif
54 extern int InitIPAcc( void );
55 extern int CloseIPAcc( void );
56 extern int iCycle;
57 extern int iScreen;
58 extern int iFile;
59 extern int iDetail;
60 extern int iRun;
61 extern long lNum;
62 extern FILE *f;
63 extern int iProto;
64 extern int iSum;
65 extern char execname[];
66 extern int mostird;
67 extern  int iLnxplus;
68
69 int set_raw_mode(void)
70 {
71     int fd = STDIN_FILENO;
72     struct termios t;
73         
74     if (tcgetattr(fd, &t) < 0) { perror("tcgetattr");   return -1; }
75     t.c_lflag &= ~ICANON;
76     if (tcsetattr(fd, TCSANOW, &t) < 0) { perror("tcsetattr"); return -1; }
77     setbuf(stdin, NULL);
78     return 0;
79 }//
80 // Function: usage
81 //
82 // Description:
83 //    Prints usage information.
84 //
85 char *author = "phj";
86
87 void usage(char *progname)
88 {
89     printf("  usage: %s options\n    where options:\n", progname);
90         printf("       [-c:sec]             Dump cycle in sec (10)\n");
91         printf("       [-f:file[-e:program]] Results into a file [and exec program](-)\n");
92         printf("       [-n:db]              Execute just db cycle (0)\n");
93         printf("       [-l:lineno]          Print lineno lines of hosts(25)\n");
94         printf("       [-k]                 Sort result by packet count (size)\n");
95         printf("       [-1]                 Ignore source IP (don't ignore)\n");
96         printf("       [-2]                 Ignore destination IP (don't ignore)\n");
97         printf("       [-h]                 Print just the header(use -a!)\n");
98         printf("       [-a]                 Print packet info&data (-)\n");
99         printf("       [-p]                 Print just summary info (-)\n");
100         printf("            Otherwise print sum&ip pairs\n");
101 //#ifndef LINUX
102         printf("       [-t:[tcp|udp|icmp|....|number]] Filter on IP protocoll (ALL)\n");
103 //#endif
104         printf("       [-g]                 Make GRE encapsulation trasparent (-)\n");
105         printf("       [-v]                 Skip VLAN headers (-)\n");
106         printf("       [-sa:IP[/Net]]       Filter on source address (-)/net\n");
107         printf("       [-sp:Port]           Filter on source port (-)\n");
108         printf("       [-da:IP[/Net]]       Filter on dest address/net (-)\n");
109         printf("       [-dp:Port]           Filter on dest port(-)\n");
110         printf("       [-xa:IP[/Net]]       Filter on src|dest address/net (-)\n");
111         printf("       [-xp:Port]           Filter on src|dest port (-)\n");
112         printf("       [-pa:pattern]        String match (0), last param!!!\n");
113 #ifndef LINUX
114         printf("       [-i:int]             Capture on this interface (0)\n");
115         printf("             Available interfaces:\n");
116         PrintInterfaceList();
117 #else
118         printf("       [-i:int[,int]]       Capture on this interface (eth0)\n");
119 #endif
120         printf("             Filtering rules:  t && (sa|da|xa) && (sp|dp|xp)");
121         printf("\nVer. %d.%d  (c):2000-2006, P l¢czi-Horv th J nos\n",MAXVER,MINVER);
122 #ifndef LINUX
123         WSACleanup();
124         ExitProcess(-1);
125 #else
126         exit(5);
127 #endif
128 }
129
130 //
131 // Function: ValidateArgs
132 //
133 // Description:
134 //    This function parses the command line arguments and
135 //    sets global variables to indicate how the app should act.
136 //
137 void ValidateArgs(int argc, char **argv)
138 {
139     int   i,j;
140     char *ptr;
141     
142     sortbysize=1; fromip=1; toip=1;
143
144         if (argc <2) { usage(argv[0]); return; }
145         if (*(author+2) != 'j') { usage(argv[0]); return; }
146     for(i=1; i < argc ;i++) {
147         if ((argv[i][0] == '-') || (argv[i][0] == '/')) {
148             switch (tolower(argv[i][1])) {
149                 case 't':        // traffic type
150                     ptr = &argv[i][2];
151                     while (*++ptr)  *ptr = toupper(*ptr);
152                     ptr = &argv[i][3];
153                     for ( j=0;j<134;j++) {
154                     if (!strcmp(ptr, szProto[j])) {
155 //                        dwIoControlCode = SIO_RCVALL;
156 #ifdef LINUX
157                         dwProtocol = j;
158 #endif
159                         iProto=j;
160                         break;
161                     }
162                     }
163                     if ((j>133) && atoi(&argv[i][3])) {
164 //                        dwIoControlCode = SIO_RCVALL;
165 #ifdef LINUX
166                         dwProtocol = atoi(&argv[i][3]);
167 #endif
168                         iProto=atoi(&argv[i][3]);
169                     } else  if (j>133)    usage(argv[0]);
170                     break;
171                 case 'i':        // interface number
172 #ifndef LINUX
173                     dwInterface = atoi(&argv[i][3]);
174 #else
175                                     strcpy(intlist,&argv[i][3]);
176                                         ptr=strchr(intlist,' ');
177                                         if (ptr) *ptr=0;
178 #endif
179                     break;
180                 case 'g':        // gre
181                     gre=1;
182                     break;
183                 case 'c':        // cycle time
184                     iCycle = atoi(&argv[i][3]);
185                     break;
186                 case 'a':        // cycle time
187                     iDetail = 1;
188                     break;
189                 case 'h':        // cycle time
190                     iDetail = justheader = 1;
191                     break;
192                 case 'n':        // just n cycle
193                     lNum = atol(&argv[i][3]);
194                     break;
195                 case 'l':        // lineno lines
196                     iline = atoi(&argv[i][3]);
197                     break;
198                 case 'p':        // just summary
199                     if ((tolower(argv[i][2]) == 'a')) {
200                        strcpy(pattern,&argv[i][4]); printf("\n Pattern: \'%s",&argv[i][4]);
201                        while (++i<argc) { strcat(pattern," "); strcat(pattern,&argv[i][0]); printf(" %s",argv[i]); }
202                        printf("\'\n");
203                     } else  iSum=1;
204                     break;
205                 case 'f':        // filename to write
206                     strcpy(filename,&argv[i][3]);
207                     iFile=1; //iScreen=0;
208                     break;
209                 case 'e':        // execname
210                     strcpy(execname,&argv[i][3]);
211                     break;
212                 case 'k':        // sor by count
213                     sortbysize = 0;
214                     break;
215                 case '1':        // ignore src
216                     fromip = 0;
217                     break;
218                 case '2':        // ignore dst
219                     toip = 0;
220                     break;
221                 case 'v':        // sor by count 
222                     skipvlan = 4; 
223                     if ((tolower(argv[i][2]) == ':')) { 
224                          skipvlan=atoi(&argv[i][3]); 
225                      } 
226                      break; 
227                 case 's':        // Filter on source ip or port
228                     if (tolower(argv[i][2]) == 'a') {
229                        ptr=strchr(&argv[i][4],'/');
230                        if (ptr) { usSourceNet=atoi(ptr+1); *ptr=0;}
231                        uiSourceAddr = ntohl(inet_addr(&argv[i][4]));
232                     } else if (tolower(argv[i][2]) == 'p')
233                         usSourcePort = (unsigned short)atoi(&argv[i][4]);
234                     else
235                     usage(argv[0]);
236                     bFilter = TRUE;
237                     break;
238                 case 'd':       // Filter on dest ip or port
239                     if (tolower(argv[i][2]) == 'a') {
240                         ptr=strchr(&argv[i][4],'/');
241                         if (ptr) { usDestNet=atoi(ptr+1); *ptr=0; }
242                         uiDestAddr = ntohl(inet_addr(&argv[i][4]));
243                     } else if (tolower(argv[i][2]) == 'p')
244                         usDestPort = (unsigned short)atoi(&argv[i][4]);
245                     else
246                         usage(argv[0]);
247                     bFilter = TRUE;
248                     break;
249                 case 'x':        // Filter on source or dest ip or port
250                     if (tolower(argv[i][2]) == 'a') {
251                        ptr=strchr(&argv[i][4],'/');
252                        if (ptr) { usXNet=atoi(ptr+1); *ptr=0; }
253                        uiXAddr = ntohl(inet_addr(&argv[i][4]));
254                     } else if (tolower(argv[i][2]) == 'p')
255                         usXPort = (unsigned short)atoi(&argv[i][4]);
256                     else
257                         usage(argv[0]);
258                     bFilter = TRUE;
259                     break;
260                 default:
261                     usage(argv[0]);
262             }
263         } else usage(argv[0]);
264     }
265     iLnxplus+=skipvlan;
266     return;
267 }
268
269 #ifndef LINUX
270 //
271 // Function: PrintInterfaceList
272 //
273 // Description:
274 //    This function prints all local IP interfaces.
275 //
276 void PrintInterfaceList()
277 {
278     SOCKET_ADDRESS_LIST *slist=NULL;
279     SOCKET               s;
280     char                 buf[2048];
281     DWORD                dwBytesRet;
282     int                  ret,
283                          i;
284
285     s = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
286     if (s == SOCKET_ERROR) {
287         printf("socket() failed: %d\n", WSAGetLastError());
288         return;
289     }
290     ret = WSAIoctl(s, SIO_ADDRESS_LIST_QUERY, NULL, 0, buf, 2048,&dwBytesRet, NULL, NULL);
291     if (ret == SOCKET_ERROR){
292         printf("WSAIoctl(SIO_ADDRESS_LIST_QUERY) failed: %d\n",WSAGetLastError());
293         return;
294     }
295     slist = (SOCKET_ADDRESS_LIST *)buf;
296     for(i=0; i < slist->iAddressCount ;i++) {
297         printf("               %-2d ........ [%s]\n", i,
298             inet_ntoa(((SOCKADDR_IN *)slist->Address[i].lpSockaddr)->sin_addr));
299     }
300     closesocket(s);
301     return;
302 }
303
304 //
305 // Function: GetInterface
306 //
307 // Description:
308 //    This function retrieves a zero based index and returns
309 //    the IP interface corresponding to that.
310 //
311 int GetInterface(SOCKET s, SOCKADDR_IN *ifx, int num)
312 {
313     SOCKET_ADDRESS_LIST *slist=NULL;
314     char                 buf[2048];
315     DWORD                dwBytesRet;
316     int                  ret;
317
318     ret = WSAIoctl(s, SIO_ADDRESS_LIST_QUERY, NULL, 0, buf, 2048,&dwBytesRet, NULL, NULL);
319     if (ret == SOCKET_ERROR) {
320         printf("WSAIoctl(SIO_ADDRESS_LIST_QUERY) failed: %d\n",WSAGetLastError());
321         return -1;
322     }
323     slist = (SOCKET_ADDRESS_LIST *)buf;
324     if (num >= slist->iAddressCount)  return -1;
325     ifx->sin_addr.s_addr = ((SOCKADDR_IN *)slist->Address[num].lpSockaddr)->sin_addr.s_addr;
326         if (*author != 'p') return -1;
327     return 0;
328 }
329 #endif
330 #ifdef LINUX
331 struct promisc_device *prom;
332
333 void init_capture( void )
334 /*
335  * 1) Open our capture socket
336  * 2) Set all the promisc devices to promiscous mode
337  */
338 {
339     struct ifreq ifr;
340     struct promisc_device *p,*pp;
341     struct protoent *pr;
342     char *p1,*p2;
343
344     if ((s = socket (AF_INET, SOCK_PACKET, htons (ETH_P_ALL))) < 0)
345         {
346             printf(" can't get socket: \n");
347             exit(1);
348         }
349     strcpy(myipname,intlist);
350     p1=intlist; p=NULL;
351     while (p1) {
352                 pp=p;
353                 p = malloc(sizeof(struct promisc_device));
354                 if (pp) pp->next=p; else prom=p;
355                 if ( (p2=strchr(p1,',')))       *p2++=0;
356                 strcpy(&p->name,p1); p->next=NULL;
357                 printf(" %s",p->name); fflush(stdout);
358                 p1=p2;
359 //    while(p!=NULL) {
360             strcpy (p -> oldifr.ifr_name, p -> name);
361
362             if (ioctl (s, SIOCGIFFLAGS, &(p -> oldifr)) < 0) {
363                     printf(" can't get flags: \n");
364                     exit(2);
365                 }
366             p -> reset = 1;
367             ifr = p -> oldifr;
368             if (ifr.ifr_flags & IFF_PROMISC) printf(" already promisc! \n");
369             ifr.ifr_flags |= IFF_PROMISC;
370             if (ioctl (s, SIOCSIFFLAGS, &ifr) < 0) {
371                     printf(" can't set flags: \n");
372                     exit(3);
373                 }
374 //          p = p -> next;
375         }
376 }
377
378 void exit_capture(void)
379 {
380     struct promisc_device *p;
381
382     /* do we have to check (capture_sd >= 0) ? */
383
384     p = prom;
385
386     while(p != NULL) {
387             if (ioctl (s, SIOCSIFFLAGS, &(p -> oldifr)) < 0) {
388                     printf("can't reset flags: \n");
389                 }
390
391             p = p -> next;
392         }
393
394     close (s);
395 }
396 #endif
397 //
398 // Function: main
399 //
400 int main(int argc, char **argv) {
401     WSADATA       wsd;
402     SOCKADDR_IN   if0;
403     int           ret,count;
404     unsigned int  optval;
405     DWORD         dwBytesRet,
406                   dwFlags,
407                   nproc;
408     char          rcvbuf[MAX_IP_SIZE];
409     WSABUF        wbuf;
410     unsigned long i;
411 #ifndef LINUX
412     // Load Winsock
413     //
414     if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) {
415         printf(" WSAStartup() failed: %d\n", GetLastError());
416         return -1;
417     }
418 #else
419     SOCKADDR    ssaddr;
420     struct promisc_device *p;
421     fd_set      ready;
422     struct timeval tv;
423 #endif
424     char Key;
425     int status;
426     FILE *input;
427 // Parse the command line
428 //
429     strcpy(intlist,"eth0");
430     for(i=100;i<255;i++) szProto[i]="?!?";
431     szProto[103]="PIM";
432     szProto[108]="IPCOMP";
433     szProto[112]="VRRP";
434     szProto[115]="L2TP";
435     szProto[124]="ISIS";
436     szProto[132]="SCTP";
437     szProto[133]="FC";
438     *execname=0;
439     ValidateArgs(argc, argv);
440     if (bFilter) {
441                 i=uiSourceAddr;
442                 if ( i || usSourcePort)
443         printf(" Source: %03d.%03d.%03d.%03d/%d:%d\n",(i&0xff000000)>>24,(i&0x00ff0000)>>16,(i&0x0000ff00)>>8,i&0xff,uiSourceAddr?usSourceNet:0, usSourcePort);
444                 i=uiDestAddr;
445                 if ( i || usDestPort)
446                         printf(" Dest. : %03d.%03d.%03d.%03d/%d:%d\n",(i&0xff000000)>>24,(i&0x00ff0000)>>16,(i&0x0000ff00)>>8,i&0xff,uiDestAddr?usDestNet:0, usDestPort);
447                 i=uiXAddr;
448                 if ( i || usXPort)
449                         printf("  IP.   : %03d.%03d.%03d.%03d/%d:%d\n",(i&0xff000000)>>24,(i&0x00ff0000)>>16,(i&0x0000ff00)>>8,i&0xff,uiXAddr?usXNet:0, usXPort);
450     }
451         if (iFile) printf(" To file : %s\n",filename);
452         if (iProto) printf(" Protocol: %s (%d)\n",szProto[iProto],iProto);
453     // Create a raw socket for receiving IP datagrams
454     //
455 #ifndef LINUX
456     s = WSASocket(AF_INET, SOCK_RAW, dwProtocol, NULL, 0, WSA_FLAG_OVERLAPPED);
457     if (s == INVALID_SOCKET)
458     {
459         printf("WSASocket() failed: %d\n", WSAGetLastError());
460         return -1;
461     }
462     // Get an interface to read IP packets on
463     //
464         memset(&if0,0,sizeof(if0));
465         if0.sin_family = AF_INET;
466     if0.sin_port = htons(0);
467     if (GetInterface(s, &if0, dwInterface) != 0)
468     {
469         printf("Unable to obtain an interface\n");
470         return -1;
471     }
472     sprintf(myipname,"%-16s",inet_ntoa(if0.sin_addr));
473 #else
474         printf("starting capture ...."); fflush(stdout);
475         init_capture();
476         printf(" capture started ....\n"); fflush(stdout);
477 #endif
478     printf(" Binding to IF: %s\n", myipname);
479 #ifndef LINUX
480 //
481 // This socket MUST be bound before calling the ioctl
482 //
483
484     if (bind(s, (SOCKADDR *)&if0, sizeof(if0)) == SOCKET_ERROR) {
485         printf("bind() failed: %d\n", WSAGetLastError());
486         return -1;
487     }
488 //
489 // Set the SIO_RCVALLxxx ioctl
490 //
491     optval = 1;
492     if (WSAIoctl(s, dwIoControlCode, &optval, sizeof(optval),
493             NULL, 0, &dwBytesRet, NULL, NULL) == SOCKET_ERROR) {
494         printf("WSAIotcl() set raw socket failed; %d\n", WSAGetLastError());
495 //        return -1;
496         optval = 2;
497         if (WSAIoctl(s, dwIoControlCode, &optval, sizeof(optval),
498             NULL, 0, &dwBytesRet, NULL, NULL) == SOCKET_ERROR) {
499         printf("WSAIotcl() set raw socket only failed; %d\n", WSAGetLastError());
500         return -1;
501         }
502     }
503     system("cls");
504 #else
505     tv.tv_sec=0; tv.tv_usec=0;
506     set_raw_mode();
507     FD_ZERO(&ready);
508     FD_SET(STDIN_FILENO,&ready);
509 #endif
510     input = fopen("/dev/tty", "r");      //open the terminal keyboard 
511     if (uiSourceAddr==0) ulSourceNet=0;
512     else for ( i=0; i<32-usSourceNet; i++) ulSourceNet <<= 1;
513     if (uiDestAddr==0) ulDestNet=0;
514     else for ( i=0; i<32-usDestNet; i++) ulDestNet <<= 1;
515     if (uiXAddr==0) ulXNet=0;
516     else for ( i=0; i<32-usXNet; i++) ulXNet <<= 1;
517     if (uiXAddr) uiSourceAddr=uiDestAddr=uiXAddr;
518     if (usXPort) usSourcePort=usDestPort=usXPort;
519     if (ulXNet) ulSourceNet=ulDestNet=ulXNet;
520     InitIPAcc();
521 // Start receiving IP datagrams until interrupted
522 //
523     count = 0;
524     if (iFile && iDetail)   f=fopen(filename,"w+");
525     if (iProto) bFilter=1;
526     if (*(author+1) != 'h') iRun=0;
527     while (iRun)    {
528         rcvbuf[MAX_IP_SIZE]=0;
529         wbuf.len = MAX_IP_SIZE;
530         wbuf.buf = rcvbuf;
531 #ifndef LINUX
532         dwFlags  = 0;
533         ret = WSARecv(s, &wbuf, 1, &dwBytesRet, &dwFlags, NULL, NULL);
534         if (ret == SOCKET_ERROR) {
535             printf("WSARecv() failed: %d\n", WSAGetLastError());
536             return -1;
537         }
538         if (kbhit()) {
539 #else
540         dwFlags  = sizeof(ssaddr);
541
542                 ret = recvfrom (s, wbuf.buf, MAX_IP_SIZE, 0, &ssaddr, (int *) &dwFlags);
543                 if (ret == -1) continue;
544                 dwBytesRet=wbuf.len=ret;
545                 p=prom;
546                 while(p!=NULL)  {
547                         if (!strcmp(p -> name, ssaddr.sa_data)) break;
548                         p=p->next;
549                 }
550                 if (!p) {
551 //                      printf("\n%s: ignored",ssaddr.sa_data); fflush(stdout);
552                         continue;
553                 }
554         FD_ZERO(&ready);
555         FD_SET(STDIN_FILENO,&ready);
556         if (select(STDIN_FILENO+1,&ready,NULL,NULL,&tv)>0) {
557 //      if (FD_ISSET(STDIN_FILENO,&ready)) {
558 #endif
559            switch (getchar())  { /* branch to appropiate key handler */
560                 case 0x1b: /* Esc */
561                     iRun=0;
562                 break;
563                 default:
564                     mostird=1;
565                 break;
566            }  //end of switch key
567         }
568
569 // Deccode the IP header
570 //
571         if (!(nproc = DecodeIPHeader(&wbuf, uiSourceAddr, usSourcePort, ulSourceNet,
572                 uiDestAddr, usDestPort, ulDestNet, dwBytesRet,usXPort,uiXAddr,ulXNet)))
573         {
574 //            printf("Error decoding IP header!\n");
575 //            break;
576         }
577     }
578     // Cleanup
579     //
580     if (iRun && !iDetail) CloseIPAcc();
581     if (f) fclose(f);
582 #ifndef LINUX
583     closesocket(s);
584     WSACleanup();
585 #else
586     exit_capture();
587 #endif
588     return 0;
589 }