/* * packet-pktap.c * Routines for dissecting Apple's PKTAP header * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 2007 Gerald Combs * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include "packet-eth.h" static dissector_handle_t pcap_pktdata_handle; void proto_register_pktap(void); void proto_reg_handoff_pktap(void); /* * Apple's PKTAP header. */ /* * Minimum header length. * * XXX - I'm assuming the header begins with a length field so that it * can be transparently *extended*, not so that fields in the current * header can be *omitted*. */ #define MIN_PKTAP_HDR_LEN 108 /* * Record types. */ #define PKT_REC_NONE 0 /* nothing follows the header */ #define PKT_REC_PACKET 1 /* a packet follows the header */ /* Protocol */ static int proto_pktap = -1; static int hf_pktap_hdrlen = -1; static int hf_pktap_rectype = -1; static int hf_pktap_dlt = -1; static int hf_pktap_ifname = -1; static int hf_pktap_flags = -1; static int hf_pktap_pfamily = -1; static int hf_pktap_llhdrlen = -1; static int hf_pktap_lltrlrlen = -1; static int hf_pktap_pid = -1; static int hf_pktap_cmdname = -1; static int hf_pktap_svc_class = -1; static int hf_pktap_iftype = -1; static int hf_pktap_ifunit = -1; static int hf_pktap_epid = -1; static int hf_pktap_ecmdname = -1; static gint ett_pktap = -1; static expert_field ei_pktap_hdrlen_too_short = EI_INIT; static dissector_handle_t pktap_handle; static capture_dissector_handle_t eth_cap_handle; /* * XXX - these are only little-endian because they've been created on * little-endian machines; the code in bsd/net/pktap.c in XNU writes * the structure out in host byte order. * * We haven't been treating it as host-endian in libpcap and libwiretap, * i.e. we haven't been byte-swapping its members when reading it on * a machine whose byte order differs from the byte order of the machine * on which the file is being read. * * Furthermore, the header is extensible, so we don't necessarily know * what fields to swap. * * Fortunately, the length of the PKTAP header is a 32-bit field and is * *presumably* never going to be 65536 or greater, so if any of the upper * 16 bits appear to be set, it means we're looking at it in the wrong * byte order, and it's never going to be zero, so those bits *will* be * set if it's >= 65536, so we can determine its byte order. * * We should do that here. */ static gboolean capture_pktap(const guchar *pd, int offset _U_, int len, capture_packet_info_t *cpinfo, const union wtap_pseudo_header *pseudo_header _U_) { guint32 hdrlen, rectype, dlt; hdrlen = pletoh32(pd); if (hdrlen < MIN_PKTAP_HDR_LEN || !BYTES_ARE_IN_FRAME(0, len, hdrlen)) return FALSE; rectype = pletoh32(pd+4); if (rectype != PKT_REC_PACKET) return FALSE; dlt = pletoh32(pd+4); /* XXX - We should probably combine this with capture_info.c:capture_info_packet() */ switch (dlt) { case 1: /* DLT_EN10MB */ return call_capture_dissector(eth_cap_handle, pd, hdrlen, len, cpinfo, pseudo_header); } return FALSE; } static int dissect_pktap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) { proto_tree *pktap_tree = NULL; proto_item *ti = NULL; tvbuff_t *next_tvb; int offset = 0; guint32 pkt_len, rectype, dlt; col_set_str(pinfo->cinfo, COL_PROTOCOL, "PKTAP"); col_clear(pinfo->cinfo, COL_INFO); pkt_len = tvb_get_letohl(tvb, offset); col_add_fstr(pinfo->cinfo, COL_INFO, "PKTAP, %u byte header", pkt_len); /* Dissect the packet */ ti = proto_tree_add_item(tree, proto_pktap, tvb, offset, pkt_len, ENC_NA); pktap_tree = proto_item_add_subtree(ti, ett_pktap); proto_tree_add_item(pktap_tree, hf_pktap_hdrlen, tvb, offset, 4, ENC_LITTLE_ENDIAN); if (pkt_len < MIN_PKTAP_HDR_LEN) { proto_tree_add_expert(tree, pinfo, &ei_pktap_hdrlen_too_short, tvb, offset, 4); return tvb_captured_length(tvb); } offset += 4; proto_tree_add_item(pktap_tree, hf_pktap_rectype, tvb, offset, 4, ENC_LITTLE_ENDIAN); rectype = tvb_get_letohl(tvb, offset); offset += 4; proto_tree_add_item(pktap_tree, hf_pktap_dlt, tvb, offset, 4, ENC_LITTLE_ENDIAN); dlt = tvb_get_letohl(tvb, offset); offset += 4; proto_tree_add_item(pktap_tree, hf_pktap_ifname, tvb, offset, 24, ENC_ASCII|ENC_NA); offset += 24; proto_tree_add_item(pktap_tree, hf_pktap_flags, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(pktap_tree, hf_pktap_pfamily, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(pktap_tree, hf_pktap_llhdrlen, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(pktap_tree, hf_pktap_lltrlrlen, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(pktap_tree, hf_pktap_pid, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(pktap_tree, hf_pktap_cmdname, tvb, offset, 20, ENC_UTF_8|ENC_NA); offset += 20; proto_tree_add_item(pktap_tree, hf_pktap_svc_class, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(pktap_tree, hf_pktap_iftype, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(pktap_tree, hf_pktap_ifunit, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(pktap_tree, hf_pktap_epid, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(pktap_tree, hf_pktap_ecmdname, tvb, offset, 20, ENC_UTF_8|ENC_NA); /*offset += 20;*/ if (rectype == PKT_REC_PACKET) { next_tvb = tvb_new_subset_remaining(tvb, pkt_len); call_dissector_with_data(pcap_pktdata_handle, next_tvb, pinfo, tree, &dlt); } return tvb_captured_length(tvb); } void proto_register_pktap(void) { static hf_register_info hf[] = { { &hf_pktap_hdrlen, { "Header length", "pktap.hdrlen", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_pktap_rectype, { "Record type", "pktap.rectype", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_pktap_dlt, { "DLT", "pktap.dlt", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_pktap_ifname, /* fixed length *and* null-terminated */ { "Interface name", "pktap.ifname", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_pktap_flags, { "Flags", "pktap.flags", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_pktap_pfamily, { "Protocol family", "pktap.pfamily", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_pktap_llhdrlen, { "Link-layer header length", "pktap.llhdrlen", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_pktap_lltrlrlen, { "Link-layer trailer length", "pktap.lltrlrlen", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_pktap_pid, { "Process ID", "pktap.pid", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_pktap_cmdname, /* fixed length *and* null-terminated */ { "Command name", "pktap.cmdname", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_pktap_svc_class, { "Service class", "pktap.svc_class", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_pktap_iftype, { "Interface type", "pktap.iftype", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_pktap_ifunit, { "Interface unit", "pktap.ifunit", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_pktap_epid, { "Effective process ID", "pktap.epid", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_pktap_ecmdname, /* fixed length *and* null-terminated */ { "Effective command name", "pktap.ecmdname", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL } }, }; static gint *ett[] = { &ett_pktap, }; static ei_register_info ei[] = { { &ei_pktap_hdrlen_too_short, { "pktap.hdrlen_too_short", PI_MALFORMED, PI_ERROR, "Header length is too short", EXPFILL }}, }; expert_module_t* expert_pktap; proto_pktap = proto_register_protocol("PKTAP packet header", "PKTAP", "pktap"); proto_register_field_array(proto_pktap, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); expert_pktap = expert_register_protocol(proto_pktap); expert_register_field_array(expert_pktap, ei, array_length(ei)); pktap_handle = register_dissector("pktap", dissect_pktap, proto_pktap); } void proto_reg_handoff_pktap(void) { capture_dissector_handle_t pktap_cap_handle; dissector_add_uint("wtap_encap", WTAP_ENCAP_PKTAP, pktap_handle); pcap_pktdata_handle = find_dissector_add_dependency("pcap_pktdata", proto_pktap); /* XXX - WTAP_ENCAP_USER2 to handle Mavericks' botch wherein it uses DLT_USER2 for PKTAP; if you are using DLT_USER2 for your own purposes, feel free to call your own capture_ routine for WTAP_ENCAP_USER2. */ pktap_cap_handle = create_capture_dissector_handle(capture_pktap, proto_pktap); capture_dissector_add_uint("wtap_encap", WTAP_ENCAP_PKTAP, pktap_cap_handle); capture_dissector_add_uint("wtap_encap", WTAP_ENCAP_USER2, pktap_cap_handle); eth_cap_handle = find_capture_dissector("eth"); } /* * Editor modelines - http://www.wireshark.org/tools/modelines.html * * Local variables: * c-basic-offset: 8 * tab-width: 8 * indent-tabs-mode: t * End: * * vi: set shiftwidth=8 tabstop=8 noexpandtab: * :indentSize=8:tabSize=8:noTabs=false: */