2 * Local Service Discovery packet dissector
4 * From http://bittorrent.org/beps/bep_0014.html
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include <epan/packet.h>
16 #include <epan/expert.h>
17 #include <epan/strutil.h>
18 #include <wsutil/pint.h>
19 #include <wsutil/strtoi.h>
21 void proto_register_lsd(void);
22 void proto_reg_handoff_lsd(void);
24 #define LSD_MULTICAST_ADDRESS 0xEFC0988F /* 239.192.152.143 */
28 static int hf_lsd_header
;
29 static int hf_lsd_host
;
30 static int hf_lsd_port
;
31 static int hf_lsd_infohash
;
32 static int hf_lsd_cookie
;
36 static expert_field ei_lsd_field
;
39 parse_string_field(proto_tree
*tree
, int hf
, packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, int* next_offset
, int* linelen
)
42 header_field_info
* hf_info
= proto_registrar_get_nth(hf
);
43 char **field_and_value
;
47 *linelen
= tvb_find_line_end(tvb
, offset
, -1, next_offset
, false);
51 str
= tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, *linelen
, ENC_ASCII
);
52 if (g_ascii_strncasecmp(str
, hf_info
->name
, strlen(hf_info
->name
)) == 0)
54 field_and_value
= wmem_strsplit(pinfo
->pool
, str
, ":", 2);
55 p
= field_and_value
[1];
57 while(g_ascii_isspace(*p
))
59 proto_tree_add_string(tree
, hf
, tvb
, offset
, *linelen
, p
);
63 ti
= proto_tree_add_string_format(tree
, hf
, tvb
, offset
, *linelen
, str
, "%s", str
);
64 expert_add_info_format(pinfo
, ti
, &ei_lsd_field
, "%s field malformed", hf_info
->name
);
70 dissect_lsd(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
72 proto_item
*ti
= NULL
;
74 int offset
= 0, next_offset
= 0, linelen
;
76 char **field_and_value
;
80 linelen
= tvb_find_line_end(tvb
, offset
, -1, &next_offset
, false);
84 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "LSD");
85 col_clear(pinfo
->cinfo
, COL_INFO
);
87 /* Create display subtree for the protocol */
88 ti
= proto_tree_add_item(tree
, proto_lsd
, tvb
, 0, -1, ENC_NA
);
89 lsd_tree
= proto_item_add_subtree(ti
, ett_lsd
);
91 proto_tree_add_item(lsd_tree
, hf_lsd_header
, tvb
, offset
, linelen
, ENC_ASCII
);
94 if (!parse_string_field(lsd_tree
, hf_lsd_host
, pinfo
, tvb
, offset
, &next_offset
, &linelen
))
95 return offset
+linelen
;
98 linelen
= tvb_find_line_end(tvb
, offset
, -1, &next_offset
, false);
100 return offset
+linelen
;
101 str
= tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, linelen
, ENC_ASCII
);
102 if (g_ascii_strncasecmp(str
, "Port", strlen("Port")) == 0)
104 field_and_value
= wmem_strsplit(pinfo
->pool
, str
, ":", 2);
105 valid
= ws_strtou16(field_and_value
[1], NULL
, &port
);
106 ti
= proto_tree_add_uint(lsd_tree
, hf_lsd_port
, tvb
, offset
, linelen
, port
);
109 expert_add_info_format(pinfo
, ti
, &ei_lsd_field
, "Port value malformed");
114 ti
= proto_tree_add_uint(lsd_tree
, hf_lsd_port
, tvb
, offset
, 0, 0xFFFF);
115 expert_add_info_format(pinfo
, ti
, &ei_lsd_field
, "Port field malformed");
117 proto_item_set_len(ti
, linelen
);
119 offset
= next_offset
;
120 if (!parse_string_field(lsd_tree
, hf_lsd_infohash
, pinfo
, tvb
, offset
, &next_offset
, &linelen
))
121 return offset
+linelen
;
123 offset
= next_offset
;
124 linelen
= tvb_find_line_end(tvb
, offset
, -1, &next_offset
, false);
126 return offset
+linelen
;
127 /* Cookie is optional */
128 if (tvb_strncaseeql(tvb
, offset
, "cookie", strlen("cookie")) == 0)
130 if (!parse_string_field(lsd_tree
, hf_lsd_cookie
, pinfo
, tvb
, offset
, &next_offset
, &linelen
))
131 return offset
+linelen
;
134 return tvb_captured_length(tvb
);
138 dissect_lsd_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
140 if (pinfo
->dst
.type
== AT_IPv4
&& pntoh32(pinfo
->dst
.data
) == LSD_MULTICAST_ADDRESS
&& pinfo
->destport
== LSD_PORT
)
141 return (dissect_lsd(tvb
, pinfo
, tree
, data
) != 0);
143 if (pinfo
->dst
.type
== AT_IPv6
&& pinfo
->destport
== LSD_PORT
)
144 return (dissect_lsd(tvb
, pinfo
, tree
, data
) != 0);
150 proto_register_lsd(void)
152 static hf_register_info hf
[] = {
154 { "Header", "lsd.header",
155 FT_STRING
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
158 { "Host", "lsd.host",
159 FT_STRING
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
162 { "Port", "lsd.port",
163 FT_UINT32
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
166 { "Infohash", "lsd.infohash",
167 FT_STRING
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
170 { "cookie", "lsd.cookie",
171 FT_STRING
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
175 static int *ett
[] = {
179 static ei_register_info ei
[] = {
180 { &ei_lsd_field
, { "lsd.malformed_field", PI_MALFORMED
, PI_ERROR
, "Malformed LDS field", EXPFILL
}},
183 expert_module_t
* expert_lsd
;
185 proto_lsd
= proto_register_protocol("Local Service Discovery", "LSD", "lsd");
187 proto_register_field_array(proto_lsd
, hf
, array_length(hf
));
188 proto_register_subtree_array(ett
, array_length(ett
));
189 expert_lsd
= expert_register_protocol(proto_lsd
);
190 expert_register_field_array(expert_lsd
, ei
, array_length(ei
));
194 proto_reg_handoff_lsd(void)
196 heur_dissector_add( "udp", dissect_lsd_heur
, "LSD over UDP", "lsd_udp", proto_lsd
, HEURISTIC_ENABLE
);
200 * Editor modelines - https://www.wireshark.org/tools/modelines.html
205 * indent-tabs-mode: nil
208 * ex: set shiftwidth=2 tabstop=8 expandtab:
209 * :indentSize=2:tabSize=8:noTabs=true: