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