diff options
Diffstat (limited to 'lib/libpcap/libpcap/tests/ngdumppktap')
-rw-r--r-- | lib/libpcap/libpcap/tests/ngdumppktap/ngdumppktap.c | 700 |
1 files changed, 700 insertions, 0 deletions
diff --git a/lib/libpcap/libpcap/tests/ngdumppktap/ngdumppktap.c b/lib/libpcap/libpcap/tests/ngdumppktap/ngdumppktap.c new file mode 100644 index 0000000..6d95e35 --- /dev/null +++ b/lib/libpcap/libpcap/tests/ngdumppktap/ngdumppktap.c @@ -0,0 +1,700 @@ +/* + * Copyright (c) 2018 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +#include <net/bpf.h> +#include <net/pktap.h> + +#include <assert.h> +#include <err.h> +#include <signal.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> +#include <unistd.h> +#include <uuid/uuid.h> + +#include "pcap/pcap-ng.h" +#include "pcap-util.h" +#include "pcap-pktap.h" + +bool capture_done = false; +bool cap_pktap_v2 = false; +bool dump_pktap_v1 = true; +bool dump_pktap_v2 = false; +const char *filename = "pktap.pcapng"; +const char *ifname = "pktap"; +bool truncation = false; +int max_count = INT_MAX; +int verbosity = 0; +size_t max_length = 0; +uint32_t snap_len = 0; +bool want_pktap = true; + +struct dump_info { + pcap_t *p_cap; + + char *ifname_v1; + pcap_dumper_t *dumper_v1; + char *filename_v1; + int packet_count_v1; + size_t total_pktap_header_space; + size_t total_bpf_length_v1; + + char *ifname_v2; + pcap_dumper_t *dumper_v2; + char *filename_v2; + int packet_count_v2; + size_t total_pktap_v2_hdr_space; + size_t total_bpf_length_v2; +}; + +#define MAX_PACKET_LEN 65535 + +static u_char temp_buffer[1024 * 1024]; + +static void +print_pktap_header(const struct pktap_header *pktp_hdr) +{ + uuid_string_t uuidstr, euuidstr; + + fprintf(stderr, "pth_length %u (sizeof(struct pktap_header) %lu)\n", + pktp_hdr->pth_length, sizeof(struct pktap_header)); + fprintf(stderr, "pth_type_next %u\n", pktp_hdr->pth_type_next); + fprintf(stderr, "pth_dlt %u\n", pktp_hdr->pth_dlt); + fprintf(stderr, "pth_ifname %s pth_iftype %d\n", pktp_hdr->pth_ifname, pktp_hdr->pth_iftype); + fprintf(stderr, "pth_flags 0x%x\n", pktp_hdr->pth_flags); + fprintf(stderr, "pth_protocol_family %u\n", pktp_hdr->pth_protocol_family); + fprintf(stderr, "pth_frame_pre_length %u pth_frame_post_length %u\n", + pktp_hdr->pth_frame_pre_length, pktp_hdr->pth_frame_post_length); + fprintf(stderr, "pth_svc %u\n", pktp_hdr->pth_svc); + fprintf(stderr, "pth_flowid %u\n", pktp_hdr->pth_flowid); + fprintf(stderr, "pth_ipproto %u\n", pktp_hdr->pth_ipproto); + fprintf(stderr, "pth_pid %u pth_epid %u\n", pktp_hdr->pth_pid, pktp_hdr->pth_epid); + fprintf(stderr, "pth_comm %s pth_ecomm %s\n", pktp_hdr->pth_comm, pktp_hdr->pth_ecomm); + uuid_unparse(pktp_hdr->pth_uuid, uuidstr); + uuid_unparse(pktp_hdr->pth_euuid, euuidstr); + fprintf(stderr, "pth_uuid %s pth_euuid %s\n", + uuid_is_null(pktp_hdr->pth_uuid) ? "" : uuidstr, + uuid_is_null(pktp_hdr->pth_euuid) ? "" : euuidstr); +} + +static void +print_pktap_v2_hdr(const struct pktap_v2_hdr *pktp_hdr) +{ + uuid_string_t uuidstr, euuidstr; + char *ptr = (char *)pktp_hdr; + + fprintf(stderr, "pth2_length %u (sizeof(struct pktap_v2_hdr) %lu)\n", + pktp_hdr->pth_length, sizeof(struct pktap_v2_hdr)); + fprintf(stderr, "pth2_dlt %u\n", pktp_hdr->pth_dlt); + fprintf(stderr, "pth2_ifname %s pth2_iftype %d\n", + pktp_hdr->pth_ifname_offset != 0 ? ptr + pktp_hdr->pth_ifname_offset : "", + pktp_hdr->pth_iftype); + fprintf(stderr, "pth2_flags 0x%x\n", pktp_hdr->pth_flags); + fprintf(stderr, "pth2_protocol_family %u\n", pktp_hdr->pth_protocol_family); + fprintf(stderr, "pth2_frame_pre_length %u pth2_frame_post_length %u\n", + pktp_hdr->pth_frame_pre_length, pktp_hdr->pth_frame_post_length); + fprintf(stderr, "pth2_svc %u\n", pktp_hdr->pth_svc); + fprintf(stderr, "pth2_flowid %u\n", pktp_hdr->pth_flowid); + fprintf(stderr, "pth2_ipproto %u\n", pktp_hdr->pth_ipproto); + fprintf(stderr, "pth2_pid %u pth2_e_pid %u\n", pktp_hdr->pth_pid, pktp_hdr->pth_e_pid); + + fprintf(stderr, "pth2_comm %s pth2_ecomm %s\n", + pktp_hdr->pth_comm_offset != 0 ? ptr + pktp_hdr->pth_comm_offset : "", + pktp_hdr->pth_e_comm_offset != 0 ? ptr + pktp_hdr->pth_e_comm_offset : ""); + if (pktp_hdr->pth_uuid_offset != 0) + uuid_unparse(*(const uuid_t *)(ptr + pktp_hdr->pth_uuid_offset), uuidstr); + if (pktp_hdr->pth_e_uuid_offset != 0) + uuid_unparse(*(const uuid_t *)(ptr + pktp_hdr->pth_e_uuid_offset), euuidstr); + fprintf(stderr, "pth2_uuid %s pth2_euuid %s\n", + pktp_hdr->pth_uuid_offset == 0 ? "" : uuidstr, + pktp_hdr->pth_e_uuid_offset == 0 ? "" : euuidstr); +} +static size_t +convert_pktap_header_to_v2(const struct pktap_header *pktp_hdr, struct pktap_v2_hdr_space *pktap_v2_hdr_space) +{ + struct pktap_v2_hdr *pktap_v2_hdr; + + pktap_v2_hdr = &pktap_v2_hdr_space->pth_hdr; + + COPY_PKTAP_COMMON_FIELDS_TO_V2(pktap_v2_hdr, pktp_hdr); + + if (!uuid_is_null(pktp_hdr->pth_uuid)) { + size_t len = sizeof(uuid_t); + uint8_t *ptr; + + pktap_v2_hdr->pth_uuid_offset = pktap_v2_hdr->pth_length; + ptr = ((uint8_t *)pktap_v2_hdr) + pktap_v2_hdr->pth_uuid_offset; + uuid_copy(*(uuid_t *)ptr, pktp_hdr->pth_uuid); + + pktap_v2_hdr->pth_length += len; + assert(pktap_v2_hdr->pth_length < sizeof(struct pktap_v2_hdr_space)); + } + + if (!uuid_is_null(pktp_hdr->pth_euuid)) { + size_t len = sizeof(uuid_t); + uint8_t *ptr; + + pktap_v2_hdr->pth_e_uuid_offset = pktap_v2_hdr->pth_length; + ptr = ((uint8_t *)pktap_v2_hdr) + pktap_v2_hdr->pth_e_uuid_offset; + uuid_copy(*(uuid_t *)ptr, pktp_hdr->pth_euuid); + + pktap_v2_hdr->pth_length += len; + assert(pktap_v2_hdr->pth_length < sizeof(struct pktap_v2_hdr_space)); + } + + if (strlen(pktp_hdr->pth_ifname) > 0) { + size_t len; + uint8_t *ptr; + + pktap_v2_hdr->pth_ifname_offset = pktap_v2_hdr->pth_length; + ptr = ((uint8_t *)pktap_v2_hdr) + pktap_v2_hdr->pth_ifname_offset; + len = 1 + strlcpy((char *)ptr, pktp_hdr->pth_ifname, sizeof(pktap_v2_hdr_space->pth_ifname)); + + pktap_v2_hdr->pth_length += len; + assert(pktap_v2_hdr->pth_length < sizeof(struct pktap_v2_hdr_space)); + } + + if (strlen(pktp_hdr->pth_comm) > 0) { + size_t len; + uint8_t *ptr; + + pktap_v2_hdr->pth_comm_offset = pktap_v2_hdr->pth_length; + ptr = ((uint8_t *)pktap_v2_hdr) + pktap_v2_hdr->pth_comm_offset; + len = 1 + strlcpy((char *)ptr, pktp_hdr->pth_comm, sizeof(pktap_v2_hdr_space->pth_comm)); + + pktap_v2_hdr->pth_length += len; + assert(pktap_v2_hdr->pth_length < sizeof(struct pktap_v2_hdr_space)); + } + + if (strlen(pktp_hdr->pth_ecomm) > 0) { + size_t len; + uint8_t *ptr; + + pktap_v2_hdr->pth_e_comm_offset = pktap_v2_hdr->pth_length; + ptr = ((uint8_t *)pktap_v2_hdr) + pktap_v2_hdr->pth_e_comm_offset; + len = 1 + strlcpy((char *)ptr, pktp_hdr->pth_ecomm, sizeof(pktap_v2_hdr_space->pth_e_comm)); + + pktap_v2_hdr->pth_length += len; + assert(pktap_v2_hdr->pth_length < sizeof(struct pktap_v2_hdr_space)); + } + + return (pktap_v2_hdr->pth_length); +} + +static size_t +convert_v2_to_pktap_header(const struct pktap_v2_hdr *pktap_v2_hdr_src, struct pktap_header *pktap_header_dst) +{ + uint8_t *ptr = (uint8_t *)pktap_v2_hdr_src; + + pktap_header_dst->pth_length = sizeof(struct pktap_header); + pktap_header_dst->pth_type_next = PTH_TYPE_PACKET; + pktap_header_dst->pth_dlt = pktap_v2_hdr_src->pth_dlt; + pktap_header_dst->pth_frame_pre_length = pktap_v2_hdr_src->pth_frame_pre_length; + pktap_header_dst->pth_frame_pre_length = pktap_v2_hdr_src->pth_frame_pre_length; + pktap_header_dst->pth_iftype = pktap_v2_hdr_src->pth_iftype; + pktap_header_dst->pth_ipproto = pktap_v2_hdr_src->pth_ipproto; + pktap_header_dst->pth_protocol_family = pktap_v2_hdr_src->pth_protocol_family; + pktap_header_dst->pth_svc = pktap_v2_hdr_src->pth_svc; + pktap_header_dst->pth_flowid = pktap_v2_hdr_src->pth_flowid; + pktap_header_dst->pth_pid = pktap_v2_hdr_src->pth_pid; + pktap_header_dst->pth_epid = pktap_v2_hdr_src->pth_e_pid; + pktap_header_dst->pth_flags = pktap_v2_hdr_src->pth_flags; + pktap_header_dst->pth_flags &= ~PTH_FLAG_V2_HDR; + + if (pktap_v2_hdr_src->pth_uuid_offset != 0) + uuid_copy(pktap_header_dst->pth_uuid, (ptr + pktap_v2_hdr_src->pth_uuid_offset)); + + if (pktap_v2_hdr_src->pth_e_uuid_offset != 0) + uuid_copy(pktap_header_dst->pth_euuid, (ptr + pktap_v2_hdr_src->pth_e_uuid_offset)); + + if (pktap_v2_hdr_src->pth_ifname_offset != 0) + strlcpy(pktap_header_dst->pth_ifname, (char *)(ptr + pktap_v2_hdr_src->pth_ifname_offset), sizeof(pktap_header_dst->pth_ifname)); + + if (pktap_v2_hdr_src->pth_comm_offset != 0) + strlcpy(pktap_header_dst->pth_comm, (char *)(ptr + pktap_v2_hdr_src->pth_comm_offset), sizeof(pktap_header_dst->pth_comm)); + + if (pktap_v2_hdr_src->pth_e_comm_offset != 0) + strlcpy(pktap_header_dst->pth_ecomm, (char *)(ptr + pktap_v2_hdr_src->pth_e_comm_offset), sizeof(pktap_header_dst->pth_ecomm)); + + return (sizeof(struct pktap_header)); +} + +static bool +save_pktap_v1(struct dump_info *dump_info, const struct pcap_pkthdr *h, const u_char *bytes) +{ + int status; + struct pcap_pkthdr pcap_pkthdr; + + memcpy(&pcap_pkthdr, h, sizeof(struct pcap_pkthdr)); + + if (snap_len > 0 && pcap_pkthdr.caplen > snap_len) { + pcap_pkthdr.caplen = snap_len; + } + if (((struct pktap_v2_hdr *)bytes)->pth_flags & PTH_FLAG_V2_HDR) { + const struct pktap_v2_hdr *pktap_v2_hdr = (struct pktap_v2_hdr *)bytes; + struct pktap_header pktap_header_space; + struct pktap_header pktap_header_space_bis; + size_t v1_hdr_len; + struct pktap_v2_hdr_space pktap_v2_hdr_space; + size_t v2_hdr_len; + + memset(&pktap_header_space, 0, sizeof(struct pktap_header)); + memset(&pktap_header_space_bis, 0, sizeof(struct pktap_header)); + memset(&pktap_v2_hdr_space, 0, sizeof(struct pktap_v2_hdr_space)); + + + v1_hdr_len = convert_v2_to_pktap_header(pktap_v2_hdr, &pktap_header_space); + assert(v1_hdr_len == sizeof(struct pktap_header)); + + if (verbosity > 1) { + print_pktap_v2_hdr(pktap_v2_hdr); + print_pktap_header(&pktap_header_space); + } + v2_hdr_len = convert_pktap_header_to_v2(&pktap_header_space, &pktap_v2_hdr_space); + + /* + * The conversion is not symetrical because the strings in the pktap_v2_hdr + * are of variable length and null uuid and empty string are omitted + * Note that BPF may pass empty string and null uuid + * We can compare the conversion to pktap_header + */ + (void) convert_v2_to_pktap_header(&pktap_v2_hdr_space.pth_hdr, &pktap_header_space_bis); + assert(memcmp(&pktap_header_space, &pktap_header_space_bis, v1_hdr_len) == 0); + + assert(pcap_pkthdr.caplen + sizeof(struct pktap_header) - pktap_v2_hdr->pth_length <= sizeof(temp_buffer)); + + memcpy(temp_buffer, &pktap_header_space, sizeof(struct pktap_header)); + memcpy(temp_buffer + sizeof(struct pktap_header), bytes + pktap_v2_hdr->pth_length, + pcap_pkthdr.caplen - pktap_v2_hdr->pth_length); + + pcap_pkthdr.caplen += sizeof(struct pktap_header) - pktap_v2_hdr->pth_length; + pcap_pkthdr.len += sizeof(struct pktap_header) - pktap_v2_hdr->pth_length; + + status = pcap_ng_dump_pktap(dump_info->p_cap, dump_info->dumper_v1, + &pcap_pkthdr, temp_buffer); + if (status == 0) { + warnx("%s: pcap_ng_dump_pktap: %s\n", + __func__, pcap_geterr(dump_info->p_cap)); + return (false); + } + } else if (((struct pktap_header *)bytes)->pth_type_next == PTH_TYPE_PACKET) { + status = pcap_ng_dump_pktap(dump_info->p_cap, dump_info->dumper_v1, + &pcap_pkthdr, bytes); + if (status == 0) { + warnx("%s: pcap_ng_dump_pktap: %s\n", + __func__, pcap_geterr(dump_info->p_cap)); + return (false); + } + } else { + warnx("%s: unkwnown pktap_header type\n", + __func__); + return (false); + } + + dump_info->packet_count_v1++; + dump_info->total_bpf_length_v1 += sizeof(struct bpf_hdr) + pcap_pkthdr.caplen; + dump_info->total_pktap_header_space += sizeof(struct pktap_header); + + if (verbosity > 0) { + fprintf(stderr, "%s: v1 packet count: %d total bpf length: %lu\n", + __func__, dump_info->packet_count_v1, dump_info->total_bpf_length_v1); + } + + return (true); +} + +static void +zero_out_unused_pktap_header_fields_for_v2(struct pktap_header *pktp_hdr) +{ + pktp_hdr->pth_ifunit = 0; + pktp_hdr->pth_tstamp.tv_sec = 0; + pktp_hdr->pth_tstamp.tv_usec = 0; +} + +static bool +save_pktap_v2(struct dump_info *dump_info, const struct pcap_pkthdr *h, const u_char *bytes) +{ + int status; + struct pcap_pkthdr pcap_pkthdr; + + memcpy(&pcap_pkthdr, h, sizeof(struct pcap_pkthdr)); + + if (snap_len > 0 && pcap_pkthdr.caplen > snap_len) { + pcap_pkthdr.caplen = snap_len; + } + + if (((struct pktap_v2_hdr *)bytes)->pth_flags & PTH_FLAG_V2_HDR) { + const struct pktap_v2_hdr *pktap_v2_hdr = (struct pktap_v2_hdr *)bytes; + struct pktap_header pktap_header_space; + size_t v1_hdr_len; + + v1_hdr_len = convert_v2_to_pktap_header(pktap_v2_hdr, &pktap_header_space); + assert(v1_hdr_len == sizeof(struct pktap_header)); + + dump_info->total_pktap_v2_hdr_space += pktap_v2_hdr->pth_length; + + status = pcap_ng_dump_pktap_v2(dump_info->p_cap, dump_info->dumper_v2, + &pcap_pkthdr, bytes, NULL); + if (status == 0) { + warnx("%s: pcap_ng_dump_pktap_v2: %s\n", + __func__, pcap_geterr(dump_info->p_cap)); + pcap_breakloop(dump_info->p_cap); + } + } else if (((struct pktap_header *)bytes)->pth_type_next == PTH_TYPE_PACKET) { + const struct pktap_header *pktp_hdr = (struct pktap_header *)bytes; + struct pktap_header pktap_header_space; + size_t v1_hdr_len; + struct pktap_v2_hdr_space pktap_v2_hdr_space; + size_t v2_hdr_len; + size_t offset; + u_char *new_bytes; + struct pktap_header pktap_header_copy; + + memset(&pktap_header_space, 0, sizeof(struct pktap_header)); + memset(&pktap_header_copy, 0, sizeof(struct pktap_header)); + + /* + * Zero out the fields in the pktap_header we do not care about + */ + memcpy(&pktap_header_copy, pktp_hdr, sizeof(struct pktap_header)); + zero_out_unused_pktap_header_fields_for_v2(&pktap_header_copy); + + v2_hdr_len = convert_pktap_header_to_v2(&pktap_header_copy, &pktap_v2_hdr_space); + + if (verbosity > 1) { + print_pktap_header(&pktap_header_copy); + print_pktap_v2_hdr(&pktap_v2_hdr_space.pth_hdr); + } + dump_info->total_pktap_v2_hdr_space += pktap_v2_hdr_space.pth_hdr.pth_length; + + v1_hdr_len = convert_v2_to_pktap_header(&pktap_v2_hdr_space.pth_hdr, &pktap_header_space); + assert(v1_hdr_len == sizeof(struct pktap_header)); + assert(memcmp(&pktap_header_copy, &pktap_header_space, sizeof(struct pktap_header)) == 0); + + offset = sizeof(struct pktap_header) - v2_hdr_len; + new_bytes = (u_char *)bytes + offset; + memcpy(new_bytes, &pktap_v2_hdr_space, v2_hdr_len); + + pcap_pkthdr.caplen -= offset; + pcap_pkthdr.len -= offset; + status = pcap_ng_dump_pktap_v2(dump_info->p_cap, dump_info->dumper_v2, + &pcap_pkthdr, new_bytes, NULL); + if (status == 0) { + warnx("%s: pcap_ng_dump_pktap_v2: %s\n", + __func__, pcap_geterr(dump_info->p_cap)); + return (false); + } + } else { + warnx("%s: unkwnown pktap header type\n", + __func__); + return (false); + } + + dump_info->packet_count_v2++; + dump_info->total_bpf_length_v2 += sizeof(struct bpf_hdr) + pcap_pkthdr.caplen; + + if (verbosity > 0) { + fprintf(stderr, "%s: v2 packet count: %d total bpf length: %lu\n", + __func__, dump_info->packet_count_v2, dump_info->total_bpf_length_v2); + } + + return (true); +} + + +static void +readcallback(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) +{ + struct dump_info *dump_info = (struct dump_info *) user; + bool v1_done = false; + bool v2_done = false; + + if (dump_pktap_v1) { + if ((max_count != 0 && dump_info->packet_count_v1 > max_count) || + (max_length != 0 && dump_info->total_bpf_length_v1 >= max_length)) { + v1_done = true; + } else if (!save_pktap_v1(dump_info, h, bytes)) { + v1_done = true; + v2_done = true; + } + } else { + v1_done = true; + } + + if (dump_pktap_v2) { + if ((max_count != 0 && dump_info->packet_count_v2 > max_count) || + (max_length != 0 && dump_info->total_bpf_length_v2 >= max_length)) { + v2_done = true; + } else if (!save_pktap_v2(dump_info, h, bytes)) { + v2_done = true; + } + } else { + v2_done = true; + } + + if (capture_done || (v1_done && v2_done)) { + if (verbosity > 0) { + fprintf(stderr, "%s: done\n", + __func__); + } + pcap_breakloop(dump_info->p_cap); + } +} + +static void +usage(void) +{ +#define OPTION_FMT " %-20s %s\n" + printf("# usage: %s [-c 1|2] [-d 1|-1|2|-2] [-f filename] [-h] [-i ifname] [-l max_length] [-n max_count] [-s snap_len] [-t 0|1] [-v]\n", + getprogname()); + printf(OPTION_FMT, "-c 1|2", "capture version 1 'struct pktap_header' or version 2 'struct pktap_hdr_v2' (v1 by default)"); + printf(OPTION_FMT, "-d 1|-1|2|-2", "dump using version 1 pcap_ng_dump_pktap() and/or version 2 pcap_ng_dump_pktap_v2() (v1 by default)"); + printf(OPTION_FMT, "-f filename", "file name for dump file (to be prefixed with 'v1_' or 'v2'"); + printf(OPTION_FMT, "-h", "display this help"); + printf(OPTION_FMT, "-i ifname", "capture interface name (pktap by default)"); + printf(OPTION_FMT, "-l max_length", "maximum length of packet captured (unlimited by default"); + printf(OPTION_FMT, "-n max_count", "maximum number of packet to capture (unlimited by default"); + printf(OPTION_FMT, "-s snap_len", "snap len (unlimited by default)"); + printf(OPTION_FMT, "-t 0|1", "truncation mode (off by default)"); + printf(OPTION_FMT, "-v", "increase versbosity"); +} + +void +parse_command_line(int argc, char * const argv[]) +{ + int ch; + + if (argc == 1) { + usage(); + exit(EX_OK); + } + while ((ch = getopt(argc, argv, "c:d:f:hi:l:n:qs:t:vw:")) != -1) { + switch (ch) { + case 'c': + if (strcmp(optarg, "1") == 0) { + cap_pktap_v2 = false; + } else if (strcmp(optarg, "2") == 0) { + cap_pktap_v2 = true; + } else { + warnx("bad parameter '%s' for option '-%c'", optarg, ch); + usage(); + exit(EX_USAGE); + } + break; + + case 'd': + if (strcmp(optarg, "1") == 0) { + dump_pktap_v1 = true; + } else if (strcmp(optarg, "-1") == 0) { + dump_pktap_v1 = false; + } else if (strcmp(optarg, "2") == 0) { + dump_pktap_v2 = true; + } else if (strcmp(optarg, "-2") == 0) { + dump_pktap_v2 = false; + } else { + warnx("bad parameter '%s' for option '-%c'", optarg, ch); + usage(); + exit(EX_USAGE); + } + break; + + case 'f': + filename = optarg; + break; + + case 'h': + usage(); + exit(EX_OK); + + case 'i': + ifname = optarg; + break; + + case 'l': + max_length = strtoul(optarg, NULL, 0); + break; + + case 'n': + max_count = atoi(optarg); + break; + + case 'q': + verbosity--; + break; + + case 's': + snap_len = (uint32_t) strtoul(optarg, NULL, 0); + break; + + case 't': + truncation = !!atoi(optarg); + break; + + case 'v': + verbosity++; + break; + + case 'w': + want_pktap = !!atoi(optarg); + break; + + default: + usage(); + exit(EX_USAGE); + } + } +} + +void +signal_handler(int sig) +{ + capture_done = true; +} + +int +main(int argc, char * const argv[]) { + char ebuf[PCAP_ERRBUF_SIZE]; + int status; + struct dump_info dump_info = {}; + + parse_command_line(argc, argv); + + dump_info.ifname_v1 = pcap_setup_pktap_interface(ifname, ebuf); + if (dump_info.ifname_v1 == NULL) { + errx(EX_OSERR, "pcap_setup_pktap_interface(%s) fail - %s", + ifname, ebuf); + } + dump_info.ifname_v2 = pcap_setup_pktap_interface(ifname, ebuf); + if (dump_info.ifname_v2 == NULL) { + errx(EX_OSERR, "pcap_setup_pktap_interface(pktap) fail - %s", + ebuf); + } + + dump_info.p_cap = pcap_create(ifname, ebuf); + if (dump_info.p_cap == NULL) { + errx(EX_OSERR, "pcap_create(%s) fail - %s", + ifname, ebuf); + } + status = pcap_set_timeout(dump_info.p_cap, 1000); + if (status != 0) { + errx(EX_OSERR, "pcap_create(%s) fail - %s", + ifname, pcap_statustostr(status)); + } + + /* + * Must be called before pcap_activate() + */ + pcap_set_want_pktap(dump_info.p_cap, want_pktap); + pcap_set_pktap_hdr_v2(dump_info.p_cap, cap_pktap_v2); + pcap_set_truncation_mode(dump_info.p_cap, truncation); + if (snap_len > 0) + pcap_set_snaplen(dump_info.p_cap, snap_len); + + status = pcap_activate(dump_info.p_cap); + if (status < 0) { + if (status == PCAP_ERROR) { + errx(EX_OSERR, "pcap_activate(%s) fail - %s", + ifname, pcap_geterr(dump_info.p_cap)); + } else { + errx(EX_OSERR, "pcap_activate(%s) fail - %s %s", + ifname, pcap_statustostr(status), pcap_geterr(dump_info.p_cap)); + } + } + + if (verbosity) { + int dlt = pcap_datalink(dump_info.p_cap); + const char *dltname = pcap_datalink_val_to_name(dlt); + int n_dlts, i; + int *dlts = 0; + + fprintf(stderr, "wantpktap %d\n", want_pktap); + + fprintf(stderr, "pcap_datalink: %d name: %s\n", dlt, dltname); + + n_dlts = pcap_list_datalinks(dump_info.p_cap, &dlts); + + for (i = 0; i < n_dlts; i++) { + dltname = pcap_datalink_val_to_name(dlts[i]); + fprintf(stderr, "pcap_list_datalinks[%d]: %d name: %s\n", i, dlts[i], dltname); + } + pcap_free_datalinks(dlts); + } + + if (dump_pktap_v1) { + dump_info.filename_v1 = malloc(PATH_MAX); + snprintf(dump_info.filename_v1, PATH_MAX, "v1_%s", filename); + dump_info.dumper_v1 = pcap_ng_dump_open(dump_info.p_cap, dump_info.filename_v1); + if (dump_info.dumper_v1 == NULL) { + errx(EX_OSERR, "pcap_ng_dump_open(%s) fail - %s", + dump_info.filename_v1, pcap_geterr(dump_info.p_cap)); + } + } + + if (dump_pktap_v2) { + dump_info.filename_v2 = malloc(PATH_MAX); + snprintf(dump_info.filename_v2, PATH_MAX, "v2_%s", filename); + dump_info.dumper_v2 = pcap_ng_dump_open(dump_info.p_cap, dump_info.filename_v2); + if (dump_info.dumper_v2 == NULL) { + errx(EX_OSERR, "pcap_ng_dump_open(%s) fail - %s", + dump_info.filename_v2, pcap_geterr(dump_info.p_cap)); + } + } + + /* to stop the capture */ + signal(SIGINT, signal_handler); + + while (true) { + status = pcap_dispatch(dump_info.p_cap, -1, readcallback, (u_char *) &dump_info); + if (status == -1) { + errx(EX_OSERR, "pcap_dispatch(%s) fail - %s", + ifname, pcap_geterr(dump_info.p_cap)); + } else if (status == -2) { + /* pcap_breakloop() called */ + break; + } + } + + if (dump_pktap_v1) { + pcap_dump_close(dump_info.dumper_v1); + fprintf(stderr, "v1 file: %s packet count: %d total bpf length: %lu pktap header space %lu\n", + dump_info.filename_v1, dump_info.packet_count_v1, + dump_info.total_bpf_length_v1, dump_info.total_pktap_header_space); + } + if (dump_pktap_v2) { + pcap_dump_close(dump_info.dumper_v2); + fprintf(stderr, "v2 file: %s packet count: %d total bpf length: %lu pktap v2 hdr space %lu\n", + dump_info.filename_v2, dump_info.packet_count_v2, + dump_info.total_bpf_length_v2, dump_info.total_pktap_v2_hdr_space); + } + pcap_close(dump_info.p_cap); + + exit(EX_OK); +} |