diff options
author | Peter Wu <peter@lekensteyn.nl> | 2017-04-04 21:30:45 +0200 |
---|---|---|
committer | Michael Mann <mmann78@netscape.net> | 2017-04-09 01:50:27 +0000 |
commit | 92ebd6389203448168a2769fa473bbbad95ec159 (patch) | |
tree | 811503a22c39f5d3c7ad093122956922ffca0d24 /epan | |
parent | 0add542dbfc6d0467d14ebb2abbde0ebd1427ce1 (diff) |
netlink: let subdissectors handle the netlink header
Let subdissectors handle parsing and addition of the Netlink header
instead of doing this before calling subdissectors. After this patch:
- Protocol filters like "netlink-netfilter" can be used to match
packets (previously only a text item was added to the tree).
- Subdissectors have more freedom in modifying the type field, so now
it shows the correct type directly rather than "Message type:
Protocol-specific".
- netfilter: the type fields are now actually linked to a tvb,
previously it was linked to a NULL tvb.
- netfilter: fix unintended rejection of packets (the length should
have been added to the offset, otherwise it would fallback to the
data dissector).
- Now subdissectors will not be called for control messages (so the
netlink-conntrack.pcap sample now shows "Netlink" instead of "Netlink
route" for the "End of dump" control message).
Change-Id: I2ab1bef91fb0080664195b281a6a45c9702914e5
Reviewed-on: https://code.wireshark.org/review/20910
Petri-Dish: Peter Wu <peter@lekensteyn.nl>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Michael Mann <mmann78@netscape.net>
Diffstat (limited to 'epan')
-rw-r--r-- | epan/dissectors/packet-netlink-netfilter.c | 49 | ||||
-rw-r--r-- | epan/dissectors/packet-netlink-route.c | 44 | ||||
-rw-r--r-- | epan/dissectors/packet-netlink-sock_diag.c | 28 | ||||
-rw-r--r-- | epan/dissectors/packet-netlink.c | 82 | ||||
-rw-r--r-- | epan/dissectors/packet-netlink.h | 6 |
5 files changed, 121 insertions, 88 deletions
diff --git a/epan/dissectors/packet-netlink-netfilter.c b/epan/dissectors/packet-netlink-netfilter.c index 40c554a8ee..64136bcb4b 100644 --- a/epan/dissectors/packet-netlink-netfilter.c +++ b/epan/dissectors/packet-netlink-netfilter.c @@ -239,6 +239,8 @@ enum ws_ipset_ip_attr { }; +static int proto_netlink_netfilter; + static int ett_netlink_netfilter = -1; static int ett_nfq_config_attr = -1; static int ett_nfq_attr = -1; @@ -735,11 +737,14 @@ static int dissect_netfilter_ulog(tvbuff_t *tvb, netlink_netfilter_info_t *info, proto_tree *tree, int offset) { enum ws_nfulnl_msg_types type = (enum ws_nfulnl_msg_types) (info->data->type & 0xff); + tvbuff_t *next_tvb; switch (type) { case WS_NFULNL_MSG_PACKET: /* Note that NFLOG dissects the nfgenmsg header */ - call_dissector(nflog_handle, tvb, info->pinfo, tree); + next_tvb = tvb_new_subset_remaining(tvb, offset); + call_dissector(nflog_handle, next_tvb, info->pinfo, tree); + offset = tvb_reported_length(tvb); break; default: @@ -1117,35 +1122,34 @@ static header_field_info hfi_netlink_netfilter_subsys NETLINK_NETFILTER_HFI_INIT static int dissect_netlink_netfilter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *_data) { - struct packet_netlink_data *data = NULL; + struct packet_netlink_data *data = (struct packet_netlink_data *)_data; netlink_netfilter_info_t info; - int offset; - - if (_data) { - if (((struct packet_netlink_data *) _data)->magic == PACKET_NETLINK_MAGIC) - data = (struct packet_netlink_data *) _data; - } + proto_tree *nlmsg_tree; + proto_item *pi; + int offset = 0; - DISSECTOR_ASSERT(data); + DISSECTOR_ASSERT(data && data->magic == PACKET_NETLINK_MAGIC); col_set_str(pinfo->cinfo, COL_PROTOCOL, "Netlink netfilter"); col_clear(pinfo->cinfo, COL_INFO); - proto_item_set_text(tree, "Linux netlink netfilter message"); + pi = proto_tree_add_item(tree, proto_registrar_get_nth(proto_netlink_netfilter), tvb, 0, -1, ENC_NA); + nlmsg_tree = proto_item_add_subtree(pi, ett_netlink_netfilter); - /* XXX, from header tvb */ - proto_tree_add_uint(tree, &hfi_netlink_netfilter_subsys, NULL, 0, 0, data->type); + /* Netlink message header (nlmsghdr) */ + offset = dissect_netlink_header(tvb, nlmsg_tree, offset, data->encoding, NULL, NULL); + proto_tree_add_item(nlmsg_tree, &hfi_netlink_netfilter_subsys, tvb, 4, 2, data->encoding); switch (data->type >> 8) { case WS_NFNL_SUBSYS_QUEUE: - proto_tree_add_uint(tree, &hfi_nfq_type, NULL, 0, 0, data->type); + proto_tree_add_item(nlmsg_tree, &hfi_nfq_type, tvb, 4, 2, data->encoding); break; case WS_NFNL_SUBSYS_ULOG: - proto_tree_add_uint(tree, &hfi_netlink_netfilter_ulog_type, NULL, 0, 0, data->type); + proto_tree_add_item(nlmsg_tree, &hfi_netlink_netfilter_ulog_type, tvb, 4, 2, data->encoding); break; case WS_NFNL_SUBSYS_IPSET: - proto_tree_add_uint(tree, &hfi_ipset_command, NULL, 0, 0, data->type); + proto_tree_add_item(nlmsg_tree, &hfi_ipset_command, tvb, 4, 2, data->encoding); break; } @@ -1154,19 +1158,22 @@ dissect_netlink_netfilter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, v info.data = data; info.hw_protocol = 0; - offset = 0; - switch (data->type >> 8) { case WS_NFNL_SUBSYS_QUEUE: - offset = dissect_netfilter_queue(tvb, &info, tree, offset); + offset = dissect_netfilter_queue(tvb, &info, nlmsg_tree, offset); break; case WS_NFNL_SUBSYS_ULOG: - offset = dissect_netfilter_ulog(tvb, &info, tree, offset); + offset = dissect_netfilter_ulog(tvb, &info, nlmsg_tree, offset); break; case WS_NFNL_SUBSYS_IPSET: - offset = dissect_netfilter_ipset(tvb, &info, tree, offset); + offset = dissect_netfilter_ipset(tvb, &info, nlmsg_tree, offset); + break; + + default: + call_data_dissector(tvb_new_subset_remaining(tvb, offset), pinfo, nlmsg_tree); + offset = tvb_reported_length(tvb); break; } @@ -1242,8 +1249,6 @@ proto_register_netlink_netfilter(void) &ett_ipset_ip_attr, }; - int proto_netlink_netfilter; - proto_netlink_netfilter = proto_register_protocol("Linux netlink netfilter protocol", "netfilter", "netlink-netfilter" ); hfi_netlink_netfilter = proto_registrar_get_nth(proto_netlink_netfilter); diff --git a/epan/dissectors/packet-netlink-route.c b/epan/dissectors/packet-netlink-route.c index c00090e0e3..0c328b0b2d 100644 --- a/epan/dissectors/packet-netlink-route.c +++ b/epan/dissectors/packet-netlink-route.c @@ -287,6 +287,8 @@ enum { WS_NUD_PERMANENT = 0x80 }; +static int proto_netlink_route; + static dissector_handle_t netlink_route_handle; static header_field_info *hfi_netlink_route = NULL; @@ -970,32 +972,24 @@ static header_field_info hfi_netlink_route_nltype NETLINK_ROUTE_HFI_INIT = static int dissect_netlink_route(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *_data) { - int offset; - struct netlink_route_info info; - struct packet_netlink_data *data = NULL; - - if (_data) { - if (((struct packet_netlink_data *) _data)->magic == PACKET_NETLINK_MAGIC) - data = (struct packet_netlink_data *) _data; - } + struct packet_netlink_data *data = (struct packet_netlink_data *)_data; + proto_tree *nlmsg_tree; + proto_item *pi; + int offset = 0; - DISSECTOR_ASSERT(data); + DISSECTOR_ASSERT(data && data->magic == PACKET_NETLINK_MAGIC); col_set_str(pinfo->cinfo, COL_PROTOCOL, "Netlink route"); col_clear(pinfo->cinfo, COL_INFO); - offset = 0; + pi = proto_tree_add_item(tree, proto_registrar_get_nth(proto_netlink_route), tvb, 0, -1, ENC_NA); + nlmsg_tree = proto_item_add_subtree(pi, ett_netlink_route); - if (tree) { - proto_item_set_text(tree, "Linux rtnetlink (route netlink) message"); - - /* XXX, from header tvb */ - proto_tree_add_uint(tree, &hfi_netlink_route_nltype, NULL, 0, 0, data->type); - } + /* Netlink message header (nlmsghdr) */ + offset = dissect_netlink_header(tvb, nlmsg_tree, offset, data->encoding, &hfi_netlink_route_nltype, NULL); info.encoding = data->encoding; - info.pinfo = pinfo; info.data = data; @@ -1005,9 +999,9 @@ dissect_netlink_route(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void case WS_RTM_GETLINK: /* backward compatibility with legacy tools; 16 is sizeof(struct ifinfomsg) */ info.legacy = (data->type == WS_RTM_GETLINK) && (tvb_reported_length_remaining(tvb, offset) < 16); - offset = dissect_netlink_route_ifinfomsg(tvb, &info, tree, offset); + offset = dissect_netlink_route_ifinfomsg(tvb, &info, nlmsg_tree, offset); /* Optional attributes */ - offset = dissect_netlink_route_attributes(tvb, &hfi_netlink_route_ifla_attr_type, &info, tree, offset, dissect_netlink_route_ifla_attrs); + offset = dissect_netlink_route_attributes(tvb, &hfi_netlink_route_ifla_attr_type, &info, nlmsg_tree, offset, dissect_netlink_route_ifla_attrs); break; case WS_RTM_NEWADDR: @@ -1015,9 +1009,9 @@ dissect_netlink_route(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void case WS_RTM_GETADDR: /* backward compatibility with legacy tools; 8 is sizeof(struct ifaddrmsg) */ info.legacy = (data->type == WS_RTM_GETADDR) && (tvb_reported_length_remaining(tvb, offset) < 8); - offset = dissect_netlink_route_ifaddrmsg(tvb, &info, tree, offset); + offset = dissect_netlink_route_ifaddrmsg(tvb, &info, nlmsg_tree, offset); /* Optional attributes */ - offset = dissect_netlink_route_attributes(tvb, &hfi_netlink_route_ifa_attr_type, &info, tree, offset, dissect_netlink_route_ifa_attrs); + offset = dissect_netlink_route_attributes(tvb, &hfi_netlink_route_ifa_attr_type, &info, nlmsg_tree, offset, dissect_netlink_route_ifa_attrs); break; case WS_RTM_NEWROUTE: @@ -1025,9 +1019,9 @@ dissect_netlink_route(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void case WS_RTM_GETROUTE: /* backward compatibility with legacy tools; 12 is sizeof(struct rtmsg) */ info.legacy = (data->type == WS_RTM_GETROUTE) && (tvb_reported_length_remaining(tvb, offset) < 12); - offset = dissect_netlink_route_rtmsg(tvb, &info, tree, offset); + offset = dissect_netlink_route_rtmsg(tvb, &info, nlmsg_tree, offset); /* Optional attributes */ - offset = dissect_netlink_route_attributes(tvb, &hfi_netlink_route_rta_attr_type, &info, tree, offset, dissect_netlink_route_route_attrs); + offset = dissect_netlink_route_attributes(tvb, &hfi_netlink_route_rta_attr_type, &info, nlmsg_tree, offset, dissect_netlink_route_route_attrs); break; case WS_RTM_NEWNEIGH: @@ -1035,7 +1029,7 @@ dissect_netlink_route(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void case WS_RTM_GETNEIGH: /* backward compatibility with legacy tools; 12 is sizeof(struct ndmsg) */ info.legacy = (data->type == WS_RTM_GETNEIGH) && (tvb_reported_length_remaining(tvb, offset) < 12); - offset = dissect_netlink_route_ndmsg(tvb, &info, tree, offset); + offset = dissect_netlink_route_ndmsg(tvb, &info, nlmsg_tree, offset); break; } @@ -1103,8 +1097,6 @@ proto_register_netlink_route(void) &ett_netlink_route_if_flags }; - int proto_netlink_route; - proto_netlink_route = proto_register_protocol("Linux rtnetlink (route netlink) protocol", "rtnetlink", "netlink-route" ); hfi_netlink_route = proto_registrar_get_nth(proto_netlink_route); diff --git a/epan/dissectors/packet-netlink-sock_diag.c b/epan/dissectors/packet-netlink-sock_diag.c index b118a0f87e..1592072c9d 100644 --- a/epan/dissectors/packet-netlink-sock_diag.c +++ b/epan/dissectors/packet-netlink-sock_diag.c @@ -39,6 +39,8 @@ typedef struct { int encoding; /* copy of data->encoding */ } netlink_sock_diag_info_t; +static int proto_netlink_sock_diag; + static dissector_handle_t netlink_sock_diag_handle; static header_field_info *hfi_netlink_sock_diag = NULL; @@ -1103,26 +1105,22 @@ static header_field_info hfi_netlink_sock_diag_nltype NETLINK_SOCK_DIAG_HFI_INIT static int dissect_netlink_sock_diag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *_data) { - struct packet_netlink_data *data = NULL; + struct packet_netlink_data *data = (struct packet_netlink_data *)_data; netlink_sock_diag_info_t info; - int offset; - - if (_data) { - if (((struct packet_netlink_data *) _data)->magic == PACKET_NETLINK_MAGIC) - data = (struct packet_netlink_data *) _data; - } + proto_tree *nlmsg_tree; + proto_item *pi; + int offset = 0; - DISSECTOR_ASSERT(data); + DISSECTOR_ASSERT(data && data->magic == PACKET_NETLINK_MAGIC); col_set_str(pinfo->cinfo, COL_PROTOCOL, "Netlink sock diag"); col_clear(pinfo->cinfo, COL_INFO); - if (tree) { - proto_item_set_text(tree, "Linux netlink sock diag message"); + pi = proto_tree_add_item(tree, proto_registrar_get_nth(proto_netlink_sock_diag), tvb, 0, -1, ENC_NA); + nlmsg_tree = proto_item_add_subtree(pi, ett_netlink_sock_diag); - /* XXX, from header tvb */ - proto_tree_add_uint(tree, &hfi_netlink_sock_diag_nltype, NULL, 0, 0, data->type); - } + /* Netlink message header (nlmsghdr) */ + offset = dissect_netlink_header(tvb, nlmsg_tree, offset, data->encoding, &hfi_netlink_sock_diag_nltype, NULL); info.encoding = data->encoding; info.pinfo = pinfo; @@ -1137,7 +1135,7 @@ dissect_netlink_sock_diag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, v break; case WS_SOCK_DIAG_BY_FAMILY: - offset = dissect_sock_diag_by_family(tvb, &info, tree, offset); + offset = dissect_sock_diag_by_family(tvb, &info, nlmsg_tree, offset); break; } @@ -1221,8 +1219,6 @@ proto_register_netlink_sock_diag(void) &ett_netlink_sock_diag_attr }; - int proto_netlink_sock_diag; - proto_netlink_sock_diag = proto_register_protocol("Linux netlink sock diag protocol", "sock_diag", "netlink-sock_diag" ); hfi_netlink_sock_diag = proto_registrar_get_nth(proto_netlink_sock_diag); diff --git a/epan/dissectors/packet-netlink.c b/epan/dissectors/packet-netlink.c index 06cb9ec154..3d73982eea 100644 --- a/epan/dissectors/packet-netlink.c +++ b/epan/dissectors/packet-netlink.c @@ -340,27 +340,43 @@ dissect_netlink_attributes_array(tvbuff_t *tvb, header_field_info *hfi_type, int return dissect_netlink_attributes_common(tvb, hfi_type, ett_array, ett_attrib, data, nl_data, tree, offset, length, cb); } -static int -dissect_netlink_hdr(tvbuff_t *tvb, proto_tree *tree, int offset, int encoding, guint16 *type, guint32 *port_id) +int +dissect_netlink_header(tvbuff_t *tvb, proto_tree *tree, int offset, int encoding, header_field_info *hfi_type, proto_item **pi_type) { guint16 hdr_flags; guint16 hdr_type; - proto_tree *fh_hdr; - proto_item *pi_type; + proto_item *pi; fh_hdr = proto_tree_add_subtree(tree, tvb, offset, 16, ett_netlink_msghdr, NULL, "Header"); proto_tree_add_item(fh_hdr, &hfi_netlink_hdr_len, tvb, offset, 4, encoding); offset += 4; - pi_type = proto_tree_add_item(fh_hdr, &hfi_netlink_hdr_type, tvb, offset, 2, encoding); hdr_type = tvb_get_guint16(tvb, offset, encoding); - if (hdr_type >= WS_NLMSG_MIN_TYPE) { - proto_item_set_text(pi_type, "Message type: Protocol-specific (0x%04x)", hdr_type); + if (hdr_type < WS_NLMSG_MIN_TYPE) { + /* Reserved control messages. */ + hfi_type = &hfi_netlink_hdr_type; + pi = proto_tree_add_item(fh_hdr, hfi_type, tvb, offset, 2, encoding); + } else { + if (hfi_type) { + pi = proto_tree_add_item(fh_hdr, hfi_type, tvb, offset, 2, encoding); + } else { + hfi_type = &hfi_netlink_hdr_type; + pi = proto_tree_add_item(fh_hdr, hfi_type, tvb, offset, 2, encoding); + proto_item_set_text(pi, "Message type: Protocol-specific (0x%04x)", hdr_type); + } } - if (type) { - *type = hdr_type; + if (pi_type) { + *pi_type = pi; + } + /* TODO export hf_try_val_to_str? */ + if (hfi_type->strings && hfi_type->display & BASE_EXT_STRING) { + proto_item_append_text(fh_hdr, " (type: %s)", val_to_str_ext(hdr_type, (value_string_ext *)hfi_type->strings, "0x%04x")); + } else if (hfi_type->strings) { + proto_item_append_text(fh_hdr, " (type: %s)", val_to_str(hdr_type, (const value_string *)hfi_type->strings, "0x%04x")); + } else { + proto_item_append_text(fh_hdr, " (type: 0x%04x)", hdr_type); } offset += 2; @@ -382,7 +398,7 @@ dissect_netlink_hdr(tvbuff_t *tvb, proto_tree *tree, int offset, int encoding, g proto_tree_add_item(fh_hdr, &hfi_netlink_hdr_seq, tvb, offset, 4, encoding); offset += 4; - proto_tree_add_item_ret_uint(fh_hdr, hfi_netlink_hdr_pid.id, tvb, offset, 4, encoding, port_id); + proto_tree_add_item(fh_hdr, &hfi_netlink_hdr_pid, tvb, offset, 4, encoding); offset += 4; return offset; @@ -403,7 +419,7 @@ dissect_netlink_error(tvbuff_t *tvb, proto_tree *tree, int offset, int encoding) proto_tree_add_item(tree, &hfi_netlink_error, tvb, offset, 4, encoding); offset += 4; - dissect_netlink_hdr(tvb, tree, offset, encoding, NULL, NULL); + dissect_netlink_header(tvb, tree, offset, encoding, NULL, NULL); } static int @@ -462,21 +478,17 @@ dissect_netlink(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *_data } while (tvb_reported_length_remaining(tvb, offset) >= 16) { - struct packet_netlink_data data; - int pkt_end_offset; + guint16 msg_type; guint32 pkt_len; guint32 port_id; - proto_tree *fh_msg; - + gboolean dissected = FALSE; pkt_len = tvb_get_guint32(tvb, offset, encoding); pkt_end_offset = offset + pkt_len; - fh_msg = proto_tree_add_subtree(tree, tvb, offset, pkt_len, ett_netlink_msg, NULL, "Netlink message"); - if (pkt_len < 16) { /* * This field includes the length of the 16-byte header, @@ -492,7 +504,9 @@ dissect_netlink(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *_data break; } - offset = dissect_netlink_hdr(tvb, fh_msg, offset, encoding, &data.type, &port_id); + /* message type field comes after length field. */ + msg_type = tvb_get_guint16(tvb, offset + 4, encoding); + port_id = tvb_get_guint32(tvb, offset + 12, encoding); /* XXX */ if (port_id == 0x00) @@ -500,17 +514,37 @@ dissect_netlink(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *_data else pinfo->p2p_dir = P2P_DIR_RECV; /* userspace or kernel -> userspace */ - if (data.type == WS_NLMSG_ERROR) { - dissect_netlink_error(tvb, fh_msg, offset, encoding); - } else if (pkt_len > 16) { + /* + * Try to invoke subdissectors for non-control messages. + */ + if (msg_type >= WS_NLMSG_MIN_TYPE && pkt_len > 16) { + struct packet_netlink_data data; + data.magic = PACKET_NETLINK_MAGIC; data.encoding = encoding; + data.type = msg_type; - next_tvb = tvb_new_subset_length(tvb, offset, pkt_len-16); + next_tvb = tvb_new_subset_length(tvb, offset, pkt_len); - if (!dissector_try_uint_new(netlink_dissector_table, protocol, next_tvb, pinfo, fh_msg, TRUE, &data)) - call_data_dissector(next_tvb, pinfo, fh_msg); + if (dissector_try_uint_new(netlink_dissector_table, protocol, next_tvb, pinfo, tree, TRUE, &data)) { + dissected = TRUE; + } + } + if (!dissected) { + /* + * No subdissector was called, add a new layer with the + * header and the payload. Note that pkt_len>=16. + */ + fh_msg = proto_tree_add_subtree(tree, tvb, offset, pkt_len, ett_netlink_msg, NULL, "Netlink message"); + offset = dissect_netlink_header(tvb, fh_msg, offset, encoding, NULL, NULL); + + if (msg_type == WS_NLMSG_ERROR) { + dissect_netlink_error(tvb, fh_msg, offset, encoding); + } else if (pkt_len > 16) { + next_tvb = tvb_new_subset_length(tvb, offset, pkt_len - 16); + call_data_dissector(next_tvb, pinfo, fh_msg); + } } offset = pkt_end_offset; diff --git a/epan/dissectors/packet-netlink.h b/epan/dissectors/packet-netlink.h index e02cd685fe..fd379fe507 100644 --- a/epan/dissectors/packet-netlink.h +++ b/epan/dissectors/packet-netlink.h @@ -105,6 +105,12 @@ struct packet_netlink_data { guint16 type; }; +/** + * Dissects the Netlink message header (struct nlmsghdr). The "hfi_type" field + * is added for the "nlmsg_type" field and returned into pi_type. + */ +int dissect_netlink_header(tvbuff_t *tvb, proto_tree *tree, int offset, int encoding, header_field_info *hfi_type, proto_item **pi_type); + typedef int netlink_attributes_cb_t(tvbuff_t *, void *data, proto_tree *, int nla_type, int offset, int len); int dissect_netlink_attributes(tvbuff_t *tvb, header_field_info *hfi_type, int ett, void *data, struct packet_netlink_data *nl_data, proto_tree *tree, int offset, int length, netlink_attributes_cb_t cb); |