1 /* 2 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that: (1) source code distributions 7 * retain the above copyright notice and this paragraph in its entirety, (2) 8 * distributions including binary code include the above copyright notice and 9 * this paragraph in its entirety in the documentation or other materials 10 * provided with the distribution, and (3) all advertising materials mentioning 11 * features or use of this software display the following acknowledgement: 12 * ``This product includes software developed by the University of California, 13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14 * the University nor the names of its contributors may be used to endorse 15 * or promote products derived from this software without specific prior 16 * written permission. 17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20 */ 21 22 #include <sys/cdefs.h> 23 #ifndef lint 24 __RCSID("$NetBSD: print-pktap.c,v 1.6 2023/08/17 20:19:40 christos Exp $"); 25 #endif 26 27 /* \summary: Apple's DLT_PKTAP printer */ 28 29 #ifdef HAVE_CONFIG_H 30 #include <config.h> 31 #endif 32 33 #include "netdissect-stdinc.h" 34 35 #define ND_LONGJMP_FROM_TCHECK 36 #include "netdissect.h" 37 #include "extract.h" 38 39 #ifdef DLT_PKTAP 40 41 /* 42 * XXX - these are little-endian in the captures I've seen, but Apple 43 * no longer make any big-endian machines (Macs use x86, iOS machines 44 * use ARM and run it little-endian), so that might be by definition 45 * or they might be host-endian. 46 * 47 * If a big-endian PKTAP file ever shows up, and it comes from a 48 * big-endian machine, presumably these are host-endian, and we need 49 * to just fetch the fields directly in tcpdump but byte-swap them 50 * to host byte order in libpcap. 51 */ 52 typedef struct pktap_header { 53 nd_uint32_t pkt_len; /* length of pktap header */ 54 nd_uint32_t pkt_rectype; /* type of record */ 55 nd_uint32_t pkt_dlt; /* DLT type of this packet */ 56 char pkt_ifname[24]; /* interface name */ 57 nd_uint32_t pkt_flags; 58 nd_uint32_t pkt_pfamily; /* "protocol family" */ 59 nd_uint32_t pkt_llhdrlen; /* link-layer header length? */ 60 nd_uint32_t pkt_lltrlrlen; /* link-layer trailer length? */ 61 nd_uint32_t pkt_pid; /* process ID */ 62 char pkt_cmdname[20]; /* command name */ 63 nd_uint32_t pkt_svc_class; /* "service class" */ 64 nd_uint16_t pkt_iftype; /* "interface type" */ 65 nd_uint16_t pkt_ifunit; /* unit number of interface? */ 66 nd_uint32_t pkt_epid; /* "effective process ID" */ 67 char pkt_ecmdname[20]; /* "effective command name" */ 68 } pktap_header_t; 69 70 /* 71 * Record types. 72 */ 73 #define PKT_REC_NONE 0 /* nothing follows the header */ 74 #define PKT_REC_PACKET 1 /* a packet follows the header */ 75 76 static void 77 pktap_header_print(netdissect_options *ndo, const u_char *bp, u_int length) 78 { 79 const pktap_header_t *hdr; 80 uint32_t dlt, hdrlen; 81 const char *dltname; 82 83 hdr = (const pktap_header_t *)bp; 84 85 dlt = GET_LE_U_4(hdr->pkt_dlt); 86 hdrlen = GET_LE_U_4(hdr->pkt_len); 87 dltname = pcap_datalink_val_to_name(dlt); 88 if (!ndo->ndo_qflag) { 89 ND_PRINT("DLT %s (%u) len %u", 90 (dltname != NULL ? dltname : "UNKNOWN"), dlt, hdrlen); 91 } else { 92 ND_PRINT("%s", (dltname != NULL ? dltname : "UNKNOWN")); 93 } 94 95 ND_PRINT(", length %u: ", length); 96 } 97 98 /* 99 * This is the top level routine of the printer. 'p' points 100 * to the ether header of the packet, 'h->ts' is the timestamp, 101 * 'h->len' is the length of the packet off the wire, and 'h->caplen' 102 * is the number of bytes actually captured. 103 */ 104 void 105 pktap_if_print(netdissect_options *ndo, 106 const struct pcap_pkthdr *h, const u_char *p) 107 { 108 uint32_t dlt, hdrlen, rectype; 109 u_int caplen = h->caplen; 110 u_int length = h->len; 111 if_printer printer; 112 const pktap_header_t *hdr; 113 struct pcap_pkthdr nhdr; 114 115 ndo->ndo_protocol = "pktap"; 116 if (length < sizeof(pktap_header_t)) { 117 ND_PRINT(" (packet too short, %u < %zu)", 118 length, sizeof(pktap_header_t)); 119 goto invalid; 120 } 121 hdr = (const pktap_header_t *)p; 122 dlt = GET_LE_U_4(hdr->pkt_dlt); 123 hdrlen = GET_LE_U_4(hdr->pkt_len); 124 if (hdrlen < sizeof(pktap_header_t)) { 125 /* 126 * Claimed header length < structure length. 127 * XXX - does this just mean some fields aren't 128 * being supplied, or is it truly an error (i.e., 129 * is the length supplied so that the header can 130 * be expanded in the future)? 131 */ 132 ND_PRINT(" (pkt_len too small, %u < %zu)", 133 hdrlen, sizeof(pktap_header_t)); 134 goto invalid; 135 } 136 if (hdrlen > length) { 137 ND_PRINT(" (pkt_len too big, %u > %u)", 138 hdrlen, length); 139 goto invalid; 140 } 141 ND_TCHECK_LEN(p, hdrlen); 142 143 if (ndo->ndo_eflag) 144 pktap_header_print(ndo, p, length); 145 146 length -= hdrlen; 147 caplen -= hdrlen; 148 p += hdrlen; 149 150 rectype = GET_LE_U_4(hdr->pkt_rectype); 151 switch (rectype) { 152 153 case PKT_REC_NONE: 154 ND_PRINT("no data"); 155 break; 156 157 case PKT_REC_PACKET: 158 printer = lookup_printer(dlt); 159 if (printer != NULL) { 160 nhdr = *h; 161 nhdr.caplen = caplen; 162 nhdr.len = length; 163 printer(ndo, &nhdr, p); 164 hdrlen += ndo->ndo_ll_hdr_len; 165 } else { 166 if (!ndo->ndo_eflag) 167 pktap_header_print(ndo, (const u_char *)hdr, 168 length + hdrlen); 169 170 if (!ndo->ndo_suppress_default_print) 171 ND_DEFAULTPRINT(p, caplen); 172 } 173 break; 174 } 175 176 ndo->ndo_ll_hdr_len += hdrlen; 177 return; 178 179 invalid: 180 nd_print_invalid(ndo); 181 } 182 #endif /* DLT_PKTAP */ 183