ngrep.c (ngrep-1_45) | : | ngrep.c (ngrep-1_47) | ||
---|---|---|---|---|
/* | /* | |||
* $Id$ | * Copyright (c) 2017 Jordan Ritter <jpr5@darkridge.com> | |||
* | ||||
* Copyright (c) 2006 Jordan Ritter <jpr5@darkridge.com> | ||||
* | * | |||
* Please refer to the LICENSE file for more information. | * Please refer to the LICENSE file for more information. | |||
* | * | |||
*/ | */ | |||
#if defined(BSD) || defined(SOLARIS) || defined(MACOSX) | #if defined(BSD) || defined(SOLARIS) || defined(MACOSX) | |||
#include <unistd.h> | #include <unistd.h> | |||
#include <ctype.h> | #include <ctype.h> | |||
#include <sys/types.h> | #include <sys/types.h> | |||
#include <sys/socket.h> | #include <sys/socket.h> | |||
skipping to change at line 35 | skipping to change at line 33 | |||
#include <sys/socket.h> | #include <sys/socket.h> | |||
#include <netinet/in.h> | #include <netinet/in.h> | |||
#include <netinet/in_systm.h> | #include <netinet/in_systm.h> | |||
#include <net/route.h> | #include <net/route.h> | |||
#include <sys/mbuf.h> | #include <sys/mbuf.h> | |||
#include <arpa/inet.h> | #include <arpa/inet.h> | |||
#include <unistd> | #include <unistd> | |||
#include <pwd.h> | #include <pwd.h> | |||
#endif | #endif | |||
#if defined(LINUX) | #if defined(LINUX) || defined(__GLIBC__) || defined(__GNU__) | |||
#include <getopt.h> | #include <getopt.h> | |||
#include <arpa/inet.h> | #include <arpa/inet.h> | |||
#include <ctype.h> | #include <ctype.h> | |||
#include <time.h> | #include <time.h> | |||
#include <unistd.h> | #include <unistd.h> | |||
#include <pwd.h> | #include <pwd.h> | |||
#include <grp.h> | #include <grp.h> | |||
#endif | #endif | |||
#if defined(AIX) | #if defined(AIX) | |||
skipping to change at line 58 | skipping to change at line 56 | |||
#include <netinet/in.h> | #include <netinet/in.h> | |||
#include <time.h> | #include <time.h> | |||
#include <unistd.h> | #include <unistd.h> | |||
#include <pwd.h> | #include <pwd.h> | |||
#endif | #endif | |||
#if defined(_WIN32) | #if defined(_WIN32) | |||
#include <io.h> | #include <io.h> | |||
#include <getopt.h> | #include <getopt.h> | |||
#include <winsock2.h> | #include <winsock2.h> | |||
#include <ws2tcpip.h> | ||||
#include <types.h> | #include <types.h> | |||
#include <inet_ntop.h> | ||||
#include <config.h> | #include <config.h> | |||
#define strcasecmp stricmp | #define strcasecmp stricmp | |||
#define strncasecmp strnicmp | ||||
#else | #else | |||
#include <netinet/ip.h> | #include <netinet/ip.h> | |||
#include <netinet/tcp.h> | #include <netinet/tcp.h> | |||
#include <netinet/udp.h> | #include <netinet/udp.h> | |||
#include <netinet/ip_icmp.h> | #include <netinet/ip_icmp.h> | |||
#include <netinet/igmp.h> | #include <netinet/igmp.h> | |||
#endif | #endif | |||
#include <stdlib.h> | #include <stdlib.h> | |||
#include <string.h> | #include <string.h> | |||
#include <signal.h> | #include <signal.h> | |||
#include <locale.h> | ||||
#if !defined(_WIN32) | #if !defined(_WIN32) | |||
#include <errno.h> | #include <errno.h> | |||
#include <sys/ioctl.h> | #include <sys/ioctl.h> | |||
#endif | #endif | |||
#include <pcap.h> | #include <pcap.h> | |||
#ifdef HAVE_CONFIG_H | #ifdef HAVE_CONFIG_H | |||
#include "config.h" | #include "config.h" | |||
#endif | #endif | |||
#if USE_IPv6 && !defined(_WIN32) | #if USE_IPv6 && !defined(_WIN32) | |||
#include <netinet/ip6.h> | #include <netinet/ip6.h> | |||
#include <netinet/icmp6.h> | #include <netinet/icmp6.h> | |||
#endif | #endif | |||
#if USE_PCRE | #if USE_PCRE | |||
#include "pcre-5.0/pcre.h" | #include <pcre.h> | |||
#else | #else | |||
#include "regex-0.12/regex.h" | #include <regex.h> | |||
#endif | #endif | |||
#include "ngrep.h" | #include "ngrep.h" | |||
static char rcsver[] = "$Revision$"; | ||||
/* | /* | |||
* Configuration Options | * Configuration Options | |||
*/ | */ | |||
uint16_t snaplen = 65535, limitlen = 65535, promisc = 1, to = 100; | uint32_t snaplen = 65535, limitlen = 65535, promisc = 1, to = 100; | |||
uint16_t match_after = 0, keep_matching = 0, matches = 0, max_matches = 0; | uint32_t match_after = 0, keep_matching = 0, matches = 0, max_matches = 0; | |||
uint32_t seen_frames = 0; | ||||
#if USE_TCPKILL | ||||
uint32_t tcpkill_active = 0; | ||||
#endif | ||||
uint8_t re_match_word = 0, re_ignore_case = 0, re_multiline_match = 1; | uint8_t re_match_word = 0, re_ignore_case = 0, re_multiline_match = 1; | |||
uint8_t show_empty = 0, show_hex = 0, show_proto = 0, quiet = 0; | uint8_t show_empty = 0, show_hex = 0, show_proto = 0, quiet = 0; | |||
uint8_t invert_match = 0, bin_match = 0; | uint8_t invert_match = 0, bin_match = 0; | |||
uint8_t live_read = 1, want_delay = 0; | uint8_t live_read = 1, want_delay = 0; | |||
uint8_t dont_dropprivs = 0; | uint8_t dont_dropprivs = 0; | |||
uint8_t enable_hilite = 0; | ||||
char *read_file = NULL, *dump_file = NULL; | char *read_file = NULL, *dump_file = NULL; | |||
char *usedev = NULL; | char *usedev = NULL; | |||
char nonprint_char = '.'; | char nonprint_char = '.'; | |||
/* | /* | |||
* GNU Regex/PCRE | * GNU Regex/PCRE | |||
*/ | */ | |||
skipping to change at line 147 | skipping to change at line 151 | |||
/* | /* | |||
* Matching | * Matching | |||
*/ | */ | |||
char *match_data = NULL, *bin_data = NULL; | char *match_data = NULL, *bin_data = NULL; | |||
uint16_t match_len = 0; | uint16_t match_len = 0; | |||
int8_t (*match_func)() = &blank_match_func; | int8_t (*match_func)() = &blank_match_func; | |||
int8_t dump_single = 0; | int8_t dump_single = 0; | |||
void (*dump_func)(unsigned char *, uint32_t) = &dump_formatted; | void (*dump_func)(unsigned char *, uint32_t, uint16_t, uint16_t) = &dump_formatt ed; | |||
/* | /* | |||
* BPF/Network | * BPF/Network | |||
*/ | */ | |||
char *filter = NULL, *filter_file = NULL; | char *filter = NULL, *filter_file = NULL; | |||
char pc_err[PCAP_ERRBUF_SIZE]; | char pc_err[PCAP_ERRBUF_SIZE]; | |||
uint8_t link_offset; | uint8_t link_offset; | |||
uint8_t radiotap_present = 0; | uint8_t radiotap_present = 0; | |||
uint8_t include_vlan = USE_VLAN_HACK; | ||||
pcap_t *pd = NULL; | pcap_t *pd = NULL, *pd_dumppcap = NULL; | |||
pcap_dumper_t *pd_dump = NULL; | pcap_dumper_t *pd_dump = NULL; | |||
struct bpf_program pcapfilter; | struct bpf_program pcapfilter; | |||
struct in_addr net, mask; | struct in_addr net, mask; | |||
/* | /* | |||
* Timestamp/delay functionality | * Timestamp/delay functionality | |||
*/ | */ | |||
struct timeval prev_ts = {0, 0}, prev_delay_ts = {0,0}; | struct timeval prev_ts = {0, 0}, prev_delay_ts = {0,0}; | |||
#if defined(_WIN32) | #if defined(_WIN32) | |||
struct timeval delay_tv; | struct timeval delay_tv; | |||
FD_SET delay_fds; | FD_SET delay_fds; | |||
SOCKET delay_socket = 0; | SOCKET delay_socket = 0; | |||
#endif | #endif | |||
void (*print_time)() = NULL, (*dump_delay)() = dump_delay_proc_init; | void (*print_time)() = NULL, (*dump_delay)() = dump_delay_proc_init; | |||
/* | /* | |||
* When !Win32, windowsize stuff. We leave it in regardless to avoid | * Window-size functionality (adjust output based on width of console display) | |||
* any additional #if complication/obfuscation. | ||||
*/ | */ | |||
uint32_t ws_row, ws_col = 80, ws_col_forced = 0; | uint32_t ws_row, ws_col = 80, ws_col_forced = 0; | |||
int main(int argc, char **argv) { | int main(int argc, char **argv) { | |||
int32_t c; | int32_t c; | |||
signal(SIGINT, clean_exit); | signal(SIGINT, clean_exit); | |||
signal(SIGABRT, clean_exit); | signal(SIGABRT, clean_exit); | |||
#if !defined(_WIN32) | #if !defined(_WIN32) | |||
signal(SIGQUIT, clean_exit); | signal(SIGQUIT, clean_exit); | |||
signal(SIGPIPE, clean_exit); | signal(SIGPIPE, clean_exit); | |||
signal(SIGWINCH, update_windowsize); | signal(SIGWINCH, update_windowsize); | |||
#endif | #endif | |||
while ((c = getopt(argc, argv, "LNhXViwqpevxlDtTRMs:n:c:d:A:I:O:S:P:F:W:")) | setlocale(LC_ALL, ""); | |||
!= EOF) { | ||||
#if !defined(_WIN32) | ||||
{ | ||||
char const *locale = getenv("LANG"); | ||||
if (locale == NULL) | ||||
locale = "en_US"; | ||||
setlocale(LC_CTYPE, locale); | ||||
} | ||||
#endif | ||||
while ((c = getopt(argc, argv, "LNhXViwqpevxlDtTRMK:Cs:n:c:d:A:I:O:S:P:F:W:" | ||||
)) != EOF) { | ||||
switch (c) { | switch (c) { | |||
case 'W': { | case 'W': { | |||
if (!strcasecmp(optarg, "normal")) | if (!strcasecmp(optarg, "normal")) | |||
dump_func = &dump_formatted; | dump_func = &dump_formatted; | |||
else if (!strcasecmp(optarg, "byline")) | else if (!strcasecmp(optarg, "byline")) | |||
dump_func = &dump_byline; | dump_func = &dump_byline; | |||
else if (!strcasecmp(optarg, "none")) | else if (!strcasecmp(optarg, "none")) | |||
dump_func = &dump_unwrapped; | dump_func = &dump_unwrapped; | |||
else if (!strcasecmp(optarg, "single")) { | else if (!strcasecmp(optarg, "single")) { | |||
dump_func = &dump_unwrapped; | dump_func = &dump_unwrapped; | |||
dump_single = 1; | dump_single = 1; | |||
} else { | } else { | |||
printf("fatal: unknown wrap method '%s'\n", optarg); | printf("fatal: unknown wrap method '%s'\n", optarg); | |||
usage(-1); | usage(); | |||
} | } | |||
} break; | } break; | |||
case 'F': | case 'F': | |||
filter_file = optarg; | filter_file = optarg; | |||
break; | break; | |||
case 'P': | case 'P': | |||
nonprint_char = *optarg; | nonprint_char = *optarg; | |||
break; | break; | |||
case 'S': | case 'S': { | |||
limitlen = atoi(optarg); | limitlen = _atoui32(optarg); | |||
break; | break; | |||
} | ||||
case 'O': | case 'O': | |||
dump_file = optarg; | dump_file = optarg; | |||
break; | break; | |||
case 'I': | case 'I': | |||
read_file = optarg; | read_file = optarg; | |||
break; | break; | |||
case 'A': | case 'A': | |||
match_after = atoi(optarg) + 1; | match_after = _atoui32(optarg); | |||
if (match_after < UINT32_MAX) | ||||
match_after++; | ||||
break; | break; | |||
#if defined(_WIN32) | #if defined(_WIN32) | |||
case 'L': | case 'L': | |||
win32_listdevices(); | win32_listdevices(); | |||
clean_exit(0); | clean_exit(2); | |||
case 'd': | case 'd': | |||
usedev = win32_usedevice(optarg); | usedev = win32_usedevice(optarg); | |||
break; | break; | |||
#else | #else | |||
case 'L': | case 'L': | |||
perror("-L is a Win32-only option"); | perror("-L is a Win32-only option"); | |||
clean_exit(-1); | clean_exit(2); | |||
case 'd': | case 'd': | |||
usedev = optarg; | usedev = optarg; | |||
/* Linux: any = DLT_LINUX_SLL, pcap says incompatible with VLAN | ||||
*/ | ||||
if (!strncasecmp(usedev, "any", 3)) | ||||
include_vlan = 0; | ||||
break; | break; | |||
#endif | #endif | |||
case 'c': | case 'c': | |||
ws_col_forced = atoi(optarg); | ws_col_forced = atoi(optarg); | |||
break; | break; | |||
case 'n': | case 'n': | |||
max_matches = atoi(optarg); | max_matches = _atoui32(optarg); | |||
break; | break; | |||
case 's': { | case 's': { | |||
uint16_t value = atoi(optarg); | uint16_t value = _atoui32(optarg); | |||
if (value > 0) | if (value > 0) | |||
snaplen = value; | snaplen = value; | |||
} break; | } break; | |||
case 'C': | ||||
enable_hilite = 1; | ||||
break; | ||||
case 'M': | case 'M': | |||
re_multiline_match = 0; | re_multiline_match = 0; | |||
break; | break; | |||
case 'R': | case 'R': | |||
dont_dropprivs = 1; | dont_dropprivs = 1; | |||
break; | break; | |||
case 'T': | case 'T': | |||
print_time = &print_time_diff; | if (print_time == &print_time_diff) { | |||
print_time = print_time_offset; | ||||
memset(&prev_ts, 0, sizeof(prev_ts)); | ||||
} else { | ||||
print_time = &print_time_diff; | ||||
#if defined(_WIN32) | #if defined(_WIN32) | |||
prev_ts.tv_sec = (uint32_t)time(NULL); | prev_ts.tv_sec = (uint32_t)time(NULL); | |||
prev_ts.tv_usec = 0; | prev_ts.tv_usec = 0; | |||
#else | #else | |||
gettimeofday(&prev_ts, NULL); | gettimeofday(&prev_ts, NULL); | |||
#endif | #endif | |||
} | ||||
break; | break; | |||
case 't': | case 't': | |||
print_time = &print_time_absolute; | print_time = &print_time_absolute; | |||
break; | break; | |||
case 'D': | case 'D': | |||
want_delay = 1; | want_delay = 1; | |||
break; | break; | |||
case 'l': | case 'l': | |||
setvbuf(stdout, NULL, _IOLBF, 0); | setvbuf(stdout, NULL, _IOLBF, 0); | |||
break; | break; | |||
skipping to change at line 310 | skipping to change at line 340 | |||
re_ignore_case++; | re_ignore_case++; | |||
break; | break; | |||
case 'V': | case 'V': | |||
version(); | version(); | |||
case 'X': | case 'X': | |||
bin_match++; | bin_match++; | |||
break; | break; | |||
case 'N': | case 'N': | |||
show_proto++; | show_proto++; | |||
break; | break; | |||
#if USE_TCPKILL | ||||
case 'K': | ||||
tcpkill_active = _atoui32(optarg); | ||||
break; | ||||
#endif | ||||
case 'h': | case 'h': | |||
usage(0); | usage(); | |||
default: | default: | |||
usage(-1); | usage(); | |||
} | } | |||
} | } | |||
if (show_hex && dump_func != &dump_formatted) { | if (show_hex && dump_func != &dump_formatted) { | |||
printf("fatal: -x (hex dump) is incompatible with -W (alternate format)\ n"); | printf("fatal: -x (hex dump) is incompatible with -W (alternate format)\ n"); | |||
usage(-1); | usage(); | |||
} | } | |||
if (argv[optind]) | if (argv[optind]) | |||
match_data = argv[optind++]; | match_data = argv[optind++]; | |||
if (read_file) { | #if USE_TCPKILL | |||
if (tcpkill_active) | ||||
if (!(pd = pcap_open_offline(read_file, pc_err))) { | tcpkill_init(); | |||
perror(pc_err); | #endif | |||
clean_exit(-1); | ||||
} | ||||
live_read = 0; | ||||
printf("input: %s\n", read_file); | ||||
} else { | /* Setup PCAP input */ | |||
char *dev = usedev ? usedev : pcap_lookupdev(pc_err); | if (setup_pcap_source()) | |||
clean_exit(2); | ||||
if (!dev) { | /* Setup BPF filter */ | |||
perror(pc_err); | ||||
clean_exit(-1); | ||||
} | ||||
if ((pd = pcap_open_live(dev, snaplen, promisc, to, pc_err)) == NULL) { | if (setup_bpf_filter(argv)) { | |||
perror(pc_err); | include_vlan = 0; | |||
clean_exit(-1); | if (filter) { free(filter); filter = NULL; } | |||
} | ||||
if (pcap_lookupnet(dev, &net.s_addr, &mask.s_addr, pc_err) == -1) { | ||||
perror(pc_err); | ||||
memset(&net, 0, sizeof(net)); | ||||
memset(&mask, 0, sizeof(mask)); | ||||
} | ||||
if (quiet < 2) { | if (setup_bpf_filter(argv)) { | |||
printf("interface: %s", dev); | pcap_perror(pd, "pcap"); | |||
if (net.s_addr && mask.s_addr) { | clean_exit(2); | |||
printf(" (%s/", inet_ntoa(net)); | ||||
printf("%s)", inet_ntoa(mask)); | ||||
} | ||||
printf("\n"); | ||||
} | } | |||
} | } | |||
if (filter_file) { | if (filter) { | |||
char buf[1024] = {0}; | if (quiet < 2) | |||
FILE *f = fopen(filter_file, "r"); | printf("filter: %s\n", filter); | |||
free(filter); | ||||
if (!f || !fgets(buf, sizeof(buf)-1, f)) { | } | |||
fprintf(stderr, "fatal: unable to get filter from %s: %s\n", filter_ | ||||
file, strerror(errno)); | ||||
usage(-1); | ||||
} | ||||
fclose(f); | ||||
filter = get_filter_from_string(buf); | ||||
if (pcap_compile(pd, &pcapfilter, filter, 0, mask.s_addr)) { | ||||
pcap_perror(pd, "pcap compile"); | ||||
clean_exit(-1); | ||||
} | ||||
} else if (argv[optind]) { | ||||
filter = get_filter_from_argv(&argv[optind]); | ||||
if (pcap_compile(pd, &pcapfilter, filter, 0, mask.s_addr)) { | /* Setup matcher */ | |||
free(filter); | ||||
filter = get_filter_from_argv(&argv[optind-1]); | ||||
#if USE_PCAP_RESTART | if (match_data) { | |||
PCAP_RESTART_FUNC(); | if (setup_matcher()) | |||
#endif | clean_exit(2); | |||
if (pcap_compile(pd, &pcapfilter, filter, 0, mask.s_addr)) { | ||||
pcap_perror(pd, "pcap compile"); | ||||
clean_exit(-1); | ||||
} else match_data = NULL; | ||||
} | ||||
} else { | if (quiet < 2 && strlen(match_data)) | |||
char *default_filter = BPF_FILTER_IP; | printf("%smatch: %s%s\n", invert_match?"don't ":"", | |||
(bin_data && !strchr(match_data, 'x'))?"0x":"", match_data); | ||||
if (pcap_compile(pd, &pcapfilter, default_filter, 0, mask.s_addr)) { | if (re_match_word) free(match_data); | |||
pcap_perror(pd, "pcap compile"); | ||||
clean_exit(-1); | ||||
} | ||||
} | } | |||
if (filter && quiet < 2) | /* Misc */ | |||
printf("filter: %s\n", filter); | ||||
if (pcap_setfilter(pd, &pcapfilter)) { | if (dump_file) { | |||
pcap_perror(pd, "pcap set"); | pd_dump = pcap_dump_open(pd, dump_file); | |||
clean_exit(-1); | if (!pd_dump) { | |||
fprintf(stderr, "fatal: %s\n", pcap_geterr(pd)); | ||||
clean_exit(2); | ||||
} else printf("output: %s\n", dump_file); | ||||
} | } | |||
if (match_data) { | update_windowsize(0); | |||
if (bin_match) { | ||||
uint32_t i = 0, n; | ||||
uint32_t len; | ||||
char *s, *d; | ||||
if (re_match_word || re_ignore_case) { | ||||
fprintf(stderr, "fatal: regex switches are incompatible with bin | ||||
ary matching\n"); | ||||
clean_exit(-1); | ||||
} | ||||
len = (uint32_t)strlen(match_data); | #if defined(_WIN32) | |||
if (len % 2 != 0 || !strishex(match_data)) { | win32_initwinsock(); | |||
fprintf(stderr, "fatal: invalid hex string specified\n"); | #endif | |||
clean_exit(-1); | ||||
} | ||||
bin_data = malloc(len / 2); | #if !defined(_WIN32) && USE_DROPPRIVS | |||
memset(bin_data, 0, len / 2); | drop_privs(); | |||
d = bin_data; | #endif | |||
if ((s = strchr(match_data, 'x'))) | ||||
len -= (uint32_t)(++s - match_data - 1); | ||||
else s = match_data; | ||||
while (i <= len) { | ||||
sscanf(s+i, "%2x", &n); | ||||
*d++ = n; | ||||
i += 2; | ||||
} | ||||
match_len = len / 2; | while (pcap_loop(pd, -1, (pcap_handler)process, 0)); | |||
match_func = &bin_match_func; | ||||
} else { | clean_exit(0); | |||
#if USE_PCRE | /* NOT REACHED */ | |||
uint32_t pcre_options = PCRE_UNGREEDY; | return 0; | |||
} | ||||
if (re_ignore_case) | int setup_pcap_source(void) { | |||
pcre_options |= PCRE_CASELESS; | if (read_file) { | |||
if (re_multiline_match) | if (!(pd = pcap_open_offline(read_file, pc_err))) { | |||
pcre_options |= PCRE_DOTALL; | perror(pc_err); | |||
#else | return 1; | |||
re_syntax_options = RE_CHAR_CLASSES | RE_NO_BK_PARENS | RE_NO_BK_VBA | } | |||
R | | ||||
RE_CONTEXT_INDEP_ANCHORS | RE_CONTEXT_INDEP_OPS; | ||||
if (re_multiline_match) | live_read = 0; | |||
re_syntax_options |= RE_DOT_NEWLINE; | printf("input: %s\n", read_file); | |||
if (re_ignore_case) { | } else { | |||
uint32_t i; | ||||
char *s; | ||||
pattern.translate = (char*)malloc(256); | ||||
s = pattern.translate; | ||||
for (i = 0; i < 256; i++) | ||||
s[i] = i; | ||||
for (i = 'A'; i <= 'Z'; i++) | ||||
s[i] = i + 32; | ||||
s = match_data; | ||||
while (*s) { | ||||
*s = tolower(*s); | ||||
s++; | ||||
} | ||||
} else pattern.translate = NULL; | char *dev = usedev ? usedev : | |||
#if defined(_WIN32) | ||||
win32_choosedevice(); | ||||
#else | ||||
pcap_lookupdev(pc_err); | ||||
#endif | #endif | |||
if (re_match_word) { | if (!dev) { | |||
char *word_regex = malloc(strlen(match_data) * 3 + strlen(WORD_R | perror(pc_err); | |||
EGEX)); | return 1; | |||
sprintf(word_regex, WORD_REGEX, match_data, match_data, match_da | } | |||
ta); | ||||
match_data = word_regex; | ||||
} | ||||
#if USE_PCRE | ||||
pattern = pcre_compile(match_data, pcre_options, (const char **)&re_ | ||||
err, &err_offset, 0); | ||||
if (!pattern) { | if ((pd = pcap_open_live(dev, snaplen, promisc, to, pc_err)) == NULL) { | |||
fprintf(stderr, "compile failed: %s\n", re_err); | perror(pc_err); | |||
clean_exit(-1); | return 1; | |||
} | } | |||
pattern_extra = pcre_study(pattern, 0, (const char **)&re_err); | if (pcap_lookupnet(dev, &net.s_addr, &mask.s_addr, pc_err) == -1) { | |||
#else | perror(pc_err); | |||
re_err = re_compile_pattern(match_data, strlen(match_data), &pattern | memset(&net, 0, sizeof(net)); | |||
); | memset(&mask, 0, sizeof(mask)); | |||
if (re_err) { | } | |||
fprintf(stderr, "regex compile: %s\n", re_err); | ||||
clean_exit(-1); | ||||
} | ||||
pattern.fastmap = (char*)malloc(256); | if (quiet < 2) { | |||
if (re_compile_fastmap(&pattern)) { | printf("interface: %s", dev); | |||
perror("fastmap compile failed"); | if (net.s_addr && mask.s_addr) { | |||
clean_exit(-1); | printf(" (%s/", inet_ntoa(net)); | |||
printf("%s)", inet_ntoa(mask)); | ||||
} | } | |||
#endif | printf("\n"); | |||
match_func = &re_match_func; | ||||
} | } | |||
if (quiet < 2 && match_data && strlen(match_data)) | ||||
printf("%smatch: %s%s\n", invert_match?"don't ":"", | ||||
(bin_data && !strchr(match_data, 'x'))?"0x":"", match_data); | ||||
} | } | |||
if (filter) free(filter); | ||||
if (re_match_word) free(match_data); | ||||
switch(pcap_datalink(pd)) { | switch(pcap_datalink(pd)) { | |||
case DLT_EN10MB: | case DLT_EN10MB: | |||
link_offset = ETHHDR_SIZE; | link_offset = ETHHDR_SIZE; | |||
break; | break; | |||
case DLT_IEEE802: | case DLT_IEEE802: | |||
link_offset = TOKENRING_SIZE; | link_offset = TOKENRING_SIZE; | |||
break; | break; | |||
case DLT_FDDI: | case DLT_FDDI: | |||
skipping to change at line 565 | skipping to change at line 512 | |||
#if HAVE_DLT_RAW | #if HAVE_DLT_RAW | |||
case DLT_RAW: | case DLT_RAW: | |||
link_offset = RAWHDR_SIZE; | link_offset = RAWHDR_SIZE; | |||
break; | break; | |||
#endif | #endif | |||
#if HAVE_DLT_LINUX_SLL | #if HAVE_DLT_LINUX_SLL | |||
case DLT_LINUX_SLL: | case DLT_LINUX_SLL: | |||
link_offset = ISDNHDR_SIZE; | link_offset = ISDNHDR_SIZE; | |||
include_vlan = 0; | ||||
break; | break; | |||
#endif | #endif | |||
#if HAVE_DLT_IEEE802_11_RADIO | #if HAVE_DLT_IEEE802_11_RADIO | |||
case DLT_IEEE802_11_RADIO: | case DLT_IEEE802_11_RADIO: | |||
radiotap_present = 1; | radiotap_present = 1; | |||
#endif | #endif | |||
#if HAVE_DLT_IEEE802_11 | #if HAVE_DLT_IEEE802_11 | |||
case DLT_IEEE802_11: | case DLT_IEEE802_11: | |||
link_offset = IEEE80211HDR_SIZE; | link_offset = IEEE80211HDR_SIZE; | |||
break; | break; | |||
#endif | #endif | |||
#if HAVE_DLT_PFLOG | ||||
case DLT_PFLOG: | ||||
link_offset = PFLOGHDR_SIZE; | ||||
break; | ||||
#endif | ||||
#if HAVE_DLT_IPNET | ||||
case DLT_IPNET: | ||||
link_offset = IPNETHDR_SIZE; | ||||
include_vlan = 0; | ||||
break; | ||||
#endif | ||||
default: | default: | |||
fprintf(stderr, "fatal: unsupported interface type %u\n", pcap_datal ink(pd)); | fprintf(stderr, "fatal: unsupported interface type %u\n", pcap_datal ink(pd)); | |||
clean_exit(-1); | return 1; | |||
} | } | |||
if (dump_file) { | return 0; | |||
if (!(pd_dump = pcap_dump_open(pd, dump_file))) { | } | |||
fprintf(stderr, "fatal: %s\n", pcap_geterr(pd)); | ||||
clean_exit(-1); | ||||
} else printf("output: %s\n", dump_file); | ||||
} | ||||
#if !defined(_WIN32) | int setup_bpf_filter(char **argv) { | |||
update_windowsize(0); | if (filter_file) { | |||
#endif | char buf[1024] = {0}; | |||
FILE *f = fopen(filter_file, "r"); | ||||
#if defined(_WIN32) | if (!f || !fgets(buf, sizeof(buf)-1, f)) { | |||
win32_initwinsock(); | fprintf(stderr, "fatal: unable to get filter from %s: %s\n", filter_ | |||
file, strerror(errno)); | ||||
usage(); | ||||
} | ||||
fclose(f); | ||||
filter = get_filter_from_string(buf); | ||||
if (pcap_compile(pd, &pcapfilter, filter, 0, mask.s_addr)) | ||||
return 1; | ||||
} else if (argv[optind]) { | ||||
filter = get_filter_from_argv(&argv[optind]); | ||||
if (pcap_compile(pd, &pcapfilter, filter, 0, mask.s_addr)) { | ||||
free(filter); | ||||
filter = get_filter_from_argv(&argv[optind-1]); | ||||
#if USE_PCAP_RESTART | ||||
PCAP_RESTART_FUNC(); | ||||
#endif | #endif | |||
#if !defined(_WIN32) && USE_DROPPRIVS | if (pcap_compile(pd, &pcapfilter, filter, 0, mask.s_addr)) | |||
drop_privs(); | return 1; | |||
match_data = NULL; | ||||
} | ||||
} else { | ||||
filter = include_vlan ? strdup(BPF_TEMPLATE_IP_VLAN) : strdup(BPF_TEMPLA | ||||
TE_IP); | ||||
if (pcap_compile(pd, &pcapfilter, filter, 0, mask.s_addr)) | ||||
return 1; | ||||
} | ||||
if (pcap_setfilter(pd, &pcapfilter)) | ||||
return 1; | ||||
return 0; | ||||
} | ||||
int setup_matcher(void) { | ||||
if (bin_match) { | ||||
uint32_t i = 0, n; | ||||
uint32_t len; | ||||
char *s, *d; | ||||
if (re_match_word || re_ignore_case) { | ||||
fprintf(stderr, "fatal: regex switches are incompatible with binary | ||||
matching\n"); | ||||
return 1; | ||||
} | ||||
len = (uint32_t)strlen(match_data); | ||||
if (len % 2 != 0 || !strishex(match_data)) { | ||||
fprintf(stderr, "fatal: invalid hex string specified\n"); | ||||
return 1; | ||||
} | ||||
bin_data = (char*)malloc(len / 2); | ||||
memset(bin_data, 0, len / 2); | ||||
d = bin_data; | ||||
if ((s = strchr(match_data, 'x'))) | ||||
len -= (uint32_t)(++s - match_data - 1); | ||||
else s = match_data; | ||||
while (i <= len) { | ||||
sscanf(s+i, "%2x", &n); | ||||
*d++ = n; | ||||
i += 2; | ||||
} | ||||
match_len = len / 2; | ||||
match_func = &bin_match_func; | ||||
} else { | ||||
#if USE_PCRE | ||||
uint32_t pcre_options = PCRE_UNGREEDY; | ||||
if (re_ignore_case) | ||||
pcre_options |= PCRE_CASELESS; | ||||
if (re_multiline_match) | ||||
pcre_options |= PCRE_DOTALL; | ||||
#else | ||||
re_syntax_options = RE_CHAR_CLASSES | RE_NO_BK_PARENS | RE_NO_BK_VBAR | | ||||
RE_CONTEXT_INDEP_ANCHORS | RE_CONTEXT_INDEP_OPS; | ||||
if (re_multiline_match) | ||||
re_syntax_options |= RE_DOT_NEWLINE; | ||||
if (re_ignore_case) { | ||||
uint32_t i; | ||||
char *s; | ||||
pattern.translate = (char*)malloc(256); | ||||
s = pattern.translate; | ||||
for (i = 0; i < 256; i++) | ||||
s[i] = i; | ||||
for (i = 'A'; i <= 'Z'; i++) | ||||
s[i] = i + 32; | ||||
s = match_data; | ||||
while (*s) { | ||||
*s = tolower(*s); | ||||
s++; | ||||
} | ||||
} else pattern.translate = NULL; | ||||
#endif | #endif | |||
while (pcap_loop(pd, 0, (pcap_handler)process, 0)); | if (re_match_word) { | |||
char *word_regex = (char*)malloc(strlen(match_data) * 3 + strlen(WOR | ||||
D_REGEX)); | ||||
sprintf(word_regex, WORD_REGEX, match_data, match_data, match_data); | ||||
match_data = word_regex; | ||||
} | ||||
clean_exit(0); | #if USE_PCRE | |||
pattern = pcre_compile(match_data, pcre_options, (const char **)&re_err, | ||||
&err_offset, 0); | ||||
if (!pattern) { | ||||
fprintf(stderr, "compile failed: %s\n", re_err); | ||||
return 1; | ||||
} | ||||
pattern_extra = pcre_study(pattern, 0, (const char **)&re_err); | ||||
#else | ||||
re_err = re_compile_pattern(match_data, strlen(match_data), &pattern); | ||||
if (re_err) { | ||||
fprintf(stderr, "regex compile: %s\n", re_err); | ||||
return 1; | ||||
} | ||||
pattern.fastmap = (char*)malloc(256); | ||||
if (re_compile_fastmap(&pattern)) { | ||||
perror("fastmap compile failed"); | ||||
return 1; | ||||
} | ||||
#endif | ||||
match_func = &re_match_func; | ||||
} | ||||
/* NOT REACHED */ | ||||
return 0; | return 0; | |||
} | } | |||
static inline uint8_t vlan_frame_count(u_char *p, uint16_t limit) { | ||||
uint8_t *et = (uint8_t*)(p + 12); | ||||
uint16_t ether_type = EXTRACT_16BITS(et); | ||||
uint8_t count = 0; | ||||
while ((void*)et < (void*)(p + limit) && | ||||
ether_type != ETHERTYPE_IP && | ||||
ether_type != ETHERTYPE_IPV6) { | ||||
count++; | ||||
et += VLANHDR_SIZE; | ||||
ether_type = EXTRACT_16BITS(et); | ||||
} | ||||
return count; | ||||
} | ||||
void process(u_char *d, struct pcap_pkthdr *h, u_char *p) { | void process(u_char *d, struct pcap_pkthdr *h, u_char *p) { | |||
struct ip *ip4_pkt = (struct ip *) (p + link_offset); | uint8_t vlan_offset = include_vlan ? vlan_frame_count(p, h->caplen) * VLANHD | |||
R_SIZE : 0; | ||||
struct ip *ip4_pkt = (struct ip *) (p + link_offset + vlan_offset); | ||||
#if USE_IPv6 | #if USE_IPv6 | |||
struct ip6_hdr *ip6_pkt = (struct ip6_hdr*)(p + link_offset); | struct ip6_hdr *ip6_pkt = (struct ip6_hdr*)(p + link_offset + vlan_offset); | |||
#endif | #endif | |||
uint32_t ip_ver; | uint32_t ip_ver; | |||
uint8_t ip_proto = 0; | uint8_t ip_proto = 0; | |||
uint32_t ip_hl = 0; | uint32_t ip_hl = 0; | |||
uint32_t ip_off = 0; | uint32_t ip_off = 0; | |||
uint8_t fragmented = 0; | uint8_t fragmented = 0; | |||
uint16_t frag_offset = 0; | uint16_t frag_offset = 0; | |||
uint32_t frag_id = 0; | uint32_t frag_id = 0; | |||
char ip_src[INET6_ADDRSTRLEN + 1], | char ip_src[INET6_ADDRSTRLEN + 1], | |||
ip_dst[INET6_ADDRSTRLEN + 1]; | ip_dst[INET6_ADDRSTRLEN + 1]; | |||
unsigned char *data; | unsigned char *data; | |||
uint32_t len = h->caplen; | uint32_t len = h->caplen - vlan_offset; | |||
seen_frames++; | ||||
#if HAVE_DLT_IEEE802_11_RADIO | #if HAVE_DLT_IEEE802_11_RADIO | |||
if (radiotap_present) { | if (radiotap_present) { | |||
uint16_t radio_len = ((struct NGREP_rtaphdr_t *)(p))->it_len; | uint16_t radio_len = ((struct NGREP_rtaphdr_t *)(p))->it_len; | |||
ip4_pkt = (struct ip *)(p + link_offset + radio_len); | ip4_pkt = (struct ip *)(p + link_offset + radio_len); | |||
len -= radio_len; | len -= radio_len; | |||
} | } | |||
#endif | #endif | |||
ip_ver = ip4_pkt->ip_v; | ip_ver = ip4_pkt->ip_v; | |||
skipping to change at line 699 | skipping to change at line 810 | |||
} | } | |||
switch (ip_proto) { | switch (ip_proto) { | |||
case IPPROTO_TCP: { | case IPPROTO_TCP: { | |||
struct tcphdr *tcp_pkt = (struct tcphdr *)((unsigned char *)(ip4_pkt ) + ip_hl); | struct tcphdr *tcp_pkt = (struct tcphdr *)((unsigned char *)(ip4_pkt ) + ip_hl); | |||
uint16_t tcphdr_offset = (frag_offset) ? 0 : (tcp_pkt->th_off * 4); | uint16_t tcphdr_offset = (frag_offset) ? 0 : (tcp_pkt->th_off * 4); | |||
data = (unsigned char *)(tcp_pkt) + tcphdr_offset; | data = (unsigned char *)(tcp_pkt) + tcphdr_offset; | |||
len -= link_offset + ip_hl + tcphdr_offset; | len -= link_offset + ip_hl + tcphdr_offset; | |||
#if USE_IPv6 | ||||
if (ip_ver == 6) | ||||
len -= ntohs(ip6_pkt->ip6_plen); | ||||
#endif | ||||
if ((int32_t)len < 0) | if ((int32_t)len < 0) | |||
len = 0; | len = 0; | |||
dump_packet(h, p, ip_proto, data, len, | dump_packet(h, p, ip_proto, data, len, | |||
ip_src, ip_dst, ntohs(tcp_pkt->th_sport), ntohs(tcp_pkt- >th_dport), tcp_pkt->th_flags, | ip_src, ip_dst, ntohs(tcp_pkt->th_sport), ntohs(tcp_pkt- >th_dport), tcp_pkt->th_flags, | |||
tcphdr_offset, fragmented, frag_offset, frag_id); | tcphdr_offset, fragmented, frag_offset, frag_id); | |||
} break; | } break; | |||
case IPPROTO_UDP: { | case IPPROTO_UDP: { | |||
struct udphdr *udp_pkt = (struct udphdr *)((unsigned char *)(ip4_pkt ) + ip_hl); | struct udphdr *udp_pkt = (struct udphdr *)((unsigned char *)(ip4_pkt ) + ip_hl); | |||
uint16_t udphdr_offset = (frag_offset) ? 0 : sizeof(*udp_pkt); | uint16_t udphdr_offset = (frag_offset) ? 0 : sizeof(*udp_pkt); | |||
data = (unsigned char *)(udp_pkt) + udphdr_offset; | data = (unsigned char *)(udp_pkt) + udphdr_offset; | |||
len -= link_offset + ip_hl + udphdr_offset; | len -= link_offset + ip_hl + udphdr_offset; | |||
#if USE_IPv6 | ||||
if (ip_ver == 6) | ||||
len -= ntohs(ip6_pkt->ip6_plen); | ||||
#endif | ||||
if ((int32_t)len < 0) | if ((int32_t)len < 0) | |||
len = 0; | len = 0; | |||
dump_packet(h, p, ip_proto, data, len, ip_src, ip_dst, | dump_packet(h, p, ip_proto, data, len, ip_src, ip_dst, | |||
#if HAVE_DUMB_UDPHDR | ||||
ntohs(udp_pkt->source), ntohs(udp_pkt->dest), 0, | ||||
#else | ||||
ntohs(udp_pkt->uh_sport), ntohs(udp_pkt->uh_dport), 0, | ntohs(udp_pkt->uh_sport), ntohs(udp_pkt->uh_dport), 0, | |||
#endif | ||||
udphdr_offset, fragmented, frag_offset, frag_id); | udphdr_offset, fragmented, frag_offset, frag_id); | |||
} break; | } break; | |||
case IPPROTO_ICMP: { | case IPPROTO_ICMP: { | |||
struct icmp *icmp4_pkt = (struct icmp *)((unsigned char *)(ip4_pkt ) + ip_hl); | struct icmp *icmp4_pkt = (struct icmp *)((unsigned char *)(ip4_pkt ) + ip_hl); | |||
uint16_t icmp4hdr_offset = (frag_offset) ? 0 : 4; | uint16_t icmp4hdr_offset = (frag_offset) ? 0 : 4; | |||
data = (unsigned char *)(icmp4_pkt) + icmp4hdr_offset; | data = (unsigned char *)(icmp4_pkt) + icmp4hdr_offset; | |||
len -= link_offset + ip_hl + icmp4hdr_offset; | len -= link_offset + ip_hl + icmp4hdr_offset; | |||
skipping to change at line 757 | skipping to change at line 854 | |||
ip_src, ip_dst, icmp4_pkt->icmp_type, icmp4_pkt->icmp_co de, 0, | ip_src, ip_dst, icmp4_pkt->icmp_type, icmp4_pkt->icmp_co de, 0, | |||
icmp4hdr_offset, fragmented, frag_offset, frag_id); | icmp4hdr_offset, fragmented, frag_offset, frag_id); | |||
} break; | } break; | |||
#if USE_IPv6 | #if USE_IPv6 | |||
case IPPROTO_ICMPV6: { | case IPPROTO_ICMPV6: { | |||
struct icmp6_hdr *icmp6_pkt = (struct icmp6_hdr *)((unsigned char *) (ip6_pkt) + ip_hl); | struct icmp6_hdr *icmp6_pkt = (struct icmp6_hdr *)((unsigned char *) (ip6_pkt) + ip_hl); | |||
uint16_t icmp6hdr_offset = (frag_offset) ? 0 : 4; | uint16_t icmp6hdr_offset = (frag_offset) ? 0 : 4; | |||
data = (unsigned char *)(icmp6_pkt) + icmp6hdr_offset; | data = (unsigned char *)(icmp6_pkt) + icmp6hdr_offset; | |||
len -= link_offset + ip_hl + ntohs(ip6_pkt->ip6_plen) + icmp6hdr_off set; | len -= link_offset + ip_hl + icmp6hdr_offset; | |||
if ((int32_t)len < 0) | if ((int32_t)len < 0) | |||
len = 0; | len = 0; | |||
dump_packet(h, p, ip_proto, data, len, | dump_packet(h, p, ip_proto, data, len, | |||
ip_src, ip_dst, icmp6_pkt->icmp6_type, icmp6_pkt->icmp6_ code, 0, | ip_src, ip_dst, icmp6_pkt->icmp6_type, icmp6_pkt->icmp6_ code, 0, | |||
icmp6hdr_offset, fragmented, frag_offset, frag_id); | icmp6hdr_offset, fragmented, frag_offset, frag_id); | |||
} break; | } break; | |||
#endif | #endif | |||
skipping to change at line 808 | skipping to change at line 905 | |||
clean_exit(0); | clean_exit(0); | |||
if (match_after && keep_matching) | if (match_after && keep_matching) | |||
keep_matching--; | keep_matching--; | |||
} | } | |||
void dump_packet(struct pcap_pkthdr *h, u_char *p, uint8_t proto, unsigned char *data, uint32_t len, | void dump_packet(struct pcap_pkthdr *h, u_char *p, uint8_t proto, unsigned char *data, uint32_t len, | |||
const char *ip_src, const char *ip_dst, uint16_t sport, uint16_ t dport, uint8_t flags, | const char *ip_src, const char *ip_dst, uint16_t sport, uint16_ t dport, uint8_t flags, | |||
uint16_t hdr_offset, uint8_t frag, uint16_t frag_offset, uint32 _t frag_id) { | uint16_t hdr_offset, uint8_t frag, uint16_t frag_offset, uint32 _t frag_id) { | |||
uint16_t match_size, match_index; | ||||
if (!show_empty && len == 0) | if (!show_empty && len == 0) | |||
return; | return; | |||
if (len > limitlen) | if (len > limitlen) | |||
len = limitlen; | len = limitlen; | |||
if ((len > 0 && match_func(data, len) == invert_match) && !keep_matching) | if ((len > 0 && match_func(data, len, &match_index, &match_size) == invert_m atch) && !keep_matching) | |||
return; | return; | |||
if (!live_read && want_delay) | if (!live_read && want_delay) | |||
dump_delay(h); | dump_delay(h); | |||
{ | { | |||
char ident; | char ident; | |||
switch (proto) { | switch (proto) { | |||
case IPPROTO_TCP: ident = TCP; break; | case IPPROTO_TCP: ident = TCP; break; | |||
skipping to change at line 876 | skipping to change at line 975 | |||
printf(" %u:%u", sport, dport); | printf(" %u:%u", sport, dport); | |||
} | } | |||
if (frag) | if (frag) | |||
printf(" %s%u@%u:%u", | printf(" %s%u@%u:%u", | |||
frag_offset?"+":"", frag_id, frag_offset, len); | frag_offset?"+":"", frag_id, frag_offset, len); | |||
if (dump_single) | if (dump_single) | |||
printf(" "); | printf(" "); | |||
else | else | |||
printf("\n"); | printf(" #%u\n", seen_frames); | |||
if (quiet < 3) | if (quiet < 3) | |||
dump_func(data, len); | dump_func(data, len, match_index, match_size); | |||
if (pd_dump) | if (pd_dump) | |||
pcap_dump((u_char*)pd_dump, h, p); | pcap_dump((u_char*)pd_dump, h, p); | |||
#if USE_TCPKILL | ||||
if (tcpkill_active) | ||||
tcpkill_kill(h, p, link_offset, tcpkill_active); | ||||
#endif | ||||
} | } | |||
int8_t re_match_func(unsigned char *data, uint32_t len) { | int8_t re_match_func(unsigned char *data, uint32_t len, uint16_t *mindex, uint16 _t *msize) { | |||
#if USE_PCRE | #if USE_PCRE | |||
switch(pcre_exec(pattern, 0, data, (int32_t)len, 0, 0, 0, 0)) { | ||||
static int sub[2]; | ||||
switch(pcre_exec(pattern, 0, (char const *)data, (int32_t)len, 0, 0, 0, 0)) | ||||
{ | ||||
case PCRE_ERROR_NULL: | case PCRE_ERROR_NULL: | |||
case PCRE_ERROR_BADOPTION: | case PCRE_ERROR_BADOPTION: | |||
case PCRE_ERROR_BADMAGIC: | case PCRE_ERROR_BADMAGIC: | |||
case PCRE_ERROR_UNKNOWN_NODE: | case PCRE_ERROR_UNKNOWN_NODE: | |||
case PCRE_ERROR_NOMEMORY: | case PCRE_ERROR_NOMEMORY: | |||
perror("she's dead, jim\n"); | perror("she's dead, jim\n"); | |||
clean_exit(-2); | clean_exit(2); | |||
case PCRE_ERROR_NOMATCH: | case PCRE_ERROR_NOMATCH: | |||
return 0; | return 0; | |||
default: | ||||
*mindex = sub[0]; | ||||
*msize = sub[1] - sub[0]; | ||||
} | } | |||
#else | #else | |||
switch (re_search(&pattern, data, (int32_t)len, 0, len, 0)) { | ||||
static struct re_registers regs; | ||||
switch (re_search(&pattern, (char const *)data, (int32_t)len, 0, len, ®s) | ||||
) { | ||||
case -2: | case -2: | |||
perror("she's dead, jim\n"); | perror("she's dead, jim\n"); | |||
clean_exit(-2); | clean_exit(2); | |||
case -1: | case -1: | |||
return 0; | return 0; | |||
default: | ||||
*mindex = regs.start[0]; | ||||
*msize = regs.end[0] - regs.start[0]; | ||||
} | } | |||
#endif | #endif | |||
if (max_matches) | matches++; | |||
matches++; | ||||
if (match_after && keep_matching != match_after) | if (match_after && keep_matching != match_after) | |||
keep_matching = match_after; | keep_matching = match_after; | |||
return 1; | return 1; | |||
} | } | |||
int8_t bin_match_func(unsigned char *data, uint32_t len) { | int8_t bin_match_func(unsigned char *data, uint32_t len, uint16_t *mindex, uint1 6_t *msize) { | |||
int32_t stop = len - match_len; | int32_t stop = len - match_len; | |||
int32_t i = 0; | int32_t i = 0; | |||
if (stop < 0) | if (stop < 0) | |||
return 0; | return 0; | |||
while (i <= stop) | while (i <= stop) | |||
if (!memcmp(data+(i++), bin_data, match_len)) { | if (!memcmp(data+(i++), bin_data, match_len)) { | |||
if (max_matches) | matches++; | |||
matches++; | ||||
if (match_after && keep_matching != match_after) | if (match_after && keep_matching != match_after) | |||
keep_matching = match_after; | keep_matching = match_after; | |||
*mindex = i - 1; | ||||
*msize = match_len; | ||||
return 1; | return 1; | |||
} | } | |||
return 0; | return 0; | |||
} | } | |||
int8_t blank_match_func(unsigned char *data, uint32_t len) { | int8_t blank_match_func(unsigned char *data, uint32_t len, uint16_t *mindex, uin | |||
if (max_matches) | t16_t *msize) { | |||
matches++; | matches++; | |||
*mindex = 0; | ||||
*msize = 0; | ||||
return 1; | return 1; | |||
} | } | |||
void dump_byline(unsigned char *data, uint32_t len) { | void dump_byline(unsigned char *data, uint32_t len, uint16_t mindex, uint16_t ms ize) { | |||
if (len > 0) { | if (len > 0) { | |||
const unsigned char *s = data; | const unsigned char *s = data; | |||
uint8_t should_hilite = (msize && enable_hilite); | ||||
unsigned char *hilite_start = data + mindex; | ||||
unsigned char *hilite_end = hilite_start + msize; | ||||
while (s < data + len) { | while (s < data + len) { | |||
if (should_hilite && s == hilite_start) | ||||
printf("%s", ANSI_hilite); | ||||
printf("%c", (*s == '\n' || isprint(*s)) ? *s : nonprint_char); | printf("%c", (*s == '\n' || isprint(*s)) ? *s : nonprint_char); | |||
s++; | s++; | |||
if (should_hilite && s == hilite_end) | ||||
printf("%s", ANSI_off); | ||||
} | } | |||
printf("\n"); | printf("\n"); | |||
} | } | |||
} | } | |||
void dump_unwrapped(unsigned char *data, uint32_t len) { | void dump_unwrapped(unsigned char *data, uint32_t len, uint16_t mindex, uint16_t msize) { | |||
if (len > 0) { | if (len > 0) { | |||
const unsigned char *s = data; | const unsigned char *s = data; | |||
uint8_t should_hilite = (msize && enable_hilite); | ||||
unsigned char *hilite_start = data + mindex; | ||||
unsigned char *hilite_end = hilite_start + msize; | ||||
while (s < data + len) { | while (s < data + len) { | |||
if (should_hilite && s == hilite_start) | ||||
printf("%s", ANSI_hilite); | ||||
printf("%c", isprint(*s) ? *s : nonprint_char); | printf("%c", isprint(*s) ? *s : nonprint_char); | |||
s++; | s++; | |||
if (should_hilite && s == hilite_end) | ||||
printf("%s", ANSI_off); | ||||
} | } | |||
printf("\n"); | printf("\n"); | |||
} | } | |||
} | } | |||
void dump_formatted(unsigned char *data, uint32_t len) { | void dump_formatted(unsigned char *data, uint32_t len, uint16_t mindex, uint16_t msize) { | |||
if (len > 0) { | if (len > 0) { | |||
unsigned char *str = data; | uint8_t should_hilite = (msize && enable_hilite); | |||
uint8_t width = show_hex ? 16 : (ws_col-5); | unsigned char *str = data; | |||
uint32_t i = 0, | uint8_t hiliting = 0; | |||
j = 0; | uint8_t width = show_hex ? 16 : (ws_col-5); | |||
uint32_t i = 0, | ||||
j = 0; | ||||
while (i < len) { | while (i < len) { | |||
printf(" "); | printf(" "); | |||
if (show_hex) | if (show_hex) { | |||
for (j = 0; j < width; j++) { | for (j = 0; j < width; j++) { | |||
if (should_hilite && (mindex <= (i+j) && (i+j) < mindex + ms | ||||
ize)) { | ||||
hiliting = 1; | ||||
printf("%s", ANSI_hilite); | ||||
} | ||||
if (i + j < len) | if (i + j < len) | |||
printf("%02x ", str[j]); | printf("%02x ", str[j]); | |||
else printf(" "); | else printf(" "); | |||
if ((j+1) % (width/2) == 0) | if ((j+1) % (width/2) == 0) | |||
printf(" "); | printf(" "); | |||
if (hiliting) { | ||||
hiliting = 0; | ||||
printf("%s", ANSI_off); | ||||
} | ||||
} | ||||
} | ||||
for (j = 0; j < width; j++) { | ||||
if (should_hilite && mindex <= (i+j) && (i+j) < mindex + msize) | ||||
{ | ||||
hiliting = 1; | ||||
printf("%s", ANSI_hilite); | ||||
} | } | |||
for (j = 0; j < width; j++) | ||||
if (i + j < len) | if (i + j < len) | |||
printf("%c", isprint(str[j]) ? str[j] : nonprint_char); | printf("%c", isprint(str[j]) ? str[j] : nonprint_char); | |||
else printf(" "); | else printf(" "); | |||
if (hiliting) { | ||||
hiliting = 0; | ||||
printf("%s", ANSI_off); | ||||
} | ||||
} | ||||
str += width; | str += width; | |||
i += j; | i += j; | |||
printf("\n"); | printf("\n"); | |||
} | } | |||
} | } | |||
} | } | |||
char *get_filter_from_string(char *str) { | char *get_filter_from_string(char *str) { | |||
const char *template = include_vlan ? BPF_TEMPLATE_USERSPEC_IP_VLAN : BPF_TE MPLATE_USERSPEC_IP; | ||||
char *mine, *s; | char *mine, *s; | |||
uint32_t len; | uint32_t len; | |||
if (!str || !*str) | if (!str || !*str) | |||
return NULL; | return NULL; | |||
len = (uint32_t)strlen(str); | len = (uint32_t)strlen(str); | |||
for (s = str; *s; s++) | for (s = str; *s; s++) | |||
if (*s == '\r' || *s == '\n') | if (*s == '\r' || *s == '\n') | |||
*s = ' '; | *s = ' '; | |||
if (!(mine = (char*)malloc(len + sizeof(BPF_MAIN_FILTER)))) | if (!(mine = (char*)malloc(len + strlen(template) + 1))) | |||
return NULL; | return NULL; | |||
memset(mine, 0, len + sizeof(BPF_MAIN_FILTER)); | memset(mine, 0, len + strlen(template) + 1); | |||
sprintf(mine, BPF_MAIN_FILTER, str); | sprintf(mine, template, str); | |||
return mine; | return mine; | |||
} | } | |||
char *get_filter_from_argv(char **argv) { | char *get_filter_from_argv(char **argv) { | |||
const char *template = include_vlan ? BPF_TEMPLATE_USERSPEC_IP_VLAN : BPF_TE MPLATE_USERSPEC_IP; | ||||
char **arg = argv, *theirs, *mine; | char **arg = argv, *theirs, *mine; | |||
char *from, *to; | char *from, *to; | |||
uint32_t len = 0; | uint32_t len = 0; | |||
if (!*arg) | if (!*arg) | |||
return NULL; | return NULL; | |||
while (*arg) | while (*arg) | |||
len += (uint32_t)strlen(*arg++) + 1; | len += (uint32_t)strlen(*arg++) + 1; | |||
if (!(theirs = (char*)malloc(len + 1)) || | if (!(theirs = (char*)malloc(len + 1)) || | |||
!(mine = (char*)malloc(len + sizeof(BPF_MAIN_FILTER)))) | !(mine = (char*)malloc(len + strlen(template) + 1))) | |||
return NULL; | return NULL; | |||
memset(theirs, 0, len + 1); | memset(theirs, 0, len + 1); | |||
memset(mine, 0, len + sizeof(BPF_MAIN_FILTER)); | memset(mine, 0, len + strlen(template) + 1); | |||
arg = argv; | arg = argv; | |||
to = theirs; | to = theirs; | |||
while ((from = *arg++)) { | while ((from = *arg++)) { | |||
while ((*to++ = *from++)); | while ((*to++ = *from++)); | |||
*(to-1) = ' '; | *(to-1) = ' '; | |||
} | } | |||
sprintf(mine, BPF_MAIN_FILTER, theirs); | sprintf(mine, template, theirs); | |||
free(theirs); | free(theirs); | |||
return mine; | return mine; | |||
} | } | |||
uint8_t strishex(char *str) { | uint8_t strishex(char *str) { | |||
char *s; | char *s; | |||
if ((s = strchr(str, 'x'))) | if ((s = strchr(str, 'x'))) | |||
s++; | s++; | |||
skipping to change at line 1101 | skipping to change at line 1264 | |||
secs--; | secs--; | |||
usecs = 1000000 - (prev_ts.tv_usec - h->ts.tv_usec); | usecs = 1000000 - (prev_ts.tv_usec - h->ts.tv_usec); | |||
} | } | |||
printf("+%u.%06u ", secs, usecs); | printf("+%u.%06u ", secs, usecs); | |||
prev_ts.tv_sec = h->ts.tv_sec; | prev_ts.tv_sec = h->ts.tv_sec; | |||
prev_ts.tv_usec = h->ts.tv_usec; | prev_ts.tv_usec = h->ts.tv_usec; | |||
} | } | |||
void print_time_offset(struct pcap_pkthdr *h) { | ||||
uint32_t secs, usecs; | ||||
secs = h->ts.tv_sec - prev_ts.tv_sec; | ||||
if (h->ts.tv_usec >= prev_ts.tv_usec) | ||||
usecs = h->ts.tv_usec - prev_ts.tv_usec; | ||||
else { | ||||
secs--; | ||||
usecs = 1000000 - (prev_ts.tv_usec - h->ts.tv_usec); | ||||
} | ||||
if (prev_ts.tv_sec == 0 && prev_ts.tv_usec == 0) { | ||||
prev_ts.tv_sec = h->ts.tv_sec; | ||||
prev_ts.tv_usec = h->ts.tv_usec; | ||||
secs = 0; | ||||
usecs = 0; | ||||
} | ||||
printf("+%u.%06u ", secs, usecs); | ||||
} | ||||
void dump_delay_proc_init(struct pcap_pkthdr *h) { | void dump_delay_proc_init(struct pcap_pkthdr *h) { | |||
dump_delay = &dump_delay_proc; | dump_delay = &dump_delay_proc; | |||
prev_delay_ts.tv_sec = h->ts.tv_sec; | prev_delay_ts.tv_sec = h->ts.tv_sec; | |||
prev_delay_ts.tv_usec = h->ts.tv_usec; | prev_delay_ts.tv_usec = h->ts.tv_usec; | |||
dump_delay(h); | dump_delay(h); | |||
} | } | |||
void dump_delay_proc(struct pcap_pkthdr *h) { | void dump_delay_proc(struct pcap_pkthdr *h) { | |||
skipping to change at line 1152 | skipping to change at line 1336 | |||
} | } | |||
#else | #else | |||
sleep(secs); | sleep(secs); | |||
usleep(usecs); | usleep(usecs); | |||
#endif | #endif | |||
prev_delay_ts.tv_sec = h->ts.tv_sec; | prev_delay_ts.tv_sec = h->ts.tv_sec; | |||
prev_delay_ts.tv_usec = h->ts.tv_usec; | prev_delay_ts.tv_usec = h->ts.tv_usec; | |||
} | } | |||
#if !defined(_WIN32) | ||||
void update_windowsize(int32_t e) { | void update_windowsize(int32_t e) { | |||
if (e == 0 && ws_col_forced) | if (e == 0 && ws_col_forced) | |||
ws_col = ws_col_forced; | ws_col = ws_col_forced; | |||
else if (!ws_col_forced) { | else if (!ws_col_forced) { | |||
#if !defined(_WIN32) | ||||
const struct winsize ws; | const struct winsize ws; | |||
if (!ioctl(0, TIOCGWINSZ, &ws)) { | if (!ioctl(0, TIOCGWINSZ, &ws)) { | |||
ws_row = ws.ws_row; | ws_row = ws.ws_row; | |||
ws_col = ws.ws_col; | ws_col = ws.ws_col; | |||
} else { | } | |||
#else | ||||
CONSOLE_SCREEN_BUFFER_INFO csbi; | ||||
if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) | ||||
{ | ||||
ws_row = csbi.dwSize.Y; | ||||
ws_col = csbi.dwSize.X; | ||||
} | ||||
#endif | ||||
else { | ||||
ws_row = 24; | ws_row = 24; | |||
ws_col = 80; | ws_col = 80; | |||
} | } | |||
} | } | |||
} | } | |||
#if USE_DROPPRIVS | #if !defined(_WIN32) && USE_DROPPRIVS | |||
void drop_privs(void) { | void drop_privs(void) { | |||
struct passwd *pw; | struct passwd *pw; | |||
uid_t newuid; | uid_t newuid; | |||
gid_t newgid; | gid_t newgid; | |||
if ((getuid() || geteuid()) || dont_dropprivs) | if ((getuid() || geteuid()) || dont_dropprivs) | |||
return; | return; | |||
pw = getpwnam(DROPPRIVS_USER); | pw = getpwnam(DROPPRIVS_USER); | |||
if (!pw) { | if (!pw) { | |||
perror("attempt to drop privileges failed: getpwnam failed"); | perror("attempt to drop privileges failed: getpwnam failed"); | |||
clean_exit(-1); | clean_exit(2); | |||
} | } | |||
newgid = pw->pw_gid; | newgid = pw->pw_gid; | |||
newuid = pw->pw_uid; | newuid = pw->pw_uid; | |||
if (getgroups(0, NULL) > 0) | if (getgroups(0, NULL) > 0) | |||
if (setgroups(1, &newgid) == -1) { | if (setgroups(1, &newgid) == -1) { | |||
perror("attempt to drop privileges failed"); | perror("attempt to drop privileges failed"); | |||
clean_exit(-1); | clean_exit(2); | |||
} | } | |||
if (((getgid() != newgid) && (setgid(newgid) == -1)) || | if (((getgid() != newgid) && (setgid(newgid) == -1)) || | |||
((getegid() != newgid) && (setegid(newgid) == -1)) || | ((getegid() != newgid) && (setegid(newgid) == -1)) || | |||
((getuid() != newuid) && (setuid(newuid) == -1)) || | ((getuid() != newuid) && (setuid(newuid) == -1)) || | |||
((geteuid() != newuid) && (seteuid(newuid) == -1))) { | ((geteuid() != newuid) && (seteuid(newuid) == -1))) { | |||
perror("attempt to drop privileges failed"); | perror("attempt to drop privileges failed"); | |||
clean_exit(-1); | clean_exit(2); | |||
} | } | |||
} | } | |||
#endif | #endif | |||
#endif | ||||
void usage(int8_t e) { | void usage(void) { | |||
printf("usage: ngrep <-" | printf("usage: ngrep <-" | |||
#if defined(_WIN32) | #if defined(_WIN32) | |||
"L" | "L" | |||
#endif | #endif | |||
"hNXViwqpevxlDtTRM> <-IO pcap_dump> <-n num> <-d dev> <-A num>\n" | "hNXViwqpevxlDtTRM> <-IO pcap_dump> <-n num> <-d dev> <-A num>\n" | |||
" <-s snaplen> <-S limitlen> <-W normal|byline|single|non e> <-c cols>\n" | " <-s snaplen> <-S limitlen> <-W normal|byline|single|non e> <-c cols>\n" | |||
" <-P char> <-F file> <match expression> <bpf filter>\n" | " <-P char> <-F file>" | |||
#if USE_TCPKILL | ||||
" <-K count>" | ||||
#endif | ||||
"\n" | ||||
" <match expression> <bpf filter>\n" | ||||
" -h is help/usage\n" | " -h is help/usage\n" | |||
" -V is version information\n" | " -V is version information\n" | |||
" -q is be quiet (don't print packet reception hash marks)\n" | " -q is be quiet (don't print packet reception hash marks)\n" | |||
" -e is show empty packets\n" | " -e is show empty packets\n" | |||
" -i is ignore case\n" | " -i is ignore case\n" | |||
" -v is invert match\n" | " -v is invert match\n" | |||
" -R is don't do privilege revocation logic\n" | " -R is don't do privilege revocation logic\n" | |||
" -x is print in alternate hexdump format\n" | " -x is print in alternate hexdump format\n" | |||
" -X is interpret match expression as hexadecimal\n" | " -X is interpret match expression as hexadecimal\n" | |||
" -w is word-regex (expression must match as a word)\n" | " -w is word-regex (expression must match as a word)\n" | |||
" -p is don't go into promiscuous mode\n" | " -p is don't go into promiscuous mode\n" | |||
" -l is make stdout line buffered\n" | " -l is make stdout line buffered\n" | |||
" -D is replay pcap_dumps with their recorded time intervals\n" | " -D is replay pcap_dumps with their recorded time intervals\n" | |||
" -t is print timestamp every time a packet is matched\n" | " -t is print timestamp every time a packet is matched\n" | |||
" -T is print delta timestamp every time a packet is matched\n" | " -T is print delta timestamp every time a packet is matched\n" | |||
" specify twice for delta from first match\n" | ||||
" -M is don't do multi-line match (do single-line match instead)\n " | " -M is don't do multi-line match (do single-line match instead)\n " | |||
" -I is read packet stream from pcap format file pcap_dump\n" | " -I is read packet stream from pcap format file pcap_dump\n" | |||
" -O is dump matched packets in pcap format to pcap_dump\n" | " -O is dump matched packets in pcap format to pcap_dump\n" | |||
" -n is look at only num packets\n" | " -n is look at only num packets\n" | |||
" -A is dump num packets after a match\n" | " -A is dump num packets after a match\n" | |||
" -s is set the bpf caplen\n" | " -s is set the bpf caplen\n" | |||
" -S is set the limitlen on matched packets\n" | " -S is set the limitlen on matched packets\n" | |||
" -W is set the dump format (normal, byline, single, none)\n" | " -W is set the dump format (normal, byline, single, none)\n" | |||
" -c is force the column width to the specified size\n" | " -c is force the column width to the specified size\n" | |||
" -P is set the non-printable display char to what is specified\n" | " -P is set the non-printable display char to what is specified\n" | |||
" -F is read the bpf filter from the specified file\n" | " -F is read the bpf filter from the specified file\n" | |||
" -N is show sub protocol number\n" | " -N is show sub protocol number\n" | |||
#if defined(_WIN32) | #if defined(_WIN32) | |||
" -d is use specified device (index) instead of the pcap default\n " | " -d is use specified device (index) instead of the pcap default\n " | |||
" -L is show the winpcap device list index\n" | " -L is show the winpcap device list index\n" | |||
#else | #else | |||
" -d is use specified device instead of the pcap default\n" | " -d is use specified device instead of the pcap default\n" | |||
#endif | #endif | |||
#if USE_TCPKILL | ||||
" -K is send N packets to kill observed connections\n" | ||||
#endif | ||||
""); | ""); | |||
exit(e); | exit(2); | |||
} | } | |||
void version(void) { | void version(void) { | |||
printf("ngrep: V%s, %s\n", VERSION, rcsver); | printf("ngrep: V%s, %s\n", VERSION, pcap_lib_version()); | |||
exit(0); | exit(0); | |||
} | } | |||
void clean_exit(int32_t sig) { | void clean_exit(int32_t sig) { | |||
struct pcap_stat s; | struct pcap_stat s; | |||
signal(SIGINT, SIG_IGN); | signal(SIGINT, SIG_IGN); | |||
signal(SIGABRT, SIG_IGN); | signal(SIGABRT, SIG_IGN); | |||
#if !defined(_WIN32) | #if !defined(_WIN32) | |||
signal(SIGQUIT, SIG_IGN); | signal(SIGQUIT, SIG_IGN); | |||
skipping to change at line 1283 | skipping to change at line 1485 | |||
#if USE_PCRE | #if USE_PCRE | |||
if (pattern) pcre_free(pattern); | if (pattern) pcre_free(pattern); | |||
if (pattern_extra) pcre_free(pattern_extra); | if (pattern_extra) pcre_free(pattern_extra); | |||
#else | #else | |||
if (pattern.translate) free(pattern.translate); | if (pattern.translate) free(pattern.translate); | |||
if (pattern.fastmap) free(pattern.fastmap); | if (pattern.fastmap) free(pattern.fastmap); | |||
#endif | #endif | |||
if (bin_data) free(bin_data); | if (bin_data) free(bin_data); | |||
if (quiet < 1 && sig >= 0 && !read_file | /* We used to report pcap_stats; but PCAP manpage says pcap_stats "may or | |||
&& pd && !pcap_stats(pd, &s)) | may not" be accurate. So useless. :-( And confusing for a user to see | |||
printf("%u received, %u dropped\n", s.ps_recv, s.ps_drop); | counts not match what ngrep thinks. */ | |||
if (quiet < 1 && sig >= 0 && !read_file) | ||||
if (pd) pcap_close(pd); | printf("%u received, %u matched\n", seen_frames, matches); | |||
if (pd_dump) pcap_dump_close(pd_dump); | ||||
if (pd) pcap_close(pd); | ||||
if (pd_dumppcap) pcap_close(pd_dumppcap); | ||||
if (pd_dump) pcap_dump_close(pd_dump); | ||||
#if defined(_WIN32) | #if defined(_WIN32) | |||
if (delay_socket) closesocket(delay_socket); | if (delay_socket) closesocket(delay_socket); | |||
if (want_delay) WSACleanup(); | if (want_delay) WSACleanup(); | |||
if (usedev) free(usedev); | if (usedev) free(usedev); | |||
#endif | #endif | |||
exit(sig); | exit(matches ? 0 : 1); | |||
} | } | |||
#if defined(_WIN32) | #if defined(_WIN32) | |||
int8_t win32_initwinsock(void) { | int8_t win32_initwinsock(void) { | |||
WORD wVersionRequested = MAKEWORD(2, 0); | WORD wVersionRequested = MAKEWORD(2, 0); | |||
WSADATA wsaData; | WSADATA wsaData; | |||
if (WSAStartup(wVersionRequested, &wsaData)) { | if (WSAStartup(wVersionRequested, &wsaData)) { | |||
perror("unable to initialize winsock"); | perror("unable to initialize winsock"); | |||
return 0; | return 0; | |||
skipping to change at line 1327 | skipping to change at line 1532 | |||
return 1; | return 1; | |||
} | } | |||
void win32_listdevices(void) { | void win32_listdevices(void) { | |||
uint32_t i = 0; | uint32_t i = 0; | |||
pcap_if_t *alldevs, *d; | pcap_if_t *alldevs, *d; | |||
char errbuf[PCAP_ERRBUF_SIZE]; | char errbuf[PCAP_ERRBUF_SIZE]; | |||
if (pcap_findalldevs(&alldevs, errbuf) == -1) { | if (pcap_findalldevs(&alldevs, errbuf) == -1) { | |||
perror("unable to enumerate device list"); | perror("unable to enumerate device list"); | |||
clean_exit(-1); | clean_exit(2); | |||
} | } | |||
printf("idx\tdev\n"); | printf("idx\tdev\n"); | |||
printf("---\t---\n"); | printf("---\t---\n"); | |||
for (d = alldevs; d != NULL; d = d->next) { | for (d = alldevs; d != NULL; d = d->next) { | |||
printf("%2u:\t%s", ++i, d->name); | printf("%2u:\t%s", ++i, d->name); | |||
if (d->description) | if (d->description) | |||
printf(" (%s)\n", d->description); | printf(" (%s)\n", d->description); | |||
skipping to change at line 1351 | skipping to change at line 1556 | |||
} | } | |||
char *win32_usedevice(const char *index) { | char *win32_usedevice(const char *index) { | |||
int32_t idx = atoi(index), i = 0; | int32_t idx = atoi(index), i = 0; | |||
pcap_if_t *alldevs, *d; | pcap_if_t *alldevs, *d; | |||
char errbuf[PCAP_ERRBUF_SIZE]; | char errbuf[PCAP_ERRBUF_SIZE]; | |||
char *dev = NULL; | char *dev = NULL; | |||
if (idx <= 0) { | if (idx <= 0) { | |||
perror("invalid device index"); | perror("invalid device index"); | |||
clean_exit(-1); | clean_exit(2); | |||
} | } | |||
if (pcap_findalldevs(&alldevs, errbuf) == -1) { | if (pcap_findalldevs(&alldevs, errbuf) == -1) { | |||
perror("unable to enumerate devices"); | perror("unable to enumerate devices"); | |||
clean_exit(-1); | clean_exit(2); | |||
} | } | |||
for (d = alldevs; d != NULL && i != idx; d = d->next) | for (d = alldevs; d != NULL && i != idx; d = d->next) | |||
if (++i == idx) | if (++i == idx) | |||
dev = _strdup(d->name); | dev = _strdup(d->name); | |||
if (i <= 0) { | if (i <= 0) { | |||
perror("no known devices"); | perror("no known devices"); | |||
clean_exit(-1); | clean_exit(2); | |||
} | } | |||
if (i != idx) { | if (i != idx) { | |||
perror("unknown device specified"); | perror("unknown device specified"); | |||
clean_exit(-1); | clean_exit(2); | |||
} | } | |||
pcap_freealldevs(alldevs); | pcap_freealldevs(alldevs); | |||
return dev; | return dev; | |||
} | } | |||
char *win32_choosedevice(void) { | ||||
pcap_if_t *alldevs, *d; | ||||
char errbuf[PCAP_ERRBUF_SIZE]; | ||||
char *dev = NULL; | ||||
if (pcap_findalldevs(&alldevs, errbuf) == -1) { | ||||
perror("unable to enumerate devices"); | ||||
clean_exit(2); | ||||
} | ||||
for (d = alldevs; d != NULL; d = d->next) | ||||
if ((d->addresses) && (d->addresses->addr)) | ||||
dev = _strdup(d->name); | ||||
pcap_freealldevs(alldevs); | ||||
if (!dev) | ||||
dev = pcap_lookupdev(errbuf); | ||||
return dev; | ||||
} | ||||
#endif | #endif | |||
End of changes. 148 change blocks. | ||||
297 lines changed or deleted | 530 lines changed or added |