Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-f5ethtrailer.c
blobb34ef8480fd74cf021f08a0ae89a598879a658f3
1 /* packet-f5ethtrailer.c
3 * F5 Ethernet Trailer Copyright 2008-2018 F5 Networks
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
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
14 Usage:
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.
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.
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".
32 Notes:
34 Follow F5 Conversation:
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.
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.
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.
51 Populate Fields for Other Dissectors:
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.
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.
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.
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.
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 )
107 Since the preference is disabled by default, it should not cause any
108 interference unless the user actively enables the preference.
110 Analysis:
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.
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).
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).
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.
155 Hiding Slot Information in Info Column:
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).
167 Statistics reports:
169 All statistics are reported as packet counts and byte counts. Byte count
170 statistics do not include the bytes of the trailer.
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.
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.
187 #include "config.h"
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>
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>
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;
218 void proto_reg_handoff_f5ethtrailer(void);
219 void proto_register_f5ethtrailer(void);
221 void proto_reg_handoff_f5fileinfo(void);
222 void proto_register_f5fileinfo(void);
224 static dissector_handle_t f5dpt_noise_handle;
225 static dissector_handle_t f5dpt_tls_handle;
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;
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;
301 static int hf_dpt_magic;
302 static int hf_dpt_ver;
303 static int hf_dpt_len;
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;
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;
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;
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;
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"};
352 static const value_string f5_flags_ingress_vs[] = {
353 {0, "Out"},
354 {1, "In"},
355 {0, NULL}
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}
367 static int * const hf_flags__fields[] = {
368 &hf_flags_ingress,
369 &hf_flags_hwaction,
370 NULL,
373 typedef enum {
374 NONE,
375 NEW_FORMAT,
376 OLD_FORMAT,
377 } found_t;
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;
384 /*-----------------------------------------------------------------------------------------------*/
386 * @brief Convert a Wireshark port type to a IP protocol number.
388 * @attention Not all port types are supported, only the ones that this dissector actively uses.
390 * @param ptype The Wireshark port_type
391 * @return The IP protocol number corresponding to the port type.
393 inline static uint8_t
394 ptype_to_ipproto(const port_type ptype)
396 uint8_t ipproto = 0;
397 switch (ptype) {
398 case PT_TCP:
399 ipproto = IP_PROTO_TCP;
400 break;
401 case PT_UDP:
402 ipproto = IP_PROTO_UDP;
403 break;
404 default:
405 ipproto = 0;
406 break;
408 return ipproto;
409 } /* ptype_to_ipproto() */
411 /*===============================================================================================*/
412 /* Analyze menu functions */
414 /*-----------------------------------------------------------------------------------------------*/
416 * @brief Determines if we can apply an IP Conversation filter.
418 * @attention This is an interface function to be called from the rest of wireshark.
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
423 static bool
424 f5_ip_conv_valid(packet_info *pinfo, void *user_data _U_)
426 bool is_ip = false;
427 bool is_f5ethtrailer = false;
429 proto_get_frame_protocols(pinfo->layers, &is_ip, NULL, NULL, NULL, NULL, NULL, NULL);
430 is_f5ethtrailer = proto_is_frame_protocol(pinfo->layers, "f5ethtrailer");
432 return is_ip && is_f5ethtrailer;
433 } /* f5_ip_conv_valid() */
435 /*-----------------------------------------------------------------------------------------------*/
437 * @brief Determines if we can apply a TCP Conversation filter.
439 * @attention This is an interface function to be called from the rest of wireshark.
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
444 static bool
445 f5_tcp_conv_valid(packet_info *pinfo, void *user_data _U_)
447 bool is_ip = false;
448 bool is_tcp = false;
449 bool is_f5ethtrailer = false;
451 proto_get_frame_protocols(pinfo->layers, &is_ip, &is_tcp, NULL, NULL, NULL, NULL, NULL);
452 is_f5ethtrailer = proto_is_frame_protocol(pinfo->layers, "f5ethtrailer");
454 return is_ip && is_tcp && is_f5ethtrailer;
455 } /* f5_tcp_conv_valid() */
457 /*-----------------------------------------------------------------------------------------------*/
459 * @brief Determines if we can apply a UDP Conversation filter.
461 * @attention This is an interface function to be called from the rest of wireshark.
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
466 static bool
467 f5_udp_conv_valid(packet_info *pinfo, void *user_data _U_)
469 bool is_ip = false;
470 bool is_udp = false;
471 bool is_f5ethtrailer = false;
473 proto_get_frame_protocols(pinfo->layers, &is_ip, NULL, &is_udp, NULL, NULL, NULL, NULL);
474 is_f5ethtrailer = proto_is_frame_protocol(pinfo->layers, "f5ethtrailer");
476 return is_ip && is_udp && is_f5ethtrailer;
477 } /* f5_tcp_conv_valid() */
479 /*-----------------------------------------------------------------------------------------------*/
481 * @brief Calculates the F5 IP conversation filter based on the current packet.
483 * @attention This is an interface function to be called from the rest of wireshark.
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().
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).
493 static char *
494 f5_ip_conv_filter(packet_info *pinfo, void *user_data _U_)
496 char *buf = NULL;
497 char src_addr[WS_INET6_ADDRSTRLEN];
498 char dst_addr[WS_INET6_ADDRSTRLEN];
500 *dst_addr = *src_addr = '\0';
501 if (pinfo->net_src.type == AT_IPv4 && pinfo->net_dst.type == AT_IPv4) {
502 address_to_str_buf(&pinfo->src, src_addr, WS_INET6_ADDRSTRLEN);
503 address_to_str_buf(&pinfo->dst, dst_addr, WS_INET6_ADDRSTRLEN);
504 if (*src_addr != '\0' && *dst_addr != '\0') {
505 buf = ws_strdup_printf(
506 "(ip.addr eq %s and ip.addr eq %s) or"
507 " (f5ethtrailer.peeraddr eq %s and f5ethtrailer.peeraddr eq %s)",
508 src_addr, dst_addr, src_addr, dst_addr);
510 } else if (pinfo->net_src.type == AT_IPv6 && pinfo->net_dst.type == AT_IPv6) {
511 address_to_str_buf(&pinfo->src, src_addr, WS_INET6_ADDRSTRLEN);
512 address_to_str_buf(&pinfo->dst, dst_addr, WS_INET6_ADDRSTRLEN);
513 if (*src_addr != '\0' && *dst_addr != '\0') {
514 buf = ws_strdup_printf(
515 "(ipv6.addr eq %s and ipv6.addr eq %s) or"
516 " (f5ethtrailer.peeraddr6 eq %s and f5ethtrailer.peeraddr6 eq %s)",
517 src_addr, dst_addr, src_addr, dst_addr);
520 return buf;
521 } /* f5_ip_conv_filter() */
523 /*-----------------------------------------------------------------------------------------------*/
525 * @brief Calculates the F5 TCP conversation filter based on the current packet.
527 * @attention This is an interface function to be called from the rest of wireshark.
529 * @param pinfo A pointer to the packet info to look at for the L3/L4 data.
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().
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".
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).
548 static char *
549 f5_tcp_conv_filter(packet_info *pinfo, void *user_data _U_)
551 char *buf = NULL;
552 char src_addr[WS_INET6_ADDRSTRLEN];
553 char dst_addr[WS_INET6_ADDRSTRLEN];
555 *dst_addr = *src_addr = '\0';
556 if (pinfo->net_src.type == AT_IPv4 && pinfo->net_dst.type == AT_IPv4) {
557 address_to_str_buf(&pinfo->src, src_addr, WS_INET6_ADDRSTRLEN);
558 address_to_str_buf(&pinfo->dst, dst_addr, WS_INET6_ADDRSTRLEN);
559 if (*src_addr != '\0' && *dst_addr != '\0') {
560 buf = ws_strdup_printf(
561 "(ip.addr eq %s and ip.addr eq %s and tcp.port eq %d and tcp.port eq %d) or"
562 " (f5ethtrailer.peeraddr eq %s and f5ethtrailer.peeraddr eq %s and"
563 " f5ethtrailer.peerport eq %d and f5ethtrailer.peerport eq %d and"
564 " (f5ethtrailer.peeripproto eq 6 or (f5ethtrailer.peeripproto eq 0 and tcp)))",
565 src_addr, dst_addr, pinfo->srcport, pinfo->destport,
566 src_addr, dst_addr, pinfo->srcport, pinfo->destport);
568 } else if (pinfo->net_src.type == AT_IPv6 && pinfo->net_dst.type == AT_IPv6) {
569 address_to_str_buf(&pinfo->src, src_addr, WS_INET6_ADDRSTRLEN);
570 address_to_str_buf(&pinfo->dst, dst_addr, WS_INET6_ADDRSTRLEN);
571 if (*src_addr != '\0' && *dst_addr != '\0') {
572 buf = ws_strdup_printf(
573 "(ipv6.addr eq %s and ipv6.addr eq %s and tcp.port eq %d and tcp.port eq %d) or"
574 " (f5ethtrailer.peeraddr6 eq %s and f5ethtrailer.peeraddr6 eq %s and"
575 " f5ethtrailer.peerport eq %d and f5ethtrailer.peerport eq %d and"
576 " (f5ethtrailer.peeripproto eq 6 or (f5ethtrailer.peeripproto eq 0 and tcp)))",
577 src_addr, dst_addr, pinfo->srcport, pinfo->destport,
578 src_addr, dst_addr, pinfo->srcport, pinfo->destport);
581 return buf;
582 } /* f5_tcp_conv_filter() */
584 /*-----------------------------------------------------------------------------------------------*/
586 * @brief Calculates the F5 UDP conversation filter based on the current packet.
588 * @attention This is an interface function to be called from the rest of wireshark.
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().
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".
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).
608 static char *
609 f5_udp_conv_filter(packet_info *pinfo, void *user_data _U_)
611 char *buf = NULL;
612 char src_addr[WS_INET6_ADDRSTRLEN];
613 char dst_addr[WS_INET6_ADDRSTRLEN];
615 *dst_addr = *src_addr = '\0';
616 if (pinfo->net_src.type == AT_IPv4 && pinfo->net_dst.type == AT_IPv4) {
617 address_to_str_buf(&pinfo->src, src_addr, WS_INET6_ADDRSTRLEN);
618 address_to_str_buf(&pinfo->dst, dst_addr, WS_INET6_ADDRSTRLEN);
619 if (*src_addr != '\0' && *dst_addr != '\0') {
620 buf = ws_strdup_printf(
621 "(ip.addr eq %s and ip.addr eq %s and udp.port eq %d and udp.port eq %d) or"
622 " (f5ethtrailer.peeraddr eq %s and f5ethtrailer.peeraddr eq %s and"
623 " f5ethtrailer.peerport eq %d and f5ethtrailer.peerport eq %d and"
624 " (f5ethtrailer.peeripproto eq 17 or (f5ethtrailer.peeripproto eq 0 and udp)))",
625 src_addr, dst_addr, pinfo->srcport, pinfo->destport,
626 src_addr, dst_addr, pinfo->srcport, pinfo->destport);
628 } else if (pinfo->net_src.type == AT_IPv6 && pinfo->net_dst.type == AT_IPv6) {
629 address_to_str_buf(&pinfo->src, src_addr, WS_INET6_ADDRSTRLEN);
630 address_to_str_buf(&pinfo->dst, dst_addr, WS_INET6_ADDRSTRLEN);
631 if (*src_addr != '\0' && *dst_addr != '\0') {
632 buf = ws_strdup_printf(
633 "(ipv6.addr eq %s and ipv6.addr eq %s and udp.port eq %d and udp.port eq %d) or"
634 " (f5ethtrailer.peeraddr6 eq %s and f5ethtrailer.peeraddr6 eq %s and"
635 " f5ethtrailer.peerport eq %d and f5ethtrailer.peerport eq %d and"
636 " (f5ethtrailer.peeripproto eq 17 or (f5ethtrailer.peeripproto eq 0 and udp)))",
637 src_addr, dst_addr, pinfo->srcport, pinfo->destport,
638 src_addr, dst_addr, pinfo->srcport, pinfo->destport);
641 return buf;
642 } /* f5_udp_conv_filter() */
644 /* End of Analyze menu functions */
645 /*===============================================================================================*/
647 /*===============================================================================================*/
648 /* Stats tree functions */
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";
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";
669 /*-----------------------------------------------------------------------------------------------*/
671 * @brief Initializer for tmm distribution statistics
673 * @attention This is an interface function to be called from the rest of wireshark.
675 * @param st A pointer to the stats tree to use
678 static void
679 f5eth_tmmdist_stats_tree_init(stats_tree *st)
681 st_node_tmmpktdist = stats_tree_create_node(st, st_str_tmmdist_pkts, 0, STAT_DT_INT, true);
682 stat_node_set_flags(st, st_str_tmmdist_pkts, 0, true, ST_FLG_SORT_TOP);
683 st_node_tmmbytedist = stats_tree_create_node(st, st_str_tmmdist_bytes, 0, STAT_DT_INT, true);
684 } /* f5eth_tmmdist_stats_tree_init() */
686 #define PER_TMM_STAT_NAME_BUF_LEN (sizeof("slot SSS,tmm TTT"))
688 /*-----------------------------------------------------------------------------------------------*/
690 * @brief Per-packet tmm distribution statistics
692 * @attention This is an interface function to be called from the rest of wireshark.
694 * @param st A pointer to the stats tree to use
695 * @param pinfo A pointer to the packet info.
696 * @param edt Unused
697 * @param data A pointer to the data provided by the tap
698 * @return TAP_PACKET_REDRAW if the data was actually used to alter
699 * the statistics, TAP_PACKET_DONT_REDRAW otherwise.
702 static tap_packet_status
703 f5eth_tmmdist_stats_tree_packet(
704 stats_tree *st, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data, tap_flags_t flags _U_)
706 const f5eth_tap_data_t *tdata = (const f5eth_tap_data_t *)data;
707 uint32_t pkt_len;
708 int st_node_tot_pkts;
709 int st_node_tot_bytes;
710 int st_node_tmm_pkts;
711 int st_node_tmm_bytes;
712 char tmm_stat_name_buffer[PER_TMM_STAT_NAME_BUF_LEN];
714 if (tdata == NULL)
715 return TAP_PACKET_DONT_REDRAW;
717 /* Unnecessary since this tap packet function and the F5 Ethernet trailer dissector are both in
718 * the same source file. If you are using this function as an example in a separate tap source
719 * file, you should uncomment this.
720 if(check_f5eth_tap_magic(tdata) == 0) return TAP_PACKET_DONT_REDRAW;
723 snprintf(tmm_stat_name_buffer, PER_TMM_STAT_NAME_BUF_LEN, "slot %3d,tmm %3d", tdata->slot,
724 tdata->tmm);
726 pkt_len = pinfo->fd->pkt_len - tdata->trailer_len;
728 st_node_tot_pkts = tick_stat_node(st, st_str_tmmdist_pkts, 0, true);
729 st_node_tot_bytes = increase_stat_node(st, st_str_tmmdist_bytes, 0, true, pkt_len);
731 st_node_tmm_pkts = tick_stat_node(st, tmm_stat_name_buffer, st_node_tot_pkts, true);
732 st_node_tmm_bytes =
733 increase_stat_node(st, tmm_stat_name_buffer, st_node_tot_bytes, true, pkt_len);
734 if (tdata->ingress == 1) {
735 tick_stat_node(st, st_str_tmm_dir_in, st_node_tmm_pkts, false);
736 increase_stat_node(st, st_str_tmm_dir_in, st_node_tmm_bytes, false, pkt_len);
737 /* Create nodes in case we see no egress packets */
738 increase_stat_node(st, st_str_tmm_dir_out, st_node_tmm_pkts, false, 0);
739 increase_stat_node(st, st_str_tmm_dir_out, st_node_tmm_bytes, false, 0);
740 } else {
741 tick_stat_node(st, st_str_tmm_dir_out, st_node_tmm_pkts, false);
742 increase_stat_node(st, st_str_tmm_dir_out, st_node_tmm_bytes, false, pkt_len);
743 /* Create nodes in case we see no ingress packets */
744 increase_stat_node(st, st_str_tmm_dir_in, st_node_tmm_pkts, false, 0);
745 increase_stat_node(st, st_str_tmm_dir_in, st_node_tmm_bytes, false, 0);
748 if (tdata->virtual_name == NULL) {
749 if (tdata->flow == 0) {
750 /* No flow ID and no virtual name */
751 tick_stat_node(st, st_str_tmm_flow_none, st_node_tmm_pkts, false);
752 increase_stat_node(st, st_str_tmm_flow_none, st_node_tmm_bytes, false, pkt_len);
754 /* Create nodes in case we see no packets without a virtual */
755 increase_stat_node(st, st_str_tmm_flow_novirt, st_node_tmm_pkts, false, 0);
756 increase_stat_node(st, st_str_tmm_flow_novirt, st_node_tmm_bytes, false, 0);
757 } else {
758 /* Flow ID and no virtual name */
759 tick_stat_node(st, st_str_tmm_flow_novirt, st_node_tmm_pkts, false);
760 increase_stat_node(st, st_str_tmm_flow_novirt, st_node_tmm_bytes, false, pkt_len);
762 /* Create nodes in case we see no packets with a virtual */
763 increase_stat_node(st, st_str_tmm_flow_none, st_node_tmm_pkts, false, 0);
764 increase_stat_node(st, st_str_tmm_flow_none, st_node_tmm_bytes, false, 0);
766 /* Create nodes in case we see no packets with a virtual */
767 increase_stat_node(st, st_str_tmm_flow_virt, st_node_tmm_pkts, false, 0);
768 increase_stat_node(st, st_str_tmm_flow_virt, st_node_tmm_bytes, false, 0);
769 } else {
770 /* Has a virtual name */
771 tick_stat_node(st, st_str_tmm_flow_virt, st_node_tmm_pkts, false);
772 increase_stat_node(st, st_str_tmm_flow_virt, st_node_tmm_bytes, false, pkt_len);
774 /* Create nodes in case we see no packets without a virtual */
775 increase_stat_node(st, st_str_tmm_flow_novirt, st_node_tmm_pkts, false, 0);
776 increase_stat_node(st, st_str_tmm_flow_novirt, st_node_tmm_bytes, false, 0);
777 /* Create nodes in case we see no packets without a flow */
778 increase_stat_node(st, st_str_tmm_flow_none, st_node_tmm_pkts, false, 0);
779 increase_stat_node(st, st_str_tmm_flow_none, st_node_tmm_bytes, false, 0);
782 return TAP_PACKET_REDRAW;
783 } /* f5eth_tmmdist_stats_tree_packet() */
785 /*-----------------------------------------------------------------------------------------------*/
787 * @brief Initialize Virtual Server stats tree
789 * @param st A pointer to the stats tree to use
791 static void
792 f5eth_virtdist_stats_tree_init(stats_tree *st)
794 st_node_virtpktdist = stats_tree_create_node(st, st_str_virtdist_pkts, 0, STAT_DT_INT, true);
795 stat_node_set_flags(st, st_str_virtdist_pkts, 0, true, ST_FLG_SORT_TOP);
796 st_node_virtbytedist = stats_tree_create_node(st, st_str_virtdist_bytes, 0, STAT_DT_INT, true);
798 stats_tree_create_node(st, st_str_virtdist_noflow, st_node_virtpktdist, STAT_DT_INT, true);
799 stat_node_set_flags(st, st_str_virtdist_noflow, st_node_virtpktdist, true, ST_FLG_SORT_TOP);
800 stats_tree_create_node(st, st_str_virtdist_novirt, st_node_virtpktdist, STAT_DT_INT, true);
801 stat_node_set_flags(st, st_str_virtdist_novirt, st_node_virtpktdist, true, ST_FLG_SORT_TOP);
803 stats_tree_create_node(st, st_str_virtdist_noflow, st_node_virtbytedist, STAT_DT_INT, true);
804 stat_node_set_flags(st, st_str_virtdist_noflow, st_node_virtbytedist, true, ST_FLG_SORT_TOP);
805 stats_tree_create_node(st, st_str_virtdist_novirt, st_node_virtbytedist, STAT_DT_INT, true);
806 stat_node_set_flags(st, st_str_virtdist_novirt, st_node_virtbytedist, true, ST_FLG_SORT_TOP);
807 } /* f5eth_virtdist_stats_tree_init() */
809 /*-----------------------------------------------------------------------------------------------*/
811 * @brief Per-packet Virtual Server distribution statistics
813 * @param st A pointer to the stats tree to use
814 * @param pinfo A pointer to the packet info.
815 * @param edt Unused
816 * @param data A pointer to the data provided by the tap
817 * @return TAP_PACKET_REDRAW if the data was actually used to alter
818 * the statistics, TAP_PACKET_DONT_REDRAW otherwise.
820 static tap_packet_status
821 f5eth_virtdist_stats_tree_packet(
822 stats_tree *st, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data, tap_flags_t flags _U_)
824 const f5eth_tap_data_t *tdata = (const f5eth_tap_data_t *)data;
825 uint32_t pkt_len;
827 if (tdata == NULL)
828 return TAP_PACKET_DONT_REDRAW;
829 /* Unnecessary since this tap packet function and the F5 Ethernet trailer dissector are both in
830 * the same source file. If you are using this function as an example in a separate tap source
831 * file, you should uncomment this.
832 if(check_f5eth_tap_magic(tdata) == 0) return TAP_PACKET_DONT_REDRAW;
835 pkt_len = pinfo->fd->pkt_len - tdata->trailer_len;
837 tick_stat_node(st, st_str_virtdist_pkts, 0, true);
838 increase_stat_node(st, st_str_virtdist_bytes, 0, true, pkt_len);
840 /* We could have low noise (with a virtual name) without medium noise (with the flow ID).
841 * That will get treated as a no flow case. */
842 if (tdata->virtual_name == NULL) {
843 if (tdata->flow == 0) {
844 /* No flow ID */
845 tick_stat_node(st, st_str_virtdist_noflow, st_node_virtpktdist, true);
846 increase_stat_node(st, st_str_virtdist_noflow, st_node_virtbytedist, true, pkt_len);
847 } else {
848 /* Flow ID without virtual name */
849 tick_stat_node(st, st_str_virtdist_novirt, st_node_virtpktdist, true);
850 increase_stat_node(st, st_str_virtdist_novirt, st_node_virtbytedist, true, pkt_len);
852 } else {
853 /* Has virtual name */
854 tick_stat_node(st, tdata->virtual_name, st_node_virtpktdist, true);
855 increase_stat_node(st, tdata->virtual_name, st_node_virtbytedist, true, pkt_len);
858 return TAP_PACKET_REDRAW;
859 } /* f5eth_virtdist_stats_tree_packet() */
861 /* End of statistics gathering */
862 /*===============================================================================================*/
864 /*===============================================================================================*/
865 /* Info column display handling.
867 * Format Specifiers:
868 * in/out are separate formats so that no printf formatting is required for these two common
869 * alternatives.
870 * There are two sets of six format strings. One set corresponding to "full" or long output
871 * ("long" is not used due to conflict with C keyword) and the other set corresponding to
872 * "brief" output.
873 * Full:
874 * in/out only; one for in, one for out:
875 * info_format_full_in_only, info_format_full_out_only
876 * in/out, slot and tmm; one for in and one for out:
877 * info_format_full_in_slot, info_format_full_out_slot
878 * in/out and tmm (no slot information); one for in and one for out:
879 * info_format_full_in_noslot, info_format_full_out_noslot
880 * Brief:
881 * in/out only; one for in, one for out:
882 * info_format_brief_in_only, info_format_brief_out_only
883 * in/out, slot and tmm; one for in and one for out:
884 * info_format_brief_in_slot, info_format_brief_out_slot
885 * in/out and tmm (no slot information); one for in and one for out:
886 * info_format_brief_in_noslot, info_format_brief_out_noslot
887 * The set of format specifiers in use are chosen based on whether brief is chosen and the
888 * following variables are set accordingly:
889 * info_format_in_only, info_format_out_only (should have no format specifiers)
890 * info_format_in_slot, info_format_out_slot (should have two format specifiers)
891 * info_format_in_noslot, info_format_out_noslot (should have one format specifier)
893 * Functions:
894 * Separate functions depending on the amount of information desired. The decision is made once
895 * when the preference is set and a function pointer is used to call the appropriate one:
896 * f5eth_set_info_col_inout(): In/out only.
897 * f5eth_set_info_col_slot(): in/out, slot and tmm.
898 * f5eth_set_info_col_noslot(): in/out and tmm (no slot information).
899 * f5eth_set_info_col is the function pointer to the function currently in use.
902 /** Info column display format formats */
903 static const char info_format_full_in_only[] = "IN : ";
904 static const char info_format_full_out_only[] = "OUT: ";
905 static const char info_format_full_in_slot[] = "IN s%u/tmm%-2u: ";
906 static const char info_format_full_out_slot[] = "OUT s%u/tmm%-2u: ";
907 static const char info_format_full_in_noslot[] = "IN tmm%-2u: ";
908 static const char info_format_full_out_noslot[] = "OUT tmm%-2u: ";
910 /* Variables used in f5eth_set_info_col functions initialized to defaults */
911 static char *info_format_in_only; /**< In format in use with in/out only */
912 static char *info_format_out_only; /**< Out format in use with in/out only */
913 static char *info_format_in_noslot; /**< In format in use without slot */
914 static char *info_format_out_noslot; /**< Out format in use without slot */
915 static char *info_format_in_slot; /**< In format in use with slot */
916 static char *info_format_out_slot; /**< Out format in use with slot */
918 /** Info column display format preference types:
919 * These correspond to bit flags
920 * Display on = 0x0001
921 * In out only = 0x0002
922 * Brief = 0x0004
924 typedef enum {
925 none = 0,
926 full = 1,
927 in_out_only = 3,
928 brief = 5,
929 brief_in_out_only = 7
930 } f5eth_info_type_t;
932 /** Info column display format type strings */
933 static const enum_val_t f5eth_display_strings[] = {
934 {"None", "None", 0},
935 {"Full", "Full", 1},
936 {"InOutOnly", "In/out only", 3},
937 {"Brief", "Brief", 5},
938 {"BriefInOutOnly", "Brief in/out only", 7},
939 {NULL, NULL, 0}
941 /** Info column display preference (default to full) */
942 static f5eth_info_type_t pref_info_type = full;
944 /** Preference for the brief in/out characters */
945 static const char *pref_brief_inout_chars;
947 /** Function pointer prototype for info column set functions */
948 typedef void (*f5eth_set_col_info_func)(packet_info *, unsigned, unsigned, unsigned);
950 /** Preference for setting platform regex for which platforms to display slot information for. */
951 static const char *pref_slots_regex;
952 /** Whether or not to display slot information, set based on platform and regex preference. */
953 static bool display_slot = true;
955 /*-----------------------------------------------------------------------------------------------*/
957 * @brief Adds full format (in/out, slot, tmm) to info column
959 * @param pinfo A pointer to the packet info structure.
960 * @param ingress zero for egress, non-zero for ingress.
961 * @param slot The slot number handling the packet
962 * @param tmm The tmm handling the packet
964 static void
965 f5eth_set_info_col_slot(packet_info *pinfo, unsigned ingress, unsigned slot, unsigned tmm)
967 bool col_writable;
969 * HTTP and other protocols set writable to false to protect
970 * their data. We don't care.
972 col_writable = col_get_writable(pinfo->cinfo, COL_INFO);
973 col_set_writable(pinfo->cinfo, COL_INFO, true);
975 if (ingress != 0) {
976 DISSECTOR_ASSERT(info_format_in_slot);
977 col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, info_format_in_slot, slot, tmm);
978 } else {
979 DISSECTOR_ASSERT(info_format_out_slot);
980 col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, info_format_out_slot, slot, tmm);
983 /* Reset writable to whatever it was before we got here. */
984 col_set_writable(pinfo->cinfo, COL_INFO, col_writable);
985 } /* f5eth_set_info_col_slot() */
987 /*-----------------------------------------------------------------------------------------------*/
989 * @brief Adds format without slot (in/out, tmm) to info column
991 * @param pinfo A pointer to the packet info structure.
992 * @param ingress zero for egress, non-zero for ingress.
993 * @param slot The slot number handling the packet (unused)
994 * @param tmm The tmm handling the packet
996 static void
997 f5eth_set_info_col_noslot(packet_info *pinfo, unsigned ingress, unsigned slot _U_, unsigned tmm)
999 bool col_writable;
1001 * HTTP and other protocols set writable to false to protect
1002 * their data. We don't care.
1004 col_writable = col_get_writable(pinfo->cinfo, COL_INFO);
1005 col_set_writable(pinfo->cinfo, COL_INFO, true);
1007 if (ingress != 0) {
1008 col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, info_format_in_noslot, tmm);
1009 } else {
1010 col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, info_format_out_noslot, tmm);
1013 /* Reset writable to whatever it was before we got here. */
1014 col_set_writable(pinfo->cinfo, COL_INFO, col_writable);
1015 } /* f5eth_set_info_col_noslot() */
1017 /*-----------------------------------------------------------------------------------------------*/
1019 * @brief Adds format with only direction (in/out) to info column
1021 * @param pinfo A pointer to the packet info structure.
1022 * @param ingress zero for egress, non-zero for ingress.
1023 * @param slot The slot number handling the packet (unused)
1024 * @param tmm The tmm handling the packet (unused)
1026 static void
1027 f5eth_set_info_col_inout(packet_info *pinfo, unsigned ingress, unsigned slot _U_, unsigned tmm _U_)
1029 bool col_writable;
1031 * HTTP and other protocols set writable to false to protect
1032 * their data. We don't care.
1034 col_writable = col_get_writable(pinfo->cinfo, COL_INFO);
1035 col_set_writable(pinfo->cinfo, COL_INFO, true);
1037 if (ingress != 0) {
1038 col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, "%s", info_format_in_only);
1039 } else {
1040 col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, "%s", info_format_out_only);
1043 /* Reset writable to whatever it was before we got here. */
1044 col_set_writable(pinfo->cinfo, COL_INFO, col_writable);
1045 } /* f5eth_set_info_col_inout() */
1047 /** The column display function. Will really be set in proto_reg_handoff_f5fileinfo() */
1048 static f5eth_set_col_info_func f5eth_set_info_col = f5eth_set_info_col_slot;
1050 /*-----------------------------------------------------------------------------------------------*/
1052 * @brief Called out of f5info processing to determine platform display information
1054 * @param platform String representing the platform name (can be NULL, will not be referenced
1055 * after the function returns.)
1057 static void
1058 f5eth_process_f5info(const uint8_t *platform)
1060 /** Always display slot information when there is no platform information in the header or
1061 * if there was no regex specified in the preference. But use the in/out only
1062 * function if that is specified in the preference.*/
1063 if (platform == NULL || platform[0] == '\0' || pref_slots_regex == NULL
1064 || pref_slots_regex[0] == '\0') {
1065 display_slot = true;
1066 if (pref_info_type == in_out_only || pref_info_type == brief_in_out_only) {
1067 f5eth_set_info_col = f5eth_set_info_col_inout;
1068 } else {
1069 f5eth_set_info_col = f5eth_set_info_col_slot;
1071 return;
1074 /** If the string matches the regex */
1075 if (g_regex_match_simple(pref_slots_regex, platform, G_REGEX_RAW, (GRegexMatchFlags)0)
1076 == true) {
1077 /** Then display the slot information (only if in/out only is not selected). */
1078 display_slot = true;
1079 if (pref_info_type == in_out_only || pref_info_type == brief_in_out_only) {
1080 f5eth_set_info_col = f5eth_set_info_col_inout;
1081 } else {
1082 f5eth_set_info_col = f5eth_set_info_col_slot;
1084 } else {
1085 /** Else do not display the slot information (only if in/out only is not selected). */
1086 display_slot = false;
1087 if (pref_info_type == in_out_only || pref_info_type == brief_in_out_only) {
1088 f5eth_set_info_col = f5eth_set_info_col_inout;
1089 } else {
1090 f5eth_set_info_col = f5eth_set_info_col_noslot;
1093 } /* f5eth_process_f5info() */
1095 /* End of info column display handling. */
1096 /*===============================================================================================*/
1098 /** Magic information for the fileinfo packet that might appear at the beginning of a capture. */
1099 static const uint8_t fileinfomagic1[] = {
1100 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x05, 0xff,
1101 'F', '5', '-', 'P', 's', 'e', 'u', 'd', 'o', '-', 'p', 'k', 't', 0
1104 #define F5_OFF_TYPE 0
1105 #define F5_OFF_LENGTH 1
1106 #define F5_OFF_VERSION 2
1107 #define F5_OFF_VALUE 3
1109 /** This is used only for old format trailers. The highest version number is 3 for medium trailers. */
1110 #define F5TRAILER_VER_MAX 3
1112 #define F5TYPE_LOW 1
1113 #define F5TYPE_MED 2
1114 #define F5TYPE_HIGH 3
1116 /* These are to perform a sanity check to try to avoid rendering true garbage
1117 * in packets. So, in addition to matching one of the types, the len of the
1118 * suspected trailer needs to fall into this range.
1120 * Max length seems to be 42 on high detail.
1121 * Max length with RST cause in medium(v1) is 30 + 8 + 1 + 96 (might be 30+96)?
1122 * Max length with RST cause in medium(v2) is 31 + 8 + 1 + 96 (might be 31+96)?
1123 * Max length with RST cause in medium(v3) is 35 + 8 + 1 + 96 (might be 35+96)?
1124 * Min length is 8 on v9.4 medium detail.
1125 * Min length is 7 on v11.2 low trailer with no VIP name.
1127 * These are only used for old format trailers.
1129 #define F5_MIN_SANE 7
1130 #define F5_MAX_SANE 140
1132 #define F5_LOW_FLAGS_INGRESS_MASK 0x01
1133 #define F5_LOW_FLAGS_HWACTION_MASK 0x06
1135 #define F5_HIV0_LEN 42
1137 /* Old format trailers */
1138 #define F5_MEDV94_LEN 8
1139 #define F5_MEDV10_LEN 21
1140 #define F5_MEDV11_LEN 29
1141 #define F5_MEDV1_LENMIN 30
1142 #define F5_MEDV2_LENMIN 31
1143 #define F5_MEDV3_LENMIN 35
1144 #define F5_LOWV94_LEN 35
1145 #define F5_LOWV10_LEN 22
1146 #define F5_OFF_LOW_ING 3
1147 #define F5_OFF_LOW_SLOT 4
1148 #define F5_OFF_LOW_TMM 5
1149 #define VIP_NAME_LEN 16
1150 #define F5_LOWV1_LENMIN 7
1152 /* New format (DPT) trailers */
1153 #define F5_MEDV4_LENMIN 32 /**< Minimum length without TLV header */
1155 #define F5_DPT_V1_HDR_MAGIC_OFF 0
1156 #define F5_DPT_V1_HDR_MAGIC_LEN 4
1157 #define F5_DPT_V1_HDR_MAGIC 0xf5deb0f5
1158 #define F5_DPT_V1_HDR_LENGTH_OFF (F5_DPT_V1_HDR_MAGIC_OFF + F5_DPT_V1_HDR_MAGIC_LEN)
1159 #define F5_DPT_V1_HDR_LENGTH_LEN 2
1160 #define F5_DPT_V1_HDR_VERSION_OFF (F5_DPT_V1_HDR_LENGTH_OFF + F5_DPT_V1_HDR_LENGTH_LEN)
1161 #define F5_DPT_V1_HDR_VERSION_LEN 2
1162 #define F5_DPT_V1_HDR_VERSION_MIN 1 /**< Minimum DPT version handled by this dissector. */
1163 #define F5_DPT_V1_HDR_VERSION_MAX 1 /**< Maximum DPT version handled by this dissector. */
1164 #define F5_DPT_V1_HDR_LEN (F5_DPT_V1_HDR_VERSION_OFF + F5_DPT_V1_HDR_VERSION_LEN)
1166 #define F5_DPT_PROVIDER_NOISE 1
1168 #define F5_DPT_V1_TLV_PROVIDER_OFF 0
1169 #define F5_DPT_V1_TLV_PROVIDER_LEN 2
1170 #define F5_DPT_V1_TLV_TYPE_OFF (F5_DPT_V1_TLV_PROVIDER_OFF + F5_DPT_V1_TLV_PROVIDER_LEN)
1171 #define F5_DPT_V1_TLV_TYPE_LEN 2
1172 #define F5_DPT_V1_TLV_LENGTH_OFF (F5_DPT_V1_TLV_TYPE_OFF + F5_DPT_V1_TLV_TYPE_LEN)
1173 #define F5_DPT_V1_TLV_LENGTH_LEN 2
1174 #define F5_DPT_V1_TLV_VERSION_OFF (F5_DPT_V1_TLV_LENGTH_OFF + F5_DPT_V1_TLV_LENGTH_LEN)
1175 #define F5_DPT_V1_TLV_VERSION_LEN 2
1176 #define F5_DPT_V1_TLV_HDR_LEN (F5_DPT_V1_TLV_VERSION_OFF+F5_DPT_V1_TLV_VERSION_LEN)
1178 /*===============================================================================================*/
1179 /* This section is for performing analysis of the trailer information. */
1181 /** Analysis Overview:
1183 * The analysis in this dissector is meant to correlate data in the F5 Ethernet trailer with other
1184 * data in the frame (e.g. IP, TCP) and highlight things that don't look right. They might be
1185 * perfectly valid, but in most cases, they are not.
1187 * How it works:
1189 * When analysis is enabled, the dissector ties protocol data to each packet. The dissector
1190 * populates some useful data it needs to perform analysis into the protocol data. It also
1191 * registers taps on IP, IPv6 and TCP to populate data from those headers into the stored protocol
1192 * data.
1194 * All of that information is then used to look for certain, common anomalies.
1196 * It uses taps rather than surfing the WS protocol tree because:
1197 * 1. I suspect that surfing the protocol tree is rather expensive.
1198 * 2. We need to try to find the outer-most headers and use those. The taps should fire in
1199 * order so that should get what is needed. When searching the tree, it's difficult to
1200 * know if, for example, the TCP header we are on is tied to the outer IP header or to
1201 * the IP header that's inside and ICMP inside an IP.
1203 * Challenges:
1205 * 1. Taps run after all dissectors run on a packet. As a result, when the trailer dissector is
1206 * running, it does not have the data from the other protocols to perform the analysis.
1207 * 2. The Ethernet dissector does not call trailer dissectors if it is not building a tree.
1209 * Flow:
1211 * In the trailer dissector, if ip_visited is set and analysis done is not set, then analysis
1212 * is performed.
1214 * In the tcp tap, if analysis_done is not set and pkt_ingress is not unknown (meaning that the
1215 * trailer dissector had an opportunity to run on this packet), then analysis is performed. Also
1216 * in this case, we attempt to attach the expert info to a top-level tree element for the
1217 * F5 Ethernet trailer.
1219 * The purpose of the analysis in the dissector is for first-pass misses of the dissector. For
1220 * example, on initial file load, if the Ethernet dissector does not call the trailer dissector
1221 * then analysis cannot be performed by the tcp tap because the data from the trailer is not
1222 * available. In order to get the analysis on the second pass, we run here.
1224 * The purpose of the analysis and rendering in the tcp tap is to handle one-pass situations
1225 * (e.g. tshark). In one-pass situations, after the tcp tap is called, the trailer dissector
1226 * will not run again to have an opportunity to perform and render analysis.
1229 #define IP_MF 0x2000 /** IP more fragments flag */
1230 #define IP_OFFSET_WIDTH 13 /** Size of fragment offset field */
1231 #define IP_OFFSET_MASK ((1 << IP_OFFSET_WIDTH) - 1)
1233 /** Structure used to store data gathered by the taps and dissector that is attached to the pinfo
1234 * structure for the packet. This structure ends up getting allocated for every packet. So, we
1235 * want to keep it small.
1237 * For fields that are 1 bit wide, they have 0 == false and 1 == true.
1238 * For fields that are 2 bits wide, they have 0 == false, 1 == true and 3 == unknown.
1240 struct f5eth_analysis_data_t {
1241 uint8_t ip_visited : 1; /**< Did the IPv4 or IPv6 tap look at this packet already? */
1242 uint8_t tcp_visited : 1; /**< Did the TCP tap look at this packet already? */
1243 uint8_t ip_istcp : 2; /**< Is this a TCP (set by ip/ip6 tap on first header) */
1244 uint8_t ip_isfrag : 2; /**< Is this packet an IP fragment? */
1245 uint8_t tcp_synset : 2; /**< Is the SYN flag set in the TCP header? */
1246 uint8_t tcp_ackset : 2; /**< Is the ACK flag set in the TCP header? */
1248 uint8_t pkt_ingress : 2; /**< Packet is ingress packet */
1249 uint8_t pkt_has_flow : 2; /**< Packet has associated flow */
1250 uint8_t pkt_has_peer : 2; /**< Packet has associated peer flow */
1252 uint8_t analysis_done : 1; /**< Analysis has been performed */
1253 uint8_t analysis_flowreuse : 1; /**< Analysis indicates flow reuse */
1254 uint8_t analysis_flowlost : 1; /**< Analysis indicates flow lost */
1255 uint8_t analysis_hasresults : 1; /**< Are there actually any results? */
1258 /*-----------------------------------------------------------------------------------------------*/
1260 * @brief Allocates a new analysis data structure and initializes the values.
1262 * @return wmem allocated analysis structure
1264 static struct f5eth_analysis_data_t *
1265 new_f5eth_analysis_data_t(void)
1267 struct f5eth_analysis_data_t *r = wmem_new0(wmem_file_scope(), struct f5eth_analysis_data_t);
1269 /* r->ip_visited = 0; */
1270 /* r->tcp_visited = 0; */
1271 r->ip_istcp = 3;
1272 r->tcp_synset = 3;
1273 r->tcp_ackset = 3;
1274 r->ip_isfrag = 3;
1276 r->pkt_ingress = 3;
1277 r->pkt_has_flow = 3;
1278 r->pkt_has_peer = 3;
1280 /* r->analysis_done = 0; */
1281 /* r->analysis_flowreuse = 0; */
1282 /* r->analysis_flowlost = 0; */
1283 /* r->analysis_hasresults = 0; */
1285 return r;
1286 } /* new_f5eth_analysis_data_t() */
1288 /* Functions for find a subtree of a particular type of the current tree. */
1290 /** Structure used as the anonymous data in the proto_tree_children_foreach() function */
1291 struct subtree_search {
1292 proto_tree *tree; /**< The matching tree that we found */
1293 int hf; /**< The type of tree that we are looking for. */
1296 /*-----------------------------------------------------------------------------------------------*/
1298 * @brief Function to see if a node is of a particular type and return it if it is a tree.
1300 * @param pn A pointer to the proto_node being looked at.
1301 * @param data A pointer to the subtree_search structure with search criteria and results.
1303 static void
1304 compare_subtree(proto_node *pn, void *data)
1306 struct subtree_search *search_struct;
1307 search_struct = (struct subtree_search *)data;
1309 if (pn && pn->finfo && pn->finfo->hfinfo && pn->finfo->hfinfo->id == search_struct->hf) {
1310 search_struct->tree = proto_item_get_subtree(pn);
1312 } /* compare_subtree() */
1314 /*-----------------------------------------------------------------------------------------------*/
1316 * @brief Function to search child trees (one level) for a tree of a specific type.
1318 * @param tree A pointer to the proto_tree being looked at.
1319 * @param hf The register hfinfo id that we are looking for.
1320 * @return The tree that was found or NULL if it was not found.
1322 static proto_tree *
1323 find_subtree(proto_tree *tree, int hf)
1325 struct subtree_search search_struct;
1327 if (tree == NULL || hf == -1)
1328 return NULL;
1329 search_struct.tree = NULL;
1330 search_struct.hf = hf;
1331 proto_tree_children_foreach(tree, compare_subtree, &search_struct);
1332 return search_struct.tree;
1333 } /* find_subtree() */
1335 /*-----------------------------------------------------------------------------------------------*/
1337 * @brief Computes the analysis results based on the data in the analysis data struct.
1339 * @param ad A pointer to the f5eth_analysis_data_t struct
1341 static void
1342 perform_analysis(struct f5eth_analysis_data_t *ad)
1344 /** Tests that apply to ingress TCP non-frags */
1345 if (ad->pkt_ingress == 1 && ad->ip_istcp == 1 && ad->tcp_visited == 1 && ad->ip_isfrag == 0) {
1346 /** If this is an inbound SYN and there is a flow ID, we might have a problem. */
1347 if (ad->tcp_synset == 1 && ad->tcp_ackset == 0 && ad->pkt_has_flow == 1) {
1348 ad->analysis_flowreuse = 1;
1349 ad->analysis_hasresults = 1;
1352 /** If this is an inbound packet with the ACK flag set and there is no flow, we might have
1353 * a problem. */
1354 if (ad->tcp_ackset == 1 && ad->pkt_has_flow == 0) {
1355 ad->analysis_flowlost = 1;
1356 ad->analysis_hasresults = 1;
1360 ad->analysis_done = 1;
1361 } /* perform_analysis() */
1363 /*-----------------------------------------------------------------------------------------------*/
1365 * @brief Puts the results of the F5 Ethernet trailer analysis into the protocol tree.
1367 * @param tvb A pointer to a TV buffer for the packet.
1368 * @param pinfo A pointer to the packet info struction for the packet
1369 * @param tree A pointer to the protocol tree structure
1370 * @param ad A pointer to the intra-noise information data
1372 static void
1373 render_analysis(
1374 tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const struct f5eth_analysis_data_t *ad)
1376 proto_item *pi;
1377 if (ad == NULL || ad->analysis_hasresults == 0)
1378 return;
1380 pi = proto_tree_add_item(tree, hf_analysis, tvb, 0, 0, ENC_NA);
1381 proto_item_set_generated(pi);
1382 if (ad->analysis_flowreuse) {
1383 expert_add_info(pinfo, pi, &ei_f5eth_flowreuse);
1385 if (ad->analysis_flowlost) {
1386 expert_add_info(pinfo, pi, &ei_f5eth_flowlost);
1388 } /* render_analysis() */
1390 /*-----------------------------------------------------------------------------------------------*/
1392 * @brief Tap call back to retrieve information about the IP headers.
1394 * @param tapdata UNUSED
1395 * @param pinfo Pointer to acket Info data structure
1396 * @param edt UNUSED
1397 * @param data Pointer to ws_ip4 structure
1398 * @return tap_packet_status
1400 static tap_packet_status
1401 ip_tap_pkt(void *tapdata _U_, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data, tap_flags_t flags _U_)
1403 struct f5eth_analysis_data_t *ad;
1404 const ws_ip4 *iph;
1406 ad = (struct f5eth_analysis_data_t *)p_get_proto_data(
1407 wmem_file_scope(), pinfo, proto_f5ethtrailer, 0);
1408 if (ad == NULL)
1409 return TAP_PACKET_DONT_REDRAW; /* No F5 information */
1410 if (ad->ip_visited == 1)
1411 return TAP_PACKET_DONT_REDRAW;
1412 ad->ip_visited = 1;
1414 if (data == NULL)
1415 return TAP_PACKET_DONT_REDRAW;
1416 iph = (const ws_ip4 *)data;
1418 /* Only care about TCP at this time */
1419 /* We wait until here to make this check so that if TCP in encapsulated in something else, we
1420 * don't work on the encapsulated header. So, we only want to work on TCP if it associated
1421 * with the first IP header (not if it's embedded in an ICMP datagram or some sort of tunnel).
1423 if (iph->ip_proto != IP_PROTO_TCP) {
1424 ad->ip_istcp = 0;
1425 return TAP_PACKET_DONT_REDRAW;
1428 ad->ip_istcp = 1;
1429 ad->ip_isfrag = ((iph->ip_off & IP_OFFSET_MASK) || (iph->ip_off & IP_MF)) ? 1 : 0;
1431 return TAP_PACKET_REDRAW;
1432 } /* ip_tap_pkt() */
1434 /*-----------------------------------------------------------------------------------------------*/
1436 * @brief Tap call back to retrieve information about the IPv6 headers.
1438 * @param tapdata UNUSED
1439 * @param pinfo Pointer to acket Info data structure
1440 * @param edt UNUSED
1441 * @param data Pointer to ws_ip6_hdr structure
1442 * @return tap_packet_status
1444 static tap_packet_status
1445 ipv6_tap_pkt(void *tapdata _U_, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data, tap_flags_t flags _U_)
1447 struct f5eth_analysis_data_t *ad;
1448 const struct ws_ip6_hdr *ipv6h;
1450 ad = (struct f5eth_analysis_data_t *)p_get_proto_data(
1451 wmem_file_scope(), pinfo, proto_f5ethtrailer, 0);
1452 if (ad == NULL)
1453 return TAP_PACKET_DONT_REDRAW; /* No F5 information */
1454 if (ad->ip_visited == 1)
1455 return TAP_PACKET_DONT_REDRAW;
1456 ad->ip_visited = 1;
1458 if (data == NULL)
1459 return TAP_PACKET_DONT_REDRAW;
1460 ipv6h = (const struct ws_ip6_hdr *)data;
1462 /* Only care about TCP at this time */
1463 /* We wait until here to make this check so that if TCP in encapsulated in something else, we
1464 * don't work on the encapsulated header. So, we only want to work on TCP if it associated
1465 * with the first IP header (not if it's embedded in an ICMP datagram or some sort of tunnel.
1467 /* Note that this only works if TCP is the first next header. If there are other IPv6 headers,
1468 * we will not see the fact that it is TCP (limitation of IPv6 tap). This becomes a problem if
1469 * there are hop_by_hop or routing headers or other (non-fragment) IPv6 headers. If it's a
1470 * fragment, we don't care anyways (too much effort). */
1471 if (ipv6h->ip6h_nxt != IP_PROTO_TCP) {
1472 ad->ip_istcp = 0;
1473 return TAP_PACKET_DONT_REDRAW;
1476 ad->ip_istcp = 1;
1478 return TAP_PACKET_REDRAW;
1479 } /* ipv6_tap_pkt() */
1481 /*-----------------------------------------------------------------------------------------------*/
1483 * @brief Tap call back to retrieve information about the TCP headers.
1485 * @param tapdata UNUSED
1486 * @param pinfo Pointer to acket Info data structure
1487 * @param edt UNUSED
1488 * @param data Pointer to tcp_info_t structure
1489 * @return tap_packet_status
1491 static tap_packet_status
1492 tcp_tap_pkt(void *tapdata _U_, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data, tap_flags_t flags _U_)
1494 struct f5eth_analysis_data_t *ad;
1495 const tcp_info_t *tcph;
1497 ad = (struct f5eth_analysis_data_t *)p_get_proto_data(
1498 wmem_file_scope(), pinfo, proto_f5ethtrailer, 0);
1499 if (ad == NULL)
1500 return TAP_PACKET_DONT_REDRAW; /* No F5 information */
1501 if (ad->tcp_visited == 1)
1502 return TAP_PACKET_DONT_REDRAW;
1503 ad->tcp_visited = 1;
1505 if (data == NULL)
1506 return TAP_PACKET_DONT_REDRAW;
1507 tcph = (const tcp_info_t *)data;
1509 ad->tcp_synset = (tcph->th_flags & TH_SYN) ? 1 : 0;
1510 ad->tcp_ackset = (tcph->th_flags & TH_ACK) ? 1 : 0;
1512 /** Only do this if the trailer dissector ran. */
1513 if (ad->pkt_ingress != 3 && ad->analysis_done == 0) {
1514 perform_analysis(ad);
1515 /** If there were results from the analysis, go find the tree and try to insert them. */
1516 if (ad->analysis_hasresults == 1) {
1517 proto_tree *tree;
1519 /** This was the first opportunity to run, so add anything necessary to the tree. */
1520 /* If we don't find a tree, we could theoretically anchor it to the top-tree. However,
1521 * this situation should not happen since, if we know the ingress property, then the
1522 * trailer dissector ran and probably created a subtree, so it should most always be
1523 * there. If it is not there, it could be because there is nothing of interest to a
1524 * filter in the f5ethtrailer protocol, so it didn't create a tree (so probably don't
1525 * want to blindly tie this to the top-tree). Other causes would warrant further
1526 * investigation as to why it couldn't be found. */
1527 if ((tree = find_subtree(edt->tree, proto_f5ethtrailer)) != NULL)
1528 render_analysis(edt->tvb, pinfo, tree, ad);
1532 return TAP_PACKET_REDRAW;
1533 } /* tcp_tap_pkt() */
1535 /* End of analysis functions */
1536 /*===============================================================================================*/
1538 /* Used to determine if an address is an IPv4 address represented as an IPv6
1539 * address. */
1540 static const uint8_t ipv4as6prefix[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff};
1541 static const uint8_t f5rtdomprefix[] = {0x26, 0x20, 0, 0, 0x0c, 0x10, 0xf5, 0x01, 0, 0};
1543 #define F5_IPV6ADDR_LEN 16
1545 /*---------------------------------------------------------------------------*/
1547 * @brief Display an IPv6 encoded IPv4 addr in an IPv4 field if appropriate.
1549 * @param tree Pointer to tree struct
1550 * @param addrfield hf_index address will be placed in
1551 * @param rtdomfield hf_index route doamin will be placed in
1552 * @param tvb Pointer to tvb
1553 * @param offset Offset into the tvb containg the IPv6 address
1554 * @param hidden Should the protocol item be hidden
1555 * @return Pointer to proto_item created
1557 static proto_item *
1558 displayIPv6as4(
1559 proto_tree *tree, int addrfield, int rtdomfield, tvbuff_t *tvb, int offset, bool hidden)
1561 proto_item *pi = NULL;
1563 if (tvb_memeql(tvb, offset, ipv4as6prefix, sizeof(ipv4as6prefix)) == 0) {
1564 if (addrfield >= 0) {
1565 pi = proto_tree_add_item(
1566 tree, addrfield, tvb, offset + (int)sizeof(ipv4as6prefix), 4, ENC_BIG_ENDIAN);
1567 if (hidden)
1568 proto_item_set_hidden(pi);
1570 } else if (tvb_memeql(tvb, offset, f5rtdomprefix, sizeof(f5rtdomprefix)) == 0) {
1571 /* Route domain information may show up here if the traffic is between tmm and the BIG-IP
1572 * host (e.g. monitor traffic). If so, break it up and render it for ease of viewing (and
1573 * searching). Ignore the incorrect addresses used by 10.0.x (solution 10511) as these
1574 * will hopefully not be common. */
1575 /* TODO: review - These are technically backwards as we are probably returning the wrong pi. However,
1576 * when configuring, people usually see route domain after the address, so that is why this
1577 * particular ordering is used (and none of the callers currently use the return value). */
1578 if (addrfield >= 0) {
1579 pi = proto_tree_add_item(
1580 tree, addrfield, tvb, offset + (int)sizeof(f5rtdomprefix) + 2, 4, ENC_BIG_ENDIAN);
1581 if (hidden)
1582 proto_item_set_hidden(pi);
1584 if (rtdomfield >= 0) {
1585 pi = proto_tree_add_item(
1586 tree, rtdomfield, tvb, offset + (int)sizeof(f5rtdomprefix), 2, ENC_BIG_ENDIAN);
1587 if (hidden)
1588 proto_item_set_hidden(pi);
1592 return pi;
1593 } /* displayIPv6as4() */
1596 * @brief Render a tree item to dispalay header info for old format trailer blocks
1598 * @attention The old format trailers used a fair amount of magic numbers. Continuing that
1599 use for now with the same magic numbers in this function
1601 * @param tvb Pointer to the tvb
1602 * @param tree Pointer to tree struct
1603 * @param offset Offset into the tvb
1604 * @return Number of bytes consumed
1606 static int
1607 render_f5_legacy_hdr(tvbuff_t *tvb, proto_tree *tree, int offset)
1609 proto_item *pi = NULL;
1610 uint32_t trailer_type;
1612 pi = proto_tree_add_item(tree, hf_trailer_hdr, tvb, offset, 3, ENC_NA);
1613 tree = proto_item_add_subtree(pi, ett_f5ethtrailer_trailer_hdr);
1615 proto_tree_add_item_ret_uint(tree, hf_type, tvb, offset, 1, ENC_BIG_ENDIAN, &trailer_type);
1616 offset += 1;
1617 proto_item_append_text(pi, ", Type: %u", trailer_type);
1618 proto_tree_add_item(tree, hf_length, tvb, offset, 1, ENC_BIG_ENDIAN);
1619 offset += 1;
1620 proto_tree_add_item(tree, hf_version, tvb, offset, 1, ENC_BIG_ENDIAN);
1621 /* offset += 1; */
1622 return 3;
1624 } /* render_f5_legacy_hdr() */
1626 /*---------------------------------------------------------------------------*/
1628 * @brief Dissect old format "high" trailer TLV
1630 * @param tvb Pointer to the tvb to be processed
1631 * @param pinfo Pointer to packet_info struct
1632 * @param tree Pointer to protocol tree
1633 * @param offset Offset into the tvb where trailer begins
1634 * @param trailer_length Length of the trailer data to process
1635 * @param trailer_ver Version of the trailer detected
1636 * @param tdata Pointer to tap data structure
1637 * @return Number of btyes consumed
1639 static unsigned
1640 dissect_high_trailer(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset,
1641 uint8_t trailer_length, uint8_t trailer_ver, f5eth_tap_data_t *tdata)
1643 proto_item *pi = NULL;
1644 unsigned o;
1645 uint8_t ipproto;
1647 if (trailer_ver != 0 || trailer_length != F5_HIV0_LEN)
1648 return 0;
1650 /* We do not need to do anything if we don't have a tree */
1651 if (tree == NULL)
1652 return trailer_length;
1654 o = offset;
1655 o += render_f5_legacy_hdr(tvb, tree, o);
1657 if (tdata->peer_flow == 0) {
1658 proto_tree_add_item(tree, hf_peer_nopeer, tvb, o, trailer_length - 3, ENC_NA);
1659 return trailer_length;
1662 /* Add in the high order structures. */
1663 ipproto = tvb_get_uint8(tvb, o);
1664 proto_tree_add_item(tree, hf_peer_ipproto, tvb, o, 1, ENC_BIG_ENDIAN);
1665 o += 1;
1666 proto_tree_add_item(tree, hf_peer_vlan, tvb, o, 2, ENC_BIG_ENDIAN);
1667 o += 2;
1669 /* peer remote address */
1670 if (pref_pop_other_fields) {
1671 displayIPv6as4(tree, hf_ip_ipaddr, -1, tvb, o, true);
1672 pi = proto_tree_add_item(tree, hf_ip6_ip6addr, tvb, o, 16, ENC_NA);
1673 proto_item_set_hidden(pi);
1675 displayIPv6as4(tree, hf_peer_remote_addr, hf_peer_remote_rtdom, tvb, o, false);
1676 displayIPv6as4(tree, hf_peer_ipaddr, hf_peer_rtdom, tvb, o, true);
1677 proto_tree_add_item(tree, hf_peer_remote_ip6addr, tvb, o, 16, ENC_NA);
1678 pi = proto_tree_add_item(tree, hf_peer_ip6addr, tvb, o, 16, ENC_NA);
1679 proto_item_set_hidden(pi);
1680 o += 16;
1682 /* peer local address */
1683 if (pref_pop_other_fields) {
1684 displayIPv6as4(tree, hf_ip_ipaddr, -1, tvb, o, true);
1685 pi = proto_tree_add_item(tree, hf_ip6_ip6addr, tvb, o, 16, ENC_NA);
1686 proto_item_set_hidden(pi);
1688 displayIPv6as4(tree, hf_peer_local_addr, hf_peer_local_rtdom, tvb, o, false);
1689 displayIPv6as4(tree, hf_peer_ipaddr, hf_peer_rtdom, tvb, o, true);
1690 proto_tree_add_item(tree, hf_peer_local_ip6addr, tvb, o, 16, ENC_NA);
1691 pi = proto_tree_add_item(tree, hf_peer_ip6addr, tvb, o, 16, ENC_NA);
1692 proto_item_set_hidden(pi);
1693 o += 16;
1695 if (pref_pop_other_fields) {
1696 /* If there is no proto in the trailer, go get it from the actual packet
1697 * information. */
1698 if (ipproto == 0) {
1699 ipproto = ptype_to_ipproto(pinfo->ptype);
1702 /* peer remote port */
1703 switch (ipproto) {
1704 case IP_PROTO_TCP:
1705 pi = proto_tree_add_item(tree, hf_tcp_tcpport, tvb, o, 2, ENC_BIG_ENDIAN);
1706 proto_item_set_hidden(pi);
1707 break;
1708 case IP_PROTO_UDP:
1709 pi = proto_tree_add_item(tree, hf_udp_udpport, tvb, o, 2, ENC_BIG_ENDIAN);
1710 proto_item_set_hidden(pi);
1711 break;
1714 proto_tree_add_item(tree, hf_peer_remote_port, tvb, o, 2, ENC_BIG_ENDIAN);
1715 pi = proto_tree_add_item(tree, hf_peer_port, tvb, o, 2, ENC_BIG_ENDIAN);
1716 proto_item_set_hidden(pi);
1717 o += 2;
1719 /* peer remote port */
1720 if (pref_pop_other_fields) {
1721 switch (ipproto) {
1722 case IP_PROTO_TCP:
1723 pi = proto_tree_add_item(tree, hf_tcp_tcpport, tvb, o, 2, ENC_BIG_ENDIAN);
1724 proto_item_set_hidden(pi);
1725 break;
1726 case IP_PROTO_UDP:
1727 pi = proto_tree_add_item(tree, hf_udp_udpport, tvb, o, 2, ENC_BIG_ENDIAN);
1728 proto_item_set_hidden(pi);
1729 break;
1732 proto_tree_add_item(tree, hf_peer_local_port, tvb, o, 2, ENC_BIG_ENDIAN);
1733 pi = proto_tree_add_item(tree, hf_peer_port, tvb, o, 2, ENC_BIG_ENDIAN);
1734 proto_item_set_hidden(pi);
1736 return trailer_length;
1737 } /* dissect_high_trailer() */
1739 /*---------------------------------------------------------------------------*/
1741 * @brief Dissect old format "medium" trailer TLV
1743 * @param tvb Pointer to the tvb to be processed
1744 * @param pinfo Pointer to packet_info struct
1745 * @param tree Pointer to protocol tree
1746 * @param offset Offset into the tvb where trailer begins
1747 * @param trailer_length Length of the trailer data to process
1748 * @param trailer_ver Version of the trailer detected
1749 * @param tdata Pointer to tap data structure
1750 * @return Number of btyes consumed
1752 static unsigned
1753 dissect_med_trailer(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset,
1754 uint8_t trailer_length, uint8_t trailer_ver, f5eth_tap_data_t *tdata)
1756 proto_item *pi = NULL;
1757 unsigned o;
1758 unsigned rstcauselen = 0;
1759 unsigned rstcausever = 0xff;
1761 switch (trailer_ver) {
1762 case 0:
1763 if (trailer_length != F5_MEDV11_LEN && trailer_length != F5_MEDV10_LEN
1764 && trailer_length != F5_MEDV94_LEN) {
1765 return 0;
1767 break;
1768 case 1:
1769 if (trailer_length < F5_MEDV1_LENMIN) { /* too small */
1770 return 0;
1772 rstcauselen = tvb_get_uint8(tvb, offset + F5_MEDV1_LENMIN - 1);
1773 /* check size is valid */
1774 if (rstcauselen + F5_MEDV1_LENMIN != trailer_length) {
1775 return 0;
1777 if (rstcauselen)
1778 rstcausever = (tvb_get_uint8(tvb, offset + F5_MEDV1_LENMIN) & 0xfe) >> 1;
1779 /* If we want the RST cause in the summary, we need to do it here,
1780 * before the tree check below */
1781 if (rstcauselen && rstcause_in_info) {
1782 if (rstcausever == 0x00) {
1783 col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "[F5RST%s: %s]",
1784 tvb_get_uint8(tvb, offset + F5_MEDV1_LENMIN) & 0x01 ? "(peer)" : "",
1785 tvb_get_string_enc(pinfo->pool, tvb, offset + F5_MEDV1_LENMIN + 9,
1786 rstcauselen - 9, ENC_ASCII));
1789 break;
1790 case 2:
1791 if (trailer_length < F5_MEDV2_LENMIN) { /* too small */
1792 return 0;
1794 rstcauselen = tvb_get_uint8(tvb, offset + F5_MEDV2_LENMIN - 1);
1795 /* check size is valid */
1796 if (rstcauselen + F5_MEDV2_LENMIN != trailer_length) {
1797 return 0;
1799 if (rstcauselen)
1800 rstcausever = (tvb_get_uint8(tvb, offset + F5_MEDV2_LENMIN) & 0x0fe) >> 1;
1801 /* If we want the RST cause in the summary, we need to do it here,
1802 * before the tree check below */
1803 if (rstcauselen && rstcause_in_info) {
1804 if (rstcausever == 0x00) {
1805 col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "[F5RST%s: %s]",
1806 tvb_get_uint8(tvb, offset + F5_MEDV2_LENMIN) & 0x01 ? "(peer)" : "",
1807 tvb_get_string_enc(pinfo->pool, tvb, offset + F5_MEDV2_LENMIN + 9,
1808 rstcauselen - 9, ENC_ASCII));
1811 break;
1812 case 3:
1813 if (trailer_length < F5_MEDV3_LENMIN) { /* too small */
1814 return 0;
1816 rstcauselen = tvb_get_int8(tvb, offset + F5_MEDV3_LENMIN -1);
1817 /* check size is valid */
1818 if (rstcauselen + F5_MEDV3_LENMIN != trailer_length) {
1819 return 0;
1821 if (rstcauselen)
1822 rstcausever = (tvb_get_int8(tvb, offset + F5_MEDV3_LENMIN) & 0xfe) >>1;
1823 /* If we want the RST cause in the summary, we need to do it here,
1824 * before the tree check below */
1825 if (rstcauselen && rstcause_in_info) {
1826 if (rstcausever == 0x00) {
1827 col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "[F5RST%s: %s]",
1828 tvb_get_int8(tvb, offset + F5_MEDV3_LENMIN) & 0x01 ? "(peer)" : "",
1829 tvb_get_string_enc(pinfo->pool, tvb, offset + F5_MEDV3_LENMIN + 9,
1830 rstcauselen - 9, ENC_ASCII));
1833 break;
1834 default:
1835 return 0;
1838 /* We do not need to do anything more if we don't have a tree and we are not performing
1839 * analysis */
1840 if (pref_perform_analysis == false && tree == NULL)
1841 return trailer_length;
1843 o = offset;
1844 o += render_f5_legacy_hdr(tvb, tree, o);
1846 /* After 9.4, flow IDs and flags and type are here in medium */
1847 if (trailer_length != F5_MEDV94_LEN || trailer_ver > 0) {
1848 if (trailer_length == F5_MEDV10_LEN && trailer_ver == 0) {
1849 /* In v10, flowIDs are 32bit */
1850 tdata->flow = tvb_get_ntohl(tvb, o);
1851 proto_tree_add_item(tree, hf_flow_id, tvb, o, 4, ENC_BIG_ENDIAN);
1852 pi = proto_tree_add_item(tree, hf_any_flow, tvb, o, 4, ENC_BIG_ENDIAN);
1853 proto_item_set_hidden(pi);
1854 o += 4;
1855 tdata->peer_flow = tvb_get_ntohl(tvb, o);
1856 proto_tree_add_item(tree, hf_peer_id, tvb, o, 4, ENC_BIG_ENDIAN);
1857 pi = proto_tree_add_item(tree, hf_any_flow, tvb, o, 4, ENC_BIG_ENDIAN);
1858 proto_item_set_hidden(pi);
1859 o += 4;
1860 } else {
1861 /* After v10, flowIDs are 64bit */
1862 tdata->flow = tvb_get_ntoh64(tvb, o);
1863 proto_tree_add_item(tree, hf_flow_id, tvb, o, 8, ENC_BIG_ENDIAN);
1864 pi = proto_tree_add_item(tree, hf_any_flow, tvb, o, 8, ENC_BIG_ENDIAN);
1865 proto_item_set_hidden(pi);
1866 o += 8;
1867 tdata->peer_flow = tvb_get_ntoh64(tvb, o);
1868 proto_tree_add_item(tree, hf_peer_id, tvb, o, 8, ENC_BIG_ENDIAN);
1869 pi = proto_tree_add_item(tree, hf_any_flow, tvb, o, 8, ENC_BIG_ENDIAN);
1870 proto_item_set_hidden(pi);
1871 o += 8;
1873 tdata->flows_set = 1;
1874 if (trailer_ver >= 3) {
1875 proto_tree_add_item(tree, hf_cf_flags2, tvb, o, 4, ENC_BIG_ENDIAN);
1876 o += 4;
1878 proto_tree_add_item(tree, hf_cf_flags, tvb, o, 4, ENC_BIG_ENDIAN);
1879 o += 4;
1880 proto_tree_add_item(tree, hf_flow_type, tvb, o, 1, ENC_BIG_ENDIAN);
1881 o += 1;
1884 /* We do not need to do anything if we don't have a tree */
1885 /* Needed to get here so that analysis and tap will work. */
1886 if (tree == NULL)
1887 return trailer_length;
1889 proto_tree_add_item(tree, hf_ha_unit, tvb, o, 1, ENC_BIG_ENDIAN);
1890 o += 1;
1891 proto_tree_add_item(tree, hf_reserved, tvb, o, 4, ENC_BIG_ENDIAN);
1892 o += 4;
1893 if (trailer_ver >= 2) {
1894 proto_tree_add_item(tree, hf_priority, tvb, o, 1, ENC_BIG_ENDIAN);
1895 o += 1;
1897 if (trailer_ver >= 1) {
1898 if (rstcauselen) {
1899 proto_tree *rc_tree;
1900 proto_item *rc_item;
1901 uint64_t rstcauseval;
1902 uint64_t rstcauseline;
1903 unsigned startcause;
1904 uint8_t rstcausepeer;
1906 rc_item = proto_tree_add_item(tree, hf_rstcause, tvb, o, rstcauselen + 1, ENC_NA);
1907 rc_tree = proto_item_add_subtree(rc_item, ett_f5ethtrailer_rstcause);
1908 proto_tree_add_item(rc_tree, hf_rstcause_len, tvb, o, 1, ENC_BIG_ENDIAN);
1909 o += 1;
1911 startcause = o;
1912 switch (rstcausever) {
1913 case 0x00:
1914 rstcausepeer = tvb_get_uint8(tvb, o) & 0x1;
1916 proto_tree_add_item(rc_tree, hf_rstcause_ver, tvb, o, 1, ENC_BIG_ENDIAN);
1917 proto_tree_add_item(rc_tree, hf_rstcause_peer, tvb, o, 1, ENC_BIG_ENDIAN);
1918 o += 1;
1920 rstcauseval = tvb_get_ntoh64(tvb, o);
1921 rstcauseline = (rstcauseval & 0x000000000000ffffLL);
1922 rstcauseval = (rstcauseval & 0xffffffffffff0000LL) >> 16;
1923 proto_tree_add_uint64_format_value(rc_tree, hf_rstcause_val, tvb, o, 6,
1924 rstcauseval, "0x%012" PRIx64, rstcauseval);
1925 proto_tree_add_item(rc_tree, hf_rstcause_line, tvb, o + 6, 2, ENC_BIG_ENDIAN);
1926 o += 8;
1928 proto_item_append_text(rc_item,
1929 ": [%" PRIx64 ":%" PRIu64 "]%s %s", rstcauseval,
1930 rstcauseline, rstcausepeer ? " {peer}" : "",
1931 tvb_get_string_enc(pinfo->pool, tvb, o,
1932 rstcauselen - (o - startcause), ENC_ASCII));
1933 proto_tree_add_item(rc_tree, hf_rstcause_txt, tvb, o,
1934 rstcauselen - (o - startcause), ENC_ASCII | ENC_NA);
1935 break;
1936 default:
1937 break;
1942 return trailer_length;
1943 } /* dissect_med_trailer() */
1945 /*---------------------------------------------------------------------------*/
1946 /* Low level trailers */
1948 * @brief Dissect old format "low" trailer TLV
1950 * @param tvb Pointer to the tvb to be processed
1951 * @param pinfo Pointer to packet_info struct
1952 * @param tree Pointer to protocol tree
1953 * @param offset Offset into the tvb where trailer begins
1954 * @param trailer_length Length of the trailer data to process
1955 * @param trailer_ver Version of the trailer detected
1956 * @param tdata Pointer to tap data structure
1957 * @return Number of btyes consumed
1959 static unsigned
1960 dissect_low_trailer(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset,
1961 uint8_t trailer_length, uint8_t trailer_ver, f5eth_tap_data_t *tdata)
1963 proto_item *pi = NULL;
1964 unsigned ingress;
1965 unsigned o;
1966 unsigned vipnamelen = VIP_NAME_LEN;
1967 unsigned slot_display = 0;
1968 int slot_display_field = -1;
1969 unsigned tmm;
1971 switch (trailer_ver) {
1972 case 0:
1973 if (trailer_length != F5_LOWV10_LEN && trailer_length != F5_LOWV94_LEN) {
1974 return 0;
1976 if (trailer_length == F5_LOWV94_LEN) {
1977 slot_display = tvb_get_uint8(tvb, offset + F5_OFF_LOW_SLOT);
1978 slot_display_field = hf_slot0;
1979 /* Analysis doesn't care about the virtual name, only populate if there is a tap
1980 * active */
1981 if (have_tap_listener(tap_f5ethtrailer)
1982 && tvb_get_uint8(tvb, offset + (F5_LOWV94_LEN - 16)) != 0) {
1983 tdata->virtual_name = tvb_get_string_enc(pinfo->pool, tvb,
1984 offset + (F5_LOWV94_LEN - 16), 16, ENC_ASCII);
1986 } else {
1987 slot_display = tvb_get_uint8(tvb, offset + F5_OFF_LOW_SLOT) + 1;
1988 slot_display_field = hf_slot1;
1989 /* Analysis doesn't care about the virtual name, only populate if there is a tap
1990 * active */
1991 if (have_tap_listener(tap_f5ethtrailer)
1992 && tvb_get_uint8(tvb, offset + (F5_LOWV10_LEN - 16)) != 0) {
1993 tdata->virtual_name = tvb_get_string_enc(pinfo->pool, tvb,
1994 offset + (F5_LOWV10_LEN - 16), 16, ENC_ASCII);
1997 break;
1998 case 1:
1999 if (trailer_length < F5_LOWV1_LENMIN) { /* too small */
2000 return 0;
2002 vipnamelen = tvb_get_uint8(tvb, offset + F5_LOWV1_LENMIN - 1);
2003 /* check size is valid */
2004 if (vipnamelen + F5_LOWV1_LENMIN != trailer_length) {
2005 return 0;
2007 slot_display = tvb_get_uint8(tvb, offset + F5_OFF_LOW_SLOT) + 1;
2008 slot_display_field = hf_slot1;
2009 /* Analysis doesn't care about the virtual name, only populate if there is a tap active
2011 if (vipnamelen > 0 && have_tap_listener(tap_f5ethtrailer)) {
2012 tdata->virtual_name = tvb_get_string_enc(pinfo->pool, tvb,
2013 offset + F5_LOWV1_LENMIN, vipnamelen, ENC_ASCII);
2015 break;
2016 default:
2017 return 0;
2020 ingress = tvb_get_uint8(tvb, offset + F5_OFF_LOW_ING);
2021 tdata->ingress = ingress == 0 ? 0 : 1;
2022 tmm = tvb_get_uint8(tvb, offset + F5_OFF_LOW_TMM);
2023 if (tmm < F5ETH_TAP_TMM_MAX && slot_display < F5ETH_TAP_SLOT_MAX) {
2024 tdata->tmm = tmm;
2025 tdata->slot = slot_display;
2027 /* Is the column visible? */
2028 if (pref_info_type != none) {
2029 f5eth_set_info_col(pinfo, ingress, slot_display, tmm);
2032 /* We do not need to do anything more if we don't have a tree and we are not performing
2033 * analysis and this is not v9.4. If v9.4, need to continue to get flow
2034 * information.*/
2035 if (pref_perform_analysis == false && tree == NULL
2036 && !(trailer_length == F5_LOWV94_LEN && trailer_ver == 0
2037 && have_tap_listener(tap_f5ethtrailer))) {
2038 return trailer_length;
2041 o = offset;
2042 o += render_f5_legacy_hdr(tvb, tree, o);
2044 /* Use special formatting here so that users do not have to filter on "IN"
2045 * and "OUT", but rather can continue to use typical boolean values. "IN"
2046 * and "OUT" are provided as convenience. */
2047 proto_tree_add_boolean_format_value(tree, hf_ingress, tvb, o, 1, ingress, "%s (%s)",
2048 tfs_get_true_false(ingress),
2049 tfs_get_string(ingress, &f5tfs_ing));
2050 o++;
2052 proto_tree_add_uint(tree, slot_display_field, tvb, o, 1, slot_display);
2053 o += 1;
2055 proto_tree_add_item(tree, hf_tmm, tvb, o, 1, ENC_BIG_ENDIAN);
2056 o += 1;
2057 if (trailer_length == F5_LOWV94_LEN && trailer_ver == 0) {
2058 /* In v9.4, flowIDs, flags and type are here in low */
2059 tdata->flow = tvb_get_ntohl(tvb, o);
2060 proto_tree_add_item(tree, hf_flow_id, tvb, o, 4, ENC_BIG_ENDIAN);
2061 pi = proto_tree_add_item(tree, hf_any_flow, tvb, o, 4, ENC_BIG_ENDIAN);
2062 proto_item_set_hidden(pi);
2063 o += 4;
2064 tdata->peer_flow = tvb_get_ntohl(tvb, o);
2065 proto_tree_add_item(tree, hf_peer_id, tvb, o, 4, ENC_BIG_ENDIAN);
2066 pi = proto_tree_add_item(tree, hf_any_flow, tvb, o, 4, ENC_BIG_ENDIAN);
2067 proto_item_set_hidden(pi);
2068 o += 4;
2069 tdata->flows_set = 1;
2070 proto_tree_add_item(tree, hf_cf_flags, tvb, o, 4, ENC_BIG_ENDIAN);
2071 o += 4;
2072 proto_tree_add_item(tree, hf_flow_type, tvb, o, 1, ENC_BIG_ENDIAN);
2073 o += 1;
2076 /* We do not need to do anything more if we don't have a tree */
2077 /* Needed to get here so that analysis will work. */
2078 if (tree == NULL)
2079 return trailer_length;
2081 if (trailer_ver == 1) {
2082 pi = proto_tree_add_item(tree, hf_vipnamelen, tvb, o, 1, ENC_BIG_ENDIAN);
2083 proto_item_set_hidden(pi);
2084 o += 1;
2086 pi = proto_tree_add_item(tree, hf_vip, tvb, o, vipnamelen, ENC_ASCII | ENC_NA);
2087 proto_item_prepend_text(pi, "VIP ");
2089 return trailer_length;
2090 } /* dissect_low_trailer() */
2093 * @brief Render a header tree for new format tlvs
2095 * @param tvb Pointer to tvb
2096 * @param tree Pointer to protocol tree
2097 * @param offset Offset into the tvb
2099 static void
2100 render_f5dptv1_tlvhdr(tvbuff_t *tvb, proto_tree *tree, int offset)
2102 proto_item *pi = NULL;
2103 uint32_t provider;
2104 uint32_t type;
2106 pi = proto_tree_add_item(tree, hf_trailer_hdr, tvb, offset, F5_DPT_V1_TLV_HDR_LEN, ENC_NA);
2107 tree = proto_item_add_subtree(pi, ett_f5ethtrailer_trailer_hdr);
2109 proto_tree_add_item_ret_uint(tree, hf_provider, tvb, offset + F5_DPT_V1_TLV_PROVIDER_OFF,
2110 F5_DPT_V1_TLV_PROVIDER_LEN, ENC_BIG_ENDIAN, &provider);
2111 proto_item_append_text(pi, ", Provider: %u", provider);
2112 proto_tree_add_item_ret_uint(tree, hf_type, tvb, offset + F5_DPT_V1_TLV_TYPE_OFF,
2113 F5_DPT_V1_TLV_TYPE_LEN, ENC_BIG_ENDIAN, &type);
2114 proto_item_append_text(pi, ", Type: %u", type);
2115 proto_tree_add_item(tree, hf_length, tvb, offset + F5_DPT_V1_TLV_LENGTH_OFF,
2116 F5_DPT_V1_TLV_LENGTH_LEN, ENC_BIG_ENDIAN);
2117 proto_tree_add_item(tree, hf_version, tvb, offset + F5_DPT_V1_TLV_VERSION_OFF,
2118 F5_DPT_V1_TLV_VERSION_LEN, ENC_BIG_ENDIAN);
2119 } /* render_f5dptv1_tlvhdr() */
2121 /*---------------------------------------------------------------------------*/
2123 * @brief Render the data for DPT high noise trailer TLV
2125 * @param tvb The tvbuff containing the TLV block (header and data)
2126 * @param pinfo The pinfo structure for the frame
2127 * @param tree The tree to render the TVB under
2128 * @param data Pointer to tdata for the trailer
2129 * @return The size of the TVB
2131 static int
2132 dissect_dpt_trailer_noise_high(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data)
2134 proto_item *pi;
2135 int o;
2136 int len;
2137 int ver;
2138 uint8_t ipproto;
2139 f5eth_tap_data_t *tdata = (f5eth_tap_data_t *)data;
2141 DISSECTOR_ASSERT(tdata != NULL);
2142 len = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_LENGTH_OFF);
2143 ver = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_VERSION_OFF);
2145 /* Unknown version, cannot do anything */
2146 if (ver != 1) {
2147 return 0;
2150 if (tree == NULL) {
2151 /* We do not need to do anything if we do not have a tree */
2152 return len;
2155 pi = proto_tree_add_item(tree, hf_high_id, tvb, 0, len, ENC_NA);
2156 tree = proto_item_add_subtree(pi, ett_f5ethtrailer_high);
2158 render_f5dptv1_tlvhdr(tvb, tree, 0);
2160 o = F5_DPT_V1_TLV_HDR_LEN;
2161 tdata->noise_high = 1;
2163 /* If there was no peer id in the medium trailer, then there is no peer flow information to
2164 * render; skip it all.
2166 if (tdata->peer_flow == 0) {
2167 proto_tree_add_item(tree, hf_peer_nopeer, tvb, o, len - o, ENC_NA);
2168 return len;
2171 /* Add in the high order structures. */
2172 ipproto = tvb_get_uint8(tvb, o);
2173 proto_tree_add_item(tree, hf_peer_ipproto, tvb, o, 1, ENC_BIG_ENDIAN);
2174 o += 1;
2175 proto_tree_add_item(tree, hf_peer_vlan, tvb, o, 2, ENC_BIG_ENDIAN);
2176 o += 2;
2178 /* peer remote address */
2179 if (pref_pop_other_fields) {
2180 displayIPv6as4(tree, hf_ip_ipaddr, -1, tvb, o, true);
2181 pi = proto_tree_add_item(tree, hf_ip6_ip6addr, tvb, o, 16, ENC_NA);
2182 proto_item_set_hidden(pi);
2184 displayIPv6as4(tree, hf_peer_remote_addr, hf_peer_remote_rtdom, tvb, o, false);
2185 displayIPv6as4(tree, hf_peer_ipaddr, hf_peer_rtdom, tvb, o, true);
2186 proto_tree_add_item(tree, hf_peer_remote_ip6addr, tvb, o, 16, ENC_NA);
2187 pi = proto_tree_add_item(tree, hf_peer_ip6addr, tvb, o, 16, ENC_NA);
2188 proto_item_set_hidden(pi);
2189 o += 16;
2191 /* peer local address */
2192 if (pref_pop_other_fields) {
2193 displayIPv6as4(tree, hf_ip_ipaddr, -1, tvb, o, true);
2194 pi = proto_tree_add_item(tree, hf_ip6_ip6addr, tvb, o, 16, ENC_NA);
2195 proto_item_set_hidden(pi);
2197 displayIPv6as4(tree, hf_peer_local_addr, hf_peer_local_rtdom, tvb, o, false);
2198 displayIPv6as4(tree, hf_peer_ipaddr, hf_peer_rtdom, tvb, o, true);
2199 proto_tree_add_item(tree, hf_peer_local_ip6addr, tvb, o, 16, ENC_NA);
2200 pi = proto_tree_add_item(tree, hf_peer_ip6addr, tvb, o, 16, ENC_NA);
2201 proto_item_set_hidden(pi);
2202 o += 16;
2204 /* peer remote port */
2205 if (pref_pop_other_fields) {
2206 switch (ipproto) {
2207 case IP_PROTO_TCP:
2208 pi = proto_tree_add_item(tree, hf_tcp_tcpport, tvb, o, 2, ENC_BIG_ENDIAN);
2209 proto_item_set_hidden(pi);
2210 break;
2211 case IP_PROTO_UDP:
2212 pi = proto_tree_add_item(tree, hf_udp_udpport, tvb, o, 2, ENC_BIG_ENDIAN);
2213 proto_item_set_hidden(pi);
2214 break;
2217 proto_tree_add_item(tree, hf_peer_remote_port, tvb, o, 2, ENC_BIG_ENDIAN);
2218 pi = proto_tree_add_item(tree, hf_peer_port, tvb, o, 2, ENC_BIG_ENDIAN);
2219 proto_item_set_hidden(pi);
2220 o += 2;
2222 /* peer remote port */
2223 if (pref_pop_other_fields) {
2224 switch (ipproto) {
2225 case IP_PROTO_TCP:
2226 pi = proto_tree_add_item(tree, hf_tcp_tcpport, tvb, o, 2, ENC_BIG_ENDIAN);
2227 proto_item_set_hidden(pi);
2228 break;
2229 case IP_PROTO_UDP:
2230 pi = proto_tree_add_item(tree, hf_udp_udpport, tvb, o, 2, ENC_BIG_ENDIAN);
2231 proto_item_set_hidden(pi);
2232 break;
2235 proto_tree_add_item(tree, hf_peer_local_port, tvb, o, 2, ENC_BIG_ENDIAN);
2236 pi = proto_tree_add_item(tree, hf_peer_port, tvb, o, 2, ENC_BIG_ENDIAN);
2237 proto_item_set_hidden(pi);
2239 return len;
2240 } /* dissect_dpt_trailer_noise_high() */
2242 /*---------------------------------------------------------------------------*/
2244 * @brief Render the data for DPT medium noise trailer TVB
2246 * @param tvb The tvbuff containing the TLV block (header and data)
2247 * @param pinfo The pinfo structure for the frame
2248 * @param tree The tree to render the TVB under
2249 * @param data Pointer to tdata for the trailer
2250 * @return The size of the TVB
2252 static int
2253 dissect_dpt_trailer_noise_med(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2255 proto_item *pi;
2256 int o;
2257 int rstcauselen = 0;
2258 int badrstcauselen = 0;
2259 unsigned rstcausever = 0xff;
2260 int len;
2261 int ver;
2262 f5eth_tap_data_t *tdata = (f5eth_tap_data_t *)data;
2264 DISSECTOR_ASSERT(tdata != NULL);
2265 len = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_LENGTH_OFF);
2266 ver = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_VERSION_OFF);
2268 /* Unknown version, cannot do anything */
2269 if (ver != 4) {
2270 return 0;
2273 pi = proto_tree_add_item(tree, hf_med_id, tvb, 0, len, ENC_NA);
2274 tree = proto_item_add_subtree(pi, ett_f5ethtrailer_med);
2276 render_f5dptv1_tlvhdr(tvb, tree, 0);
2278 o = F5_DPT_V1_TLV_HDR_LEN;
2279 tdata->noise_med = 1;
2280 rstcauselen = tvb_get_uint8(tvb, o + F5_MEDV4_LENMIN - 1);
2281 /* Check for an invalid reset cause length and do not try to reference any of the data if it is
2282 * bad
2284 if (tvb_reported_length_remaining(tvb, o + F5_MEDV4_LENMIN) < rstcauselen) {
2285 badrstcauselen = 1;
2286 /* Set this to zero to prevent processing of things that utilze it */
2287 rstcauselen = 0;
2289 if (rstcauselen)
2290 rstcausever = (tvb_get_uint8(tvb, o + F5_MEDV4_LENMIN) & 0xfe) >> 1;
2291 /* If we want the RST cause in the summary, we need to do it here,
2292 * before the tree check below */
2293 if (rstcauselen && rstcause_in_info) {
2294 if (rstcausever == 0x00) {
2295 col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "[F5RST%s: %s]",
2296 tvb_get_uint8(tvb, o + F5_MEDV4_LENMIN) & 0x01 ? "(peer)" : "",
2297 tvb_get_string_enc(
2298 pinfo->pool, tvb, o + F5_MEDV4_LENMIN + 9, rstcauselen - 9, ENC_ASCII));
2302 /* We do not need to do anything more if we don't have a tree and we are not performing
2303 * analysis */
2304 if (pref_perform_analysis == false && tree == NULL)
2305 return len;
2307 tdata->flow = tvb_get_ntoh64(tvb, o);
2308 proto_tree_add_item(tree, hf_flow_id, tvb, o, 8, ENC_BIG_ENDIAN);
2309 pi = proto_tree_add_item(tree, hf_any_flow, tvb, o, 8, ENC_BIG_ENDIAN);
2310 proto_item_set_hidden(pi);
2311 o += 8;
2312 tdata->peer_flow = tvb_get_ntoh64(tvb, o);
2313 proto_tree_add_item(tree, hf_peer_id, tvb, o, 8, ENC_BIG_ENDIAN);
2314 pi = proto_tree_add_item(tree, hf_any_flow, tvb, o, 8, ENC_BIG_ENDIAN);
2315 proto_item_set_hidden(pi);
2316 o += 8;
2317 tdata->flows_set = 1;
2318 proto_tree_add_item(tree, hf_cf_flags2, tvb, o, 4, ENC_BIG_ENDIAN);
2319 o += 4;
2320 proto_tree_add_item(tree, hf_cf_flags, tvb, o, 4, ENC_BIG_ENDIAN);
2321 o += 4;
2322 proto_tree_add_item(tree, hf_flow_type, tvb, o, 1, ENC_BIG_ENDIAN);
2323 o += 1;
2325 /* We do not need to do anything if we don't have a tree */
2326 /* Needed to get here so that analysis and tap will work. */
2327 if (tree == NULL) {
2328 return len;
2331 proto_tree_add_item(tree, hf_ha_unit, tvb, o, 1, ENC_BIG_ENDIAN);
2332 o += 1;
2333 proto_tree_add_item(tree, hf_reserved, tvb, o, 4, ENC_BIG_ENDIAN);
2334 o += 4;
2335 proto_tree_add_item(tree, hf_priority, tvb, o, 1, ENC_BIG_ENDIAN);
2336 o += 1;
2337 if (badrstcauselen) {
2338 proto_tree *rc_tree;
2339 proto_item *rc_item;
2341 rc_item = proto_tree_add_item(tree, hf_rstcause, tvb, o, len - o, ENC_NA);
2342 rc_tree = proto_item_add_subtree(rc_item, ett_f5ethtrailer_rstcause);
2343 rc_item = proto_tree_add_item(rc_tree, hf_rstcause_len, tvb, o, 1, ENC_BIG_ENDIAN);
2344 expert_add_info(pinfo, rc_item, &ei_f5eth_badlen);
2345 } else if (rstcauselen) {
2346 proto_tree *rc_tree;
2347 proto_item *rc_item;
2348 uint64_t rstcauseval;
2349 uint64_t rstcauseline;
2350 unsigned startcause;
2351 uint8_t rstcausepeer;
2353 rc_item = proto_tree_add_item(tree, hf_rstcause, tvb, o, rstcauselen + 1, ENC_NA);
2354 rc_tree = proto_item_add_subtree(rc_item, ett_f5ethtrailer_rstcause);
2355 proto_tree_add_item(rc_tree, hf_rstcause_len, tvb, o, 1, ENC_BIG_ENDIAN);
2356 o += 1;
2358 startcause = o;
2359 switch (rstcausever) {
2360 case 0x00:
2361 rstcausepeer = tvb_get_uint8(tvb, o) & 0x1;
2362 proto_tree_add_item(rc_tree, hf_rstcause_ver, tvb, o, 1, ENC_BIG_ENDIAN);
2363 proto_tree_add_item(rc_tree, hf_rstcause_peer, tvb, o, 1, ENC_BIG_ENDIAN);
2364 o += 1;
2366 rstcauseval = tvb_get_ntoh64(tvb, o);
2367 rstcauseline = (rstcauseval & 0x000000000000ffffLL);
2368 rstcauseval = (rstcauseval & 0xffffffffffff0000LL) >> 16;
2369 proto_tree_add_uint64_format_value(rc_tree, hf_rstcause_val, tvb, o, 6, rstcauseval,
2370 "0x%012" PRIx64, rstcauseval);
2371 proto_tree_add_item(rc_tree, hf_rstcause_line, tvb, o + 6, 2, ENC_BIG_ENDIAN);
2372 o += 8;
2374 proto_item_append_text(rc_item,
2375 ": [%" PRIx64 ":%" PRIu64 "]%s %s", rstcauseval,
2376 rstcauseline, rstcausepeer ? " {peer}" : "",
2377 tvb_get_string_enc(
2378 pinfo->pool, tvb, o, rstcauselen - (o - startcause), ENC_ASCII));
2379 proto_tree_add_item(rc_tree, hf_rstcause_txt, tvb, o,
2380 rstcauselen - (o - startcause), ENC_ASCII | ENC_NA);
2381 /*o = startcause + rstcauselen;*/
2382 break;
2383 default:
2384 break;
2387 return len;
2388 } /* dissect_dpt_trailer_noise_med() */
2390 static const value_string f5_obj_data_types[] = {
2391 {0, "Virtual Server"},
2392 {1, "Port"},
2393 {2, "Trunk"},
2394 {255, "Unknown"},
2395 {0, NULL}
2398 /*---------------------------------------------------------------------------*/
2400 * @brief Render the data for DPT low noise trailer TVB
2402 * @param tvb The tvbuff containing the TLV block (header and data)
2403 * @param pinfo The pinfo structure for the frame
2404 * @param tree The tree to render the TVB under
2405 * @param data Pointer to tdata for the trailer
2406 * @return The size of the TVB
2408 static int
2409 dissect_dpt_trailer_noise_low(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2411 int len;
2412 int ver;
2413 proto_item *pi;
2414 proto_item *ti;
2415 int offset;
2416 unsigned flags;
2417 unsigned ingress;
2418 unsigned slot_display = 0;
2419 unsigned tmm;
2420 f5eth_tap_data_t *tdata = (f5eth_tap_data_t *)data;
2422 DISSECTOR_ASSERT(tdata != NULL);
2423 len = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_LENGTH_OFF);
2424 ver = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_VERSION_OFF);
2426 /* Unknown version, cannot do anything */
2427 if (ver < 2 || ver > 4) {
2428 return 0;
2431 /* Add the Low Noise trailer and attach a subtree */
2432 pi = proto_tree_add_item(tree, hf_low_id, tvb, 0, len, ENC_NA);
2433 tree = proto_item_add_subtree(pi, ett_f5ethtrailer_low);
2435 render_f5dptv1_tlvhdr(tvb, tree, 0);
2437 offset = F5_DPT_V1_TLV_HDR_LEN;
2438 tdata->noise_low = 1;
2440 /* Direction */
2441 flags = tvb_get_uint8(tvb, offset);
2442 if (ver == 2) {
2443 ingress = flags;
2444 } else {
2445 ingress = flags & F5_LOW_FLAGS_INGRESS_MASK;
2447 /* Use special formatting here so that users do not have to filter on "IN"
2448 * and "OUT", but rather can continue to use typical boolean values. "IN"
2449 * and "OUT" are provided as convenience. */
2450 pi = proto_tree_add_boolean_format_value(tree, hf_ingress, tvb, offset, 1, ingress,
2451 "%s (%s)", tfs_get_true_false(ingress),
2452 tfs_get_string(ingress, &f5tfs_ing));
2453 if (ver > 2) {
2454 /* The old ingress field is now a flag field. Leave the old ingress field
2455 * for backward compatibility for users that are accustomed to using
2456 * "f5ethtrailer.ingress" but mark it as generated to indicate that that
2457 * field no longer really exists. */
2458 proto_item_set_generated(pi);
2459 proto_tree_add_bitmask(
2460 tree, tvb, offset, hf_flags, ett_f5ethtrailer_low_flags, hf_flags__fields,
2461 ENC_BIG_ENDIAN);
2463 tdata->ingress = ingress == 0 ? 0 : 1;
2464 offset += 1;
2466 /* Slot */
2467 slot_display = tvb_get_uint8(tvb, offset) + 1;
2468 proto_tree_add_uint(tree, hf_slot1, tvb, offset, 1, slot_display);
2469 offset += 1;
2471 /* TMM */
2472 tmm = tvb_get_uint8(tvb, offset);
2473 if (tmm < F5ETH_TAP_TMM_MAX && slot_display < F5ETH_TAP_SLOT_MAX) {
2474 tdata->tmm = tmm;
2475 tdata->slot = slot_display;
2477 proto_tree_add_item(tree, hf_tmm, tvb, offset, 1, ENC_BIG_ENDIAN);
2478 offset += 1;
2480 /* Is the column visible? */
2481 if (pref_info_type != none) {
2482 f5eth_set_info_col(pinfo, ingress, slot_display, tmm);
2485 if (ver < 4) { /* Low noise versions 2 and 3 */
2486 /* VIP Name */
2487 int viplen = tvb_get_uint8(tvb, offset);
2488 /* Make sure VIP Name Length does not extend past the TVB */
2489 if (tvb_reported_length_remaining(tvb, offset) < viplen) {
2490 pi = proto_tree_add_item(tree, hf_vip, tvb, offset, 0, ENC_ASCII);
2491 expert_add_info(pinfo, pi, &ei_f5eth_badlen);
2492 /* Cannot go any further */
2493 return len;
2495 char *text = tvb_format_text(pinfo->pool, tvb, offset +1, viplen);
2496 ti = proto_tree_add_subtree_format(
2497 tree, tvb, offset, viplen + 1, ett_f5ethtrailer_obj_names, NULL,
2498 "Virtual Server: %s", text);
2499 proto_tree_add_item(ti, hf_vipnamelen, tvb, offset, 1, ENC_BIG_ENDIAN);
2500 offset += 1;
2501 proto_tree_add_item(ti, hf_vip, tvb, offset, viplen, ENC_ASCII);
2502 if (viplen > 0 && have_tap_listener(tap_f5ethtrailer)) {
2503 tdata->virtual_name = text;
2505 offset += viplen;
2506 } else { /* Low noise version 4 */
2507 /* This area now is a data block containing a number of BIG-IP config object names
2508 * i.e. Virtual server that handled the packt
2509 * Port that handled the packet
2510 * Trunk that handled the packet
2512 * 1-Byte Length of block (excluding this byte)
2513 * len-Bytes data block
2514 * <len><data block...>
2516 * Then the "data block" is a variable number of object names
2517 * Each name value is:
2518 * 1-Byte Type
2519 * 1-Byte Length (excluding type and length bytes)
2520 * len-Bytes String
2521 * <type><len><string><type><len><string>
2524 int data_len = tvb_get_int8(tvb, offset);
2525 pi = proto_tree_add_item(tree, hf_data, tvb, offset, 1, ENC_NA);
2526 proto_item_set_text(pi, "Associated config object names");
2527 ti = proto_item_add_subtree(pi, ett_f5ethtrailer_obj_names);
2528 proto_tree_add_item(ti, hf_obj_data_len, tvb, offset, 1, ENC_BIG_ENDIAN);
2529 offset += 1;
2530 if (tvb_reported_length_remaining(tvb, offset) < data_len) {
2531 expert_add_info(pinfo, pi, &ei_f5eth_badlen);
2532 /* Cannot go any further */
2533 return len;
2535 proto_item_set_len(pi, data_len + 1);
2537 /* Begin parsing the data field and adding items for the strings contained */
2538 tvbuff_t *data_tvb = tvb_new_subset_length(tvb, offset, data_len);
2539 int data_off = 0;
2541 while (data_off < data_len) {
2542 int field_name_len_idx;
2543 int field_name_idx;
2544 char *text_format;
2545 uint8_t t = tvb_get_uint8(data_tvb, data_off);
2546 uint8_t l = tvb_get_uint8(data_tvb, data_off + 1);
2548 switch (t) {
2549 case 0: /* Virtual Server */
2550 field_name_len_idx = hf_vipnamelen;
2551 field_name_idx = hf_vip;
2552 text_format = "Virtual Server: %s";
2553 break;
2554 case 1: /* Port */
2555 field_name_len_idx = hf_portnamelen;
2556 field_name_idx = hf_phys_port;
2557 text_format = "Port: %s";
2558 break;
2559 case 2: /* Trunk */
2560 field_name_len_idx = hf_trunknamelen;
2561 field_name_idx = hf_trunk;
2562 text_format = "Trunk: %s";
2563 break;
2564 default:
2565 /* unknown type */
2566 t = 255; /* Unknown */
2567 field_name_len_idx = hf_obj_data_len;
2568 field_name_idx = hf_data_str;
2569 text_format = "Unknown type";
2570 break;
2573 if (tvb_reported_length_remaining(data_tvb, data_off + 2) < l) {
2574 ti = proto_tree_add_subtree_format(
2575 tree, data_tvb, data_off, 2, ett_f5ethtrailer_obj_names, NULL,
2576 text_format, "");
2577 proto_tree_add_item(ti, hf_obj_name_type, data_tvb, data_off, 1, ENC_BIG_ENDIAN);
2578 pi = proto_tree_add_item(
2579 ti, field_name_len_idx, data_tvb, data_off + 1, 1, ENC_BIG_ENDIAN);
2580 expert_add_info(pinfo, pi, &ei_f5eth_badlen);
2581 /* Cannot go any further */
2582 return len;
2584 char *text = tvb_format_text(pinfo->pool, data_tvb, data_off + 2, l);
2585 ti = proto_tree_add_subtree_format(
2586 tree, data_tvb, data_off, l + 2, ett_f5ethtrailer_obj_names, NULL,
2587 text_format, text);
2588 pi = proto_tree_add_item(ti, hf_obj_name_type, data_tvb, data_off, 1, ENC_BIG_ENDIAN);
2589 if (t == 255) {
2590 expert_add_info(pinfo, pi, &ei_f5eth_undecoded);
2592 proto_tree_add_item(ti, field_name_len_idx, data_tvb, data_off + 1, 1, ENC_BIG_ENDIAN);
2593 proto_tree_add_item(ti, field_name_idx, data_tvb, data_off + 2, l, ENC_ASCII|ENC_NA);
2594 if (t == 0 && l > 0 && have_tap_listener(tap_f5ethtrailer)) {
2595 tdata->virtual_name = text;
2597 data_off += l + 2;
2599 offset += data_off;
2601 return offset;
2602 } /* dissect_dpt_trailer_noise_low() */
2604 /*---------------------------------------------------------------------------*/
2606 * @brief Render the data for DPT noise provider TVB
2608 * @param tvb The tvbuff containing the packet data for this TLV
2609 * @param pinfo The pinfo structure for the frame
2610 * @param tree The tree to render the TVB under
2611 * @param data Pointer to tdata for the trailer
2612 * @return The size of the TVB
2614 static int
2615 dissect_dpt_trailer_noise(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2617 uint32_t pattern;
2618 pattern = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_TYPE_OFF) << 16
2619 | tvb_get_ntohs(tvb, F5_DPT_V1_TLV_VERSION_OFF);
2620 return (
2621 dissector_try_uint_with_data(noise_subdissector_table, pattern, tvb, pinfo, tree, false, data));
2622 } /* dissect_dpt_trailer_noise() */
2624 /*---------------------------------------------------------------------------*/
2626 * @brief Render the data for DPT TVB for an unknown provider
2628 * @param tvb The tvbuff containing the packet data for this DPT
2629 * @param pinfo The pinfo structure for the frame
2630 * @param tree The tree to render the TVB under
2631 * @param data Pointer to tdata for the trailer
2632 * @return The size of the TVB
2634 static int
2635 dissect_dpt_trailer_unknown(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
2637 proto_item *pi;
2638 int len;
2640 len = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_LENGTH_OFF);
2642 if (tree) {
2643 pi = proto_tree_add_item(tree, hf_dpt_unknown, tvb, 0, len, ENC_NA);
2644 tree = proto_item_add_subtree(pi, ett_f5ethtrailer_unknown);
2646 render_f5dptv1_tlvhdr(tvb, tree, 0);
2648 proto_tree_add_item(
2649 tree, hf_data, tvb, F5_DPT_V1_TLV_HDR_LEN, len - F5_DPT_V1_TLV_HDR_LEN, ENC_NA);
2652 return len;
2653 } /* dissect_dpt_trailer_unknown() */
2655 /*---------------------------------------------------------------------------*/
2657 * @brief Render the data for DPT block
2659 * There is no predetermined or guaranteed order the DPT TLVs will be
2660 * attached to the frame. Use conversation data to coalesce information
2661 * across TLVs and frames.
2663 * @param tvb The tvbuff containing the packet data for this DPT block
2664 * @param pinfo The pinfo structure for the frame
2665 * @param tree The tree to render the DPT block in
2666 * @param data Pointer to tdata for the trailer
2667 * @return The size of the DPT block
2669 static int
2670 dissect_dpt_trailer(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2672 proto_item *pi;
2673 proto_tree *hdr_tree;
2674 int dpt_len;
2675 int dpt_ver;
2676 int o; /* offset*/
2678 dpt_len = tvb_get_ntohs(tvb, F5_DPT_V1_HDR_LENGTH_OFF);
2679 dpt_ver = tvb_get_ntohs(tvb, F5_DPT_V1_HDR_VERSION_OFF);
2681 /* Render the DPT header */
2682 pi = proto_tree_add_item(tree, hf_trailer_hdr, tvb, 0, F5_DPT_V1_TLV_HDR_LEN, ENC_NA);
2683 proto_item_append_text(pi, " - Version: %d", dpt_ver);
2684 hdr_tree = proto_item_add_subtree(pi, ett_f5ethtrailer_trailer_hdr);
2686 proto_tree_add_item(hdr_tree, hf_dpt_magic, tvb, F5_DPT_V1_HDR_MAGIC_OFF,
2687 F5_DPT_V1_HDR_MAGIC_LEN, ENC_BIG_ENDIAN);
2688 proto_tree_add_item(hdr_tree, hf_dpt_len, tvb, F5_DPT_V1_HDR_LENGTH_OFF,
2689 F5_DPT_V1_HDR_LENGTH_LEN, ENC_BIG_ENDIAN);
2690 proto_tree_add_item(hdr_tree, hf_dpt_ver, tvb, F5_DPT_V1_HDR_VERSION_OFF,
2691 F5_DPT_V1_HDR_VERSION_LEN, ENC_BIG_ENDIAN);
2693 /* If this is an unknown version, return after rendering header and data */
2694 if (dpt_ver < F5_DPT_V1_HDR_VERSION_MIN || dpt_ver > F5_DPT_V1_HDR_VERSION_MAX) {
2695 proto_tree_add_item(
2696 tree, hf_data, tvb, F5_DPT_V1_HDR_LEN, dpt_len - F5_DPT_V1_HDR_LEN, ENC_NA);
2697 return dpt_len;
2700 o = F5_DPT_V1_HDR_LEN;
2702 while (tvb_reported_length_remaining(tvb, o) >= F5_DPT_V1_TLV_HDR_LEN) {
2703 tvbuff_t *tvb_dpt_tlv;
2704 int tvb_dpt_tlv_len;
2705 int provider_id;
2707 tvb_dpt_tlv_len = tvb_get_ntohs(tvb, o + F5_DPT_V1_TLV_LENGTH_OFF);
2708 /* Report an error if the length specified in the header is either
2709 * Not long enough to contain the header
2710 * Indicates that the TLV is longer than the data that would have been captured.
2712 if (tvb_dpt_tlv_len < F5_DPT_V1_TLV_HDR_LEN
2713 || tvb_dpt_tlv_len > tvb_reported_length_remaining(tvb, o)) {
2714 proto_tree *subtree;
2715 pi = proto_tree_add_item(tree, hf_dpt_unknown, tvb, o, F5_DPT_V1_TLV_HDR_LEN, ENC_NA);
2716 subtree = proto_item_add_subtree(pi, ett_f5ethtrailer_unknown);
2717 proto_tree_add_item(subtree, hf_provider, tvb, o + F5_DPT_V1_TLV_PROVIDER_OFF,
2718 F5_DPT_V1_TLV_PROVIDER_LEN, ENC_BIG_ENDIAN);
2719 proto_tree_add_item(subtree, hf_type, tvb, o + F5_DPT_V1_TLV_TYPE_OFF,
2720 F5_DPT_V1_TLV_TYPE_LEN, ENC_BIG_ENDIAN);
2721 pi = proto_tree_add_item(subtree, hf_length, tvb, o + F5_DPT_V1_TLV_LENGTH_OFF,
2722 F5_DPT_V1_TLV_LENGTH_LEN, ENC_BIG_ENDIAN);
2723 expert_add_info(pinfo, pi, &ei_f5eth_badlen);
2724 if (tvb_dpt_tlv_len >= F5_DPT_V1_TLV_HDR_LEN) {
2725 proto_tree_add_item(subtree, hf_version, tvb, o + F5_DPT_V1_TLV_VERSION_OFF,
2726 F5_DPT_V1_TLV_VERSION_LEN, ENC_BIG_ENDIAN);
2728 /* If the length here is bad, then we probably will not index to the next TLV, so
2729 * abort and do not try to render anymore TLVs.
2731 break;
2733 provider_id = tvb_get_ntohs(tvb, o + F5_DPT_V1_TLV_PROVIDER_OFF);
2734 tvb_dpt_tlv = tvb_new_subset_length(tvb, o, tvb_dpt_tlv_len);
2735 if (dissector_try_uint_with_data(
2736 provider_subdissector_table, provider_id, tvb_dpt_tlv, pinfo, tree, false, data)
2737 == 0) {
2738 /* Render the TLV header as unknown */
2739 dissect_dpt_trailer_unknown(tvb_dpt_tlv, pinfo, tree, data);
2741 o += tvb_dpt_tlv_len;
2744 return dpt_len;
2745 } /* dissect_dpt_trailer() */
2747 /*---------------------------------------------------------------------------*/
2749 * @brief Dissect the old format trailers (9.4.2 - 13.x)
2751 * @param tvb The tvbuff containing the packet data for this trailer
2752 * @param pinfo The pinfo structure for the frame
2753 * @param tree The tree to render the thrailer under
2754 * @param data Pointer to tdata for the trailer
2755 * @return int Number of bytes cosumed by the dissector
2757 static int
2758 dissect_old_trailer(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2760 unsigned offset = 0;
2762 /* While we still have data in the trailer. For old format trailers, this needs
2763 * type, length, version (3 bytes) and for new format trailers, the magic header (4 bytes).
2764 * All old format trailers are at least 4 bytes long, so just check for length of magic.
2766 while (tvb_reported_length_remaining(tvb, offset) >= F5_MIN_SANE) {
2767 /* length field does not include the type and length bytes. Add them back in */
2768 uint8_t len = tvb_get_uint8(tvb, offset + F5_OFF_LENGTH) + F5_OFF_VERSION;
2769 if (len > tvb_reported_length_remaining(tvb, offset)
2770 || len < F5_MIN_SANE || len > F5_MAX_SANE) {
2771 /* Invalid length - either a malformed trailer, corrupt packet, or not f5ethtrailer */
2772 return offset;
2774 uint8_t type = tvb_get_uint8(tvb, offset);
2775 uint8_t ver = tvb_get_uint8(tvb, offset + F5_OFF_VERSION);
2777 /* Parse out the specified trailer. */
2778 proto_tree *type_tree = NULL;
2779 proto_item *ti = NULL;
2780 f5eth_tap_data_t *tdata = (f5eth_tap_data_t *)data;
2781 unsigned processed = 0;
2783 switch (type) {
2784 case F5TYPE_LOW:
2785 ti = proto_tree_add_item(tree, hf_low_id, tvb, offset, len, ENC_NA);
2786 type_tree = proto_item_add_subtree(ti, ett_f5ethtrailer_low);
2788 processed = dissect_low_trailer(tvb, pinfo, type_tree, offset, len, ver, tdata);
2789 if (processed > 0) {
2790 tdata->trailer_len += processed;
2791 tdata->noise_low = 1;
2793 break;
2794 case F5TYPE_MED:
2795 ti = proto_tree_add_item(tree, hf_med_id, tvb, offset, len, ENC_NA);
2796 type_tree = proto_item_add_subtree(ti, ett_f5ethtrailer_med);
2798 processed = dissect_med_trailer(tvb, pinfo, type_tree, offset, len, ver, tdata);
2799 if (processed > 0) {
2800 tdata->trailer_len += processed;
2801 tdata->noise_med = 1;
2803 break;
2804 case F5TYPE_HIGH:
2805 ti = proto_tree_add_item(tree, hf_high_id, tvb, offset, len, ENC_NA);
2806 type_tree = proto_item_add_subtree(ti, ett_f5ethtrailer_high);
2808 processed =
2809 dissect_high_trailer(tvb, pinfo, type_tree, offset, len, ver, tdata);
2810 if (processed > 0) {
2811 tdata->trailer_len += processed;
2812 tdata->noise_high = 1;
2814 break;
2815 default:
2816 /* Unknown type - malformed trailer, corrupt packet, or not f5ethtrailer - bali out*/
2817 return offset;
2819 if (processed == 0) {
2820 /* couldn't process trailer - bali out */
2821 proto_item_set_len(ti, 1);
2822 return offset;
2824 offset += processed;
2826 return offset;
2827 } /* dissect_old_trailer() */
2829 /*---------------------------------------------------------------------------*/
2831 * @brief Dissector entry point
2833 * @param tvb The tvbuff containing the packet data for this trailer
2834 * @param pinfo The pinfo structure for the frame
2835 * @param tree The tree to render the thrailer under
2836 * @param data Pointer to tdata for the trailer
2837 * @return int Number of bytes cosumed by the dissector
2839 * New format trailers (BIG-IP 14.0 and later) begin with
2840 * 4-byte magic number (0xf5deb0f5)
2841 * 2-byte trailer length (Length includes header)
2842 * 2-byte version
2843 * 1 or more variable length TLVs
2845 * Each New format TLV starts with
2846 * 2-byte Provider ID
2847 * 2-byte Type ID
2848 * 2-byte TLV Length (Length includes header)
2849 * 2-byte Version
2850 * (TLVlen - 8) bytes of data
2852 * Old format trailers (BIG-IP 9.4.2 - 13.x) were a list of variable length
2853 * TLVs.
2854 * 1-byte Type
2855 * 1-byte TLV Length (TLVlen does not include the type and length fields)
2856 * TLVlen bytes of data
2858 static int
2859 dissect_f5ethtrailer(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2861 unsigned trailer_length;
2862 unsigned offset = 0;
2863 found_t found = NONE;
2864 bool has_fcs = false;
2866 if (tvb_reported_length(tvb) != tvb_captured_length(tvb)) {
2867 /* The trailers are really only helpful if we have the entire trailer. If we
2868 don't, don't try to dissect it. */
2869 return 0;
2872 /* In some circumstances it is possible that a short ethernet frame was padded before tmm
2873 was able to append f5ethtrailer. In many cases (and should be) this padding is zeros.
2874 The f5ethtrailer does not start with a zero, so trim off any leading zeros before
2875 looking for an f5ethtrailer. */
2876 while (tvb_offset_exists(tvb, offset) && tvb_get_int8(tvb, offset) == 0) {
2877 offset++;
2880 trailer_length = tvb_reported_length_remaining(tvb, offset);
2881 if (trailer_length < F5_LOWV1_LENMIN) {
2882 /* There must be at least enough bytes for a legacy low ver1 trailer. New format
2883 trailers will be longer */
2884 return 0;
2887 while (found == NONE) {
2888 /* Check if this is a new format trailer. */
2889 if (trailer_length - offset >= F5_DPT_V1_HDR_MAGIC_LEN + F5_DPT_V1_HDR_LEN) {
2890 if (tvb_get_ntohl(tvb, offset) == F5_DPT_V1_HDR_MAGIC) {
2891 if (tvb_get_ntohs(tvb, offset + F5_DPT_V1_HDR_LENGTH_OFF) > trailer_length) {
2892 /* we have the right magic, but the length doesn't match up.
2893 assume we're not an f5ethtrailer, or it is corrupt.
2894 Either way, don't try and dissect. */
2895 return 0;
2897 /* Looks like a new format trailer */
2898 found = NEW_FORMAT;
2899 goto found_trailer;
2901 /* It's possible to have the trailer added after the FCS has already been added.
2902 Let's move in 4 bytes and check there. However, it is also possible for the FCS
2903 to start with a sequence of zeros that would have been already been skipped. If so,
2904 we need to back up. If there is an FCS display the Original.
2906 Only add this check for new format trailers. Old format trailers are becoming less
2907 common and likely wouldn't have been added after FCS anyway.
2908 If needed, the walk trailer prefernce would find the old format trailer after an FCS.
2909 This seems reasonable enough for old format trailers. */
2910 for (unsigned i = 0; i <= offset && i <= 4; i++) {
2911 if (tvb_get_ntohl(tvb, offset + 4 - i) == F5_DPT_V1_HDR_MAGIC) {
2912 if (tvb_get_ntohs(tvb, offset + 4 - i + F5_DPT_V1_HDR_LENGTH_OFF) > trailer_length) {
2913 return 0;
2915 found = NEW_FORMAT;
2916 has_fcs = true;
2917 offset += 4 - i;
2918 goto found_trailer;
2923 /* Not new format? Are we old format? */
2924 unsigned tlv_type, tlv_length, tlv_ver;
2926 /* Check for old format trailers */
2927 tlv_type = tvb_get_uint8(tvb, offset);
2928 tlv_length = tvb_get_uint8(tvb, offset + F5_OFF_LENGTH) + F5_OFF_VERSION;
2929 tlv_ver = tvb_get_uint8(tvb, offset + F5_OFF_VERSION);
2931 if ( tlv_length <= trailer_length && tlv_type >= F5TYPE_LOW && tlv_type <= F5TYPE_HIGH &&
2932 tlv_length >= F5_MIN_SANE && tlv_length <= F5_MAX_SANE &&
2933 tlv_ver <= F5TRAILER_VER_MAX) {
2934 /* Found at least one old format TLV */
2935 found = OLD_FORMAT;
2936 goto found_trailer;
2938 if (!pref_walk_trailer || tvb_reported_length_remaining(tvb, offset) <= F5_LOWV1_LENMIN)
2939 /* Didn't find an f5ethtrailer, and we're not going to keep looking. */
2940 return 0;
2942 offset++;
2945 found_trailer:
2947 /* Good to go, start dissection */
2948 f5eth_tap_data_t *tdata;
2949 proto_item *trailer_item = NULL;
2951 /* Initialize data structure for taps and analysis */
2952 tdata = wmem_new0(pinfo->pool, f5eth_tap_data_t);
2954 tdata->magic = F5ETH_TAP_MAGIC;
2955 tdata->slot = F5ETH_TAP_SLOT_MAX;
2956 tdata->tmm = F5ETH_TAP_TMM_MAX;
2958 if (tree) {
2959 trailer_item = proto_tree_add_item(tree, proto_f5ethtrailer, tvb, offset, -1, ENC_NA);
2960 tree = proto_item_add_subtree(trailer_item, ett_f5ethtrailer);
2961 if (has_fcs) {
2962 proto_tree_add_item(tree, hf_orig_fcs, tvb, offset - 4, 4, ENC_NA);
2966 if (found == NEW_FORMAT) {
2967 /* dissect new format trailer */
2968 trailer_length = dissect_dpt_trailer(tvb_new_subset_remaining(tvb, offset),
2969 pinfo, tree, tdata);
2970 } else {
2971 /* dissect old format trailer */
2972 trailer_length = dissect_old_trailer(tvb_new_subset_remaining(tvb, offset),
2973 pinfo, tree, tdata);
2975 tdata->trailer_len = trailer_length;
2976 proto_item_set_len(trailer_item, trailer_length);
2978 /* If the analyis preference is enabled, process it */
2979 if (pref_perform_analysis) {
2980 struct f5eth_analysis_data_t *ad;
2982 /* Get the analysis data information for this packet */
2983 ad = (struct f5eth_analysis_data_t *)p_get_proto_data(
2984 wmem_file_scope(), pinfo, proto_f5ethtrailer, 0);
2985 if (ad == NULL) {
2986 ad = new_f5eth_analysis_data_t();
2987 p_add_proto_data(wmem_file_scope(), pinfo, proto_f5ethtrailer, 0, ad);
2989 if (ad->analysis_done == 0) {
2990 ad->pkt_ingress = tdata->ingress;
2991 if (tdata->flows_set == 1) {
2992 ad->pkt_has_flow = tdata->flow == 0 ? 0 : 1;
2993 ad->pkt_has_peer = tdata->peer_flow == 0 ? 0 : 1;
2995 /* Only perform the analysis if we had an opportunity to get the TCP information. In
2996 * this case, if the ip tap ran then they all should have run. We use IP so we don't
2997 * perform analysis every time we visit a UDP/ICMP, etc. packet. */
2998 if (ad->ip_visited)
2999 perform_analysis(ad);
3001 render_analysis(tvb, pinfo, tree, ad);
3004 /* Call tap handlers if it appears that we got enough data
3005 * (should have low noise if there is anything) */
3006 if (tdata->noise_low != 0) {
3007 tap_queue_packet(tap_f5ethtrailer, pinfo, tdata);
3009 return trailer_length;
3010 } /* dissect_f5ethtrailer() */
3012 static bool
3013 dissect_f5ethtrailer_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
3015 return dissect_f5ethtrailer(tvb, pinfo, tree, data) > 0;
3018 /*-----------------------------------------------------------------------------------------------*/
3019 /* Begin DPT TLS provider */
3020 /*-----------------------------------------------------------------------------------------------*/
3021 /* We want to be able to render TLS diagnostic data that is available and
3022 * generate keylog entries for later decryption use. We are not making
3023 * decisions about RFC compliance or functional correctness of the TLS
3024 * data here. If data is there, we will render it. If a keylog entry
3025 * can be generated we will generate it even if it is wrong.
3027 * The diagnostic information provided in F5 Ethernet trailers is state information
3028 * inteded for troubleshooting and diagnostics. This data is not sent on the wire.
3029 * It is only appended to frames captured on the BIG-IP, if explicitly requested. As
3030 * such if the data exists in the context, it will be appended to each packet with a
3031 * TLS layer. Filtering of duplicate / appropriate data and interpretation is left
3032 * to the dissector.
3034 * This will result in things like the TLS dissector displaying the client random
3035 * in the CLIENT HELLO packet, while the F5 Ethtrailer TLS shows all zeros for the
3036 * client random. Then the F5 Ethtrailer will provide the client random in the
3037 * ACK to the CLIENT HELLO. It will also result in the same information being
3038 * provided on multiple packets.
3040 * All the necessary parts to create a valid keylog record needed for decryption
3041 * may not be available in the same frame.
3044 #define F5_DPT_PROVIDER_TLS 4
3046 /* PRE13 in this context indicates pre TLS-v1.3, not pre-standard (draft) TLS-v1.3. i.e. TLS-v1.2 and earlier */
3047 #define F5_DPT_TLS_PRE13_STD 0
3048 #define F5_DPT_TLS_PRE13_EXT 1
3049 #define F5_DPT_TLS_13_STD 2
3050 #define F5_DPT_TLS_13_EXT 3
3052 #define F5TLS_SECRET_LEN 48
3053 #define F5TLS_SESS_ID_LEN 32
3054 #define F5TLS_RANDOM_LEN 32
3055 #define F5TLS_HASH_LEN 64
3056 #define F5TLS_ZEROS_LEN 256
3057 #define F5TLS_T2V1_LEN 393
3059 typedef struct _F5TLS_ELEMENT {
3060 unsigned char *data; /* Pointer to a string of bytes wmem_file_scope allocated as needed. */
3061 int len; /* length of the item stored. */
3062 } f5tls_element_t;
3065 * As we come across the initial crypto data, store it in a struct on the conversation.
3067 typedef struct _F5TLS_CONVERSATION_DATA {
3068 f5tls_element_t master_secret;
3069 f5tls_element_t client_random;
3070 /* added by TLS 1.3 */
3071 f5tls_element_t erly_traf_sec;
3072 f5tls_element_t clnt_hs_sec;
3073 f5tls_element_t srvr_hs_sec;
3074 f5tls_element_t clnt_ap_sec;
3075 f5tls_element_t srvr_ap_sec;
3076 } f5tls_conversation_data_t;
3079 * As we collect enough information to create a keylog entry in the conversation data create
3080 * a field with the keylog entry on the first frame and store on the frame. This should limit
3081 * keylog entries to a unique list.
3083 typedef struct _F5TLS_PACKET_DATA {
3084 char *cr_ms;
3085 /* TLS 1.3 keylogs */
3086 char *cr_erly_traff;
3087 char *cr_clnt_app;
3088 char *cr_srvr_app;
3089 char *cr_clnt_hs;
3090 char *cr_srvr_hs;
3091 } f5tls_packet_data_t;
3093 typedef struct _F5TLS_DATA {
3094 f5tls_conversation_data_t *conv;
3095 f5tls_packet_data_t *pkt;
3096 } f5tls_data_t;
3098 static int proto_f5ethtrailer_dpt_tls;
3100 static int hf_f5tls_tls;
3102 /* TLS 1.x fields */
3103 static int hf_f5tls_secret_len;
3104 static int hf_f5tls_mstr_sec;
3105 static int hf_f5tls_clnt_rand;
3106 static int hf_f5tls_srvr_rand;
3108 /* TLS 1.3 fields */
3109 static int hf_f5tls_early_traffic_sec;
3110 static int hf_f5tls_clnt_hs_sec;
3111 static int hf_f5tls_srvr_hs_sec;
3112 static int hf_f5tls_clnt_app_sec;
3113 static int hf_f5tls_srvr_app_sec;
3114 static int hf_f5tls_keylog;
3116 static int ett_f5tls;
3117 static int ett_f5tls_std;
3118 static int ett_f5tls_ext;
3120 static dissector_table_t tls_subdissector_table;
3122 /* The types of keylog entries that could be created */
3123 typedef enum {
3124 CLIENT_RANDOM,
3125 CLIENT_TRAFFIC_SECRET_0,
3126 SERVER_TRAFFIC_SECRET_0,
3127 CLIENT_HANDSHAKE_TRAFFIC_SECRET,
3128 SERVER_HANDSHAKE_TRAFFIC_SECRET,
3129 EARLY_TRAFFIC_SECRET,
3130 } keylog_t;
3132 /* Create a field of zeros. We need to check if the secrets, randoms, etc are all zeros and memcmp
3133 * looks like the best way to do it. So, create a single, global field of zeros at file scope.
3134 * That should cut down on some overhead...
3136 static unsigned char f5tls_zeros[F5TLS_ZEROS_LEN];
3138 /*-----------------------------------------------------------------------*/
3139 /** Get a null terminated hexstring of a byte array
3141 * @param scope scope of the wmem allocate buffer
3142 * @param ba The byte aray to convert to a hexstring
3143 * @param ba_len Number of bytes to convert
3144 * @return Null terminated char* wmem allocated - no need to free
3146 static char *
3147 f5eth_bytes_to_hexstrnz(wmem_allocator_t *scope, const unsigned char *ba, int ba_len)
3149 char *hexstr;
3150 char *end;
3152 hexstr = (char *)wmem_alloc(scope, ba_len * 2 + 1);
3153 end = bytes_to_hexstr(hexstr, ba, ba_len);
3154 *end = '\0';
3155 return hexstr;
3156 } /* f5eth_bytes_to_hexstrnz */
3158 /*-----------------------------------------------------------------------------------------------*/
3160 * @brief Create a keylog entry and add it to the packet info
3162 * Keylog entries will be created as described in the tls dissector.
3163 * packet-tls-utils.c: tls_keylog_process_lines()
3165 * @param keylog_type Type of keylog record to generate
3166 * @param xxxx First crypto element in for keylog record (see above)
3167 * @param yyyy Second crypto element in the keylog record (see above)
3168 * @return Null terminated keylog record wmem allocated with file scope
3170 static char *
3171 f5eth_add_tls_keylog(packet_info *pinfo, keylog_t keylog_type, f5tls_element_t *xxxx, f5tls_element_t *yyyy)
3173 char *xxxx_hex;
3174 char *yyyy_hex;
3176 xxxx_hex = f5eth_bytes_to_hexstrnz(pinfo->pool, xxxx->data, xxxx->len);
3177 yyyy_hex = f5eth_bytes_to_hexstrnz(pinfo->pool, yyyy->data, yyyy->len);
3179 switch (keylog_type) {
3180 case CLIENT_RANDOM:
3181 return wmem_strdup_printf(wmem_file_scope(), "CLIENT_RANDOM %s %s", xxxx_hex, yyyy_hex);
3182 case CLIENT_TRAFFIC_SECRET_0:
3183 return wmem_strdup_printf(
3184 wmem_file_scope(), "CLIENT_TRAFFIC_SECRET_0 %s %s", xxxx_hex, yyyy_hex);
3185 case SERVER_TRAFFIC_SECRET_0:
3186 return wmem_strdup_printf(
3187 wmem_file_scope(), "SERVER_TRAFFIC_SECRET_0 %s %s", xxxx_hex, yyyy_hex);
3188 case CLIENT_HANDSHAKE_TRAFFIC_SECRET:
3189 return wmem_strdup_printf(
3190 wmem_file_scope(), "CLIENT_HANDSHAKE_TRAFFIC_SECRET %s %s", xxxx_hex, yyyy_hex);
3191 case SERVER_HANDSHAKE_TRAFFIC_SECRET:
3192 return wmem_strdup_printf(
3193 wmem_file_scope(), "SERVER_HANDSHAKE_TRAFFIC_SECRET %s %s", xxxx_hex, yyyy_hex);
3194 case EARLY_TRAFFIC_SECRET:
3195 return wmem_strdup_printf(
3196 wmem_file_scope(), "CLIENT_EARLY_TRAFFIC_SECRET %s %s", xxxx_hex, yyyy_hex);
3197 default:
3198 DISSECTOR_ASSERT_NOT_REACHED();
3200 } /* f5eth_add_tls_keylog() */
3202 /*-----------------------------------------------------------------------------------------------*/
3204 * @brief Process the data entries
3206 * @param element Pointer to crypto element
3207 * @param pinfo Packet info pointer (unused)
3208 * @param tvb tvb
3209 * @param offset Offset into the tvb to pull the entry
3210 * @param len Length of byte string to convert from the tvb
3211 * @return Is the entry different than previously seen
3213 static bool
3214 f5eth_add_tls_element(
3215 f5tls_element_t *element, packet_info *pinfo _U_, tvbuff_t *tvb, unsigned offset, int len)
3217 if (element == NULL || len <= 0 || tvb_memeql(tvb, offset, f5tls_zeros, len) == 0) {
3218 /* Nothing to do */
3219 return false;
3222 if (element->len == len && tvb_memeql(tvb, offset, element->data, len) == 0) {
3223 /* unchanged */
3224 return false;
3227 /* Populate the element structure */
3228 element->data = (unsigned char *)wmem_realloc(wmem_file_scope(), element->data, len);
3229 element->len = len;
3230 tvb_memcpy(tvb, element->data, offset, len);
3231 return true;
3233 } /* f5eth_add_tls_element() */
3235 /*----------------------------------------------------------------------*/
3236 /** TLS <= 1.2 trailer - Type 0
3238 * @param tvb The tvbuff containing the DPT TLV block (header and data).
3239 * @param pinfo The pinfo structure for the frame.
3240 * @param tree The tree to render the DPT TLV under.
3241 * @param data Structure pointing to conversation and packet proto data.
3242 * @return Number of bytes decoded.
3244 static int
3245 dissect_dpt_trailer_tls_type0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
3247 proto_item *pi;
3248 int len;
3249 int ver;
3250 int o;
3251 f5tls_conversation_data_t *conv_data = NULL;
3252 f5tls_packet_data_t *pdata = NULL;
3254 len = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_LENGTH_OFF);
3255 ver = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_VERSION_OFF);
3257 switch (ver) {
3258 case 0:
3259 /* Create a subtree and render a header */
3260 pi = proto_tree_add_item(tree, hf_f5tls_tls, tvb, 0, len, ENC_NA);
3261 tree = proto_item_add_subtree(pi, ett_f5tls_std);
3263 render_f5dptv1_tlvhdr(tvb, tree, 0);
3265 o = F5_DPT_V1_TLV_HDR_LEN;
3267 /* Add our fields */
3268 proto_tree_add_item(tree, hf_f5tls_mstr_sec, tvb, o, F5TLS_SECRET_LEN, ENC_NA);
3269 o += F5TLS_SECRET_LEN;
3270 proto_tree_add_item(tree, hf_f5tls_clnt_rand, tvb, o, F5TLS_RANDOM_LEN, ENC_NA);
3271 o += F5TLS_RANDOM_LEN;
3272 proto_tree_add_item(tree, hf_f5tls_srvr_rand, tvb, o, F5TLS_RANDOM_LEN, ENC_NA);
3273 /* o += F5TLS_RANDOM_LEN; */
3275 if (!pref_generate_keylog || data == NULL) {
3276 break;
3279 pdata = ((f5tls_data_t *)data)->pkt;
3280 conv_data = ((f5tls_data_t *)data)->conv;
3282 /* If this is our first pass through, add protocol data and build keylog entries.
3283 Assume that by the time the master secret is processed, the client random is
3284 available on the conversation data. */
3285 if (!pinfo->fd->visited) {
3286 bool ms_changed;
3288 ms_changed = f5eth_add_tls_element(
3289 &conv_data->master_secret, pinfo, tvb, F5_DPT_V1_TLV_HDR_LEN, F5TLS_SECRET_LEN);
3290 f5eth_add_tls_element(&conv_data->client_random, pinfo, tvb,
3291 F5_DPT_V1_TLV_HDR_LEN + F5TLS_SECRET_LEN, F5TLS_RANDOM_LEN);
3293 if (conv_data->client_random.len != 0 && ms_changed) {
3294 pdata->cr_ms = f5eth_add_tls_keylog(pinfo,
3295 CLIENT_RANDOM, &conv_data->client_random, &conv_data->master_secret);
3299 /* Display any keylog entries we have in our packet data */
3300 if (pdata->cr_ms != NULL) {
3301 pi = proto_tree_add_string(tree, hf_f5tls_keylog, tvb, 0, 0, pdata->cr_ms);
3302 proto_item_set_generated(pi);
3304 break;
3305 default:
3306 /* Unknown version */
3307 len = 0;
3308 break;
3310 return len;
3311 } /* dissect_dpt_trailer_tls_type0() */
3313 /*----------------------------------------------------------------------*/
3314 /** TLS 1.3 trailer - Type 2
3316 * @param tvb The tvbuff containing the DPT TLV block (header and data).
3317 * @param pinfo The pinfo structure for the frame.
3318 * @param tree The tree to render the DPT TLV under.
3319 * @param data Structure pointing to conversation and packet proto data.
3320 * @return Number of bytes decoded.
3322 static int
3323 dissect_dpt_trailer_tls_type2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
3325 proto_item *pi;
3326 int len;
3327 int ver;
3328 int o;
3329 int secret_len;
3330 f5tls_conversation_data_t *conv_data = NULL;
3331 f5tls_packet_data_t *pdata = NULL;
3333 len = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_LENGTH_OFF);
3334 ver = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_VERSION_OFF);
3336 switch (ver) {
3337 case 0:
3338 case 1:
3339 /* Create a subtree and render a header */
3340 pi = proto_tree_add_item(tree, hf_f5tls_tls, tvb, 0, len, ENC_NA);
3341 tree = proto_item_add_subtree(pi, ett_f5tls_std);
3343 render_f5dptv1_tlvhdr(tvb, tree, 0);
3345 o = F5_DPT_V1_TLV_HDR_LEN;
3347 secret_len = tvb_get_uint8(tvb, o);
3348 /* Add our fields */
3349 pi = proto_tree_add_item(tree, hf_f5tls_secret_len, tvb, o, 1, ENC_NA);
3350 o += 1;
3351 if (secret_len == 0) {
3352 /* nothing to render */
3353 break; /* switch (ver) */
3354 } else if (secret_len > F5TLS_HASH_LEN) {
3355 expert_add_info(pinfo, pi, &ei_f5eth_badlen);
3356 break; /* switch (ver) */
3357 } else {
3358 if (ver == 1) {
3359 proto_tree_add_item(tree, hf_f5tls_early_traffic_sec, tvb, o, secret_len, ENC_NA);
3360 o += F5TLS_HASH_LEN;
3361 } else if (ver == 0 && len == F5TLS_T2V1_LEN) {
3362 o += F5TLS_HASH_LEN;
3364 proto_tree_add_item(tree, hf_f5tls_clnt_hs_sec, tvb, o, secret_len, ENC_NA);
3365 o += F5TLS_HASH_LEN;
3366 proto_tree_add_item(tree, hf_f5tls_srvr_hs_sec, tvb, o, secret_len, ENC_NA);
3367 o += F5TLS_HASH_LEN;
3368 proto_tree_add_item(tree, hf_f5tls_clnt_app_sec, tvb, o, secret_len, ENC_NA);
3369 o += F5TLS_HASH_LEN;
3370 proto_tree_add_item(tree, hf_f5tls_srvr_app_sec, tvb, o, secret_len, ENC_NA);
3371 o += F5TLS_HASH_LEN;
3372 proto_tree_add_item(tree, hf_f5tls_clnt_rand, tvb, o, F5TLS_RANDOM_LEN, ENC_NA);
3373 o += F5TLS_RANDOM_LEN;
3374 proto_tree_add_item(tree, hf_f5tls_srvr_rand, tvb, o, F5TLS_RANDOM_LEN, ENC_NA);
3375 /* o += F5TLS_RANDOM_LEN; */
3378 if (!pref_generate_keylog || data == NULL) {
3379 break;
3382 pdata = ((f5tls_data_t *)data)->pkt;
3383 conv_data = ((f5tls_data_t *)data)->conv;
3385 /* If this is our first pass through, add protocol data and build keylog entries.
3386 Assume that if a CRand exists on the conversation that it is the one that matches
3387 up with the newly set / changed secret. */
3388 if (!pinfo->fd->visited) {
3389 bool ets_changed = false;
3390 bool chs_changed = false;
3391 bool shs_changed = false;
3392 bool cap_changed = false;
3393 bool sap_changed = false;
3395 o = F5_DPT_V1_TLV_HDR_LEN + 1;
3397 if (ver == 1) {
3398 ets_changed =
3399 f5eth_add_tls_element(&conv_data->erly_traf_sec, pinfo, tvb, o, secret_len);
3400 o += F5TLS_HASH_LEN;
3401 } else if (ver == 0 && len == F5TLS_T2V1_LEN) {
3402 o += F5TLS_HASH_LEN;
3404 chs_changed =
3405 f5eth_add_tls_element(&conv_data->clnt_hs_sec, pinfo, tvb, o, secret_len);
3406 o += F5TLS_HASH_LEN;
3407 shs_changed =
3408 f5eth_add_tls_element(&conv_data->srvr_hs_sec, pinfo, tvb, o, secret_len);
3409 o += F5TLS_HASH_LEN;
3410 cap_changed =
3411 f5eth_add_tls_element(&conv_data->clnt_ap_sec, pinfo, tvb, o, secret_len);
3412 o += F5TLS_HASH_LEN;
3413 sap_changed =
3414 f5eth_add_tls_element(&conv_data->srvr_ap_sec, pinfo, tvb, o, secret_len);
3415 o += F5TLS_HASH_LEN;
3416 f5eth_add_tls_element(&conv_data->client_random, pinfo, tvb, o, F5TLS_RANDOM_LEN);
3418 if (conv_data->client_random.len != 0) {
3419 if (ver == 1 && ets_changed) {
3420 pdata->cr_erly_traff = f5eth_add_tls_keylog(pinfo, EARLY_TRAFFIC_SECRET,
3421 &conv_data->client_random, &conv_data->erly_traf_sec);
3423 if (cap_changed) {
3424 pdata->cr_clnt_app = f5eth_add_tls_keylog(pinfo, CLIENT_TRAFFIC_SECRET_0,
3425 &conv_data->client_random, &conv_data->clnt_ap_sec);
3427 if (sap_changed) {
3428 pdata->cr_srvr_app = f5eth_add_tls_keylog(pinfo, SERVER_TRAFFIC_SECRET_0,
3429 &conv_data->client_random, &conv_data->srvr_ap_sec);
3431 if (chs_changed) {
3432 pdata->cr_clnt_hs = f5eth_add_tls_keylog(pinfo, CLIENT_HANDSHAKE_TRAFFIC_SECRET,
3433 &conv_data->client_random, &conv_data->clnt_hs_sec);
3435 if (shs_changed) {
3436 pdata->cr_srvr_hs = f5eth_add_tls_keylog(pinfo, SERVER_HANDSHAKE_TRAFFIC_SECRET,
3437 &conv_data->client_random, &conv_data->srvr_hs_sec);
3442 /* Display any keylog entries we have in our packet data */
3443 if (pdata->cr_erly_traff != NULL) {
3444 pi = proto_tree_add_string(tree, hf_f5tls_keylog, tvb, 0, 0, pdata->cr_erly_traff);
3445 proto_item_set_generated(pi);
3447 if (pdata->cr_clnt_app != NULL) {
3448 pi = proto_tree_add_string(tree, hf_f5tls_keylog, tvb, 0, 0, pdata->cr_clnt_app);
3449 proto_item_set_generated(pi);
3451 if (pdata->cr_srvr_app != NULL) {
3452 pi = proto_tree_add_string(tree, hf_f5tls_keylog, tvb, 0, 0, pdata->cr_srvr_app);
3453 proto_item_set_generated(pi);
3455 if (pdata->cr_clnt_hs != NULL) {
3456 pi = proto_tree_add_string(tree, hf_f5tls_keylog, tvb, 0, 0, pdata->cr_clnt_hs);
3457 proto_item_set_generated(pi);
3459 if (pdata->cr_srvr_hs != NULL) {
3460 pi = proto_tree_add_string(tree, hf_f5tls_keylog, tvb, 0, 0, pdata->cr_srvr_hs);
3461 proto_item_set_generated(pi);
3463 break;
3464 default:
3465 /* Unknown version */
3466 len = 0;
3467 break;
3469 return len;
3470 } /* dissect_dpt_trailer_tls_type2() */
3472 /*----------------------------------------------------------------------*/
3473 /** TLS extended trailer - Types 1 and 3
3475 * Render as <DATA> - No dissection
3477 * @param tvb The tvbuff containing the DPT TLV block (header and data).
3478 * @param pinfo The pinfo structure for the frame (unused).
3479 * @param tree The tree to render the DPT TLV under.
3480 * @param data Data passed (unused).
3481 * @return Number of bytes decoded.
3483 static int
3484 dissect_dpt_trailer_tls_extended(
3485 tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
3487 proto_item *pi;
3488 int len;
3490 len = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_LENGTH_OFF);
3492 /* Create a subtree and render a header */
3493 pi = proto_tree_add_item(tree, hf_f5tls_tls, tvb, 0, len, ENC_NA);
3494 proto_item_append_text(pi, ", Extended Info");
3495 tree = proto_item_add_subtree(pi, ett_f5tls_ext);
3497 render_f5dptv1_tlvhdr(tvb, tree, 0);
3499 proto_tree_add_item(
3500 tree, hf_data, tvb, F5_DPT_V1_TLV_HDR_LEN, len - F5_DPT_V1_TLV_HDR_LEN, ENC_NA);
3501 return len;
3502 } /* dissect_dpt_trailer_tls_extended() */
3504 /*-----------------------------------------------------------------------------------------------*/
3506 * @brief Dissector for the TLS DPT provider
3508 * @param tvb The tvbuff containing the DPT TLV block (header and data).
3509 * @param pinfo The pinfo structure for the frame.
3510 * @param tree The tree to render the DPT TLV under.
3511 * @param data Data passed (tap data) (unused).
3512 * @return The length as read from the TLV header.
3515 static int
3516 dissect_dpt_trailer_tls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
3518 uint32_t pattern;
3519 conversation_t *conv = NULL;
3520 f5tls_data_t *tls_data = NULL;
3522 /* We only need the conversation to bring data parts together that arrive on
3523 different frames. After the first pass, the keylog entries are stored
3524 on the individual packet's data */
3525 if (pref_generate_keylog) {
3526 tls_data = wmem_new0(pinfo->pool, f5tls_data_t);
3527 if (!pinfo->fd->visited) {
3528 conv = find_or_create_conversation(pinfo);
3529 tls_data->conv = (f5tls_conversation_data_t *)conversation_get_proto_data(
3530 conv, proto_f5ethtrailer_dpt_tls);
3531 if (tls_data->conv == NULL) {
3532 tls_data->conv = wmem_new0(wmem_file_scope(), f5tls_conversation_data_t);
3533 conversation_add_proto_data(conv, proto_f5ethtrailer_dpt_tls, tls_data->conv);
3536 tls_data->pkt = (f5tls_packet_data_t *)p_get_proto_data(
3537 wmem_file_scope(), pinfo, proto_f5ethtrailer_dpt_tls, 0);
3538 if (tls_data->pkt == NULL) {
3539 tls_data->pkt = wmem_new0(wmem_file_scope(), f5tls_packet_data_t);
3540 p_add_proto_data(
3541 wmem_file_scope(), pinfo, proto_f5ethtrailer_dpt_tls, 0, tls_data->pkt);
3545 /* Combine 2 byte TYPE with 2 byte VERSION into uint32_t for the subdissector table lookup */
3546 pattern = tvb_get_ntohs(tvb, F5_DPT_V1_TLV_TYPE_OFF) << 16
3547 | tvb_get_ntohs(tvb, F5_DPT_V1_TLV_VERSION_OFF);
3548 return (
3549 dissector_try_uint_with_data(tls_subdissector_table, pattern, tvb, pinfo, tree, false, tls_data));
3550 } /* dissect_f5dpt_tls() */
3552 /*-----------------------------------------------------------------------------------------------*/
3553 /* End DPT TLS Provider */
3554 /*-----------------------------------------------------------------------------------------------*/
3557 * @brief Initialization routine called before first pass through a capture.
3560 static void
3561 proto_init_f5ethtrailer(void)
3563 /** Need to set display_slot to true when initially reading a capture. This covers the
3564 * situation when a user loads a capture that turns off slot display and then loads a
3565 * different capture that contains trailers, but does not have the F5INFO frame. In this
3566 * case, we need to turn the slot display back on. */
3567 display_slot = true;
3568 /* Set the info column function to use based on whether or not an in/out only
3569 * preference is chosen. */
3570 switch (pref_info_type) {
3571 case in_out_only:
3572 case brief_in_out_only:
3573 f5eth_set_info_col = f5eth_set_info_col_inout;
3574 break;
3575 default:
3576 f5eth_set_info_col = f5eth_set_info_col_slot;
3577 break;
3580 /* If we are doing analysis, enable the tap listeners */
3581 if (pref_perform_analysis) {
3582 GString *error_string;
3584 error_string = register_tap_listener(
3585 "ip", &tap_ip_enabled, NULL, TL_REQUIRES_NOTHING, NULL, ip_tap_pkt, NULL, NULL);
3586 if (error_string) {
3587 ws_warning("Unable to register tap \"ip\" for f5ethtrailer: %s", error_string->str);
3588 g_string_free(error_string, TRUE);
3589 } else {
3590 tap_ip_enabled = true;
3592 error_string = register_tap_listener(
3593 "ipv6", &tap_ipv6_enabled, NULL, TL_REQUIRES_NOTHING, NULL, ipv6_tap_pkt, NULL, NULL);
3594 if (error_string) {
3595 ws_warning("Unable to register tap \"ipv6\" for f5ethtrailer: %s", error_string->str);
3596 g_string_free(error_string, TRUE);
3597 } else {
3598 tap_ipv6_enabled = true;
3600 error_string = register_tap_listener(
3601 "tcp", &tap_tcp_enabled, NULL, TL_REQUIRES_NOTHING, NULL, tcp_tap_pkt, NULL, NULL);
3602 if (error_string) {
3603 ws_warning("Unable to register tap \"tcp\" for f5ethtrailer: %s", error_string->str);
3604 g_string_free(error_string, TRUE);
3605 } else {
3606 tap_tcp_enabled = true;
3612 * @brief Cleanup after closing a capture file.
3615 static void
3616 f5ethtrailer_cleanup(void)
3618 if (tap_tcp_enabled) {
3619 remove_tap_listener(&tap_tcp_enabled);
3620 tap_tcp_enabled = false;
3622 if (tap_ipv6_enabled) {
3623 remove_tap_listener(&tap_ipv6_enabled);
3624 tap_ipv6_enabled = false;
3626 if (tap_ip_enabled) {
3627 remove_tap_listener(&tap_ip_enabled);
3628 tap_ip_enabled = false;
3633 * @brief Sets up the format strings to use for the Info column
3636 static void
3637 f5ethtrailer_prefs(void)
3639 wmem_free(NULL, info_format_in_only);
3640 wmem_free(NULL, info_format_out_only);
3641 wmem_free(NULL, info_format_in_slot);
3642 wmem_free(NULL, info_format_out_slot);
3643 wmem_free(NULL, info_format_in_noslot);
3644 wmem_free(NULL, info_format_out_noslot);
3646 /* Set the set of format specifier strings to use based on whether or not one of the
3647 * brief preferences is chosen */
3648 switch (pref_info_type) {
3649 case brief:
3650 case brief_in_out_only:
3651 if (pref_brief_inout_chars != NULL && strlen(pref_brief_inout_chars) >= 2) {
3652 info_format_in_only = wmem_strdup_printf(NULL, "%c: ", pref_brief_inout_chars[0]);
3653 info_format_out_only = wmem_strdup_printf(NULL, "%c: ", pref_brief_inout_chars[1]);
3654 info_format_in_slot =
3655 wmem_strdup_printf(NULL, "%c%%u/%%-2u: ", pref_brief_inout_chars[0]);
3656 info_format_out_slot =
3657 wmem_strdup_printf(NULL, "%c%%u/%%-2u: ", pref_brief_inout_chars[1]);
3658 info_format_in_noslot =
3659 wmem_strdup_printf(NULL, "%ct%%-2u: ", pref_brief_inout_chars[0]);
3660 info_format_out_noslot =
3661 wmem_strdup_printf(NULL, "%ct%%-2u: ", pref_brief_inout_chars[1]);
3662 } else {
3663 info_format_in_only = wmem_strdup(NULL, ">: ");
3664 info_format_out_only = wmem_strdup(NULL, "<: ");
3665 info_format_in_slot = wmem_strdup(NULL, ">%u/%-2u: ");
3666 info_format_out_slot = wmem_strdup(NULL, "<%u/%-2u: ");
3667 info_format_in_noslot = wmem_strdup(NULL, ">t%-2u: ");
3668 info_format_out_noslot = wmem_strdup(NULL, "<t%-2u: ");
3670 break;
3671 default:
3672 info_format_in_only = wmem_strdup(NULL, info_format_full_in_only);
3673 info_format_out_only = wmem_strdup(NULL, info_format_full_out_only);
3674 info_format_in_slot = wmem_strdup(NULL, info_format_full_in_slot);
3675 info_format_out_slot = wmem_strdup(NULL, info_format_full_out_slot);
3676 info_format_in_noslot = wmem_strdup(NULL, info_format_full_in_noslot);
3677 info_format_out_noslot = wmem_strdup(NULL, info_format_full_out_noslot);
3678 break;
3683 * @brief f5ethtrailer Dissector registration
3686 void
3687 proto_register_f5ethtrailer(void)
3689 module_t *f5ethtrailer_module;
3691 /* A header field is something you can search/filter on.
3693 * We create a structure to register our fields. It consists of an
3694 * array of hf_register_info structures, each of which are of the format
3695 * {&(field id), {name, abrv, type, display, strs, bitmask, blurb, HFILL}}.
3697 static hf_register_info hf[] = {
3698 { &hf_trailer_hdr,
3699 { "F5 Trailer Header", "f5ethtrailer.header", FT_NONE, BASE_NONE, NULL,
3700 0x0, NULL, HFILL }
3702 { &hf_provider,
3703 { "Provider", "f5ethtrailer.provider", FT_UINT16, BASE_DEC, NULL,
3704 0x0, NULL, HFILL }
3706 { &hf_type,
3707 { "Type", "f5ethtrailer.type", FT_UINT16, BASE_DEC, NULL,
3708 0x0, NULL, HFILL }
3710 { &hf_length,
3711 { "Trailer length", "f5ethtrailer.length", FT_UINT16, BASE_DEC, NULL,
3712 0x0, NULL, HFILL }
3714 { &hf_version,
3715 { "Version", "f5ethtrailer.version", FT_UINT16, BASE_DEC, NULL,
3716 0x0, NULL, HFILL }
3718 { &hf_dpt_unknown,
3719 { "Unknown trailer", "f5ethtrailer.unknown_trailer", FT_NONE, BASE_NONE, NULL,
3720 0x0, NULL, HFILL }
3722 { &hf_data,
3723 { "Data", "f5ethtrailer.data", FT_BYTES, SEP_SPACE, NULL,
3724 0x0, NULL, HFILL }
3726 { &hf_data_str,
3727 { "Data", "f5ethtrailer.data.string", FT_STRING, BASE_NONE, NULL,
3728 0x0, NULL, HFILL }
3730 { &hf_orig_fcs,
3731 { "Original FCS", "f5ethtrailer.orig_fcs", FT_UINT32, BASE_HEX, NULL,
3732 0x0, NULL, HFILL }
3735 /* Low parameters */
3736 { &hf_low_id,
3737 { "Low Details", "f5ethtrailer.low", FT_NONE, BASE_NONE, NULL,
3738 0x0, NULL, HFILL }
3740 { &hf_flags,
3741 { "Flags", "f5ethtrailer.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }
3743 { &hf_flags_ingress,
3744 { "Ingress", "f5ethtrailer.flags.ingress", FT_UINT8, BASE_DEC,
3745 VALS(f5_flags_ingress_vs), F5_LOW_FLAGS_INGRESS_MASK, NULL, HFILL }
3747 { &hf_flags_hwaction,
3748 { "Hardware Action", "f5ethtrailer.flags.hwaction", FT_UINT8, BASE_DEC,
3749 VALS(f5_flags_hwaction_vs), F5_LOW_FLAGS_HWACTION_MASK, NULL, HFILL }
3751 { &hf_ingress,
3752 { "Ingress", "f5ethtrailer.ingress", FT_BOOLEAN, BASE_NONE, NULL,
3753 0x0, NULL, HFILL }
3755 { &hf_slot0,
3756 { "Slot (0-based)", "f5ethtrailer.slot", FT_UINT8, BASE_DEC, NULL,
3757 0x0, "Slot captured on", HFILL }
3759 { &hf_slot1,
3760 { "Slot (1-based)", "f5ethtrailer.slot", FT_UINT8, BASE_DEC, NULL,
3761 0x0, "Slot captured on", HFILL }
3763 { &hf_tmm,
3764 { "TMM (0-based)", "f5ethtrailer.tmm", FT_UINT8, BASE_DEC, NULL,
3765 0x0, "TMM captured on", HFILL }
3767 { &hf_obj_name_type,
3768 { "Type", "f5ethtrailer.objnametype", FT_UINT8, BASE_DEC,
3769 VALS(f5_obj_data_types), 0x0, NULL, HFILL }
3771 { &hf_obj_data_len,
3772 { "Object Name Data Length", "f5ethtrailer.objnamelen", FT_UINT8, BASE_DEC, NULL,
3773 0x0, NULL, HFILL }
3775 { &hf_vipnamelen,
3776 { "Length", "f5ethtrailer.vipnamelen", FT_UINT8, BASE_DEC, NULL,
3777 0x0, NULL, HFILL }
3779 { &hf_vip,
3780 { "Name", "f5ethtrailer.vip", FT_STRING, BASE_NONE, NULL,
3781 0x0, "VIP flow associated with", HFILL }
3783 { &hf_portnamelen,
3784 { "Length", "f5ethtrailer.portnamelen", FT_UINT8, BASE_DEC, NULL,
3785 0x0, NULL, HFILL }
3787 { &hf_phys_port,
3788 { "Name", "f5ethtrailer.phys_port", FT_STRING, BASE_NONE, NULL,
3789 0x0, "Physical port", HFILL }
3791 { &hf_trunknamelen,
3792 { "Length", "f5ethtrailer.trunknamelen", FT_UINT8, BASE_DEC, NULL,
3793 0x0, NULL, HFILL }
3795 { &hf_trunk,
3796 { "Name", "f5ethtrailer.trunk", FT_STRING, BASE_NONE, NULL,
3797 0x0, "Trunk name", HFILL }
3800 /* Medium parameters */
3801 { &hf_med_id,
3802 { "Medium Details", "f5ethtrailer.medium", FT_NONE, BASE_NONE, NULL,
3803 0x0, NULL, HFILL }
3805 { &hf_any_flow,
3806 { "Flow ID or peer flow ID", "f5ethtrailer.anyflowid", FT_UINT64, BASE_HEX, NULL,
3807 0x0, NULL, HFILL }
3809 { &hf_flow_id,
3810 { "Flow ID", "f5ethtrailer.flowid", FT_UINT64, BASE_HEX, NULL,
3811 0x0, NULL, HFILL }
3813 { &hf_peer_id,
3814 { "Peer ID", "f5ethtrailer.peerid", FT_UINT64, BASE_HEX, NULL,
3815 0x0, NULL, HFILL }
3817 { &hf_cf_flags,
3818 { "Connflow Flags", "f5ethtrailer.cfflags", FT_UINT32, BASE_HEX, NULL,
3819 0x0, NULL, HFILL }
3821 { &hf_cf_flags2,
3822 { "Connflow Flags High Bits", "f5ethtrailer.cfflags2", FT_UINT32,
3823 BASE_HEX, NULL, 0x0, NULL, HFILL }
3825 { &hf_flow_type,
3826 { "Flow Type", "f5ethtrailer.flowtype", FT_UINT8, BASE_HEX, NULL,
3827 0x0, NULL, HFILL }
3829 { &hf_ha_unit,
3830 { "HA Unit", "f5ethtrailer.haunit", FT_UINT8, BASE_HEX, NULL,
3831 0x0, NULL, HFILL }
3833 { &hf_reserved,
3834 { "Reserved", "f5ethtrailer.reserved", FT_UINT32, BASE_HEX, NULL,
3835 0x0, NULL, HFILL }
3837 { &hf_priority,
3838 { "Priority", "f5ethtrailer.priority", FT_UINT8, BASE_DEC, NULL,
3839 0x0, NULL, HFILL }
3841 { &hf_rstcause,
3842 { "RST cause", "f5ethtrailer.rstcause", FT_NONE, BASE_NONE, NULL,
3843 0x0, NULL, HFILL }
3845 { &hf_rstcause_len,
3846 { "Length", "f5ethtrailer.rstcauselen", FT_UINT8, BASE_DEC,
3847 NULL, 0x0, "RST cause length", HFILL }
3849 { &hf_rstcause_ver,
3850 { "Version", "f5ethtrailer.rstcausever", FT_UINT8, BASE_DEC_HEX,
3851 NULL, 0xfe, "RST cause version", HFILL }
3853 { &hf_rstcause_peer,
3854 { "Peer", "f5ethtrailer.rstcausepeer", FT_UINT8, BASE_DEC,
3855 NULL, 0x01, "RST cause peer", HFILL }
3857 { &hf_rstcause_val,
3858 { "Value", "f5ethtrailer.rstcauseval", FT_UINT64, BASE_HEX,
3859 NULL, 0x0, "RST cause value", HFILL }
3861 { &hf_rstcause_line,
3862 { "Line", "f5ethtrailer.rstcauseline", FT_UINT16, BASE_DEC,
3863 NULL, 0x0, "RST cause line", HFILL }
3865 { &hf_rstcause_txt,
3866 { "Cause", "f5ethtrailer.rstcausetxt", FT_STRING, BASE_NONE,
3867 NULL, 0x0, "RST cause", HFILL }
3870 /* High parameters */
3871 { &hf_high_id,
3872 { "High Details", "f5ethtrailer.high", FT_NONE, BASE_NONE, NULL,
3873 0x0, NULL, HFILL }
3875 { &hf_peer_ipproto,
3876 { "Peer IP Protocol", "f5ethtrailer.peeripproto", FT_UINT8, BASE_DEC,
3877 NULL, 0x0, NULL, HFILL }
3879 { &hf_peer_vlan,
3880 { "Peer VLAN", "f5ethtrailer.peervlan", FT_UINT16, BASE_DEC, NULL,
3881 0x0, NULL, HFILL }
3883 { &hf_peer_remote_addr,
3884 { "Peer remote address", "f5ethtrailer.peerremoteaddr", FT_IPv4,
3885 BASE_NONE, NULL, 0x0, "Peer remote IPv4 address", HFILL }
3887 { &hf_peer_remote_ip6addr,
3888 { "Peer remote address", "f5ethtrailer.peerremoteaddr6", FT_IPv6,
3889 BASE_NONE, NULL, 0x0, "Peer remote IPv6 address", HFILL }
3891 { &hf_peer_local_addr,
3892 { "Peer local address", "f5ethtrailer.peerlocaladdr", FT_IPv4,
3893 BASE_NONE, NULL, 0x0, "Peer local IPv4 address", HFILL }
3895 { &hf_peer_local_ip6addr,
3896 { "Peer local address", "f5ethtrailer.peerlocaladdr6", FT_IPv6,
3897 BASE_NONE, NULL, 0x0, "Peer local IPv6 address", HFILL }
3899 { &hf_peer_ipaddr,
3900 { "Peer remote or local address", "f5ethtrailer.peeraddr", FT_IPv4,
3901 BASE_NONE, NULL, 0x0, "Peer IPv4 address", HFILL }
3903 { &hf_peer_ip6addr,
3904 { "Peer remote or local address", "f5ethtrailer.peeraddr6", FT_IPv6,
3905 BASE_NONE, NULL, 0x0, "Peer IPv6 address", HFILL }
3907 { &hf_peer_remote_rtdom,
3908 { "Peer remote route domain", "f5ethtrailer.peerremotertdom", FT_UINT16,
3909 BASE_DEC, NULL, 0x0, NULL, HFILL }
3911 { &hf_peer_local_rtdom,
3912 { "Peer local route domain", "f5ethtrailer.peerlocalrtdom", FT_UINT16,
3913 BASE_DEC, NULL, 0x0, NULL, HFILL }
3915 { &hf_peer_rtdom,
3916 { "Peer remote or local route domain", "f5ethtrailer.peerrtdom", FT_UINT16,
3917 BASE_DEC, NULL, 0x0, NULL, HFILL }
3919 { &hf_peer_remote_port,
3920 { "Peer remote port", "f5ethtrailer.peerremoteport", FT_UINT16, BASE_DEC,
3921 NULL, 0x0, NULL, HFILL }
3923 { &hf_peer_local_port,
3924 { "Peer local port", "f5ethtrailer.peerlocalport", FT_UINT16, BASE_DEC,
3925 NULL, 0x0, NULL, HFILL }
3927 { &hf_peer_port,
3928 { "Peer remote or local port", "f5ethtrailer.peerport", FT_UINT16, BASE_DEC,
3929 NULL, 0x0, NULL, HFILL }
3931 { &hf_peer_nopeer,
3932 { "No peer connection information", "f5ethtrailer.nopeer", FT_NONE, BASE_NONE,
3933 NULL, 0x0, NULL, HFILL }
3936 /* Analysis parameters */
3937 { &hf_analysis,
3938 { "Analysis", "f5ethtrailer.analysis", FT_NONE, BASE_NONE, NULL,
3939 0x0, "Analysis of details", HFILL }
3942 { &hf_dpt_magic,
3943 { "Magic", "f5ethtrailer.trailer_magic", FT_UINT32, BASE_HEX, NULL,
3944 0x0, NULL, HFILL }
3946 { &hf_dpt_ver,
3947 { "Version", "f5ethtrailer.trailer_version", FT_UINT16, BASE_DEC, NULL,
3948 0x0, NULL, HFILL }
3950 { &hf_dpt_len,
3951 { "Length", "f5ethtrailer.trailer_length", FT_UINT16, BASE_DEC, NULL,
3952 0x0, NULL, HFILL }
3955 /* TLS provider parameters */
3956 { &hf_f5tls_tls,
3957 { "F5 TLS", "f5ethtrailer.tls.data", FT_NONE, BASE_NONE, NULL,
3958 0x0, NULL, HFILL }
3960 { &hf_f5tls_secret_len,
3961 { "Secret Length", "f5ethtrailer.tls.secret_len", FT_UINT8, BASE_DEC, NULL,
3962 0x0, NULL, HFILL }
3964 { &hf_f5tls_mstr_sec,
3965 { "Master Secret", "f5ethtrailer.tls.master_secret", FT_BYTES, BASE_NONE, NULL,
3966 0x0, NULL, HFILL }
3968 { &hf_f5tls_clnt_rand,
3969 { "Client Random", "f5ethtrailer.tls.client_random", FT_BYTES, BASE_NONE, NULL,
3970 0x0, NULL, HFILL }
3972 { &hf_f5tls_srvr_rand,
3973 { "Server Random", "f5ethtrailer.tls.server_random", FT_BYTES, BASE_NONE, NULL,
3974 0x0, NULL, HFILL }
3976 { &hf_f5tls_early_traffic_sec,
3977 { "Early Traffic Secret", "f5ethtrailer.tls.early_traffic_secret", FT_BYTES, BASE_NONE, NULL,
3978 0x0, NULL, HFILL }
3980 { &hf_f5tls_clnt_hs_sec,
3981 { "Client Handshake Traffic Secret", "f5ethtrailer.tls.client_hs_secret", FT_BYTES, BASE_NONE, NULL,
3982 0x0, NULL, HFILL }
3984 { &hf_f5tls_srvr_hs_sec,
3985 { "Server Handshake Traffic Secret", "f5ethtrailer.tls.server_hs_secret", FT_BYTES, BASE_NONE, NULL,
3986 0x0, NULL, HFILL }
3988 { &hf_f5tls_clnt_app_sec,
3989 { "Client Application Traffic Secret", "f5ethtrailer.tls.client_app_secret", FT_BYTES, BASE_NONE, NULL,
3990 0x0, NULL, HFILL }
3992 { &hf_f5tls_srvr_app_sec,
3993 { "Server Application Traffic Secret", "f5ethtrailer.tls.server_app_secret", FT_BYTES, BASE_NONE, NULL,
3994 0x0, NULL, HFILL }
3996 { &hf_f5tls_keylog,
3997 { "Keylog entry", "f5ethtrailer.tls.keylog", FT_STRINGZ, BASE_NONE, NULL,
3998 0x0, NULL, HFILL }
4002 static int *ett[] = {
4003 &ett_f5ethtrailer,
4004 &ett_f5ethtrailer_unknown,
4005 &ett_f5ethtrailer_low,
4006 &ett_f5ethtrailer_low_flags,
4007 &ett_f5ethtrailer_med,
4008 &ett_f5ethtrailer_high,
4009 &ett_f5ethtrailer_rstcause,
4010 &ett_f5ethtrailer_trailer_hdr,
4011 &ett_f5ethtrailer_obj_names,
4012 &ett_f5tls,
4013 &ett_f5tls_std,
4014 &ett_f5tls_ext,
4017 expert_module_t *expert_f5ethtrailer;
4018 static ei_register_info ei[] = {
4019 { &ei_f5eth_flowlost, { "f5ethtrailer.flowlost", PI_SEQUENCE, PI_WARN,
4020 "Flow lost, incorrect VLAN, loose initiation, tunnel, or SYN cookie use",
4021 EXPFILL } },
4022 { &ei_f5eth_flowreuse, { "f5ethtrailer.flowreuse", PI_SEQUENCE, PI_WARN,
4023 "Flow reuse or SYN retransmit", EXPFILL } },
4024 { &ei_f5eth_badlen, { "f5ethtrailer.badlen", PI_MALFORMED, PI_ERROR,
4025 "Length extends past remaining available bytes", EXPFILL } },
4026 { &ei_f5eth_undecoded, { "f5ethtrailer.undecoded", PI_UNDECODED, PI_NOTE,
4027 "This version of Wireshark does not understand how to decode this value", EXPFILL } },
4030 proto_f5ethtrailer = proto_register_protocol("F5 Ethernet Trailer Protocol", "F5 Ethernet trailer", "f5ethtrailer");
4032 expert_f5ethtrailer = expert_register_protocol(proto_f5ethtrailer);
4033 expert_register_field_array(expert_f5ethtrailer, ei, array_length(ei));
4035 proto_register_field_array(proto_f5ethtrailer, hf, array_length(hf));
4036 proto_register_subtree_array(ett, array_length(ett));
4038 /* Register the dissector preferences */
4039 f5ethtrailer_module = prefs_register_protocol(proto_f5ethtrailer, f5ethtrailer_prefs);
4041 prefs_register_bool_preference(f5ethtrailer_module, "pref_walk_trailer",
4042 "Walk ethernet trailer looking for f5ethtrailer",
4043 "In a few cases a short ethernet frame will be padded with non-zero"
4044 "bytes. If this happens, an f5ethtrailer will not be found."
4045 "Enabling this will step through each byte of the ethernet trailer"
4046 "to try and find the start of an f5ethtrailer",
4047 &pref_walk_trailer);
4049 prefs_register_bool_preference(f5ethtrailer_module, "pref_pop_other_fields",
4050 "Populate fields for other dissectors",
4051 "Disable this if you do not want this dissector to populate"
4052 " well-known fields in other dissectors (i.e. ip.addr, ipv6.addr,"
4053 " tcp.port and udp.port). Enabling this will allow filters that"
4054 " reference those fields to also find data in the trailers but"
4055 " will reduce performance. After disabling, you should restart"
4056 " Wireshark to get performance back.",
4057 &pref_pop_other_fields);
4059 prefs_register_bool_preference(f5ethtrailer_module, "perform_analysis",
4060 "Perform analysis of trailer data",
4061 "Enabling this will perform analysis of the trailer data. It will"
4062 " enable taps on other protocols and slow down Wireshark.",
4063 &pref_perform_analysis);
4065 prefs_register_static_text_preference(f5ethtrailer_module, "info_col_section",
4066 "Information column preferences",
4067 "The settings below affect how information from this dissector is"
4068 " displayed in the info column in the packet list pane.");
4070 prefs_register_obsolete_preference(f5ethtrailer_module, "summary_in_info");
4072 prefs_register_enum_preference(f5ethtrailer_module, "info_type",
4073 "Summary display in info column",
4074 "In/out only removes slot/tmm information. Brief shortens the string"
4075 " to >S/T (for in) or <S/T (for out). See \"Brief in/out characters\""
4076 " below.",
4077 (unsigned *)&pref_info_type, f5eth_display_strings, true);
4079 prefs_register_string_preference(f5ethtrailer_module, "brief_inout_chars",
4080 "Brief in/out characters",
4081 "A string specifying the characters to use to represent \"in\" and"
4082 " \"out\" in the brief summary. The default is \"><\" ('>' for in"
4083 " and '<' for out). If this is not set or is less than two"
4084 " characters, the default is used. If it is longer than two"
4085 " characters, the extra characters are ignored.",
4086 &pref_brief_inout_chars);
4088 prefs_register_string_preference(f5ethtrailer_module, "slots_regex",
4089 "Only display slot information for platforms",
4090 "If the platform in the F5 FILEINFO packet matches the provided regex,"
4091 " slot information will be displayed in the info column; otherwise, it"
4092 " will not. A reasonable value is \"^(A.*|Z101)$\". If the regex is"
4093 " empty or there is no platform information in the capture, slot"
4094 " information is always displayed.",
4095 &pref_slots_regex);
4097 prefs_register_bool_preference(f5ethtrailer_module, "rstcause_in_info",
4098 "Add RST cause string to info",
4099 "If present, include the RST cause text from the trailer in the "
4100 "\"info\" column of the packet list pane.",
4101 &rstcause_in_info);
4103 prefs_register_bool_preference(f5ethtrailer_module, "generate_keylog",
4104 "Generate KEYLOG records from TLS f5ethtrailer",
4105 "If enabled, KEYLOG entries will be added to the TLS decode"
4106 " in the f5ethtrailer protocol tree. It will populate the"
4107 " f5ethtrailer.tls.keylog field.",
4108 &pref_generate_keylog);
4110 register_init_routine(proto_init_f5ethtrailer);
4111 register_cleanup_routine(f5ethtrailer_cleanup);
4113 /* Register dissector table for additional providers */
4114 provider_subdissector_table = register_dissector_table("f5ethtrailer.provider",
4115 "F5 Ethernet trailer provider", proto_f5ethtrailer, FT_UINT16, BASE_DEC);
4116 proto_f5ethtrailer_dpt_noise =
4117 proto_register_protocol_in_name_only("F5 Ethernet trailer provider - Noise", "Noise",
4118 "f5ethtrailer.provider.noise", proto_f5ethtrailer, FT_BYTES);
4119 noise_subdissector_table = register_dissector_table("f5ethtrailer.noise_type_ver",
4120 "F5 Ethernet Trailer Noise", proto_f5ethtrailer, FT_UINT32, BASE_DEC);
4121 proto_f5ethtrailer_dpt_tls =
4122 proto_register_protocol_in_name_only("F5 Ethernet Trailer Protocol - TLS Provider",
4123 "F5 TLS", "f5ethtrailer.tls", proto_f5ethtrailer, FT_BYTES);
4124 tls_subdissector_table = register_dissector_table("f5ethtrailer.tls_type_ver",
4125 "F5 Ethernet Trailer TLS", proto_f5ethtrailer, FT_UINT32, BASE_DEC);
4127 f5dpt_noise_handle =
4128 register_dissector("f5ethtrailer.noise", dissect_dpt_trailer_noise, proto_f5ethtrailer_dpt_noise);
4129 f5dpt_tls_handle = register_dissector("f5ethtrailer.tls", dissect_dpt_trailer_tls, proto_f5ethtrailer_dpt_tls);
4131 /* Analyze Menu Items */
4132 register_conversation_filter("f5ethtrailer", "F5 TCP", f5_tcp_conv_valid, f5_tcp_conv_filter, NULL);
4133 register_conversation_filter("f5ethtrailer", "F5 UDP", f5_udp_conv_valid, f5_udp_conv_filter, NULL);
4134 register_conversation_filter("f5ethtrailer", "F5 IP", f5_ip_conv_valid, f5_ip_conv_filter, NULL);
4136 /* Register the f5ethtrailer tap for statistics */
4137 tap_f5ethtrailer = register_tap("f5ethtrailer");
4139 stats_tree_register_plugin("f5ethtrailer", "f5_tmm_dist", st_str_tmmdist,
4140 (ST_SORT_COL_NAME << ST_FLG_SRTCOL_SHIFT), f5eth_tmmdist_stats_tree_packet,
4141 f5eth_tmmdist_stats_tree_init, NULL);
4142 stats_tree_register_plugin("f5ethtrailer", "f5_virt_dist", st_str_virtdist,
4143 (ST_SORT_COL_NAME << ST_FLG_SRTCOL_SHIFT), f5eth_virtdist_stats_tree_packet,
4144 f5eth_virtdist_stats_tree_init, NULL);
4146 /* Setup col info strings */
4147 f5ethtrailer_prefs();
4148 } /* proto_register_f5ethtrailer() */
4151 * @brief f5ethtrailer Dissector handoff function
4154 void
4155 proto_reg_handoff_f5ethtrailer(void)
4157 heur_dissector_add("eth.trailer", dissect_f5ethtrailer_heur, "F5 Ethernet Trailer",
4158 "f5ethtrailer", proto_f5ethtrailer, HEURISTIC_ENABLE);
4160 /* Register helper dissectors */
4161 /* Noise Provider */
4162 dissector_add_uint("f5ethtrailer.provider", F5_DPT_PROVIDER_NOISE, f5dpt_noise_handle);
4163 dissector_add_uint("f5ethtrailer.noise_type_ver", F5TYPE_LOW << 16 | 2,
4164 create_dissector_handle(dissect_dpt_trailer_noise_low, proto_f5ethtrailer_dpt_noise));
4165 dissector_add_uint("f5ethtrailer.noise_type_ver", F5TYPE_LOW << 16 | 3,
4166 create_dissector_handle(dissect_dpt_trailer_noise_low, proto_f5ethtrailer_dpt_noise));
4167 dissector_add_uint("f5ethtrailer.noise_type_ver", F5TYPE_LOW << 16 | 4,
4168 create_dissector_handle(dissect_dpt_trailer_noise_low, proto_f5ethtrailer_dpt_noise));
4169 dissector_add_uint("f5ethtrailer.noise_type_ver", F5TYPE_MED << 16 | 4,
4170 create_dissector_handle(dissect_dpt_trailer_noise_med, proto_f5ethtrailer_dpt_noise));
4171 dissector_add_uint("f5ethtrailer.noise_type_ver", F5TYPE_HIGH << 16 | 1,
4172 create_dissector_handle(dissect_dpt_trailer_noise_high, proto_f5ethtrailer_dpt_noise));
4173 /* TLS provider */
4174 dissector_add_uint("f5ethtrailer.provider", F5_DPT_PROVIDER_TLS, f5dpt_tls_handle);
4175 dissector_add_uint("f5ethtrailer.tls_type_ver", F5_DPT_TLS_PRE13_STD << 16 | 0,
4176 create_dissector_handle(dissect_dpt_trailer_tls_type0, proto_f5ethtrailer_dpt_tls));
4177 dissector_add_uint("f5ethtrailer.tls_type_ver", F5_DPT_TLS_PRE13_EXT << 16 | 0,
4178 create_dissector_handle(dissect_dpt_trailer_tls_extended, proto_f5ethtrailer_dpt_tls));
4179 dissector_add_uint("f5ethtrailer.tls_type_ver", F5_DPT_TLS_13_STD << 16 | 0,
4180 create_dissector_handle(dissect_dpt_trailer_tls_type2, proto_f5ethtrailer_dpt_tls));
4181 dissector_add_uint("f5ethtrailer.tls_type_ver", F5_DPT_TLS_13_STD << 16 | 1,
4182 create_dissector_handle(dissect_dpt_trailer_tls_type2, proto_f5ethtrailer_dpt_tls));
4183 dissector_add_uint("f5ethtrailer.tls_type_ver", F5_DPT_TLS_13_EXT << 16 | 0,
4184 create_dissector_handle(dissect_dpt_trailer_tls_extended, proto_f5ethtrailer_dpt_tls));
4186 /* These fields are duplicates of other, well-known fields so that
4187 * filtering on these fields will also pick up data out of the
4188 * trailers.
4191 hf_ip_ipaddr = proto_registrar_get_id_byname("ip.addr");
4192 hf_ip6_ip6addr = proto_registrar_get_id_byname("ipv6.addr");
4193 hf_tcp_tcpport = proto_registrar_get_id_byname("tcp.port");
4194 hf_udp_udpport = proto_registrar_get_id_byname("udp.port");
4197 /*===============================================================================================*/
4198 /* This section is rendering the F5 tcpdump file properties packet.
4200 * Note that this should technically have a protocol tree item, but it does not. The data
4201 * rendered by this dissector should be the only data in the packet. So, rather than requiring
4202 * the user to select the packet and expand the tree to view it, putting the items into the top
4203 * tree essentially renders them expanded. There is no proto_tree_expand_item() sort of call that
4204 * can be used to do this in a data-encapsulated manner (it can be hacked, but I opted for this
4205 * method instead).
4208 /* Platform ID to platform name mapping
4210 * https://my.f5.com/manage/s/article/K9476
4211 * https://my.f5.com/manage/s/article/K86001294
4212 * https://my.f5.com/manage/s/article/K4309
4215 static const string_string f5info_platform_strings[] = {
4216 /* rSeries */
4217 {"C128", "F5 r10000 Series (r10600, r10800, r10900)"},
4218 {"C129", "F5 r5000 Series (r5600, r5800, r5900)"},
4219 {"C130", "F5 r2000 Series (r2600, r2800)"},
4220 {"C131", "F5 r4000 Series (r4600, r4800)"},
4221 {"C136", "F5 r5920-DF"},
4222 {"C137", "F5 r10920-DF"},
4223 {"C138", "F5 r12000 Series (r12600-DS, r12800-DS, r12900-DS)"},
4225 /* VELOS */
4226 {"F101", "VELOS CX410 Chassis"},
4227 {"R100", "VELOS CX1610 Chassis"},
4229 /* iSeries */
4230 {"C115", "BIG-IP i4000 Series (i4600, i4800)"},
4231 {"C116", "BIG-IP i10000 Series (i10600, i10800)"},
4232 {"C117", "BIG-IP i2000 Series (i2600, i2800), BIG-IP i850)"},
4233 {"C118", "BIG-IP i7000 Series (i7600, i7800)"},
4234 {"C119", "BIG-IP i5000 Series (i5600, i5800)"},
4235 {"C123", "BIG-IP i11600, i11800"},
4236 {"C124", "BIG-IP i11400-DS, i11600-DS, i11800-DS"},
4237 {"C125", "BIG-IP i5820-DF"},
4238 {"C126", "BIG-IP i7820-DF"},
4239 {"D116", "BIG-IP i15000 Series (i15600, i15800)"},
4240 {"D120", "BIG-IP i15820-DF"},
4242 /* Standard series */
4243 {"C102", "BIG-IP 1600"},
4244 {"C103", "BIG-IP 3600"},
4245 {"C106", "BIG-IP 3900, Enterprise Manager 4000"},
4246 {"C109", "BIG-IP 5000s, 5050s, 5200v, 5250v, 5250v-F"},
4247 {"C112", "BIG-IP 2000 Series (2000s, 2200s)"},
4248 {"C113", "BIG-IP 4000 Series (4000s, 4200v)"},
4249 {"C114", "BIG-IP 800 (LTM only)"},
4250 {"D104", "BIG-IP 6900 Series (6900, 6900S, 6900F, 6900N)"},
4251 {"D106", "BIG-IP 8900"},
4252 {"D107", "BIG-IP 8950"},
4253 {"D110", "BIG-IP 7000 Series (7000s, 7050s, 7055s, 7200v, 7250v, 7255v), BIG-IQ 7000"},
4254 {"D111", "BIG-IP 12000 Series (12250v)"},
4255 {"D112", "BIG-IP 10050 Series (10150s-NEBS, 10350v (AC), 10350v-NEBS, 10350v-FIPS)"},
4256 {"D113", "BIG-IP 10000 Series (10000s, 10050s, 10055, 10200v, 10250v, 10255)"},
4257 {"E101", "BIG-IP 11000, BIG-IP 11000 FIPS"},
4258 {"E102", "BIG-IP 11050, 11050 NEBS"},
4259 {"E103", "BIG-IP 11050N"},
4261 /* VIPRION */
4262 {"A100", "VIPRION B4100 Blade"},
4263 {"A105", "VIPRION B4100N Blade"},
4264 {"A107", "VIPRION B4200 Blade"},
4265 {"A108", "VIPRION B4300 Blade"},
4266 {"A109", "VIPRION B2100 Blade"},
4267 {"A110", "VIPRION B4340N Blade"},
4268 {"A111", "VIPRION B4200N Blade"},
4269 {"A112", "VIPRION B2250 Blade"},
4270 {"A113", "VIPRION B2150 Blade"},
4271 {"A114", "VIPRION B4450 Blade"},
4273 /* Herculon */
4274 {"C120", "Herculon i2800"},
4275 {"C121", "Herculon i5800"},
4276 {"C122", "Herculon i10800"},
4278 /* Virtualized platforms*/
4279 {"Z100", "BIG-IP Virtual Edition (VE)"},
4280 {"Z101", "BIG-IP vCMP Guest"},
4281 {NULL, NULL}
4283 /* It currently looks like these do not apply. Kept for completeness only */
4284 #if 0
4285 {"A118", "VELOS BX110 Blade"},
4286 {"A119", "VELOS BX520 Blade"},
4287 {"C21", "FirePass 1200"},
4288 {"D46", "FirePass 4100"},
4289 {"D63", "BIG-IP 6400-NEBS"},
4290 {"D101", "FirePass 4300"},
4291 {"D114", "VIPRION C2200 Chassis"},
4292 {"F100", "VIPRION C2400 Chassis"},
4293 {"J100", "VIPRION C4400 Chassis"},
4294 {"J101", "VIPRION C4400N Chassis"},
4295 {"J102", "VIPRION C4480 Chassis"},
4296 {"J103", "VIPRION C4480N Chassis"},
4297 {"S100", "VIPRION C4800 Chassis"},
4298 {"S101", "VIPRION C4800N Chassis"},
4299 #endif
4302 * @brief Dissector for rendering the F5 tcpdump file properties packet.
4304 * This is a heuristic dissector because the Ethernet dissector has a hook
4305 * to pass packets to a dissector before it gets rendered as Ethernet and
4306 * that seems to make sense here. This could be a registered dissector on
4307 * the Ethertype 0x5ff, but this way it can skip a packet and let other
4308 * dissectors have a chance to dissect (and the Ethernet dissector does not
4309 * waste its time rendering Ethernet information for no reason).
4311 * TODO: This should return int with how many bytes were consumed.
4313 * @param tvb Pointer to tvb
4314 * @param pinfo Pointer to packet info
4315 * @param tree Pointer to protocol tree
4316 * @param data Pointer to data structure (unused)
4317 * @return bool
4319 static bool
4320 dissect_f5fileinfo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
4322 unsigned offset = 0;
4323 const uint8_t *object;
4324 const char *platform = NULL;
4325 const char *platform_name = NULL;
4326 int objlen;
4327 struct f5fileinfo_tap_data *tap_data;
4329 /* Must be the first packet */
4330 if (pinfo->fd->num > 1)
4331 return false;
4333 if (tvb_captured_length(tvb) >= (int)sizeof(fileinfomagic1)) {
4334 if (tvb_memeql(tvb, 0, fileinfomagic1, sizeof(fileinfomagic1)) == 0)
4335 offset = sizeof(fileinfomagic1);
4338 /* Didn't find the magic at the start of the packet. */
4339 if (offset == 0)
4340 return false;
4342 col_set_str(pinfo->cinfo, COL_PROTOCOL, "FILEINFO");
4344 tap_data = wmem_new0(pinfo->pool, struct f5fileinfo_tap_data);
4345 tap_data->magic = F5FILEINFO_TAP_MAGIC;
4347 while (tvb_captured_length_remaining(tvb, offset)) {
4348 object = tvb_get_stringz_enc(pinfo->pool, tvb, offset, &objlen, ENC_ASCII);
4350 if (objlen <= 0 || object == NULL)
4351 break;
4353 if (strncmp(object, "CMD: ", 5) == 0) {
4354 proto_tree_add_string(tree, hf_fi_command, tvb, offset + 5, objlen - 5, &object[5]);
4355 col_add_str(pinfo->cinfo, COL_INFO, &object[5]);
4356 } else if (strncmp(object, "VER: ", 5) == 0) {
4357 unsigned i;
4358 const uint8_t *c;
4360 proto_tree_add_string(tree, hf_fi_version, tvb, offset + 5, objlen - 5, &object[5]);
4361 for (c = object; *c && (*c < '0' || *c > '9'); c++);
4362 for (i = 0; i < 6 && *c; c++) {
4363 if (*c < '0' || *c > '9') {
4364 i++;
4365 continue;
4367 tap_data->ver[i] = (tap_data->ver[i] * 10) + (*c - '0');
4369 } else if (strncmp(object, "HOST: ", 6) == 0)
4370 proto_tree_add_string(tree, hf_fi_hostname, tvb, offset + 6, objlen - 6, &object[6]);
4371 else if (strncmp(object, "PLAT: ", 6) == 0) {
4372 proto_tree_add_string(tree, hf_fi_platform, tvb, offset + 6, objlen - 6, &object[6]);
4373 platform = &object[6];
4374 platform_name = str_to_str(platform, f5info_platform_strings, "Unknown, please report");
4375 proto_tree_add_string_format(tree, hf_fi_platformname, tvb, offset + 6, objlen - 6, platform_name,
4376 "%s: %s", platform, platform_name);
4377 } else if (strncmp(object, "PROD: ", 6) == 0)
4378 proto_tree_add_string(tree, hf_fi_product, tvb, offset + 6, objlen - 6, &object[6]);
4379 else if (strncmp(object, "SESS: ", 6) == 0)
4380 proto_tree_add_string(tree, hf_fi_session, tvb, offset + 6, objlen - 6, &object[6]);
4382 offset += objlen;
4384 tvb_set_reported_length(tvb, offset);
4385 tap_queue_packet(tap_f5fileinfo, pinfo, tap_data);
4386 f5eth_process_f5info(platform);
4387 return true;
4388 } /* dissect_f5fileinfo() */
4391 * @brief F5FILEINFO protocol dissector registration
4394 void
4395 proto_register_f5fileinfo(void)
4397 static hf_register_info hf[] =
4398 { { &hf_fi_command,
4399 { "Tcpdump command line", "f5fileinfo.cmdline", FT_STRINGZ, BASE_NONE,
4400 NULL, 0x0, NULL, HFILL }
4402 { &hf_fi_version,
4403 { "Platform version", "f5fileinfo.version", FT_STRINGZ, BASE_NONE,
4404 NULL, 0x0, NULL, HFILL }
4406 { &hf_fi_hostname,
4407 { "Hostname", "f5fileinfo.hostname", FT_STRINGZ, BASE_NONE,
4408 NULL, 0x0, NULL, HFILL }
4410 { &hf_fi_platform,
4411 { "Platform", "f5fileinfo.platform", FT_STRINGZ, BASE_NONE,
4412 NULL, 0x0, NULL, HFILL }
4414 { &hf_fi_platformname,
4415 { "Platform name", "f5fileinfo.platformname", FT_STRINGZ, BASE_NONE,
4416 NULL, 0x0, NULL, HFILL }
4418 { &hf_fi_product,
4419 { "Platform product", "f5fileinfo.product", FT_STRINGZ, BASE_NONE,
4420 NULL, 0x0, NULL, HFILL }
4422 { &hf_fi_session,
4423 { "Session", "f5fileinfo.session", FT_STRINGZ, BASE_NONE,
4424 NULL, 0x0, NULL, HFILL }
4428 proto_f5fileinfo = proto_register_protocol("F5 Capture Information", "FILEINFO", "f5fileinfo");
4429 proto_register_field_array(proto_f5fileinfo, hf, array_length(hf));
4431 tap_f5fileinfo = register_tap("f5fileinfo");
4435 * @brief F5FILEINFO dissector handoff
4438 void
4439 proto_reg_handoff_f5fileinfo(void)
4441 heur_dissector_add("eth", dissect_f5fileinfo, "F5 Capture Information", "f5fileinfo",
4442 proto_f5fileinfo, HEURISTIC_ENABLE);
4446 * Editor modelines - https://www.wireshark.org/tools/modelines.html
4448 * Local variables:
4449 * c-basic-offset: 4
4450 * tab-width: 8
4451 * indent-tabs-mode: nil
4452 * End:
4454 * vi: set shiftwidth=4 tabstop=8 expandtab:
4455 * :indentSize=4:tabSize=8:noTabs=true: