Coverage Report

Created: 2025-08-04 07:15

/src/wireshark/epan/dissectors/packet-f5ethtrailer.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-f5ethtrailer.c
2
 *
3
 * F5 Ethernet Trailer Copyright 2008-2018 F5 Networks
4
 *
5
 * SPDX-License-Identifier: GPL-2.0-or-later
6
 */
7
8
/*
9
Supported Platforms:
10
    BIG-IP 9.4.2 - 13.x for the old format trailers
11
    BIG-IP 11.2.0 and later for fileinfo
12
    BIG-IP 14.0 began using the new format trailers
13
14
Usage:
15
16
  * Acquire capture files using the following command line:
17
    * tcpdump -w capture.pcap -s0 -i internal:nnn
18
  * Load the capture file into wireshark.
19
20
  * Observe the grammar added to the beginning of each packet in the "Info"
21
    column of the packet list pane.
22
  * Observe the added "F5 Ethernet trailer" section in the packet detail
23
    pane.
24
  * These fields are filterable like any other field.
25
  * Review the preferences for the dissector.
26
27
  * If you are missing the Low details of the trailer for some packets, try
28
    modifying the settings for the Ethernet dissector.  Go to "Edit/Preferences...",
29
    expand "Protocols" on the left and select "Ethernet".  Disable "Assume
30
    short frames which include a trailer contain padding".
31
32
Notes:
33
34
  Follow F5 Conversation:
35
36
    As an alternative to the Populate Fields for Other Dissectors below, you
37
    can now follow a connection through the BIG-IP using the main menu
38
    Analyze/Conversation Filter menu.  There are three options: follow "F5 IP",
39
    "F5 TCP" or "F5 UDP".  Select a frame and choose the appropriate menu item.
40
    For best results, disable Populate Fields for Other Dissectors.  This
41
    method of following a conversation should avoid the stray packets problem
42
    mentioned below.
43
44
    These menu selections will populate an appropriate filter expression with
45
    ip.addr, tcp.port or udp.port, f5ethtrailer.peeraddr, f5ethtrailer.peerport
46
    and f5ethtrailer.peeripproto.
47
48
    You will need to have gathered the capture with high noise (":nnn") to
49
    contain the peer flow information in order for this to work.
50
51
  Populate Fields for Other Dissectors:
52
53
    The populate fields for other dissectors will add hidden fields to the
54
    f5ethtrailer for "ip.addr", "ipv6.addr", "tcp.port" and "udp.port" based on
55
    information in high noise of a packet.  This will allow the "Conversation
56
    Filter" option in Wireshark to find both the client-side and server-side
57
    flows for a connection.
58
59
    In order to use this, you will need to enable the "Populate fields for
60
    other dissectors" preference.  Note that the fields are registered when the
61
    preference is enabled.  After changing the preference, you may need to
62
    restart Wireshark for proper handling.
63
64
    Please note that this may cause some stray packets to show up in filter
65
    results since, for example, "tcp.port eq A and tcp.port eq B" can now be
66
    matching on at least four fields (tcp.port from the TCP dissector and
67
    tcp.port from the f5ethtrailer dissector) and a filter can match on an
68
    address/port from the IP/TCP/UDP dissector or an address/port from the
69
    f5ethtrailer dissector.
70
71
    For example, given two connections:
72
      client:12345 <-> VIP:443 {BIGIP} clientS:12346 <-> poolmember:80
73
      client:12346 <-> VIP:443 {BIGIP} clientS:12347 <-> poolmember:80
74
    Selecting "Conversation Filter->TCP" on the client side of the second
75
    connection will result in a filter of:
76
      ip.addr eq client and ip.addr eq VIP and
77
      tcp.port eq 12346 and tcp.port eq 443
78
    All four flows would be displayed by the filter:
79
      * From client:12345 <-> VIP:443 (unexpected)
80
        - ip.addr from ip.src matches.
81
        - ip.addr from ip.dst matches.
82
        - tcp.port from f5ethtrailer.peerlocalport matches.
83
        - tcp.port from tcp.dstport matches.
84
      * From clientS:12346 <-> poolmember:80 (unexpected)
85
        - ip.addr from f5ethtrailer.peerremoteaddr matches.
86
        - ip.addr from f5ethtrailer.peerlocaladdr matches.
87
        - tcp.port from tcp.srcport matches.
88
        - tcp.port from f5ethtrailer.peerlocalport matches.
89
      * From client:12346 <-> VIP:443 (expected)
90
        - ip.addr from ip.src matches.
91
        - ip.addr from ip.dst matches.
92
        - tcp.port from tcp.srcport matches.
93
        - tcp.port from tcp.dstport matches.
94
      * From clientS:12347 <-> poolmember:80 (desired)
95
        - ip.addr from f5ethtrailer.peerremoteaddr matches.
96
        - ip.addr from f5ethtrailer.peerlocaladdr matches.
97
        - tcp.port from f5ethtrailer.peerremoteport matches.
98
        - tcp.port from f5ethtrailer.peerlocalport matches.
99
100
    You can filter based on IP/port information by disabling the "Populate
101
    fields for other dissectors" and creating your own filter like:
102
      ( ip.addr eq client and ip.addr eq VIP and
103
        tcp.port eq 12346 and tcp.port eq 443 ) or
104
      ( f5ethtrailer.peeraddr eq client and f5ethtrailer.peeraddr eq VIP and
105
        f5ethtrailer.peerport eq 12346 and f5ethtrailer.peerport eq 443 )
106
107
    Since the preference is disabled by default, it should not cause any
108
    interference unless the user actively enables the preference.
109
110
  Analysis:
111
112
    The f5ethtrailer dissector can add an "F5 Analysis" subtree to the "F5
113
    Ethernet trailer" protocol tree.  The items added here are also added to
114
    Wireshark expert info.  The analysis done is intended to help spot traffic
115
    anomalies.
116
117
    Possible Analysis:
118
      * Flow reuse or SYN retransmit
119
        Filter field name: f5ethtrailer.analysis.flowreuse
120
        This is intended to highlight initial packets that arrive that match
121
        a pre-existing flow.  In other words, a TCP SYN packet that arrives
122
        and matches an existing flow.  This can indicate:
123
        - A prior flow was not properly terminated and a new flow is starting.
124
        - A stray SYN has arrived for an existing connection.
125
        - A SYN has been retransmitted (the first SYN would have created the
126
          flow that subsequent SYNs would match).
127
128
      * Flow lost, incorrect VLAN, loose initiation, tunnel or SYN cookie use
129
        Filter field name: f5ethtrailer.analysis.flowlost
130
        This is intended to highlight non-initial packets that arrive that
131
        do not match an existing flow.  In other words, a TCP non-SYN packet
132
        arriving that does not match an existing flow.  This can indicate:
133
        - The flow is no longer in the BIGIP's connection table.
134
        - VLAN keyed connections is in use (the default) and a packet arrived
135
          on an incorrect VLAN.
136
        - A stray packet has arrived.
137
        - The packet may be handled by a virtual server with loose initiation.
138
          In this case, a packet in the middle of a TCP conversation could
139
          arrive and then be handled by a virtual server that has loose
140
          initiation enabled to create a flow.
141
        - The packet may be the inner payload of a tunnel.  For inbound tunnel
142
          traffic, the encapsulating packet is shown as well as the
143
          encapsulated packet (and the encapsulated packet may not have flow
144
          information).
145
        - SYN cookies are being used (the initial SYN would not have created
146
          a flow).
147
148
    A few notes.  The analysis is implemented by using Wireshark taps and
149
    tapping the IP/IPv6/TCP dissectors.  The taps are not called until after
150
    packet dissection is completely finished.  So, the f5ethtrailer dissector
151
    may not have the necessary data to draw conclusions.  The traffic light
152
    in the lower left corner of the Wireshark GUI might not properly reflect
153
    the existence of these analysis fields.
154
155
  Hiding Slot Information in Info Column:
156
157
    You can now specify which platforms will display slot information in the
158
    summary in the info columns.  In the preferences for the F5 Ethernet
159
    trailer dissector, you can provide a regular expression to match the
160
    platform in F5 tcpdump header packet.  If there is no platform information
161
    in the header (or there is no header at all), slot information will always
162
    be displayed.  A reasonable regular expression would be "^(A.*|Z101)$" to
163
    match chassis and vCMP platforms (there is no distinction for vCMP on a
164
    chassis versus an appliance).  The default is to always display slot
165
    information (no regular expression is provided by default).
166
167
  Statistics reports:
168
169
    All statistics are reported as packet counts and byte counts.  Byte count
170
    statistics do not include the bytes of the trailer.
171
172
    Statistics menu now has:
173
      F5/Virtual Server Distribution
174
        A line for each named virtual server name
175
        A line for traffic with a flow ID and no virtual server name
176
        A line for traffic without a flow ID.
177
178
      F5/tmm Distribution
179
        A line for each tmm.
180
          A line each for ingress and egress (should add to tmm total)
181
          A line each for (should add to tmm total)
182
            Traffic with a virtual server name
183
            Traffic with a flow ID and no virtual server name
184
            Traffic without a flow ID.
185
 */
186
187
#include "config.h"
188
189
#include <string.h>
190
#include <epan/packet.h>
191
#include <epan/prefs.h>
192
#include <epan/epan_dissect.h>
193
#include <epan/ipproto.h>
194
#include <epan/tap.h>
195
#include <epan/expert.h>
196
#include <epan/proto.h>
197
#include <epan/proto_data.h>
198
#include <epan/conversation_filter.h>
199
#include <epan/tfs.h>
200
201
#include "packet-ip.h"
202
#include "packet-tcp.h"
203
#include <epan/to_str.h>
204
#include <epan/stats_tree.h>
205
#define F5FILEINFOTAP_SRC
206
#include "packet-f5ethtrailer.h"
207
#undef F5FILEINFOTAP_SRC
208
#include <wsutil/wslog.h>
209
210
/* Wireshark ID of the F5ETHTRAILER protocol */
211
static int proto_f5ethtrailer;
212
static int tap_f5ethtrailer   = -1;
213
static int proto_f5fileinfo;
214
static int tap_f5fileinfo     = -1;
215
/** Helper dissector for DPT format noise */
216
static int proto_f5ethtrailer_dpt_noise;
217
218
void proto_reg_handoff_f5ethtrailer(void);
219
void proto_register_f5ethtrailer(void);
220
221
void proto_reg_handoff_f5fileinfo(void);
222
void proto_register_f5fileinfo(void);
223
224
static dissector_handle_t f5dpt_noise_handle;
225
static dissector_handle_t f5dpt_tls_handle;
226
227
228
/* Common Fields */
229
static int hf_provider;
230
static int hf_type;
231
static int hf_length;
232
static int hf_version;
233
static int hf_data;
234
static int hf_data_str;
235
static int hf_dpt_unknown;
236
static int hf_trailer_hdr;
237
static int hf_orig_fcs;
238
/* Low */
239
static int hf_low_id;
240
static int hf_flags;
241
static int hf_flags_ingress;
242
static int hf_flags_hwaction;
243
static int hf_ingress;
244
static int hf_slot0;
245
static int hf_slot1;
246
static int hf_tmm;
247
static int hf_obj_name_type;
248
static int hf_obj_data_len;
249
static int hf_vipnamelen;
250
static int hf_vip;
251
static int hf_portnamelen;
252
static int hf_phys_port;
253
static int hf_trunknamelen;
254
static int hf_trunk;
255
/* Med */
256
static int hf_med_id;
257
static int hf_flow_id;
258
static int hf_peer_id;
259
static int hf_any_flow;
260
static int hf_cf_flags;
261
static int hf_cf_flags2;
262
static int hf_flow_type;
263
static int hf_ha_unit;
264
static int hf_reserved;
265
static int hf_priority;
266
static int hf_rstcause;
267
static int hf_rstcause_len;
268
static int hf_rstcause_ver;
269
static int hf_rstcause_peer;
270
static int hf_rstcause_val;
271
static int hf_rstcause_line;
272
static int hf_rstcause_txt;
273
/* High */
274
static int hf_high_id;
275
static int hf_peer_ipproto;
276
static int hf_peer_vlan;
277
static int hf_peer_remote_addr;
278
static int hf_peer_remote_ip6addr;
279
static int hf_peer_remote_rtdom;
280
static int hf_peer_local_addr;
281
static int hf_peer_local_ip6addr;
282
static int hf_peer_local_rtdom;
283
static int hf_peer_ipaddr;
284
static int hf_peer_ip6addr;
285
static int hf_peer_rtdom;
286
static int hf_peer_remote_port;
287
static int hf_peer_local_port;
288
static int hf_peer_port;
289
static int hf_peer_nopeer;
290
/* Analysis */
291
static int hf_analysis;
292
293
/* These fields will be used if pref_pop_other_fields is enabled.
294
   They will be populated with data from the "high" trailer so that filtering on ip.addr, tcp.port, etc...
295
   can find peer side flows of the specific flow you're searching for. */
296
static int hf_ip_ipaddr;
297
static int hf_ip6_ip6addr;
298
static int hf_tcp_tcpport;
299
static int hf_udp_udpport;
300
301
static int hf_dpt_magic;
302
static int hf_dpt_ver;
303
static int hf_dpt_len;
304
305
static expert_field ei_f5eth_flowlost;
306
static expert_field ei_f5eth_flowreuse;
307
static expert_field ei_f5eth_badlen;
308
static expert_field ei_f5eth_undecoded;
309
310
/* These are the ids of the subtrees that we may be creating */
311
static int ett_f5ethtrailer;
312
static int ett_f5ethtrailer_unknown;
313
static int ett_f5ethtrailer_low;
314
static int ett_f5ethtrailer_low_flags;
315
static int ett_f5ethtrailer_med;
316
static int ett_f5ethtrailer_high;
317
static int ett_f5ethtrailer_rstcause;
318
static int ett_f5ethtrailer_trailer_hdr;
319
static int ett_f5ethtrailer_obj_names;
320
321
/* For fileinformation */
322
static int hf_fi_command;
323
static int hf_fi_version;
324
static int hf_fi_hostname;
325
static int hf_fi_platform;
326
static int hf_fi_platformname;
327
static int hf_fi_product;
328
static int hf_fi_session;
329
330
/* Wireshark preference to show RST cause in info column */
331
static bool rstcause_in_info = true;
332
/** Wireshark preference to look at all trailer bytes for f5ethtrailer */
333
static bool pref_walk_trailer;
334
/* Wireshark preference to enable/disable the population of other dissectors'
335
 * fields.*/
336
static bool pref_pop_other_fields;
337
/** Wireshark preference to perform analysis */
338
static bool pref_perform_analysis;
339
/** Wireshark preference to generate keylog entries from f5ethtrailer TLS data */
340
static bool pref_generate_keylog = true;
341
/** Identifiers for taps (when enabled), only the address is important, the
342
 * values are unused. */
343
static bool tap_ip_enabled;
344
static bool tap_ipv6_enabled;
345
static bool tap_tcp_enabled;
346
347
/** Used "in" and "out" map for the true and false for ingress. (Not actually
348
 * used in field definition, but rather used to display via a format call
349
 * and in the info column information.) */
350
static const true_false_string f5tfs_ing = {"IN", "OUT"};
351
352
static const value_string f5_flags_ingress_vs[] = {
353
    {0, "Out"},
354
    {1, "In"},
355
    {0, NULL}
356
};
357
358
/** Strings for decoding the hardware action */
359
static const value_string f5_flags_hwaction_vs[] = {
360
    {0, "Not set"},
361
    {1, "Challenge"},
362
    {2, "Drop"},
363
    {3, "Forward"},
364
    {0, NULL}
365
};
366
367
static int * const hf_flags__fields[] = {
368
    &hf_flags_ingress,
369
    &hf_flags_hwaction,
370
    NULL,
371
};
372
373
typedef enum {
374
    NONE,
375
    NEW_FORMAT,
376
    OLD_FORMAT,
377
} found_t;
378
379
/** Table containing subdissectors for different providers
380
 *  These are used with new format trailers */
381
static dissector_table_t provider_subdissector_table;
382
static dissector_table_t noise_subdissector_table;
383
384
/*-----------------------------------------------------------------------------------------------*/
385
/**
386
 * @brief Convert a Wireshark port type to a IP protocol number.
387
 *
388
 * @attention Not all port types are supported, only the ones that this dissector actively uses.
389
 *
390
 * @param ptype The Wireshark port_type
391
 * @return      The IP protocol number corresponding to the port type.
392
 */
393
inline static uint8_t
394
ptype_to_ipproto(const port_type ptype)
395
0
{
396
0
    uint8_t ipproto = 0;
397
0
    switch (ptype) {
398
0
    case PT_TCP:
399
0
        ipproto = IP_PROTO_TCP;
400
0
        break;
401
0
    case PT_UDP:
402
0
        ipproto = IP_PROTO_UDP;
403
0
        break;
404
0
    default:
405
0
        ipproto = 0;
406
0
        break;
407
0
    }
408
0
    return ipproto;
409
0
} /* ptype_to_ipproto() */
410
411
/*===============================================================================================*/
412
/* Analyze menu functions */
413
414
/*-----------------------------------------------------------------------------------------------*/
415
/**
416
 * @brief Determines if we can apply an IP Conversation filter.
417
 *
418
 * @attention This is an interface function to be called from the rest of wireshark.
419
 *
420
 * @param pinfo   A pointer to the packet info to look at for the L3 data.
421
 * @return        True if it is valid IP/IPv6, false otherwise
422
 */
423
static bool
424
f5_ip_conv_valid(packet_info *pinfo, void *user_data _U_)
425
0
{
426
0
    bool is_ip = false;
427
0
    bool is_f5ethtrailer = false;
428
429
0
    proto_get_frame_protocols(pinfo->layers, &is_ip, NULL, NULL, NULL, NULL, NULL, NULL);
430
0
    is_f5ethtrailer = proto_is_frame_protocol(pinfo->layers, "f5ethtrailer");
431
432
0
    return is_ip && is_f5ethtrailer;
433
0
} /* f5_ip_conv_valid() */
434
435
/*-----------------------------------------------------------------------------------------------*/
436
/**
437
 * @brief Determines if we can apply a TCP Conversation filter.
438
 *
439
 * @attention This is an interface function to be called from the rest of wireshark.
440
 *
441
 * @param pinfo   A pointer to the packet info to look at for the L3/L4 data.
442
 * @return        True if it is valid IP/IPv6 + TCP, false otherwise
443
 */
444
static bool
445
f5_tcp_conv_valid(packet_info *pinfo, void *user_data _U_)
446
0
{
447
0
    bool is_ip  = false;
448
0
    bool is_tcp = false;
449
0
    bool is_f5ethtrailer = false;
450
451
0
    proto_get_frame_protocols(pinfo->layers, &is_ip, &is_tcp, NULL, NULL, NULL, NULL, NULL);
452
0
    is_f5ethtrailer = proto_is_frame_protocol(pinfo->layers, "f5ethtrailer");
453
454
0
    return is_ip && is_tcp && is_f5ethtrailer;
455
0
} /* f5_tcp_conv_valid() */
456
457
/*-----------------------------------------------------------------------------------------------*/
458
/**
459
 * @brief Determines if we can apply a UDP Conversation filter.
460
 *
461
 * @attention This is an interface function to be called from the rest of wireshark.
462
 *
463
 * @param pinfo   A pointer to the packet info to look at for the L3/L4 data.
464
 * @return        True if it is valid IP/IPv6 + UDP, false otherwise
465
 */
466
static bool
467
f5_udp_conv_valid(packet_info *pinfo, void *user_data _U_)
468
0
{
469
0
    bool is_ip  = false;
470
0
    bool is_udp = false;
471
0
    bool is_f5ethtrailer = false;
472
473
0
    proto_get_frame_protocols(pinfo->layers, &is_ip, NULL, &is_udp, NULL, NULL, NULL, NULL);
474
0
    is_f5ethtrailer = proto_is_frame_protocol(pinfo->layers, "f5ethtrailer");
475
476
0
    return is_ip && is_udp && is_f5ethtrailer;
477
0
} /* f5_tcp_conv_valid() */
478
479
/*-----------------------------------------------------------------------------------------------*/
480
/**
481
 * @brief Calculates the F5 IP conversation filter based on the current packet.
482
 *
483
 * @attention This is an interface function to be called from the rest of wireshark.
484
 *
485
 * @param pinfo   A pointer to the packet info to look at for the L3/L4 data.
486
 * @return        A filter string for the F5 IP conversation or NULL if no filter can be
487
 *                  computed.  The caller should free this string with g_free().
488
 *
489
 * @attention This function uses ws_strdup_printf() rather than the wmem equivalent because the
490
 *             caller (menu_dissector_filter_cb()) uses g_free to free the filter string.
491
 *             (as of WS 1.12).
492
 */
493
static char *
494
f5_ip_conv_filter(packet_info *pinfo, void *user_data _U_)
495
0
{
496
0
    char *buf = NULL;
497
0
    char src_addr[WS_INET6_ADDRSTRLEN];
498
0
    char dst_addr[WS_INET6_ADDRSTRLEN];
499
500
0
    *dst_addr = *src_addr = '\0';
501
0
    if (pinfo->net_src.type == AT_IPv4 && pinfo->net_dst.type == AT_IPv4) {
502
0
        address_to_str_buf(&pinfo->src, src_addr, WS_INET6_ADDRSTRLEN);
503
0
        address_to_str_buf(&pinfo->dst, dst_addr, WS_INET6_ADDRSTRLEN);
504
0
        if (*src_addr != '\0' && *dst_addr != '\0') {
505
0
            buf = ws_strdup_printf(
506
0
                "(ip.addr eq %s and ip.addr eq %s) or"
507
0
                " (f5ethtrailer.peeraddr eq %s and f5ethtrailer.peeraddr eq %s)",
508
0
                src_addr, dst_addr, src_addr, dst_addr);
509
0
        }
510
0
    } else if (pinfo->net_src.type == AT_IPv6 && pinfo->net_dst.type == AT_IPv6) {
511
0
        address_to_str_buf(&pinfo->src, src_addr, WS_INET6_ADDRSTRLEN);
512
0
        address_to_str_buf(&pinfo->dst, dst_addr, WS_INET6_ADDRSTRLEN);
513
0
        if (*src_addr != '\0' && *dst_addr != '\0') {
514
0
            buf = ws_strdup_printf(
515
0
                "(ipv6.addr eq %s and ipv6.addr eq %s) or"
516
0
                " (f5ethtrailer.peeraddr6 eq %s and f5ethtrailer.peeraddr6 eq %s)",
517
0
                src_addr, dst_addr, src_addr, dst_addr);
518
0
        }
519
0
    }
520
0
    return buf;
521
0
} /* f5_ip_conv_filter() */
522
523
/*-----------------------------------------------------------------------------------------------*/
524
/**
525
 * @brief Calculates the F5 TCP conversation filter based on the current packet.
526
 *
527
 * @attention This is an interface function to be called from the rest of wireshark.
528
 *
529
 * @param pinfo   A pointer to the packet info to look at for the L3/L4 data.
530
 *
531
 * @return        A filter string for the F5 TCP conversation or NULL if no filter can be
532
 *                  computed.  The caller should free this string with g_free().
533
 *
534
 *  Prior to version 11.0.0, the f5ethtrailer.peeripproto field was not populated properly.  In
535
 *  an effort to accurately match the appropriate protocol, the filter adds:
536
 *       f5ethtrailer.ipproto eq 6 (for the >=11.0.0 case)
537
 *    or f5ethtrailer.ipproto eq 0 and tcp (for the <11.0.0 case)
538
 *  This is in an attempt to try to not pick up UDP packets that happen to have the same ports when
539
 *  you are filtering on a TCP conversation.  Note that in the <11.0.0 case, an IP protocol change
540
 *  across the peer flows (I don't know that I've seen that happen, so it's at least rare) will not
541
 *  be filtered properly.  In the >=11.0.0 case, if you have TCP on one side and UDP on the other
542
 *  and it should "do the right thing".
543
 *
544
 * @attention This function uses ws_strdup_printf() rather than the wmem equivalent because the
545
 *             caller (menu_dissector_filter_cb()) uses g_free to free the filter string.
546
 *             (as of WS 1.12).
547
 */
548
static char *
549
f5_tcp_conv_filter(packet_info *pinfo, void *user_data _U_)
550
0
{
551
0
    char *buf = NULL;
552
0
    char src_addr[WS_INET6_ADDRSTRLEN];
553
0
    char dst_addr[WS_INET6_ADDRSTRLEN];
554
555
0
    *dst_addr = *src_addr = '\0';
556
0
    if (pinfo->net_src.type == AT_IPv4 && pinfo->net_dst.type == AT_IPv4) {
557
0
        address_to_str_buf(&pinfo->src, src_addr, WS_INET6_ADDRSTRLEN);
558
0
        address_to_str_buf(&pinfo->dst, dst_addr, WS_INET6_ADDRSTRLEN);
559
0
        if (*src_addr != '\0' && *dst_addr != '\0') {
560
0
            buf = ws_strdup_printf(
561
0
                "(ip.addr eq %s and ip.addr eq %s and tcp.port eq %d and tcp.port eq %d) or"
562
0
                " (f5ethtrailer.peeraddr eq %s and f5ethtrailer.peeraddr eq %s and"
563
0
                " f5ethtrailer.peerport eq %d and f5ethtrailer.peerport eq %d and"
564
0
                " (f5ethtrailer.peeripproto eq 6 or (f5ethtrailer.peeripproto eq 0 and tcp)))",
565
0
                src_addr, dst_addr, pinfo->srcport, pinfo->destport,
566
0
                src_addr, dst_addr, pinfo->srcport, pinfo->destport);
567
0
        }
568
0
    } else if (pinfo->net_src.type == AT_IPv6 && pinfo->net_dst.type == AT_IPv6) {
569
0
        address_to_str_buf(&pinfo->src, src_addr, WS_INET6_ADDRSTRLEN);
570
0
        address_to_str_buf(&pinfo->dst, dst_addr, WS_INET6_ADDRSTRLEN);
571
0
        if (*src_addr != '\0' && *dst_addr != '\0') {
572
0
            buf = ws_strdup_printf(
573
0
                "(ipv6.addr eq %s and ipv6.addr eq %s and tcp.port eq %d and tcp.port eq %d) or"
574
0
                " (f5ethtrailer.peeraddr6 eq %s and f5ethtrailer.peeraddr6 eq %s and"
575
0
                " f5ethtrailer.peerport eq %d and f5ethtrailer.peerport eq %d and"
576
0
                " (f5ethtrailer.peeripproto eq 6 or (f5ethtrailer.peeripproto eq 0 and tcp)))",
577
0
                src_addr, dst_addr, pinfo->srcport, pinfo->destport,
578
0
                src_addr, dst_addr, pinfo->srcport, pinfo->destport);
579
0
        }
580
0
    }
581
0
    return buf;
582
0
} /* f5_tcp_conv_filter() */
583
584
/*-----------------------------------------------------------------------------------------------*/
585
/**
586
 * @brief Calculates the F5 UDP conversation filter based on the current packet.
587
 *
588
 * @attention This is an interface function to be called from the rest of wireshark.
589
 *
590
 * @param pinfo   A pointer to the packet info to look at for the L3/L4 data.
591
 * @return        A filter string for the F5 UDP conversation or NULL if no filter can be
592
 *                  computed.  The caller should free this string with g_free().
593
 *
594
 *  Prior to version 11.0.0, the f5ethtrailer.peeripproto field was not populated properly.  In
595
 *  an effort to accurately match the appropriate protocol, the filter adds:
596
 *       f5ethtrailer.ipproto eq 17 (for the >=11.0.0 case)
597
 *    or f5ethtrailer.ipproto eq 0 and udp (for the <11.0.0 case)
598
 *  This is in an attempt to try to not pick up TCP packets that happen to have the same ports when
599
 *  you are filtering on a UDP conversation.  Note that in the <11.0.0 case, an IP protocol change
600
 *  across the peer flows (I don't know that I've seen that happen, so it's at least rare) will not
601
 *  be filtered properly.  In the >=11.0.0 case, if you have TCP on one side and UDP on the other
602
 *  and it should "do the right thing".
603
 *
604
 * @attention This function uses ws_strdup_printf() rather than the wmem equivalent because the
605
 *             caller (menu_dissector_filter_cb()) uses g_free to free the filter string.
606
 *             (as of WS 1.12).
607
 */
608
static char *
609
f5_udp_conv_filter(packet_info *pinfo, void *user_data _U_)
610
0
{
611
0
    char *buf = NULL;
612
0
    char src_addr[WS_INET6_ADDRSTRLEN];
613
0
    char dst_addr[WS_INET6_ADDRSTRLEN];
614
615
0
    *dst_addr = *src_addr = '\0';
616
0
    if (pinfo->net_src.type == AT_IPv4 && pinfo->net_dst.type == AT_IPv4) {
617
0
        address_to_str_buf(&pinfo->src, src_addr, WS_INET6_ADDRSTRLEN);
618
0
        address_to_str_buf(&pinfo->dst, dst_addr, WS_INET6_ADDRSTRLEN);
619
0
        if (*src_addr != '\0' && *dst_addr != '\0') {
620
0
            buf = ws_strdup_printf(
621
0
                "(ip.addr eq %s and ip.addr eq %s and udp.port eq %d and udp.port eq %d) or"
622
0
                " (f5ethtrailer.peeraddr eq %s and f5ethtrailer.peeraddr eq %s and"
623
0
                " f5ethtrailer.peerport eq %d and f5ethtrailer.peerport eq %d and"
624
0
                " (f5ethtrailer.peeripproto eq 17 or (f5ethtrailer.peeripproto eq 0 and udp)))",
625
0
                src_addr, dst_addr, pinfo->srcport, pinfo->destport,
626
0
                src_addr, dst_addr, pinfo->srcport, pinfo->destport);
627
0
        }
628
0
    } else if (pinfo->net_src.type == AT_IPv6 && pinfo->net_dst.type == AT_IPv6) {
629
0
        address_to_str_buf(&pinfo->src, src_addr, WS_INET6_ADDRSTRLEN);
630
0
        address_to_str_buf(&pinfo->dst, dst_addr, WS_INET6_ADDRSTRLEN);
631
0
        if (*src_addr != '\0' && *dst_addr != '\0') {
632
0
            buf = ws_strdup_printf(
633
0
                "(ipv6.addr eq %s and ipv6.addr eq %s and udp.port eq %d and udp.port eq %d) or"
634
0
                " (f5ethtrailer.peeraddr6 eq %s and f5ethtrailer.peeraddr6 eq %s and"
635
0
                " f5ethtrailer.peerport eq %d and f5ethtrailer.peerport eq %d and"
636
0
                " (f5ethtrailer.peeripproto eq 17 or (f5ethtrailer.peeripproto eq 0 and udp)))",
637
0
                src_addr, dst_addr, pinfo->srcport, pinfo->destport,
638
0
                src_addr, dst_addr, pinfo->srcport, pinfo->destport);
639
0
        }
640
0
    }
641
0
    return buf;
642
0
} /* f5_udp_conv_filter() */
643
644
/* End of Analyze menu functions */
645
/*===============================================================================================*/
646
647
/*===============================================================================================*/
648
/* Stats tree functions */
649
650
static int st_node_tmmpktdist              = -1; /**< Tree for packet counts */
651
static int st_node_tmmbytedist             = -1; /**< Tree for byte counts (excludes trailer) */
652
static const char *st_str_tmmdist         = "F5" STATS_TREE_MENU_SEPARATOR "tmm Distribution";
653
static const char *st_str_tmmdist_pkts    = "tmm Packet Distribution";
654
static const char *st_str_tmmdist_bytes   = "tmm Byte Distribution (excludes trailer)";
655
static const char *st_str_tmm_dir_in      = "direction in";
656
static const char *st_str_tmm_dir_out     = "direction out";
657
static const char *st_str_tmm_flow_virt   = "flow with virtual";
658
static const char *st_str_tmm_flow_novirt = "flow without virtual";
659
static const char *st_str_tmm_flow_none   = "flow none";
660
661
static int st_node_virtpktdist             = -1; /**< Tree for packet counts */
662
static int st_node_virtbytedist            = -1; /**< Tree for packet counts (excludes trailer) */
663
static const char *st_str_virtdist        = "F5" STATS_TREE_MENU_SEPARATOR "Virtual Server Distribution";
664
static const char *st_str_virtdist_pkts   = "Virtual Server Packet Distribution";
665
static const char *st_str_virtdist_bytes  = "Virtual Server Byte Distribution (excludes trailer)";
666
static const char *st_str_virtdist_noflow = "No flow";
667
static const char *st_str_virtdist_novirt = "Flow without virtual server name";
668
669
/*-----------------------------------------------------------------------------------------------*/
670
/**
671
 * @brief Initializer for tmm distribution statistics
672
 *
673
 * @attention This is an interface function to be called from the rest of wireshark.
674
 *
675
 * @param st      A pointer to the stats tree to use
676
 *
677
 */
678
static void
679
f5eth_tmmdist_stats_tree_init(stats_tree *st)
680
0
{
681
0
    st_node_tmmpktdist = stats_tree_create_node(st, st_str_tmmdist_pkts, 0, STAT_DT_INT, true);
682
0
    stat_node_set_flags(st, st_str_tmmdist_pkts, 0, true, ST_FLG_SORT_TOP);
683
0
    st_node_tmmbytedist = stats_tree_create_node(st, st_str_tmmdist_bytes, 0, STAT_DT_INT, true);
684
0
} /* f5eth_tmmdist_stats_tree_init() */
685
686
/*-----------------------------------------------------------------------------------------------*/
687
/**
688
 * @brief Per-packet tmm distribution statistics
689
 *
690
 * @attention This is an interface function to be called from the rest of wireshark.
691
 *
692
 * @param st      A pointer to the stats tree to use
693
 * @param pinfo   A pointer to the packet info.
694
 * @param edt     Unused
695
 * @param data    A pointer to the data provided by the tap
696
 * @return        TAP_PACKET_REDRAW if the data was actually used to alter
697
 *                  the statistics, TAP_PACKET_DONT_REDRAW otherwise.
698
 *
699
 */
700
static tap_packet_status
701
f5eth_tmmdist_stats_tree_packet(
702
    stats_tree *st, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data, tap_flags_t flags _U_)
703
0
{
704
0
    const f5eth_tap_data_t *tdata = (const f5eth_tap_data_t *)data;
705
0
    uint32_t pkt_len;
706
0
    int st_node_tot_pkts;
707
0
    int st_node_tot_bytes;
708
0
    int st_node_tmm_pkts;
709
0
    int st_node_tmm_bytes;
710
0
    char *tmm_stat_name;
711
712
0
    if (tdata == NULL)
713
0
        return TAP_PACKET_DONT_REDRAW;
714
715
    /* Unnecessary since this tap packet function and the F5 Ethernet trailer dissector are both in
716
     * the same source file.  If you are using this function as an example in a separate tap source
717
     * file, you should uncomment this.
718
    if(check_f5eth_tap_magic(tdata) == 0) return TAP_PACKET_DONT_REDRAW;
719
     */
720
721
0
    tmm_stat_name = wmem_strdup_printf(NULL, "slot %3d,tmm %3d", tdata->slot, tdata->tmm);
722
723
0
    pkt_len = pinfo->fd->pkt_len - tdata->trailer_len;
724
725
0
    st_node_tot_pkts  = tick_stat_node(st, st_str_tmmdist_pkts, 0, true);
726
0
    st_node_tot_bytes = increase_stat_node(st, st_str_tmmdist_bytes, 0, true, pkt_len);
727
728
0
    st_node_tmm_pkts = tick_stat_node(st, tmm_stat_name, st_node_tot_pkts, true);
729
0
    st_node_tmm_bytes =
730
0
        increase_stat_node(st, tmm_stat_name, st_node_tot_bytes, true, pkt_len);
731
0
    if (tdata->ingress == 1) {
732
0
        tick_stat_node(st, st_str_tmm_dir_in, st_node_tmm_pkts, false);
733
0
        increase_stat_node(st, st_str_tmm_dir_in, st_node_tmm_bytes, false, pkt_len);
734
        /* Create nodes in case we see no egress packets */
735
0
        increase_stat_node(st, st_str_tmm_dir_out, st_node_tmm_pkts, false, 0);
736
0
        increase_stat_node(st, st_str_tmm_dir_out, st_node_tmm_bytes, false, 0);
737
0
    } else {
738
0
        tick_stat_node(st, st_str_tmm_dir_out, st_node_tmm_pkts, false);
739
0
        increase_stat_node(st, st_str_tmm_dir_out, st_node_tmm_bytes, false, pkt_len);
740
        /* Create nodes in case we see no ingress packets */
741
0
        increase_stat_node(st, st_str_tmm_dir_in, st_node_tmm_pkts, false, 0);
742
0
        increase_stat_node(st, st_str_tmm_dir_in, st_node_tmm_bytes, false, 0);
743
0
    }
744
745
0
    if (tdata->virtual_name == NULL) {
746
0
        if (tdata->flow == 0) {
747
            /* No flow ID and no virtual name */
748
0
            tick_stat_node(st, st_str_tmm_flow_none, st_node_tmm_pkts, false);
749
0
            increase_stat_node(st, st_str_tmm_flow_none, st_node_tmm_bytes, false, pkt_len);
750
751
            /* Create nodes in case we see no packets without a virtual */
752
0
            increase_stat_node(st, st_str_tmm_flow_novirt, st_node_tmm_pkts, false, 0);
753
0
            increase_stat_node(st, st_str_tmm_flow_novirt, st_node_tmm_bytes, false, 0);
754
0
        } else {
755
            /* Flow ID and no virtual name */
756
0
            tick_stat_node(st, st_str_tmm_flow_novirt, st_node_tmm_pkts, false);
757
0
            increase_stat_node(st, st_str_tmm_flow_novirt, st_node_tmm_bytes, false, pkt_len);
758
759
            /* Create nodes in case we see no packets with a virtual */
760
0
            increase_stat_node(st, st_str_tmm_flow_none, st_node_tmm_pkts, false, 0);
761
0
            increase_stat_node(st, st_str_tmm_flow_none, st_node_tmm_bytes, false, 0);
762
0
        }
763
        /* Create nodes in case we see no packets with a virtual */
764
0
        increase_stat_node(st, st_str_tmm_flow_virt, st_node_tmm_pkts, false, 0);
765
0
        increase_stat_node(st, st_str_tmm_flow_virt, st_node_tmm_bytes, false, 0);
766
0
    } else {
767
        /* Has a virtual name */
768
0
        tick_stat_node(st, st_str_tmm_flow_virt, st_node_tmm_pkts, false);
769
0
        increase_stat_node(st, st_str_tmm_flow_virt, st_node_tmm_bytes, false, pkt_len);
770
771
        /* Create nodes in case we see no packets without a virtual */
772
0
        increase_stat_node(st, st_str_tmm_flow_novirt, st_node_tmm_pkts, false, 0);
773
0
        increase_stat_node(st, st_str_tmm_flow_novirt, st_node_tmm_bytes, false, 0);
774
        /* Create nodes in case we see no packets without a flow */
775
0
        increase_stat_node(st, st_str_tmm_flow_none, st_node_tmm_pkts, false, 0);
776
0
        increase_stat_node(st, st_str_tmm_flow_none, st_node_tmm_bytes, false, 0);
777
0
    }
778
779
0
    wmem_free(NULL, tmm_stat_name);
780
0
    return TAP_PACKET_REDRAW;
781
0
} /* f5eth_tmmdist_stats_tree_packet() */
782
783
/*-----------------------------------------------------------------------------------------------*/
784
/**
785
 * @brief Initialize Virtual Server stats tree
786
 *
787
 * @param st A pointer to the stats tree to use
788
 */
789
static void
790
f5eth_virtdist_stats_tree_init(stats_tree *st)
791
0
{
792
0
    st_node_virtpktdist = stats_tree_create_node(st, st_str_virtdist_pkts, 0, STAT_DT_INT, true);
793
0
    stat_node_set_flags(st, st_str_virtdist_pkts, 0, true, ST_FLG_SORT_TOP);
794
0
    st_node_virtbytedist = stats_tree_create_node(st, st_str_virtdist_bytes, 0, STAT_DT_INT, true);
795
796
0
    stats_tree_create_node(st, st_str_virtdist_noflow, st_node_virtpktdist, STAT_DT_INT, true);
797
0
    stat_node_set_flags(st, st_str_virtdist_noflow, st_node_virtpktdist, true, ST_FLG_SORT_TOP);
798
0
    stats_tree_create_node(st, st_str_virtdist_novirt, st_node_virtpktdist, STAT_DT_INT, true);
799
0
    stat_node_set_flags(st, st_str_virtdist_novirt, st_node_virtpktdist, true, ST_FLG_SORT_TOP);
800
801
0
    stats_tree_create_node(st, st_str_virtdist_noflow, st_node_virtbytedist, STAT_DT_INT, true);
802
0
    stat_node_set_flags(st, st_str_virtdist_noflow, st_node_virtbytedist, true, ST_FLG_SORT_TOP);
803
0
    stats_tree_create_node(st, st_str_virtdist_novirt, st_node_virtbytedist, STAT_DT_INT, true);
804
0
    stat_node_set_flags(st, st_str_virtdist_novirt, st_node_virtbytedist, true, ST_FLG_SORT_TOP);
805
0
} /* f5eth_virtdist_stats_tree_init() */
806
807
/*-----------------------------------------------------------------------------------------------*/
808
/**
809
 * @brief Per-packet Virtual Server distribution statistics
810
 *
811
 * @param st      A pointer to the stats tree to use
812
 * @param pinfo   A pointer to the packet info.
813
 * @param edt     Unused
814
 * @param data    A pointer to the data provided by the tap
815
 * @return        TAP_PACKET_REDRAW if the data was actually used to alter
816
 *                  the statistics, TAP_PACKET_DONT_REDRAW otherwise.
817
 */
818
static tap_packet_status
819
f5eth_virtdist_stats_tree_packet(
820
    stats_tree *st, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data, tap_flags_t flags _U_)
821
0
{
822
0
    const f5eth_tap_data_t *tdata = (const f5eth_tap_data_t *)data;
823
0
    uint32_t pkt_len;
824
825
0
    if (tdata == NULL)
826
0
        return TAP_PACKET_DONT_REDRAW;
827
    /* Unnecessary since this tap packet function and the F5 Ethernet trailer dissector are both in
828
     * the same source file.  If you are using this function as an example in a separate tap source
829
     * file, you should uncomment this.
830
    if(check_f5eth_tap_magic(tdata) == 0) return TAP_PACKET_DONT_REDRAW;
831
     */
832
833
0
    pkt_len = pinfo->fd->pkt_len - tdata->trailer_len;
834
835
0
    tick_stat_node(st, st_str_virtdist_pkts, 0, true);
836
0
    increase_stat_node(st, st_str_virtdist_bytes, 0, true, pkt_len);
837
838
    /* We could have low noise (with a virtual name) without medium noise (with the flow ID).
839
     * That will get treated as a no flow case. */
840
0
    if (tdata->virtual_name == NULL) {
841
0
        if (tdata->flow == 0) {
842
            /* No flow ID */
843
0
            tick_stat_node(st, st_str_virtdist_noflow, st_node_virtpktdist, true);
844
0
            increase_stat_node(st, st_str_virtdist_noflow, st_node_virtbytedist, true, pkt_len);
845
0
        } else {
846
            /* Flow ID without virtual name */
847
0
            tick_stat_node(st, st_str_virtdist_novirt, st_node_virtpktdist, true);
848
0
            increase_stat_node(st, st_str_virtdist_novirt, st_node_virtbytedist, true, pkt_len);
849
0
        }
850
0
    } else {
851
        /* Has virtual name */
852
0
        tick_stat_node(st, tdata->virtual_name, st_node_virtpktdist, true);
853
0
        increase_stat_node(st, tdata->virtual_name, st_node_virtbytedist, true, pkt_len);
854
0
    }
855
856
0
    return TAP_PACKET_REDRAW;
857
0
} /* f5eth_virtdist_stats_tree_packet() */
858
859
/* End of statistics gathering */
860
/*===============================================================================================*/
861
862
/*===============================================================================================*/
863
/* Info column display handling.
864
 *
865
 * Format Specifiers:
866
 *   in/out are separate formats so that no printf formatting is required for these two common
867
 *     alternatives.
868
 *   There are two sets of six format strings.  One set corresponding to "full" or long output
869
 *     ("long" is not used due to conflict with C keyword) and the other set corresponding to
870
 *     "brief" output.
871
 *     Full:
872
 *       in/out only; one for in, one for out:
873
 *         info_format_full_in_only,    info_format_full_out_only
874
 *       in/out, slot and tmm; one for in and one for out:
875
 *         info_format_full_in_slot,    info_format_full_out_slot
876
 *       in/out and tmm (no slot information); one for in and one for out:
877
 *         info_format_full_in_noslot,  info_format_full_out_noslot
878
 *     Brief:
879
 *       in/out only; one for in, one for out:
880
 *         info_format_brief_in_only,   info_format_brief_out_only
881
 *       in/out, slot and tmm; one for in and one for out:
882
 *         info_format_brief_in_slot,   info_format_brief_out_slot
883
 *       in/out and tmm (no slot information); one for in and one for out:
884
 *         info_format_brief_in_noslot, info_format_brief_out_noslot
885
 *   The set of format specifiers in use are chosen based on whether brief is chosen and the
886
 *     following variables are set accordingly:
887
 *        info_format_in_only,          info_format_out_only   (should have no format specifiers)
888
 *        info_format_in_slot,          info_format_out_slot   (should have two format specifiers)
889
 *        info_format_in_noslot,        info_format_out_noslot (should have one format specifier)
890
 *
891
 * Functions:
892
 *   Separate functions depending on the amount of information desired.  The decision is made once
893
 *     when the preference is set and a function pointer is used to call the appropriate one:
894
 *       f5eth_set_info_col_inout():   In/out only.
895
 *       f5eth_set_info_col_slot():    in/out, slot and tmm.
896
 *       f5eth_set_info_col_noslot():  in/out and tmm (no slot information).
897
 *   f5eth_set_info_col is the function pointer to the function currently in use.
898
 */
899
900
/** Info column display format formats */
901
static const char info_format_full_in_only[]    = "IN : ";
902
static const char info_format_full_out_only[]   = "OUT: ";
903
static const char info_format_full_in_slot[]    = "IN  s%u/tmm%-2u: ";
904
static const char info_format_full_out_slot[]   = "OUT s%u/tmm%-2u: ";
905
static const char info_format_full_in_noslot[]  = "IN  tmm%-2u: ";
906
static const char info_format_full_out_noslot[] = "OUT tmm%-2u: ";
907
908
/* Variables used in f5eth_set_info_col functions initialized to defaults */
909
static char *info_format_in_only; /**< In format in use with in/out only */
910
static char *info_format_out_only; /**< Out format in use with in/out only */
911
static char *info_format_in_noslot; /**< In format in use without slot */
912
static char *info_format_out_noslot; /**< Out format in use without slot */
913
static char *info_format_in_slot; /**< In format in use with slot */
914
static char *info_format_out_slot; /**< Out format in use with slot */
915
916
/** Info column display format preference types:
917
  * These correspond to bit flags
918
  *   Display on  = 0x0001
919
  *   In out only = 0x0002
920
  *   Brief       = 0x0004
921
  */
922
typedef enum {
923
    none              = 0,
924
    full              = 1,
925
    in_out_only       = 3,
926
    brief             = 5,
927
    brief_in_out_only = 7
928
} f5eth_info_type_t;
929
930
/** Info column display format type strings */
931
static const enum_val_t f5eth_display_strings[] = {
932
    {"None",           "None",               0},
933
    {"Full",           "Full",               1},
934
    {"InOutOnly",      "In/out only",        3},
935
    {"Brief",          "Brief",              5},
936
    {"BriefInOutOnly", "Brief in/out only",  7},
937
    {NULL,             NULL,                 0}
938
};
939
/** Info column display preference (default to full) */
940
static f5eth_info_type_t pref_info_type = full;
941
942
/** Preference for the brief in/out characters */
943
static const char *pref_brief_inout_chars;
944
945
/** Function pointer prototype for info column set functions */
946
typedef void (*f5eth_set_col_info_func)(packet_info *, unsigned, unsigned, unsigned);
947
948
/** Preference for setting platform regex for which platforms to display slot information for. */
949
static const char *pref_slots_regex;
950
/** Whether or not to display slot information, set based on platform and regex preference. */
951
static bool display_slot = true;
952
953
/*-----------------------------------------------------------------------------------------------*/
954
/**
955
 * @brief Adds full format (in/out, slot, tmm) to info column
956
 *
957
 * @param pinfo   A pointer to the packet info structure.
958
 * @param ingress zero for egress, non-zero for ingress.
959
 * @param slot    The slot number handling the packet
960
 * @param tmm     The tmm handling the packet
961
 */
962
static void
963
f5eth_set_info_col_slot(packet_info *pinfo, unsigned ingress, unsigned slot, unsigned tmm)
964
6
{
965
6
    bool col_writable;
966
    /*
967
     * HTTP and other protocols set writable to false to protect
968
     * their data.  We don't care.
969
     */
970
6
    col_writable = col_get_writable(pinfo->cinfo, COL_INFO);
971
6
    col_set_writable(pinfo->cinfo, COL_INFO, true);
972
973
6
    if (ingress != 0) {
974
4
        DISSECTOR_ASSERT(info_format_in_slot);
975
4
        col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, info_format_in_slot, slot, tmm);
976
4
    } else {
977
2
        DISSECTOR_ASSERT(info_format_out_slot);
978
2
        col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, info_format_out_slot, slot, tmm);
979
2
    }
980
981
    /* Reset writable to whatever it was before we got here. */
982
6
    col_set_writable(pinfo->cinfo, COL_INFO, col_writable);
983
6
} /* f5eth_set_info_col_slot() */
984
985
/*-----------------------------------------------------------------------------------------------*/
986
/**
987
 * @brief Adds format without slot (in/out, tmm) to info column
988
 *
989
 * @param pinfo   A pointer to the packet info structure.
990
 * @param ingress zero for egress, non-zero for ingress.
991
 * @param slot    The slot number handling the packet (unused)
992
 * @param tmm     The tmm handling the packet
993
 */
994
static void
995
f5eth_set_info_col_noslot(packet_info *pinfo, unsigned ingress, unsigned slot _U_, unsigned tmm)
996
0
{
997
0
    bool col_writable;
998
    /*
999
     * HTTP and other protocols set writable to false to protect
1000
     * their data.  We don't care.
1001
     */
1002
0
    col_writable = col_get_writable(pinfo->cinfo, COL_INFO);
1003
0
    col_set_writable(pinfo->cinfo, COL_INFO, true);
1004
1005
0
    if (ingress != 0) {
1006
0
        col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, info_format_in_noslot, tmm);
1007
0
    } else {
1008
0
        col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, info_format_out_noslot, tmm);
1009
0
    }
1010
1011
    /* Reset writable to whatever it was before we got here. */
1012
0
    col_set_writable(pinfo->cinfo, COL_INFO, col_writable);
1013
0
} /* f5eth_set_info_col_noslot() */
1014
1015
/*-----------------------------------------------------------------------------------------------*/
1016
/**
1017
 * @brief Adds format with only direction (in/out) to info column
1018
 *
1019
 * @param pinfo   A pointer to the packet info structure.
1020
 * @param ingress zero for egress, non-zero for ingress.
1021
 * @param slot    The slot number handling the packet (unused)
1022
 * @param tmm     The tmm handling the packet (unused)
1023
 */
1024
static void
1025
f5eth_set_info_col_inout(packet_info *pinfo, unsigned ingress, unsigned slot _U_, unsigned tmm _U_)
1026
0
{
1027
0
    bool col_writable;
1028
    /*
1029
     * HTTP and other protocols set writable to false to protect
1030
     * their data.  We don't care.
1031
     */
1032
0
    col_writable = col_get_writable(pinfo->cinfo, COL_INFO);
1033
0
    col_set_writable(pinfo->cinfo, COL_INFO, true);
1034
1035
0
    if (ingress != 0) {
1036
0
        col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, "%s", info_format_in_only);
1037
0
    } else {
1038
0
        col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, "%s", info_format_out_only);
1039
0
    }
1040
1041
    /* Reset writable to whatever it was before we got here. */
1042
0
    col_set_writable(pinfo->cinfo, COL_INFO, col_writable);
1043
0
} /* f5eth_set_info_col_inout() */
1044
1045
/** The column display function.  Will really be set in proto_reg_handoff_f5fileinfo() */
1046
static f5eth_set_col_info_func f5eth_set_info_col = f5eth_set_info_col_slot;
1047
1048
/*-----------------------------------------------------------------------------------------------*/
1049
/**
1050
 * @brief Called out of f5info processing to determine platform display information
1051
 *
1052
 * @param platform String representing the platform name (can be NULL, will not be referenced
1053
 *                   after the function returns.)
1054
 */
1055
static void
1056
f5eth_process_f5info(const uint8_t *platform)
1057
0
{
1058
    /** Always display slot information when there is no platform information in the header or
1059
     *  if there was no regex specified in the preference.  But use the in/out only
1060
     *  function if that is specified in the preference.*/
1061
0
    if (platform == NULL || platform[0] == '\0' || pref_slots_regex == NULL
1062
0
        || pref_slots_regex[0] == '\0') {
1063
0
        display_slot = true;
1064
0
        if (pref_info_type == in_out_only || pref_info_type == brief_in_out_only) {
1065
0
            f5eth_set_info_col = f5eth_set_info_col_inout;
1066
0
        } else {
1067
0
            f5eth_set_info_col = f5eth_set_info_col_slot;
1068
0
        }
1069
0
        return;
1070
0
    }
1071
1072
    /** If the string matches the regex */
1073
0
    if (g_regex_match_simple(pref_slots_regex, platform, G_REGEX_RAW, (GRegexMatchFlags)0)
1074
0
        == true) {
1075
        /** Then display the slot information (only if in/out only is not selected). */
1076
0
        display_slot = true;
1077
0
        if (pref_info_type == in_out_only || pref_info_type == brief_in_out_only) {
1078
0
            f5eth_set_info_col = f5eth_set_info_col_inout;
1079
0
        } else {
1080
0
            f5eth_set_info_col = f5eth_set_info_col_slot;
1081
0
        }
1082
0
    } else {
1083
        /** Else do not display the slot information (only if in/out only is not selected). */
1084
0
        display_slot = false;
1085
0
        if (pref_info_type == in_out_only || pref_info_type == brief_in_out_only) {
1086
0
            f5eth_set_info_col = f5eth_set_info_col_inout;
1087
0
        } else {
1088
0
            f5eth_set_info_col = f5eth_set_info_col_noslot;
1089
0
        }
1090
0
    }
1091
0
} /* f5eth_process_f5info() */
1092
1093
/* End of info column display handling.                                                          */
1094
/*===============================================================================================*/
1095
1096
/** Magic information for the fileinfo packet that might appear at the beginning of a capture. */
1097
static const uint8_t fileinfomagic1[] = {
1098
    0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0,  0x05, 0xff,
1099
    'F', '5', '-', 'P', 's', 'e', 'u', 'd', 'o', '-', 'p', 'k', 't',   0
1100
};
1101
1102
#define F5_OFF_TYPE    0
1103
1.14k
#define F5_OFF_LENGTH  1
1104
2.27k
#define F5_OFF_VERSION 2
1105
#define F5_OFF_VALUE   3
1106
1107
/** This is used only for old format trailers.  The highest version number is 3 for medium trailers. */
1108
97
#define F5TRAILER_VER_MAX 3
1109
1110
1.68k
#define F5TYPE_LOW  1
1111
43
#define F5TYPE_MED  2
1112
1.62k
#define F5TYPE_HIGH 3
1113
1114
/* These are to perform a sanity check to try to avoid rendering true garbage
1115
 * in packets.  So, in addition to matching one of the types, the len of the
1116
 * suspected trailer needs to fall into this range.
1117
 *
1118
 * Max length seems to be 42 on high detail.
1119
 * Max length with RST cause in medium(v1) is 30 + 8 + 1 + 96 (might be 30+96)?
1120
 * Max length with RST cause in medium(v2) is 31 + 8 + 1 + 96 (might be 31+96)?
1121
 * Max length with RST cause in medium(v3) is 35 + 8 + 1 + 96 (might be 35+96)?
1122
 * Min length is 8 on v9.4 medium detail.
1123
 * Min length is 7 on v11.2 low trailer with no VIP name.
1124
 *
1125
 * These are only used for old format trailers.
1126
 */
1127
1.47k
#define F5_MIN_SANE 7
1128
1.24k
#define F5_MAX_SANE 140
1129
1130
14
#define F5_LOW_FLAGS_INGRESS_MASK     0x01
1131
14
#define F5_LOW_FLAGS_HWACTION_MASK    0x06
1132
1133
4
#define F5_HIV0_LEN                   42
1134
1135
/* Old format trailers */
1136
18
#define F5_MEDV94_LEN                  8
1137
24
#define F5_MEDV10_LEN                 21
1138
18
#define F5_MEDV11_LEN                 29
1139
16
#define F5_MEDV1_LENMIN               30
1140
16
#define F5_MEDV2_LENMIN               31
1141
13
#define F5_MEDV3_LENMIN               35
1142
24
#define F5_LOWV94_LEN                 35
1143
20
#define F5_LOWV10_LEN                 22
1144
6
#define F5_OFF_LOW_ING                 3
1145
6
#define F5_OFF_LOW_SLOT                4
1146
6
#define F5_OFF_LOW_TMM                 5
1147
36
#define VIP_NAME_LEN                  16
1148
1.23k
#define F5_LOWV1_LENMIN                7
1149
1150
/* New format (DPT) trailers */
1151
0
#define F5_MEDV4_LENMIN               32 /**< Minimum length without TLV header */
1152
1153
1.06k
#define F5_DPT_V1_HDR_MAGIC_OFF        0
1154
2.12k
#define F5_DPT_V1_HDR_MAGIC_LEN        4
1155
2.56k
#define F5_DPT_V1_HDR_MAGIC            0xf5deb0f5
1156
1.06k
#define F5_DPT_V1_HDR_LENGTH_OFF       (F5_DPT_V1_HDR_MAGIC_OFF + F5_DPT_V1_HDR_MAGIC_LEN)
1157
1.06k
#define F5_DPT_V1_HDR_LENGTH_LEN       2
1158
1.06k
#define F5_DPT_V1_HDR_VERSION_OFF      (F5_DPT_V1_HDR_LENGTH_OFF + F5_DPT_V1_HDR_LENGTH_LEN)
1159
1.06k
#define F5_DPT_V1_HDR_VERSION_LEN      2
1160
2
#define F5_DPT_V1_HDR_VERSION_MIN      1 /**< Minimum DPT version handled by this dissector. */
1161
1
#define F5_DPT_V1_HDR_VERSION_MAX      1 /**< Maximum DPT version handled by this dissector. */
1162
1.06k
#define F5_DPT_V1_HDR_LEN              (F5_DPT_V1_HDR_VERSION_OFF + F5_DPT_V1_HDR_VERSION_LEN)
1163
1164
14
#define F5_DPT_PROVIDER_NOISE          1
1165
1166
1
#define F5_DPT_V1_TLV_PROVIDER_OFF     0
1167
1
#define F5_DPT_V1_TLV_PROVIDER_LEN     2
1168
1
#define F5_DPT_V1_TLV_TYPE_OFF         (F5_DPT_V1_TLV_PROVIDER_OFF + F5_DPT_V1_TLV_PROVIDER_LEN)
1169
1
#define F5_DPT_V1_TLV_TYPE_LEN         2
1170
1
#define F5_DPT_V1_TLV_LENGTH_OFF       (F5_DPT_V1_TLV_TYPE_OFF + F5_DPT_V1_TLV_TYPE_LEN)
1171
1
#define F5_DPT_V1_TLV_LENGTH_LEN       2
1172
1
#define F5_DPT_V1_TLV_VERSION_OFF      (F5_DPT_V1_TLV_LENGTH_OFF + F5_DPT_V1_TLV_LENGTH_LEN)
1173
1
#define F5_DPT_V1_TLV_VERSION_LEN      2
1174
1
#define F5_DPT_V1_TLV_HDR_LEN          (F5_DPT_V1_TLV_VERSION_OFF+F5_DPT_V1_TLV_VERSION_LEN)
1175
1176
/*===============================================================================================*/
1177
/* This section is for performing analysis of the trailer information. */
1178
1179
/** Analysis Overview:
1180
 *
1181
 *  The analysis in this dissector is meant to correlate data in the F5 Ethernet trailer with other
1182
 *  data in the frame (e.g. IP, TCP) and highlight things that don't look right.  They might be
1183
 *  perfectly valid, but in most cases, they are not.
1184
 *
1185
 *  How it works:
1186
 *
1187
 *  When analysis is enabled, the dissector ties protocol data to each packet.  The dissector
1188
 *  populates some useful data it needs to perform analysis into the protocol data.  It also
1189
 *  registers taps on IP, IPv6 and TCP to populate data from those headers into the stored protocol
1190
 *  data.
1191
 *
1192
 *  All of that information is then used to look for certain, common anomalies.
1193
 *
1194
 *  It uses taps rather than surfing the WS protocol tree because:
1195
 *    1. I suspect that surfing the protocol tree is rather expensive.
1196
 *    2. We need to try to find the outer-most headers and use those.  The taps should fire in
1197
 *       order so that should get what is needed.  When searching the tree, it's difficult to
1198
 *       know if, for example, the TCP header we are on is tied to the outer IP header or to
1199
 *       the IP header that's inside and ICMP inside an IP.
1200
 *
1201
 *  Challenges:
1202
 *
1203
 *  1.  Taps run after all dissectors run on a packet.  As a result, when the trailer dissector is
1204
 *      running, it does not have the data from the other protocols to perform the analysis.
1205
 *  2.  The Ethernet dissector does not call trailer dissectors if it is not building a tree.
1206
 *
1207
 *  Flow:
1208
 *
1209
 *  In the trailer dissector, if ip_visited is set and analysis done is not set, then analysis
1210
 *  is performed.
1211
 *
1212
 *  In the tcp tap, if analysis_done is not set and pkt_ingress is not unknown (meaning that the
1213
 *  trailer dissector had an opportunity to run on this packet), then analysis is performed.  Also
1214
 *  in this case, we attempt to attach the expert info to a top-level tree element for the
1215
 *  F5 Ethernet trailer.
1216
 *
1217
 *  The purpose of the analysis in the dissector is for first-pass misses of the dissector.  For
1218
 *  example, on initial file load, if the Ethernet dissector does not call the trailer dissector
1219
 *  then analysis cannot be performed by the tcp tap because the data from the trailer is not
1220
 *  available.  In order to get the analysis on the second pass, we run here.
1221
 *
1222
 *  The purpose of the analysis and rendering in the tcp tap is to handle one-pass situations
1223
 *  (e.g. tshark).  In one-pass situations, after the tcp tap is called, the trailer dissector
1224
 *  will not run again to have an opportunity to perform and render analysis.
1225
 */
1226
1227
0
#define IP_MF 0x2000       /** IP more fragments flag */
1228
0
#define IP_OFFSET_WIDTH 13 /** Size of fragment offset field */
1229
0
#define IP_OFFSET_MASK ((1 << IP_OFFSET_WIDTH) - 1)
1230
1231
/** Structure used to store data gathered by the taps and dissector that is attached to the pinfo
1232
 * structure for the packet.  This structure ends up getting allocated for every packet.  So, we
1233
 * want to keep it small.
1234
 *
1235
 * For fields that are 1 bit wide, they have 0 == false and 1 == true.
1236
 * For fields that are 2 bits wide, they have 0 == false, 1 == true and 3 == unknown.
1237
 */
1238
struct f5eth_analysis_data_t {
1239
    uint8_t ip_visited : 1;  /**< Did the IPv4 or IPv6 tap look at this packet already? */
1240
    uint8_t tcp_visited : 1; /**< Did the TCP tap look at this packet already? */
1241
    uint8_t ip_istcp : 2;    /**< Is this a TCP (set by ip/ip6 tap on first header) */
1242
    uint8_t ip_isfrag : 2;   /**< Is this packet an IP fragment? */
1243
    uint8_t tcp_synset : 2;  /**< Is the SYN flag set in the TCP header? */
1244
    uint8_t tcp_ackset : 2;  /**< Is the ACK flag set in the TCP header? */
1245
1246
    uint8_t pkt_ingress : 2;  /**< Packet is ingress packet */
1247
    uint8_t pkt_has_flow : 2; /**< Packet has associated flow */
1248
    uint8_t pkt_has_peer : 2; /**< Packet has associated peer flow */
1249
1250
    uint8_t analysis_done : 1;       /**< Analysis has been performed */
1251
    uint8_t analysis_flowreuse : 1;  /**< Analysis indicates flow reuse */
1252
    uint8_t analysis_flowlost : 1;   /**< Analysis indicates flow lost */
1253
    uint8_t analysis_hasresults : 1; /**< Are there actually any results? */
1254
};
1255
1256
/*-----------------------------------------------------------------------------------------------*/
1257
/**
1258
 * @brief Allocates a new analysis data structure and initializes the values.
1259
 *
1260
 * @return wmem allocated analysis structure
1261
 */
1262
static struct f5eth_analysis_data_t *
1263
new_f5eth_analysis_data_t(void)
1264
0
{
1265
0
    struct f5eth_analysis_data_t *r = wmem_new0(wmem_file_scope(), struct f5eth_analysis_data_t);
1266
1267
    /* r->ip_visited = 0; */
1268
    /* r->tcp_visited = 0; */
1269
0
    r->ip_istcp   = 3;
1270
0
    r->tcp_synset = 3;
1271
0
    r->tcp_ackset = 3;
1272
0
    r->ip_isfrag  = 3;
1273
1274
0
    r->pkt_ingress  = 3;
1275
0
    r->pkt_has_flow = 3;
1276
0
    r->pkt_has_peer = 3;
1277
1278
    /* r->analysis_done = 0; */
1279
    /* r->analysis_flowreuse = 0; */
1280
    /* r->analysis_flowlost = 0; */
1281
    /* r->analysis_hasresults = 0; */
1282
1283
0
    return r;
1284
0
} /* new_f5eth_analysis_data_t() */
1285
1286
/* Functions for find a subtree of a particular type of the current tree. */
1287
1288
/** Structure used as the anonymous data in the proto_tree_children_foreach() function */
1289
struct subtree_search {
1290
    proto_tree *tree; /**< The matching tree that we found */
1291
    int hf;          /**< The type of tree that we are looking for. */
1292
};
1293
1294
/*-----------------------------------------------------------------------------------------------*/
1295
/**
1296
 * @brief Function to see if a node is of a particular type and return it if it is a tree.
1297
 *
1298
 * @param pn   A pointer to the proto_node being looked at.
1299
 * @param data A pointer to the subtree_search structure with search criteria and results.
1300
 */
1301
static void
1302
compare_subtree(proto_node *pn, void *data)
1303
0
{
1304
0
    struct subtree_search *search_struct;
1305
0
    search_struct = (struct subtree_search *)data;
1306
1307
0
    if (pn && pn->finfo && pn->finfo->hfinfo && pn->finfo->hfinfo->id == search_struct->hf) {
1308
0
        search_struct->tree = proto_item_get_subtree(pn);
1309
0
    }
1310
0
} /* compare_subtree() */
1311
1312
/*-----------------------------------------------------------------------------------------------*/
1313
/**
1314
 * @brief Function to search child trees (one level) for a tree of a specific type.
1315
 *
1316
 * @param tree A pointer to the proto_tree being looked at.
1317
 * @param hf   The register hfinfo id that we are looking for.
1318
 * @return     The tree that was found or NULL if it was not found.
1319
 */
1320
static proto_tree *
1321
find_subtree(proto_tree *tree, int hf)
1322
0
{
1323
0
    struct subtree_search search_struct;
1324
1325
0
    if (tree == NULL || hf == -1)
1326
0
        return NULL;
1327
0
    search_struct.tree = NULL;
1328
0
    search_struct.hf   = hf;
1329
0
    proto_tree_children_foreach(tree, compare_subtree, &search_struct);
1330
0
    return search_struct.tree;
1331
0
} /* find_subtree() */
1332
1333
/*-----------------------------------------------------------------------------------------------*/
1334
/**
1335
 * @brief Computes the analysis results based on the data in the analysis data struct.
1336
 *
1337
 * @param ad A pointer to the f5eth_analysis_data_t struct
1338
 */
1339
static void
1340
perform_analysis(struct f5eth_analysis_data_t *ad)
1341
0
{
1342
    /** Tests that apply to ingress TCP non-frags */
1343
0
    if (ad->pkt_ingress == 1 && ad->ip_istcp == 1 && ad->tcp_visited == 1 && ad->ip_isfrag == 0) {
1344
        /** If this is an inbound SYN and there is a flow ID, we might have a problem. */
1345
0
        if (ad->tcp_synset == 1 && ad->tcp_ackset == 0 && ad->pkt_has_flow == 1) {
1346
0
            ad->analysis_flowreuse  = 1;
1347
0
            ad->analysis_hasresults = 1;
1348
0
        }
1349
1350
        /** If this is an inbound packet with the ACK flag set and there is no flow, we might have
1351
         *  a problem. */
1352
0
        if (ad->tcp_ackset == 1 && ad->pkt_has_flow == 0) {
1353
0
            ad->analysis_flowlost   = 1;
1354
0
            ad->analysis_hasresults = 1;
1355
0
        }
1356
0
    }
1357
1358
0
    ad->analysis_done = 1;
1359
0
} /* perform_analysis() */
1360
1361
/*-----------------------------------------------------------------------------------------------*/
1362
/**
1363
 * @brief Puts the results of the F5 Ethernet trailer analysis into the protocol tree.
1364
 *
1365
 * @param tvb   A pointer to a TV buffer for the packet.
1366
 * @param pinfo A pointer to the packet info struction for the packet
1367
 * @param tree  A pointer to the protocol tree structure
1368
 * @param ad    A pointer to the intra-noise information data
1369
 */
1370
static void
1371
render_analysis(
1372
    tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const struct f5eth_analysis_data_t *ad)
1373
0
{
1374
0
    proto_item *pi;
1375
0
    if (ad == NULL || ad->analysis_hasresults == 0)
1376
0
        return;
1377
1378
0
    pi = proto_tree_add_item(tree, hf_analysis, tvb, 0, 0, ENC_NA);
1379
0
    proto_item_set_generated(pi);
1380
0
    if (ad->analysis_flowreuse) {
1381
0
        expert_add_info(pinfo, pi, &ei_f5eth_flowreuse);
1382
0
    }
1383
0
    if (ad->analysis_flowlost) {
1384
0
        expert_add_info(pinfo, pi, &ei_f5eth_flowlost);
1385
0
    }
1386
0
} /* render_analysis() */
1387
1388
/*-----------------------------------------------------------------------------------------------*/
1389
/**
1390
 * @brief Tap call back to retrieve information about the IP headers.
1391
 *
1392
 * @param tapdata UNUSED
1393
 * @param pinfo   Pointer to acket Info data structure
1394
 * @param edt     UNUSED
1395
 * @param data    Pointer to ws_ip4 structure
1396
 * @return tap_packet_status
1397
 */
1398
static tap_packet_status
1399
ip_tap_pkt(void *tapdata _U_, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data, tap_flags_t flags _U_)
1400
0
{
1401
0
    struct f5eth_analysis_data_t *ad;
1402
0
    const ws_ip4 *iph;
1403
1404
0
    ad = (struct f5eth_analysis_data_t *)p_get_proto_data(
1405
0
        wmem_file_scope(), pinfo, proto_f5ethtrailer, 0);
1406
0
    if (ad == NULL)
1407
0
        return TAP_PACKET_DONT_REDRAW; /* No F5 information */
1408
0
    if (ad->ip_visited == 1)
1409
0
        return TAP_PACKET_DONT_REDRAW;
1410
0
    ad->ip_visited = 1;
1411
1412
0
    if (data == NULL)
1413
0
        return TAP_PACKET_DONT_REDRAW;
1414
0
    iph = (const ws_ip4 *)data;
1415
1416
    /* Only care about TCP at this time */
1417
    /* We wait until here to make this check so that if TCP in encapsulated in something else, we
1418
     * don't work on the encapsulated header.  So, we only want to work on TCP if it associated
1419
     * with the first IP header (not if it's embedded in an ICMP datagram or some sort of tunnel).
1420
     */
1421
0
    if (iph->ip_proto != IP_PROTO_TCP) {
1422
0
        ad->ip_istcp = 0;
1423
0
        return TAP_PACKET_DONT_REDRAW;
1424
0
    }
1425
1426
0
    ad->ip_istcp  = 1;
1427
0
    ad->ip_isfrag = ((iph->ip_off & IP_OFFSET_MASK) || (iph->ip_off & IP_MF)) ? 1 : 0;
1428
1429
0
    return TAP_PACKET_REDRAW;
1430
0
} /* ip_tap_pkt() */
1431
1432
/*-----------------------------------------------------------------------------------------------*/
1433
/**
1434
 * @brief Tap call back to retrieve information about the IPv6 headers.
1435
 *
1436
 * @param tapdata UNUSED
1437
 * @param pinfo   Pointer to acket Info data structure
1438
 * @param edt     UNUSED
1439
 * @param data    Pointer to ws_ip6_hdr structure
1440
 * @return tap_packet_status
1441
 */
1442
static tap_packet_status
1443
ipv6_tap_pkt(void *tapdata _U_, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data, tap_flags_t flags _U_)
1444
0
{
1445
0
    struct f5eth_analysis_data_t *ad;
1446
0
    const struct ws_ip6_hdr *ipv6h;
1447
1448
0
    ad = (struct f5eth_analysis_data_t *)p_get_proto_data(
1449
0
        wmem_file_scope(), pinfo, proto_f5ethtrailer, 0);
1450
0
    if (ad == NULL)
1451
0
        return TAP_PACKET_DONT_REDRAW; /* No F5 information */
1452
0
    if (ad->ip_visited == 1)
1453
0
        return TAP_PACKET_DONT_REDRAW;
1454
0
    ad->ip_visited = 1;
1455
1456
0
    if (data == NULL)
1457
0
        return TAP_PACKET_DONT_REDRAW;
1458
0
    ipv6h = (const struct ws_ip6_hdr *)data;
1459
1460
    /* Only care about TCP at this time */
1461
    /* We wait until here to make this check so that if TCP in encapsulated in something else, we
1462
     * don't work on the encapsulated header.  So, we only want to work on TCP if it associated
1463
     * with the first IP header (not if it's embedded in an ICMP datagram or some sort of tunnel.
1464
     */
1465
    /* Note that this only works if TCP is the first next header.  If there are other IPv6 headers,
1466
     * we will not see the fact that it is TCP (limitation of IPv6 tap).  This becomes a problem if
1467
     * there are hop_by_hop or routing headers or other (non-fragment) IPv6 headers.  If it's a
1468
     * fragment, we don't care anyways (too much effort). */
1469
0
    if (ipv6h->ip6h_nxt != IP_PROTO_TCP) {
1470
0
        ad->ip_istcp = 0;
1471
0
        return TAP_PACKET_DONT_REDRAW;
1472
0
    }
1473
1474
0
    ad->ip_istcp = 1;
1475
1476
0
    return TAP_PACKET_REDRAW;
1477
0
} /* ipv6_tap_pkt() */
1478
1479
/*-----------------------------------------------------------------------------------------------*/
1480
/**
1481
 * @brief Tap call back to retrieve information about the TCP headers.
1482
 *
1483
 * @param tapdata UNUSED
1484
 * @param pinfo   Pointer to acket Info data structure
1485
 * @param edt     UNUSED
1486
 * @param data    Pointer to tcp_info_t structure
1487
 * @return tap_packet_status
1488
 */
1489
static tap_packet_status
1490
tcp_tap_pkt(void *tapdata _U_, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data, tap_flags_t flags _U_)
1491
0
{
1492
0
    struct f5eth_analysis_data_t *ad;
1493
0
    const tcp_info_t *tcph;
1494
1495
0
    ad = (struct f5eth_analysis_data_t *)p_get_proto_data(
1496
0
        wmem_file_scope(), pinfo, proto_f5ethtrailer, 0);
1497
0
    if (ad == NULL)
1498
0
        return TAP_PACKET_DONT_REDRAW; /* No F5 information */
1499
0
    if (ad->tcp_visited == 1)
1500
0
        return TAP_PACKET_DONT_REDRAW;
1501
0
    ad->tcp_visited = 1;
1502
1503
0
    if (data == NULL)
1504
0
        return TAP_PACKET_DONT_REDRAW;
1505
0
    tcph = (const tcp_info_t *)data;
1506
1507
0
    ad->tcp_synset = (tcph->th_flags & TH_SYN) ? 1 : 0;
1508
0
    ad->tcp_ackset = (tcph->th_flags & TH_ACK) ? 1 : 0;
1509
1510
    /** Only do this if the trailer dissector ran. */
1511
0
    if (ad->pkt_ingress != 3 && ad->analysis_done == 0) {
1512
0
        perform_analysis(ad);
1513
        /** If there were results from the analysis, go find the tree and try to insert them. */
1514
0
        if (ad->analysis_hasresults == 1) {
1515
0
            proto_tree *tree;
1516
1517
            /** This was the first opportunity to run, so add anything necessary to the tree. */
1518
            /* If we don't find a tree, we could theoretically anchor it to the top-tree.  However,
1519
             * this situation should not happen since, if we know the ingress property, then the
1520
             * trailer dissector ran and probably created a subtree, so it should most always be
1521
             * there.  If it is not there, it could be because there is nothing of interest to a
1522
             * filter in the f5ethtrailer protocol, so it didn't create a tree (so probably don't
1523
             * want to blindly tie this to the top-tree).  Other causes would warrant further
1524
             * investigation as to why it couldn't be found. */
1525
0
            if ((tree = find_subtree(edt->tree, proto_f5ethtrailer)) != NULL)
1526
0
                render_analysis(edt->tvb, pinfo, tree, ad);
1527
0
        }
1528
0
    }
1529
1530
0
    return TAP_PACKET_REDRAW;
1531
0
} /* tcp_tap_pkt() */
1532
1533
/* End of analysis functions */
1534
/*===============================================================================================*/
1535
1536
/* Used to determine if an address is an IPv4 address represented as an IPv6
1537
 * address. */
1538
static const uint8_t ipv4as6prefix[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff};
1539
static const uint8_t f5rtdomprefix[] = {0x26, 0x20, 0, 0, 0x0c, 0x10, 0xf5, 0x01, 0, 0};
1540
1541
#define F5_IPV6ADDR_LEN 16
1542
1543
/*---------------------------------------------------------------------------*/
1544
/**
1545
 * @brief Display an IPv6 encoded IPv4 addr in an IPv4 field if appropriate.
1546
 *
1547
 * @param tree          Pointer to tree struct
1548
 * @param addrfield     hf_index address will be placed in
1549
 * @param rtdomfield    hf_index route doamin will be placed in
1550
 * @param tvb           Pointer to tvb
1551
 * @param offset        Offset into the tvb containg the IPv6 address
1552
 * @param hidden        Should the protocol item be hidden
1553
 * @return              Pointer to proto_item created
1554
 */
1555
static proto_item *
1556
displayIPv6as4(
1557
    proto_tree *tree, int addrfield, int rtdomfield, tvbuff_t *tvb, int offset, bool hidden)
1558
0
{
1559
0
    proto_item *pi = NULL;
1560
1561
0
    if (tvb_memeql(tvb, offset, ipv4as6prefix, sizeof(ipv4as6prefix)) == 0) {
1562
0
        if (addrfield >= 0) {
1563
0
            pi = proto_tree_add_item(
1564
0
                tree, addrfield, tvb, offset + (int)sizeof(ipv4as6prefix), 4, ENC_BIG_ENDIAN);
1565
0
            if (hidden)
1566
0
                proto_item_set_hidden(pi);
1567
0
        }
1568
0
    } else if (tvb_memeql(tvb, offset, f5rtdomprefix, sizeof(f5rtdomprefix)) == 0) {
1569
        /* Route domain information may show up here if the traffic is between tmm and the BIG-IP
1570
         * host (e.g. monitor traffic).  If so, break it up and render it for ease of viewing (and
1571
         * searching).  Ignore the incorrect addresses used by 10.0.x (solution 10511) as these
1572
         * will hopefully not be common. */
1573
        /* TODO: review - These are technically backwards as we are probably returning the wrong pi.  However,
1574
         * when configuring, people usually see route domain after the address, so that is why this
1575
         * particular ordering is used (and none of the callers currently use the return value). */
1576
0
        if (addrfield >= 0) {
1577
0
            pi = proto_tree_add_item(
1578
0
                tree, addrfield, tvb, offset + (int)sizeof(f5rtdomprefix) + 2, 4, ENC_BIG_ENDIAN);
1579
0
            if (hidden)
1580
0
                proto_item_set_hidden(pi);
1581
0
        }
1582
0
        if (rtdomfield >= 0) {
1583
0
            pi = proto_tree_add_item(
1584
0
                tree, rtdomfield, tvb, offset + (int)sizeof(f5rtdomprefix), 2, ENC_BIG_ENDIAN);
1585
0
            if (hidden)
1586
0
                proto_item_set_hidden(pi);
1587
0
        }
1588
0
    }
1589
1590
0
    return pi;
1591
0
} /* displayIPv6as4() */
1592
1593
/**
1594
 * @brief Render a tree item to dispalay header info for old format trailer blocks
1595
 *
1596
 * @attention The old format trailers used a fair amount of magic numbers.  Continuing that
1597
              use for now with the same magic numbers in this function
1598
 *
1599
 * @param tvb       Pointer to the tvb
1600
 * @param tree      Pointer to tree struct
1601
 * @param offset    Offset into the tvb
1602
 * @return          Number of bytes consumed
1603
 */
1604
static int
1605
render_f5_legacy_hdr(tvbuff_t *tvb, proto_tree *tree, int offset)
1606
12
{
1607
12
    proto_item *pi = NULL;
1608
12
    uint32_t trailer_type;
1609
1610
12
    pi   = proto_tree_add_item(tree, hf_trailer_hdr, tvb, offset, 3, ENC_NA);
1611
12
    tree = proto_item_add_subtree(pi, ett_f5ethtrailer_trailer_hdr);
1612
1613
12
    proto_tree_add_item_ret_uint(tree, hf_type, tvb, offset, 1, ENC_BIG_ENDIAN, &trailer_type);
1614
12
    offset += 1;
1615
12
    proto_item_append_text(pi, ", Type: %u", trailer_type);
1616
12
    proto_tree_add_item(tree, hf_length, tvb, offset, 1, ENC_BIG_ENDIAN);
1617
12
    offset += 1;
1618
12
    proto_tree_add_item(tree, hf_version, tvb, offset, 1, ENC_BIG_ENDIAN);
1619
    /*  offset += 1; */
1620
12
    return 3;
1621
1622
12
} /* render_f5_legacy_hdr() */
1623
1624
/*---------------------------------------------------------------------------*/
1625
/**
1626
 * @brief Dissect old format "high" trailer TLV
1627
 *
1628
 * @param tvb               Pointer to the tvb to be processed
1629
 * @param pinfo             Pointer to packet_info struct
1630
 * @param tree              Pointer to protocol tree
1631
 * @param offset            Offset into the tvb where trailer begins
1632
 * @param trailer_length    Length of the trailer data to process
1633
 * @param trailer_ver       Version of the trailer detected
1634
 * @param tdata             Pointer to tap data structure
1635
 * @return                  Number of btyes consumed
1636
 */
1637
static unsigned
1638
dissect_high_trailer(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset,
1639
    uint8_t trailer_length, uint8_t trailer_ver, f5eth_tap_data_t *tdata)
1640
10
{
1641
10
    proto_item *pi = NULL;
1642
10
    unsigned o;
1643
10
    uint8_t ipproto;
1644
1645
10
    if (trailer_ver != 0 || trailer_length != F5_HIV0_LEN)
1646
10
        return 0;
1647
1648
    /* We do not need to do anything if we don't have a tree */
1649
0
    if (tree == NULL)
1650
0
        return trailer_length;
1651
1652
0
    o = offset;
1653
0
    o += render_f5_legacy_hdr(tvb, tree, o);
1654
1655
0
    if (tdata->peer_flow == 0) {
1656
0
        proto_tree_add_item(tree, hf_peer_nopeer, tvb, o, trailer_length - 3, ENC_NA);
1657
0
        return trailer_length;
1658
0
    }
1659
1660
    /* Add in the high order structures. */
1661
0
    ipproto = tvb_get_uint8(tvb, o);
1662
0
    proto_tree_add_item(tree, hf_peer_ipproto, tvb, o, 1, ENC_BIG_ENDIAN);
1663
0
    o += 1;
1664
0
    proto_tree_add_item(tree, hf_peer_vlan, tvb, o, 2, ENC_BIG_ENDIAN);
1665
0
    o += 2;
1666
1667
    /* peer remote address */
1668
0
    if (pref_pop_other_fields) {
1669
0
        displayIPv6as4(tree, hf_ip_ipaddr, -1, tvb, o, true);
1670
0
        pi = proto_tree_add_item(tree, hf_ip6_ip6addr, tvb, o, 16, ENC_NA);
1671
0
        proto_item_set_hidden(pi);
1672
0
    }
1673
0
    displayIPv6as4(tree, hf_peer_remote_addr, hf_peer_remote_rtdom, tvb, o, false);
1674
0
    displayIPv6as4(tree, hf_peer_ipaddr, hf_peer_rtdom, tvb, o, true);
1675
0
    proto_tree_add_item(tree, hf_peer_remote_ip6addr, tvb, o, 16, ENC_NA);
1676
0
    pi = proto_tree_add_item(tree, hf_peer_ip6addr, tvb, o, 16, ENC_NA);
1677
0
    proto_item_set_hidden(pi);
1678
0
    o += 16;
1679
1680
    /* peer local address */
1681
0
    if (pref_pop_other_fields) {
1682
0
        displayIPv6as4(tree, hf_ip_ipaddr, -1, tvb, o, true);
1683
0
        pi = proto_tree_add_item(tree, hf_ip6_ip6addr, tvb, o, 16, ENC_NA);
1684
0
        proto_item_set_hidden(pi);
1685
0
    }
1686
0
    displayIPv6as4(tree, hf_peer_local_addr, hf_peer_local_rtdom, tvb, o, false);
1687
0
    displayIPv6as4(tree, hf_peer_ipaddr, hf_peer_rtdom, tvb, o, true);
1688
0
    proto_tree_add_item(tree, hf_peer_local_ip6addr, tvb, o, 16, ENC_NA);
1689
0
    pi = proto_tree_add_item(tree, hf_peer_ip6addr, tvb, o, 16, ENC_NA);
1690
0
    proto_item_set_hidden(pi);
1691
0
    o += 16;
1692
1693
0
    if (pref_pop_other_fields) {
1694
        /* If there is no proto in the trailer, go get it from the actual packet
1695
         * information. */
1696
0
        if (ipproto == 0) {
1697
0
            ipproto = ptype_to_ipproto(pinfo->ptype);
1698
0
        }
1699
1700
        /* peer remote port */
1701
0
        switch (ipproto) {
1702
0
        case IP_PROTO_TCP:
1703
0
            pi = proto_tree_add_item(tree, hf_tcp_tcpport, tvb, o, 2, ENC_BIG_ENDIAN);
1704
0
            proto_item_set_hidden(pi);
1705
0
            break;
1706
0
        case IP_PROTO_UDP:
1707
0
            pi = proto_tree_add_item(tree, hf_udp_udpport, tvb, o, 2, ENC_BIG_ENDIAN);
1708
0
            proto_item_set_hidden(pi);
1709
0
            break;
1710
0
        }
1711
0
    }
1712
0
    proto_tree_add_item(tree, hf_peer_remote_port, tvb, o, 2, ENC_BIG_ENDIAN);
1713
0
    pi = proto_tree_add_item(tree, hf_peer_port, tvb, o, 2, ENC_BIG_ENDIAN);
1714
0
    proto_item_set_hidden(pi);
1715
0
    o += 2;
1716
1717
    /* peer remote port */
1718
0
    if (pref_pop_other_fields) {
1719
0
        switch (ipproto) {
1720
0
        case IP_PROTO_TCP:
1721
0
            pi = proto_tree_add_item(tree, hf_tcp_tcpport, tvb, o, 2, ENC_BIG_ENDIAN);
1722
0
            proto_item_set_hidden(pi);
1723
0
            break;
1724
0
        case IP_PROTO_UDP:
1725
0
            pi = proto_tree_add_item(tree, hf_udp_udpport, tvb, o, 2, ENC_BIG_ENDIAN);
1726
0
            proto_item_set_hidden(pi);
1727
0
            break;
1728
0
        }
1729
0
    }
1730
0
    proto_tree_add_item(tree, hf_peer_local_port, tvb, o, 2, ENC_BIG_ENDIAN);
1731
0
    pi = proto_tree_add_item(tree, hf_peer_port, tvb, o, 2, ENC_BIG_ENDIAN);
1732
0
    proto_item_set_hidden(pi);
1733
1734
0
    return trailer_length;
1735
0
} /* dissect_high_trailer() */
1736
1737
/*---------------------------------------------------------------------------*/
1738
/**
1739
 * @brief Dissect old format "medium" trailer TLV
1740
 *
1741
 * @param tvb               Pointer to the tvb to be processed
1742
 * @param pinfo             Pointer to packet_info struct
1743
 * @param tree              Pointer to protocol tree
1744
 * @param offset            Offset into the tvb where trailer begins
1745
 * @param trailer_length    Length of the trailer data to process
1746
 * @param trailer_ver       Version of the trailer detected
1747
 * @param tdata             Pointer to tap data structure
1748
 * @return                  Number of btyes consumed
1749
 */
1750
static unsigned
1751
dissect_med_trailer(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset,
1752
    uint8_t trailer_length, uint8_t trailer_ver, f5eth_tap_data_t *tdata)
1753
29
{
1754
29
    proto_item *pi = NULL;
1755
29
    unsigned o;
1756
29
    unsigned rstcauselen = 0;
1757
29
    unsigned rstcausever = 0xff;
1758
1759
29
    switch (trailer_ver) {
1760
9
    case 0:
1761
9
        if (trailer_length != F5_MEDV11_LEN && trailer_length != F5_MEDV10_LEN
1762
9
            && trailer_length != F5_MEDV94_LEN) {
1763
4
            return 0;
1764
4
        }
1765
5
        break;
1766
7
    case 1:
1767
7
        if (trailer_length < F5_MEDV1_LENMIN) { /* too small */
1768
4
            return 0;
1769
4
        }
1770
3
        rstcauselen = tvb_get_uint8(tvb, offset + F5_MEDV1_LENMIN - 1);
1771
        /* check size is valid */
1772
3
        if (rstcauselen + F5_MEDV1_LENMIN != trailer_length) {
1773
2
            return 0;
1774
2
        }
1775
1
        if (rstcauselen)
1776
1
            rstcausever = (tvb_get_uint8(tvb, offset + F5_MEDV1_LENMIN) & 0xfe) >> 1;
1777
        /* If we want the RST cause in the summary, we need to do it here,
1778
         * before the tree check below */
1779
1
        if (rstcauselen && rstcause_in_info) {
1780
1
            if (rstcausever == 0x00) {
1781
1
                col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "[F5RST%s: %s]",
1782
1
                    tvb_get_uint8(tvb, offset + F5_MEDV1_LENMIN) & 0x01 ? "(peer)" : "",
1783
1
                    tvb_get_string_enc(pinfo->pool, tvb, offset + F5_MEDV1_LENMIN + 9,
1784
1
                        rstcauselen - 9, ENC_ASCII));
1785
1
            }
1786
1
        }
1787
1
        break;
1788
8
    case 2:
1789
8
        if (trailer_length < F5_MEDV2_LENMIN) { /* too small */
1790
4
            return 0;
1791
4
        }
1792
4
        rstcauselen = tvb_get_uint8(tvb, offset + F5_MEDV2_LENMIN - 1);
1793
        /* check size is valid */
1794
4
        if (rstcauselen + F5_MEDV2_LENMIN != trailer_length) {
1795
4
            return 0;
1796
4
        }
1797
0
        if (rstcauselen)
1798
0
            rstcausever = (tvb_get_uint8(tvb, offset + F5_MEDV2_LENMIN) & 0x0fe) >> 1;
1799
        /* If we want the RST cause in the summary, we need to do it here,
1800
         * before the tree check below */
1801
0
        if (rstcauselen && rstcause_in_info) {
1802
0
            if (rstcausever == 0x00) {
1803
0
            col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "[F5RST%s: %s]",
1804
0
                tvb_get_uint8(tvb, offset + F5_MEDV2_LENMIN) & 0x01 ? "(peer)" : "",
1805
0
                    tvb_get_string_enc(pinfo->pool, tvb, offset + F5_MEDV2_LENMIN + 9,
1806
0
                        rstcauselen - 9, ENC_ASCII));
1807
0
            }
1808
0
        }
1809
0
        break;
1810
5
    case 3:
1811
5
        if (trailer_length < F5_MEDV3_LENMIN) { /* too small */
1812
1
            return 0;
1813
1
        }
1814
4
        rstcauselen = tvb_get_int8(tvb, offset + F5_MEDV3_LENMIN -1);
1815
        /* check size is valid */
1816
4
        if (rstcauselen + F5_MEDV3_LENMIN != trailer_length) {
1817
4
            return 0;
1818
4
        }
1819
0
        if (rstcauselen)
1820
0
            rstcausever = (tvb_get_int8(tvb, offset + F5_MEDV3_LENMIN) & 0xfe) >>1;
1821
        /* If we want the RST cause in the summary, we need to do it here,
1822
         * before the tree check below */
1823
0
        if (rstcauselen && rstcause_in_info) {
1824
0
            if (rstcausever == 0x00) {
1825
0
            col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "[F5RST%s: %s]",
1826
0
                tvb_get_int8(tvb, offset + F5_MEDV3_LENMIN) & 0x01 ? "(peer)" : "",
1827
0
                    tvb_get_string_enc(pinfo->pool, tvb, offset + F5_MEDV3_LENMIN + 9,
1828
0
                        rstcauselen - 9, ENC_ASCII));
1829
0
            }
1830
0
        }
1831
0
        break;
1832
0
    default:
1833
0
        return 0;
1834
29
    }
1835
1836
    /* We do not need to do anything more if we don't have a tree and we are not performing
1837
     * analysis */
1838
6
    if (pref_perform_analysis == false && tree == NULL)
1839
0
        return trailer_length;
1840
1841
6
    o = offset;
1842
6
    o += render_f5_legacy_hdr(tvb, tree, o);
1843
1844
    /* After 9.4, flow IDs and flags and type are here in medium */
1845
6
    if (trailer_length != F5_MEDV94_LEN || trailer_ver > 0) {
1846
4
        if (trailer_length == F5_MEDV10_LEN && trailer_ver == 0) {
1847
            /* In v10, flowIDs are 32bit */
1848
1
            tdata->flow = tvb_get_ntohl(tvb, o);
1849
1
            proto_tree_add_item(tree, hf_flow_id, tvb, o, 4, ENC_BIG_ENDIAN);
1850
1
            pi = proto_tree_add_item(tree, hf_any_flow, tvb, o, 4, ENC_BIG_ENDIAN);
1851
1
            proto_item_set_hidden(pi);
1852
1
            o += 4;
1853
1
            tdata->peer_flow = tvb_get_ntohl(tvb, o);
1854
1
            proto_tree_add_item(tree, hf_peer_id, tvb, o, 4, ENC_BIG_ENDIAN);
1855
1
            pi = proto_tree_add_item(tree, hf_any_flow, tvb, o, 4, ENC_BIG_ENDIAN);
1856
1
            proto_item_set_hidden(pi);
1857
1
            o += 4;
1858
3
        } else {
1859
            /* After v10, flowIDs are 64bit */
1860
3
            tdata->flow = tvb_get_ntoh64(tvb, o);
1861
3
            proto_tree_add_item(tree, hf_flow_id, tvb, o, 8, ENC_BIG_ENDIAN);
1862
3
            pi = proto_tree_add_item(tree, hf_any_flow, tvb, o, 8, ENC_BIG_ENDIAN);
1863
3
            proto_item_set_hidden(pi);
1864
3
            o += 8;
1865
3
            tdata->peer_flow = tvb_get_ntoh64(tvb, o);
1866
3
            proto_tree_add_item(tree, hf_peer_id, tvb, o, 8, ENC_BIG_ENDIAN);
1867
3
            pi = proto_tree_add_item(tree, hf_any_flow, tvb, o, 8, ENC_BIG_ENDIAN);
1868
3
            proto_item_set_hidden(pi);
1869
3
            o += 8;
1870
3
        }
1871
4
        tdata->flows_set = 1;
1872
4
        if (trailer_ver >= 3) {
1873
0
            proto_tree_add_item(tree, hf_cf_flags2, tvb, o, 4, ENC_BIG_ENDIAN);
1874
0
            o += 4;
1875
0
        }
1876
4
        proto_tree_add_item(tree, hf_cf_flags, tvb, o, 4, ENC_BIG_ENDIAN);
1877
4
        o += 4;
1878
4
        proto_tree_add_item(tree, hf_flow_type, tvb, o, 1, ENC_BIG_ENDIAN);
1879
4
        o += 1;
1880
4
    }
1881
1882
    /* We do not need to do anything if we don't have a tree */
1883
    /* Needed to get here so that analysis and tap will work. */
1884
6
    if (tree == NULL)
1885
0
        return trailer_length;
1886
1887
6
    proto_tree_add_item(tree, hf_ha_unit, tvb, o, 1, ENC_BIG_ENDIAN);
1888
6
    o += 1;
1889
6
    proto_tree_add_item(tree, hf_reserved, tvb, o, 4, ENC_BIG_ENDIAN);
1890
6
    o += 4;
1891
6
    if (trailer_ver >= 2) {
1892
0
        proto_tree_add_item(tree, hf_priority, tvb, o, 1, ENC_BIG_ENDIAN);
1893
0
        o += 1;
1894
0
    }
1895
6
    if (trailer_ver >= 1) {
1896
1
        if (rstcauselen) {
1897
1
            proto_tree *rc_tree;
1898
1
            proto_item *rc_item;
1899
1
            uint64_t rstcauseval;
1900
1
            uint64_t rstcauseline;
1901
1
            unsigned startcause;
1902
1
            uint8_t rstcausepeer;
1903
1904
1
            rc_item = proto_tree_add_item(tree, hf_rstcause, tvb, o, rstcauselen + 1, ENC_NA);
1905
1
            rc_tree = proto_item_add_subtree(rc_item, ett_f5ethtrailer_rstcause);
1906
1
            proto_tree_add_item(rc_tree, hf_rstcause_len, tvb, o, 1, ENC_BIG_ENDIAN);
1907
1
            o += 1;
1908
1909
1
            startcause = o;
1910
1
            switch (rstcausever) {
1911
1
            case 0x00:
1912
1
                rstcausepeer = tvb_get_uint8(tvb, o) & 0x1;
1913
1914
1
                proto_tree_add_item(rc_tree, hf_rstcause_ver, tvb, o, 1, ENC_BIG_ENDIAN);
1915
1
                proto_tree_add_item(rc_tree, hf_rstcause_peer, tvb, o, 1, ENC_BIG_ENDIAN);
1916
1
                o += 1;
1917
1918
1
                rstcauseval  = tvb_get_ntoh64(tvb, o);
1919
1
                rstcauseline = (rstcauseval & 0x000000000000ffffLL);
1920
1
                rstcauseval  = (rstcauseval & 0xffffffffffff0000LL) >> 16;
1921
1
                proto_tree_add_uint64_format_value(rc_tree, hf_rstcause_val, tvb, o, 6,
1922
1
                    rstcauseval, "0x%012" PRIx64, rstcauseval);
1923
1
                proto_tree_add_item(rc_tree, hf_rstcause_line, tvb, o + 6, 2, ENC_BIG_ENDIAN);
1924
1
                o += 8;
1925
1926
1
                proto_item_append_text(rc_item,
1927
1
                    ": [%" PRIx64 ":%" PRIu64 "]%s %s", rstcauseval,
1928
1
                    rstcauseline, rstcausepeer ? " {peer}" : "",
1929
1
                        tvb_get_string_enc(pinfo->pool, tvb, o,
1930
1
                        rstcauselen - (o - startcause), ENC_ASCII));
1931
1
                proto_tree_add_item(rc_tree, hf_rstcause_txt, tvb, o,
1932
1
                    rstcauselen - (o - startcause), ENC_ASCII);
1933
1
                break;
1934
0
            default:
1935
0
                break;
1936
1
            }
1937
1
        }
1938
1
    }
1939
1940
6
    return trailer_length;
1941
6
} /* dissect_med_trailer() */
1942
1943
/*---------------------------------------------------------------------------*/
1944
/* Low level trailers */
1945
/**
1946
 * @brief Dissect old format "low" trailer TLV
1947
 *
1948
 * @param tvb               Pointer to the tvb to be processed
1949
 * @param pinfo             Pointer to packet_info struct
1950
 * @param tree              Pointer to protocol tree
1951
 * @param offset            Offset into the tvb where trailer begins
1952
 * @param trailer_length    Length of the trailer data to process
1953
 * @param trailer_ver       Version of the trailer detected
1954
 * @param tdata             Pointer to tap data structure
1955
 * @return                  Number of btyes consumed
1956
 */
1957
static unsigned
1958
dissect_low_trailer(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset,
1959
    uint8_t trailer_length, uint8_t trailer_ver, f5eth_tap_data_t *tdata)
1960
36
{
1961
36
    proto_item *pi = NULL;
1962
36
    unsigned ingress;
1963
36
    unsigned o;
1964
36
    unsigned vipnamelen        = VIP_NAME_LEN;
1965
36
    unsigned slot_display      = 0;
1966
36
    int slot_display_field = -1;
1967
36
    unsigned tmm;
1968
1969
36
    switch (trailer_ver) {
1970
10
    case 0:
1971
10
        if (trailer_length != F5_LOWV10_LEN && trailer_length != F5_LOWV94_LEN) {
1972
6
            return 0;
1973
6
        }
1974
4
        if (trailer_length == F5_LOWV94_LEN) {
1975
2
            slot_display       = tvb_get_uint8(tvb, offset + F5_OFF_LOW_SLOT);
1976
2
            slot_display_field = hf_slot0;
1977
            /* Analysis doesn't care about the virtual name, only populate if there is a tap
1978
             * active */
1979
2
            if (have_tap_listener(tap_f5ethtrailer)
1980
2
                && tvb_get_uint8(tvb, offset + (F5_LOWV94_LEN - 16)) != 0) {
1981
0
                tdata->virtual_name = tvb_get_string_enc(pinfo->pool, tvb,
1982
0
                    offset + (F5_LOWV94_LEN - 16), 16, ENC_ASCII);
1983
0
            }
1984
2
        } else {
1985
2
            slot_display       = tvb_get_uint8(tvb, offset + F5_OFF_LOW_SLOT) + 1;
1986
2
            slot_display_field = hf_slot1;
1987
            /* Analysis doesn't care about the virtual name, only populate if there is a tap
1988
             * active */
1989
2
            if (have_tap_listener(tap_f5ethtrailer)
1990
2
                && tvb_get_uint8(tvb, offset + (F5_LOWV10_LEN - 16)) != 0) {
1991
0
                tdata->virtual_name = tvb_get_string_enc(pinfo->pool, tvb,
1992
0
                    offset + (F5_LOWV10_LEN - 16), 16, ENC_ASCII);
1993
0
            }
1994
2
        }
1995
4
        break;
1996
6
    case 1:
1997
6
        if (trailer_length < F5_LOWV1_LENMIN) { /* too small */
1998
0
            return 0;
1999
0
        }
2000
6
        vipnamelen = tvb_get_uint8(tvb, offset + F5_LOWV1_LENMIN - 1);
2001
        /* check size is valid */
2002
6
        if (vipnamelen + F5_LOWV1_LENMIN != trailer_length) {
2003
4
            return 0;
2004
4
        }
2005
2
        slot_display       = tvb_get_uint8(tvb, offset + F5_OFF_LOW_SLOT) + 1;
2006
2
        slot_display_field = hf_slot1;
2007
        /* Analysis doesn't care about the virtual name, only populate if there is a tap active
2008
         */
2009
2
        if (vipnamelen > 0 && have_tap_listener(tap_f5ethtrailer)) {
2010
0
            tdata->virtual_name = tvb_get_string_enc(pinfo->pool, tvb,
2011
0
                offset + F5_LOWV1_LENMIN, vipnamelen, ENC_ASCII);
2012
0
        }
2013
2
        break;
2014
20
    default:
2015
20
        return 0;
2016
36
    }
2017
2018
6
    ingress        = tvb_get_uint8(tvb, offset + F5_OFF_LOW_ING);
2019
6
    tdata->ingress = ingress == 0 ? 0 : 1;
2020
6
    tmm            = tvb_get_uint8(tvb, offset + F5_OFF_LOW_TMM);
2021
6
    if (tmm < F5ETH_TAP_TMM_MAX && slot_display < F5ETH_TAP_SLOT_MAX) {
2022
6
        tdata->tmm  = tmm;
2023
6
        tdata->slot = slot_display;
2024
6
    }
2025
    /* Is the column visible? */
2026
6
    if (pref_info_type != none) {
2027
6
        f5eth_set_info_col(pinfo, ingress, slot_display, tmm);
2028
6
    }
2029
2030
    /* We do not need to do anything more if we don't have a tree and we are not performing
2031
     * analysis and this is not v9.4.  If v9.4, need to continue to get flow
2032
     * information.*/
2033
6
    if (pref_perform_analysis == false && tree == NULL
2034
6
        && !(trailer_length == F5_LOWV94_LEN && trailer_ver == 0
2035
0
             && have_tap_listener(tap_f5ethtrailer))) {
2036
0
        return trailer_length;
2037
0
    }
2038
2039
6
    o = offset;
2040
6
    o += render_f5_legacy_hdr(tvb, tree, o);
2041
2042
    /* Use special formatting here so that users do not have to filter on "IN"
2043
     * and "OUT", but rather can continue to use typical boolean values.  "IN"
2044
     * and "OUT" are provided as convenience. */
2045
6
    proto_tree_add_boolean_format_value(tree, hf_ingress, tvb, o, 1, ingress, "%s (%s)",
2046
6
            tfs_get_true_false(ingress),
2047
6
            tfs_get_string(ingress, &f5tfs_ing));
2048
6
    o++;
2049
2050
6
    proto_tree_add_uint(tree, slot_display_field, tvb, o, 1, slot_display);
2051
6
    o += 1;
2052
2053
6
    proto_tree_add_item(tree, hf_tmm, tvb, o, 1, ENC_BIG_ENDIAN);
2054
6
    o += 1;
2055
6
    if (trailer_length == F5_LOWV94_LEN && trailer_ver == 0) {
2056
        /* In v9.4, flowIDs, flags and type are here in low */
2057
2
        tdata->flow = tvb_get_ntohl(tvb, o);
2058
2
        proto_tree_add_item(tree, hf_flow_id, tvb, o, 4, ENC_BIG_ENDIAN);
2059
2
        pi = proto_tree_add_item(tree, hf_any_flow, tvb, o, 4, ENC_BIG_ENDIAN);
2060
2
        proto_item_set_hidden(pi);
2061
2
        o += 4;
2062
2
        tdata->peer_flow = tvb_get_ntohl(tvb, o);
2063
2
        proto_tree_add_item(tree, hf_peer_id, tvb, o, 4, ENC_BIG_ENDIAN);
2064
2
        pi = proto_tree_add_item(tree, hf_any_flow, tvb, o, 4, ENC_BIG_ENDIAN);
2065
2
        proto_item_set_hidden(pi);
2066
2
        o += 4;
2067
2
        tdata->flows_set = 1;
2068
2
        proto_tree_add_item(tree, hf_cf_flags, tvb, o, 4, ENC_BIG_ENDIAN);
2069
2
        o += 4;
2070
2
        proto_tree_add_item(tree, hf_flow_type, tvb, o, 1, ENC_BIG_ENDIAN);
2071
2
        o += 1;
2072
2
    }
2073
2074
    /* We do not need to do anything more if we don't have a tree */
2075
    /* Needed to get here so that analysis will work. */
2076
6
    if (tree == NULL)
2077
0
        return trailer_length;
2078
2079
6
    if (trailer_ver == 1) {
2080
2
        pi = proto_tree_add_item(tree, hf_vipnamelen, tvb, o, 1, ENC_BIG_ENDIAN);
2081
2
        proto_item_set_hidden(pi);
2082
2
        o += 1;
2083
2
    }
2084
6
    pi = proto_tree_add_item(tree, hf_vip, tvb, o, vipnamelen, ENC_ASCII);
2085
6
    proto_item_prepend_text(pi, "VIP ");
2086
2087
6
    return trailer_length;
2088
6
} /* dissect_low_trailer() */
2089
2090
/**
2091
 * @brief Render a header tree for new format tlvs
2092
 *
2093
 * @param tvb       Pointer to tvb
2094
 * @param tree      Pointer to protocol tree
2095
 * @param offset    Offset into the tvb
2096
 */
2097
static void
2098
render_f5dptv1_tlvhdr(tvbuff_t *tvb, proto_tree *tree, int offset)
2099
0
{
2100
0
    proto_item *pi = NULL;
2101
0
    uint32_t provider;
2102
0
    uint32_t type;
2103
2104
0
    pi   = proto_tree_add_item(tree, hf_trailer_hdr, tvb, offset, F5_DPT_V1_TLV_HDR_LEN, ENC_NA);
2105
0
    tree = proto_item_add_subtree(pi, ett_f5ethtrailer_trailer_hdr);
2106
2107
0
    proto_tree_add_item_ret_uint(tree, hf_provider, tvb, offset + F5_DPT_V1_TLV_PROVIDER_OFF,
2108
0
            F5_DPT_V1_TLV_PROVIDER_LEN, ENC_BIG_ENDIAN, &provider);
2109
0
    proto_item_append_text(pi, ", Provider: %u", provider);
2110
0
    proto_tree_add_item_ret_uint(tree, hf_type, tvb, offset + F5_DPT_V1_TLV_TYPE_OFF,
2111
0
            F5_DPT_V1_TLV_TYPE_LEN, ENC_BIG_ENDIAN, &type);
2112
0
    proto_item_append_text(pi, ", Type: %u", type);
2113
0
    proto_tree_add_item(tree, hf_length, tvb, offset + F5_DPT_V1_TLV_LENGTH_OFF,
2114
0
            F5_DPT_V1_TLV_LENGTH_LEN, ENC_BIG_ENDIAN);
2115
0
    proto_tree_add_item(tree, hf_version, tvb, offset + F5_DPT_V1_TLV_VERSION_OFF,
2116
0
            F5_DPT_V1_TLV_VERSION_LEN, ENC_BIG_ENDIAN);
2117
0
} /* render_f5dptv1_tlvhdr() */
2118
2119
/*---------------------------------------------------------------------------*/
2120
/**
2121
 * @brief Render the data for DPT high noise trailer TLV
2122
 *
2123
 * @param tvb    The tvbuff containing the TLV block (header and data)
2124
 * @param pinfo  The pinfo structure for the frame
2125
 * @param tree   The tree to render the TVB under
2126
 * @param data   Pointer to tdata for the trailer
2127
 * @return       The size of the TVB
2128
 */
2129
static int
2130
dissect_dpt_trailer_noise_high(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data)
2131
0
{
2132
0
    proto_item *pi;
2133
0
    int o;
2134
0
    int len;
2135
0
    int ver;
2136
0
    uint8_t ipproto;
2137
0
    f5eth_tap_data_t *tdata = (f5eth_tap_data_t *)data;
2138
2139
0
    DISSECTOR_ASSERT(tdata != NULL);
2140
0
    len = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_LENGTH_OFF);
2141
0
    ver = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_VERSION_OFF);
2142
2143
    /* Unknown version, cannot do anything */
2144
0
    if (ver != 1) {
2145
0
        return 0;
2146
0
    }
2147
2148
0
    if (tree == NULL) {
2149
        /* We do not need to do anything if we do not have a tree */
2150
0
        return len;
2151
0
    }
2152
2153
0
    pi   = proto_tree_add_item(tree, hf_high_id, tvb, 0, len, ENC_NA);
2154
0
    tree = proto_item_add_subtree(pi, ett_f5ethtrailer_high);
2155
2156
0
    render_f5dptv1_tlvhdr(tvb, tree, 0);
2157
2158
0
    o                 = F5_DPT_V1_TLV_HDR_LEN;
2159
0
    tdata->noise_high = 1;
2160
2161
    /* If there was no peer id in the medium trailer, then there is no peer flow information to
2162
     * render; skip it all.
2163
     */
2164
0
    if (tdata->peer_flow == 0) {
2165
0
        proto_tree_add_item(tree, hf_peer_nopeer, tvb, o, len - o, ENC_NA);
2166
0
        return len;
2167
0
    }
2168
2169
    /* Add in the high order structures. */
2170
0
    ipproto = tvb_get_uint8(tvb, o);
2171
0
    proto_tree_add_item(tree, hf_peer_ipproto, tvb, o, 1, ENC_BIG_ENDIAN);
2172
0
    o += 1;
2173
0
    proto_tree_add_item(tree, hf_peer_vlan, tvb, o, 2, ENC_BIG_ENDIAN);
2174
0
    o += 2;
2175
2176
    /* peer remote address */
2177
0
    if (pref_pop_other_fields) {
2178
0
        displayIPv6as4(tree, hf_ip_ipaddr, -1, tvb, o, true);
2179
0
        pi = proto_tree_add_item(tree, hf_ip6_ip6addr, tvb, o, 16, ENC_NA);
2180
0
        proto_item_set_hidden(pi);
2181
0
    }
2182
0
    displayIPv6as4(tree, hf_peer_remote_addr, hf_peer_remote_rtdom, tvb, o, false);
2183
0
    displayIPv6as4(tree, hf_peer_ipaddr, hf_peer_rtdom, tvb, o, true);
2184
0
    proto_tree_add_item(tree, hf_peer_remote_ip6addr, tvb, o, 16, ENC_NA);
2185
0
    pi = proto_tree_add_item(tree, hf_peer_ip6addr, tvb, o, 16, ENC_NA);
2186
0
    proto_item_set_hidden(pi);
2187
0
    o += 16;
2188
2189
    /* peer local address */
2190
0
    if (pref_pop_other_fields) {
2191
0
        displayIPv6as4(tree, hf_ip_ipaddr, -1, tvb, o, true);
2192
0
        pi = proto_tree_add_item(tree, hf_ip6_ip6addr, tvb, o, 16, ENC_NA);
2193
0
        proto_item_set_hidden(pi);
2194
0
    }
2195
0
    displayIPv6as4(tree, hf_peer_local_addr, hf_peer_local_rtdom, tvb, o, false);
2196
0
    displayIPv6as4(tree, hf_peer_ipaddr, hf_peer_rtdom, tvb, o, true);
2197
0
    proto_tree_add_item(tree, hf_peer_local_ip6addr, tvb, o, 16, ENC_NA);
2198
0
    pi = proto_tree_add_item(tree, hf_peer_ip6addr, tvb, o, 16, ENC_NA);
2199
0
    proto_item_set_hidden(pi);
2200
0
    o += 16;
2201
2202
    /* peer remote port */
2203
0
    if (pref_pop_other_fields) {
2204
0
        switch (ipproto) {
2205
0
        case IP_PROTO_TCP:
2206
0
            pi = proto_tree_add_item(tree, hf_tcp_tcpport, tvb, o, 2, ENC_BIG_ENDIAN);
2207
0
            proto_item_set_hidden(pi);
2208
0
            break;
2209
0
        case IP_PROTO_UDP:
2210
0
            pi = proto_tree_add_item(tree, hf_udp_udpport, tvb, o, 2, ENC_BIG_ENDIAN);
2211
0
            proto_item_set_hidden(pi);
2212
0
            break;
2213
0
        }
2214
0
    }
2215
0
    proto_tree_add_item(tree, hf_peer_remote_port, tvb, o, 2, ENC_BIG_ENDIAN);
2216
0
    pi = proto_tree_add_item(tree, hf_peer_port, tvb, o, 2, ENC_BIG_ENDIAN);
2217
0
    proto_item_set_hidden(pi);
2218
0
    o += 2;
2219
2220
    /* peer remote port */
2221
0
    if (pref_pop_other_fields) {
2222
0
        switch (ipproto) {
2223
0
        case IP_PROTO_TCP:
2224
0
            pi = proto_tree_add_item(tree, hf_tcp_tcpport, tvb, o, 2, ENC_BIG_ENDIAN);
2225
0
            proto_item_set_hidden(pi);
2226
0
            break;
2227
0
        case IP_PROTO_UDP:
2228
0
            pi = proto_tree_add_item(tree, hf_udp_udpport, tvb, o, 2, ENC_BIG_ENDIAN);
2229
0
            proto_item_set_hidden(pi);
2230
0
            break;
2231
0
        }
2232
0
    }
2233
0
    proto_tree_add_item(tree, hf_peer_local_port, tvb, o, 2, ENC_BIG_ENDIAN);
2234
0
    pi = proto_tree_add_item(tree, hf_peer_port, tvb, o, 2, ENC_BIG_ENDIAN);
2235
0
    proto_item_set_hidden(pi);
2236
2237
0
    return len;
2238
0
} /* dissect_dpt_trailer_noise_high() */
2239
2240
/*---------------------------------------------------------------------------*/
2241
/**
2242
 * @brief Render the data for DPT medium noise trailer TVB
2243
 *
2244
 * @param tvb    The tvbuff containing the TLV block (header and data)
2245
 * @param pinfo  The pinfo structure for the frame
2246
 * @param tree   The tree to render the TVB under
2247
 * @param data   Pointer to tdata for the trailer
2248
 * @return       The size of the TVB
2249
 */
2250
static int
2251
dissect_dpt_trailer_noise_med(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2252
0
{
2253
0
    proto_item *pi;
2254
0
    int o;
2255
0
    int rstcauselen    = 0;
2256
0
    int badrstcauselen = 0;
2257
0
    unsigned rstcausever  = 0xff;
2258
0
    int len;
2259
0
    int ver;
2260
0
    f5eth_tap_data_t *tdata = (f5eth_tap_data_t *)data;
2261
2262
0
    DISSECTOR_ASSERT(tdata != NULL);
2263
0
    len = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_LENGTH_OFF);
2264
0
    ver = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_VERSION_OFF);
2265
2266
    /* Unknown version, cannot do anything */
2267
0
    if (ver != 4) {
2268
0
        return 0;
2269
0
    }
2270
2271
0
    pi   = proto_tree_add_item(tree, hf_med_id, tvb, 0, len, ENC_NA);
2272
0
    tree = proto_item_add_subtree(pi, ett_f5ethtrailer_med);
2273
2274
0
    render_f5dptv1_tlvhdr(tvb, tree, 0);
2275
2276
0
    o                = F5_DPT_V1_TLV_HDR_LEN;
2277
0
    tdata->noise_med = 1;
2278
0
    rstcauselen      = tvb_get_uint8(tvb, o + F5_MEDV4_LENMIN - 1);
2279
    /* Check for an invalid reset cause length and do not try to reference any of the data if it is
2280
     * bad
2281
     */
2282
0
    if (tvb_reported_length_remaining(tvb, o + F5_MEDV4_LENMIN) < rstcauselen) {
2283
0
        badrstcauselen = 1;
2284
        /* Set this to zero to prevent processing of things that utilize it */
2285
0
        rstcauselen = 0;
2286
0
    }
2287
0
    if (rstcauselen)
2288
0
        rstcausever = (tvb_get_uint8(tvb, o + F5_MEDV4_LENMIN) & 0xfe) >> 1;
2289
    /* If we want the RST cause in the summary, we need to do it here,
2290
     * before the tree check below */
2291
0
    if (rstcauselen && rstcause_in_info) {
2292
0
        if (rstcausever == 0x00) {
2293
0
            col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "[F5RST%s: %s]",
2294
0
                tvb_get_uint8(tvb, o + F5_MEDV4_LENMIN) & 0x01 ? "(peer)" : "",
2295
0
                tvb_get_string_enc(
2296
0
                    pinfo->pool, tvb, o + F5_MEDV4_LENMIN + 9, rstcauselen - 9, ENC_ASCII));
2297
0
        }
2298
0
    }
2299
2300
    /* We do not need to do anything more if we don't have a tree and we are not performing
2301
     * analysis */
2302
0
    if (pref_perform_analysis == false && tree == NULL)
2303
0
        return len;
2304
2305
0
    tdata->flow = tvb_get_ntoh64(tvb, o);
2306
0
    proto_tree_add_item(tree, hf_flow_id, tvb, o, 8, ENC_BIG_ENDIAN);
2307
0
    pi = proto_tree_add_item(tree, hf_any_flow, tvb, o, 8, ENC_BIG_ENDIAN);
2308
0
    proto_item_set_hidden(pi);
2309
0
    o += 8;
2310
0
    tdata->peer_flow = tvb_get_ntoh64(tvb, o);
2311
0
    proto_tree_add_item(tree, hf_peer_id, tvb, o, 8, ENC_BIG_ENDIAN);
2312
0
    pi = proto_tree_add_item(tree, hf_any_flow, tvb, o, 8, ENC_BIG_ENDIAN);
2313
0
    proto_item_set_hidden(pi);
2314
0
    o += 8;
2315
0
    tdata->flows_set = 1;
2316
0
    proto_tree_add_item(tree, hf_cf_flags2, tvb, o, 4, ENC_BIG_ENDIAN);
2317
0
    o += 4;
2318
0
    proto_tree_add_item(tree, hf_cf_flags, tvb, o, 4, ENC_BIG_ENDIAN);
2319
0
    o += 4;
2320
0
    proto_tree_add_item(tree, hf_flow_type, tvb, o, 1, ENC_BIG_ENDIAN);
2321
0
    o += 1;
2322
2323
    /* We do not need to do anything if we don't have a tree */
2324
    /* Needed to get here so that analysis and tap will work. */
2325
0
    if (tree == NULL) {
2326
0
        return len;
2327
0
    }
2328
2329
0
    proto_tree_add_item(tree, hf_ha_unit, tvb, o, 1, ENC_BIG_ENDIAN);
2330
0
    o += 1;
2331
0
    proto_tree_add_item(tree, hf_reserved, tvb, o, 4, ENC_BIG_ENDIAN);
2332
0
    o += 4;
2333
0
    proto_tree_add_item(tree, hf_priority, tvb, o, 1, ENC_BIG_ENDIAN);
2334
0
    o += 1;
2335
0
    if (badrstcauselen) {
2336
0
        proto_tree *rc_tree;
2337
0
        proto_item *rc_item;
2338
2339
0
        rc_item = proto_tree_add_item(tree, hf_rstcause, tvb, o, len - o, ENC_NA);
2340
0
        rc_tree = proto_item_add_subtree(rc_item, ett_f5ethtrailer_rstcause);
2341
0
        rc_item = proto_tree_add_item(rc_tree, hf_rstcause_len, tvb, o, 1, ENC_BIG_ENDIAN);
2342
0
        expert_add_info(pinfo, rc_item, &ei_f5eth_badlen);
2343
0
    } else if (rstcauselen) {
2344
0
        proto_tree *rc_tree;
2345
0
        proto_item *rc_item;
2346
0
        uint64_t rstcauseval;
2347
0
        uint64_t rstcauseline;
2348
0
        unsigned startcause;
2349
0
        uint8_t rstcausepeer;
2350
2351
0
        rc_item = proto_tree_add_item(tree, hf_rstcause, tvb, o, rstcauselen + 1, ENC_NA);
2352
0
        rc_tree = proto_item_add_subtree(rc_item, ett_f5ethtrailer_rstcause);
2353
0
        proto_tree_add_item(rc_tree, hf_rstcause_len, tvb, o, 1, ENC_BIG_ENDIAN);
2354
0
        o += 1;
2355
2356
0
        startcause = o;
2357
0
        switch (rstcausever) {
2358
0
        case 0x00:
2359
0
            rstcausepeer = tvb_get_uint8(tvb, o) & 0x1;
2360
0
            proto_tree_add_item(rc_tree, hf_rstcause_ver, tvb, o, 1, ENC_BIG_ENDIAN);
2361
0
            proto_tree_add_item(rc_tree, hf_rstcause_peer, tvb, o, 1, ENC_BIG_ENDIAN);
2362
0
            o += 1;
2363
2364
0
            rstcauseval  = tvb_get_ntoh64(tvb, o);
2365
0
            rstcauseline = (rstcauseval & 0x000000000000ffffLL);
2366
0
            rstcauseval  = (rstcauseval & 0xffffffffffff0000LL) >> 16;
2367
0
            proto_tree_add_uint64_format_value(rc_tree, hf_rstcause_val, tvb, o, 6, rstcauseval,
2368
0
                "0x%012" PRIx64, rstcauseval);
2369
0
            proto_tree_add_item(rc_tree, hf_rstcause_line, tvb, o + 6, 2, ENC_BIG_ENDIAN);
2370
0
            o += 8;
2371
2372
0
            proto_item_append_text(rc_item,
2373
0
                ": [%" PRIx64 ":%" PRIu64 "]%s %s", rstcauseval,
2374
0
                rstcauseline, rstcausepeer ? " {peer}" : "",
2375
0
                tvb_get_string_enc(
2376
0
                    pinfo->pool, tvb, o, rstcauselen - (o - startcause), ENC_ASCII));
2377
0
            proto_tree_add_item(rc_tree, hf_rstcause_txt, tvb, o,
2378
0
                rstcauselen - (o - startcause), ENC_ASCII);
2379
            /*o = startcause + rstcauselen;*/
2380
0
            break;
2381
0
        default:
2382
0
            break;
2383
0
        }
2384
0
    }
2385
0
    return len;
2386
0
} /* dissect_dpt_trailer_noise_med() */
2387
2388
static const value_string f5_obj_data_types[] = {
2389
    {0, "Virtual Server"},
2390
    {1, "Port"},
2391
    {2, "Trunk"},
2392
    {255, "Unknown"},
2393
    {0, NULL}
2394
};
2395
2396
/*---------------------------------------------------------------------------*/
2397
/**
2398
 * @brief Render the data for DPT low noise trailer TVB
2399
 *
2400
 * @param tvb    The tvbuff containing the TLV block (header and data)
2401
 * @param pinfo  The pinfo structure for the frame
2402
 * @param tree   The tree to render the TVB under
2403
 * @param data   Pointer to tdata for the trailer
2404
 * @return       The size of the TVB
2405
 */
2406
static int
2407
dissect_dpt_trailer_noise_low(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2408
0
{
2409
0
    int len;
2410
0
    int ver;
2411
0
    proto_item *pi;
2412
0
    proto_item *ti;
2413
0
    int offset;
2414
0
    unsigned flags;
2415
0
    unsigned ingress;
2416
0
    unsigned slot_display  = 0;
2417
0
    unsigned tmm;
2418
0
    f5eth_tap_data_t *tdata = (f5eth_tap_data_t *)data;
2419
2420
0
    DISSECTOR_ASSERT(tdata != NULL);
2421
0
    len = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_LENGTH_OFF);
2422
0
    ver = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_VERSION_OFF);
2423
2424
    /* Unknown version, cannot do anything */
2425
0
    if (ver < 2 || ver > 4) {
2426
0
        return 0;
2427
0
    }
2428
2429
    /* Add the Low Noise trailer and attach a subtree */
2430
0
    pi   = proto_tree_add_item(tree, hf_low_id, tvb, 0, len, ENC_NA);
2431
0
    tree = proto_item_add_subtree(pi, ett_f5ethtrailer_low);
2432
2433
0
    render_f5dptv1_tlvhdr(tvb, tree, 0);
2434
2435
0
    offset           = F5_DPT_V1_TLV_HDR_LEN;
2436
0
    tdata->noise_low = 1;
2437
2438
    /* Direction */
2439
0
    flags = tvb_get_uint8(tvb, offset);
2440
0
    if (ver == 2) {
2441
0
        ingress = flags;
2442
0
    } else {
2443
0
        ingress = flags & F5_LOW_FLAGS_INGRESS_MASK;
2444
0
    }
2445
    /* Use special formatting here so that users do not have to filter on "IN"
2446
     * and "OUT", but rather can continue to use typical boolean values.  "IN"
2447
     * and "OUT" are provided as convenience. */
2448
0
    pi = proto_tree_add_boolean_format_value(tree, hf_ingress, tvb, offset, 1, ingress,
2449
0
        "%s (%s)", tfs_get_true_false(ingress),
2450
0
            tfs_get_string(ingress, &f5tfs_ing));
2451
0
    if (ver > 2) {
2452
        /* The old ingress field is now a flag field.  Leave the old ingress field
2453
         * for backward compatibility for users that are accustomed to using
2454
         * "f5ethtrailer.ingress" but mark it as generated to indicate that that
2455
         * field no longer really exists. */
2456
0
        proto_item_set_generated(pi);
2457
0
        proto_tree_add_bitmask(
2458
0
            tree, tvb, offset, hf_flags, ett_f5ethtrailer_low_flags, hf_flags__fields,
2459
0
            ENC_BIG_ENDIAN);
2460
0
    }
2461
0
    tdata->ingress = ingress == 0 ? 0 : 1;
2462
0
    offset += 1;
2463
2464
    /* Slot */
2465
0
    slot_display = tvb_get_uint8(tvb, offset) + 1;
2466
0
    proto_tree_add_uint(tree, hf_slot1, tvb, offset, 1, slot_display);
2467
0
    offset += 1;
2468
2469
    /* TMM */
2470
0
    tmm = tvb_get_uint8(tvb, offset);
2471
0
    if (tmm < F5ETH_TAP_TMM_MAX && slot_display < F5ETH_TAP_SLOT_MAX) {
2472
0
        tdata->tmm  = tmm;
2473
0
        tdata->slot = slot_display;
2474
0
    }
2475
0
    proto_tree_add_item(tree, hf_tmm, tvb, offset, 1, ENC_BIG_ENDIAN);
2476
0
    offset += 1;
2477
2478
    /* Is the column visible? */
2479
0
    if (pref_info_type != none) {
2480
0
        f5eth_set_info_col(pinfo, ingress, slot_display, tmm);
2481
0
    }
2482
2483
0
    if (ver < 4) {        /* Low noise versions 2 and 3 */
2484
        /* VIP Name */
2485
0
        int viplen = tvb_get_uint8(tvb, offset);
2486
        /* Make sure VIP Name Length does not extend past the TVB */
2487
0
        if (tvb_reported_length_remaining(tvb, offset) < viplen) {
2488
0
            pi = proto_tree_add_item(tree, hf_vip, tvb, offset, 0, ENC_ASCII);
2489
0
            expert_add_info(pinfo, pi, &ei_f5eth_badlen);
2490
            /* Cannot go any further */
2491
0
            return len;
2492
0
        }
2493
0
        char *text = tvb_format_text(pinfo->pool, tvb, offset +1, viplen);
2494
0
        ti = proto_tree_add_subtree_format(
2495
0
            tree, tvb, offset, viplen + 1, ett_f5ethtrailer_obj_names, NULL,
2496
0
            "Virtual Server: %s", text);
2497
0
        proto_tree_add_item(ti, hf_vipnamelen, tvb, offset, 1, ENC_BIG_ENDIAN);
2498
0
        offset += 1;
2499
0
        proto_tree_add_item(ti, hf_vip, tvb, offset, viplen, ENC_ASCII);
2500
0
        if (viplen > 0 && have_tap_listener(tap_f5ethtrailer)) {
2501
0
            tdata->virtual_name = text;
2502
0
        }
2503
0
        offset += viplen;
2504
0
    } else {           /* Low noise version 4 */
2505
        /* This area now is a data block containing a number of BIG-IP config object names
2506
         * i.e. Virtual server that handled the packt
2507
         *     Port that handled the packet
2508
         *     Trunk that handled the packet
2509
         *
2510
         * 1-Byte      Length of block (excluding this byte)
2511
         * len-Bytes   data block
2512
         * <len><data block...>
2513
         *
2514
         * Then the "data block" is a variable number of object names
2515
         * Each name value is:
2516
         * 1-Byte      Type
2517
         * 1-Byte      Length (excluding type and length bytes)
2518
         * len-Bytes   String
2519
         * <type><len><string><type><len><string>
2520
         */
2521
2522
0
        int data_len = tvb_get_int8(tvb, offset);
2523
0
        pi = proto_tree_add_item(tree, hf_data, tvb, offset, 1, ENC_NA);
2524
0
        proto_item_set_text(pi, "Associated config object names");
2525
0
        ti = proto_item_add_subtree(pi, ett_f5ethtrailer_obj_names);
2526
0
        proto_tree_add_item(ti, hf_obj_data_len, tvb, offset, 1, ENC_BIG_ENDIAN);
2527
0
        offset += 1;
2528
0
        if (tvb_reported_length_remaining(tvb, offset) < data_len) {
2529
0
            expert_add_info(pinfo, pi, &ei_f5eth_badlen);
2530
            /* Cannot go any further */
2531
0
            return len;
2532
0
        }
2533
0
        proto_item_set_len(pi, data_len + 1);
2534
2535
        /* Begin parsing the data field and adding items for the strings contained */
2536
0
        tvbuff_t *data_tvb = tvb_new_subset_length(tvb, offset, data_len);
2537
0
        int data_off = 0;
2538
2539
0
        while (data_off < data_len) {
2540
0
            int field_name_len_idx;
2541
0
            int field_name_idx;
2542
0
            char *text_format;
2543
0
            uint8_t t = tvb_get_uint8(data_tvb, data_off);
2544
0
            uint8_t l = tvb_get_uint8(data_tvb, data_off + 1);
2545
2546
0
            switch (t) {
2547
0
            case 0: /* Virtual Server */
2548
0
                field_name_len_idx = hf_vipnamelen;
2549
0
                field_name_idx = hf_vip;
2550
0
                text_format = "Virtual Server: %s";
2551
0
                break;
2552
0
            case 1: /* Port */
2553
0
                field_name_len_idx = hf_portnamelen;
2554
0
                field_name_idx = hf_phys_port;
2555
0
                text_format = "Port: %s";
2556
0
                break;
2557
0
            case 2: /* Trunk */
2558
0
                field_name_len_idx = hf_trunknamelen;
2559
0
                field_name_idx = hf_trunk;
2560
0
                text_format = "Trunk: %s";
2561
0
                break;
2562
0
            default:
2563
                /* unknown type */
2564
0
                t = 255; /* Unknown */
2565
0
                field_name_len_idx = hf_obj_data_len;
2566
0
                field_name_idx = hf_data_str;
2567
0
                text_format = "Unknown type";
2568
0
                break;
2569
0
            }
2570
2571
0
            if (tvb_reported_length_remaining(data_tvb, data_off + 2) < l) {
2572
0
                ti = proto_tree_add_subtree_format(
2573
0
                    tree, data_tvb, data_off, 2, ett_f5ethtrailer_obj_names, NULL,
2574
0
                    text_format, "");
2575
0
                proto_tree_add_item(ti, hf_obj_name_type, data_tvb, data_off, 1, ENC_BIG_ENDIAN);
2576
0
                pi = proto_tree_add_item(
2577
0
                    ti, field_name_len_idx, data_tvb, data_off + 1, 1, ENC_BIG_ENDIAN);
2578
0
                expert_add_info(pinfo, pi, &ei_f5eth_badlen);
2579
                /* Cannot go any further */
2580
0
                return len;
2581
0
            }
2582
0
            char *text = tvb_format_text(pinfo->pool, data_tvb, data_off + 2, l);
2583
0
            ti = proto_tree_add_subtree_format(
2584
0
                tree, data_tvb, data_off, l + 2, ett_f5ethtrailer_obj_names, NULL,
2585
0
                text_format, text);
2586
0
            pi = proto_tree_add_item(ti, hf_obj_name_type, data_tvb, data_off, 1, ENC_BIG_ENDIAN);
2587
0
            if (t == 255) {
2588
0
                expert_add_info(pinfo, pi, &ei_f5eth_undecoded);
2589
0
            }
2590
0
            proto_tree_add_item(ti, field_name_len_idx, data_tvb, data_off + 1, 1, ENC_BIG_ENDIAN);
2591
0
            proto_tree_add_item(ti, field_name_idx, data_tvb, data_off + 2, l, ENC_ASCII|ENC_NA);
2592
0
            if (t == 0 && l > 0 && have_tap_listener(tap_f5ethtrailer)) {
2593
0
                tdata->virtual_name = text;
2594
0
            }
2595
0
            data_off += l + 2;
2596
0
        }
2597
0
        offset += data_off;
2598
0
    }
2599
0
    return offset;
2600
0
} /* dissect_dpt_trailer_noise_low() */
2601
2602
/*---------------------------------------------------------------------------*/
2603
/**
2604
 * @brief Render the data for DPT noise provider TVB
2605
 *
2606
 * @param tvb    The tvbuff containing the packet data for this TLV
2607
 * @param pinfo  The pinfo structure for the frame
2608
 * @param tree   The tree to render the TVB under
2609
 * @param data   Pointer to tdata for the trailer
2610
 * @return       The size of the TVB
2611
 */
2612
static int
2613
dissect_dpt_trailer_noise(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2614
0
{
2615
0
    uint32_t pattern;
2616
0
    pattern = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_TYPE_OFF) << 16
2617
0
              | tvb_get_ntohs(tvb, F5_DPT_V1_TLV_VERSION_OFF);
2618
0
    return (
2619
0
        dissector_try_uint_with_data(noise_subdissector_table, pattern, tvb, pinfo, tree, false, data));
2620
0
} /* dissect_dpt_trailer_noise() */
2621
2622
/*---------------------------------------------------------------------------*/
2623
/**
2624
 * @brief Render the data for DPT TVB for an unknown provider
2625
 *
2626
 * @param tvb    The tvbuff containing the packet data for this DPT
2627
 * @param pinfo  The pinfo structure for the frame
2628
 * @param tree   The tree to render the TVB under
2629
 * @param data   Pointer to tdata for the trailer
2630
 * @return       The size of the TVB
2631
 */
2632
static int
2633
dissect_dpt_trailer_unknown(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
2634
0
{
2635
0
    proto_item *pi;
2636
0
    int len;
2637
2638
0
    len = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_LENGTH_OFF);
2639
2640
0
    if (tree) {
2641
0
        pi   = proto_tree_add_item(tree, hf_dpt_unknown, tvb, 0, len, ENC_NA);
2642
0
        tree = proto_item_add_subtree(pi, ett_f5ethtrailer_unknown);
2643
2644
0
        render_f5dptv1_tlvhdr(tvb, tree, 0);
2645
2646
0
        proto_tree_add_item(
2647
0
            tree, hf_data, tvb, F5_DPT_V1_TLV_HDR_LEN, len - F5_DPT_V1_TLV_HDR_LEN, ENC_NA);
2648
0
    }
2649
2650
0
    return len;
2651
0
} /* dissect_dpt_trailer_unknown() */
2652
2653
/*---------------------------------------------------------------------------*/
2654
/**
2655
 * @brief Render the data for DPT block
2656
 *
2657
 *   There is no predetermined or guaranteed order the DPT TLVs will be
2658
 *   attached to the frame.  Use conversation data to coalesce information
2659
 *   across TLVs and frames.
2660
 *
2661
 * @param tvb    The tvbuff containing the packet data for this DPT block
2662
 * @param pinfo  The pinfo structure for the frame
2663
 * @param tree   The tree to render the DPT block in
2664
 * @param data   Pointer to tdata for the trailer
2665
 * @return       The size of the DPT block
2666
 */
2667
static int
2668
dissect_dpt_trailer(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2669
1
{
2670
1
    proto_item *pi;
2671
1
    proto_tree *hdr_tree;
2672
1
    int dpt_len;
2673
1
    int dpt_ver;
2674
1
    int o; /* offset*/
2675
2676
1
    dpt_len = tvb_get_ntohs(tvb, F5_DPT_V1_HDR_LENGTH_OFF);
2677
1
    dpt_ver = tvb_get_ntohs(tvb, F5_DPT_V1_HDR_VERSION_OFF);
2678
2679
    /* Render the DPT header */
2680
1
    pi = proto_tree_add_item(tree, hf_trailer_hdr, tvb, 0, F5_DPT_V1_TLV_HDR_LEN, ENC_NA);
2681
1
    proto_item_append_text(pi, " - Version: %d", dpt_ver);
2682
1
    hdr_tree = proto_item_add_subtree(pi, ett_f5ethtrailer_trailer_hdr);
2683
2684
1
    proto_tree_add_item(hdr_tree, hf_dpt_magic, tvb, F5_DPT_V1_HDR_MAGIC_OFF,
2685
1
            F5_DPT_V1_HDR_MAGIC_LEN, ENC_BIG_ENDIAN);
2686
1
    proto_tree_add_item(hdr_tree, hf_dpt_len, tvb, F5_DPT_V1_HDR_LENGTH_OFF,
2687
1
            F5_DPT_V1_HDR_LENGTH_LEN, ENC_BIG_ENDIAN);
2688
1
    proto_tree_add_item(hdr_tree, hf_dpt_ver, tvb, F5_DPT_V1_HDR_VERSION_OFF,
2689
1
            F5_DPT_V1_HDR_VERSION_LEN, ENC_BIG_ENDIAN);
2690
2691
    /* If this is an unknown version, return after rendering header and data */
2692
1
    if (dpt_ver < F5_DPT_V1_HDR_VERSION_MIN || dpt_ver > F5_DPT_V1_HDR_VERSION_MAX) {
2693
1
        proto_tree_add_item(
2694
1
            tree, hf_data, tvb, F5_DPT_V1_HDR_LEN, dpt_len - F5_DPT_V1_HDR_LEN, ENC_NA);
2695
1
        return dpt_len;
2696
1
    }
2697
2698
0
    o = F5_DPT_V1_HDR_LEN;
2699
2700
0
    while (tvb_reported_length_remaining(tvb, o) >= F5_DPT_V1_TLV_HDR_LEN) {
2701
0
        tvbuff_t *tvb_dpt_tlv;
2702
0
        int tvb_dpt_tlv_len;
2703
0
        int provider_id;
2704
2705
0
        tvb_dpt_tlv_len = tvb_get_ntohs(tvb, o + F5_DPT_V1_TLV_LENGTH_OFF);
2706
        /* Report an error if the length specified in the header is either
2707
         *   Not long enough to contain the header
2708
         *   Indicates that the TLV is longer than the data that would have been captured.
2709
         */
2710
0
        if (tvb_dpt_tlv_len < F5_DPT_V1_TLV_HDR_LEN
2711
0
            || tvb_dpt_tlv_len > tvb_reported_length_remaining(tvb, o)) {
2712
0
            proto_tree *subtree;
2713
0
            pi = proto_tree_add_item(tree, hf_dpt_unknown, tvb, o, F5_DPT_V1_TLV_HDR_LEN, ENC_NA);
2714
0
            subtree = proto_item_add_subtree(pi, ett_f5ethtrailer_unknown);
2715
0
            proto_tree_add_item(subtree, hf_provider, tvb, o + F5_DPT_V1_TLV_PROVIDER_OFF,
2716
0
                    F5_DPT_V1_TLV_PROVIDER_LEN, ENC_BIG_ENDIAN);
2717
0
            proto_tree_add_item(subtree, hf_type, tvb, o + F5_DPT_V1_TLV_TYPE_OFF,
2718
0
                    F5_DPT_V1_TLV_TYPE_LEN, ENC_BIG_ENDIAN);
2719
0
            pi = proto_tree_add_item(subtree, hf_length, tvb, o + F5_DPT_V1_TLV_LENGTH_OFF,
2720
0
                    F5_DPT_V1_TLV_LENGTH_LEN, ENC_BIG_ENDIAN);
2721
0
            expert_add_info(pinfo, pi, &ei_f5eth_badlen);
2722
0
            if (tvb_dpt_tlv_len >= F5_DPT_V1_TLV_HDR_LEN) {
2723
0
                proto_tree_add_item(subtree, hf_version, tvb, o + F5_DPT_V1_TLV_VERSION_OFF,
2724
0
                        F5_DPT_V1_TLV_VERSION_LEN, ENC_BIG_ENDIAN);
2725
0
            }
2726
            /* If the length here is bad, then we probably will not index to the next TLV, so
2727
             * abort and do not try to render anymore TLVs.
2728
             */
2729
0
            break;
2730
0
        }
2731
0
        provider_id = tvb_get_ntohs(tvb, o + F5_DPT_V1_TLV_PROVIDER_OFF);
2732
0
        tvb_dpt_tlv = tvb_new_subset_length(tvb, o, tvb_dpt_tlv_len);
2733
0
        if (dissector_try_uint_with_data(
2734
0
                provider_subdissector_table, provider_id, tvb_dpt_tlv, pinfo, tree, false, data)
2735
0
            == 0) {
2736
            /* Render the TLV header as unknown */
2737
0
            dissect_dpt_trailer_unknown(tvb_dpt_tlv, pinfo, tree, data);
2738
0
        }
2739
0
        o += tvb_dpt_tlv_len;
2740
0
    }
2741
2742
0
    return dpt_len;
2743
1
} /* dissect_dpt_trailer() */
2744
2745
/*---------------------------------------------------------------------------*/
2746
/**
2747
 * @brief Dissect the old format trailers (9.4.2 - 13.x)
2748
 *
2749
 * @param tvb    The tvbuff containing the packet data for this trailer
2750
 * @param pinfo  The pinfo structure for the frame
2751
 * @param tree   The tree to render the thrailer under
2752
 * @param data   Pointer to tdata for the trailer
2753
 * @return int   Number of bytes cosumed by the dissector
2754
 */
2755
static int
2756
dissect_old_trailer(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2757
75
{
2758
75
    unsigned offset            = 0;
2759
2760
    /* While we still have data in the trailer.  For old format trailers, this needs
2761
     * type, length, version (3 bytes) and for new format trailers, the magic header (4 bytes).
2762
     * All old format trailers are at least 4 bytes long, so just check for length of magic.
2763
     */
2764
87
    while (tvb_reported_length_remaining(tvb, offset) >= F5_MIN_SANE) {
2765
        /* length field does not include the type and length bytes.  Add them back in */
2766
85
        uint8_t len = tvb_get_uint8(tvb, offset + F5_OFF_LENGTH) + F5_OFF_VERSION;
2767
85
        if (len > tvb_reported_length_remaining(tvb, offset)
2768
85
            || len < F5_MIN_SANE || len > F5_MAX_SANE) {
2769
            /* Invalid length - either a malformed trailer, corrupt packet, or not f5ethtrailer */
2770
7
            return offset;
2771
7
        }
2772
78
        uint8_t type = tvb_get_uint8(tvb, offset);
2773
78
        uint8_t ver = tvb_get_uint8(tvb, offset + F5_OFF_VERSION);
2774
2775
        /* Parse out the specified trailer. */
2776
78
        proto_tree *type_tree   = NULL;
2777
78
        proto_item *ti          = NULL;
2778
78
        f5eth_tap_data_t *tdata = (f5eth_tap_data_t *)data;
2779
78
        unsigned processed = 0;
2780
2781
78
        switch (type) {
2782
36
        case F5TYPE_LOW:
2783
36
            ti        = proto_tree_add_item(tree, hf_low_id, tvb, offset, len, ENC_NA);
2784
36
            type_tree = proto_item_add_subtree(ti, ett_f5ethtrailer_low);
2785
2786
36
            processed = dissect_low_trailer(tvb, pinfo, type_tree, offset, len, ver, tdata);
2787
36
            if (processed > 0) {
2788
6
                tdata->trailer_len += processed;
2789
6
                tdata->noise_low = 1;
2790
6
            }
2791
36
            break;
2792
29
        case F5TYPE_MED:
2793
29
            ti        = proto_tree_add_item(tree, hf_med_id, tvb, offset, len, ENC_NA);
2794
29
            type_tree = proto_item_add_subtree(ti, ett_f5ethtrailer_med);
2795
2796
29
            processed = dissect_med_trailer(tvb, pinfo, type_tree, offset, len, ver, tdata);
2797
29
            if (processed > 0) {
2798
6
                tdata->trailer_len += processed;
2799
6
                tdata->noise_med = 1;
2800
6
            }
2801
29
            break;
2802
10
        case F5TYPE_HIGH:
2803
10
            ti        = proto_tree_add_item(tree, hf_high_id, tvb, offset, len, ENC_NA);
2804
10
            type_tree = proto_item_add_subtree(ti, ett_f5ethtrailer_high);
2805
2806
10
            processed =
2807
10
                dissect_high_trailer(tvb, pinfo, type_tree, offset, len, ver, tdata);
2808
10
            if (processed > 0) {
2809
0
                tdata->trailer_len += processed;
2810
0
                tdata->noise_high = 1;
2811
0
            }
2812
10
            break;
2813
3
        default:
2814
            /* Unknown type - malformed trailer, corrupt packet, or not f5ethtrailer - bali out*/
2815
3
            return offset;
2816
78
        }
2817
75
        if (processed == 0) {
2818
            /* couldn't process trailer - bali out */
2819
63
            proto_item_set_len(ti, 1);
2820
63
            return offset;
2821
63
        }
2822
12
        offset += processed;
2823
12
    }
2824
2
    return offset;
2825
75
} /* dissect_old_trailer() */
2826
2827
/*---------------------------------------------------------------------------*/
2828
/**
2829
 * @brief Dissector entry point
2830
 *
2831
 * @param tvb    The tvbuff containing the packet data for this trailer
2832
 * @param pinfo  The pinfo structure for the frame
2833
 * @param tree   The tree to render the thrailer under
2834
 * @param data   Pointer to tdata for the trailer
2835
 * @return int   Number of bytes cosumed by the dissector
2836
 *
2837
 * New format trailers (BIG-IP 14.0 and later) begin with
2838
 * 4-byte magic number (0xf5deb0f5)
2839
 * 2-byte trailer length (Length includes header)
2840
 * 2-byte version
2841
 * 1 or more variable length TLVs
2842
 *
2843
 * Each New format TLV starts with
2844
 * 2-byte Provider ID
2845
 * 2-byte Type ID
2846
 * 2-byte TLV Length (Length includes header)
2847
 * 2-byte Version
2848
 * (TLVlen - 8) bytes of data
2849
 *
2850
 * Old format trailers (BIG-IP 9.4.2 - 13.x) were a list of variable length
2851
 * TLVs.
2852
 * 1-byte Type
2853
 * 1-byte TLV Length (TLVlen does not include the type and length fields)
2854
 * TLVlen bytes of data
2855
 */
2856
static int
2857
dissect_f5ethtrailer(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2858
1.22k
{
2859
1.22k
    unsigned trailer_length;
2860
1.22k
    unsigned offset  = 0;
2861
1.22k
    found_t found = NONE;
2862
1.22k
    bool has_fcs = false;
2863
2864
1.22k
    if (tvb_reported_length(tvb) != tvb_captured_length(tvb)) {
2865
        /* The trailers are really only helpful if we have the entire trailer. If we
2866
           don't, don't try to dissect it. */
2867
8
        return 0;
2868
8
    }
2869
2870
    /* In some circumstances it is possible that a short ethernet frame was padded before tmm
2871
       was able to append f5ethtrailer.  In many cases (and should be) this padding is zeros.
2872
       The f5ethtrailer does not start with a zero, so trim off any leading zeros before
2873
       looking for an f5ethtrailer. */
2874
4.58k
    while (tvb_offset_exists(tvb, offset) && tvb_get_int8(tvb, offset) == 0) {
2875
3.36k
        offset++;
2876
3.36k
    }
2877
2878
1.21k
    trailer_length = tvb_reported_length_remaining(tvb, offset);
2879
1.21k
    if (trailer_length < F5_LOWV1_LENMIN) {
2880
        /* There must be at least enough bytes for a legacy low ver1 trailer.  New format
2881
           trailers will be longer */
2882
159
        return 0;
2883
159
    }
2884
2885
1.06k
    while (found == NONE) {
2886
        /* Check if this is a new format trailer. */
2887
1.06k
        if (trailer_length - offset >= F5_DPT_V1_HDR_MAGIC_LEN + F5_DPT_V1_HDR_LEN) {
2888
898
            if (tvb_get_ntohl(tvb, offset) == F5_DPT_V1_HDR_MAGIC) {
2889
2
                if (tvb_get_ntohs(tvb, offset + F5_DPT_V1_HDR_LENGTH_OFF) > trailer_length) {
2890
                    /* we have the right magic, but the length doesn't match up.
2891
                    assume we're not an f5ethtrailer, or it is corrupt.
2892
                    Either way, don't try and dissect. */
2893
1
                    return 0;
2894
1
                }
2895
                /* Looks like a new format trailer  */
2896
1
                found = NEW_FORMAT;
2897
1
                goto found_trailer;
2898
2
            }
2899
            /* It's possible to have the trailer added after the FCS has already been added.
2900
            Let's move in 4 bytes and check there.  However, it is also possible for the FCS
2901
            to start with a sequence of zeros that would have been already been skipped.  If so,
2902
            we need to back up.  If there is an FCS display the Original.
2903
2904
            Only add this check for new format trailers.  Old format trailers are becoming less
2905
            common and likely wouldn't have been added after FCS anyway.
2906
            If needed, the walk trailer prefernce would find the old format trailer after an FCS.
2907
            This seems reasonable enough for old format trailers. */
2908
2.56k
            for (unsigned i = 0; i <= offset && i <= 4; i++) {
2909
1.66k
                if (tvb_get_ntohl(tvb, offset + 4 - i) == F5_DPT_V1_HDR_MAGIC) {
2910
0
                    if (tvb_get_ntohs(tvb, offset + 4 - i + F5_DPT_V1_HDR_LENGTH_OFF) > trailer_length) {
2911
0
                        return 0;
2912
0
                    }
2913
0
                    found = NEW_FORMAT;
2914
0
                    has_fcs = true;
2915
0
                    offset += 4 - i;
2916
0
                    goto found_trailer;
2917
0
                }
2918
1.66k
            }
2919
896
        }
2920
2921
        /* Not new format? Are we old format? */
2922
1.05k
        unsigned tlv_type, tlv_length, tlv_ver;
2923
2924
        /* Check for old format trailers */
2925
1.05k
        tlv_type = tvb_get_uint8(tvb, offset);
2926
1.05k
        tlv_length = tvb_get_uint8(tvb, offset + F5_OFF_LENGTH) + F5_OFF_VERSION;
2927
1.05k
        tlv_ver = tvb_get_uint8(tvb, offset + F5_OFF_VERSION);
2928
2929
1.05k
        if ( tlv_length <= trailer_length && tlv_type >= F5TYPE_LOW && tlv_type <= F5TYPE_HIGH &&
2930
1.05k
            tlv_length >= F5_MIN_SANE && tlv_length <= F5_MAX_SANE &&
2931
1.05k
            tlv_ver <= F5TRAILER_VER_MAX) {
2932
            /* Found at least one old format TLV */
2933
75
            found = OLD_FORMAT;
2934
75
            goto found_trailer;
2935
75
        }
2936
983
        if (!pref_walk_trailer || tvb_reported_length_remaining(tvb, offset) <= F5_LOWV1_LENMIN)
2937
            /* Didn't find an f5ethtrailer, and we're not going to keep looking. */
2938
983
            return 0;
2939
2940
0
        offset++;
2941
0
    }
2942
2943
76
found_trailer:
2944
76
;
2945
    /* Good to go, start dissection */
2946
76
    f5eth_tap_data_t *tdata;
2947
76
    proto_item *trailer_item = NULL;
2948
2949
    /* Initialize data structure for taps and analysis */
2950
76
    tdata = wmem_new0(pinfo->pool, f5eth_tap_data_t);
2951
2952
76
    tdata->magic = F5ETH_TAP_MAGIC;
2953
76
    tdata->slot = F5ETH_TAP_SLOT_MAX;
2954
76
    tdata->tmm = F5ETH_TAP_TMM_MAX;
2955
2956
76
    if (tree) {
2957
76
        trailer_item = proto_tree_add_item(tree, proto_f5ethtrailer, tvb, offset, -1, ENC_NA);
2958
76
        tree = proto_item_add_subtree(trailer_item, ett_f5ethtrailer);
2959
76
        if (has_fcs) {
2960
0
            proto_tree_add_item(tree, hf_orig_fcs, tvb, offset - 4, 4, ENC_BIG_ENDIAN);
2961
0
        }
2962
76
    }
2963
2964
76
    if (found == NEW_FORMAT) {
2965
        /* dissect new format trailer */
2966
1
        trailer_length = dissect_dpt_trailer(tvb_new_subset_remaining(tvb, offset),
2967
1
                                             pinfo, tree, tdata);
2968
75
    } else {
2969
        /* dissect old format trailer */
2970
75
        trailer_length = dissect_old_trailer(tvb_new_subset_remaining(tvb, offset),
2971
75
                                             pinfo, tree, tdata);
2972
75
    }
2973
76
    tdata->trailer_len = trailer_length;
2974
76
    proto_item_set_len(trailer_item, trailer_length);
2975
2976
    /* If the analysis preference is enabled, process it */
2977
76
    if (pref_perform_analysis) {
2978
0
        struct f5eth_analysis_data_t *ad;
2979
2980
        /* Get the analysis data information for this packet */
2981
0
        ad = (struct f5eth_analysis_data_t *)p_get_proto_data(
2982
0
            wmem_file_scope(), pinfo, proto_f5ethtrailer, 0);
2983
0
        if (ad == NULL) {
2984
0
            ad = new_f5eth_analysis_data_t();
2985
0
            p_add_proto_data(wmem_file_scope(), pinfo, proto_f5ethtrailer, 0, ad);
2986
0
        }
2987
0
        if (ad->analysis_done == 0) {
2988
0
            ad->pkt_ingress = tdata->ingress;
2989
0
            if (tdata->flows_set == 1) {
2990
0
                ad->pkt_has_flow = tdata->flow == 0 ? 0 : 1;
2991
0
                ad->pkt_has_peer = tdata->peer_flow == 0 ? 0 : 1;
2992
0
            }
2993
            /* Only perform the analysis if we had an opportunity to get the TCP information.  In
2994
             * this case, if the ip tap ran then they all should have run.  We use IP so we don't
2995
             * perform analysis every time we visit a UDP/ICMP, etc. packet. */
2996
0
            if (ad->ip_visited)
2997
0
                perform_analysis(ad);
2998
0
        }
2999
0
        render_analysis(tvb, pinfo, tree, ad);
3000
0
    }
3001
3002
    /* Call tap handlers if it appears that we got enough data
3003
     * (should have low noise if there is anything) */
3004
76
    if (tdata->noise_low != 0) {
3005
6
        tap_queue_packet(tap_f5ethtrailer, pinfo, tdata);
3006
6
    }
3007
76
    return trailer_length;
3008
1.06k
} /* dissect_f5ethtrailer() */
3009
3010
static bool
3011
dissect_f5ethtrailer_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
3012
1.22k
{
3013
1.22k
    return dissect_f5ethtrailer(tvb, pinfo, tree, data) > 0;
3014
1.22k
}
3015
3016
/*-----------------------------------------------------------------------------------------------*/
3017
/*  Begin DPT TLS provider */
3018
/*-----------------------------------------------------------------------------------------------*/
3019
/*  We want to be able to render TLS diagnostic data that is available and
3020
 *  generate keylog entries for later decryption use.  We are not making
3021
 *  decisions about RFC compliance or functional correctness of the TLS
3022
 *  data here.  If data is there, we will render it.  If a keylog entry
3023
 *  can be generated we will generate it even if it is wrong.
3024
 *
3025
 *  The diagnostic information provided in F5 Ethernet trailers is state information
3026
 *  inteded for troubleshooting and diagnostics.  This data is not sent on the wire.
3027
 *  It is only appended to frames captured on the BIG-IP, if explicitly requested.  As
3028
 *  such if the data exists in the context, it will be appended to each packet with a
3029
 *  TLS layer.  Filtering of duplicate / appropriate data and interpretation is left
3030
 *  to the dissector.
3031
 *
3032
 *  This will result in things like the TLS dissector displaying the client random
3033
 *  in the CLIENT HELLO packet, while the F5 Ethtrailer TLS shows all zeros for the
3034
 *  client random.  Then the F5 Ethtrailer will provide the client random in the
3035
 *  ACK to the CLIENT HELLO.  It will also result in the same information being
3036
 *  provided on multiple packets.
3037
 *
3038
 *  All the necessary parts to create a valid keylog record needed for decryption
3039
 *  may not be available in the same frame.
3040
 */
3041
3042
14
#define F5_DPT_PROVIDER_TLS    4
3043
3044
/* PRE13 in this context indicates pre TLS-v1.3, not pre-standard (draft) TLS-v1.3.  i.e. TLS-v1.2 and earlier */
3045
14
#define F5_DPT_TLS_PRE13_STD   0
3046
14
#define F5_DPT_TLS_PRE13_EXT   1
3047
28
#define F5_DPT_TLS_13_STD      2
3048
14
#define F5_DPT_TLS_13_EXT      3
3049
3050
0
#define F5TLS_SECRET_LEN      48
3051
#define F5TLS_SESS_ID_LEN     32
3052
0
#define F5TLS_RANDOM_LEN      32
3053
0
#define F5TLS_HASH_LEN        64
3054
#define F5TLS_ZEROS_LEN      256
3055
0
#define F5TLS_T2V1_LEN       393
3056
3057
typedef struct _F5TLS_ELEMENT {
3058
    unsigned char *data; /* Pointer to a string of bytes wmem_file_scope allocated as needed. */
3059
    int len;     /* length of the item stored. */
3060
} f5tls_element_t;
3061
3062
/*
3063
 *  As we come across the initial crypto data, store it in a struct on the conversation.
3064
 */
3065
typedef struct _F5TLS_CONVERSATION_DATA {
3066
    f5tls_element_t master_secret;
3067
    f5tls_element_t client_random;
3068
    /* added by TLS 1.3 */
3069
    f5tls_element_t erly_traf_sec;
3070
    f5tls_element_t clnt_hs_sec;
3071
    f5tls_element_t srvr_hs_sec;
3072
    f5tls_element_t clnt_ap_sec;
3073
    f5tls_element_t srvr_ap_sec;
3074
} f5tls_conversation_data_t;
3075
3076
/*
3077
 * As we collect enough information to create a keylog entry in the conversation data create
3078
 * a field with the keylog entry on the first frame and store on the frame.  This should limit
3079
 * keylog entries to a unique list.
3080
 */
3081
typedef struct _F5TLS_PACKET_DATA {
3082
    char *cr_ms;
3083
    /* TLS 1.3 keylogs */
3084
    char *cr_erly_traff;
3085
    char *cr_clnt_app;
3086
    char *cr_srvr_app;
3087
    char *cr_clnt_hs;
3088
    char *cr_srvr_hs;
3089
} f5tls_packet_data_t;
3090
3091
typedef struct _F5TLS_DATA {
3092
    f5tls_conversation_data_t *conv;
3093
    f5tls_packet_data_t *pkt;
3094
} f5tls_data_t;
3095
3096
static int proto_f5ethtrailer_dpt_tls;
3097
3098
static int hf_f5tls_tls;
3099
3100
/* TLS 1.x fields */
3101
static int hf_f5tls_secret_len;
3102
static int hf_f5tls_mstr_sec;
3103
static int hf_f5tls_clnt_rand;
3104
static int hf_f5tls_srvr_rand;
3105
3106
/* TLS 1.3 fields */
3107
static int hf_f5tls_early_traffic_sec;
3108
static int hf_f5tls_clnt_hs_sec;
3109
static int hf_f5tls_srvr_hs_sec;
3110
static int hf_f5tls_clnt_app_sec;
3111
static int hf_f5tls_srvr_app_sec;
3112
static int hf_f5tls_keylog;
3113
3114
static int ett_f5tls;
3115
static int ett_f5tls_std;
3116
static int ett_f5tls_ext;
3117
3118
static dissector_table_t tls_subdissector_table;
3119
3120
/* The types of keylog entries that could be created */
3121
typedef enum {
3122
    CLIENT_RANDOM,
3123
    CLIENT_TRAFFIC_SECRET_0,
3124
    SERVER_TRAFFIC_SECRET_0,
3125
    CLIENT_HANDSHAKE_TRAFFIC_SECRET,
3126
    SERVER_HANDSHAKE_TRAFFIC_SECRET,
3127
    EARLY_TRAFFIC_SECRET,
3128
} keylog_t;
3129
3130
/* Create a field of zeros.  We need to check if the secrets, randoms, etc are all zeros and memcmp
3131
 * looks like the best way to do it.  So, create a single, global field of zeros at file scope.
3132
 * That should cut down on some overhead...
3133
 */
3134
static unsigned char f5tls_zeros[F5TLS_ZEROS_LEN];
3135
3136
/*-----------------------------------------------------------------------*/
3137
/** Get a null terminated hexstring of a byte array
3138
 *
3139
 * @param scope   scope of the wmem allocate buffer
3140
 * @param ba      The byte aray to convert to a hexstring
3141
 * @param ba_len  Number of bytes to convert
3142
 * @return        Null terminated char* wmem allocated - no need to free
3143
 */
3144
static char *
3145
f5eth_bytes_to_hexstrnz(wmem_allocator_t *scope, const unsigned char *ba, int ba_len)
3146
0
{
3147
0
    char *hexstr;
3148
0
    char *end;
3149
3150
0
    hexstr = (char *)wmem_alloc(scope, ba_len * 2 + 1);
3151
0
    end    = bytes_to_hexstr(hexstr, ba, ba_len);
3152
0
    *end   = '\0';
3153
0
    return hexstr;
3154
0
} /* f5eth_bytes_to_hexstrnz */
3155
3156
/*-----------------------------------------------------------------------------------------------*/
3157
/**
3158
 * @brief Create a keylog entry and add it to the packet info
3159
 *
3160
 * Keylog entries will be created as described in the tls dissector.
3161
 * packet-tls-utils.c:  tls_keylog_process_lines()
3162
 *
3163
 * @param keylog_type  Type of keylog record to generate
3164
 * @param xxxx         First crypto element in for keylog record (see above)
3165
 * @param yyyy         Second crypto element in the keylog record (see above)
3166
 * @return             Null terminated keylog record wmem allocated with file scope
3167
 */
3168
static char *
3169
f5eth_add_tls_keylog(packet_info *pinfo, keylog_t keylog_type, f5tls_element_t *xxxx, f5tls_element_t *yyyy)
3170
0
{
3171
0
    char *xxxx_hex;
3172
0
    char *yyyy_hex;
3173
3174
0
    xxxx_hex = f5eth_bytes_to_hexstrnz(pinfo->pool, xxxx->data, xxxx->len);
3175
0
    yyyy_hex = f5eth_bytes_to_hexstrnz(pinfo->pool, yyyy->data, yyyy->len);
3176
3177
0
    switch (keylog_type) {
3178
0
    case CLIENT_RANDOM:
3179
0
        return wmem_strdup_printf(wmem_file_scope(), "CLIENT_RANDOM %s %s", xxxx_hex, yyyy_hex);
3180
0
    case CLIENT_TRAFFIC_SECRET_0:
3181
0
        return wmem_strdup_printf(
3182
0
            wmem_file_scope(), "CLIENT_TRAFFIC_SECRET_0 %s %s", xxxx_hex, yyyy_hex);
3183
0
    case SERVER_TRAFFIC_SECRET_0:
3184
0
        return wmem_strdup_printf(
3185
0
            wmem_file_scope(), "SERVER_TRAFFIC_SECRET_0 %s %s", xxxx_hex, yyyy_hex);
3186
0
    case CLIENT_HANDSHAKE_TRAFFIC_SECRET:
3187
0
        return wmem_strdup_printf(
3188
0
            wmem_file_scope(), "CLIENT_HANDSHAKE_TRAFFIC_SECRET %s %s", xxxx_hex, yyyy_hex);
3189
0
    case SERVER_HANDSHAKE_TRAFFIC_SECRET:
3190
0
        return wmem_strdup_printf(
3191
0
            wmem_file_scope(), "SERVER_HANDSHAKE_TRAFFIC_SECRET %s %s", xxxx_hex, yyyy_hex);
3192
0
    case EARLY_TRAFFIC_SECRET:
3193
0
        return wmem_strdup_printf(
3194
0
            wmem_file_scope(), "CLIENT_EARLY_TRAFFIC_SECRET %s %s", xxxx_hex, yyyy_hex);
3195
0
    default:
3196
0
        DISSECTOR_ASSERT_NOT_REACHED();
3197
0
    }
3198
0
} /* f5eth_add_tls_keylog() */
3199
3200
/*-----------------------------------------------------------------------------------------------*/
3201
/**
3202
 * @brief Process the data entries
3203
 *
3204
 * @param element   Pointer to crypto element
3205
 * @param pinfo     Packet info pointer (unused)
3206
 * @param tvb       tvb
3207
 * @param offset    Offset into the tvb to pull the entry
3208
 * @param len       Length of byte string to convert from the tvb
3209
 * @return          Is the entry different than previously seen
3210
 */
3211
static bool
3212
f5eth_add_tls_element(
3213
    f5tls_element_t *element, packet_info *pinfo _U_, tvbuff_t *tvb, unsigned offset, int len)
3214
0
{
3215
0
    if (element == NULL || len <= 0 || tvb_memeql(tvb, offset, f5tls_zeros, len) == 0) {
3216
        /* Nothing to do */
3217
0
        return false;
3218
0
    }
3219
3220
0
    if (element->len == len && tvb_memeql(tvb, offset, element->data, len) == 0) {
3221
        /* unchanged */
3222
0
        return false;
3223
0
    }
3224
3225
    /* Populate the element structure */
3226
0
    element->data = (unsigned char *)wmem_realloc(wmem_file_scope(), element->data, len);
3227
0
    element->len  = len;
3228
0
    tvb_memcpy(tvb, element->data, offset, len);
3229
0
    return true;
3230
3231
0
} /* f5eth_add_tls_element() */
3232
3233
/*----------------------------------------------------------------------*/
3234
/** TLS <= 1.2 trailer - Type 0
3235
 *
3236
 * @param tvb    The tvbuff containing the DPT TLV block (header and data).
3237
 * @param pinfo  The pinfo structure for the frame.
3238
 * @param tree   The tree to render the DPT TLV under.
3239
 * @param data   Structure pointing to conversation and packet proto data.
3240
 * @return       Number of bytes decoded.
3241
 */
3242
static int
3243
dissect_dpt_trailer_tls_type0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
3244
0
{
3245
0
    proto_item *pi;
3246
0
    int len;
3247
0
    int ver;
3248
0
    int o;
3249
0
    f5tls_conversation_data_t *conv_data = NULL;
3250
0
    f5tls_packet_data_t *pdata           = NULL;
3251
3252
0
    len = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_LENGTH_OFF);
3253
0
    ver = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_VERSION_OFF);
3254
3255
0
    switch (ver) {
3256
0
    case 0:
3257
        /* Create a subtree and render a header */
3258
0
        pi   = proto_tree_add_item(tree, hf_f5tls_tls, tvb, 0, len, ENC_NA);
3259
0
        tree = proto_item_add_subtree(pi, ett_f5tls_std);
3260
3261
0
        render_f5dptv1_tlvhdr(tvb, tree, 0);
3262
3263
0
        o = F5_DPT_V1_TLV_HDR_LEN;
3264
3265
        /* Add our fields */
3266
0
        proto_tree_add_item(tree, hf_f5tls_mstr_sec, tvb, o, F5TLS_SECRET_LEN, ENC_NA);
3267
0
        o += F5TLS_SECRET_LEN;
3268
0
        proto_tree_add_item(tree, hf_f5tls_clnt_rand, tvb, o, F5TLS_RANDOM_LEN, ENC_NA);
3269
0
        o += F5TLS_RANDOM_LEN;
3270
0
        proto_tree_add_item(tree, hf_f5tls_srvr_rand, tvb, o, F5TLS_RANDOM_LEN, ENC_NA);
3271
        /* o += F5TLS_RANDOM_LEN; */
3272
3273
0
        if (!pref_generate_keylog || data == NULL) {
3274
0
            break;
3275
0
        }
3276
3277
0
        pdata     = ((f5tls_data_t *)data)->pkt;
3278
0
        conv_data = ((f5tls_data_t *)data)->conv;
3279
3280
        /* If this is our first pass through, add protocol data and build keylog entries.
3281
           Assume that by the time the master secret is processed, the client random is
3282
           available on the conversation data. */
3283
0
        if (!pinfo->fd->visited) {
3284
0
            bool ms_changed;
3285
3286
0
            ms_changed = f5eth_add_tls_element(
3287
0
                &conv_data->master_secret, pinfo, tvb, F5_DPT_V1_TLV_HDR_LEN, F5TLS_SECRET_LEN);
3288
0
            f5eth_add_tls_element(&conv_data->client_random, pinfo, tvb,
3289
0
                F5_DPT_V1_TLV_HDR_LEN + F5TLS_SECRET_LEN, F5TLS_RANDOM_LEN);
3290
3291
0
            if (conv_data->client_random.len != 0 && ms_changed) {
3292
0
                pdata->cr_ms = f5eth_add_tls_keylog(pinfo,
3293
0
                    CLIENT_RANDOM, &conv_data->client_random, &conv_data->master_secret);
3294
0
            }
3295
0
        }
3296
3297
        /* Display any keylog entries we have in our packet data */
3298
0
        if (pdata->cr_ms != NULL) {
3299
0
            pi = proto_tree_add_string(tree, hf_f5tls_keylog, tvb, 0, 0, pdata->cr_ms);
3300
0
            proto_item_set_generated(pi);
3301
0
        }
3302
0
        break;
3303
0
    default:
3304
        /* Unknown version */
3305
0
        len = 0;
3306
0
        break;
3307
0
    }
3308
0
    return len;
3309
0
} /* dissect_dpt_trailer_tls_type0() */
3310
3311
/*----------------------------------------------------------------------*/
3312
/** TLS 1.3 trailer - Type 2
3313
 *
3314
 * @param tvb    The tvbuff containing the DPT TLV block (header and data).
3315
 * @param pinfo  The pinfo structure for the frame.
3316
 * @param tree   The tree to render the DPT TLV under.
3317
 * @param data   Structure pointing to conversation and packet proto data.
3318
 * @return       Number of bytes decoded.
3319
 */
3320
static int
3321
dissect_dpt_trailer_tls_type2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
3322
0
{
3323
0
    proto_item *pi;
3324
0
    int len;
3325
0
    int ver;
3326
0
    int o;
3327
0
    int secret_len;
3328
0
    f5tls_conversation_data_t *conv_data = NULL;
3329
0
    f5tls_packet_data_t *pdata           = NULL;
3330
3331
0
    len = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_LENGTH_OFF);
3332
0
    ver = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_VERSION_OFF);
3333
3334
0
    switch (ver) {
3335
0
    case 0:
3336
0
    case 1:
3337
        /* Create a subtree and render a header */
3338
0
        pi   = proto_tree_add_item(tree, hf_f5tls_tls, tvb, 0, len, ENC_NA);
3339
0
        tree = proto_item_add_subtree(pi, ett_f5tls_std);
3340
3341
0
        render_f5dptv1_tlvhdr(tvb, tree, 0);
3342
3343
0
        o = F5_DPT_V1_TLV_HDR_LEN;
3344
3345
0
        secret_len = tvb_get_uint8(tvb, o);
3346
        /* Add our fields */
3347
0
        pi = proto_tree_add_item(tree, hf_f5tls_secret_len, tvb, o, 1, ENC_NA);
3348
0
        o += 1;
3349
0
        if (secret_len == 0) {
3350
            /* nothing to render */
3351
0
            break; /* switch (ver) */
3352
0
        } else if (secret_len > F5TLS_HASH_LEN) {
3353
0
            expert_add_info(pinfo, pi, &ei_f5eth_badlen);
3354
0
            break; /* switch (ver) */
3355
0
        } else {
3356
0
            if (ver == 1) {
3357
0
                proto_tree_add_item(tree, hf_f5tls_early_traffic_sec, tvb, o, secret_len, ENC_NA);
3358
0
                o += F5TLS_HASH_LEN;
3359
0
            } else if (ver == 0 && len == F5TLS_T2V1_LEN) {
3360
0
                o += F5TLS_HASH_LEN;
3361
0
            }
3362
0
            proto_tree_add_item(tree, hf_f5tls_clnt_hs_sec, tvb, o, secret_len, ENC_NA);
3363
0
            o += F5TLS_HASH_LEN;
3364
0
            proto_tree_add_item(tree, hf_f5tls_srvr_hs_sec, tvb, o, secret_len, ENC_NA);
3365
0
            o += F5TLS_HASH_LEN;
3366
0
            proto_tree_add_item(tree, hf_f5tls_clnt_app_sec, tvb, o, secret_len, ENC_NA);
3367
0
            o += F5TLS_HASH_LEN;
3368
0
            proto_tree_add_item(tree, hf_f5tls_srvr_app_sec, tvb, o, secret_len, ENC_NA);
3369
0
            o += F5TLS_HASH_LEN;
3370
0
            proto_tree_add_item(tree, hf_f5tls_clnt_rand, tvb, o, F5TLS_RANDOM_LEN, ENC_NA);
3371
0
            o += F5TLS_RANDOM_LEN;
3372
0
            proto_tree_add_item(tree, hf_f5tls_srvr_rand, tvb, o, F5TLS_RANDOM_LEN, ENC_NA);
3373
            /* o += F5TLS_RANDOM_LEN; */
3374
0
        }
3375
3376
0
        if (!pref_generate_keylog || data == NULL) {
3377
0
            break;
3378
0
        }
3379
3380
0
        pdata     = ((f5tls_data_t *)data)->pkt;
3381
0
        conv_data = ((f5tls_data_t *)data)->conv;
3382
3383
        /* If this is our first pass through, add protocol data and build keylog entries.
3384
           Assume that if a CRand exists on the conversation that it is the one that matches
3385
           up with the newly set / changed secret. */
3386
0
        if (!pinfo->fd->visited) {
3387
0
            bool ets_changed = false;
3388
0
            bool chs_changed = false;
3389
0
            bool shs_changed = false;
3390
0
            bool cap_changed = false;
3391
0
            bool sap_changed = false;
3392
3393
0
            o = F5_DPT_V1_TLV_HDR_LEN + 1;
3394
3395
0
            if (ver == 1) {
3396
0
                ets_changed =
3397
0
                    f5eth_add_tls_element(&conv_data->erly_traf_sec, pinfo, tvb, o, secret_len);
3398
0
                o += F5TLS_HASH_LEN;
3399
0
            } else if (ver == 0 && len == F5TLS_T2V1_LEN) {
3400
0
                o += F5TLS_HASH_LEN;
3401
0
            }
3402
0
            chs_changed =
3403
0
                f5eth_add_tls_element(&conv_data->clnt_hs_sec, pinfo, tvb, o, secret_len);
3404
0
            o += F5TLS_HASH_LEN;
3405
0
            shs_changed =
3406
0
                f5eth_add_tls_element(&conv_data->srvr_hs_sec, pinfo, tvb, o, secret_len);
3407
0
            o += F5TLS_HASH_LEN;
3408
0
            cap_changed =
3409
0
                f5eth_add_tls_element(&conv_data->clnt_ap_sec, pinfo, tvb, o, secret_len);
3410
0
            o += F5TLS_HASH_LEN;
3411
0
            sap_changed =
3412
0
                f5eth_add_tls_element(&conv_data->srvr_ap_sec, pinfo, tvb, o, secret_len);
3413
0
            o += F5TLS_HASH_LEN;
3414
0
            f5eth_add_tls_element(&conv_data->client_random, pinfo, tvb, o, F5TLS_RANDOM_LEN);
3415
3416
0
            if (conv_data->client_random.len != 0) {
3417
0
                if (ver == 1 && ets_changed) {
3418
0
                    pdata->cr_erly_traff = f5eth_add_tls_keylog(pinfo, EARLY_TRAFFIC_SECRET,
3419
0
                        &conv_data->client_random, &conv_data->erly_traf_sec);
3420
0
                }
3421
0
                if (cap_changed) {
3422
0
                    pdata->cr_clnt_app = f5eth_add_tls_keylog(pinfo, CLIENT_TRAFFIC_SECRET_0,
3423
0
                        &conv_data->client_random, &conv_data->clnt_ap_sec);
3424
0
                }
3425
0
                if (sap_changed) {
3426
0
                    pdata->cr_srvr_app = f5eth_add_tls_keylog(pinfo, SERVER_TRAFFIC_SECRET_0,
3427
0
                        &conv_data->client_random, &conv_data->srvr_ap_sec);
3428
0
                }
3429
0
                if (chs_changed) {
3430
0
                    pdata->cr_clnt_hs = f5eth_add_tls_keylog(pinfo, CLIENT_HANDSHAKE_TRAFFIC_SECRET,
3431
0
                        &conv_data->client_random, &conv_data->clnt_hs_sec);
3432
0
                }
3433
0
                if (shs_changed) {
3434
0
                    pdata->cr_srvr_hs = f5eth_add_tls_keylog(pinfo, SERVER_HANDSHAKE_TRAFFIC_SECRET,
3435
0
                        &conv_data->client_random, &conv_data->srvr_hs_sec);
3436
0
                }
3437
0
            }
3438
0
        }
3439
3440
        /* Display any keylog entries we have in our packet data */
3441
0
        if (pdata->cr_erly_traff != NULL) {
3442
0
            pi = proto_tree_add_string(tree, hf_f5tls_keylog, tvb, 0, 0, pdata->cr_erly_traff);
3443
0
            proto_item_set_generated(pi);
3444
0
        }
3445
0
        if (pdata->cr_clnt_app != NULL) {
3446
0
            pi = proto_tree_add_string(tree, hf_f5tls_keylog, tvb, 0, 0, pdata->cr_clnt_app);
3447
0
            proto_item_set_generated(pi);
3448
0
        }
3449
0
        if (pdata->cr_srvr_app != NULL) {
3450
0
            pi = proto_tree_add_string(tree, hf_f5tls_keylog, tvb, 0, 0, pdata->cr_srvr_app);
3451
0
            proto_item_set_generated(pi);
3452
0
        }
3453
0
        if (pdata->cr_clnt_hs != NULL) {
3454
0
            pi = proto_tree_add_string(tree, hf_f5tls_keylog, tvb, 0, 0, pdata->cr_clnt_hs);
3455
0
            proto_item_set_generated(pi);
3456
0
        }
3457
0
        if (pdata->cr_srvr_hs != NULL) {
3458
0
            pi = proto_tree_add_string(tree, hf_f5tls_keylog, tvb, 0, 0, pdata->cr_srvr_hs);
3459
0
            proto_item_set_generated(pi);
3460
0
        }
3461
0
        break;
3462
0
    default:
3463
        /* Unknown version */
3464
0
        len = 0;
3465
0
        break;
3466
0
    }
3467
0
    return len;
3468
0
} /* dissect_dpt_trailer_tls_type2() */
3469
3470
/*----------------------------------------------------------------------*/
3471
/** TLS extended trailer - Types 1 and 3
3472
 *
3473
 *  Render as <DATA> - No dissection
3474
 *
3475
 * @param tvb    The tvbuff containing the DPT TLV block (header and data).
3476
 * @param pinfo  The pinfo structure for the frame (unused).
3477
 * @param tree   The tree to render the DPT TLV under.
3478
 * @param data   Data passed (unused).
3479
 * @return       Number of bytes decoded.
3480
 */
3481
static int
3482
dissect_dpt_trailer_tls_extended(
3483
    tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
3484
0
{
3485
0
    proto_item *pi;
3486
0
    int len;
3487
3488
0
    len = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_LENGTH_OFF);
3489
3490
    /* Create a subtree and render a header */
3491
0
    pi = proto_tree_add_item(tree, hf_f5tls_tls, tvb, 0, len, ENC_NA);
3492
0
    proto_item_append_text(pi, ", Extended Info");
3493
0
    tree = proto_item_add_subtree(pi, ett_f5tls_ext);
3494
3495
0
    render_f5dptv1_tlvhdr(tvb, tree, 0);
3496
3497
0
    proto_tree_add_item(
3498
0
        tree, hf_data, tvb, F5_DPT_V1_TLV_HDR_LEN, len - F5_DPT_V1_TLV_HDR_LEN, ENC_NA);
3499
0
    return len;
3500
0
} /* dissect_dpt_trailer_tls_extended() */
3501
3502
/*-----------------------------------------------------------------------------------------------*/
3503
/**
3504
 * @brief Dissector for the TLS DPT provider
3505
 *
3506
 * @param tvb    The tvbuff containing the DPT TLV block (header and data).
3507
 * @param pinfo  The pinfo structure for the frame.
3508
 * @param tree   The tree to render the DPT TLV under.
3509
 * @param data   Data passed (tap data) (unused).
3510
 * @return       The length as read from the TLV header.
3511
 *
3512
 */
3513
static int
3514
dissect_dpt_trailer_tls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
3515
0
{
3516
0
    uint32_t pattern;
3517
0
    conversation_t *conv   = NULL;
3518
0
    f5tls_data_t *tls_data = NULL;
3519
3520
    /* We only need the conversation to bring data parts together that arrive on
3521
       different frames.  After the first pass, the keylog entries are stored
3522
       on the individual packet's data */
3523
0
    if (pref_generate_keylog) {
3524
0
        tls_data = wmem_new0(pinfo->pool, f5tls_data_t);
3525
0
        if (!pinfo->fd->visited) {
3526
0
            conv           = find_or_create_conversation(pinfo);
3527
0
            tls_data->conv = (f5tls_conversation_data_t *)conversation_get_proto_data(
3528
0
                conv, proto_f5ethtrailer_dpt_tls);
3529
0
            if (tls_data->conv == NULL) {
3530
0
                tls_data->conv = wmem_new0(wmem_file_scope(), f5tls_conversation_data_t);
3531
0
                conversation_add_proto_data(conv, proto_f5ethtrailer_dpt_tls, tls_data->conv);
3532
0
            }
3533
0
        }
3534
0
        tls_data->pkt = (f5tls_packet_data_t *)p_get_proto_data(
3535
0
            wmem_file_scope(), pinfo, proto_f5ethtrailer_dpt_tls, 0);
3536
0
        if (tls_data->pkt == NULL) {
3537
0
            tls_data->pkt = wmem_new0(wmem_file_scope(), f5tls_packet_data_t);
3538
0
            p_add_proto_data(
3539
0
                wmem_file_scope(), pinfo, proto_f5ethtrailer_dpt_tls, 0, tls_data->pkt);
3540
0
        }
3541
0
    }
3542
3543
    /* Combine 2 byte TYPE with 2 byte VERSION into uint32_t for the subdissector table lookup */
3544
0
    pattern = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_TYPE_OFF) << 16
3545
0
              | tvb_get_ntohs(tvb, F5_DPT_V1_TLV_VERSION_OFF);
3546
0
    return (
3547
0
        dissector_try_uint_with_data(tls_subdissector_table, pattern, tvb, pinfo, tree, false, tls_data));
3548
0
} /* dissect_f5dpt_tls() */
3549
3550
/*-----------------------------------------------------------------------------------------------*/
3551
/* End DPT TLS Provider */
3552
/*-----------------------------------------------------------------------------------------------*/
3553
3554
/**
3555
 * @brief Initialization routine called before first pass through a capture.
3556
 *
3557
 */
3558
static void
3559
proto_init_f5ethtrailer(void)
3560
14
{
3561
    /** Need to set display_slot to true when initially reading a capture.  This covers the
3562
     *  situation when a user loads a capture that turns off slot display and then loads a
3563
     *  different capture that contains trailers, but does not have the F5INFO frame.  In this
3564
     *  case, we need to turn the slot display back on. */
3565
14
    display_slot = true;
3566
    /* Set the info column function to use based on whether or not an in/out only
3567
     * preference is chosen. */
3568
14
    switch (pref_info_type) {
3569
0
    case in_out_only:
3570
0
    case brief_in_out_only:
3571
0
        f5eth_set_info_col = f5eth_set_info_col_inout;
3572
0
        break;
3573
14
    default:
3574
14
        f5eth_set_info_col = f5eth_set_info_col_slot;
3575
14
        break;
3576
14
    }
3577
3578
    /* If we are doing analysis, enable the tap listeners */
3579
14
    if (pref_perform_analysis) {
3580
0
        GString *error_string;
3581
3582
0
        error_string = register_tap_listener(
3583
0
            "ip", &tap_ip_enabled, NULL, TL_REQUIRES_NOTHING, NULL, ip_tap_pkt, NULL, NULL);
3584
0
        if (error_string) {
3585
0
            ws_warning("Unable to register tap \"ip\" for f5ethtrailer: %s", error_string->str);
3586
0
            g_string_free(error_string, TRUE);
3587
0
        } else {
3588
0
            tap_ip_enabled = true;
3589
0
        }
3590
0
        error_string = register_tap_listener(
3591
0
            "ipv6", &tap_ipv6_enabled, NULL, TL_REQUIRES_NOTHING, NULL, ipv6_tap_pkt, NULL, NULL);
3592
0
        if (error_string) {
3593
0
            ws_warning("Unable to register tap \"ipv6\" for f5ethtrailer: %s", error_string->str);
3594
0
            g_string_free(error_string, TRUE);
3595
0
        } else {
3596
0
            tap_ipv6_enabled = true;
3597
0
        }
3598
0
        error_string = register_tap_listener(
3599
0
            "tcp", &tap_tcp_enabled, NULL, TL_REQUIRES_NOTHING, NULL, tcp_tap_pkt, NULL, NULL);
3600
0
        if (error_string) {
3601
0
            ws_warning("Unable to register tap \"tcp\" for f5ethtrailer: %s", error_string->str);
3602
0
            g_string_free(error_string, TRUE);
3603
0
        } else {
3604
0
            tap_tcp_enabled = true;
3605
0
        }
3606
0
    }
3607
14
}
3608
3609
/**
3610
 * @brief Cleanup after closing a capture file.
3611
 *
3612
 */
3613
static void
3614
f5ethtrailer_cleanup(void)
3615
0
{
3616
0
    if (tap_tcp_enabled) {
3617
0
        remove_tap_listener(&tap_tcp_enabled);
3618
0
        tap_tcp_enabled = false;
3619
0
    }
3620
0
    if (tap_ipv6_enabled) {
3621
0
        remove_tap_listener(&tap_ipv6_enabled);
3622
0
        tap_ipv6_enabled = false;
3623
0
    }
3624
0
    if (tap_ip_enabled) {
3625
0
        remove_tap_listener(&tap_ip_enabled);
3626
0
        tap_ip_enabled = false;
3627
0
    }
3628
0
}
3629
3630
/**
3631
 * @brief Sets up the format strings to use for the Info column
3632
 *
3633
 */
3634
static void
3635
f5ethtrailer_prefs(void)
3636
14
{
3637
14
    wmem_free(NULL, info_format_in_only);
3638
14
    wmem_free(NULL, info_format_out_only);
3639
14
    wmem_free(NULL, info_format_in_slot);
3640
14
    wmem_free(NULL, info_format_out_slot);
3641
14
    wmem_free(NULL, info_format_in_noslot);
3642
14
    wmem_free(NULL, info_format_out_noslot);
3643
3644
    /* Set the set of format specifier strings to use based on whether or not one of the
3645
     * brief preferences is chosen */
3646
14
    switch (pref_info_type) {
3647
0
    case brief:
3648
0
    case brief_in_out_only:
3649
0
        if (pref_brief_inout_chars != NULL && strlen(pref_brief_inout_chars) >= 2) {
3650
0
            info_format_in_only  = wmem_strdup_printf(NULL, "%c: ", pref_brief_inout_chars[0]);
3651
0
            info_format_out_only = wmem_strdup_printf(NULL, "%c: ", pref_brief_inout_chars[1]);
3652
0
            info_format_in_slot =
3653
0
                wmem_strdup_printf(NULL, "%c%%u/%%-2u: ", pref_brief_inout_chars[0]);
3654
0
            info_format_out_slot =
3655
0
                wmem_strdup_printf(NULL, "%c%%u/%%-2u: ", pref_brief_inout_chars[1]);
3656
0
            info_format_in_noslot =
3657
0
                wmem_strdup_printf(NULL, "%ct%%-2u: ", pref_brief_inout_chars[0]);
3658
0
            info_format_out_noslot =
3659
0
                wmem_strdup_printf(NULL, "%ct%%-2u: ", pref_brief_inout_chars[1]);
3660
0
        } else {
3661
0
            info_format_in_only    = wmem_strdup(NULL, ">: ");
3662
0
            info_format_out_only   = wmem_strdup(NULL, "<: ");
3663
0
            info_format_in_slot    = wmem_strdup(NULL, ">%u/%-2u: ");
3664
0
            info_format_out_slot   = wmem_strdup(NULL, "<%u/%-2u: ");
3665
0
            info_format_in_noslot  = wmem_strdup(NULL, ">t%-2u: ");
3666
0
            info_format_out_noslot = wmem_strdup(NULL, "<t%-2u: ");
3667
0
        }
3668
0
        break;
3669
14
    default:
3670
14
        info_format_in_only    = wmem_strdup(NULL, info_format_full_in_only);
3671
14
        info_format_out_only   = wmem_strdup(NULL, info_format_full_out_only);
3672
14
        info_format_in_slot    = wmem_strdup(NULL, info_format_full_in_slot);
3673
14
        info_format_out_slot   = wmem_strdup(NULL, info_format_full_out_slot);
3674
14
        info_format_in_noslot  = wmem_strdup(NULL, info_format_full_in_noslot);
3675
14
        info_format_out_noslot = wmem_strdup(NULL, info_format_full_out_noslot);
3676
14
        break;
3677
14
    }
3678
14
}
3679
3680
/**
3681
 * @brief f5ethtrailer Dissector registration
3682
 *
3683
 */
3684
void
3685
proto_register_f5ethtrailer(void)
3686
14
{
3687
14
    module_t *f5ethtrailer_module;
3688
3689
    /* A header field is something you can search/filter on.
3690
     *
3691
     * We create a structure to register our fields. It consists of an
3692
     * array of hf_register_info structures, each of which are of the format
3693
     * {&(field id), {name, abrv, type, display, strs, bitmask, blurb, HFILL}}.
3694
     */
3695
14
    static hf_register_info hf[] = {
3696
14
        { &hf_trailer_hdr,
3697
14
          { "F5 Trailer Header", "f5ethtrailer.header", FT_NONE, BASE_NONE, NULL,
3698
14
            0x0, NULL, HFILL }
3699
14
        },
3700
14
        { &hf_provider,
3701
14
          { "Provider", "f5ethtrailer.provider", FT_UINT16, BASE_DEC, NULL,
3702
14
            0x0, NULL, HFILL }
3703
14
        },
3704
14
        { &hf_type,
3705
14
          { "Type", "f5ethtrailer.type", FT_UINT16, BASE_DEC, NULL,
3706
14
            0x0, NULL, HFILL }
3707
14
        },
3708
14
        { &hf_length,
3709
14
          { "Trailer length", "f5ethtrailer.length", FT_UINT16, BASE_DEC, NULL,
3710
14
            0x0, NULL, HFILL }
3711
14
        },
3712
14
        { &hf_version,
3713
14
          { "Version", "f5ethtrailer.version", FT_UINT16, BASE_DEC, NULL,
3714
14
            0x0, NULL, HFILL }
3715
14
        },
3716
14
        { &hf_dpt_unknown,
3717
14
          { "Unknown trailer", "f5ethtrailer.unknown_trailer", FT_NONE, BASE_NONE, NULL,
3718
14
            0x0, NULL, HFILL }
3719
14
        },
3720
14
        { &hf_data,
3721
14
          { "Data", "f5ethtrailer.data", FT_BYTES, SEP_SPACE, NULL,
3722
14
            0x0, NULL, HFILL }
3723
14
        },
3724
14
        { &hf_data_str,
3725
14
          { "Data", "f5ethtrailer.data.string", FT_STRING, BASE_NONE, NULL,
3726
14
            0x0, NULL, HFILL }
3727
14
        },
3728
14
        { &hf_orig_fcs,
3729
14
          { "Original FCS", "f5ethtrailer.orig_fcs", FT_UINT32, BASE_HEX, NULL,
3730
14
            0x0, NULL, HFILL }
3731
14
        },
3732
3733
    /* Low parameters */
3734
14
        { &hf_low_id,
3735
14
          { "Low Details", "f5ethtrailer.low", FT_NONE, BASE_NONE, NULL,
3736
14
            0x0, NULL, HFILL }
3737
14
        },
3738
14
        { &hf_flags,
3739
14
          { "Flags", "f5ethtrailer.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }
3740
14
        },
3741
14
        { &hf_flags_ingress,
3742
14
          { "Ingress", "f5ethtrailer.flags.ingress", FT_UINT8, BASE_DEC,
3743
14
            VALS(f5_flags_ingress_vs), F5_LOW_FLAGS_INGRESS_MASK, NULL, HFILL }
3744
14
        },
3745
14
        { &hf_flags_hwaction,
3746
14
          { "Hardware Action", "f5ethtrailer.flags.hwaction", FT_UINT8, BASE_DEC,
3747
14
            VALS(f5_flags_hwaction_vs), F5_LOW_FLAGS_HWACTION_MASK, NULL, HFILL }
3748
14
        },
3749
14
        { &hf_ingress,
3750
14
          { "Ingress", "f5ethtrailer.ingress", FT_BOOLEAN, BASE_NONE, NULL,
3751
14
            0x0, NULL, HFILL }
3752
14
        },
3753
14
        { &hf_slot0,
3754
14
          { "Slot (0-based)", "f5ethtrailer.slot", FT_UINT8, BASE_DEC, NULL,
3755
14
            0x0, "Slot captured on", HFILL }
3756
14
        },
3757
14
        { &hf_slot1,
3758
14
          { "Slot (1-based)", "f5ethtrailer.slot", FT_UINT8, BASE_DEC, NULL,
3759
14
            0x0, "Slot captured on", HFILL }
3760
14
        },
3761
14
        { &hf_tmm,
3762
14
          { "TMM (0-based)", "f5ethtrailer.tmm", FT_UINT8, BASE_DEC, NULL,
3763
14
            0x0, "TMM captured on", HFILL }
3764
14
        },
3765
14
        { &hf_obj_name_type,
3766
14
          { "Type", "f5ethtrailer.objnametype", FT_UINT8, BASE_DEC,
3767
14
          VALS(f5_obj_data_types), 0x0, NULL, HFILL }
3768
14
        },
3769
14
        { &hf_obj_data_len,
3770
14
          { "Object Name Data Length", "f5ethtrailer.objnamelen", FT_UINT8, BASE_DEC, NULL,
3771
14
            0x0, NULL, HFILL }
3772
14
        },
3773
14
        { &hf_vipnamelen,
3774
14
          { "Length", "f5ethtrailer.vipnamelen", FT_UINT8, BASE_DEC, NULL,
3775
14
            0x0, NULL, HFILL }
3776
14
        },
3777
14
        { &hf_vip,
3778
14
          { "Name", "f5ethtrailer.vip", FT_STRING, BASE_NONE, NULL,
3779
14
            0x0, "VIP flow associated with", HFILL }
3780
14
        },
3781
14
        { &hf_portnamelen,
3782
14
          { "Length", "f5ethtrailer.portnamelen", FT_UINT8, BASE_DEC, NULL,
3783
14
            0x0, NULL, HFILL }
3784
14
        },
3785
14
        { &hf_phys_port,
3786
14
          { "Name", "f5ethtrailer.phys_port", FT_STRING, BASE_NONE, NULL,
3787
14
            0x0, "Physical port", HFILL }
3788
14
        },
3789
14
        { &hf_trunknamelen,
3790
14
          { "Length", "f5ethtrailer.trunknamelen", FT_UINT8, BASE_DEC, NULL,
3791
14
            0x0, NULL, HFILL }
3792
14
        },
3793
14
        { &hf_trunk,
3794
14
          { "Name", "f5ethtrailer.trunk", FT_STRING, BASE_NONE, NULL,
3795
14
            0x0, "Trunk name", HFILL }
3796
14
        },
3797
3798
    /* Medium parameters */
3799
14
        { &hf_med_id,
3800
14
          { "Medium Details", "f5ethtrailer.medium", FT_NONE, BASE_NONE, NULL,
3801
14
            0x0, NULL, HFILL }
3802
14
        },
3803
14
        { &hf_any_flow,
3804
14
          { "Flow ID or peer flow ID", "f5ethtrailer.anyflowid", FT_UINT64, BASE_HEX, NULL,
3805
14
            0x0, NULL, HFILL }
3806
14
        },
3807
14
        { &hf_flow_id,
3808
14
          { "Flow ID", "f5ethtrailer.flowid", FT_UINT64, BASE_HEX, NULL,
3809
14
            0x0, NULL, HFILL }
3810
14
        },
3811
14
        { &hf_peer_id,
3812
14
          { "Peer ID", "f5ethtrailer.peerid", FT_UINT64, BASE_HEX, NULL,
3813
14
            0x0, NULL, HFILL }
3814
14
        },
3815
14
        { &hf_cf_flags,
3816
14
          { "Connflow Flags", "f5ethtrailer.cfflags", FT_UINT32, BASE_HEX, NULL,
3817
14
            0x0, NULL, HFILL }
3818
14
        },
3819
14
        { &hf_cf_flags2,
3820
14
          { "Connflow Flags High Bits", "f5ethtrailer.cfflags2", FT_UINT32,
3821
14
            BASE_HEX, NULL, 0x0, NULL, HFILL }
3822
14
        },
3823
14
        { &hf_flow_type,
3824
14
          { "Flow Type", "f5ethtrailer.flowtype", FT_UINT8, BASE_HEX, NULL,
3825
14
            0x0, NULL, HFILL }
3826
14
        },
3827
14
        { &hf_ha_unit,
3828
14
          { "HA Unit", "f5ethtrailer.haunit", FT_UINT8, BASE_HEX, NULL,
3829
14
            0x0, NULL, HFILL }
3830
14
        },
3831
14
        { &hf_reserved,
3832
14
          { "Reserved", "f5ethtrailer.reserved", FT_UINT32, BASE_HEX, NULL,
3833
14
            0x0, NULL, HFILL }
3834
14
        },
3835
14
        { &hf_priority,
3836
14
          { "Priority", "f5ethtrailer.priority", FT_UINT8, BASE_DEC, NULL,
3837
14
            0x0, NULL, HFILL }
3838
14
        },
3839
14
        { &hf_rstcause,
3840
14
          { "RST cause", "f5ethtrailer.rstcause", FT_NONE, BASE_NONE, NULL,
3841
14
            0x0, NULL, HFILL }
3842
14
        },
3843
14
        { &hf_rstcause_len,
3844
14
          { "Length", "f5ethtrailer.rstcauselen", FT_UINT8, BASE_DEC,
3845
14
            NULL, 0x0, "RST cause length", HFILL }
3846
14
        },
3847
14
        { &hf_rstcause_ver,
3848
14
          { "Version", "f5ethtrailer.rstcausever", FT_UINT8, BASE_DEC_HEX,
3849
14
            NULL, 0xfe, "RST cause version", HFILL }
3850
14
        },
3851
14
        { &hf_rstcause_peer,
3852
14
          { "Peer", "f5ethtrailer.rstcausepeer", FT_UINT8, BASE_DEC,
3853
14
            NULL, 0x01, "RST cause peer", HFILL }
3854
14
        },
3855
14
        { &hf_rstcause_val,
3856
14
          { "Value", "f5ethtrailer.rstcauseval", FT_UINT64, BASE_HEX,
3857
14
            NULL, 0x0, "RST cause value", HFILL }
3858
14
        },
3859
14
        { &hf_rstcause_line,
3860
14
          { "Line", "f5ethtrailer.rstcauseline", FT_UINT16, BASE_DEC,
3861
14
            NULL, 0x0, "RST cause line", HFILL }
3862
14
        },
3863
14
        { &hf_rstcause_txt,
3864
14
          { "Cause", "f5ethtrailer.rstcausetxt", FT_STRING, BASE_NONE,
3865
14
            NULL, 0x0, "RST cause", HFILL }
3866
14
        },
3867
3868
    /* High parameters */
3869
14
        { &hf_high_id,
3870
14
          { "High Details", "f5ethtrailer.high", FT_NONE, BASE_NONE, NULL,
3871
14
            0x0, NULL, HFILL }
3872
14
        },
3873
14
        { &hf_peer_ipproto,
3874
14
          { "Peer IP Protocol", "f5ethtrailer.peeripproto", FT_UINT8, BASE_DEC,
3875
14
            NULL, 0x0, NULL, HFILL }
3876
14
        },
3877
14
        { &hf_peer_vlan,
3878
14
          { "Peer VLAN", "f5ethtrailer.peervlan", FT_UINT16, BASE_DEC, NULL,
3879
14
            0x0, NULL, HFILL }
3880
14
        },
3881
14
        { &hf_peer_remote_addr,
3882
14
          { "Peer remote address", "f5ethtrailer.peerremoteaddr", FT_IPv4,
3883
14
            BASE_NONE, NULL, 0x0, "Peer remote IPv4 address", HFILL }
3884
14
        },
3885
14
        { &hf_peer_remote_ip6addr,
3886
14
          { "Peer remote address", "f5ethtrailer.peerremoteaddr6", FT_IPv6,
3887
14
            BASE_NONE, NULL, 0x0, "Peer remote IPv6 address", HFILL }
3888
14
        },
3889
14
        { &hf_peer_local_addr,
3890
14
          { "Peer local address", "f5ethtrailer.peerlocaladdr", FT_IPv4,
3891
14
            BASE_NONE, NULL, 0x0, "Peer local IPv4 address", HFILL }
3892
14
        },
3893
14
        { &hf_peer_local_ip6addr,
3894
14
          { "Peer local address", "f5ethtrailer.peerlocaladdr6", FT_IPv6,
3895
14
            BASE_NONE, NULL, 0x0, "Peer local IPv6 address", HFILL }
3896
14
        },
3897
14
        { &hf_peer_ipaddr,
3898
14
          { "Peer remote or local address", "f5ethtrailer.peeraddr", FT_IPv4,
3899
14
            BASE_NONE, NULL, 0x0, "Peer IPv4 address", HFILL }
3900
14
        },
3901
14
        { &hf_peer_ip6addr,
3902
14
          { "Peer remote or local address", "f5ethtrailer.peeraddr6", FT_IPv6,
3903
14
            BASE_NONE, NULL, 0x0, "Peer IPv6 address", HFILL }
3904
14
        },
3905
14
        { &hf_peer_remote_rtdom,
3906
14
          { "Peer remote route domain", "f5ethtrailer.peerremotertdom", FT_UINT16,
3907
14
            BASE_DEC, NULL, 0x0, NULL, HFILL }
3908
14
        },
3909
14
        { &hf_peer_local_rtdom,
3910
14
          { "Peer local route domain", "f5ethtrailer.peerlocalrtdom", FT_UINT16,
3911
14
            BASE_DEC, NULL, 0x0, NULL, HFILL }
3912
14
        },
3913
14
        { &hf_peer_rtdom,
3914
14
          { "Peer remote or local route domain", "f5ethtrailer.peerrtdom", FT_UINT16,
3915
14
            BASE_DEC, NULL, 0x0, NULL, HFILL }
3916
14
        },
3917
14
        { &hf_peer_remote_port,
3918
14
          { "Peer remote port", "f5ethtrailer.peerremoteport", FT_UINT16, BASE_DEC,
3919
14
            NULL, 0x0, NULL, HFILL }
3920
14
        },
3921
14
        { &hf_peer_local_port,
3922
14
          { "Peer local port", "f5ethtrailer.peerlocalport", FT_UINT16, BASE_DEC,
3923
14
            NULL, 0x0, NULL, HFILL }
3924
14
        },
3925
14
        { &hf_peer_port,
3926
14
          { "Peer remote or local port", "f5ethtrailer.peerport", FT_UINT16, BASE_DEC,
3927
14
            NULL, 0x0, NULL, HFILL }
3928
14
        },
3929
14
        { &hf_peer_nopeer,
3930
14
          { "No peer connection information", "f5ethtrailer.nopeer", FT_NONE, BASE_NONE,
3931
14
            NULL, 0x0, NULL, HFILL }
3932
14
        },
3933
3934
    /* Analysis parameters */
3935
14
        { &hf_analysis,
3936
14
          { "Analysis", "f5ethtrailer.analysis", FT_NONE, BASE_NONE, NULL,
3937
14
            0x0, "Analysis of details", HFILL }
3938
14
        },
3939
3940
14
        { &hf_dpt_magic,
3941
14
          { "Magic", "f5ethtrailer.trailer_magic", FT_UINT32, BASE_HEX, NULL,
3942
14
            0x0, NULL, HFILL }
3943
14
        },
3944
14
        { &hf_dpt_ver,
3945
14
          { "Version", "f5ethtrailer.trailer_version", FT_UINT16, BASE_DEC, NULL,
3946
14
            0x0, NULL, HFILL }
3947
14
        },
3948
14
        { &hf_dpt_len,
3949
14
          { "Length", "f5ethtrailer.trailer_length", FT_UINT16, BASE_DEC, NULL,
3950
14
            0x0, NULL, HFILL }
3951
14
        },
3952
3953
    /* TLS provider parameters */
3954
14
        { &hf_f5tls_tls,
3955
14
          { "F5 TLS", "f5ethtrailer.tls.data", FT_NONE, BASE_NONE, NULL,
3956
14
            0x0, NULL, HFILL }
3957
14
        },
3958
14
        { &hf_f5tls_secret_len,
3959
14
          { "Secret Length", "f5ethtrailer.tls.secret_len", FT_UINT8, BASE_DEC, NULL,
3960
14
            0x0, NULL, HFILL }
3961
14
        },
3962
14
        { &hf_f5tls_mstr_sec,
3963
14
          { "Master Secret", "f5ethtrailer.tls.master_secret", FT_BYTES, BASE_NONE, NULL,
3964
14
            0x0, NULL, HFILL }
3965
14
        },
3966
14
        { &hf_f5tls_clnt_rand,
3967
14
          { "Client Random", "f5ethtrailer.tls.client_random", FT_BYTES, BASE_NONE, NULL,
3968
14
            0x0, NULL, HFILL }
3969
14
        },
3970
14
        { &hf_f5tls_srvr_rand,
3971
14
          { "Server Random", "f5ethtrailer.tls.server_random", FT_BYTES, BASE_NONE, NULL,
3972
14
            0x0, NULL, HFILL }
3973
14
        },
3974
14
        { &hf_f5tls_early_traffic_sec,
3975
14
          { "Early Traffic Secret", "f5ethtrailer.tls.early_traffic_secret", FT_BYTES, BASE_NONE, NULL,
3976
14
            0x0, NULL, HFILL }
3977
14
        },
3978
14
        { &hf_f5tls_clnt_hs_sec,
3979
14
          { "Client Handshake Traffic Secret", "f5ethtrailer.tls.client_hs_secret", FT_BYTES, BASE_NONE, NULL,
3980
14
            0x0, NULL, HFILL }
3981
14
        },
3982
14
        { &hf_f5tls_srvr_hs_sec,
3983
14
          { "Server Handshake Traffic Secret", "f5ethtrailer.tls.server_hs_secret", FT_BYTES, BASE_NONE, NULL,
3984
14
            0x0, NULL, HFILL }
3985
14
        },
3986
14
        { &hf_f5tls_clnt_app_sec,
3987
14
          { "Client Application Traffic Secret", "f5ethtrailer.tls.client_app_secret", FT_BYTES, BASE_NONE, NULL,
3988
14
            0x0, NULL, HFILL }
3989
14
        },
3990
14
        { &hf_f5tls_srvr_app_sec,
3991
14
          { "Server Application Traffic Secret", "f5ethtrailer.tls.server_app_secret", FT_BYTES, BASE_NONE, NULL,
3992
14
            0x0, NULL, HFILL }
3993
14
        },
3994
14
        { &hf_f5tls_keylog,
3995
14
          { "Keylog entry", "f5ethtrailer.tls.keylog", FT_STRINGZ, BASE_NONE, NULL,
3996
14
            0x0, NULL, HFILL }
3997
14
        },
3998
14
    };
3999
4000
14
    static int *ett[] = {
4001
14
        &ett_f5ethtrailer,
4002
14
        &ett_f5ethtrailer_unknown,
4003
14
        &ett_f5ethtrailer_low,
4004
14
        &ett_f5ethtrailer_low_flags,
4005
14
        &ett_f5ethtrailer_med,
4006
14
        &ett_f5ethtrailer_high,
4007
14
        &ett_f5ethtrailer_rstcause,
4008
14
        &ett_f5ethtrailer_trailer_hdr,
4009
14
        &ett_f5ethtrailer_obj_names,
4010
14
        &ett_f5tls,
4011
14
        &ett_f5tls_std,
4012
14
        &ett_f5tls_ext,
4013
14
    };
4014
4015
14
    expert_module_t *expert_f5ethtrailer;
4016
14
    static ei_register_info ei[] = {
4017
14
        { &ei_f5eth_flowlost,  { "f5ethtrailer.flowlost", PI_SEQUENCE, PI_WARN,
4018
14
                "Flow lost, incorrect VLAN, loose initiation, tunnel, or SYN cookie use",
4019
14
                EXPFILL } },
4020
14
        { &ei_f5eth_flowreuse, { "f5ethtrailer.flowreuse", PI_SEQUENCE, PI_WARN,
4021
14
                "Flow reuse or SYN retransmit", EXPFILL } },
4022
14
        { &ei_f5eth_badlen, { "f5ethtrailer.badlen", PI_MALFORMED, PI_ERROR,
4023
14
                "Length extends past remaining available bytes", EXPFILL } },
4024
14
        { &ei_f5eth_undecoded, { "f5ethtrailer.undecoded", PI_UNDECODED, PI_NOTE,
4025
14
                "This version of Wireshark does not understand how to decode this value", EXPFILL } },
4026
14
    };
4027
4028
14
    proto_f5ethtrailer = proto_register_protocol("F5 Ethernet Trailer Protocol", "F5 Ethernet trailer", "f5ethtrailer");
4029
4030
14
    expert_f5ethtrailer = expert_register_protocol(proto_f5ethtrailer);
4031
14
    expert_register_field_array(expert_f5ethtrailer, ei, array_length(ei));
4032
4033
14
    proto_register_field_array(proto_f5ethtrailer, hf, array_length(hf));
4034
14
    proto_register_subtree_array(ett, array_length(ett));
4035
4036
    /* Register the dissector preferences */
4037
14
    f5ethtrailer_module = prefs_register_protocol(proto_f5ethtrailer, f5ethtrailer_prefs);
4038
4039
14
    prefs_register_bool_preference(f5ethtrailer_module, "pref_walk_trailer",
4040
14
        "Walk ethernet trailer looking for f5ethtrailer",
4041
14
        "In a few cases a short ethernet frame will be padded with non-zero"
4042
14
        "bytes.  If this happens, an f5ethtrailer will not be found."
4043
14
        "Enabling this will step through each byte of the ethernet trailer"
4044
14
        "to try and find the start of an f5ethtrailer",
4045
14
        &pref_walk_trailer);
4046
4047
14
    prefs_register_bool_preference(f5ethtrailer_module, "pref_pop_other_fields",
4048
14
        "Populate fields for other dissectors",
4049
14
        "Disable this if you do not want this dissector to populate"
4050
14
        " well-known fields in other dissectors (i.e. ip.addr, ipv6.addr,"
4051
14
        " tcp.port and udp.port).  Enabling this will allow filters that"
4052
14
        " reference those fields to also find data in the trailers but"
4053
14
        " will reduce performance.  After disabling, you should restart"
4054
14
        " Wireshark to get performance back.",
4055
14
        &pref_pop_other_fields);
4056
4057
14
    prefs_register_bool_preference(f5ethtrailer_module, "perform_analysis",
4058
14
        "Perform analysis of trailer data",
4059
14
        "Enabling this will perform analysis of the trailer data.  It will"
4060
14
        " enable taps on other protocols and slow down Wireshark.",
4061
14
        &pref_perform_analysis);
4062
4063
14
    prefs_register_static_text_preference(f5ethtrailer_module, "info_col_section",
4064
14
        "Information column preferences",
4065
14
        "The settings below affect how information from this dissector is"
4066
14
        " displayed in the info column in the packet list pane.");
4067
4068
14
    prefs_register_obsolete_preference(f5ethtrailer_module, "summary_in_info");
4069
4070
14
    prefs_register_enum_preference(f5ethtrailer_module, "info_type",
4071
14
        "Summary display in info column",
4072
14
        "In/out only removes slot/tmm information.  Brief shortens the string"
4073
14
        " to >S/T (for in) or <S/T (for out).  See \"Brief in/out characters\""
4074
14
        " below.",
4075
14
        (unsigned *)&pref_info_type, f5eth_display_strings, true);
4076
4077
14
    prefs_register_string_preference(f5ethtrailer_module, "brief_inout_chars",
4078
14
        "Brief in/out characters",
4079
14
        "A string specifying the characters to use to represent \"in\" and"
4080
14
        " \"out\" in the brief summary.  The default is \"><\" ('>' for in"
4081
14
        " and '<' for out).  If this is not set or is less than two"
4082
14
        " characters, the default is used.  If it is longer than two"
4083
14
        " characters, the extra characters are ignored.",
4084
14
        &pref_brief_inout_chars);
4085
4086
14
    prefs_register_string_preference(f5ethtrailer_module, "slots_regex",
4087
14
        "Only display slot information for platforms",
4088
14
        "If the platform in the F5 FILEINFO packet matches the provided regex,"
4089
14
        " slot information will be displayed in the info column; otherwise, it"
4090
14
        " will not.  A reasonable value is \"^(A.*|Z101)$\".  If the regex is"
4091
14
        " empty or there is no platform information in the capture, slot"
4092
14
        " information is always displayed.",
4093
14
        &pref_slots_regex);
4094
4095
14
    prefs_register_bool_preference(f5ethtrailer_module, "rstcause_in_info",
4096
14
        "Add RST cause string to info",
4097
14
        "If present, include the RST cause text from the trailer in the "
4098
14
        "\"info\" column of the packet list pane.",
4099
14
        &rstcause_in_info);
4100
4101
14
    prefs_register_bool_preference(f5ethtrailer_module, "generate_keylog",
4102
14
        "Generate KEYLOG records from TLS f5ethtrailer",
4103
14
        "If enabled, KEYLOG entries will be added to the TLS decode"
4104
14
        " in the f5ethtrailer protocol tree.  It will populate the"
4105
14
        " f5ethtrailer.tls.keylog field.",
4106
14
        &pref_generate_keylog);
4107
4108
14
    register_init_routine(proto_init_f5ethtrailer);
4109
14
    register_cleanup_routine(f5ethtrailer_cleanup);
4110
4111
    /* Register dissector table for additional providers */
4112
14
    provider_subdissector_table = register_dissector_table("f5ethtrailer.provider",
4113
14
            "F5 Ethernet trailer provider", proto_f5ethtrailer, FT_UINT16, BASE_DEC);
4114
14
    proto_f5ethtrailer_dpt_noise =
4115
14
        proto_register_protocol_in_name_only("F5 Ethernet trailer provider - Noise", "Noise",
4116
14
            "f5ethtrailer.provider.noise", proto_f5ethtrailer, FT_BYTES);
4117
14
    noise_subdissector_table = register_dissector_table("f5ethtrailer.noise_type_ver",
4118
14
        "F5 Ethernet Trailer Noise", proto_f5ethtrailer, FT_UINT32, BASE_DEC);
4119
14
    proto_f5ethtrailer_dpt_tls =
4120
14
        proto_register_protocol_in_name_only("F5 Ethernet Trailer Protocol - TLS Provider",
4121
14
            "F5 TLS", "f5ethtrailer.tls", proto_f5ethtrailer, FT_BYTES);
4122
14
    tls_subdissector_table = register_dissector_table("f5ethtrailer.tls_type_ver",
4123
14
        "F5 Ethernet Trailer TLS", proto_f5ethtrailer, FT_UINT32, BASE_DEC);
4124
4125
14
    f5dpt_noise_handle =
4126
14
        register_dissector("f5ethtrailer.noise", dissect_dpt_trailer_noise, proto_f5ethtrailer_dpt_noise);
4127
14
    f5dpt_tls_handle = register_dissector("f5ethtrailer.tls", dissect_dpt_trailer_tls, proto_f5ethtrailer_dpt_tls);
4128
4129
    /* Analyze Menu Items */
4130
14
    register_conversation_filter("f5ethtrailer", "F5 TCP", f5_tcp_conv_valid, f5_tcp_conv_filter, NULL);
4131
14
    register_conversation_filter("f5ethtrailer", "F5 UDP", f5_udp_conv_valid, f5_udp_conv_filter, NULL);
4132
14
    register_conversation_filter("f5ethtrailer", "F5 IP", f5_ip_conv_valid, f5_ip_conv_filter, NULL);
4133
4134
    /* Register the f5ethtrailer tap for statistics */
4135
14
    tap_f5ethtrailer = register_tap("f5ethtrailer");
4136
4137
14
    stats_tree_register_plugin("f5ethtrailer", "f5_tmm_dist", st_str_tmmdist,
4138
14
        (ST_SORT_COL_NAME << ST_FLG_SRTCOL_SHIFT), f5eth_tmmdist_stats_tree_packet,
4139
14
        f5eth_tmmdist_stats_tree_init, NULL);
4140
14
    stats_tree_register_plugin("f5ethtrailer", "f5_virt_dist", st_str_virtdist,
4141
14
        (ST_SORT_COL_NAME << ST_FLG_SRTCOL_SHIFT), f5eth_virtdist_stats_tree_packet,
4142
14
        f5eth_virtdist_stats_tree_init, NULL);
4143
4144
    /* Setup col info strings */
4145
14
    f5ethtrailer_prefs();
4146
14
} /* proto_register_f5ethtrailer() */
4147
4148
/**
4149
 * @brief f5ethtrailer Dissector handoff function
4150
 *
4151
 */
4152
void
4153
proto_reg_handoff_f5ethtrailer(void)
4154
14
{
4155
14
    heur_dissector_add("eth.trailer", dissect_f5ethtrailer_heur, "F5 Ethernet Trailer",
4156
14
            "f5ethtrailer", proto_f5ethtrailer, HEURISTIC_ENABLE);
4157
4158
    /* Register helper dissectors */
4159
    /* Noise Provider */
4160
14
    dissector_add_uint("f5ethtrailer.provider", F5_DPT_PROVIDER_NOISE, f5dpt_noise_handle);
4161
14
    dissector_add_uint("f5ethtrailer.noise_type_ver", F5TYPE_LOW << 16 | 2,
4162
14
        create_dissector_handle(dissect_dpt_trailer_noise_low, proto_f5ethtrailer_dpt_noise));
4163
14
    dissector_add_uint("f5ethtrailer.noise_type_ver", F5TYPE_LOW << 16 | 3,
4164
14
        create_dissector_handle(dissect_dpt_trailer_noise_low, proto_f5ethtrailer_dpt_noise));
4165
14
    dissector_add_uint("f5ethtrailer.noise_type_ver", F5TYPE_LOW << 16 | 4,
4166
14
        create_dissector_handle(dissect_dpt_trailer_noise_low, proto_f5ethtrailer_dpt_noise));
4167
14
    dissector_add_uint("f5ethtrailer.noise_type_ver", F5TYPE_MED << 16 | 4,
4168
14
        create_dissector_handle(dissect_dpt_trailer_noise_med, proto_f5ethtrailer_dpt_noise));
4169
14
    dissector_add_uint("f5ethtrailer.noise_type_ver", F5TYPE_HIGH << 16 | 1,
4170
14
        create_dissector_handle(dissect_dpt_trailer_noise_high, proto_f5ethtrailer_dpt_noise));
4171
    /* TLS provider */
4172
14
    dissector_add_uint("f5ethtrailer.provider", F5_DPT_PROVIDER_TLS, f5dpt_tls_handle);
4173
14
    dissector_add_uint("f5ethtrailer.tls_type_ver", F5_DPT_TLS_PRE13_STD << 16 | 0,
4174
14
        create_dissector_handle(dissect_dpt_trailer_tls_type0, proto_f5ethtrailer_dpt_tls));
4175
14
    dissector_add_uint("f5ethtrailer.tls_type_ver", F5_DPT_TLS_PRE13_EXT << 16 | 0,
4176
14
        create_dissector_handle(dissect_dpt_trailer_tls_extended, proto_f5ethtrailer_dpt_tls));
4177
14
    dissector_add_uint("f5ethtrailer.tls_type_ver", F5_DPT_TLS_13_STD << 16 | 0,
4178
14
        create_dissector_handle(dissect_dpt_trailer_tls_type2, proto_f5ethtrailer_dpt_tls));
4179
14
    dissector_add_uint("f5ethtrailer.tls_type_ver", F5_DPT_TLS_13_STD << 16 | 1,
4180
14
        create_dissector_handle(dissect_dpt_trailer_tls_type2, proto_f5ethtrailer_dpt_tls));
4181
14
    dissector_add_uint("f5ethtrailer.tls_type_ver", F5_DPT_TLS_13_EXT << 16 | 0,
4182
14
        create_dissector_handle(dissect_dpt_trailer_tls_extended, proto_f5ethtrailer_dpt_tls));
4183
4184
    /* These fields are duplicates of other, well-known fields so that
4185
     * filtering on these fields will also pick up data out of the
4186
     * trailers.
4187
     */
4188
4189
14
    hf_ip_ipaddr   = proto_registrar_get_id_byname("ip.addr");
4190
14
    hf_ip6_ip6addr = proto_registrar_get_id_byname("ipv6.addr");
4191
14
    hf_tcp_tcpport = proto_registrar_get_id_byname("tcp.port");
4192
14
    hf_udp_udpport = proto_registrar_get_id_byname("udp.port");
4193
14
}
4194
4195
/*===============================================================================================*/
4196
/* This section is rendering the F5 tcpdump file properties packet.
4197
 *
4198
 * Note that this should technically have a protocol tree item, but it does not.  The data
4199
 * rendered by this dissector should be the only data in the packet.  So, rather than requiring
4200
 * the user to select the packet and expand the tree to view it, putting the items into the top
4201
 * tree essentially renders them expanded.  There is no proto_tree_expand_item() sort of call that
4202
 * can be used to do this in a data-encapsulated manner (it can be hacked, but I opted for this
4203
 * method instead).
4204
 */
4205
4206
/* Platform ID to platform name mapping
4207
 *
4208
 * https://my.f5.com/manage/s/article/K9476
4209
 * https://my.f5.com/manage/s/article/K86001294
4210
 * https://my.f5.com/manage/s/article/K4309
4211
 */
4212
4213
static const string_string f5info_platform_strings[] = {
4214
    /* rSeries */
4215
    {"C128", "F5 r10000 Series (r10600, r10800, r10900)"},
4216
    {"C129", "F5 r5000 Series (r5600, r5800, r5900)"},
4217
    {"C130", "F5 r2000 Series (r2600, r2800)"},
4218
    {"C131", "F5 r4000 Series (r4600, r4800)"},
4219
    {"C136", "F5 r5920-DF"},
4220
    {"C137", "F5 r10920-DF"},
4221
    {"C138", "F5 r12000 Series (r12600-DS, r12800-DS, r12900-DS)"},
4222
4223
    /* VELOS */
4224
    {"F101", "VELOS CX410 Chassis"},
4225
    {"R100", "VELOS CX1610 Chassis"},
4226
4227
    /* iSeries */
4228
    {"C115", "BIG-IP i4000 Series (i4600, i4800)"},
4229
    {"C116", "BIG-IP i10000 Series (i10600, i10800)"},
4230
    {"C117", "BIG-IP i2000 Series (i2600, i2800), BIG-IP i850)"},
4231
    {"C118", "BIG-IP i7000 Series (i7600, i7800)"},
4232
    {"C119", "BIG-IP i5000 Series (i5600, i5800)"},
4233
    {"C123", "BIG-IP i11600, i11800"},
4234
    {"C124", "BIG-IP i11400-DS, i11600-DS, i11800-DS"},
4235
    {"C125", "BIG-IP i5820-DF"},
4236
    {"C126", "BIG-IP i7820-DF"},
4237
    {"D116", "BIG-IP i15000 Series (i15600, i15800)"},
4238
    {"D120", "BIG-IP i15820-DF"},
4239
4240
    /* Standard series */
4241
    {"C102", "BIG-IP 1600"},
4242
    {"C103", "BIG-IP 3600"},
4243
    {"C106", "BIG-IP 3900, Enterprise Manager 4000"},
4244
    {"C109", "BIG-IP 5000s, 5050s, 5200v, 5250v, 5250v-F"},
4245
    {"C112", "BIG-IP 2000 Series (2000s, 2200s)"},
4246
    {"C113", "BIG-IP 4000 Series (4000s, 4200v)"},
4247
    {"C114", "BIG-IP 800 (LTM only)"},
4248
    {"D104", "BIG-IP 6900 Series (6900, 6900S, 6900F, 6900N)"},
4249
    {"D106", "BIG-IP 8900"},
4250
    {"D107", "BIG-IP 8950"},
4251
    {"D110", "BIG-IP 7000 Series (7000s, 7050s, 7055s, 7200v, 7250v, 7255v), BIG-IQ 7000"},
4252
    {"D111", "BIG-IP 12000 Series (12250v)"},
4253
    {"D112", "BIG-IP 10050 Series (10150s-NEBS, 10350v (AC), 10350v-NEBS, 10350v-FIPS)"},
4254
    {"D113", "BIG-IP 10000 Series (10000s, 10050s, 10055, 10200v, 10250v, 10255)"},
4255
    {"E101", "BIG-IP 11000, BIG-IP 11000 FIPS"},
4256
    {"E102", "BIG-IP 11050, 11050 NEBS"},
4257
    {"E103", "BIG-IP 11050N"},
4258
4259
    /* VIPRION */
4260
    {"A100", "VIPRION B4100 Blade"},
4261
    {"A105", "VIPRION B4100N Blade"},
4262
    {"A107", "VIPRION B4200 Blade"},
4263
    {"A108", "VIPRION B4300 Blade"},
4264
    {"A109", "VIPRION B2100 Blade"},
4265
    {"A110", "VIPRION B4340N Blade"},
4266
    {"A111", "VIPRION B4200N Blade"},
4267
    {"A112", "VIPRION B2250 Blade"},
4268
    {"A113", "VIPRION B2150 Blade"},
4269
    {"A114", "VIPRION B4450 Blade"},
4270
4271
    /* Herculon */
4272
    {"C120", "Herculon i2800"},
4273
    {"C121", "Herculon i5800"},
4274
    {"C122", "Herculon i10800"},
4275
4276
    /* Virtualized platforms*/
4277
    {"Z100", "BIG-IP Virtual Edition (VE)"},
4278
    {"Z101", "BIG-IP vCMP Guest"},
4279
    {NULL, NULL}
4280
};
4281
    /* It currently looks like these do not apply. Kept for completeness only */
4282
#if 0
4283
    {"A118", "VELOS BX110 Blade"},
4284
    {"A119", "VELOS BX520 Blade"},
4285
    {"C21",  "FirePass 1200"},
4286
    {"D46",  "FirePass 4100"},
4287
    {"D63",  "BIG-IP 6400-NEBS"},
4288
    {"D101", "FirePass 4300"},
4289
    {"D114", "VIPRION C2200 Chassis"},
4290
    {"F100", "VIPRION C2400 Chassis"},
4291
    {"J100", "VIPRION C4400 Chassis"},
4292
    {"J101", "VIPRION C4400N Chassis"},
4293
    {"J102", "VIPRION C4480 Chassis"},
4294
    {"J103", "VIPRION C4480N Chassis"},
4295
    {"S100", "VIPRION C4800 Chassis"},
4296
    {"S101", "VIPRION C4800N Chassis"},
4297
#endif
4298
4299
/**
4300
 * @brief Dissector for rendering the F5 tcpdump file properties packet.
4301
 *
4302
 * This is a heuristic dissector because the Ethernet dissector has a hook
4303
 * to pass packets to a dissector before it gets rendered as Ethernet and
4304
 * that seems to make sense here.  This could be a registered dissector on
4305
 * the Ethertype 0x5ff, but this way it can skip a packet and let other
4306
 * dissectors have a chance to dissect (and the Ethernet dissector does not
4307
 * waste its time rendering Ethernet information for no reason).
4308
 *
4309
 * TODO:  This should return int with how many bytes were consumed.
4310
 *
4311
 * @param tvb   Pointer to tvb
4312
 * @param pinfo Pointer to packet info
4313
 * @param tree  Pointer to protocol tree
4314
 * @param data  Pointer to data structure (unused)
4315
 * @return bool
4316
 */
4317
static bool
4318
dissect_f5fileinfo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
4319
25.8k
{
4320
25.8k
    unsigned offset = 0;
4321
25.8k
    const uint8_t *object;
4322
25.8k
    const char *platform = NULL;
4323
25.8k
    const char *platform_name = NULL;
4324
25.8k
    int objlen;
4325
25.8k
    struct f5fileinfo_tap_data *tap_data;
4326
4327
    /* Must be the first packet */
4328
25.8k
    if (pinfo->fd->num > 1)
4329
25.8k
        return false;
4330
4331
0
    if (tvb_captured_length(tvb) >= (int)sizeof(fileinfomagic1)) {
4332
0
        if (tvb_memeql(tvb, 0, fileinfomagic1, sizeof(fileinfomagic1)) == 0)
4333
0
            offset = sizeof(fileinfomagic1);
4334
0
    }
4335
4336
    /* Didn't find the magic at the start of the packet. */
4337
0
    if (offset == 0)
4338
0
        return false;
4339
4340
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "FILEINFO");
4341
4342
0
    tap_data        = wmem_new0(pinfo->pool, struct f5fileinfo_tap_data);
4343
0
    tap_data->magic = F5FILEINFO_TAP_MAGIC;
4344
4345
0
    while (tvb_captured_length_remaining(tvb, offset)) {
4346
0
        object = tvb_get_stringz_enc(pinfo->pool, tvb, offset, &objlen, ENC_ASCII);
4347
4348
0
        if (objlen <= 0 || object == NULL)
4349
0
            break;
4350
4351
0
        if (strncmp(object, "CMD: ", 5) == 0) {
4352
0
            proto_tree_add_string(tree, hf_fi_command, tvb, offset + 5, objlen - 5, &object[5]);
4353
0
            col_add_str(pinfo->cinfo, COL_INFO, &object[5]);
4354
0
        } else if (strncmp(object, "VER: ", 5) == 0) {
4355
0
            unsigned i;
4356
0
            const uint8_t *c;
4357
4358
0
            proto_tree_add_string(tree, hf_fi_version, tvb, offset + 5, objlen - 5, &object[5]);
4359
0
            for (c = object; *c && (*c < '0' || *c > '9'); c++);
4360
0
            for (i = 0; i < 6 && *c; c++) {
4361
0
                if (*c < '0' || *c > '9') {
4362
0
                    i++;
4363
0
                    continue;
4364
0
                }
4365
0
                tap_data->ver[i] = (tap_data->ver[i] * 10) + (*c - '0');
4366
0
            }
4367
0
        } else if (strncmp(object, "HOST: ", 6) == 0)
4368
0
            proto_tree_add_string(tree, hf_fi_hostname, tvb, offset + 6, objlen - 6, &object[6]);
4369
0
        else if (strncmp(object, "PLAT: ", 6) == 0) {
4370
0
            proto_tree_add_string(tree, hf_fi_platform, tvb, offset + 6, objlen - 6, &object[6]);
4371
0
            platform = &object[6];
4372
0
            platform_name = str_to_str_wmem(pinfo->pool, platform, f5info_platform_strings, "Unknown, please report");
4373
0
            proto_tree_add_string_format(tree, hf_fi_platformname, tvb, offset + 6, objlen - 6, platform_name,
4374
0
                "%s: %s", platform, platform_name);
4375
0
        } else if (strncmp(object, "PROD: ", 6) == 0)
4376
0
            proto_tree_add_string(tree, hf_fi_product, tvb, offset + 6, objlen - 6, &object[6]);
4377
0
        else if (strncmp(object, "SESS: ", 6) == 0)
4378
0
            proto_tree_add_string(tree, hf_fi_session, tvb, offset + 6, objlen - 6, &object[6]);
4379
4380
0
        offset += objlen;
4381
0
    }
4382
0
    tvb_set_reported_length(tvb, offset);
4383
0
    tap_queue_packet(tap_f5fileinfo, pinfo, tap_data);
4384
0
    f5eth_process_f5info(platform);
4385
0
    return true;
4386
0
} /* dissect_f5fileinfo() */
4387
4388
/**
4389
 * @brief F5FILEINFO protocol dissector registration
4390
 *
4391
 */
4392
void
4393
proto_register_f5fileinfo(void)
4394
14
{
4395
14
    static hf_register_info hf[] =
4396
14
        { { &hf_fi_command,
4397
14
            { "Tcpdump command line", "f5fileinfo.cmdline", FT_STRINGZ, BASE_NONE,
4398
14
              NULL, 0x0, NULL, HFILL }
4399
14
          },
4400
14
          { &hf_fi_version,
4401
14
            { "Platform version", "f5fileinfo.version", FT_STRINGZ, BASE_NONE,
4402
14
              NULL, 0x0, NULL, HFILL }
4403
14
          },
4404
14
          { &hf_fi_hostname,
4405
14
            { "Hostname", "f5fileinfo.hostname", FT_STRINGZ, BASE_NONE,
4406
14
              NULL, 0x0, NULL, HFILL }
4407
14
          },
4408
14
          { &hf_fi_platform,
4409
14
            { "Platform", "f5fileinfo.platform", FT_STRINGZ, BASE_NONE,
4410
14
              NULL, 0x0, NULL, HFILL }
4411
14
          },
4412
14
          { &hf_fi_platformname,
4413
14
            { "Platform name", "f5fileinfo.platformname", FT_STRINGZ, BASE_NONE,
4414
14
              NULL, 0x0, NULL, HFILL }
4415
14
          },
4416
14
          { &hf_fi_product,
4417
14
            { "Platform product", "f5fileinfo.product", FT_STRINGZ, BASE_NONE,
4418
14
              NULL, 0x0, NULL, HFILL }
4419
14
          },
4420
14
          { &hf_fi_session,
4421
14
            { "Session", "f5fileinfo.session", FT_STRINGZ, BASE_NONE,
4422
14
              NULL, 0x0, NULL, HFILL }
4423
14
          },
4424
14
    };
4425
4426
14
    proto_f5fileinfo = proto_register_protocol("F5 Capture Information", "FILEINFO", "f5fileinfo");
4427
14
    proto_register_field_array(proto_f5fileinfo, hf, array_length(hf));
4428
4429
14
    tap_f5fileinfo = register_tap("f5fileinfo");
4430
14
}
4431
4432
/**
4433
 * @brief F5FILEINFO dissector handoff
4434
 *
4435
 */
4436
void
4437
proto_reg_handoff_f5fileinfo(void)
4438
14
{
4439
14
    heur_dissector_add("eth", dissect_f5fileinfo, "F5 Capture Information", "f5fileinfo",
4440
14
        proto_f5fileinfo, HEURISTIC_ENABLE);
4441
14
}
4442
4443
/*
4444
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
4445
 *
4446
 * Local variables:
4447
 * c-basic-offset: 4
4448
 * tab-width: 8
4449
 * indent-tabs-mode: nil
4450
 * End:
4451
 *
4452
 * vi: set shiftwidth=4 tabstop=8 expandtab:
4453
 * :indentSize=4:tabSize=8:noTabs=true:
4454
 */