1 /***************************************************************************
2 
3     disco.c - Disco main c file
4 
5     Date: 06.12.2003
6     Ver : 1.2
7 
8     Disco: The passive ip discovery and fingerprinting tool
9 
10     Copyright (c) 2003 by Preston Wood
11     All rights reserved.
12 
13     Author(s): Preston Wood  <p@altmode.com>
14 
15 /***************************************************************************
16 
17   This program is free software; you can redistribute it and/or modify
18   it under the terms of the GNU General Public License as published by
19   the Free Software Foundation; either version 2 of the License, or
20   (at your option) any later version.
21 
22   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
25   THE AUTHOR, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
26   DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
27   OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
28   OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 
30 ***************************************************************************/
31 
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include "./disco.h"
39 /* disco.c */
40 
41 int loop = 1;
42 u_long ip = 0;
43 int synack=0,verbose=0,fp_cand=0,found=0,unique_ip=0,totpacket_fp=0,totfp=0,ack=0,fingerprint=0,allip=0;
44 char found_os[255];
45 char optstr[60]="";
46 uint32_t srcip;
47 struct fingerprints loadedfp[MAXFP];
48 struct fingerprints packet_fp;
49 struct table_entry *fhash_table[HASH_TABLE_SIZE];
50 struct table_entry *ihash_table[HASH_TABLE_SIZE];
51 struct table_entry *ahash_table[HASH_TABLE_SIZE];
52 struct iphdr *ip_h;
53 struct tcphdr *tcp_h;
54 
55 
main(int argc,char ** argv)56 int main(int argc, char **argv)
57 {
58     int c=0;
59     int totfp=0;
60     pcap_t *p;
61     char *device = NULL, *rule = NULL;
62     char *foundip;
63     char *dstip;
64     char *logfile = NULL;
65 
66     char *pipearg = NULL;     // -p argument as a C string
67     char *pretext = NULL;     // -P argument as a C string
68     char *args[MAX_NUM_ARGS]; // Arguments for pipe output
69 
70     char *saved_file = NULL;
71     char *timestamp = NULL;
72     u_char *packet;
73     int print_ip=1,ethmode=0,discover=0,itime=0,disp_time=0,only_syn=0,iphlen=0,use_file=0;
74     struct pcap_pkthdr h;
75     struct pcap_stat ps;
76     struct in_addr *paaddr;
77     char errbuf[PCAP_ERRBUF_SIZE];
78     struct bpf_program filter_code;
79     bpf_u_int32 local_net, netmask;
80     FILE *outfile;
81     time_t stime;
82 
83     while ((c = getopt(argc, argv, "evDAfNSs:i:r:o:p:P:uht")) != -1)
84 
85     {
86             switch (c)
87             {
88 		     case 'e':
89 		     	ethmode = 1;
90 			break;
91 		     case 'v':
92 		        verbose = 1;
93 			break;
94 		     case 'D':
95 		        discover = 1;
96 			break;
97 		     case 'A':
98 		     	ack = 1;
99 			break;
100 		     case 'f':
101                         totfp = load_fingerprints();
102                         fingerprint = 1;
103                         break;
104                      case 'N':
105                         print_ip = 0;
106                         break;
107                      case 'S':
108                         only_syn = 1;
109                         break;
110 		     case 's':
111 		     	saved_file = optarg;
112 			use_file = 1;
113 			break;
114                      case 'i':
115                         device = optarg;
116                         break;
117                      case 'r':
118                         rule = optarg;
119                         break;
120                      case 'u':
121                         unique_ip = 1;
122                         break;
123                      case 'o':
124                         logfile = optarg;
125                         break;
126 		     case 'p':
127                         pipearg = optarg;
128                         break;
129                      case 'P':
130                         pretext = optarg;
131                         break;
132                      case 'h':
133                         usage("Options");
134                         break;
135 		     case 't':
136 			disp_time = 1;
137 //			timer = time(NULL);
138 			break;
139                      default:
140                         usage("Bad Option");
141             }
142             if ( rule == NULL )
143             {
144                 rule = "ip";
145             }
146     }
147 
148     if ( c==0 )
149     {
150         usage("Need Option");
151     }
152 
153     printf("Disco v1.2\n");
154 
155     /* If the -p option was set, parse its argument into an
156      * argv-style array */
157 
158     if (pipearg != NULL)
159     {
160         if (!parse(pipearg, args))
161         {
162             fprintf(stderr, "Could not parse -p argument\n");
163             exit(EXIT_FAILURE);
164 
165         } // if (parsing failed)
166 
167     } // if (parsing pipearg)
168 
169     /* If no device is specified error out */
170 
171     if (device == NULL)
172     {
173         device = pcap_lookupdev(errbuf);
174         if (device == NULL)
175         {
176             fprintf(stderr, "pcap_lookupdev() failed: %s\n", errbuf);
177         }
178     }
179 
180     if (saved_file == NULL)
181     {
182 
183     	/* Open the ethernet interface for packet capture */
184 
185     	p = pcap_open_live(device, SNAPLEN, PROMISC, TIMEOUT, errbuf);
186     	if (p == NULL)
187     	{
188         	fprintf(stderr, "pcap_open_live() failed: %s\n", errbuf);
189         	exit(EXIT_FAILURE);
190     	}
191 
192 
193 	if (ethmode == 0)
194 	{
195 		/* Set BPF filter only looking at IP packets */
196 		if (pcap_lookupnet(device, &local_net, &netmask, errbuf) == -1)
197     		{
198         		fprintf(stderr, "pcap_lookupnet() failed: %s\n", errbuf);
199         		pcap_close(p);
200         		exit(EXIT_FAILURE);
201     		}
202 	}
203 
204     }
205     else
206     {
207     	p = pcap_open_offline(saved_file, errbuf);
208     	if (p == NULL)
209     	{
210     		fprintf(stderr, "pcap_open_offline() failed: %s\n", errbuf);
211 		exit(EXIT_FAILURE);
212     	}
213     }
214 
215     /* Compile rule expression into a program */
216 
217     if (pcap_compile(p, &filter_code, rule, 1, netmask) == -1)
218     {
219         fprintf(stderr, "pcap_compile() failed: %s\n", pcap_geterr(p));
220         pcap_close(p);
221         exit(EXIT_FAILURE);
222     }
223 
224     /* Load the compiled filter in the packet capture device */
225 
226     if (pcap_setfilter(p, &filter_code) == -1)
227     {
228         fprintf(stderr, "pcap_setfilter() failed: %s\n", pcap_geterr(p));
229         pcap_close(p);
230         exit(EXIT_FAILURE);
231     }
232 
233     /* Check the link to make sure it is ethernet */
234 
235     if (pcap_datalink(p) != DLT_EN10MB)
236     {
237         fprintf(stderr, "Disco only works on ethernet networks\n");
238         pcap_close(p);
239         exit(EXIT_FAILURE);
240     }
241 
242     /* Gather captured packet stats before we exit */
243 
244     if (catch_sig(SIGINT, cleanup) == -1)
245     {
246         fprintf(stderr, "Can't catch the signal\n");
247         pcap_close(p);
248         exit(EXIT_FAILURE);
249     }
250 
251     ht_init_table(ihash_table);
252     outfile = fopen(logfile,"w");
253 
254     /* Start looping through packets ctrl-c to exit */
255 
256     for ( ht_init_table(fhash_table); loop;)
257     {
258         packet = (u_char *)pcap_next(p, &h);
259         if (packet == NULL)
260         {
261 		if ( use_file == 1 )
262 		{
263 			exit(EXIT_SUCCESS);
264 		}
265 		else
266 		{
267             		continue;
268 		}
269         }
270 
271         /* Parse IP Hdr to check */
272         ip_h = (struct iphdr *) (packet + 14);
273         iphlen = ((ip_h->ihl*4));
274 
275         srcip = (ntohl(ip_h->saddr)); //Convert src network ip to host order for easier handling
276 
277         if (discover == 1)
278         {
279             if (packet_to_check(srcip, ihash_table))  //Pass src to check for dupes if none print output
280             {
281                 if ( logfile != NULL )
282                 {
283 		    if ( disp_time == 0 )
284 		    {
285                     	fprintf(outfile, "%s\n", iprintf(packet + 26));
286 		    }
287 		    else
288 		    {
289 		    	stime = time(NULL);
290 			timestamp = asctime(localtime(&stime));
291 			if ( timestamp[strlen(timestamp)-1]=='\n')
292 				timestamp[strlen(timestamp)-1] = 0;
293 			fprintf(outfile, "%s,%s\n", timestamp, iprintf(packet + 26));
294 		    }
295                 }
296                 if ( print_ip == 1 )
297                 {
298                     if ( pipearg != NULL )
299                         pipe_out(pretext, iprintf(packet + 26), args);
300                     else
301                         printf("%s\n", iprintf(packet + 26));
302 
303                 }
304             }
305         }
306 
307         if ( unique_ip==1 && only_syn == 1) // If fingerprint flag and unique flag is set
308         {
309           if (ip_h->protocol==6)
310           {
311             switch (ip_h->ihl)
312             {
313               case 5:     //IP Header length of 20 - no options
314                 tcp_h = (struct tcphdr *) (packet + (iphlen+14));
315                 break;
316               default:    //Parse through IP options
317                 tcp_h = (struct tcphdr *)(packet+14+(iphlen<<2));
318                 break;
319             }
320 
321             if (tcp_h->syn==1 && tcp_h->ack==0) // Looking for just SYN packets
322             {
323                 synack = 0;
324                 if (packet_to_check(srcip, fhash_table))
325                 {
326                     fingerprint_packet(packet);
327 
328                     if ( found==1 ) //If fingerprint match is found for packet output IP and OS
329                     {
330                         foundip = iprintf(packet + 26);
331                         if ( logfile != NULL )
332                         {
333 			    if ( disp_time == 0 )
334 			    {
335                             	fprintf(outfile, "%s,%s,S\n", foundip, found_os);
336 			    }
337 			    else
338 			    {
339 			    	stime = time(NULL);
340 				timestamp = asctime(localtime(&stime));
341 				if ( timestamp[strlen(timestamp)-1]=='\n')
342 					timestamp[strlen(timestamp)-1] = 0;
343 				if ( verbose == 1)
344 				{
345 					fprintf(outfile, "%s,%s,%s,S,%s\n", timestamp, foundip, found_os, optstr);
346 				}
347 				else
348 				{
349 					fprintf(outfile, "%s,%s,%s,S\n", timestamp, foundip, found_os);
350 				}
351 			    }
352                         }
353                         if ( print_ip == 1 )
354                         {
355                             printf("%s: %s (S)\n", foundip, found_os);
356                         }
357                         strcpy (found_os, "");
358                         totpacket_fp++; //Increment total IP counter
359                     }
360                     if ( found==0 )  //If no fingerprint match is found for packet output IP and fingerprint
361                     {
362                         foundip = iprintf(packet + 26);
363                         if ( logfile != NULL )
364                         {
365 			    if ( disp_time == 0 )
366 			    {
367                             	fprintf(outfile, "%s,%d:%d:%d:%d:%d:%d:%d:%d,S\n",foundip,packet_fp.win, packet_fp.ttl, packet_fp.mss, packet_fp.df, packet_fp.wscale, packet_fp.sackok, packet_fp.nop, packet_fp.psize);
368 			    }
369 			    else
370 			    {
371 			    	stime = time(NULL);
372 				timestamp = asctime(localtime(&stime));
373 				if ( timestamp[strlen(timestamp)-1]=='\n')
374 					timestamp[strlen(timestamp)-1] = 0;
375 				if ( verbose == 1)
376 				{
377 
378                             		fprintf(outfile, "%s,%s,%d:%d:%d:%d:%d:%d:%d:%d,S,%s\n",timestamp, foundip,packet_fp.win, packet_fp.ttl, packet_fp.mss, packet_fp.df, packet_fp.wscale, packet_fp.sackok, packet_fp.nop, packet_fp.psize,optstr);
379 				}
380 				else
381 				{
382                             		fprintf(outfile, "%s,%s,%d:%d:%d:%d:%d:%d:%d:%d,S\n",timestamp, foundip,packet_fp.win, packet_fp.ttl, packet_fp.mss, packet_fp.df, packet_fp.wscale, packet_fp.sackok, packet_fp.nop, packet_fp.psize);
383 				}
384 			    }
385                         }
386                         if ( print_ip == 1 )
387                         {
388                             printf("%s: %d:%d:%d:%d:%d:%d:%d:%d:%s\n",foundip,packet_fp.win, packet_fp.ttl, packet_fp.mss, packet_fp.df, packet_fp.wscale, packet_fp.sackok, packet_fp.nop, packet_fp.psize, packet_fp.packet_type);
389                         }
390                         totpacket_fp++;
391                     }
392 
393                     /* Reset globals for next packet to check */
394 
395                     fp_cand = 0;
396                     found = 0;
397                 }
398             }
399           }
400         }
401         else if ( unique_ip==0 && only_syn == 1) //If fingerprint flag is set and unique flag is not
402         {
403             if (ip_h->protocol==6)
404             {
405                 switch (ip_h->ihl)
406                 {
407                     case 5:     //IP Header length of 20 - no options
408                       tcp_h = (struct tcphdr *) (packet + (iphlen+14));
409                       //tcp_opt = (struct tcphdr *) (packet + iphlen);
410                       break;
411                     default:    //Parse through IP options
412                       tcp_h = (struct tcphdr *)(packet+14+(iphlen<<2));
413                       break;
414                 }
415                 if (tcp_h->syn==1 && tcp_h->ack==0)
416                 {
417                     synack = 0;
418                     fingerprint_packet(packet);
419                     if ( found==1 )
420                     {
421                         foundip = iprintf(packet + 26);
422                         if ( logfile != NULL )
423                         {
424 			    if ( disp_time == 0 )
425 			    {
426                             	fprintf(outfile, "%s,%s,S\n",foundip, found_os);
427 			    }
428 			    else
429 			    {
430 			    	stime = time(NULL);
431 				timestamp = asctime(localtime(&stime));
432 				if ( timestamp[strlen(timestamp)-1]=='\n')
433 					timestamp[strlen(timestamp)-1] = 0;
434 				if ( verbose == 1 )
435 				{
436 				fprintf(outfile, "%s,%s,%s,S,%s\n", timestamp, foundip, found_os,optstr);
437 				}
438 				else
439 				{
440 					fprintf(outfile, "%s,%s,%s,S\n", timestamp, foundip, found_os);
441 				}
442 			    }
443                         }
444                         if ( print_ip == 1 )
445                         {
446                             printf("%s: %s (S)\n", foundip, found_os);
447                         }
448                         strcpy (found_os, "");
449                         totpacket_fp++;
450                     }
451                     if ( found==0 )
452                     {
453                         foundip = iprintf(packet + 26);
454                         if ( logfile != NULL )
455                         {
456 			    if ( disp_time == 0 )
457 			    {
458                            	fprintf(outfile, "%s,%d:%d:%d:%d:%d:%d:%d:%d,S\n",foundip,packet_fp.win, packet_fp.ttl, packet_fp.mss, packet_fp.df, packet_fp.wscale, packet_fp.sackok, packet_fp.nop, packet_fp.psize);
459 			    }
460 			    else
461 			    {
462 			    	stime = time(NULL);
463 			    	timestamp = asctime(localtime(&stime));
464 			    	if ( timestamp[strlen(timestamp)-1]=='\n')
465 					timestamp[strlen(timestamp)-1] = 0;
466 				if ( verbose == 1 )
467 				{
468 fprintf(outfile,"%s,%s,%d:%d:%d:%d:%d:%d:%d:%d,S,%s\n",timestamp,foundip,packet_fp.win,packet_fp.ttl, packet_fp.mss, packet_fp.df, packet_fp.wscale, packet_fp.sackok, packet_fp.nop, packet_fp.psize,optstr);
469 				}
470 				else
471 				{
472                          		fprintf(outfile, "%s,%s,%d:%d:%d:%d:%d:%d:%d:%d,S\n",timestamp,foundip,packet_fp.win, packet_fp.ttl, packet_fp.mss, packet_fp.df, packet_fp.wscale, packet_fp.sackok, packet_fp.nop, packet_fp.psize);
473 				}
474 			    }
475                         }
476                         if ( print_ip == 1 )
477                         {
478                             printf("%s: %d:%d:%d:%d:%d:%d:%d:%d:%s\n",foundip,packet_fp.win, packet_fp.ttl, packet_fp.mss, packet_fp.df, packet_fp.wscale, packet_fp.sackok, packet_fp.nop, packet_fp.psize, packet_fp.packet_type);
479                         }
480                         totpacket_fp++;
481                     }
482 
483                     /* Reset globals for next packet to check */
484 
485                     fp_cand = 0;
486                     found = 0;
487                 }
488             }
489         }
490 
491 	if ( unique_ip==1 && ack==1) // If fingerprint flag and unique flag is set
492         {
493           if (ip_h->protocol==6)
494           {
495             switch (ip_h->ihl)
496             {
497               case 5:     //IP Header length of 20 - no options
498                 tcp_h = (struct tcphdr *) (packet + (iphlen+14));
499                 break;
500               default:    //Parse through IP options
501                 tcp_h = (struct tcphdr *)(packet+14+(iphlen<<2));
502                 break;
503             }
504 
505             if (tcp_h->syn==1 && tcp_h->ack==1) // Looking for SYNACK packets
506             {
507                 synack = 1;
508                 if (packet_to_check(srcip, ahash_table))
509                 {
510                     fingerprint_packet(packet);
511 
512                     if ( found==1 ) //If fingerprint match is found for packet output IP and OS
513                     {
514                         foundip = iprintf(packet + 26);
515                         if ( logfile != NULL )
516                         {
517 			    if ( disp_time == 0 )
518 			    {
519                             	fprintf(outfile, "%s,%s,A\n", foundip, found_os);
520 			    }
521 			    else
522 			    {
523 			    	stime = time(NULL);
524 				timestamp = asctime(localtime(&stime));
525 				if ( timestamp[strlen(timestamp)-1]=='\n')
526 					timestamp[strlen(timestamp)-1] = 0;
527 				if ( verbose == 1)
528 				{
529 				fprintf(outfile, "%s,%s,%s,A,%s\n", timestamp, foundip, found_os,optstr);
530 				}
531 				else
532 				{
533 					fprintf(outfile, "%s,%s,%s,A\n", timestamp, foundip, found_os);
534 				}
535 			    }
536                         }
537                         if ( print_ip == 1 )
538                         {
539                             printf("%s: %s (A)\n", foundip, found_os);
540                         }
541                         strcpy (found_os, "");
542                         totpacket_fp++; //Increment total IP counter
543                     }
544                     if ( found==0 )  //If no fingerprint match is found for packet output IP and fingerprint
545                     {
546                         foundip = iprintf(packet + 26);
547                         if ( logfile != NULL )
548                         {
549 			    if ( disp_time == 0 )
550 			    {
551                             	fprintf(outfile, "%s,%d:%d:%d:%d:%d:%d:%d:%d,A\n",foundip,packet_fp.win, packet_fp.ttl, packet_fp.mss, packet_fp.df, packet_fp.wscale, packet_fp.sackok, packet_fp.nop, packet_fp.psize);
552 			    }
553 			    else
554 			    {
555 			    	stime = time(NULL);
556 				timestamp = asctime(localtime(&stime));
557 				if ( timestamp[strlen(timestamp)-1]=='\n')
558 					timestamp[strlen(timestamp)-1] = 0;
559 				if ( verbose == 1)
560 				{
561                             	fprintf(outfile,"%s,%s,%d:%d:%d:%d:%d:%d:%d:%d,A,%s\n",timestamp, foundip,packet_fp.win, packet_fp.ttl, packet_fp.mss, packet_fp.df, packet_fp.wscale, packet_fp.sackok, packet_fp.nop, packet_fp.psize,optstr);
562 				}
563 				else
564 				{
565                             		fprintf(outfile, "%s,%s,%d:%d:%d:%d:%d:%d:%d:%d,A\n",timestamp, foundip,packet_fp.win, packet_fp.ttl, packet_fp.mss, packet_fp.df, packet_fp.wscale, packet_fp.sackok, packet_fp.nop, packet_fp.psize);
566 				}
567 			    }
568                         }
569                         if ( print_ip == 1 )
570                         {
571                             printf("%s: %d:%d:%d:%d:%d:%d:%d:%d:%s\n",foundip,packet_fp.win, packet_fp.ttl, packet_fp.mss, packet_fp.df, packet_fp.wscale, packet_fp.sackok, packet_fp.nop, packet_fp.psize, packet_fp.packet_type);
572                         }
573                         totpacket_fp++;
574                     }
575 
576                     /* Reset globals for next packet to check */
577 
578                     fp_cand = 0;
579                     found = 0;
580                 }
581             }
582           }
583         }
584         else if ( unique_ip==0 && ack==1) //If fingerprint flag is set and unique flag is not
585         {
586             if (ip_h->protocol==6)
587             {
588                 switch (ip_h->ihl)
589                 {
590                     case 5:     //IP Header length of 20 - no options
591                       tcp_h = (struct tcphdr *) (packet + (iphlen+14));
592                       //tcp_opt = (struct tcphdr *) (packet + iphlen);
593                       break;
594                     default:    //Parse through IP options
595                       tcp_h = (struct tcphdr *)(packet+14+(iphlen<<2));
596                       break;
597                 }
598                 if (tcp_h->syn==1 && tcp_h->ack==1)
599                 {
600                     synack = 1;
601                     fingerprint_packet(packet);
602                     if ( found==1 )
603                     {
604                         foundip = iprintf(packet + 26);
605                         if ( logfile != NULL )
606                         {
607 			    if ( disp_time == 0 )
608 			    {
609                             	fprintf(outfile, "%s,%s,A\n",foundip, found_os);
610 			    }
611 			    else
612 			    {
613 			    	stime = time(NULL);
614 				timestamp = asctime(localtime(&stime));
615 				if ( timestamp[strlen(timestamp)-1]=='\n')
616 					timestamp[strlen(timestamp)-1] = 0;
617 				if ( verbose == 1 )
618 				{
619 					fprintf(outfile, "%s,%s,%s,A,%s\n", timestamp, foundip, found_os,optstr);
620 				}
621 				else
622 				{
623 					fprintf(outfile, "%s,%s,%s,A\n", timestamp, foundip, found_os);
624 				}
625 			    }
626                         }
627                         if ( print_ip == 1 )
628                         {
629                             printf("%s: %s (A)\n", foundip, found_os);
630                         }
631                         strcpy (found_os, "");
632                         totpacket_fp++;
633                     }
634                     if ( found==0 )
635                     {
636                         foundip = iprintf(packet + 26);
637                         if ( logfile != NULL )
638                         {
639 			    if ( disp_time == 0 )
640 			    {
641                            	fprintf(outfile, "%s,%d:%d:%d:%d:%d:%d:%d:%d,A\n",foundip,packet_fp.win, packet_fp.ttl, packet_fp.mss, packet_fp.df, packet_fp.wscale, packet_fp.sackok, packet_fp.nop, packet_fp.psize);
642 			    }
643 			    else
644 			    {
645 			    	stime = time(NULL);
646 			    	timestamp = asctime(localtime(&stime));
647 			    	if ( timestamp[strlen(timestamp)-1]=='\n')
648 					timestamp[strlen(timestamp)-1] = 0;
649 				if ( verbose == 1 )
650 				{
651 fprintf(outfile,"%s,%s,%d:%d:%d:%d:%d:%d:%d:%d,A,%s\n",timestamp,foundip,packet_fp.win, packet_fp.ttl, packet_fp.mss, packet_fp.df, packet_fp.wscale, packet_fp.sackok, packet_fp.nop, packet_fp.psize,optstr);
652 				}
653 				else
654 				{
655                          		fprintf(outfile, "%s,%s,%d:%d:%d:%d:%d:%d:%d:%d,A\n",timestamp,foundip,packet_fp.win, packet_fp.ttl, packet_fp.mss, packet_fp.df, packet_fp.wscale, packet_fp.sackok, packet_fp.nop, packet_fp.psize);
656 				}
657 			    }
658                         }
659                         if ( print_ip == 1 )
660                         {
661                             printf("%s: %d:%d:%d:%d:%d:%d:%d:%d:%s\n",foundip,packet_fp.win, packet_fp.ttl, packet_fp.mss, packet_fp.df, packet_fp.wscale, packet_fp.sackok, packet_fp.nop, packet_fp.psize, packet_fp.packet_type);
662                         }
663                         totpacket_fp++;
664                     }
665 
666                     /* Reset globals for next packet to check */
667 
668                     fp_cand = 0;
669                     found = 0;
670                 }
671             }
672         }
673 
674 
675 
676     }
677 
678     /* crtl-c exit */
679 
680     if (pcap_stats(p, &ps) == -1)
681     {
682         fprintf(stderr, "pcap_stats() failed: %s\n", pcap_geterr(p));
683     }
684     else
685     {
686         /* If user exits display some packet statistics */
687 
688         printf("\nPackets received by Disco:\t%6d\n"
689                  "Packets dropped by Disco:\t%6d\n"
690                  "Unique IP addresses received by Disco:\t%6ld\n",
691                  ps.ps_recv, ps.ps_drop, ip);
692         printf("Total IP fingerprinted by Disco: \t%6d\n", totpacket_fp);
693     }
694     pcap_close(p);
695     return (EXIT_SUCCESS);
696 }
697 
698 
699 /* Routine to print hex ip in decimal */
700 
iprintf(u_char * address)701 char * iprintf(u_char *address)
702 {
703     static char ip_addr[17];
704 
705     sprintf(ip_addr, "%3d.%3d.%3d.%3d", (address[0]&255), (address[1]&255), (address[2]&255), (address[3]&255));
706     return (ip_addr);
707 }
708 
709 /* Check packet source ip for uniqueness */
710 
packet_to_check(uint32_t src_ip,struct table_entry ** hash_table)711 int packet_to_check(uint32_t src_ip, struct table_entry **hash_table)
712 {
713     uint32_t n;
714 
715     n = packet_hash(src_ip);  //Function to hash src ip from packet
716 
717     allip++;  //Increment packet statistic counter
718 
719     if (hash_table[n]) //If entry exists in hash table
720     {
721         if (!packet_dup_check(src_ip, hash_table, n)) //Check hash table for src ip
722         {
723             if (packet_add_entry(src_ip, hash_table, n)) //If no dupes are found add src ip to hash table
724             {
725                 ip++;
726                 return(1);
727             }
728         }
729         else  // If src ip dupe is found exit
730         {
731             return(0);
732         }
733     }
734     else
735     {
736         if (packet_add_entry(src_ip, hash_table, n))
737         {
738             ip++;
739             return(1);
740         }
741     }
742     return (0);
743 }
744 
745 /* Hash source ip into unique number */
746 
packet_hash(uint32_t src_ip)747 uint32_t packet_hash(uint32_t src_ip)
748 {
749     return (src_ip %= HASH_TABLE_SIZE); //Return remainder (Modulus) from src ip divided by hash table size
750 }
751 
752 /* Check source ip for dups in the hash table */
753 
packet_dup_check(uint32_t src_ip,struct table_entry ** hash_table,uint32_t loc)754 int packet_dup_check(uint32_t src_ip, struct table_entry **hash_table, uint32_t loc)
755 {
756     struct table_entry *p;
757 
758     for (p = hash_table[loc]; p; p = p->next)
759     {
760         if (p->uip == src_ip)
761         {
762             return (1);
763         }
764     }
765     return (0);
766 }
767 
768 /* If packet isn't a dup add to hash table */
769 
packet_add_entry(uint32_t src_ip,struct table_entry ** hash_table,uint32_t loc)770 int packet_add_entry(uint32_t src_ip, struct table_entry **hash_table, uint32_t loc) //Add src ip to hash table
771 {
772     struct table_entry *p;
773 
774     if (hash_table[loc] == NULL)
775     {
776         hash_table[loc] = malloc(sizeof(struct table_entry));
777         if (hash_table[loc] == NULL)
778         {
779             return(0);
780         }
781         hash_table[loc]->uip = src_ip;
782         hash_table[loc]->next = NULL;
783         return (1);
784     }
785     else
786     {
787         for (p = hash_table[loc]; p->next; p = p->next);
788         p->next = malloc(sizeof(struct table_entry));
789         if (p->next == NULL)
790         {
791             return (0);
792         }
793 
794         p = p->next;
795 
796         p->uip = src_ip;
797         p->next = NULL;
798     }
799     return (1);
800 }
801 
802 /* Routine to fingerprint the SYN packet */
803 
fingerprint_packet(u_char * packet)804 char fingerprint_packet(u_char *packet)
805 {
806     int i=0,j=0;
807     int testi=0;
808     char teststr[6];
809     int count=0;
810     int opt=0;
811     int fullopt=0;
812     int iphlen=0;
813     int optlen=0;
814     int packettype_cmp;
815     int ttlcount;
816     int wscale_exists = 0;
817 //    char optstrg;
818     struct iphdr *ip_h;
819     struct tcphdr *tcp_h;
820     struct ethhdr *ether;
821 
822     void* opt_ptr;
823 
824     char src_ip[20], dest_ip[20];
825 
826     ip_h = (struct iphdr *) (packet + 14);
827 
828 
829     iphlen = ((ip_h->ihl*4));
830 
831        switch (ip_h->ihl)
832         {
833             case 5:     //IP Header length of 20 - no options
834               tcp_h = (struct tcphdr *) (packet + (iphlen+14));
835               break;
836             default:    //Parse through IP options
837               tcp_h = (struct tcphdr *)(packet+14+(iphlen<<2));
838               break;
839         }
840                 fp_cand = 1;
841                 packet_fp.win = ntohs(tcp_h->window);
842                 packet_fp.ttl = ip_h->ttl;
843                 packet_fp.sackok = 0;
844                 packet_fp.nop = 0;
845                 packet_fp.psize = ntohs(ip_h->tot_len);
846                 if (ip_h->frag_off==64)
847                 {
848                   packet_fp.df = 1;
849                 }
850                 else
851                 {
852                   packet_fp.df = 0;
853                 }
854 		if ( synack == 0 )
855 		{
856 //		  packet_fp.packet_type = (char) malloc(strlen (SYNCHAR)+1);
857 		  strcpy (packet_fp.packet_type, SYNCHAR);
858 		}
859 		if ( synack == 1 )
860 		{
861 //		  packet_fp.packet_type = (char) malloc(strlen (SYNACKCHAR)+1);
862 		  strcpy (packet_fp.packet_type, SYNACKCHAR);
863 		}
864                 opt_ptr=(void*)tcp_h+sizeof(struct tcphdr);
865                 optlen = (ntohs(ip_h->tot_len))-(sizeof(struct iphdr))-(sizeof(struct tcphdr));
866 		if ( verbose == 1 )
867 		{
868 			strcpy(teststr, "       ");
869 			testi = sprintf(teststr, "%d", packet_fp.win);
870 			strcpy(optstr, "WIN-");
871 			strcat(optstr, teststr);
872 			strcat(optstr, "|");
873 			testi = sprintf(teststr, "%d", packet_fp.df);
874 			strcat(optstr, "DF-");
875 			strcat(optstr, teststr);
876 			strcat(optstr, "|");
877 		}
878                 while ( i < optlen )
879                 {
880                   opt=(int)(*(u_char*)(opt_ptr+i));
881                   switch(opt)
882                   {
883                     case TCPOPT_MAXSEG:
884                     {
885                       packet_fp.mss = EXTRACT_16BITS(opt_ptr+2);
886                       i+=3;
887 		      if ( verbose == 1 )
888 		      {
889 		      	testi = sprintf(teststr, "%d", packet_fp.mss);
890 		      	strcat(optstr, "MSS-");
891 		      	strcat(optstr, teststr);
892 		      	strcat(optstr, "|");
893 		      }
894                       break;
895                     }
896                     case TCPOPT_SACKOK:
897                     {
898                       packet_fp.sackok = 1;
899                       i+=1;
900 		      if ( verbose == 1 )
901 		      {
902 		      	strcat(optstr, "SACKOK");
903 		      	strcat(optstr, "|");
904 		      }
905                       break;
906                     }
907                     case TCPOPT_NOP:
908                     {
909                       packet_fp.nop = 1;
910 		      if ( verbose == 1)
911 		      {
912 		      	strcat(optstr, "NOP");
913 		      	strcat(optstr, "|");
914 		      }
915                       break;
916                     }
917                     case TCPOPT_WSCALE:
918                     {
919                       packet_fp.wscale = (u_short)*((u_char *)(opt_ptr+i+2));
920                       i+=2;
921 		      if ( verbose == 1)
922 		      {
923 		      	testi = sprintf(teststr, "%d", packet_fp.wscale);
924 		      	strcat(optstr, "WS-");
925 		      	strcat(optstr, teststr);
926 		      	strcat(optstr, "|");
927 		      }
928                       wscale_exists = 1;
929                       break;
930                     }
931                 }
932                 i++;
933                 }
934                 if ( wscale_exists==0 )
935                 {
936                   packet_fp.wscale = -1;
937                 }
938 		if ( verbose == 1)
939 		{
940 			testi = sprintf(teststr, "%d", packet_fp.psize);
941 			strcat(optstr, "PS-");
942 			strcat(optstr, teststr);
943 			strcat(optstr, "|");
944 		}
945                 while ( count < totfp  && found==0 )
946                 {
947 //		  packettype_cmp = strcmp(loadedfp[count].packet_type, packet_fp.packet_type);
948                   if (loadedfp[count].win == packet_fp.win &&
949                       loadedfp[count].mss == packet_fp.mss &&
950                       loadedfp[count].df == packet_fp.df &&
951                       loadedfp[count].wscale == packet_fp.wscale &&
952                       loadedfp[count].sackok == packet_fp.sackok &&
953                       loadedfp[count].nop == packet_fp.nop &&
954                       loadedfp[count].psize == packet_fp.psize &&
955 		      (strcmp(loadedfp[count].packet_type, packet_fp.packet_type)) == 0)
956                   {
957                       for ( ttlcount=0;ttlcount<64;ttlcount++ )
958                       {
959                           if (loadedfp[count].ttl == ((packet_fp.ttl)+ttlcount))
960                           {
961                               strcpy (found_os, loadedfp[count].os);
962                               found = 1;
963                               count = totfp;
964                           }
965                           if ( found==1 )
966                           {
967                               break
968                               ;
969                           }
970                       }
971                   }
972                   count++;
973                 }
974 		if ( verbose == 1 )
975 		{
976 			testi = sprintf(teststr, "%d", packet_fp.ttl);
977 			strcat(optstr, "TTL-");
978 			strcat(optstr, teststr);
979 		}
980                 count=0;
981                 if ( tcp_h->ack == 1 )
982                 {
983                   synack=1;
984                 }
985 }
986 
cleanup(int signo)987 void cleanup(int signo)
988 {
989     loop = 0;
990     printf("Interrupt signal caught...\n");
991 }
992 
ht_init_table(struct table_entry ** hash_table)993 void ht_init_table(struct table_entry **hash_table)
994 {
995     int c;
996 
997     for (c = 0; c < HASH_TABLE_SIZE; c++)
998     {
999         hash_table[c] = NULL;
1000     }
1001 }
1002 
catch_sig(int signo,void (* handler)())1003 int catch_sig(int signo, void (*handler)())
1004 {
1005     struct sigaction action;
1006 
1007     action.sa_handler = handler;
1008     sigemptyset(&action.sa_mask);
1009     action.sa_flags = 0;
1010 
1011     if (sigaction(signo, &action, NULL) == -1)
1012     {
1013         return (-1);
1014     }
1015     else
1016     {
1017         return (1);
1018     }
1019 }
1020 
load_fingerprints()1021 int load_fingerprints()
1022 {
1023     char *fp;
1024     char *line;
1025     char infile[200];
1026     FILE *fp_file;
1027 	int len=0;
1028 
1029     fp_file=fopen("disco.fp", "r");
1030 
1031     if (!fp_file)
1032     {
1033         fprintf(stderr, "No fingerprint file found\n");
1034         return -1;
1035     }
1036 
1037     while (fgets(infile, 1500, fp_file) != NULL && infile[0] != '\n')
1038     {
1039         line = strtok ( infile, "\n");
1040 
1041         fp = strtok ( line, ":");
1042         loadedfp[totfp].win = atoi(fp);
1043         fp = strtok ( NULL, ":");
1044         loadedfp[totfp].ttl = atoi(fp);
1045         fp = strtok ( NULL, ":");
1046         loadedfp[totfp].mss = atoi(fp);
1047         fp = strtok ( NULL, ":");
1048         loadedfp[totfp].df = atoi(fp);
1049         fp = strtok ( NULL, ":");
1050         loadedfp[totfp].wscale = atoi(fp);
1051         fp = strtok ( NULL, ":");
1052         loadedfp[totfp].sackok = atoi(fp);
1053         fp = strtok ( NULL, ":");
1054         loadedfp[totfp].nop = atoi(fp);
1055         fp = strtok ( NULL, ":");
1056         loadedfp[totfp].psize = atoi(fp);
1057         fp = strtok ( NULL, ":");
1058 //	loadedfp[totfp].packet_type = (char) malloc(strlen (fp)+1);
1059 	strcpy (loadedfp[totfp].packet_type, fp);
1060 	fp = strtok ( NULL, ":");
1061         loadedfp[totfp].os =  (char *) malloc(strlen (fp)+1);
1062         strcpy (loadedfp[totfp].os, fp);
1063         totfp++;
1064     }
1065     fclose(fp_file);
1066     return(totfp);
1067 }
1068 
usage(char * errmsg)1069 void usage(char *errmsg)
1070 {
1071     fprintf(stderr,"Disco 1.2: %s\n", errmsg);
1072     fprintf(stderr,"\nUsage: disco  [options below]\n");
1073     fprintf(stderr," -i device	capture packets from device\n");
1074     fprintf(stderr," -N 		Do not print IP info to STDOUT\n");
1075     fprintf(stderr," -f 		fingerprint SYN / SYNACK packets\n");
1076     fprintf(stderr," -D 		discover all IPs\n");
1077     fprintf(stderr," -S 	        only watch for SYN packets\n");
1078     fprintf(stderr," -A 		watch for SYNACK packets\n");
1079     fprintf(stderr," -s filename	use tcpdump file for parsing\n");
1080     fprintf(stderr," -o filename	write output to file\n");
1081     fprintf(stderr," -r filter	tcpdump filter rules\n");
1082     fprintf(stderr," -u 	        unique ip only applies to fingerprint option\n");
1083     fprintf(stderr," -h 	        help - display options\n");
1084     fprintf(stderr," -g 		output to gherkin database - not implemented yet\n");
1085     fprintf(stderr," -p pipeargs	pipe output to program (see README.pipe)\n");
1086     fprintf(stderr," -P string	string to print before output when using -p (see README.pipe)\n");
1087     fprintf(stderr," -t 		timestamp IP and/or fingerprint in output file (-o)\n");
1088     fprintf(stderr," -v 		verbose mode - more detail when used with output file\n");
1089     fprintf(stderr," -e 		Ethernet Mode (certain devices with no IP assigned)\n");
1090 
1091     exit(1);
1092 }
1093 
1094 /** parse()
1095  *
1096  * See disco.h
1097  */
1098 
parse(char * buf,char ** args)1099 int parse(char *buf, char **args)
1100 {
1101     while (*buf != NULL)
1102     {
1103         // Convert whitespace to nulls, so that the previous argument is
1104         // terminated automatically
1105         while ((*buf == ' ') || (*buf == '\t'))
1106             *buf++ = '\0';
1107 
1108         // Save the argument
1109         *args++ = buf;
1110 
1111         // Skip over the argument
1112         while ((*buf != NULL) && (*buf != ' ') && (*buf != '\t'))
1113             buf++;
1114 
1115     } // while (processing string)
1116 
1117     *args = NULL;
1118     return 1;
1119 
1120 } // parse()
1121 
1122 
1123 /** pipe_out()
1124  *
1125  * See disco.h
1126  */
1127 
pipe_out(char * pre,char * str,char ** args)1128 int pipe_out(char *pre, char *str, char **args)
1129 {
1130     int pid;        // PID of the child
1131     int status;     // Status of the child, for wait()
1132     int pipe_fd[2]; // File descriptor of pipe
1133 
1134 
1135     // Create the pipe or return failure
1136     if (pipe(pipe_fd) == -1)
1137     {
1138         perror("pipe_out");
1139         return 0;
1140 
1141     } // if (pipe() failed)
1142 
1143     // Fork off the child or return failure
1144     if ((pid = fork()) == -1)
1145     {
1146         perror("pipe_out");
1147         return 0;
1148 
1149     } // if (fork() failed)
1150 
1151     // Child
1152     if (pid == 0)
1153     {
1154         // Close stdin
1155         close( 0 );
1156 
1157         // Bind the read end of the pipe to stdin
1158         dup(pipe_fd[0]);
1159 
1160         // Close the read from and write to ends of the pipe
1161         close(pipe_fd[0]);
1162         close(pipe_fd[1]);
1163 
1164         // Fire up the reporter program
1165         execvp(*args, args);
1166 
1167         // execvp() should not return, so if it did, we have an error
1168         perror( "pipe_out" );
1169         return 0;
1170 
1171     } // if (child)
1172 
1173     // Parent
1174     else
1175     {
1176         int i;   // Counter
1177 
1178         // Close the read end of the pipe
1179         close(pipe_fd[0]);
1180 
1181         // If there is a pretext, write it
1182         if (pre != NULL)
1183         {
1184             for (i = 0; i < MAX_STR_LEN; i++)
1185                 if (pre[i] == '\0')
1186                     break;
1187 
1188             write(pipe_fd[1], pre, i);
1189 
1190         } // if (writing pretext)
1191 
1192         // Give the output to the child
1193         for (i = 0; i < MAX_STR_LEN; i++)
1194             if (str[i] == '\0')
1195                 break;
1196 
1197         write(pipe_fd[1], str, i);
1198         write(pipe_fd[1], "\n", 1);
1199 
1200         // Tear down the pipe (sends SIGPIPE to prog, which should make it
1201         // realise that it has encountered EOF)
1202         close(pipe_fd[1]);
1203 
1204         // Wait for the child to terminate
1205         while(wait( &status ) != pid);
1206 
1207     } // else (parent)
1208 
1209     // Success!
1210     return 1;
1211 
1212 } // pipe_out()
1213