ongrep

A cleaned up fork of ngrep for OpenBSD
git clone git://git.sgregoratto.me/ongrep
Log | Files | Refs | README | LICENSE

ngrep.c (28663B)


      1 /*
      2  * Copyright (c) 2017  Jordan Ritter <jpr5@darkridge.com>
      3  * Copyright (c) 2020  Stephen Gregoratto <dev@sgregoratto.me>
      4  *
      5  * Please refer to the LICENSE file for more information.
      6  *
      7  */
      8 #include <sys/types.h>
      9 #include <sys/ioctl.h>
     10 #include <sys/limits.h>
     11 #include <sys/socket.h>
     12 #include <sys/stat.h>
     13 
     14 #include <net/if.h>
     15 
     16 #include <netinet/in.h>
     17 #include <netinet/icmp6.h>
     18 #include <netinet/if_ether.h>
     19 #include <netinet/igmp.h>
     20 #include <netinet/ip.h>
     21 #include <netinet/ip6.h>
     22 #include <netinet/ip_icmp.h>
     23 #include <netinet/tcp.h>
     24 #include <netinet/udp.h>
     25 
     26 #include <net80211/ieee80211_radiotap.h>
     27 
     28 #include <arpa/inet.h>
     29 
     30 #include <ctype.h>
     31 #include <err.h>
     32 #include <errno.h>
     33 #include <fcntl.h>
     34 #include <pcap.h>
     35 #include <pcre.h>
     36 #include <pwd.h>
     37 #include <signal.h>
     38 #include <stdbool.h>
     39 #include <stdint.h>
     40 #include <stdio.h>
     41 #include <stdlib.h>
     42 #include <string.h>
     43 #include <time.h>
     44 #include <unistd.h>
     45 
     46 #include "ngrep.h"
     47 
     48 /* Configuration Options */
     49 bool		re_match_word = false;
     50 bool		re_ignore_case = false;
     51 bool		re_multiline_match = true;
     52 bool		promisc = true;
     53 bool		show_empty = false;
     54 bool		show_hex = false;
     55 bool		show_proto = false;
     56 bool		invert_match = false;
     57 bool		bin_match = false;
     58 bool		live_read = true;
     59 bool		want_delay = false;
     60 bool		highlight = false;
     61 
     62 size_t		keep_matching = 0;
     63 size_t		match_after = 0;
     64 size_t		matches = 0;
     65 size_t		max_matches = 0;
     66 size_t		seen_frames = 0;
     67 
     68 uint32_t	limitlen = 65535;
     69 char		nonprint_char = '.';
     70 uint32_t	snaplen = 65535;
     71 int		quiet = 0;
     72 
     73 char		*read_file = NULL;
     74 char		*dump_file = NULL;
     75 char		*usedev = NULL;
     76 
     77 /* PCRE and matching */
     78 int		 err_offset;
     79 const char	*re_err = NULL;
     80 
     81 pcre		*pattern = NULL;
     82 pcre_extra	*pattern_extra = NULL;
     83 
     84 char		*match_data = NULL;
     85 char		*bin_data = NULL;
     86 bool		 add_hex_exp_pfx = true;
     87 size_t		 match_len = 0;
     88 match_func	 matcher = blank_match_func;
     89 
     90 bool		dump_single = false;
     91 char_cmp_func	char_cmp = &isprint;
     92 dump_func	dumper = &dump_formatted;
     93 
     94 /* BPF/Network */
     95 char		*filter = NULL;
     96 char		*filter_file = NULL;
     97 char		 pc_err[PCAP_ERRBUF_SIZE];
     98 size_t		 link_offset;
     99 bool		 radiotap_present = false;
    100 bool		 include_vlan = true;
    101 
    102 pcap_t			*pd = NULL;
    103 pcap_t			*pd_dumppcap = NULL;
    104 pcap_dumper_t		*pd_dump = NULL;
    105 struct bpf_program	 pcapfilter;
    106 struct in_addr		 net, mask;
    107 
    108 /* Timestamp/delay functionality */
    109 struct timeval	prev_ts = {0, 0};
    110 struct timeval	prev_delay_ts = {0, 0};
    111 delay_func	dump_delay = dump_delay_proc_init;
    112 ts_func		print_time = NULL;
    113 
    114 /*
    115  * Window-size functionality
    116  * (adjust output based on width of console display)
    117  */
    118 uint32_t	ws_row, ws_col = 80, ws_col_forced = 0;
    119 
    120 const char	*optstring = "A:Cc:d:DeF:hiI:lMn:NO:pP:qs:S:tTvwW:xX";
    121 
    122 int
    123 main(int argc, char **argv)
    124 {
    125 	int c;
    126 	const char *errstr;
    127 
    128 	if (unveil("/etc/services", "r") == -1)
    129 		err(2, "unveil");
    130 	if (unveil("/etc/protocols", "r") == -1)
    131 		err(2, "unveil");
    132 	if (unveil("/etc/pwd.db", "r") == -1)
    133 		err(2, "unveil");
    134 	/*
    135 	 * XXX: pcap_open_live opens /dev/bpf as RW,
    136 	 * even though we don't write to it.
    137 	 *
    138 	 * The base programs work around this by implementing their own version
    139 	 * of pcap_open_live and setting the hidden members of pcap_t. Lame.
    140 	 */
    141 	if (unveil("/dev/bpf", "rw") == -1)
    142 		err(1, "unveil");
    143 	if (unveil("/var/empty", "r") == -1)
    144 		err(1, "unveil");
    145 
    146 	signal(SIGINT, clean_exit);
    147 	signal(SIGABRT, clean_exit);
    148 	signal(SIGQUIT, clean_exit);
    149 	signal(SIGPIPE, clean_exit);
    150 	signal(SIGWINCH, update_windowsize);
    151 
    152 	highlight = isatty(STDOUT_FILENO);
    153 
    154 	while ((c = getopt(argc, argv, optstring)) != EOF) {
    155 		switch (c) {
    156 		case 'A':
    157 			match_after = strtonum(optarg, 1, UINT32_MAX, &errstr);
    158 			if (errstr != NULL)
    159 				errx(2, "num is %s: %s", errstr, optarg);
    160 			if (match_after < UINT32_MAX)
    161 				match_after++;
    162 			break;
    163 		case 'c':
    164 			ws_col_forced = strtonum(optarg, 1, UINT32_MAX, &errstr);
    165 			if (errstr != NULL)
    166 				errx(2, "cols is %s: %s", errstr, optarg);
    167 			break;
    168 		case 'C':
    169 			highlight = true;
    170 			break;
    171 		case 'd':
    172 			usedev = optarg;
    173 			break;
    174 		case 'D':
    175 			want_delay = true;
    176 			break;
    177 		case 'e':
    178 			show_empty = true;
    179 			break;
    180 		case 'F':
    181 			filter_file = optarg;
    182 			if (unveil(filter_file, "r") == -1)
    183 				err(2, "unveil");
    184 			break;
    185 		case 'i':
    186 			re_ignore_case++;
    187 			break;
    188 		case 'I':
    189 			read_file = optarg;
    190 			if (unveil(read_file, "r") == -1)
    191 				err(2, "unveil");
    192 			break;
    193 		case 'l':
    194 			setvbuf(stdout, NULL, _IOLBF, 0);
    195 			break;
    196 		case 'M':
    197 			re_multiline_match = false;
    198 			break;
    199 		case 'n':
    200 			max_matches = strtonum(optarg, 1, UINT32_MAX, &errstr);
    201 			if (errstr != NULL)
    202 				errx(2, "num is %s: %s", errstr, optarg);
    203 			break;
    204 		case 'N':
    205 			show_proto = true;
    206 			break;
    207 		case 'O':
    208 			dump_file = optarg;
    209 			if (unveil(dump_file, "wc") == -1)
    210 				err(2, "unveil");
    211 			break;
    212 		case 'p':
    213 			promisc = false;
    214 			break;
    215 		case 'P':
    216 			nonprint_char = *optarg;
    217 			break;
    218 		case 'q':
    219 			quiet++;
    220 			break;
    221 		case 's':
    222 			snaplen = strtonum(optarg, 1, UINT32_MAX, &errstr);
    223 			if (errstr != NULL)
    224 				errx(2, "snaplen is %s: %s", errstr, optarg);
    225 		case 'S':
    226 			limitlen = strtonum(optarg, 1, UINT32_MAX, &errstr);
    227 			if (errstr != NULL)
    228 				errx(2, "limitlen is %s: %s", errstr, optarg);
    229 			break;
    230 		case 't':
    231 			print_time = &print_time_absolute;
    232 			break;
    233 		case 'T':
    234 			if (print_time == &print_time_diff) {
    235 				print_time = print_time_offset;
    236 				memset(&prev_ts, 0, sizeof(prev_ts));
    237 			} else {
    238 				print_time = &print_time_diff;
    239 				gettimeofday(&prev_ts, NULL);
    240 			}
    241 			break;
    242 		case 'v':
    243 			invert_match = true;
    244 			break;
    245 		case 'w':
    246 			re_match_word = true;
    247 			break;
    248 		case 'W':
    249 			if (!strcasecmp(optarg, "normal")) {
    250 				dumper = &dump_formatted;
    251 				char_cmp = &isprint;
    252 			} else if (!strcasecmp(optarg, "byline")) {
    253 				dumper = &dump_unformatted;
    254 				char_cmp = &byline_cmp;
    255 			} else if (!strcasecmp(optarg, "none")) {
    256 				dumper = &dump_unformatted;
    257 				char_cmp = &isprint;
    258 			} else if (!strcasecmp(optarg, "single")) {
    259 				dumper = &dump_unformatted;
    260 				char_cmp = &isprint;
    261 				dump_single = true;
    262 			} else {
    263 				warnx("invalid wrap method: %s", optarg);
    264 				usage();
    265 			}
    266 			break;
    267 		case 'x':
    268 			show_hex = true;
    269 			break;
    270 		case 'X':
    271 			bin_match = true;
    272 			break;
    273 		case 'h':
    274 			/* FALLTHROUGH */
    275 		default:
    276 			usage();
    277 		}
    278 	}
    279 
    280 	if (unveil(NULL, NULL) == -1)
    281 		err(2, "unveil");
    282 
    283 	if (show_hex && dumper != &dump_formatted) {
    284 		warnx("-x is incompatible with -W");
    285 		usage();
    286 	}
    287 	if (bin_match) {
    288 		if (re_ignore_case) {
    289 			warnx("-i is incompatible with -X");
    290 			usage();
    291 		} else if (!re_multiline_match) {
    292 			warnx("-M is incompatible with -X");
    293 			usage();
    294 		} else if (re_match_word) {
    295 			warnx("-w is incompatible with -X");
    296 			usage();
    297 		}
    298 	}
    299 	if (argv[optind])
    300 		match_data = argv[optind++];
    301 
    302 	/* Setup PCAP input */
    303 	if (setup_pcap_source() == -1)
    304 		clean_exit(-1);
    305 
    306 	/*
    307 	 * XXX: Originally, the filter would be setup again without the vlan
    308 	 * hack if the first one failed. Not sure if we need to do this.
    309 	 */
    310 	if (setup_bpf_filter(argv) == -1) {
    311 		warnx("cannot compile filter: %s", pcap_geterr(pd));
    312 		clean_exit(-1);
    313 	}
    314 
    315 	drop_privs();
    316 
    317 	if (quiet < 2)
    318 		printf("filter: %s\n", filter);
    319 	free(filter);
    320 	filter = NULL;
    321 
    322 	/* Setup matcher */
    323 	if (match_data) {
    324 		if (bin_match) {
    325 			if (setup_hex_match() == -1)
    326 				clean_exit(-1);
    327 		} else {
    328 			if (setup_pattern_match() == -1)
    329 				clean_exit(-1);
    330 		}
    331 
    332 		if (quiet < 2)
    333 			printf("%smatch: %s%s\n",
    334 			       invert_match ? "don't " : "",
    335 			       (bin_match && add_hex_exp_pfx) ? "0x" : "",
    336 			       match_data);
    337 
    338 		if (re_match_word)
    339 			free(match_data);
    340 	}
    341 
    342 	/* Misc */
    343 	if (dump_file) {
    344 		if ((pd_dump = pcap_dump_open(pd, dump_file)) == NULL) {
    345 			warnx("pcap_dump_open: %s", pcap_geterr(pd));
    346 			clean_exit(-2);
    347 		} else {
    348 			printf("output: %s\n", dump_file);
    349 		}
    350 	}
    351 	update_windowsize(0);
    352 
    353 	while (pcap_loop(pd, -1, process, 0))
    354 		;
    355 
    356 	clean_exit(0);
    357 
    358 	/* NOT REACHED */
    359 	return 0;
    360 }
    361 
    362 int
    363 setup_pcap_source(void)
    364 {
    365 	if (read_file) {
    366 		if ((pd = pcap_open_offline(read_file, pc_err)) == NULL) {
    367 			warnx("pcap_open_offline: %s", pc_err);
    368 			return -1;
    369 		}
    370 		live_read = false;
    371 		printf("input: %s\n", read_file);
    372 	} else {
    373 		char *dev;
    374 		pcap_if_t *devs = NULL;
    375 
    376 		if (usedev != NULL) {
    377 			dev = usedev;
    378 		} else {
    379 			if (pcap_findalldevs(&devs, pc_err) == PCAP_ERROR) {
    380 				warnx("pcap_findalldevs: %s", pc_err);
    381 				return -1;
    382 			}
    383 			if (devs == NULL) {
    384 				warnx("pcap_findalldevs: no devices found");
    385 				return -1;
    386 			}
    387 
    388 			dev = devs->name;
    389 		}
    390 
    391 		pd = pcap_open_live(dev, snaplen, promisc, BUF_TIMEOUT, pc_err);
    392 		if (pd == NULL) {
    393 			warnx("pcap_open_live: %s", pc_err);
    394 			return -1;
    395 		}
    396 		if (pcap_lookupnet(dev, &net.s_addr, &mask.s_addr, pc_err) ==
    397 		    PCAP_ERROR) {
    398 			warnx("pcap_lookupnet: %s", pc_err);
    399 			memset(&net, 0, sizeof(net));
    400 			memset(&mask, 0, sizeof(mask));
    401 		}
    402 		if (quiet < 2) {
    403 			printf("interface: %s", dev);
    404 			if (net.s_addr && mask.s_addr)
    405 				printf(" (%s/%s)",
    406 				       inet_ntoa(net), inet_ntoa(mask));
    407 			printf("\n");
    408 		}
    409 
    410 		pcap_freealldevs(devs);
    411 	}
    412 
    413 	switch (pcap_datalink(pd)) {
    414 	case DLT_EN10MB:
    415 		link_offset = ETHHDR_SIZE;
    416 		break;
    417 	case DLT_IEEE802:
    418 		link_offset = TOKENRING_SIZE;
    419 		break;
    420 	case DLT_FDDI:
    421 		link_offset = FDDIHDR_SIZE;
    422 		break;
    423 	case DLT_SLIP:
    424 		link_offset = SLIPHDR_SIZE;
    425 		break;
    426 	case DLT_PPP:
    427 		link_offset = PPPHDR_SIZE;
    428 		break;
    429 	case DLT_LOOP:
    430 		/* FALLTHROUGH */
    431 	case DLT_NULL:
    432 		link_offset = LOOPHDR_SIZE;
    433 		break;
    434 	case DLT_RAW:
    435 		link_offset = RAWHDR_SIZE;
    436 		break;
    437 	case DLT_IEEE802_11_RADIO:
    438 		radiotap_present = true;
    439 		/* FALLTHROUGH */
    440 	case DLT_IEEE802_11:
    441 		link_offset = IEEE80211HDR_SIZE;
    442 		break;
    443 	case DLT_PFLOG:
    444 		link_offset = PFLOGHDR_SIZE;
    445 		break;
    446 	default:
    447 		warnx("fatal: unsupported interface type %u",
    448 		      pcap_datalink(pd));
    449 		return -1;
    450 	}
    451 
    452 	return 0;
    453 }
    454 
    455 int
    456 setup_bpf_filter(char **argv)
    457 {
    458 	if (filter_file) {
    459 		filter = get_filter_from_file();
    460 		if (pcap_compile(pd, &pcapfilter, filter, 0, mask.s_addr) == -1)
    461 			return -1;
    462 	} else if (argv[optind]) {
    463 		/*
    464 		 * XXX: Find a better way of doing this that doesn't eat memory.
    465 		 *
    466 		 * If the filter doesn't compile the first time,
    467 		 * we assume that there is no match expression and include the
    468 		 * previous argument in the filter.
    469 		 */
    470 		filter = get_filter_from_argv(&argv[optind]);
    471 
    472 		if (pcap_compile(pd, &pcapfilter, filter, 0, mask.s_addr)) {
    473 			free(filter);
    474 			filter = get_filter_from_argv(&argv[optind - 1]);
    475 
    476 			if (pcap_compile(pd, &pcapfilter, filter, 0,
    477 					 mask.s_addr))
    478 				return -1;
    479 
    480 			match_data = NULL;
    481 		}
    482 	} else {
    483 		filter = include_vlan ? strdup(BPF_TEMPLATE_IP_VLAN)
    484 				      : strdup(BPF_TEMPLATE_IP);
    485 		if (filter == NULL)
    486 			err(2, "strdup");
    487 
    488 		if (pcap_compile(pd, &pcapfilter, filter, 0, mask.s_addr))
    489 			return -1;
    490 	}
    491 
    492 	if (pcap_setfilter(pd, &pcapfilter))
    493 		return -1;
    494 
    495 	return 0;
    496 }
    497 
    498 int
    499 hextoc(char d, char *c)
    500 {
    501 	if (c == NULL)
    502 		return -1;
    503 
    504 	if (d >= '0' && d <= '9')
    505 		*c = d - '0';
    506 	else if (d >= 'A' && d <= 'F')
    507 		*c = d - 'A' + 10;
    508 	else if (d >= 'a' && d <= 'f')
    509 		*c = d - 'a' + 10;
    510 	else
    511 		return -1;
    512 
    513 	return 0;
    514 }
    515 
    516 int
    517 setup_hex_match(void)
    518 {
    519 	size_t len;
    520 	char *bytes = NULL, *str = match_data;
    521 	char ld, rd;
    522 
    523 	if (str == NULL || *str == '\0') {
    524 		warnx("hex expression is empty");
    525 		goto err;
    526 	}
    527 
    528 	len = strlen(str);
    529 	if (len % 2 != 0) {
    530 		warnx("hex expression has odd digits: %s", match_data);
    531 		goto err;
    532 	}
    533 
    534 	if (str[0] == '0' && (str[1] == 'X' || str[1] == 'x')) {
    535 		add_hex_exp_pfx = false;
    536 		str += 2;
    537 		len -= 2;
    538 	}
    539 	if (len == 0) {
    540 		warnx("hex expression has no digits after prefix: %s",
    541 		      match_data);
    542 		goto err;
    543 	} else if (len / 2 > UINT16_MAX) {
    544 		/* XXX: Check bin_match_func to see if this is needed */
    545 		warnx("hex expression is too long: %s", match_data);
    546 		goto err;
    547 	}
    548 
    549 	if ((bytes = calloc(len / 2, 1)) == NULL)
    550 		err(2, "calloc");
    551 
    552 	for (size_t i = 0, j = 0; j < len; j += 2, i++) {
    553 		if (hextoc(str[j], &ld) == -1) {
    554 			warnx("hex expression has invalid digit '%c': %s",
    555 			      str[j], match_data);
    556 			goto err;
    557 		}
    558 		if (hextoc(str[j + 1], &rd) == -1) {
    559 			warnx("hex expression has invalid digit '%c': %s",
    560 			      str[j + 1], match_data);
    561 			goto err;
    562 		}
    563 		bytes[i] = (ld << 4) | rd;
    564 	}
    565 
    566 	bin_data = bytes;
    567 	match_len = len / 2;
    568 	matcher = bin_match_func;
    569 
    570 	return 0;
    571 err:
    572 	free(bytes);
    573 
    574 	return -1;
    575 }
    576 
    577 int
    578 setup_pattern_match(void)
    579 {
    580 	int pcre_options = PCRE_UNGREEDY;
    581 	char *word_regex;
    582 
    583 	if (re_ignore_case)
    584 		pcre_options |= PCRE_CASELESS;
    585 	if (re_multiline_match)
    586 		pcre_options |= PCRE_DOTALL;
    587 
    588 	if (re_match_word) {
    589 		if (asprintf(&word_regex, WORD_REGEX,
    590 			     match_data, match_data, match_data) < 0) {
    591 			warn("asprintf");
    592 			return -1;
    593 		}
    594 		match_data = word_regex;
    595 	}
    596 
    597 	pattern = pcre_compile(match_data, pcre_options, &re_err, &err_offset,
    598 			       NULL);
    599 	if (!pattern) {
    600 		warnx("pcre_compile: %s", re_err);
    601 		return -1;
    602 	}
    603 	pattern_extra = pcre_study(pattern, 0, &re_err);
    604 	matcher = re_match_func;
    605 
    606 	return 0;
    607 }
    608 
    609 static inline size_t
    610 vlan_frame_count(const uint8_t *p, uint32_t caplen)
    611 {
    612 	const uint8_t *et = p + 12;
    613 	uint16_t ether_type = EXTRACT_16BITS(et);
    614 	size_t count = 0;
    615 
    616 	while (et < (p + caplen) &&
    617 	       ether_type != ETHERTYPE_IP &&
    618 	       ether_type != ETHERTYPE_IPV6) {
    619 		count++;
    620 		et += VLANHDR_SIZE;
    621 		ether_type = EXTRACT_16BITS(et);
    622 	}
    623 
    624 	return count;
    625 }
    626 
    627 void
    628 process(UNUSED uint8_t *d, const struct pcap_pkthdr *h, const uint8_t *p)
    629 {
    630 	uint8_t *data;
    631 	struct ip *ip4_pkt;
    632 	struct ip6_hdr *ip6_pkt;
    633 	size_t vlan_offset = 0;
    634 	uint32_t len = 0;
    635 
    636 	uint8_t ip_proto = 0;
    637 	uint32_t ip_hl = 0;
    638 	uint32_t ip_off = 0;
    639 
    640 	bool fragmented = false;
    641 	uint16_t frag_offset = 0;
    642 	uint32_t frag_id = 0;
    643 
    644 	char ip_src[INET6_ADDRSTRLEN + 1];
    645 	char ip_dst[INET6_ADDRSTRLEN + 1];
    646 
    647 	seen_frames++;
    648 
    649 	if (include_vlan)
    650 		vlan_offset = vlan_frame_count(p, h->caplen) * VLANHDR_SIZE;
    651 	len = h->caplen - vlan_offset;
    652 
    653 	ip4_pkt = (struct ip *)     (p + link_offset + vlan_offset);
    654 	ip6_pkt = (struct ip6_hdr *)(p + link_offset + vlan_offset);
    655 
    656 	if (radiotap_present) {
    657 		struct ieee80211_radiotap_header *rh =
    658 		    (struct ieee80211_radiotap_header*)p;
    659 		uint16_t radio_len = rh->it_len;
    660 		ip4_pkt = (struct ip *)     (p + link_offset + radio_len);
    661 		ip6_pkt = (struct ip6_hdr *)(p + link_offset + radio_len);
    662 		len -= radio_len;
    663 	}
    664 
    665 	switch (ip4_pkt->ip_v) {
    666 	case 4: {
    667 		ip_hl = ip4_pkt->ip_hl * 4;
    668 		ip_proto = ip4_pkt->ip_p;
    669 		ip_off = ntohs(ip4_pkt->ip_off);
    670 
    671 		fragmented = (ip_off & (IP_MF | IP_OFFMASK)) != 0;
    672 		if (fragmented)
    673 			frag_offset = (ip_off & IP_OFFMASK) * 8;
    674 		frag_id = ntohs(ip4_pkt->ip_id);
    675 
    676 		inet_ntop(AF_INET, &ip4_pkt->ip_src, ip_src, sizeof(ip_src));
    677 		inet_ntop(AF_INET, &ip4_pkt->ip_dst, ip_dst, sizeof(ip_dst));
    678 	} break;
    679 	case 6: {
    680 		ip_hl = sizeof(struct ip6_hdr);
    681 		ip_proto = ip6_pkt->ip6_nxt;
    682 
    683 		if (ip_proto == IPPROTO_FRAGMENT) {
    684 			struct ip6_frag *ip6_fraghdr =
    685 			    (struct ip6_frag *)((uint8_t *)ip6_pkt + ip_hl);
    686 			ip_hl += sizeof(struct ip6_frag);
    687 			ip_proto = ip6_fraghdr->ip6f_nxt;
    688 
    689 			fragmented = true;
    690 			frag_offset = ntohs(ip6_fraghdr->ip6f_offlg & IP6F_OFF_MASK);
    691 			frag_id = ntohl(ip6_fraghdr->ip6f_ident);
    692 		}
    693 		inet_ntop(AF_INET6, &ip6_pkt->ip6_src, ip_src, sizeof(ip_src));
    694 		inet_ntop(AF_INET6, &ip6_pkt->ip6_dst, ip_dst, sizeof(ip_dst));
    695 	} break;
    696 	}
    697 
    698 	if (quiet < 1) {
    699 		printf("#");
    700 		fflush(stdout);
    701 	}
    702 
    703 	switch (ip_proto) {
    704 	case IPPROTO_TCP: {
    705 		struct tcphdr *tcp_pkt =
    706 		    (struct tcphdr *)((uint8_t *)ip4_pkt + ip_hl);
    707 		uint16_t tcphdr_offset = frag_offset ? 0 : tcp_pkt->th_off * 4;
    708 
    709 		data = (uint8_t *)tcp_pkt + tcphdr_offset;
    710 		len -= link_offset + ip_hl + tcphdr_offset;
    711 
    712 		if ((int32_t)len < 0)
    713 			len = 0;
    714 
    715 		dump_packet(h, p, ip_proto, data, len, ip_src, ip_dst,
    716 			    ntohs(tcp_pkt->th_sport), ntohs(tcp_pkt->th_dport),
    717 			    tcp_pkt->th_flags, tcphdr_offset, fragmented,
    718 			    frag_offset, frag_id);
    719 	} break;
    720 	case IPPROTO_UDP: {
    721 		struct udphdr *udp_pkt =
    722 		    (struct udphdr *)((uint8_t *)ip4_pkt + ip_hl);
    723 		uint16_t udphdr_offset = frag_offset ? 0 : sizeof(*udp_pkt);
    724 
    725 		data = (uint8_t *)udp_pkt + udphdr_offset;
    726 		len -= link_offset + ip_hl + udphdr_offset;
    727 
    728 		if ((int32_t)len < 0)
    729 			len = 0;
    730 
    731 		dump_packet(h, p, ip_proto, data, len, ip_src, ip_dst,
    732 			    ntohs(udp_pkt->uh_sport), ntohs(udp_pkt->uh_dport),
    733 			    0, udphdr_offset, fragmented, frag_offset, frag_id);
    734 	} break;
    735 	case IPPROTO_ICMP: {
    736 		struct icmp *icmp4_pkt =
    737 		    (struct icmp *)((uint8_t *)ip4_pkt + ip_hl);
    738 		uint16_t icmp4hdr_offset = frag_offset ? 0 : 4;
    739 
    740 		data = (uint8_t *)icmp4_pkt + icmp4hdr_offset;
    741 		len -= link_offset + ip_hl + icmp4hdr_offset;
    742 
    743 		if ((int32_t)len < 0)
    744 			len = 0;
    745 
    746 		dump_packet(h, p, ip_proto, data, len, ip_src, ip_dst,
    747 			    icmp4_pkt->icmp_type, icmp4_pkt->icmp_code, 0,
    748 			    icmp4hdr_offset, fragmented, frag_offset, frag_id);
    749 	} break;
    750 	case IPPROTO_ICMPV6: {
    751 		struct icmp6_hdr *icmp6_pkt =
    752 		    (struct icmp6_hdr *)((uint8_t *)ip6_pkt + ip_hl);
    753 		uint16_t icmp6hdr_offset = frag_offset ? 0 : 4;
    754 
    755 		data = (uint8_t *)icmp6_pkt + icmp6hdr_offset;
    756 		len -= link_offset + ip_hl + icmp6hdr_offset;
    757 
    758 		if ((int32_t)len < 0)
    759 			len = 0;
    760 
    761 		dump_packet(h, p, ip_proto, data, len, ip_src, ip_dst,
    762 			    icmp6_pkt->icmp6_type, icmp6_pkt->icmp6_code, 0,
    763 			    icmp6hdr_offset, fragmented, frag_offset, frag_id);
    764 	} break;
    765 	case IPPROTO_IGMP: {
    766 		struct igmp *igmp_pkt =
    767 		    (struct igmp *)((uint8_t *)ip4_pkt + ip_hl);
    768 		uint16_t igmphdr_offset = frag_offset ? 0 : 4;
    769 
    770 		data = (uint8_t *)igmp_pkt + igmphdr_offset;
    771 		len -= link_offset + ip_hl + igmphdr_offset;
    772 
    773 		if ((int32_t)len < 0)
    774 			len = 0;
    775 
    776 		dump_packet(h, p, ip_proto, data, len, ip_src, ip_dst,
    777 			    igmp_pkt->igmp_type, igmp_pkt->igmp_code, 0,
    778 			    igmphdr_offset, fragmented, frag_offset, frag_id);
    779 	} break;
    780 	default: {
    781 		data = (uint8_t *)ip4_pkt + ip_hl;
    782 		len -= link_offset + ip_hl;
    783 
    784 		if ((int32_t)len < 0)
    785 			len = 0;
    786 
    787 		dump_packet(h, p, ip_proto, data, len, ip_src, ip_dst, 0, 0, 0,
    788 			    0, fragmented, frag_offset, frag_id);
    789 	} break;
    790 	}
    791 
    792 	if (max_matches && matches >= max_matches)
    793 		clean_exit(0);
    794 
    795 	if (match_after && keep_matching)
    796 		keep_matching--;
    797 }
    798 
    799 void
    800 dump_packet(const struct pcap_pkthdr *h, const uint8_t *p, uint8_t proto,
    801             uint8_t *data, uint32_t len, const char *ip_src, const char *ip_dst,
    802             uint16_t sport, uint16_t dport, uint8_t flags, uint16_t hdr_offset,
    803             bool frag, uint16_t frag_offset, uint32_t frag_id)
    804 {
    805 	size_t match_size, match_index;
    806 	char ident = '?';
    807 
    808 	if (!show_empty && len == 0)
    809 		return;
    810 
    811 	if (len > limitlen)
    812 		len = limitlen;
    813 
    814 	if (len > 0 &&
    815 	    matcher(data, len, &match_index, &match_size) == invert_match &&
    816 	    !keep_matching)
    817 		return;
    818 
    819 	if (!live_read && want_delay)
    820 		dump_delay(h);
    821 
    822 	switch (proto) {
    823 	case IPPROTO_TCP:
    824 		ident = 'T';
    825 		break;
    826 	case IPPROTO_UDP:
    827 		ident = 'U';
    828 		break;
    829 	case IPPROTO_ICMP:
    830 		/* FALLTHROUGH */
    831 	case IPPROTO_ICMPV6:
    832 		ident = 'I';
    833 		break;
    834 	case IPPROTO_IGMP:
    835 		ident = 'G';
    836 		break;
    837 	}
    838 
    839 	printf("\n%c", ident);
    840 
    841 	if (show_proto)
    842 		printf("(%u)", proto);
    843 
    844 	printf(" ");
    845 
    846 	if (print_time)
    847 		print_time(h);
    848 
    849 	if ((proto == IPPROTO_TCP || proto == IPPROTO_UDP) &&
    850 	    (sport || dport) && (hdr_offset || frag_offset == 0))
    851 		printf("%s:%u -> %s:%u", ip_src, sport, ip_dst, dport);
    852 	else
    853 		printf("%s -> %s", ip_src, ip_dst);
    854 
    855 	if (proto == IPPROTO_TCP && flags)
    856 		printf(" [%s%s%s%s%s%s%s%s]",
    857 		       (flags & TH_ACK)  ? "A" : "",
    858 		       (flags & TH_SYN)  ? "S" : "",
    859 		       (flags & TH_RST)  ? "R" : "",
    860 		       (flags & TH_FIN)  ? "F" : "",
    861 		       (flags & TH_URG)  ? "U" : "",
    862 		       (flags & TH_PUSH) ? "P" : "",
    863 		       (flags & TH_ECE)  ? "E" : "",
    864 		       (flags & TH_CWR)  ? "C" : "");
    865 
    866 	switch (proto) {
    867 	case IPPROTO_ICMP:
    868 		/* FALLTHROUGH */
    869 	case IPPROTO_ICMPV6:
    870 		/* FALLTHROUGH */
    871 	case IPPROTO_IGMP:
    872 		printf(" %u:%u", sport, dport);
    873 	}
    874 
    875 	if (frag)
    876 		printf(" %s%u@%u:%u", frag_offset ? "+" : "",
    877 		       frag_id, frag_offset, len);
    878 
    879 	if (dump_single)
    880 		printf(" ");
    881 	else
    882 		printf(" #%zu\n", seen_frames);
    883 
    884 	if (quiet < 3 && len > 0)
    885 		dumper(data, len, match_index, match_size);
    886 
    887 	if (pd_dump)
    888 		pcap_dump((uint8_t *)pd_dump, h, p);
    889 }
    890 
    891 bool
    892 re_match_func(uint8_t *data, uint32_t len, size_t *mindex, size_t *msize)
    893 {
    894 	static int matchpos[2] = {0};
    895 	int did_match = pcre_exec(pattern, 0, (const char *)data, (int)len,
    896 				  0, 0, matchpos, 2);
    897 	if (did_match < 0) {
    898 		if (did_match == PCRE_ERROR_NOMATCH) {
    899 			return false;
    900 		} else {
    901 			warnx("pcre_exec: returned %d", did_match);
    902 			clean_exit(-1);
    903 		}
    904 	}
    905 
    906 	*mindex = (size_t)matchpos[0];
    907 	*msize = (size_t)matchpos[1] - matchpos[0];
    908 	matches++;
    909 
    910 	if (match_after && keep_matching != match_after)
    911 		keep_matching = match_after;
    912 
    913 	return true;
    914 }
    915 
    916 bool
    917 bin_match_func(uint8_t *data, uint32_t len, size_t *mindex, size_t *msize)
    918 {
    919 	uint8_t *p;
    920 
    921 	if (match_len > len)
    922 		return false;
    923 
    924 	if ((p = memmem(data, len, bin_data, match_len)) != NULL) {
    925 		matches++;
    926 
    927 		if (match_after && keep_matching != match_after)
    928 			keep_matching = match_after;
    929 
    930 		*mindex = (size_t)(p - data);
    931 		*msize = match_len;
    932 
    933 		return true;
    934 	}
    935 
    936 	return false;
    937 }
    938 
    939 bool
    940 blank_match_func(UNUSED uint8_t *data, UNUSED uint32_t len, size_t *mindex,
    941 		 size_t *msize)
    942 {
    943 	matches++;
    944 
    945 	*mindex = 0;
    946 	*msize = 0;
    947 
    948 	return true;
    949 }
    950 
    951 inline int
    952 byline_cmp(int c)
    953 {
    954 	return c == '\n' || isprint(c);
    955 }
    956 
    957 void
    958 dump_unformatted(uint8_t *data, uint32_t len, size_t mindex, size_t msize)
    959 {
    960 	for (uint8_t *s = data; s < data + len; s++)
    961 		*s = char_cmp(*s) ? *s : nonprint_char;
    962 
    963 	if (highlight && msize) {
    964 		fwrite(data, 1, mindex, stdout);
    965 		fputs(RED, stdout);
    966 		fwrite(data + mindex, 1, msize, stdout);
    967 		fputs(RESET, stdout);
    968 		fwrite(data + mindex + msize, 1, len - mindex - msize, stdout);
    969 	} else {
    970 		fwrite(data, 1, len, stdout);
    971 	}
    972 }
    973 
    974 void
    975 dump_formatted(uint8_t *data, uint32_t len, size_t mindex, size_t msize)
    976 {
    977 	bool should_hl = (highlight && msize);
    978 	uint8_t *str = data;
    979 	bool hl_state = false;
    980 	uint8_t width = show_hex ? 16 : (ws_col - 5);
    981 	uint32_t i = 0, j = 0;
    982 
    983 	while (i < len) {
    984 		printf("  ");
    985 
    986 		if (show_hex) {
    987 			for (j = 0; j < width; j++) {
    988 				if (should_hl &&
    989 				    mindex <= i + j &&
    990 				    i + j < mindex + msize) {
    991 					hl_state = true;
    992 					fputs(RED, stdout);
    993 				}
    994 
    995 				if (i + j < len)
    996 					printf("%02x ", str[j]);
    997 				else
    998 					printf("   ");
    999 
   1000 				if ((j + 1) % (width / 2) == 0)
   1001 					printf("   ");
   1002 
   1003 				if (hl_state) {
   1004 					hl_state = false;
   1005 					fputs(RESET, stdout);
   1006 				}
   1007 			}
   1008 		}
   1009 
   1010 		for (j = 0; j < width; j++) {
   1011 			if (should_hl &&
   1012 			    mindex <= i + j &&
   1013 			    i + j < mindex + msize) {
   1014 				hl_state = true;
   1015 				fputs(RED, stdout);
   1016 			}
   1017 
   1018 			if (i + j < len)
   1019 				putchar(char_cmp(str[j]) ? str[j] : nonprint_char);
   1020 			else
   1021 				printf(" ");
   1022 
   1023 			if (hl_state) {
   1024 				hl_state = false;
   1025 				fputs(RESET, stdout);
   1026 			}
   1027 		}
   1028 
   1029 		str += width;
   1030 		i += j;
   1031 
   1032 		putchar('\n');
   1033 	}
   1034 }
   1035 
   1036 char *
   1037 get_filter_from_file(void)
   1038 {
   1039 	char *fstr;
   1040 	size_t size;
   1041 	const char *template;
   1042 	int fd;
   1043 	struct stat st;
   1044 	ssize_t flen;
   1045 
   1046 	template = include_vlan ? BPF_TEMPLATE_IP_VLAN : BPF_TEMPLATE_IP;
   1047 
   1048 	if ((fd = open(filter_file, O_RDONLY)) == -1) {
   1049 		warn("cannot open %s", filter_file);
   1050 		clean_exit(-1);
   1051 	}
   1052 	if (fstat(fd, &st) == -1) {
   1053 		warn("cannot stat %s", filter_file);
   1054 		clean_exit(-1);
   1055 	}
   1056 	if (st.st_size >= SSIZE_MAX) {
   1057 		warn("file too long: %s", filter_file);
   1058 		clean_exit(-1);
   1059 	}
   1060 
   1061 	/* filter = "( " + file + " ) and " + template + '\0' */
   1062 	size = 2 + st.st_size + 7 + strlen(template) + 1;
   1063 	if (size >= SIZE_MAX)
   1064 		warnx("filter too long: %s", filter_file);
   1065 	if ((fstr = malloc(size)) == NULL)
   1066 		err(2, "malloc");
   1067 
   1068 	(void)strlcpy(fstr, "( ", size);
   1069 	flen = read(fd, fstr + 2, st.st_size);
   1070 	if (flen == -1) {
   1071 		warn("read %s", filter_file);
   1072 		clean_exit(-1);
   1073 	} else if (flen != st.st_size) {
   1074 		warn("short read of %s: expected %lld, got %zu",
   1075 		     filter_file, st.st_size, flen);
   1076 		clean_exit(-1);
   1077 	}
   1078 	for (char *s = fstr + 2; *s; s++)
   1079 		if (*s == '\n' || *s == '\r')
   1080 			*s = ' ';
   1081 	/*
   1082 	 * XXX: looks ugly if the file doesn't end in a newline.
   1083 	 * Then again, do we even need to pad the parens?
   1084 	 */
   1085 	(void)strlcat(fstr, ") and ", size);
   1086 	(void)strlcat(fstr, template, size);
   1087 
   1088 	return fstr;
   1089 }
   1090 
   1091 char *
   1092 get_filter_from_argv(char **argv)
   1093 {
   1094 	char *fstr;
   1095 	size_t size = 0;
   1096 	char **arg = argv;
   1097 	const char *template;
   1098 
   1099 	template = include_vlan ? BPF_TEMPLATE_IP_VLAN : BPF_TEMPLATE_IP;
   1100 
   1101 	if (arg == NULL)
   1102 		return NULL;
   1103 
   1104 	for (; *arg != NULL; arg++)
   1105 		size += strlen(*arg) + 1;
   1106 
   1107 	/* filter = "( " + args + ") and " + template + '\0' */
   1108 	size = 2 + size + 6 + strlen(template) + 1;
   1109 	if (size >= SIZE_MAX) {
   1110 		warnx("filter too long");
   1111 		clean_exit(-1);
   1112 	}
   1113 
   1114 	if ((fstr = malloc(size)) == NULL)
   1115 		err(2, "malloc");
   1116 
   1117 	(void)strlcpy(fstr, "( ", size);
   1118 	for (arg = argv; *arg != NULL; arg++) {
   1119 		(void)strlcat(fstr, *arg, size);
   1120 		(void)strlcat(fstr, " ", size);
   1121 	}
   1122 	(void)strlcat(fstr, ") and ", size);
   1123 	(void)strlcat(fstr, template, size);
   1124 
   1125 	return fstr;
   1126 }
   1127 
   1128 void
   1129 print_time_absolute(const struct pcap_pkthdr *h)
   1130 {
   1131 	struct tm *t;
   1132 	time_t ts = h->ts.tv_sec;
   1133 	t = localtime(&ts);
   1134 
   1135 	printf("%02u/%02u/%02u %02u:%02u:%02u.%06u ",
   1136 	       t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour,
   1137 	       t->tm_min, t->tm_sec, h->ts.tv_usec);
   1138 }
   1139 
   1140 void
   1141 print_time_diff(const struct pcap_pkthdr *h)
   1142 {
   1143 	uint32_t secs, usecs;
   1144 
   1145 	secs = h->ts.tv_sec - prev_ts.tv_sec;
   1146 	if (h->ts.tv_usec >= prev_ts.tv_usec)
   1147 		usecs = h->ts.tv_usec - prev_ts.tv_usec;
   1148 	else {
   1149 		secs--;
   1150 		usecs = 1000000 - (prev_ts.tv_usec - h->ts.tv_usec);
   1151 	}
   1152 
   1153 	printf("+%u.%06u ", secs, usecs);
   1154 
   1155 	prev_ts.tv_sec = h->ts.tv_sec;
   1156 	prev_ts.tv_usec = h->ts.tv_usec;
   1157 }
   1158 
   1159 void
   1160 print_time_offset(const struct pcap_pkthdr *h)
   1161 {
   1162 	uint32_t secs, usecs;
   1163 
   1164 	secs = h->ts.tv_sec - prev_ts.tv_sec;
   1165 	if (h->ts.tv_usec >= prev_ts.tv_usec)
   1166 		usecs = h->ts.tv_usec - prev_ts.tv_usec;
   1167 	else {
   1168 		secs--;
   1169 		usecs = 1000000 - (prev_ts.tv_usec - h->ts.tv_usec);
   1170 	}
   1171 
   1172 	if (prev_ts.tv_sec == 0 && prev_ts.tv_usec == 0) {
   1173 		prev_ts.tv_sec = h->ts.tv_sec;
   1174 		prev_ts.tv_usec = h->ts.tv_usec;
   1175 		secs = 0;
   1176 		usecs = 0;
   1177 	}
   1178 	printf("+%u.%06u ", secs, usecs);
   1179 }
   1180 
   1181 void
   1182 dump_delay_proc_init(const struct pcap_pkthdr *h)
   1183 {
   1184 	dump_delay = &dump_delay_proc;
   1185 
   1186 	prev_delay_ts.tv_sec = h->ts.tv_sec;
   1187 	prev_delay_ts.tv_usec = h->ts.tv_usec;
   1188 
   1189 	dump_delay(h);
   1190 }
   1191 
   1192 void
   1193 dump_delay_proc(const struct pcap_pkthdr *h)
   1194 {
   1195 	uint32_t secs, usecs;
   1196 
   1197 	secs = h->ts.tv_sec - prev_delay_ts.tv_sec;
   1198 	if (h->ts.tv_usec >= prev_delay_ts.tv_usec)
   1199 		usecs = h->ts.tv_usec - prev_delay_ts.tv_usec;
   1200 	else {
   1201 		secs--;
   1202 		usecs = 1000000 - (prev_delay_ts.tv_usec - h->ts.tv_usec);
   1203 	}
   1204 
   1205 	sleep(secs);
   1206 	usleep(usecs);
   1207 
   1208 	prev_delay_ts.tv_sec = h->ts.tv_sec;
   1209 	prev_delay_ts.tv_usec = h->ts.tv_usec;
   1210 }
   1211 
   1212 void
   1213 update_windowsize(int32_t e)
   1214 {
   1215 	if (e == 0 && ws_col_forced)
   1216 		ws_col = ws_col_forced;
   1217 	else if (!ws_col_forced) {
   1218 		const struct winsize ws;
   1219 
   1220 		if (!ioctl(0, TIOCGWINSZ, &ws)) {
   1221 			ws_row = ws.ws_row;
   1222 			ws_col = ws.ws_col;
   1223 		} else {
   1224 			ws_row = 24;
   1225 			ws_col = 80;
   1226 		}
   1227 	}
   1228 }
   1229 
   1230 void
   1231 drop_privs(void)
   1232 {
   1233 	struct passwd *pw;
   1234 	gid_t gidset[1];
   1235 
   1236 	if ((pw = getpwnam(UNPRIV_USER)) == NULL) {
   1237 		warn("cannot drop privileges: getpwnam");
   1238 		clean_exit(-1);
   1239 	}
   1240 	endpwent();
   1241 
   1242 	if (chroot("/var/empty") == -1) {
   1243 		warn("cannot drop privileges: chroot");
   1244 		clean_exit(-1);
   1245 	}
   1246 	if (chdir("/") == -1) {
   1247 		warn("cannot drop privileges: chdir");
   1248 		clean_exit(-1);
   1249 	}
   1250 
   1251 	gidset[0] = pw->pw_gid;
   1252 	if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1) {
   1253 		warn("cannot drop privileges: setresgid");
   1254 		clean_exit(-1);
   1255 	}
   1256 	if (setgroups(1, gidset) == -1) {
   1257 		warn("cannot drop privileges: setgroups");
   1258 		clean_exit(-1);
   1259 	}
   1260 	if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) {
   1261 		warn("cannot drop privileges: setresuid");
   1262 		clean_exit(-1);
   1263 	}
   1264 
   1265 }
   1266 
   1267 void
   1268 usage(void)
   1269 {
   1270 	fprintf(stderr,
   1271 		"usage: %s [-CDeilMNpqtTvwxX] [-A num] [-c cols] [-d dev] [-F file] [-I pcap_dump]\n"
   1272 		"             [-n num] [-O pcap_dump] [-P char] [-S limitlen] [-s snaplen]\n"
   1273 		"             [-W normal | byline | single | none] [expression] [filter]\n",
   1274 		getprogname());
   1275 
   1276 	exit(2);
   1277 }
   1278 
   1279 void
   1280 clean_exit(int sig)
   1281 {
   1282 	int code;
   1283 
   1284 	signal(SIGINT, SIG_IGN);
   1285 	signal(SIGABRT, SIG_IGN);
   1286 	signal(SIGQUIT, SIG_IGN);
   1287 	signal(SIGPIPE, SIG_IGN);
   1288 	signal(SIGWINCH, SIG_IGN);
   1289 
   1290 	if (sig == -1)
   1291 		code = 2;
   1292 	else if (matches > 0)
   1293 		code = 0;
   1294 	else
   1295 		code = 1;
   1296 
   1297 	if (quiet < 1 && sig >= 0)
   1298 		puts("exit");
   1299 
   1300 	if (pattern)
   1301 		pcre_free(pattern);
   1302 	if (pattern_extra)
   1303 		pcre_free(pattern_extra);
   1304 	if (bin_data)
   1305 		free(bin_data);
   1306 
   1307 	/*
   1308 	 * We used to report pcap_stats; but PCAP manpage says pcap_stats
   1309 	 * "may or may not" be accurate. So useless. :-( And confusing for a
   1310 	 * user to see counts not match what ngrep thinks.
   1311 	 */
   1312 	if (quiet < 1 && sig >= 0 && read_file == NULL)
   1313 		printf("%zu received, %zu matched\n", seen_frames, matches);
   1314 
   1315 	if (pd)
   1316 		pcap_close(pd);
   1317 	if (pd_dumppcap)
   1318 		pcap_close(pd_dumppcap);
   1319 	if (pd_dump)
   1320 		pcap_dump_close(pd_dump);
   1321 
   1322 	exit(code);
   1323 }