Coverage Report

Created: 2025-02-15 06:25

/src/wireshark/epan/dissectors/packet-pktap.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * packet-pktap.c
3
 * Routines for dissecting Apple's PKTAP header
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 2007 Gerald Combs
8
 *
9
 * SPDX-License-Identifier: GPL-2.0-or-later
10
 */
11
12
#include "config.h"
13
14
#include <epan/packet.h>
15
#include <epan/capture_dissectors.h>
16
#include <epan/expert.h>
17
#include <wsutil/pint.h>
18
19
#include "packet-eth.h"
20
21
static dissector_handle_t pcap_pktdata_handle;
22
23
void proto_register_pktap(void);
24
void proto_reg_handoff_pktap(void);
25
26
/*
27
 * Apple's PKTAP header.
28
 */
29
30
/*
31
 * Minimum header length.
32
 *
33
 * XXX - I'm assuming the header begins with a length field so that it
34
 * can be transparently *extended*, not so that fields in the current
35
 * header can be *omitted*.
36
 */
37
1
#define MIN_PKTAP_HDR_LEN 108
38
39
/*
40
 * Record types.
41
 */
42
#define PKT_REC_NONE  0 /* nothing follows the header */
43
1
#define PKT_REC_PACKET  1  /* a packet follows the header */
44
45
/* Protocol */
46
static int proto_pktap;
47
48
static int hf_pktap_hdrlen;
49
static int hf_pktap_rectype;
50
static int hf_pktap_dlt;
51
static int hf_pktap_ifname;
52
static int hf_pktap_flags;
53
static int hf_pktap_pfamily;
54
static int hf_pktap_llhdrlen;
55
static int hf_pktap_lltrlrlen;
56
static int hf_pktap_pid;
57
static int hf_pktap_cmdname;
58
static int hf_pktap_svc_class;
59
static int hf_pktap_iftype;
60
static int hf_pktap_ifunit;
61
static int hf_pktap_epid;
62
static int hf_pktap_ecmdname;
63
64
static int ett_pktap;
65
66
static expert_field ei_pktap_hdrlen_too_short;
67
68
static dissector_handle_t pktap_handle;
69
static capture_dissector_handle_t eth_cap_handle;
70
71
/*
72
 * XXX - these are only little-endian because they've been created on
73
 * little-endian machines; the code in bsd/net/pktap.c in XNU writes
74
 * the structure out in host byte order.
75
 *
76
 * We haven't been treating it as host-endian in libpcap and libwiretap,
77
 * i.e. we haven't been byte-swapping its members when reading it on
78
 * a machine whose byte order differs from the byte order of the machine
79
 * on which the file is being read.
80
 *
81
 * Furthermore, the header is extensible, so we don't necessarily know
82
 * what fields to swap.
83
 *
84
 * Fortunately, the length of the PKTAP header is a 32-bit field and is
85
 * *presumably* never going to be 65536 or greater, so if any of the upper
86
 * 16 bits appear to be set, it means we're looking at it in the wrong
87
 * byte order, and it's never going to be zero, so those bits *will* be
88
 * set if it's >= 65536, so we can determine its byte order.
89
 *
90
 * We should do that here.
91
 */
92
93
static bool
94
capture_pktap(const unsigned char *pd, int offset _U_, int len, capture_packet_info_t *cpinfo, const union wtap_pseudo_header *pseudo_header _U_)
95
0
{
96
0
  uint32_t hdrlen, rectype, dlt;
97
98
0
  hdrlen = pletoh32(pd);
99
0
  if (hdrlen < MIN_PKTAP_HDR_LEN || !BYTES_ARE_IN_FRAME(0, len, hdrlen))
100
0
    return false;
101
102
0
  rectype = pletoh32(pd+4);
103
0
  if (rectype != PKT_REC_PACKET)
104
0
    return false;
105
106
0
  dlt = pletoh32(pd+4);
107
108
  /* XXX - We should probably combine this with capture_info.c:capture_info_packet() */
109
0
  switch (dlt) {
110
111
0
  case 1: /* DLT_EN10MB */
112
0
    return call_capture_dissector(eth_cap_handle, pd, hdrlen, len, cpinfo, pseudo_header);
113
114
0
  }
115
116
0
  return false;
117
0
}
118
119
static int
120
dissect_pktap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
121
1
{
122
1
  proto_tree *pktap_tree = NULL;
123
1
  proto_item *ti = NULL;
124
1
  tvbuff_t *next_tvb;
125
1
  int offset = 0;
126
1
  uint32_t pkt_len, rectype, dlt;
127
128
1
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "PKTAP");
129
1
  col_clear(pinfo->cinfo, COL_INFO);
130
131
1
  pkt_len = tvb_get_letohl(tvb, offset);
132
1
  col_add_fstr(pinfo->cinfo, COL_INFO, "PKTAP, %u byte header", pkt_len);
133
134
  /* Dissect the packet */
135
1
  ti = proto_tree_add_item(tree, proto_pktap, tvb, offset, pkt_len, ENC_NA);
136
1
  pktap_tree = proto_item_add_subtree(ti, ett_pktap);
137
138
1
  proto_tree_add_item(pktap_tree, hf_pktap_hdrlen, tvb, offset, 4,
139
1
      ENC_LITTLE_ENDIAN);
140
1
  if (pkt_len < MIN_PKTAP_HDR_LEN) {
141
0
    proto_tree_add_expert(tree, pinfo, &ei_pktap_hdrlen_too_short,
142
0
        tvb, offset, 4);
143
0
    return tvb_captured_length(tvb);
144
0
  }
145
1
  offset += 4;
146
147
1
  proto_tree_add_item(pktap_tree, hf_pktap_rectype, tvb, offset, 4,
148
1
      ENC_LITTLE_ENDIAN);
149
1
  rectype = tvb_get_letohl(tvb, offset);
150
1
  offset += 4;
151
1
  proto_tree_add_item(pktap_tree, hf_pktap_dlt, tvb, offset, 4,
152
1
      ENC_LITTLE_ENDIAN);
153
1
  dlt = tvb_get_letohl(tvb, offset);
154
1
  offset += 4;
155
1
  proto_tree_add_item(pktap_tree, hf_pktap_ifname, tvb, offset, 24,
156
1
      ENC_ASCII);
157
1
  offset += 24;
158
1
  proto_tree_add_item(pktap_tree, hf_pktap_flags, tvb, offset, 4,
159
1
      ENC_LITTLE_ENDIAN);
160
1
  offset += 4;
161
1
  proto_tree_add_item(pktap_tree, hf_pktap_pfamily, tvb, offset, 4,
162
1
      ENC_LITTLE_ENDIAN);
163
1
  offset += 4;
164
1
  proto_tree_add_item(pktap_tree, hf_pktap_llhdrlen, tvb, offset, 4,
165
1
      ENC_LITTLE_ENDIAN);
166
1
  offset += 4;
167
1
  proto_tree_add_item(pktap_tree, hf_pktap_lltrlrlen, tvb, offset, 4,
168
1
      ENC_LITTLE_ENDIAN);
169
1
  offset += 4;
170
1
  proto_tree_add_item(pktap_tree, hf_pktap_pid, tvb, offset, 4,
171
1
      ENC_LITTLE_ENDIAN);
172
1
  offset += 4;
173
1
  proto_tree_add_item(pktap_tree, hf_pktap_cmdname, tvb, offset, 20,
174
1
      ENC_UTF_8);
175
1
  offset += 20;
176
1
  proto_tree_add_item(pktap_tree, hf_pktap_svc_class, tvb, offset, 4,
177
1
      ENC_LITTLE_ENDIAN);
178
1
  offset += 4;
179
1
  proto_tree_add_item(pktap_tree, hf_pktap_iftype, tvb, offset, 2,
180
1
      ENC_LITTLE_ENDIAN);
181
1
  offset += 2;
182
1
  proto_tree_add_item(pktap_tree, hf_pktap_ifunit, tvb, offset, 2,
183
1
      ENC_LITTLE_ENDIAN);
184
1
  offset += 2;
185
1
  proto_tree_add_item(pktap_tree, hf_pktap_epid, tvb, offset, 4,
186
1
      ENC_LITTLE_ENDIAN);
187
1
  offset += 4;
188
1
  proto_tree_add_item(pktap_tree, hf_pktap_ecmdname, tvb, offset, 20,
189
1
      ENC_UTF_8);
190
  /*offset += 20;*/
191
192
1
  if (rectype == PKT_REC_PACKET) {
193
0
    next_tvb = tvb_new_subset_remaining(tvb, pkt_len);
194
0
    call_dissector_with_data(pcap_pktdata_handle, next_tvb,
195
0
        pinfo, tree, &dlt);
196
0
  }
197
1
  return tvb_captured_length(tvb);
198
1
}
199
200
void
201
proto_register_pktap(void)
202
14
{
203
14
  static hf_register_info hf[] = {
204
14
    { &hf_pktap_hdrlen,
205
14
      { "Header length", "pktap.hdrlen",
206
14
        FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
207
14
    { &hf_pktap_rectype,
208
14
      { "Record type", "pktap.rectype",
209
14
        FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
210
14
    { &hf_pktap_dlt,
211
14
      { "DLT", "pktap.dlt",
212
14
        FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
213
14
    { &hf_pktap_ifname, /* fixed length *and* null-terminated */
214
14
      { "Interface name", "pktap.ifname",
215
14
        FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL } },
216
14
    { &hf_pktap_flags,
217
14
      { "Flags", "pktap.flags",
218
14
        FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
219
14
    { &hf_pktap_pfamily,
220
14
      { "Protocol family", "pktap.pfamily",
221
14
        FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
222
14
    { &hf_pktap_llhdrlen,
223
14
      { "Link-layer header length", "pktap.llhdrlen",
224
14
        FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
225
14
    { &hf_pktap_lltrlrlen,
226
14
      { "Link-layer trailer length", "pktap.lltrlrlen",
227
14
        FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
228
14
    { &hf_pktap_pid,
229
14
      { "Process ID", "pktap.pid",
230
14
        FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
231
14
    { &hf_pktap_cmdname,  /* fixed length *and* null-terminated */
232
14
      { "Command name", "pktap.cmdname",
233
14
        FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL } },
234
14
    { &hf_pktap_svc_class,
235
14
      { "Service class", "pktap.svc_class",
236
14
        FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
237
14
    { &hf_pktap_iftype,
238
14
      { "Interface type", "pktap.iftype",
239
14
        FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
240
14
    { &hf_pktap_ifunit,
241
14
      { "Interface unit", "pktap.ifunit",
242
14
        FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
243
14
    { &hf_pktap_epid,
244
14
      { "Effective process ID", "pktap.epid",
245
14
        FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
246
14
    { &hf_pktap_ecmdname, /* fixed length *and* null-terminated */
247
14
      { "Effective command name", "pktap.ecmdname",
248
14
        FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL } },
249
14
  };
250
251
14
  static int *ett[] = {
252
14
    &ett_pktap,
253
14
  };
254
255
14
  static ei_register_info ei[] = {
256
14
      { &ei_pktap_hdrlen_too_short,
257
14
        { "pktap.hdrlen_too_short", PI_MALFORMED, PI_ERROR,
258
14
          "Header length is too short", EXPFILL }},
259
14
  };
260
261
14
  expert_module_t* expert_pktap;
262
263
14
  proto_pktap = proto_register_protocol("PKTAP packet header", "PKTAP",
264
14
      "pktap");
265
14
  proto_register_field_array(proto_pktap, hf, array_length(hf));
266
14
  proto_register_subtree_array(ett, array_length(ett));
267
14
  expert_pktap = expert_register_protocol(proto_pktap);
268
14
  expert_register_field_array(expert_pktap, ei, array_length(ei));
269
270
14
  pktap_handle = register_dissector("pktap", dissect_pktap, proto_pktap);
271
14
}
272
273
void
274
proto_reg_handoff_pktap(void)
275
14
{
276
14
  capture_dissector_handle_t pktap_cap_handle;
277
278
14
  dissector_add_uint("wtap_encap", WTAP_ENCAP_PKTAP, pktap_handle);
279
280
14
  pcap_pktdata_handle = find_dissector_add_dependency("pcap_pktdata", proto_pktap);
281
282
  /* XXX - WTAP_ENCAP_USER2 to handle Mavericks' botch wherein it
283
    uses DLT_USER2 for PKTAP; if you are using DLT_USER2 for your
284
    own purposes, feel free to call your own capture_ routine for
285
    WTAP_ENCAP_USER2. */
286
14
  pktap_cap_handle = create_capture_dissector_handle(capture_pktap, proto_pktap);
287
14
  capture_dissector_add_uint("wtap_encap", WTAP_ENCAP_PKTAP, pktap_cap_handle);
288
14
  capture_dissector_add_uint("wtap_encap", WTAP_ENCAP_USER2, pktap_cap_handle);
289
290
14
  eth_cap_handle = find_capture_dissector("eth");
291
14
}
292
293
/*
294
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
295
 *
296
 * Local variables:
297
 * c-basic-offset: 8
298
 * tab-width: 8
299
 * indent-tabs-mode: t
300
 * End:
301
 *
302
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
303
 * :indentSize=8:tabSize=8:noTabs=false:
304
 */