"Fossies" - the Fresh Open Source Software Archive 
Member "ngrep-1_47/ngrep.c" (7 Sep 2017, 41892 Bytes) of package /linux/misc/ngrep-1_47.tar.gz:
1 /*
2 * Copyright (c) 2017 Jordan Ritter <jpr5@darkridge.com>
3 *
4 * Please refer to the LICENSE file for more information.
5 *
6 */
7
8 #if defined(BSD) || defined(SOLARIS) || defined(MACOSX)
9 #include <unistd.h>
10 #include <ctype.h>
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <netinet/in.h>
14 #include <netinet/in_systm.h>
15 #include <net/if.h>
16 #include <arpa/inet.h>
17 #include <sys/tty.h>
18 #include <pwd.h>
19 #endif
20
21 #if defined(OSF1)
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <netinet/in_systm.h>
26 #include <net/route.h>
27 #include <sys/mbuf.h>
28 #include <arpa/inet.h>
29 #include <unistd>
30 #include <pwd.h>
31 #endif
32
33 #if defined(LINUX) || defined(__GLIBC__) || defined(__GNU__)
34 #include <getopt.h>
35 #include <arpa/inet.h>
36 #include <ctype.h>
37 #include <time.h>
38 #include <unistd.h>
39 #include <pwd.h>
40 #include <grp.h>
41 #endif
42
43 #if defined(AIX)
44 #include <sys/machine.h>
45 #include <sys/types.h>
46 #include <netinet/in.h>
47 #include <time.h>
48 #include <unistd.h>
49 #include <pwd.h>
50 #endif
51
52 #if defined(_WIN32)
53 #include <io.h>
54 #include <getopt.h>
55 #include <winsock2.h>
56 #include <ws2tcpip.h>
57 #include <types.h>
58 #include <config.h>
59
60 #define strcasecmp stricmp
61 #define strncasecmp strnicmp
62
63 #else
64
65 #include <netinet/ip.h>
66 #include <netinet/tcp.h>
67 #include <netinet/udp.h>
68 #include <netinet/ip_icmp.h>
69 #include <netinet/igmp.h>
70
71 #endif
72
73 #include <stdlib.h>
74 #include <string.h>
75 #include <signal.h>
76 #include <locale.h>
77
78 #if !defined(_WIN32)
79 #include <errno.h>
80 #include <sys/ioctl.h>
81 #endif
82
83 #include <pcap.h>
84
85 #ifdef HAVE_CONFIG_H
86 #include "config.h"
87 #endif
88
89 #if USE_IPv6 && !defined(_WIN32)
90 #include <netinet/ip6.h>
91 #include <netinet/icmp6.h>
92 #endif
93
94 #if USE_PCRE
95 #include <pcre.h>
96 #else
97 #include <regex.h>
98 #endif
99
100 #include "ngrep.h"
101
102
103 /*
104 * Configuration Options
105 */
106
107 uint32_t snaplen = 65535, limitlen = 65535, promisc = 1, to = 100;
108 uint32_t match_after = 0, keep_matching = 0, matches = 0, max_matches = 0;
109 uint32_t seen_frames = 0;
110
111 #if USE_TCPKILL
112 uint32_t tcpkill_active = 0;
113 #endif
114
115 uint8_t re_match_word = 0, re_ignore_case = 0, re_multiline_match = 1;
116 uint8_t show_empty = 0, show_hex = 0, show_proto = 0, quiet = 0;
117 uint8_t invert_match = 0, bin_match = 0;
118 uint8_t live_read = 1, want_delay = 0;
119 uint8_t dont_dropprivs = 0;
120 uint8_t enable_hilite = 0;
121
122 char *read_file = NULL, *dump_file = NULL;
123 char *usedev = NULL;
124
125 char nonprint_char = '.';
126
127 /*
128 * GNU Regex/PCRE
129 */
130
131 #if USE_PCRE
132 int32_t err_offset;
133 char *re_err = NULL;
134
135 pcre *pattern = NULL;
136 pcre_extra *pattern_extra = NULL;
137 #else
138 const char *re_err = NULL;
139
140 struct re_pattern_buffer pattern;
141 #endif
142
143 /*
144 * Matching
145 */
146
147 char *match_data = NULL, *bin_data = NULL;
148 uint16_t match_len = 0;
149 int8_t (*match_func)() = &blank_match_func;
150
151 int8_t dump_single = 0;
152 void (*dump_func)(unsigned char *, uint32_t, uint16_t, uint16_t) = &dump_formatted;
153
154 /*
155 * BPF/Network
156 */
157
158 char *filter = NULL, *filter_file = NULL;
159 char pc_err[PCAP_ERRBUF_SIZE];
160 uint8_t link_offset;
161 uint8_t radiotap_present = 0;
162 uint8_t include_vlan = USE_VLAN_HACK;
163
164 pcap_t *pd = NULL, *pd_dumppcap = NULL;
165 pcap_dumper_t *pd_dump = NULL;
166 struct bpf_program pcapfilter;
167 struct in_addr net, mask;
168
169 /*
170 * Timestamp/delay functionality
171 */
172
173 struct timeval prev_ts = {0, 0}, prev_delay_ts = {0,0};
174 #if defined(_WIN32)
175 struct timeval delay_tv;
176 FD_SET delay_fds;
177 SOCKET delay_socket = 0;
178 #endif
179
180 void (*print_time)() = NULL, (*dump_delay)() = dump_delay_proc_init;
181
182
183 /*
184 * Window-size functionality (adjust output based on width of console display)
185 */
186
187 uint32_t ws_row, ws_col = 80, ws_col_forced = 0;
188
189
190 int main(int argc, char **argv) {
191 int32_t c;
192
193 signal(SIGINT, clean_exit);
194 signal(SIGABRT, clean_exit);
195
196 #if !defined(_WIN32)
197 signal(SIGQUIT, clean_exit);
198 signal(SIGPIPE, clean_exit);
199 signal(SIGWINCH, update_windowsize);
200 #endif
201
202 setlocale(LC_ALL, "");
203
204 #if !defined(_WIN32)
205 {
206 char const *locale = getenv("LANG");
207 if (locale == NULL)
208 locale = "en_US";
209
210 setlocale(LC_CTYPE, locale);
211 }
212 #endif
213
214 while ((c = getopt(argc, argv, "LNhXViwqpevxlDtTRMK:Cs:n:c:d:A:I:O:S:P:F:W:")) != EOF) {
215 switch (c) {
216 case 'W': {
217 if (!strcasecmp(optarg, "normal"))
218 dump_func = &dump_formatted;
219 else if (!strcasecmp(optarg, "byline"))
220 dump_func = &dump_byline;
221 else if (!strcasecmp(optarg, "none"))
222 dump_func = &dump_unwrapped;
223 else if (!strcasecmp(optarg, "single")) {
224 dump_func = &dump_unwrapped;
225 dump_single = 1;
226 } else {
227 printf("fatal: unknown wrap method '%s'\n", optarg);
228 usage();
229 }
230 } break;
231
232 case 'F':
233 filter_file = optarg;
234 break;
235 case 'P':
236 nonprint_char = *optarg;
237 break;
238 case 'S': {
239 limitlen = _atoui32(optarg);
240 break;
241 }
242 case 'O':
243 dump_file = optarg;
244 break;
245 case 'I':
246 read_file = optarg;
247 break;
248 case 'A':
249 match_after = _atoui32(optarg);
250 if (match_after < UINT32_MAX)
251 match_after++;
252 break;
253 #if defined(_WIN32)
254 case 'L':
255 win32_listdevices();
256 clean_exit(2);
257 case 'd':
258 usedev = win32_usedevice(optarg);
259 break;
260 #else
261 case 'L':
262 perror("-L is a Win32-only option");
263 clean_exit(2);
264 case 'd':
265 usedev = optarg;
266 /* Linux: any = DLT_LINUX_SLL, pcap says incompatible with VLAN */
267 if (!strncasecmp(usedev, "any", 3))
268 include_vlan = 0;
269 break;
270 #endif
271 case 'c':
272 ws_col_forced = atoi(optarg);
273 break;
274 case 'n':
275 max_matches = _atoui32(optarg);
276 break;
277 case 's': {
278 uint16_t value = _atoui32(optarg);
279 if (value > 0)
280 snaplen = value;
281 } break;
282 case 'C':
283 enable_hilite = 1;
284 break;
285 case 'M':
286 re_multiline_match = 0;
287 break;
288 case 'R':
289 dont_dropprivs = 1;
290 break;
291 case 'T':
292 if (print_time == &print_time_diff) {
293 print_time = print_time_offset;
294 memset(&prev_ts, 0, sizeof(prev_ts));
295 } else {
296 print_time = &print_time_diff;
297 #if defined(_WIN32)
298 prev_ts.tv_sec = (uint32_t)time(NULL);
299 prev_ts.tv_usec = 0;
300 #else
301 gettimeofday(&prev_ts, NULL);
302 #endif
303 }
304 break;
305 case 't':
306 print_time = &print_time_absolute;
307 break;
308 case 'D':
309 want_delay = 1;
310 break;
311 case 'l':
312 setvbuf(stdout, NULL, _IOLBF, 0);
313 break;
314 case 'x':
315 show_hex++;
316 break;
317 case 'v':
318 invert_match++;
319 break;
320 case 'e':
321 show_empty++;
322 break;
323 case 'p':
324 promisc = 0;
325 break;
326 case 'q':
327 quiet++;
328 break;
329 case 'w':
330 re_match_word++;
331 break;
332 case 'i':
333 re_ignore_case++;
334 break;
335 case 'V':
336 version();
337 case 'X':
338 bin_match++;
339 break;
340 case 'N':
341 show_proto++;
342 break;
343 #if USE_TCPKILL
344 case 'K':
345 tcpkill_active = _atoui32(optarg);
346 break;
347 #endif
348 case 'h':
349 usage();
350 default:
351 usage();
352 }
353 }
354
355 if (show_hex && dump_func != &dump_formatted) {
356 printf("fatal: -x (hex dump) is incompatible with -W (alternate format)\n");
357 usage();
358 }
359
360 if (argv[optind])
361 match_data = argv[optind++];
362
363 #if USE_TCPKILL
364 if (tcpkill_active)
365 tcpkill_init();
366 #endif
367
368 /* Setup PCAP input */
369
370 if (setup_pcap_source())
371 clean_exit(2);
372
373 /* Setup BPF filter */
374
375 if (setup_bpf_filter(argv)) {
376 include_vlan = 0;
377 if (filter) { free(filter); filter = NULL; }
378
379 if (setup_bpf_filter(argv)) {
380 pcap_perror(pd, "pcap");
381 clean_exit(2);
382 }
383 }
384
385 if (filter) {
386 if (quiet < 2)
387 printf("filter: %s\n", filter);
388 free(filter);
389 }
390
391 /* Setup matcher */
392
393 if (match_data) {
394 if (setup_matcher())
395 clean_exit(2);
396
397 if (quiet < 2 && strlen(match_data))
398 printf("%smatch: %s%s\n", invert_match?"don't ":"",
399 (bin_data && !strchr(match_data, 'x'))?"0x":"", match_data);
400
401 if (re_match_word) free(match_data);
402 }
403
404 /* Misc */
405
406 if (dump_file) {
407 pd_dump = pcap_dump_open(pd, dump_file);
408 if (!pd_dump) {
409 fprintf(stderr, "fatal: %s\n", pcap_geterr(pd));
410 clean_exit(2);
411 } else printf("output: %s\n", dump_file);
412 }
413
414 update_windowsize(0);
415
416 #if defined(_WIN32)
417 win32_initwinsock();
418 #endif
419
420 #if !defined(_WIN32) && USE_DROPPRIVS
421 drop_privs();
422 #endif
423
424 while (pcap_loop(pd, -1, (pcap_handler)process, 0));
425
426 clean_exit(0);
427
428 /* NOT REACHED */
429 return 0;
430 }
431
432 int setup_pcap_source(void) {
433 if (read_file) {
434
435 if (!(pd = pcap_open_offline(read_file, pc_err))) {
436 perror(pc_err);
437 return 1;
438 }
439
440 live_read = 0;
441 printf("input: %s\n", read_file);
442
443 } else {
444
445 char *dev = usedev ? usedev :
446 #if defined(_WIN32)
447 win32_choosedevice();
448 #else
449 pcap_lookupdev(pc_err);
450 #endif
451
452 if (!dev) {
453 perror(pc_err);
454 return 1;
455 }
456
457 if ((pd = pcap_open_live(dev, snaplen, promisc, to, pc_err)) == NULL) {
458 perror(pc_err);
459 return 1;
460 }
461
462 if (pcap_lookupnet(dev, &net.s_addr, &mask.s_addr, pc_err) == -1) {
463 perror(pc_err);
464 memset(&net, 0, sizeof(net));
465 memset(&mask, 0, sizeof(mask));
466 }
467
468 if (quiet < 2) {
469 printf("interface: %s", dev);
470 if (net.s_addr && mask.s_addr) {
471 printf(" (%s/", inet_ntoa(net));
472 printf("%s)", inet_ntoa(mask));
473 }
474 printf("\n");
475 }
476 }
477
478 switch(pcap_datalink(pd)) {
479 case DLT_EN10MB:
480 link_offset = ETHHDR_SIZE;
481 break;
482
483 case DLT_IEEE802:
484 link_offset = TOKENRING_SIZE;
485 break;
486
487 case DLT_FDDI:
488 link_offset = FDDIHDR_SIZE;
489 break;
490
491 case DLT_SLIP:
492 link_offset = SLIPHDR_SIZE;
493 break;
494
495 case DLT_PPP:
496 link_offset = PPPHDR_SIZE;
497 break;
498
499 #if HAVE_DLT_LOOP
500 case DLT_LOOP:
501 #endif
502 case DLT_NULL:
503 link_offset = LOOPHDR_SIZE;
504 break;
505
506 #if HAVE_DLT_RAW
507 case DLT_RAW:
508 link_offset = RAWHDR_SIZE;
509 break;
510 #endif
511
512 #if HAVE_DLT_LINUX_SLL
513 case DLT_LINUX_SLL:
514 link_offset = ISDNHDR_SIZE;
515 include_vlan = 0;
516 break;
517 #endif
518
519 #if HAVE_DLT_IEEE802_11_RADIO
520 case DLT_IEEE802_11_RADIO:
521 radiotap_present = 1;
522 #endif
523
524 #if HAVE_DLT_IEEE802_11
525 case DLT_IEEE802_11:
526 link_offset = IEEE80211HDR_SIZE;
527 break;
528 #endif
529
530 #if HAVE_DLT_PFLOG
531 case DLT_PFLOG:
532 link_offset = PFLOGHDR_SIZE;
533 break;
534 #endif
535
536 #if HAVE_DLT_IPNET
537 case DLT_IPNET:
538 link_offset = IPNETHDR_SIZE;
539 include_vlan = 0;
540 break;
541 #endif
542
543 default:
544 fprintf(stderr, "fatal: unsupported interface type %u\n", pcap_datalink(pd));
545 return 1;
546 }
547
548 return 0;
549 }
550
551 int setup_bpf_filter(char **argv) {
552 if (filter_file) {
553 char buf[1024] = {0};
554 FILE *f = fopen(filter_file, "r");
555
556 if (!f || !fgets(buf, sizeof(buf)-1, f)) {
557 fprintf(stderr, "fatal: unable to get filter from %s: %s\n", filter_file, strerror(errno));
558 usage();
559 }
560
561 fclose(f);
562
563 filter = get_filter_from_string(buf);
564
565 if (pcap_compile(pd, &pcapfilter, filter, 0, mask.s_addr))
566 return 1;
567
568 } else if (argv[optind]) {
569 filter = get_filter_from_argv(&argv[optind]);
570
571 if (pcap_compile(pd, &pcapfilter, filter, 0, mask.s_addr)) {
572 free(filter);
573 filter = get_filter_from_argv(&argv[optind-1]);
574
575 #if USE_PCAP_RESTART
576 PCAP_RESTART_FUNC();
577 #endif
578
579 if (pcap_compile(pd, &pcapfilter, filter, 0, mask.s_addr))
580 return 1;
581
582 match_data = NULL;
583 }
584
585 } else {
586 filter = include_vlan ? strdup(BPF_TEMPLATE_IP_VLAN) : strdup(BPF_TEMPLATE_IP);
587
588 if (pcap_compile(pd, &pcapfilter, filter, 0, mask.s_addr))
589 return 1;
590 }
591
592 if (pcap_setfilter(pd, &pcapfilter))
593 return 1;
594
595 return 0;
596 }
597
598 int setup_matcher(void) {
599 if (bin_match) {
600 uint32_t i = 0, n;
601 uint32_t len;
602 char *s, *d;
603
604 if (re_match_word || re_ignore_case) {
605 fprintf(stderr, "fatal: regex switches are incompatible with binary matching\n");
606 return 1;
607 }
608
609 len = (uint32_t)strlen(match_data);
610 if (len % 2 != 0 || !strishex(match_data)) {
611 fprintf(stderr, "fatal: invalid hex string specified\n");
612 return 1;
613 }
614
615 bin_data = (char*)malloc(len / 2);
616 memset(bin_data, 0, len / 2);
617 d = bin_data;
618
619 if ((s = strchr(match_data, 'x')))
620 len -= (uint32_t)(++s - match_data - 1);
621 else s = match_data;
622
623 while (i <= len) {
624 sscanf(s+i, "%2x", &n);
625 *d++ = n;
626 i += 2;
627 }
628
629 match_len = len / 2;
630 match_func = &bin_match_func;
631
632 } else {
633
634 #if USE_PCRE
635 uint32_t pcre_options = PCRE_UNGREEDY;
636
637 if (re_ignore_case)
638 pcre_options |= PCRE_CASELESS;
639
640 if (re_multiline_match)
641 pcre_options |= PCRE_DOTALL;
642 #else
643 re_syntax_options = RE_CHAR_CLASSES | RE_NO_BK_PARENS | RE_NO_BK_VBAR |
644 RE_CONTEXT_INDEP_ANCHORS | RE_CONTEXT_INDEP_OPS;
645
646 if (re_multiline_match)
647 re_syntax_options |= RE_DOT_NEWLINE;
648
649 if (re_ignore_case) {
650 uint32_t i;
651 char *s;
652
653 pattern.translate = (char*)malloc(256);
654 s = pattern.translate;
655
656 for (i = 0; i < 256; i++)
657 s[i] = i;
658 for (i = 'A'; i <= 'Z'; i++)
659 s[i] = i + 32;
660
661 s = match_data;
662 while (*s) {
663 *s = tolower(*s);
664 s++;
665 }
666
667 } else pattern.translate = NULL;
668 #endif
669
670 if (re_match_word) {
671 char *word_regex = (char*)malloc(strlen(match_data) * 3 + strlen(WORD_REGEX));
672 sprintf(word_regex, WORD_REGEX, match_data, match_data, match_data);
673 match_data = word_regex;
674 }
675
676 #if USE_PCRE
677 pattern = pcre_compile(match_data, pcre_options, (const char **)&re_err, &err_offset, 0);
678
679 if (!pattern) {
680 fprintf(stderr, "compile failed: %s\n", re_err);
681 return 1;
682 }
683
684 pattern_extra = pcre_study(pattern, 0, (const char **)&re_err);
685 #else
686 re_err = re_compile_pattern(match_data, strlen(match_data), &pattern);
687 if (re_err) {
688 fprintf(stderr, "regex compile: %s\n", re_err);
689 return 1;
690 }
691
692 pattern.fastmap = (char*)malloc(256);
693 if (re_compile_fastmap(&pattern)) {
694 perror("fastmap compile failed");
695 return 1;
696 }
697 #endif
698
699 match_func = &re_match_func;
700 }
701
702 return 0;
703 }
704
705 static inline uint8_t vlan_frame_count(u_char *p, uint16_t limit) {
706 uint8_t *et = (uint8_t*)(p + 12);
707 uint16_t ether_type = EXTRACT_16BITS(et);
708 uint8_t count = 0;
709
710 while ((void*)et < (void*)(p + limit) &&
711 ether_type != ETHERTYPE_IP &&
712 ether_type != ETHERTYPE_IPV6) {
713 count++;
714 et += VLANHDR_SIZE;
715 ether_type = EXTRACT_16BITS(et);
716 }
717
718 return count;
719 }
720
721 void process(u_char *d, struct pcap_pkthdr *h, u_char *p) {
722 uint8_t vlan_offset = include_vlan ? vlan_frame_count(p, h->caplen) * VLANHDR_SIZE : 0;
723
724 struct ip *ip4_pkt = (struct ip *) (p + link_offset + vlan_offset);
725 #if USE_IPv6
726 struct ip6_hdr *ip6_pkt = (struct ip6_hdr*)(p + link_offset + vlan_offset);
727 #endif
728
729 uint32_t ip_ver;
730
731 uint8_t ip_proto = 0;
732 uint32_t ip_hl = 0;
733 uint32_t ip_off = 0;
734
735 uint8_t fragmented = 0;
736 uint16_t frag_offset = 0;
737 uint32_t frag_id = 0;
738
739 char ip_src[INET6_ADDRSTRLEN + 1],
740 ip_dst[INET6_ADDRSTRLEN + 1];
741
742 unsigned char *data;
743 uint32_t len = h->caplen - vlan_offset;
744
745 seen_frames++;
746
747 #if HAVE_DLT_IEEE802_11_RADIO
748 if (radiotap_present) {
749 uint16_t radio_len = ((struct NGREP_rtaphdr_t *)(p))->it_len;
750 ip4_pkt = (struct ip *)(p + link_offset + radio_len);
751 len -= radio_len;
752 }
753 #endif
754
755 ip_ver = ip4_pkt->ip_v;
756
757 switch (ip_ver) {
758
759 case 4: {
760 #if defined(AIX)
761 #undef ip_hl
762 ip_hl = ip4_pkt->ip_ff.ip_fhl * 4;
763 #else
764 ip_hl = ip4_pkt->ip_hl * 4;
765 #endif
766 ip_proto = ip4_pkt->ip_p;
767 ip_off = ntohs(ip4_pkt->ip_off);
768
769 fragmented = ip_off & (IP_MF | IP_OFFMASK);
770 frag_offset = (fragmented) ? (ip_off & IP_OFFMASK) * 8 : 0;
771 frag_id = ntohs(ip4_pkt->ip_id);
772
773 inet_ntop(AF_INET, (const void *)&ip4_pkt->ip_src, ip_src, sizeof(ip_src));
774 inet_ntop(AF_INET, (const void *)&ip4_pkt->ip_dst, ip_dst, sizeof(ip_dst));
775 } break;
776
777 #if USE_IPv6
778 case 6: {
779 ip_hl = sizeof(struct ip6_hdr);
780 ip_proto = ip6_pkt->ip6_nxt;
781
782 if (ip_proto == IPPROTO_FRAGMENT) {
783 struct ip6_frag *ip6_fraghdr;
784
785 ip6_fraghdr = (struct ip6_frag *)((unsigned char *)(ip6_pkt) + ip_hl);
786 ip_hl += sizeof(struct ip6_frag);
787 ip_proto = ip6_fraghdr->ip6f_nxt;
788
789 fragmented = 1;
790 frag_offset = ntohs(ip6_fraghdr->ip6f_offlg & IP6F_OFF_MASK);
791 frag_id = ntohl(ip6_fraghdr->ip6f_ident);
792 }
793
794 inet_ntop(AF_INET6, (const void *)&ip6_pkt->ip6_src, ip_src, sizeof(ip_src));
795 inet_ntop(AF_INET6, (const void *)&ip6_pkt->ip6_dst, ip_dst, sizeof(ip_dst));
796 } break;
797 #endif
798 }
799
800 if (quiet < 1) {
801 printf("#");
802 fflush(stdout);
803 }
804
805 switch (ip_proto) {
806 case IPPROTO_TCP: {
807 struct tcphdr *tcp_pkt = (struct tcphdr *)((unsigned char *)(ip4_pkt) + ip_hl);
808 uint16_t tcphdr_offset = (frag_offset) ? 0 : (tcp_pkt->th_off * 4);
809
810 data = (unsigned char *)(tcp_pkt) + tcphdr_offset;
811 len -= link_offset + ip_hl + tcphdr_offset;
812
813 if ((int32_t)len < 0)
814 len = 0;
815
816 dump_packet(h, p, ip_proto, data, len,
817 ip_src, ip_dst, ntohs(tcp_pkt->th_sport), ntohs(tcp_pkt->th_dport), tcp_pkt->th_flags,
818 tcphdr_offset, fragmented, frag_offset, frag_id);
819 } break;
820
821 case IPPROTO_UDP: {
822 struct udphdr *udp_pkt = (struct udphdr *)((unsigned char *)(ip4_pkt) + ip_hl);
823 uint16_t udphdr_offset = (frag_offset) ? 0 : sizeof(*udp_pkt);
824
825 data = (unsigned char *)(udp_pkt) + udphdr_offset;
826 len -= link_offset + ip_hl + udphdr_offset;
827
828 if ((int32_t)len < 0)
829 len = 0;
830
831 dump_packet(h, p, ip_proto, data, len, ip_src, ip_dst,
832 ntohs(udp_pkt->uh_sport), ntohs(udp_pkt->uh_dport), 0,
833 udphdr_offset, fragmented, frag_offset, frag_id);
834 } break;
835
836 case IPPROTO_ICMP: {
837 struct icmp *icmp4_pkt = (struct icmp *)((unsigned char *)(ip4_pkt) + ip_hl);
838 uint16_t icmp4hdr_offset = (frag_offset) ? 0 : 4;
839
840 data = (unsigned char *)(icmp4_pkt) + icmp4hdr_offset;
841 len -= link_offset + ip_hl + icmp4hdr_offset;
842
843 if ((int32_t)len < 0)
844 len = 0;
845
846 dump_packet(h, p, ip_proto, data, len,
847 ip_src, ip_dst, icmp4_pkt->icmp_type, icmp4_pkt->icmp_code, 0,
848 icmp4hdr_offset, fragmented, frag_offset, frag_id);
849 } break;
850
851 #if USE_IPv6
852 case IPPROTO_ICMPV6: {
853 struct icmp6_hdr *icmp6_pkt = (struct icmp6_hdr *)((unsigned char *)(ip6_pkt) + ip_hl);
854 uint16_t icmp6hdr_offset = (frag_offset) ? 0 : 4;
855
856 data = (unsigned char *)(icmp6_pkt) + icmp6hdr_offset;
857 len -= link_offset + ip_hl + icmp6hdr_offset;
858
859 if ((int32_t)len < 0)
860 len = 0;
861
862 dump_packet(h, p, ip_proto, data, len,
863 ip_src, ip_dst, icmp6_pkt->icmp6_type, icmp6_pkt->icmp6_code, 0,
864 icmp6hdr_offset, fragmented, frag_offset, frag_id);
865 } break;
866 #endif
867
868 case IPPROTO_IGMP: {
869 struct igmp *igmp_pkt = (struct igmp *)((unsigned char *)(ip4_pkt) + ip_hl);
870 uint16_t igmphdr_offset = (frag_offset) ? 0 : 4;
871
872 data = (unsigned char *)(igmp_pkt) + igmphdr_offset;
873 len -= link_offset + ip_hl + igmphdr_offset;
874
875 if ((int32_t)len < 0)
876 len = 0;
877
878 dump_packet(h, p, ip_proto, data, len,
879 ip_src, ip_dst, igmp_pkt->igmp_type, igmp_pkt->igmp_code, 0,
880 igmphdr_offset, fragmented, frag_offset, frag_id);
881 } break;
882
883 default: {
884 data = (unsigned char *)(ip4_pkt) + ip_hl;
885 len -= link_offset + ip_hl;
886
887 if ((int32_t)len < 0)
888 len = 0;
889
890 dump_packet(h, p, ip_proto, data, len,
891 ip_src, ip_dst, 0, 0, 0,
892 0, fragmented, frag_offset, frag_id);
893 } break;
894
895 }
896
897 if (max_matches && matches >= max_matches)
898 clean_exit(0);
899
900 if (match_after && keep_matching)
901 keep_matching--;
902 }
903
904 void dump_packet(struct pcap_pkthdr *h, u_char *p, uint8_t proto, unsigned char *data, uint32_t len,
905 const char *ip_src, const char *ip_dst, uint16_t sport, uint16_t dport, uint8_t flags,
906 uint16_t hdr_offset, uint8_t frag, uint16_t frag_offset, uint32_t frag_id) {
907
908 uint16_t match_size, match_index;
909
910 if (!show_empty && len == 0)
911 return;
912
913 if (len > limitlen)
914 len = limitlen;
915
916 if ((len > 0 && match_func(data, len, &match_index, &match_size) == invert_match) && !keep_matching)
917 return;
918
919 if (!live_read && want_delay)
920 dump_delay(h);
921
922 {
923 char ident;
924
925 switch (proto) {
926 case IPPROTO_TCP: ident = TCP; break;
927 case IPPROTO_UDP: ident = UDP; break;
928 case IPPROTO_ICMP: ident = ICMP; break;
929 case IPPROTO_ICMPV6: ident = ICMPv6; break;
930 case IPPROTO_IGMP: ident = IGMP; break;
931 default: ident = UNKNOWN; break;
932 }
933
934 printf("\n%c", ident);
935 }
936
937 if (show_proto)
938 printf("(%u)", proto);
939
940 printf(" ");
941
942 if (print_time)
943 print_time(h);
944
945 if ((proto == IPPROTO_TCP || proto == IPPROTO_UDP) && (sport || dport) && (hdr_offset || frag_offset == 0))
946
947 printf("%s:%u -> %s:%u", ip_src, sport, ip_dst, dport);
948
949 else
950
951 printf("%s -> %s", ip_src, ip_dst);
952
953 if (proto == IPPROTO_TCP && flags)
954 printf(" [%s%s%s%s%s%s%s%s]",
955 (flags & TH_ACK) ? "A" : "",
956 (flags & TH_SYN) ? "S" : "",
957 (flags & TH_RST) ? "R" : "",
958 (flags & TH_FIN) ? "F" : "",
959 (flags & TH_URG) ? "U" : "",
960 (flags & TH_PUSH)? "P" : "",
961 (flags & TH_ECE) ? "E" : "",
962 (flags & TH_CWR) ? "C" : "");
963
964 switch (proto) {
965 case IPPROTO_ICMP:
966 case IPPROTO_ICMPV6:
967 case IPPROTO_IGMP:
968 printf(" %u:%u", sport, dport);
969 }
970
971 if (frag)
972 printf(" %s%u@%u:%u",
973 frag_offset?"+":"", frag_id, frag_offset, len);
974
975 if (dump_single)
976 printf(" ");
977 else
978 printf(" #%u\n", seen_frames);
979
980 if (quiet < 3)
981 dump_func(data, len, match_index, match_size);
982
983 if (pd_dump)
984 pcap_dump((u_char*)pd_dump, h, p);
985
986 #if USE_TCPKILL
987 if (tcpkill_active)
988 tcpkill_kill(h, p, link_offset, tcpkill_active);
989 #endif
990 }
991
992 int8_t re_match_func(unsigned char *data, uint32_t len, uint16_t *mindex, uint16_t *msize) {
993 #if USE_PCRE
994
995 static int sub[2];
996 switch(pcre_exec(pattern, 0, (char const *)data, (int32_t)len, 0, 0, 0, 0)) {
997 case PCRE_ERROR_NULL:
998 case PCRE_ERROR_BADOPTION:
999 case PCRE_ERROR_BADMAGIC:
1000 case PCRE_ERROR_UNKNOWN_NODE:
1001 case PCRE_ERROR_NOMEMORY:
1002 perror("she's dead, jim\n");
1003 clean_exit(2);
1004
1005 case PCRE_ERROR_NOMATCH:
1006 return 0;
1007
1008 default:
1009 *mindex = sub[0];
1010 *msize = sub[1] - sub[0];
1011 }
1012 #else
1013
1014 static struct re_registers regs;
1015 switch (re_search(&pattern, (char const *)data, (int32_t)len, 0, len, ®s)) {
1016 case -2:
1017 perror("she's dead, jim\n");
1018 clean_exit(2);
1019
1020 case -1:
1021 return 0;
1022
1023 default:
1024 *mindex = regs.start[0];
1025 *msize = regs.end[0] - regs.start[0];
1026 }
1027 #endif
1028
1029 matches++;
1030
1031 if (match_after && keep_matching != match_after)
1032 keep_matching = match_after;
1033
1034 return 1;
1035 }
1036
1037 int8_t bin_match_func(unsigned char *data, uint32_t len, uint16_t *mindex, uint16_t *msize) {
1038 int32_t stop = len - match_len;
1039 int32_t i = 0;
1040
1041 if (stop < 0)
1042 return 0;
1043
1044 while (i <= stop)
1045 if (!memcmp(data+(i++), bin_data, match_len)) {
1046 matches++;
1047
1048 if (match_after && keep_matching != match_after)
1049 keep_matching = match_after;
1050
1051 *mindex = i - 1;
1052 *msize = match_len;
1053
1054 return 1;
1055 }
1056
1057 return 0;
1058 }
1059
1060 int8_t blank_match_func(unsigned char *data, uint32_t len, uint16_t *mindex, uint16_t *msize) {
1061 matches++;
1062
1063 *mindex = 0;
1064 *msize = 0;
1065
1066 return 1;
1067 }
1068
1069 void dump_byline(unsigned char *data, uint32_t len, uint16_t mindex, uint16_t msize) {
1070 if (len > 0) {
1071 const unsigned char *s = data;
1072 uint8_t should_hilite = (msize && enable_hilite);
1073 unsigned char *hilite_start = data + mindex;
1074 unsigned char *hilite_end = hilite_start + msize;
1075
1076 while (s < data + len) {
1077 if (should_hilite && s == hilite_start)
1078 printf("%s", ANSI_hilite);
1079
1080 printf("%c", (*s == '\n' || isprint(*s)) ? *s : nonprint_char);
1081 s++;
1082
1083 if (should_hilite && s == hilite_end)
1084 printf("%s", ANSI_off);
1085 }
1086
1087 printf("\n");
1088 }
1089 }
1090
1091 void dump_unwrapped(unsigned char *data, uint32_t len, uint16_t mindex, uint16_t msize) {
1092 if (len > 0) {
1093 const unsigned char *s = data;
1094 uint8_t should_hilite = (msize && enable_hilite);
1095 unsigned char *hilite_start = data + mindex;
1096 unsigned char *hilite_end = hilite_start + msize;
1097
1098 while (s < data + len) {
1099 if (should_hilite && s == hilite_start)
1100 printf("%s", ANSI_hilite);
1101
1102 printf("%c", isprint(*s) ? *s : nonprint_char);
1103 s++;
1104
1105 if (should_hilite && s == hilite_end)
1106 printf("%s", ANSI_off);
1107 }
1108
1109 printf("\n");
1110 }
1111 }
1112
1113 void dump_formatted(unsigned char *data, uint32_t len, uint16_t mindex, uint16_t msize) {
1114 if (len > 0) {
1115 uint8_t should_hilite = (msize && enable_hilite);
1116 unsigned char *str = data;
1117 uint8_t hiliting = 0;
1118 uint8_t width = show_hex ? 16 : (ws_col-5);
1119 uint32_t i = 0,
1120 j = 0;
1121
1122 while (i < len) {
1123 printf(" ");
1124
1125 if (show_hex) {
1126 for (j = 0; j < width; j++) {
1127 if (should_hilite && (mindex <= (i+j) && (i+j) < mindex + msize)) {
1128 hiliting = 1;
1129 printf("%s", ANSI_hilite);
1130 }
1131
1132 if (i + j < len)
1133 printf("%02x ", str[j]);
1134 else printf(" ");
1135
1136 if ((j+1) % (width/2) == 0)
1137 printf(" ");
1138
1139 if (hiliting) {
1140 hiliting = 0;
1141 printf("%s", ANSI_off);
1142 }
1143 }
1144 }
1145
1146 for (j = 0; j < width; j++) {
1147 if (should_hilite && mindex <= (i+j) && (i+j) < mindex + msize) {
1148 hiliting = 1;
1149 printf("%s", ANSI_hilite);
1150 }
1151
1152 if (i + j < len)
1153 printf("%c", isprint(str[j]) ? str[j] : nonprint_char);
1154 else printf(" ");
1155
1156 if (hiliting) {
1157 hiliting = 0;
1158 printf("%s", ANSI_off);
1159 }
1160 }
1161
1162 str += width;
1163 i += j;
1164
1165 printf("\n");
1166 }
1167 }
1168 }
1169
1170 char *get_filter_from_string(char *str) {
1171 const char *template = include_vlan ? BPF_TEMPLATE_USERSPEC_IP_VLAN : BPF_TEMPLATE_USERSPEC_IP;
1172 char *mine, *s;
1173 uint32_t len;
1174
1175 if (!str || !*str)
1176 return NULL;
1177
1178 len = (uint32_t)strlen(str);
1179
1180 for (s = str; *s; s++)
1181 if (*s == '\r' || *s == '\n')
1182 *s = ' ';
1183
1184 if (!(mine = (char*)malloc(len + strlen(template) + 1)))
1185 return NULL;
1186
1187 memset(mine, 0, len + strlen(template) + 1);
1188
1189 sprintf(mine, template, str);
1190
1191 return mine;
1192 }
1193
1194 char *get_filter_from_argv(char **argv) {
1195 const char *template = include_vlan ? BPF_TEMPLATE_USERSPEC_IP_VLAN : BPF_TEMPLATE_USERSPEC_IP;
1196 char **arg = argv, *theirs, *mine;
1197 char *from, *to;
1198 uint32_t len = 0;
1199
1200 if (!*arg)
1201 return NULL;
1202
1203 while (*arg)
1204 len += (uint32_t)strlen(*arg++) + 1;
1205
1206 if (!(theirs = (char*)malloc(len + 1)) ||
1207 !(mine = (char*)malloc(len + strlen(template) + 1)))
1208 return NULL;
1209
1210 memset(theirs, 0, len + 1);
1211 memset(mine, 0, len + strlen(template) + 1);
1212
1213 arg = argv;
1214 to = theirs;
1215
1216 while ((from = *arg++)) {
1217 while ((*to++ = *from++));
1218 *(to-1) = ' ';
1219 }
1220
1221 sprintf(mine, template, theirs);
1222
1223 free(theirs);
1224 return mine;
1225 }
1226
1227
1228 uint8_t strishex(char *str) {
1229 char *s;
1230
1231 if ((s = strchr(str, 'x')))
1232 s++;
1233 else
1234 s = str;
1235
1236 while (*s)
1237 if (!isxdigit(*s++))
1238 return 0;
1239
1240 return 1;
1241 }
1242
1243
1244 void print_time_absolute(struct pcap_pkthdr *h) {
1245 struct tm *t = localtime((const time_t *)&h->ts.tv_sec);
1246
1247 printf("%02u/%02u/%02u %02u:%02u:%02u.%06u ",
1248 t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour,
1249 t->tm_min, t->tm_sec, (uint32_t)h->ts.tv_usec);
1250 }
1251
1252 void print_time_diff(struct pcap_pkthdr *h) {
1253 uint32_t secs, usecs;
1254
1255 secs = h->ts.tv_sec - prev_ts.tv_sec;
1256 if (h->ts.tv_usec >= prev_ts.tv_usec)
1257 usecs = h->ts.tv_usec - prev_ts.tv_usec;
1258 else {
1259 secs--;
1260 usecs = 1000000 - (prev_ts.tv_usec - h->ts.tv_usec);
1261 }
1262
1263 printf("+%u.%06u ", secs, usecs);
1264
1265 prev_ts.tv_sec = h->ts.tv_sec;
1266 prev_ts.tv_usec = h->ts.tv_usec;
1267 }
1268
1269 void print_time_offset(struct pcap_pkthdr *h) {
1270 uint32_t secs, usecs;
1271
1272 secs = h->ts.tv_sec - prev_ts.tv_sec;
1273 if (h->ts.tv_usec >= prev_ts.tv_usec)
1274 usecs = h->ts.tv_usec - prev_ts.tv_usec;
1275 else {
1276 secs--;
1277 usecs = 1000000 - (prev_ts.tv_usec - h->ts.tv_usec);
1278 }
1279
1280 if (prev_ts.tv_sec == 0 && prev_ts.tv_usec == 0) {
1281 prev_ts.tv_sec = h->ts.tv_sec;
1282 prev_ts.tv_usec = h->ts.tv_usec;
1283 secs = 0;
1284 usecs = 0;
1285 }
1286
1287 printf("+%u.%06u ", secs, usecs);
1288 }
1289
1290 void dump_delay_proc_init(struct pcap_pkthdr *h) {
1291 dump_delay = &dump_delay_proc;
1292
1293 prev_delay_ts.tv_sec = h->ts.tv_sec;
1294 prev_delay_ts.tv_usec = h->ts.tv_usec;
1295
1296 dump_delay(h);
1297 }
1298
1299 void dump_delay_proc(struct pcap_pkthdr *h) {
1300 uint32_t secs, usecs;
1301
1302 secs = h->ts.tv_sec - prev_delay_ts.tv_sec;
1303 if (h->ts.tv_usec >= prev_delay_ts.tv_usec)
1304 usecs = h->ts.tv_usec - prev_delay_ts.tv_usec;
1305 else {
1306 secs--;
1307 usecs = 1000000 - (prev_delay_ts.tv_usec - h->ts.tv_usec);
1308 }
1309
1310 #ifdef _WIN32
1311 {
1312 // grevious hack, yes, but windows sucks. sorry. :( --jordan
1313 if ((delay_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
1314 perror("delay socket creation failed, disabling -D");
1315 Sleep(3000); // give them time to read the message
1316 want_delay = 0;
1317 return;
1318 }
1319
1320 FD_ZERO(&delay_fds);
1321 FD_SET(delay_socket, &delay_fds);
1322
1323 delay_tv.tv_sec = secs;
1324 delay_tv.tv_usec = usecs;
1325
1326 if (select(0, &delay_fds, 0, 0, &delay_tv) == -1)
1327 fprintf(stderr, "WSAGetLastError = %u\n", WSAGetLastError());
1328
1329 closesocket(delay_socket);
1330 delay_socket = 0; // in case someone ^C's out of me
1331 }
1332 #else
1333 sleep(secs);
1334 usleep(usecs);
1335 #endif
1336
1337 prev_delay_ts.tv_sec = h->ts.tv_sec;
1338 prev_delay_ts.tv_usec = h->ts.tv_usec;
1339 }
1340
1341 void update_windowsize(int32_t e) {
1342 if (e == 0 && ws_col_forced)
1343
1344 ws_col = ws_col_forced;
1345
1346 else if (!ws_col_forced) {
1347
1348 #if !defined(_WIN32)
1349 const struct winsize ws;
1350
1351 if (!ioctl(0, TIOCGWINSZ, &ws)) {
1352 ws_row = ws.ws_row;
1353 ws_col = ws.ws_col;
1354 }
1355 #else
1356 CONSOLE_SCREEN_BUFFER_INFO csbi;
1357 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
1358 ws_row = csbi.dwSize.Y;
1359 ws_col = csbi.dwSize.X;
1360 }
1361 #endif
1362 else {
1363 ws_row = 24;
1364 ws_col = 80;
1365 }
1366
1367 }
1368 }
1369
1370 #if !defined(_WIN32) && USE_DROPPRIVS
1371 void drop_privs(void) {
1372 struct passwd *pw;
1373 uid_t newuid;
1374 gid_t newgid;
1375
1376 if ((getuid() || geteuid()) || dont_dropprivs)
1377 return;
1378
1379 pw = getpwnam(DROPPRIVS_USER);
1380 if (!pw) {
1381 perror("attempt to drop privileges failed: getpwnam failed");
1382 clean_exit(2);
1383 }
1384
1385 newgid = pw->pw_gid;
1386 newuid = pw->pw_uid;
1387
1388 if (getgroups(0, NULL) > 0)
1389 if (setgroups(1, &newgid) == -1) {
1390 perror("attempt to drop privileges failed");
1391 clean_exit(2);
1392 }
1393
1394 if (((getgid() != newgid) && (setgid(newgid) == -1)) ||
1395 ((getegid() != newgid) && (setegid(newgid) == -1)) ||
1396 ((getuid() != newuid) && (setuid(newuid) == -1)) ||
1397 ((geteuid() != newuid) && (seteuid(newuid) == -1))) {
1398
1399 perror("attempt to drop privileges failed");
1400 clean_exit(2);
1401 }
1402 }
1403
1404 #endif
1405
1406 void usage(void) {
1407 printf("usage: ngrep <-"
1408 #if defined(_WIN32)
1409 "L"
1410 #endif
1411 "hNXViwqpevxlDtTRM> <-IO pcap_dump> <-n num> <-d dev> <-A num>\n"
1412 " <-s snaplen> <-S limitlen> <-W normal|byline|single|none> <-c cols>\n"
1413 " <-P char> <-F file>"
1414 #if USE_TCPKILL
1415 " <-K count>"
1416 #endif
1417 "\n"
1418 " <match expression> <bpf filter>\n"
1419 " -h is help/usage\n"
1420 " -V is version information\n"
1421 " -q is be quiet (don't print packet reception hash marks)\n"
1422 " -e is show empty packets\n"
1423 " -i is ignore case\n"
1424 " -v is invert match\n"
1425 " -R is don't do privilege revocation logic\n"
1426 " -x is print in alternate hexdump format\n"
1427 " -X is interpret match expression as hexadecimal\n"
1428 " -w is word-regex (expression must match as a word)\n"
1429 " -p is don't go into promiscuous mode\n"
1430 " -l is make stdout line buffered\n"
1431 " -D is replay pcap_dumps with their recorded time intervals\n"
1432 " -t is print timestamp every time a packet is matched\n"
1433 " -T is print delta timestamp every time a packet is matched\n"
1434 " specify twice for delta from first match\n"
1435 " -M is don't do multi-line match (do single-line match instead)\n"
1436 " -I is read packet stream from pcap format file pcap_dump\n"
1437 " -O is dump matched packets in pcap format to pcap_dump\n"
1438 " -n is look at only num packets\n"
1439 " -A is dump num packets after a match\n"
1440 " -s is set the bpf caplen\n"
1441 " -S is set the limitlen on matched packets\n"
1442 " -W is set the dump format (normal, byline, single, none)\n"
1443 " -c is force the column width to the specified size\n"
1444 " -P is set the non-printable display char to what is specified\n"
1445 " -F is read the bpf filter from the specified file\n"
1446 " -N is show sub protocol number\n"
1447 #if defined(_WIN32)
1448 " -d is use specified device (index) instead of the pcap default\n"
1449 " -L is show the winpcap device list index\n"
1450 #else
1451 " -d is use specified device instead of the pcap default\n"
1452 #endif
1453 #if USE_TCPKILL
1454 " -K is send N packets to kill observed connections\n"
1455 #endif
1456 "");
1457
1458 exit(2);
1459 }
1460
1461
1462 void version(void) {
1463 printf("ngrep: V%s, %s\n", VERSION, pcap_lib_version());
1464 exit(0);
1465 }
1466
1467
1468 void clean_exit(int32_t sig) {
1469 struct pcap_stat s;
1470
1471 signal(SIGINT, SIG_IGN);
1472 signal(SIGABRT, SIG_IGN);
1473 #if !defined(_WIN32)
1474 signal(SIGQUIT, SIG_IGN);
1475 signal(SIGPIPE, SIG_IGN);
1476 signal(SIGWINCH, SIG_IGN);
1477 #endif
1478
1479 if (quiet < 1 && sig >= 0)
1480 printf("exit\n");
1481
1482 #if USE_PCRE
1483 if (pattern) pcre_free(pattern);
1484 if (pattern_extra) pcre_free(pattern_extra);
1485 #else
1486 if (pattern.translate) free(pattern.translate);
1487 if (pattern.fastmap) free(pattern.fastmap);
1488 #endif
1489
1490 if (bin_data) free(bin_data);
1491
1492 /* We used to report pcap_stats; but PCAP manpage says pcap_stats "may or
1493 may not" be accurate. So useless. :-( And confusing for a user to see
1494 counts not match what ngrep thinks. */
1495 if (quiet < 1 && sig >= 0 && !read_file)
1496 printf("%u received, %u matched\n", seen_frames, matches);
1497
1498 if (pd) pcap_close(pd);
1499 if (pd_dumppcap) pcap_close(pd_dumppcap);
1500 if (pd_dump) pcap_dump_close(pd_dump);
1501
1502 #if defined(_WIN32)
1503 if (delay_socket) closesocket(delay_socket);
1504 if (want_delay) WSACleanup();
1505 if (usedev) free(usedev);
1506 #endif
1507
1508 exit(matches ? 0 : 1);
1509 }
1510
1511 #if defined(_WIN32)
1512 int8_t win32_initwinsock(void) {
1513 WORD wVersionRequested = MAKEWORD(2, 0);
1514 WSADATA wsaData;
1515
1516 if (WSAStartup(wVersionRequested, &wsaData)) {
1517 perror("unable to initialize winsock");
1518 return 0;
1519 }
1520
1521 // we want at least major version 2
1522 if (LOBYTE(wsaData.wVersion) < 2) {
1523 fprintf(stderr, "unable to find winsock 2.0 or greater (found %u.%u)\n",
1524 LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
1525 WSACleanup();
1526 return 0;
1527 }
1528
1529 return 1;
1530 }
1531
1532 void win32_listdevices(void) {
1533 uint32_t i = 0;
1534 pcap_if_t *alldevs, *d;
1535 char errbuf[PCAP_ERRBUF_SIZE];
1536
1537 if (pcap_findalldevs(&alldevs, errbuf) == -1) {
1538 perror("unable to enumerate device list");
1539 clean_exit(2);
1540 }
1541
1542 printf("idx\tdev\n");
1543 printf("---\t---\n");
1544
1545 for (d = alldevs; d != NULL; d = d->next) {
1546 printf("%2u:\t%s", ++i, d->name);
1547
1548 if (d->description)
1549 printf(" (%s)\n", d->description);
1550 }
1551
1552 pcap_freealldevs(alldevs);
1553 }
1554
1555 char *win32_usedevice(const char *index) {
1556 int32_t idx = atoi(index), i = 0;
1557 pcap_if_t *alldevs, *d;
1558 char errbuf[PCAP_ERRBUF_SIZE];
1559 char *dev = NULL;
1560
1561 if (idx <= 0) {
1562 perror("invalid device index");
1563 clean_exit(2);
1564 }
1565
1566 if (pcap_findalldevs(&alldevs, errbuf) == -1) {
1567 perror("unable to enumerate devices");
1568 clean_exit(2);
1569 }
1570
1571 for (d = alldevs; d != NULL && i != idx; d = d->next)
1572 if (++i == idx)
1573 dev = _strdup(d->name);
1574
1575 if (i <= 0) {
1576 perror("no known devices");
1577 clean_exit(2);
1578 }
1579
1580 if (i != idx) {
1581 perror("unknown device specified");
1582 clean_exit(2);
1583 }
1584
1585 pcap_freealldevs(alldevs);
1586
1587 return dev;
1588 }
1589
1590 char *win32_choosedevice(void) {
1591 pcap_if_t *alldevs, *d;
1592 char errbuf[PCAP_ERRBUF_SIZE];
1593 char *dev = NULL;
1594
1595 if (pcap_findalldevs(&alldevs, errbuf) == -1) {
1596 perror("unable to enumerate devices");
1597 clean_exit(2);
1598 }
1599
1600 for (d = alldevs; d != NULL; d = d->next)
1601 if ((d->addresses) && (d->addresses->addr))
1602 dev = _strdup(d->name);
1603
1604 pcap_freealldevs(alldevs);
1605
1606 if (!dev)
1607 dev = pcap_lookupdev(errbuf);
1608
1609 return dev;
1610 }
1611 #endif