/src/wireshark/epan/dissectors/packet-lsd.c
Line | Count | Source |
1 | | /* packet-lsd.c |
2 | | * Local Service Discovery packet dissector |
3 | | * |
4 | | * From http://bittorrent.org/beps/bep_0014.html |
5 | | * |
6 | | * Wireshark - Network traffic analyzer |
7 | | * By Gerald Combs <gerald@wireshark.org> |
8 | | * Copyright 1998 Gerald Combs |
9 | | * |
10 | | * SPDX-License-Identifier: GPL-2.0-or-later |
11 | | */ |
12 | | |
13 | | #include "config.h" |
14 | | |
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> |
20 | | |
21 | | void proto_register_lsd(void); |
22 | | void proto_reg_handoff_lsd(void); |
23 | | |
24 | 1.42k | #define LSD_MULTICAST_ADDRESS 0xEFC0988F /* 239.192.152.143 */ |
25 | 227 | #define LSD_PORT 6771 |
26 | | |
27 | | static int proto_lsd; |
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; |
33 | | |
34 | | static int ett_lsd; |
35 | | |
36 | | static expert_field ei_lsd_field; |
37 | | |
38 | | static bool |
39 | | parse_string_field(proto_tree *tree, int hf, packet_info *pinfo, tvbuff_t *tvb, unsigned offset, unsigned* next_offset, unsigned* linelen) |
40 | 0 | { |
41 | 0 | const char *str; |
42 | 0 | header_field_info* hf_info = proto_registrar_get_nth(hf); |
43 | 0 | char **field_and_value; |
44 | 0 | proto_item* ti; |
45 | 0 | char *p; |
46 | |
|
47 | 0 | if (!tvb_find_line_end_remaining(tvb, offset, linelen, next_offset)) |
48 | 0 | return false; |
49 | | |
50 | 0 | str = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset, *linelen, ENC_ASCII); |
51 | 0 | if (g_ascii_strncasecmp(str, hf_info->name, strlen(hf_info->name)) == 0) |
52 | 0 | { |
53 | 0 | field_and_value = wmem_strsplit(pinfo->pool, str, ":", 2); |
54 | 0 | p = field_and_value[1]; |
55 | 0 | if (p) { |
56 | 0 | while(g_ascii_isspace(*p)) |
57 | 0 | p++; |
58 | 0 | proto_tree_add_string(tree, hf, tvb, offset, *linelen, p); |
59 | 0 | return true; |
60 | 0 | } |
61 | 0 | } |
62 | 0 | ti = proto_tree_add_string(tree, hf, tvb, offset, *linelen, str); |
63 | 0 | expert_add_info_format(pinfo, ti, &ei_lsd_field, "%s field malformed", hf_info->name); |
64 | |
|
65 | 0 | return true; |
66 | 0 | } |
67 | | |
68 | | static int |
69 | | dissect_lsd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
70 | 0 | { |
71 | 0 | proto_item *ti = NULL; |
72 | 0 | proto_tree *lsd_tree; |
73 | 0 | unsigned offset = 0, next_offset = 0, linelen; |
74 | 0 | const char *str; |
75 | 0 | char **field_and_value; |
76 | 0 | uint16_t port; |
77 | 0 | bool valid; |
78 | |
|
79 | 0 | if (!tvb_find_line_end_remaining(tvb, offset, &linelen, &next_offset)) |
80 | 0 | return 0; |
81 | | |
82 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "LSD"); |
83 | 0 | col_clear(pinfo->cinfo, COL_INFO); |
84 | | |
85 | | /* Create display subtree for the protocol */ |
86 | 0 | ti = proto_tree_add_item(tree, proto_lsd, tvb, 0, -1, ENC_NA); |
87 | 0 | lsd_tree = proto_item_add_subtree(ti, ett_lsd); |
88 | |
|
89 | 0 | proto_tree_add_item(lsd_tree, hf_lsd_header, tvb, offset, linelen, ENC_ASCII); |
90 | |
|
91 | 0 | offset = next_offset; |
92 | 0 | if (!parse_string_field(lsd_tree, hf_lsd_host, pinfo, tvb, offset, &next_offset, &linelen)) |
93 | 0 | return offset+linelen; |
94 | | |
95 | 0 | offset = next_offset; |
96 | 0 | if (!tvb_find_line_end_remaining(tvb, offset, &linelen, &next_offset)) |
97 | 0 | return offset+linelen; |
98 | 0 | str = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset, linelen, ENC_ASCII); |
99 | 0 | if (g_ascii_strncasecmp(str, "Port", strlen("Port")) == 0) |
100 | 0 | { |
101 | 0 | field_and_value = wmem_strsplit(pinfo->pool, str, ":", 2); |
102 | 0 | valid = ws_strtou16(field_and_value[1], NULL, &port); |
103 | 0 | ti = proto_tree_add_uint(lsd_tree, hf_lsd_port, tvb, offset, linelen, port); |
104 | 0 | if (!valid) |
105 | 0 | { |
106 | 0 | expert_add_info_format(pinfo, ti, &ei_lsd_field, "Port value malformed"); |
107 | 0 | } |
108 | 0 | } |
109 | 0 | else |
110 | 0 | { |
111 | 0 | ti = proto_tree_add_uint(lsd_tree, hf_lsd_port, tvb, offset, 0, 0xFFFF); |
112 | 0 | expert_add_info_format(pinfo, ti, &ei_lsd_field, "Port field malformed"); |
113 | 0 | } |
114 | 0 | proto_item_set_len(ti, linelen); |
115 | |
|
116 | 0 | offset = next_offset; |
117 | 0 | if (!parse_string_field(lsd_tree, hf_lsd_infohash, pinfo, tvb, offset, &next_offset, &linelen)) |
118 | 0 | return offset+linelen; |
119 | | |
120 | 0 | offset = next_offset; |
121 | 0 | if (!tvb_find_line_end_remaining(tvb, offset, &linelen, &next_offset)) |
122 | 0 | return offset+linelen; |
123 | | /* Cookie is optional */ |
124 | 0 | if (tvb_strncaseeql(tvb, offset, "cookie", strlen("cookie")) == 0) |
125 | 0 | { |
126 | 0 | if (!parse_string_field(lsd_tree, hf_lsd_cookie, pinfo, tvb, offset, &next_offset, &linelen)) |
127 | 0 | return offset+linelen; |
128 | 0 | } |
129 | | |
130 | 0 | return tvb_captured_length(tvb); |
131 | 0 | } |
132 | | |
133 | | static bool |
134 | | dissect_lsd_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
135 | 1.42k | { |
136 | 1.42k | if (pinfo->dst.type == AT_IPv4 && pntohu32(pinfo->dst.data) == LSD_MULTICAST_ADDRESS && pinfo->destport == LSD_PORT) |
137 | 0 | return (dissect_lsd(tvb, pinfo, tree, data) != 0); |
138 | | |
139 | 1.42k | if (pinfo->dst.type == AT_IPv6 && pinfo->destport == LSD_PORT) |
140 | 0 | return (dissect_lsd(tvb, pinfo, tree, data) != 0); |
141 | | |
142 | 1.42k | return false; |
143 | 1.42k | } |
144 | | |
145 | | void |
146 | | proto_register_lsd(void) |
147 | 15 | { |
148 | 15 | static hf_register_info hf[] = { |
149 | 15 | { &hf_lsd_header, |
150 | 15 | { "Header", "lsd.header", |
151 | 15 | FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } |
152 | 15 | }, |
153 | 15 | { &hf_lsd_host, |
154 | 15 | { "Host", "lsd.host", |
155 | 15 | FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } |
156 | 15 | }, |
157 | 15 | { &hf_lsd_port, |
158 | 15 | { "Port", "lsd.port", |
159 | 15 | FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } |
160 | 15 | }, |
161 | 15 | { &hf_lsd_infohash, |
162 | 15 | { "Infohash", "lsd.infohash", |
163 | 15 | FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } |
164 | 15 | }, |
165 | 15 | { &hf_lsd_cookie, |
166 | 15 | { "cookie", "lsd.cookie", |
167 | 15 | FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } |
168 | 15 | }, |
169 | 15 | }; |
170 | | |
171 | 15 | static int *ett[] = { |
172 | 15 | &ett_lsd, |
173 | 15 | }; |
174 | | |
175 | 15 | static ei_register_info ei[] = { |
176 | 15 | { &ei_lsd_field, { "lsd.malformed_field", PI_MALFORMED, PI_ERROR, "Malformed LDS field", EXPFILL }}, |
177 | 15 | }; |
178 | | |
179 | 15 | expert_module_t* expert_lsd; |
180 | | |
181 | 15 | proto_lsd = proto_register_protocol("Local Service Discovery", "LSD", "lsd"); |
182 | | |
183 | 15 | proto_register_field_array(proto_lsd, hf, array_length(hf)); |
184 | 15 | proto_register_subtree_array(ett, array_length(ett)); |
185 | 15 | expert_lsd = expert_register_protocol(proto_lsd); |
186 | 15 | expert_register_field_array(expert_lsd, ei, array_length(ei)); |
187 | 15 | } |
188 | | |
189 | | void |
190 | | proto_reg_handoff_lsd(void) |
191 | 15 | { |
192 | 15 | heur_dissector_add( "udp", dissect_lsd_heur, "LSD over UDP", "lsd_udp", proto_lsd, HEURISTIC_ENABLE); |
193 | 15 | } |
194 | | |
195 | | /* |
196 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
197 | | * |
198 | | * Local Variables: |
199 | | * c-basic-offset: 2 |
200 | | * tab-width: 8 |
201 | | * indent-tabs-mode: nil |
202 | | * End: |
203 | | * |
204 | | * ex: set shiftwidth=2 tabstop=8 expandtab: |
205 | | * :indentSize=2:tabSize=8:noTabs=true: |
206 | | */ |